Confused on using UpdateAsync

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. :+1:

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.

1 Like

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.

GlobalDataStore:GetAsync (roblox.com)

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.

1 Like

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

1 Like

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.

2 Likes