DataStore not saving in PlayerRemoving

I think I found an intermediate solution, but I couldn’t understand:

local DataStoreService = game:GetService("DataStoreService")
local Jogo = {a = 1} -- any data inside the dictionary

game.Players.PlayerRemoving:Connect(function(Player)
	local JogoStore = DataStoreService:GetDataStore("Jogo", Player)
	print("before PlayerRemoving SetAsync") -- working
	JogoStore:SetAsync("Jogo", Jogo)
	print("after PlayerRemoving SetAsync") -- "after" will not print
end)

game:BindToClose(function()
	print("BindToClose before wait(3)")
	wait(3)
	print("BindToClose before wait(3)")
end)

This will work:

Also, if I decrease the wait time, it will not work again.
So, it seems I have to force the game to wait 3 seconds in order to save the data…
Can anyone explain why?

4 Likes

PlayerRemoving doesn’t typically work with normal datastores, because the server shuts down before it’s able to save (in-studio). game:BindToClose is the better option for saving with normal datastores (when it comes to studio). In-game, PlayerRemoving successfully fires and saves data

1 Like

I’m NOT saying that you can’t. I’m saying that it doesn’t work for me when I want Data Stores to create new data. I have to play the game not in Studio, it creates the data and then when I join Studio game, the new data is loaded even if it wasn’t before.

I don’t know if you understand me.

1 Like

What exactly are you trying to save here? If you’re trying to save specific player data, you’re going about it the wrong way.

I want to save the player’s data when the player exits the game. But ALSO when testing in STUDIO.

Edit

Check the better solution for this: DataStore not saving in PlayerRemoving - #38 by rogeriodec_games


It seems the most reliable code to save the player’s data when the player exits the game (and make it work within Studio), I should do something like:

game.Players.PlayerRemoving:Connect(function(Player)
	local JogoStore = DataStoreService:GetDataStore("Jogo", Player)
	JogoStore:SetAsync("Jogo", Jogo)
end)

game:BindToClose(function() -- (only needed inside Studio)
	if RunService:IsStudio() then -- (only needed inside Studio)
		wait(3) -- this will force the "SetAsync" above to complete 
    end
end)
8 Likes

I have similar issue, to test this event in studio I use the command :kick() to run.

Your data might not be saving because the server is closing while its trying to process those lines of codes. I’ve had this issue before, and usually what solves it is this bit:

game:BindToClose(function()
    wait(5)
end)

That will wait 5 seconds before actually closing the server, I believe.

Edit: Just now noticed you came to that conclusion on your own.

8 Likes

Is API enabled for that game? Data stores require the API to be enabled.

Right well, you aren’t gonna be saving any data that way. I don’t think that will actually work, and if it does, you shouldn’t be using it as it has no error checks whatsoever.
Here’s a modified version of that script. Please tell me if it works.

local DataStoreService = game:GetService("DataStoreService")
local JogoStore = DataStoreService:GetDataStore("Jogo")
local Jogo = {} -- any data inside the dictionary

