No errors noted. I added an if not success warn message to the code and nothing popped up.
LGTM. I fully support your use of UpdateAsync here.
Edit: Ignore my posts. I was under the impression that OP wanted to have the player start with 0 points if they haven’t had anything in the DataStore before.
I think maybe this could be because it’s updating the value before it has time to get the value? Not really sure still. If that were the case, how would I go about waiting for the value?
If you have multiple scripts that look for the points whenever the player joins, you can always have a
(value gotten from datastore) or 0
in them. The script you initially posted will at some point update the DataStore to have 0. This way you’re guaranteed to never get nil
.
So the issue would still be that it’s not getting the value from the data store and is instead giving the value of 0 though, wouldn’t it be? When I join the game the value is always 0.
I’ve not really done anything with PlayerRemoving, not sure if I needed to do that.
Here’s my leaderstats, maybe something in that caused this not to work:
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(plr)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = plr
local points = Instance.new("IntValue")
points.Name = "Points"
points.Value = 0
points.Parent = leaderstats
end)
So I tried removing the or 0 part to see what happened and it still doesn’t work. Any feedback would be appreciated.
Current DataStore script:
local pointsDataStore = game:GetService("DataStoreService"):GetDataStore("Points")
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(plr)
local playerKey = "Player_"..plr.UserId
local success, errormessage = pcall(function()
pointsDataStore:UpdateAsync(playerKey, function(oldValue)
local newValue = oldValue
return newValue
end)
end)
if not success then
warn("Could not save"..errormessage)
elseif success then
print("Progress updated")
end
end)
you’re saving something that is already saved, try:
local success, errormessage = pcall(function()
pointsDataStore:UpdateAsync(playerKey, function(oldValue)
local newValue = oldValue + points.Value
return newValue
end)
end)
or just return points.Value
why are you saving when they join?..
and I don’t see you reference any points variable so what are you even trying to save
The problem with the script is that you are returning oldValue to UpdateAsync. That just sets the new data in the store to the data that is already there. Second issue is that your using UpdateAsync in PlayerAdded. There is no reason to save their data right when they join the game. You probably want to use GetAsync there because it returns the saved data.
To answer the question though, there is a whole article written about it here.
Simplified, it is recommend to use UpdateAsync as it can be used safer, not that it just is safer. Doing UpdateAsync and just returning the new data wouldn’t be much different from SetAsync.
As stated in the article, a good way of utilizing UpdateAsync is by having some kind of DataId that increments by one each time the player saves. The reason this prevents stuff like data loss is because GetAsync may not return the latest data, and if it didn’t, you can check for this inside of UpdateAsync by using the data id - if the data you are about to save is older than the saved data, you can stop saving
I haven’t read the whole thread, but I’m confused.
You’re using UpdateAsync
, but you’re just using it to set a default value or keep the existing value? What actual update are you doing here??
Setting a default value is fine and dandy through UpdateAsync, but I don’t know why you’d do that if there’s never going to be anything but a default value.
I’m confused, I just want this to retain the same value that the player has when they leave the game. I.e. If a player leaves the game with 3 points, they should have 3 points when they rejoin.
Yes, I know how GetAsync works, but I’m trying to figure out how to do this with UpdateAsync.
You shouldnt do it with update async thats the thing
I don’t see why you would use update async > get async for getting the last saved value
UpdateAsync updates data. Your updating data when the player joins a game. Use GetAsync if you want to get the amount of points they have saved. Make sure you also use UpdateAsync when the player leaves or there wont be any data to retrieve with GetAsync.
Doesn’t UpdateAsync allow the person to reference the last saved value with its second parameter?
If you don’t have something to do with UpdateAsync then just stick with SetAsync unless you want to implement session locking. Update async doesn’t mean less data loss etc it’s just a way to mess with data before saving it which means if you just want to save you don’t need update async at all.
The last saved value is retrieved with GetAsync… you use UpdateAsync to check the last value then update it accordingly
If you want something that simple, I’d suggest just using SetAsync
. I only recommend using UpdateAsync
for things that depend upon the existing value.
So, something like this:
--!strict
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local playerPointsDataStore = DataStoreService:GetDataStore("PlayerPointsDataStore-PUT-YOUR-ACTUAL-DATA-STORE-NAME-HERE")
-- this is a map keyed by player and the value is their points
local pointsByPlayer = {}
function generateDataStoreKeyForPlayer(player: Player)
return "player_userId:" .. player.UserId
end
function loadPointsForPlayerAsync(player: Player)
local dataStoreKey = generateDataStoreKeyForPlayer(player)
local dataStoreValue = playerPointsDataStore:GetAsync(dataStoreKey)
if type(dataStoreValue) == "number" then
pointsByPlayer[player] = dataStoreValue
else
pointsByPlayer[player] = 0
end
end
function savePointsForPlayerAsync(player: Player)
if pointsByPlayer[player] == nil then
warn("Cannot save points for player " .. player.Name .. " because their points have not been loaded yet.")
return
end
local dataStoreKey = generateDataStoreKeyForPlayer(player)
playerPointsDataStore:SetAsync(dataStoreKey, pointsByPlayer[player])
end
Players.PlayerAdded:Connect(loadPointsForPlayerAsync)
Players.PlayerRemoving:Connect(function(player: Player)
savePointsForPlayerAsync(player)
pointsByPlayer[player] = nil -- avoid a memory leak
end)
game:BindToClose(function()
for player, pointsForPlayer in pairs(pointsByPlayer) do
savePointsForPlayerAsync(player)
end
end)
This will load on player join, store in a cache (pointsByPlayer
) in Lua, and then save to the data store as you want - including already being wired up to players leaving and the game closing.