Suggestion
As eLunate said, having the game close before saving the data to data store can be problematic, and using his example of the game.OnClose callback should be implemented. However, you have slightly bigger problems in this case.
How Data Store works?
Here is a simple manifestation of how data store works:
Global Data Store > Data Store File > Keys / Values
We could even demonstrate this example using Lua tables. In which case, it'd look something like this:
local GlobalDataStore = {
DataStorage1 = {
["Kills"] = 10,
["Deaths"] = 0
},
DataStorage2 = {
["Kills"] = 12,
["Deaths"] = 1
}
}
Where GlobalDataStore is the DataStoreService, DataStorage1 / DataStorage2 are the data files created with the GetDataStore method on the DataStoreService, and the Kills / Deaths are the Keys / Values associated with the created "data files".
What's the point of all that?
The reason I'm explaining this is because of the way you've created your data store system. The only thing that should change in the DataStoreService while the game is running, are the Keys / Values of a data file.
Instead of saving new keys / values to the data store, you're actually created entire new data files each time a player leaves the game (that GetDataStore method within your PlayerRemoving event is the one responsible for this)
Solution?
What you're gonna wanna do, is create your data file head-on at the beginning of your program, then use Get/Set/Update Async to modify that created file, in whatever system you have to manage that (in this case, your PlayerRemoving event).
Here's a revised version of the code you provided implementing the solution above:
local players = game:GetService("Players")
local datastore = game:GetService("DataStoreService")
local playerstats = datastore:GetDataStore("PlayerStats")
Players.PlayerRemoving:connect(function(player)
local data = playerstats:GetAsync(player.UserId.."_stats")
local statstorage = player.PlayerData.SaveOther:GetChildren()
local newplayer = data==nil
local saved = {}
for i =1, #statstorage do
saved[i] = v
end
if newplayer then
playerstats:SetAsync("Stats",saved)
else
playerstats:UpdateAsync("Stats",function(Old)
for i,v in next, saved do
Old[i] = v
end
return Old
end)
end
end)
Hope that helped, let me know if you have any questions.
2 comments
There's a possibility that statstorage has a length of 0
It appears that PlayerData gets removed before it's had a chance to save the data, although thanks for your help.