Datastore data loss

If you don’t want to use DataStore2 or an external database, there’s still some ways to make your system a bit more reliable.

If distance is always an increasing number, UpdateAsync could be helpful here – even if it’s not in the way ClientScripts said. The good thing about UpdateAsync is that it will use the previously saved value instead of just getting rid of it. That means if your initial GetAsync fails, by the time the player leaves you could be able to increment their old data instead of overwriting it.

The problem with this is that it means you would have to store two distances – the distance they’ve gained in that session (internally, for saving) and their overall distance (externally, for the leaderboard). This shouldn’t be a big change, but you would still have to rework your code a bit. Alternatively, you could keep the original data fetched from the datastore somewhere (if it’s nil, you’d have it be 0 or whatever your default value is) and find the difference to use as session time.

An example using both methods: (this is just the saving part, it wouldn’t replace your pcalls or if statements)

--at the top of the script outside any functions
-- this assumes it's all one script
local ppTable = {}

--later when you get data:
pp = DataStorage:GetAsync(player.UserId .. "-dist")
ppTable[player] = pp -- store original value for later

-- somewhere far away in the script:
local totalTime = player.leaderstats.Distance.Value
DataStorage:UpdateAsync(player.UserId .. "-dist", function(old)
     if old then -- if there's anything saved
          return old + (totalTime - (ppTable[player] or 0)) --add the session time to total time and save
     else -- if nothing's saved
          return totalTime -- no need to subtract out old data
     end
end)
--when you get data:
local sessionData = Instance.new("IntValue")
sessionData.Name = "sessionDistance"
sessionData.Parent = player -- not leaderstats because you probably don't want to display that number
local success, errormessage = pcall(function()
     pp = DataStorage:GetAsync(player.UserId .. "-dist")
end)
-- whenever you increase the one distance thing in leaderstats, you'd have to increase the other.
--later, when saving data:
local sessionDist = player.sessionDistance.Value
DataStorage:UpdateAsync(player.UserId .. "-dist", function(old)
     if old then -- if there's anything saved
          return old + sessionDist --add the session time to total time and save
     else -- if nothing's saved
          return sessionDist -- no need to add to old
     end
end)

Keep in mind, this system assumes that your distance can only go up or stay the same in any given session, and that it can’t go down. If that’s not true, don’t use this system. Another method of using UpdateAsync, which assumes that your distance saved should be the greatest distance you’ve ever gotten in a session (i.e., the best distance you’ve ever had) might be helpful, too. This would be a lot easier to implement, since you wouldn’t need anything special until you save data. Then, you would just make sure that your current session’s best is better than your saved best before saving.

local bestTime = player.leaderstats.Distance.Value
DataStorage:UpdateAsync(player.UserId .. "-dist", function(old)
     if old and old > bestTime then -- if there's anything saved and it's better than your best
          return old -- save the old value
     else -- if either are not true
          return bestTime -- save the current best
     end
end)

The problem here is with unclear variable names, lack of comments, and not explaining what your “Distance” represents in a clear way. In the future, explaining what the data means could be helpful when asking for alternative methods of saving. I can’t be sure if you want to save the highest distance you’ve ever had, like a “best time” thing in a racing game, or if you want to increment the old value to have a distance counter sort of thing (that increases similar to a “wins” counter). That aside, there’s a few other ways to improve your code.

  • Using DataStore2 or an external database is going to be more reliable than using datastores no matter what you do, since it gives access to all past saves of the data and makes restoring it much easier. An external database is the most reliable because you don’t have to worry about Roblox datastores being down.

  • You don’t check if data exists before distance.Value to it. Try something like this:

if success then
     distance.Value = pp or 0 -- 0 being the default value
else
     -- do your current error handling, whatever
end

since this won’t error if nothing is saved. Basically, this just replaces the saved value with 0 if it would have been nil. If you try to set it to nil, I’m pretty sure it errors, but if I’m wrong somebody please correct me.

I’m not sure how to fix formatting for the final bullet, sorry about that.

7 Likes