GetAsync()/SetAsync()

I can’t save the value. why?

local datastore = game:GetService("DataStoreService"):GetDataStore("save")

local function load(player)
	local storeditems = datastore:GetAsync(player.userId)
	workspace.Folder.Value.Value = storeditems
end

local function save(player)
	
	datastore:SetAsync(player.userId,workspace.Folder.Value.Value)
	print("werwer")
end
game.Players.PlayerAdded:Connect(load)
game.Players.PlayerRemoving:Connect(save)
1 Like

It’s probably because it’s saving the value under nil because “userId” is not a property of the player instance, it’s “UserId” (uppercase U).

I recommend you wrap the SetAsync and GetAsync in a pcall.

I did some tests but it still doesn’t save

local datastore = game:GetService("DataStoreService"):GetDataStore("save")

local function load(player)
	pcall(function()
		local storeditems = datastore:GetAsync(player.UserId)
		workspace.Folder.Value.Value = storeditems
	end)	
end

local function save(player)
	pcall(function()
		datastore:SetAsync(player.UserId,workspace.Folder.Value.Value)
		print("werwer")
	end)
end
game.Players.PlayerAdded:Connect(load)
game.Players.PlayerRemoving:Connect(save)

Do you have API services enabled?

This could stop your game from acting access to services like DSS / DataStoreService

1 Like

yes i have API services enabled

1 Like

This surprisingly isn’t the problem “userId” actually exists as a deprecated property and is the old name for UserId

1 Like

Hm well the only other thing I can think of that the moment is for the OP to check if their script is on the server and if it’s not a LocalScript

1 Like

As for your code not working, assuming you’re trying to test this out in Studio, one common problem is the game server shutting down before the code can finish executing, this can happen in-game as well but it’s more rare as studio shuts down faster, either way, you can address this problem by having the game wait for all data saving to finish before shutting down, here’s a modified version of your code that adresses this issue, I also made some additional modifications with comments to explain why I did that:

local LoadedPlayers = {} -- Store all players that have their data loaded here so you can keep track
local datastore = game:GetService("DataStoreService"):GetDataStore("save")

local function load(player)
    local success,returnval = pcall(datastore.GetAsync,datastore,player.UserId)
    --The first value pcall is returns is whether or not the code errored, the second is whatever the code returns, if their is no return, this value will be nil, if there was an error during code execution, this will be the error string
    if success then
        LoadedPlayers[player] = true -- Store the player into the dictionary as their data has successfully loaded
        if returnval then --Only set the value if the returnval isn't nil, data for new players who don't have an existing value will always be nil
            workspace.Folder.Value.Value = returnval
        end
    else
        player:Kick("Error occured while loading data, please rejoin") -- It's recommended that you remove players if data load fails
        print(string.format("Data load failed\nError: %s",returnval))
    end
end

local function save(player)
    if LoadedPlayers[player] == nil then
        return --This will prevent data from saving if the player's data load failed, this may not make much sense at first but if data fails to load when someone joins your game, and you do not have this check, once they leave, their new blank data will overwrite their original data, resulting in data loss
    end
    --You may have noticed I massively changed the code here, what I've done here is basically have it retry data saving if it fails once, to minimize any risks of data loss, currently I have it set to 1 so it will only try once, you can change this to your liking
    local success,returnval = nil
    local Max_Tries = 1
    local CurrentTries = 0
    while success ~= true and CurrentTries <= Max_Tries do
        success,returnval = pcall(datastore.SetAsync,datastore,player.UserId,workspace.Folder.Value.Value)
        CurrentTries += 1
    end
    if success then
        print("werwer")
    else
        print(string.format("Data save failed\nError: %s",returnval))
    end
end
game.Players.PlayerAdded:Connect(load)
game.Players.PlayerRemoving:Connect(function(player)
    save(player)
    LoadedPlayers[player] = nil -- Remove the player from the table, this is done outside of the save function as this should only be done when the player is leaving
end)

--Now this is where we finally make the game wait for data saving to finish before shutting off
game:BindToClose(function() --This function will only run once the game begins shutting down, :BindToClose() can stop the game from shutting down until your code has finished executing, however, if it takes longer than 30 seconds, it will shut down anyway, fortunately data saving will hardly take 3 seconds
    while next(LoadedPlayers) ~= nil do
        task.wait() -- Keep waiting until the LoadedPlayers data is empty, which will only be empty once all data saving operations have completed, the loop will automatically break once this happens and the game can finally shut down
    end
end)

Also, as @Doomcolp3, make sure it’s not a LocalScript, data saving cannot work through a LocalScript

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.