Problem with DataStore

I have problem with datastore. it doesn’t save values when player leaves. I tried to fix it but no effects.

local DataStoreService = game:GetService('DataStoreService')

local SaveValue = DataStoreService:GetDataStore('SaveValue')

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local hiddenvalue = Instance.new("Folder")
	hiddenvalue.Name = "hiddenfolder"
	hiddenvalue.Parent = leaderstats

	local cash = Instance.new("IntValue")
	cash.Name = "Coins"
	cash.Parent = hiddenvalue

	local data
	local success, errormessage = pcall(function()
		data = SaveValue:GetAsync(player.UserId .. "-coins")
	end)

	if success then
		cash.Value = data or 0 -- Default to 0 if data is nil
	else
		print("There was an error whilst getting your data")
		warn(errormessage)
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local success, errormessage = pcall(function()
		SaveValue:UpdateAsync(player.UserId .. "-coins", player.hiddenfolder.Coins.Value)
	end)

	if success then
		print("Player Data Saved")
	else
		print("Player data not saved")
		warn(errormessage)
	end
end)

Use SetAsync() instead. Also I would suggest putting the PlayerRemoving Function into the PlayerAdded function.

Here is the script with my changes:

local DataStoreService = game:GetService('DataStoreService')

local SaveValue = DataStoreService:GetDataStore('SaveValue')

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local hiddenvalue = Instance.new("Folder")
	hiddenvalue.Name = "hiddenfolder"
	hiddenvalue.Parent = leaderstats

	local cash = Instance.new("IntValue")
	cash.Name = "Coins"
	cash.Parent = hiddenvalue

	local data
	local success, errormessage = pcall(function()
		data = SaveValue:GetAsync(player.UserId .. "-coins")
	end)

	if success then
		cash.Value = data or 0 -- Default to 0 if data is nil
	else
		print("There was an error whilst getting your data")
		warn(errormessage)
	end

	game.Players.PlayerRemoving:Connect(function()
		local success, errormessage = pcall(function()
			SaveValue:SetAsync(player.UserId .. "-coins", player.hiddenfolder.Coins.Value)
		end)

		if success then
			print("Player Data Saved")
		else
			print("Player data not saved")
			warn(errormessage)
		end
	end)
end)

Add a game:BindToClose() function to ensure the data saves both on Studio and in game.

Like this:

local DataStoreService = game:GetService('DataStoreService')

local SaveValue = DataStoreService:GetDataStore('SaveValue')

function SaveData(player)
    local success, errormessage = pcall(function()
		SaveValue:SetAsync(player.UserId .. "-coins", player.hiddenfolder.Coins.Value)
	end)
	if success then
		print("Player Data Saved")
	else
		print("Player data not saved")
		warn(errormessage)
	end
end

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local hiddenvalue = Instance.new("Folder")
	hiddenvalue.Name = "hiddenfolder"
	hiddenvalue.Parent = leaderstats

	local cash = Instance.new("IntValue")
	cash.Name = "Coins"
	cash.Parent = hiddenvalue

	local data
	local success, errormessage = pcall(function()
		data = SaveValue:GetAsync(player.UserId .. "-coins")
	end)

	if success then
		cash.Value = data or 0 -- Default to 0 if data is nil
	else
		print("There was an error whilst getting your data")
		warn(errormessage)
	end

	game.Players.PlayerRemoving:Connect(SaveData)
end)

game:BindToClose(function()
    for _,player in pairs(game:GetService("Players"):GetPlayers()) do
        SaveData(player)
    end
end)

The reason why I believe your code doesn’t work when the player leaves is that you index player.hiddenfolder, which doesn’t exist and is going to cause the script to error. Since hiddenfolder is created and parented to leaderstats the correct hierarchy should be: player.leaderstats.hiddenfolder

The suggestions posted have been helpful, but I noticed one glaring flaw with setting up your data system. If the GetAsync call fails, the player’s coin leaderstat value will be left at 0 (default value for IntValues.) Afterward, you have a PlayerRemoving listener and a suggested BindToClose handler which will save the player’s data using their coin leaderstat value (0) This will result in data loss.

Even if you correct that issue, there are still some considerations to make here. What if the server abruptly ends and PlayerRemoving and BindToClose are never called? Without periodically auto-saving you will lose player data. What if the UpdateAsync call fails when the player leaves? You simply just warn that the player data was not saved, goodbye player data!

I highly suggest you use a module like ProfileService or DataStore2 because this stuff is tricky to get right. Those two modules periodically auto-save data, implement caching, etc.

The leaderstat values should also be purely frontend and shouldn’t impact how the player’s data is saved on the server.

1 Like

Like some other replies said, you need to do

  1. Give the server time to save the data with the :BindToClose function
  2. Use :SetAsync instead of :UpdateAsync

If you still want to use UpdateAsync, your code should look something like this:

SaveValue:UpdateAsync(player.UserId .. "-coins", function(PreviousData)
    if PreviousData ~= nil then
        local AmountToAdd = player.hiddenfolder.Coins.Value - PreviousData
        return player.hiddenfolder.Coins.Value + AmountToAdd
    else
        return player.hiddenfolder.Coins.Value --Runs if the player has no previous data
    end
end)

@TheSoldierOfTheNoobs, putting the PlayerRemoving event in the PlayerAdded event is a bad idea because it will fire multiple times and cause other issues.

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