omg that code is beautiful. As i was reading through it, it all just clicked together and i see why its going to work much better than my old code lol. I have one question though! Technically, my game is comprised of three separate parts. So these are all of the values i need to save:
Deaths1
Escapes1
Deaths2
Escapes2
Deaths3
Escapes3
I have adjusted the code accordingly. Can you take a quick glance at it and tell me if it’s all good to go? (i only want the Deaths1 and Escapes1 to appear in leaderstats btw).
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")
local function SaveData(player, data)
local success, errorMessage = pcall(function()
playerDataStore:SetAsync(player.UserId, data)
end)
if not success then
warn(errorMessage)
end
end
local function OnPlayerRemoving(player)
local leaderstats = player.leaderstats
local data = {
Deaths1 = leaderstats["Deaths I"].Value,
Escapes1 = leaderstats["Escapes I"].Value,
Deaths2 = leaderstats["Deaths II"].Value,
Escapes2 = leaderstats["Escapes II"].Value,
Deaths3 = leaderstats["Deaths III"].Value,
Escapes3 = leaderstats["Escapes III"].Value
}
SaveData(player, data)
end
Players.PlayerAdded:Connect(function(player)
local playerData = playerDataStore:GetAsync(player.UserId) or {
Deaths1 = 0,
Escapes1 = 0,
Deaths2 = 0,
Escapes2 = 0,
Deaths3 = 0,
Escapes3 = 0
}
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
local deaths1 = Instance.new("IntValue")
deaths1.Name = "Deaths I"
deaths1.Value = playerData.Deaths1
deaths1.Parent = leaderstats
local escapes1 = Instance.new("IntValue")
escapes1.Name = "Escapes I"
escapes1.Value = playerData.Escapes1
escapes1.Parent = leaderstats
leaderstats.Parent = player
end)
Players.PlayerRemoving:Connect(OnPlayerRemoving)
game:BindToClose(function()
for i, player in Players:GetPlayers() do
task.spawn(OnPlayerRemoving, player)
end
end)
You may have connected your Deaths II, Escape II, and the others wrong since you didn’t put them in leaderstats. You also have to set the aforementioned values in your code.
What you may want:
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")
local function SaveData(player, data)
local success, errorMessage = pcall(function()
playerDataStore:SetAsync(player.UserId, data)
end)
if not success then
warn(errorMessage)
end
end
local function OnPlayerRemoving(player)
local leaderstats = player.leaderstats
local otherFolder = player.OtherFolder
local data = {
Deaths1 = leaderstats["Deaths I"].Value,
Escapes1 = leaderstats["Escapes I"].Value,
Deaths2 = otherFolder["Deaths II"].Value,
Escapes2 = otherFolder["Escapes II"].Value,
Deaths3 = otherFolder["Deaths III"].Value,
Escapes3 = otherFolder["Escapes III"].Value
}
SaveData(player, data)
end
Players.PlayerAdded:Connect(function(player)
local playerData = playerDataStore:GetAsync(player.UserId) or {
Deaths1 = 0,
Escapes1 = 0,
Deaths2 = 0,
Escapes2 = 0,
Deaths3 = 0,
Escapes3 = 0
}
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
local deaths1 = Instance.new("IntValue")
deaths1.Name = "Deaths I"
deaths1.Value = playerData.Deaths1
deaths1.Parent = leaderstats
local escapes1 = Instance.new("IntValue")
escapes1.Name = "Escapes I"
escapes1.Value = playerData.Escapes1
escapes1.Parent = leaderstats
leaderstats.Parent = player
local otherFolder = player:WaitForChild("OtherFolder")
otherFolder["Deaths II"].Value = playerData.Deaths2
otherFolder["Escapes II"].Value = playerData.Escapes2
otherFolder["Deaths III"].Value = playerData.Deaths3
otherFolder["Escapes III"].Value = playerData.Escapes3
end)
Players.PlayerRemoving:Connect(OnPlayerRemoving)
game:BindToClose(function()
for i, player in Players:GetPlayers() do
task.spawn(OnPlayerRemoving, player)
end
end)
It may also be preferable for you to create the OtherFolder in this script too, as it will be easier to manage later. It’s your choice though, so do as you like.
By the way, the reason why studio bugs out is because sometimes the server will close before the player leaves (which will never happen in a real game), therefore not being able to save the data.
It could be because the player’s data fails to load in, causing their save to “reset” back to zero when they leave. You could probably kick the player from the game and tell the PlayerRemoving function not to save the incorrect data.
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")
local defaultData = {
leaderstats = {
["Deaths I"] = 0,
["Escapes I"] = 0
},
storedData = {
["Deaths II"] = 0,
["Escapes II"] = 0,
["Deaths III"] = 0,
["Escapes III"] = 0
}
}
local function SaveData(player, data)
local success, errorMessage = pcall(function()
playerDataStore:SetAsync(player.UserId, data)
end)
if not success then
warn(errorMessage)
end
end
local function OnPlayerRemoving(player)
local data = defaultData
for folderName, folderValues in defaultData do
local folder = player[folderName]
for valueName, _ in folderValues do
data[folderName][valueName] = folder[valueName].Value
end
end
SaveData(player, data)
end
Players.PlayerAdded:Connect(function(player)
local playerData = playerDataStore:GetAsync(player.UserId) or defaultData
for folderName, folderValues in defaultData do
local folder = Instance.new("Folder")
folder.Name = folderName
for valueName, _ in folderValues do
local intValue = Instance.new("IntValue")
intValue.Name = valueName
intValue.Value = playerData[folderName][valueName]
intValue.Parent = folder
end
folder.Parent = player
end
end)
Players.PlayerRemoving:Connect(OnPlayerRemoving)
game:BindToClose(function()
for i, player in Players:GetPlayers() do
task.spawn(OnPlayerRemoving, player)
end
end)
I’ve refactored your code to be easier to read, you will have to reset your data for this to work.
Command to reset data (put it in your command bar):
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")
playerDataStore:RemoveAsync(YourId)
Also, further elaborating on this:
If you want to test saving in studio, open up a Local Server test, as it will emulate how an actual game would work.
You’re going to have to load all the data anyways to keep it persistent, so you can keep it as is.
If you want to hide the leaderstats though, you can do this:
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")
local defaultData = {
leaderstats = {
["Deaths I"] = 0,
["Escapes I"] = 0
},
storedData = {
["Deaths II"] = 0,
["Escapes II"] = 0,
["Deaths III"] = 0,
["Escapes III"] = 0
}
}
local leaderstatsName = game.PlaceId == firstPlace and "leaderstats" or "folder"
local function SaveData(player, data)
local success, errorMessage = pcall(function()
playerDataStore:SetAsync(player.UserId, data)
end)
if not success then
warn(errorMessage)
end
end
local function OnPlayerRemoving(player)
local data = defaultData
for folderName, folderValues in defaultData do
local folder = player[folderName == "leaderstats" and leaderstatsName or folderName]
for valueName, _ in folderValues do
data[folderName][valueName] = folder[valueName].Value
end
end
SaveData(player, data)
end
Players.PlayerAdded:Connect(function(player)
local playerData = playerDataStore:GetAsync(player.UserId) or defaultData
for folderName, folderValues in defaultData do
local folder = Instance.new("Folder")
folder.Name = folderName == "leaderstats" and leaderstatsName or folderName
for valueName, _ in folderValues do
local intValue = Instance.new("IntValue")
intValue.Name = valueName
intValue.Value = playerData[folderName][valueName]
intValue.Parent = folder
end
folder.Parent = player
end
end)
Players.PlayerRemoving:Connect(OnPlayerRemoving)
game:BindToClose(function()
for i, player in Players:GetPlayers() do
task.spawn(OnPlayerRemoving, player)
end
end)
When i go to my second place, for example, though it doesn’t load my saved Part 1 values.
Here’s the code for the second place:
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")
local defaultData = {
leaderstats = {
["Deaths II"] = 0,
["Escapes II"] = 0,
},
storedData = {
["Deaths I"] = 0,
["Escapes I"] = 0,
["Deaths III"] = 0,
["Escapes III"] = 0
}
}
local leaderstatsName = game.PlaceId == myreal2ndplaceidishere and "leaderstats" or "folder"
local function SaveData(player, data)
local success, errorMessage = pcall(function()
playerDataStore:SetAsync(player.UserId, data)
end)
if not success then
warn(errorMessage)
end
end
local function OnPlayerRemoving(player)
local data = defaultData
for folderName, folderValues in defaultData do
local folder = player[folderName == "leaderstats" and leaderstatsName or folderName]
for valueName, _ in folderValues do
data[folderName][valueName] = folder[valueName].Value
end
end
SaveData(player, data)
end
Players.PlayerAdded:Connect(function(player)
local playerData = playerDataStore:GetAsync(player.UserId) or defaultData
for folderName, folderValues in defaultData do
local folder = Instance.new("Folder")
folder.Name = folderName == "leaderstats" and leaderstatsName or folderName
for valueName, _ in folderValues do
local intValue = Instance.new("IntValue")
intValue.Name = valueName
intValue.Value = playerData[folderName][valueName]
intValue.Parent = folder
end
folder.Parent = player
end
end)
Players.PlayerRemoving:Connect(OnPlayerRemoving)
game:BindToClose(function()
for i, player in Players:GetPlayers() do
task.spawn(OnPlayerRemoving, player)
end
end)
That is what i want, but when i check the storedData folder inside of the Player, where Deaths1, Escapes1, Deaths3, & Escapes3 should all be, they’re in the folder but their values are all at zero, so they didn’t save from place 1 or place 3. I’m trying to get all of the data to transfer to the other places because in my Lobby place i have leaderboards for each of the different values.
Oh, I just realized you did it wrong. If you want the leaderstats to only show the current world’s count, then we have to do something different.
Code:
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")
local defaultData = {
["Deaths I"] = 0,
["Escapes I"] = 0,
["Deaths II"] = 0,
["Escapes II"] = 0,
["Deaths III"] = 0,
["Escapes III"] = 0
}
local leaderstatValues = {"Death I", "Escapes I"} -- Change this depending on level
local function SaveData(player, data)
local success, errorMessage = pcall(function()
playerDataStore:SetAsync(player.UserId, data)
end)
if not success then
warn(errorMessage)
end
end
local function OnPlayerRemoving(player)
local leaderstats = player.leaderstats
local storedData = player.storedData
local data = {}
for valueName, _ in defaultData do
data[valueName] = table.find(leaderstatValues, valueName) and leaderstats[valueName].Value or storedData[valueName].Value
end
SaveData(player, data)
end
Players.PlayerAdded:Connect(function(player)
local playerData = playerDataStore:GetAsync(player.UserId) or defaultData
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
local storedData = Instance.new("Folder")
storedData.Name = "storedData"
for valueName, _ in defaultData do
local intValue = Instance.new("IntValue")
intValue.Name = valueName
intValue.Value = playerData[valueName]
intValue.Parent = table.find(leaderstatValues, valueName) and leaderstats or storedData
end
leaderstats.Parent = player
storedData.Parent = player
end)
Players.PlayerRemoving:Connect(OnPlayerRemoving)
game:BindToClose(function()
for i, player in Players:GetPlayers() do
task.spawn(OnPlayerRemoving, player)
end
end)
Do i need to reset everybody’s data as well? because there are a couple of other people that have tested my game out and they have data. Is there a way to reset all data? if that’s what i need to do?
local DSS = game:GetService("DataStoreService")
local DataStore = DSS:GetDataStore("playerData")
local KeysPages = DataStore:ListKeysAsync()
while true do
local CurrentKeysPage = KeysPages:GetCurrentPage()
for j, Key in pairs(CurrentKeysPage) do
DataStore:RemoveAsync(Key.KeyName)
end
if KeysPages.IsFinished then break end
KeysPages:AdvanceToNextPageAsync()
end
If you want me to implement a way that preserves their data, tell me. There will be a performance cost though.
The data still isn’t saving or transferring.
Code:
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("playerData")
local defaultData = {
["Deaths I"] = 0,
["Escapes I"] = 0,
["Deaths II"] = 0,
["Escapes II"] = 0,
["Deaths III"] = 0,
["Escapes III"] = 0
}
local leaderstatValues = {"Deaths I", "Escapes I"} -- Change this depending on level
local function SaveData(player, data)
local success, errorMessage = pcall(function()
playerDataStore:SetAsync(player.UserId, data)
end)
if not success then
warn(errorMessage)
end
end
local function OnPlayerRemoving(player)
local leaderstats = player.leaderstats
local storedData = player.storedData
local data = {}
for valueName, _ in defaultData do
data[valueName] = table.find(leaderstatValues, valueName) and leaderstats[valueName] or storedData[valueName]
end
SaveData(player, data)
end
Players.PlayerAdded:Connect(function(player)
local playerData = playerDataStore:GetAsync(player.UserId) or defaultData
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
local storedData = Instance.new("Folder")
storedData.Name = "storedData"
for valueName, _ in defaultData do
local intValue = Instance.new("IntValue")
intValue.Name = valueName
intValue.Value = playerData[valueName]
intValue.Parent = table.find(leaderstatValues, valueName) and leaderstats or storedData
end
leaderstats.Parent = player
storedData.Parent = player
end)
Players.PlayerRemoving:Connect(OnPlayerRemoving)
game:BindToClose(function()
for i, player in Players:GetPlayers() do
task.spawn(OnPlayerRemoving, player)
end
end)
I ran the command for myself a couple of times on accident lol. And i ran the one that resets all datastores once.
Here’s what’s in the Output:
DataStoreService: CantStoreValue: Cannot store Dictionary in data store. Data stores can only accept valid UTF-8 characters. API: SetAsync, Data Store: playerData - Studio
Cannot store Dictionary in data store. Data stores can only accept valid UTF-8 characters. - Server - Leaderstats/Datastore:22