Hello, I've been struggling with getting this script to work. Focusing on the saving side, the word "Test" prints, but doesn't print "Saved Value", neither does it print any error. I'd appreciate it if anyone could identify what I've done wrong. (There's a folder called PlayerData within the Player, and a SaveOther folder within the PlayerData folder, containing a few values)
game.Players.PlayerRemoving:connect(function(player) local datastore = game:GetService("DataStoreService"):GetDataStore(player.Name.."aStats") local statstorage = player.PlayerData.SaveOther:GetChildren() print (datastore) print (player.PlayerData.SaveOther) for i =1, #statstorage do print "Test" datastore:SetAsync(statstorage[i].Name, statstorage[i].Value) print("Saved value "..i) end print("Stats successfully saved") end)
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:
-- Player service local players = game:GetService("Players") -- The Global Data Store local datastore = game:GetService("DataStoreService") -- A created data file named "PlayerStats" local playerstats = datastore:GetDataStore("PlayerStats") Players.PlayerRemoving:connect(function(player) -- Here is the loaded player data. I also recommend using the player's UserId, and not Name. That way if the player changed their username, their data will still be saved. local data = playerstats:GetAsync(player.UserId.."_stats") local statstorage = player.PlayerData.SaveOther:GetChildren() -- A variable that will return true if the player's past data doesn't exist. This way we can use UpdateAsync instead of SetAsync if necessary. local newplayer = data==nil -- Let's save the actual data as a table, so we don't need to create multiple keys for it. local saved = {} -- Store the physical representation of the player's data in the "saved" table for i =1, #statstorage do saved[i] = v end -- The final condition. "Stats" will be the name of the key. if newplayer then -- If it's the player's first time, use SetAsync. playerstats:SetAsync("Stats",saved) else -- If they have a history of previous data, Update it. -- "Old" is the argument that represents past data. Here, we're just overwriting all it's keys to everything in the "saved" table, the returning it to the update process. 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.