My datastore is not working and I have no idea why

Hello! I’ve been trying to set up a data store recently for one of my games. However, it’s not working right and I have no idea why.

I run the game and then change one of the values. Then I stop the game. When I run it again, I get that the data was saved as 0, 0 which is not what I set the values.

Here’s my script:


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


function SaveData(Plr: Player) : ()
	local id = Plr.UserId
	local cwinsdata = Plr:WaitForChild("leaderstats"):WaitForChild("Casual Wins").Value
	local rwinsdata = Plr:WaitForChild("leaderstats"):WaitForChild("Ranked Wins").Value
	
	datastore:SetAsync(id, {cwinsdata, rwinsdata})	
end



function GetData(Plr: Player) : ()
	local id = Plr.UserId
	
	local gotdata = false
	
	while not gotdata do
		local success, errormessage = pcall(function()
			return datastore:GetAsync(id)
		end)
		if success then 
			gotdata = true
			return errormessage
		end
		wait(0.1)
	end
end


local function PlrJoined(Plr: Player): ()
	print("doing")
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = Plr

	local cwins = Instance.new("IntValue")
	cwins.Name = "Casual Wins"
	cwins.Parent = leaderstats

	local rwins = Instance.new("IntValue")
	rwins.Name = "Ranked Wins"
	rwins.Parent = leaderstats
	
	local data = GetData(Plr)
	print(data)
	if data == nil then
		cwins = 0
		rwins = 0
	else
		cwins = data[1]
		rwins = data[2]
	end
end

game.Players.PlayerAdded:Connect(function(player: Player) 
	PlrJoined(player)
end)


game.Players.PlayerRemoving:Connect(function(player: Player) 
	SaveData(player)
end)

game:BindToClose(function()
	for i, v in pairs(game.Players:GetChildren()) do
		coroutine.wrap(function()
			local id = v.UserId
			local cwinsdata = v:WaitForChild("leaderstats"):WaitForChild("Casual Wins").Value
			local rwinsdata = v:WaitForChild("leaderstats"):WaitForChild("Ranked Wins").Value

			datastore:SetAsync(id, {cwinsdata, rwinsdata})	
		end)
	end

	
end)

Thanks!

1 Like
coroutine.wrap(function()
			local id = v.UserId
			local cwinsdata = v:WaitForChild("leaderstats"):WaitForChild("Casual Wins").Value
			local rwinsdata = v:WaitForChild("leaderstats"):WaitForChild("Ranked Wins").Value

			datastore:SetAsync(id, {cwinsdata, rwinsdata})	
		end)

After coroutine.wrap(function() end) you add an () so it would be

coroutine.wrap(function()
			local id = v.UserId
			local cwinsdata = v:WaitForChild("leaderstats"):WaitForChild("Casual Wins").Value
			local rwinsdata = v:WaitForChild("leaderstats"):WaitForChild("Ranked Wins").Value

			datastore:SetAsync(id, {cwinsdata, rwinsdata})	
		end)()

It wont execute if you dont add an ()

1 Like

Thanks for getting back to me! I’ll try that.

in addition to this, you forgot to set the value of “cwins” and “rwins”!

if data == nil then
		cwins.Value = 0
		rwins.Value = 0
	else
		cwins.Value = data[1]
		rwins.Value = data[2]
	end
2 Likes

Alright thanks!

Also, as an update, I tested it and its now running. However, when the bindtoclose runs, it runs after the player left the game. This is an issue because in my code, I run through the remaining players and save their data.

I added a print(#game.Players:GetChildren()) and got 0.

How do I fix this?

you’re already saving player’s data once they leave, can i ask why you’re using bindtoclose?

If I don’t use a bindtoclose, the server will shutdown before the function for playerremoving will run.

This is wrong; game.Players.PlayerRemoving runs before the server shutdowns.

If your game has big servers; game:BindToClose(function() can actually cause more destruction than expected because you’re spamming Datastore:SetAsync, let alone the risks!

Your best approach would be avoiding this, and giving players an option to save it regularly.

1 Like

I have always been told to use BindToClose in addition to PlayerRemoving. PlayerRemoving never worked for me when i shut down servers or ended games in studio testing. I suppose I could see a problem if it double saves but in my experience it never reaches the PlayerRemoving function

1 Like

BindToClose is meant for studio testing and stats that aren’t priority, not for data-saving.

Ok but how do I make sure the player’s data saves when they leave? If there really Isn’t a solution, then I guess I’ll have to do a manual save like how @iitreyonly said. :smile:

can you explain why it’s not working? does it print any errors?

Ok so there are no errors, the only problem is that the function in PlayerRemoving doesn’t fully run before the server shuts down. Most people suggest that you use BindToClose to fix this issue. However, I implemented that and It’s still not working.

With the BindToClose, it runs the code but it does so after the player already left. This is an issue because in a BindToClose, you need to loop through all the players and save their data. I added a line to the BindToClose at the front.

print(#game.Players:GetChildren))

This in theory would print the number of players left in the game when the code ran. I ran this and got 0.

This is the issue I’m trying to solve.

Thanks for your time!

are you using admin commands to shutdown the server?

No, this is when I leave naturally and I’m the only person in the server.