Game data won't save

I’ve started a game, and I need to save a multiplier stat. I’m using datastores, but for some reason it won’t save correctly. pCall is saying that both saving and loading work, so I have no idea what the issue is. I do have another script, which gives you cash and multiplier when you get enough cash and shows those stats on a Gui. I can provide that script if anyone would like to see it. Might anyone have any ideas with what’s wrong?

local DataStoreService = game:GetService("DataStoreService")

local StatStore = DataStoreService:GetDataStore("StatStore")

game.Players.PlayerAdded:Connect(function(player)
	
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	
	--Stats
	local Multi = Instance.new("IntValue")
	Multi.Name = "Multi"
	Multi.Parent = leaderstats
	
	local Cash = Instance.new("NumberValue")
	Cash.Name = "Cash"
	Cash.Parent = leaderstats
	
	--Loading stats
	local multidata = 0
	local success, errormessage = pcall(function()
		multidata = StatStore:GetAsync(tostring(player.UserId).."Multi")
	end)
	if success then
		
		Multi.Value = multidata
		print("Data Succesfully Restored")
		
	else
		
		print("Error in retreiving  data.")
		warn(errormessage)
		
	end
	
end)

game.Players.PlayerRemoving:Connect(function(player)
	
	local success, errormessage = pcall(function()
		local data = StatStore:SetAsync(tostring(player.UserId).."Multi",player.leaderstats.Multi.Value)
	end)
	
	if success then
		print("Player Data Saved Succesfully")
	else
		print("There was an error in saving data...")
		warn(errormessage)
	end
	
end)

game:BindToClose(function()
	for i,v in pairs(game.Players:GetPlayers()) do
		v:Kick("Server Shutdown")
		wait(0.2)
	end
	wait(3)
end)

I’ve turned on studio access to API and made sure that everyone’s data is saved when the server shuts down. I’m completely stuck.

Are you testing in studio? Sometimes the studio server will close before it saves.

Do not kick the players, that is the opposite of what game:BindToClose is suppose to do.

Yeah that is true. Also maybe try updateasync. It is much more reliable than setasync since it will keep running until it runs out of retrys or until its finished. You can also use it to compare data since the callback function passed to updateasync returns the old value too.

1 Like

I removed the BindToClose and changed the setasync to updateasync, but that didn’t seem to work. Any other ideas? Or am I doing something wrong?

Does the print statement in the saving print?

It says “unable to cast value to function.”

Did you pass a function to update a sync?

I’m not sure what that means, could you give me an example?

Updateasync takes a function. In this function it has one argument which is the old data. You return the data you want to save using return.

:UpdateAsync(function(old)
return new or old;
end);

Ok, I have to go so I will try it later and see if it works.

If you’re testing in studio then use game:BindToClose() and move the saving functionality there as well.

I won’t not move the saving functions there. Also, they already have game:BindToClose.

.PlayerRemoving won’t fire in studio if the locally hosted server closes before the player instance is removed hence if you’re testing in studio it’s best to use :BindToClose().

1 Like

I tried changing the script, to use UpdateAsync, but it didn’t work. Am I still doing something wrong? I’m somewhat new to scripting, especially datastores, so that could be the case.

game.Players.PlayerRemoving:Connect(function(player)

local success, errormessage = pcall(function()
	StatStore:UpdateAsync(tostring(player.UserId).."Multi", function(old)
		return player.leaderstats.Multi.Value
	end)
end)
if success then
	print("Player Data Saved Succesfully")
else
	print("There was an error in saving data...")
	warn(errormessage)
end
end)

Ok what seems to be the issue? You can’t save and load data? Lemme try your script and see what the issue is.

This works for me, Let me know if this fixes any of the issues you are facing.

-- Variables --
local DataStoreService=Game:service'DataStoreService';
local StatsDataStore=DataStoreService:GetDataStore'Player_Stats';
-- Load data. --
LoadData=function(Player)
-- Check if already loaded data for player. --
if(Player:GetAttribute'DataLoaded')then
-- We did so return. --
return;
end;
-- Set DataLoaded. --
Player:GetAttribute'DataLoaded'
-- Create leaderstats. --
local a=Instance.new'Folder';
a.Name='leaderstats';
a.Parent=Player;
-- Create stats --
local b=Instance.new'IntValue';
b.Name='Multi';
b.Parent=a;
local c=Instance.new'NumberValue';
c.Name='Cash';
c.Parent=a;
-- Loop through all stats in leaderstats. --
for _,d in next,a:children() do
-- Spawn it to it doesn't yeild. --
Spawn(function()
-- Load data from datastore. --
local Success,Error=ypcall(function()
d.Value=(StatsDataStore:GetAsync(('%s_%s'):format(Player.UserId,d.Name)))or(0);
end);
-- Check for any errors. --
if(not(Success))then
-- Warn. --
warn(Error);
end;
end);
end;
end;
-- Load data to datastores. --
local SaveData=function(Player)
-- Clone stats. --
local Stats=Player.leaderstats:clone();
-- Loop through all stats in leaderstats. --
for _,d in next,Stats:children() do
-- Spawn it to it doesn't yeild. --
Spawn(function()
-- Save data to datastore. --
local Success,Error=ypcall(function()
-- UpdateAsync is better than SetAsync. --
StatsDataStore:UpdateAsync(('%s_%s'):format(Player.UserId,d.Name),function(Old)
-- Return their new stats or their old ones. --
return(d.Value)or(Old);
end);
end);
-- Check for any errors. --
if(not(Success))then
-- Warn. --
warn(Error);
end;
end);
end;
end;
-- New player --
Game.Players.PlayerAdded:connect(LoadData);
-- Player leaving. --
Game.Players.PlayerRemoving:connect(SaveData);
-- Early joiners, if any. --
for _,a in next,Game.Players:players() do
-- Load. --
LoadData(a);
end;
-- Bind to close. --
Game:BindToClose(function()
Wait(3);
end);

I figured it out, the script that changed the player’s stats was a local script, so the saving script saw the stats at zero.

Yes that is because of filtering enabled.