game.Players.PlayerAdded:Connect(function(Player) 
local playerjogo 
local suc, err = pcall(function() 
        playerjogo = JogoStore:GetAsync(Player.UserId) or "0" --Get their jogo, or if they have none, set it to zero
end)
if suc then 
   Jogo[Player] = playerjogo 
else 
   Jogo[Player] = "ERR"
   warn("Error fetching "..Player.Name.."'s data."
end
end)
game.Players.PlayerRemoving:Connect(function(Player)
    if Jogo[Player] == "ERR" then return end --If we couldn't get their data, we don't want to save it since it's corrupted
	local suc, err = pcall(function() 
               JogoStore:SetAsync(Player.UserId, Jogo)
    end)
if err then warn("Unable to save data for"..Player.Name) end 
end)

Sorry for the terrible formatting. The Discourse script editor is really sucky.

Thanks for you effort!
Actually, the last code I posted was just a test to confirm why the SetASync was not working, so I removed all error treatment there to clean up the code.
In short, what I realized is: SetASync will work “in-game”, without needing to use BindToClose.
And if you read that code, you’ll notice that the BindToClose is there only to force a wait if it’s inside Studio.

1 Like

@HugeCoolboy2007 is right about the game:BindToClose, however when I use that function the game still saves my data when there are only some values to change, not things to add to my MainTable.

I use game:BindToClose function like this:

game:BindToClose(function()
	for i, player in pairs(game.Players:GetChildren()) do
            -- I save player data here.
        end
end)

By saying this I mean that whenever I add more things to my game to save and I play the game in Studio, add some new currency to my account and play in Studio again- it doesn’t save (even when there’s a game:BindToClose function). If I want to make new data work in Studio, I simply join my game (not in Studio), than I play it in Studio and when it seems that the data loads correctly in Studio too.

1 Like

Are you sure? Because I got the idea for saving the player’s data when the player exits the game from the official Roblox Documentation:
https://developer.roblox.com/en-us/articles/Saving-Player-Data#save-data-on-exit

I was talking about in-studio, not in-game. Sorry, I should’ve clarified

But this will save the data for all players ONLY when the server will shutdown, ie, when the last player exits the game; I want to save the player’s data WHEN a player exits the game.

I know, that’s the proper use of the BindToClose function. I would recommend you using that function and the game:GetService(“Players”).PlayerRemoving function too.

Also, as I’m trying to say, the data DOES NOT ALWAYS saves propertly in Studio, even if DataStore Service is enabled!

Ok, so that’s the solution I put in the post:

1 Like

Why?

I don’t really know why. Try publishing the game, playing it. And now when you change values in Studio, the new changes should be applied.

The last example of me trying to make you understand, @rogeriodec_games what I mean. The reason i have (tagged?) you is to make you see this reply again because I made and edit.

The example:

  1. Game before an update. Everything saves correctly even when I change values of my coins in Studio. Here’s the table (normally I use WaitForChild() function but this is only the example):

    local ExampleTable = {
    Coins= plr.Coins.Value,
    }

  2. I relased the update of my game that adds new thing to my table (my game only had coins value before the update as you can see above, now it also has XP value in it). Here’s the table with XP:

    local ExampleTable = {
    Coins= plr.Coins.Value,
    XP = plr.XP.Value,
    }

  3. I play the game in Studio, change the value of my XP to 10000000 (why not, I’m the game developer lol) and I hit the Stop playtest button.

  4. I join Studio again. Where’s my XP??? The XP didn’t change (I don’t know why, I had DataStore Setting on).

  5. I join a game on Roblox website and give XP to my account again. I leave and join Studio. The XP is here.

  6. I change XP in Studio to 23000 (it can be whatever you like). I leave playtest, join it again and I see that the XP have updated to 23000 even if I was in Studio.

As you can see in the example, the XP data only saved when I joined my game first when the update came out. Then the Studio was able to change XP (after I joined the game on the website).

That’s it. I hope you understand. I tried to help you.


Edit: I was not that good in Roblox scripting as I am now, 6 months later. It is probably caused because what Studio does is following: it closes the server / shuts it down so the PlayerRemoving doesn’t run (only when you click ‘Stop’ button and not ‘Leave’ game button). You can use this code if you always click the ‘Stop’ button:

-- Works when you click 'Stop' button in Studio and not 'Leave' game button.

local function SaveData(player)
	-- Your SaveData function.
end

-- Listen to Player leaving the game.
game:GetService("Players").PlayerRemoving:Connect(function(player)
	if not game:GetService("RunService"):IsStudio() then
		local success = pcall(function()
			SaveData(player)
		end)
	end
end)

-- Listen to server shutting down.
game:BindToClose(function()
	for _, player in pairs(game:GetService("Players"):GetPlayers()) do
		local success = pcall(function()
			SaveData(player)
		end)
	end
end)

That should fix the problem.

5 Likes