local DataStore = game:GetService("DataStoreService") local ds = DataStore:GetDataStore("CashSaveSystem") game.Players.PlayerAdded:Connect(function(player) local leader = Instance.new("Folder", player) leader.Name = "leaderstats" local Stage = Instance.new("IntValue", leader) Stage.Name = "Stage" Stage.Value = ds:GetAsync(player.UserId) or 1 ds:SetAsync(player.UserId, Stage.Value) Stage.Changed:Connect(function() ds:SetAsync(player.UserId, Stage.Value) print("Saved") end) end) game.Players.PlayerRemoving:Connect(function(player) ds:SetAsync(player.UserId, player.leaderstats:FindFirstChild("Stage").Value) print("Saved") end)
For some reason this code doesn't save the stage value of the player when they join, when the value is updated/changed, or when they leave the game. Been stuck for quite awhile and I haven't seemed to figure it out.
This has also worked on a different game, and still does, so I have no clue why it doesn't work on this game. (And yes, studio access to API services is on)
First of all, if neither request work then I'd recommend making sure your script can execute from its current location. Scripts will not execute in certain locations. Make sure this is not one of them.
As pointed out by Fifkee and incapaz in the comments, you shouldn't use DataStore:SetAsync()
if the data store key already exists and the new value to be saved depends on the old. Also, there is no reason to save immediately after loading. Only save when a player leaves the game or during an autosave.
Secondly, the PlayerRemoving
event is never fired when the last player in a game server leaves, because the server stops anything it's doing and focuses solely on shutting down. Which means your players' data will not be saved before leaving, and so their data may not be up to date when they rejoin.
For this reason you will have to save the player's data from a game:BindToClose()
callback function.
A function passed to BindToClose
will be invoked right before Roblox shuts down. Multiple functions can be bound with BindToClose
, in which case they will execute in parallel.
Also, from the Roblox Wiki's documentation:
"The game will wait a maximum of 30 seconds for all bound functions to complete running before shutting down. After 30 seconds, the game will shut down regardless if all bound functions have completed or not."
But wait, that's not all! We shouldn't only save the last connected player's data from a BindToClose()
callback function, as it's entirely possible for the server to close even if there are more players in-game; in case of a network issue, or if you manually shutdown all servers from your game's page, for example.
Additionally, since data store requests need to make web calls, and therefore take time to complete, if we saved every player's data one after the other we could run out of time, as each data store request would have to wait for the previous one to finish. Remember, Roblox will only allow you 30 seconds before shutting down.
So what we're going to do is save every connected player's data in parallel using spawn()
:
local Players = game:GetService("Players") local function savePlayerData(player) -- logic to save a player's data end game:BindToClose(function() for _, player in pairs(Players:GetPlayers()) do spawn(function() savePlayerData(player) end) end end)
This way our code will save every connected player's data when the server closes -- regardless of why it closes -- and start the next data store request when one yields (that is, when it pauses the current thread until it's finished).