My XP doesn't save if I add myself some money through the explorer in the studio even if I team test, but if I earn the XP slowly like it's supposed to it saves. Xpn and lvl doesn't save at all.
RebirthData = game:GetService("DataStoreService"):GetDataStore("Data1911") XpData = game:GetService("DataStoreService"):GetDataStore("Data1912") KillsData = game:GetService("DataStoreService"):GetDataStore("Data1913") DeathsData = game:GetService("DataStoreService"):GetDataStore("Data1914") LvlData = game:GetService("DataStoreService"):GetDataStore("Data1915") XpnData = game:GetService("DataStoreService"):GetDataStore("Data1916") ----------------------------------------------------------------------------------- game.Players.PlayerAdded:Connect(function(plr) local LB = Instance.new("Folder", plr) LB.Name = "leaderstats" local K = Instance.new("IntValue", LB) K.Name = "Kills" K.Value = KillsData:GetAsync(plr.userId) or 0 local Xp = Instance.new ("IntValue", plr) Xp.Name = "XP" Xp.Value = XpData:GetAsync(plr.userId) or 0 local lvl = Instance.new ("IntValue", plr) lvl.Name = "lvl" lvl.Value = LvlData:GetAsync(plr.userId) or 1 local D = Instance.new("IntValue", LB) D.Name = "Deaths" D.Value = DeathsData:GetAsync(plr.userId) or 0 local Xpn = Instance.new("IntValue", plr) Xpn.Name = "XpNeeded" Xpn.Value = XpnData:GetAsync (plr.userId) or 50 Xpn.Value = 50 local r = Instance.new("IntValue", LB) r.Name = "Rebirths" r.Value = RebirthData:GetAsync(plr.userId) or 0 plr.CharacterAdded:Connect(function(char) local humanoid repeat humanoid = char:FindFirstChild("Humanoid") wait() until humanoid humanoid.Died:Connect(function() D.Value = D.Value+1 local tag = humanoid:FindFirstChild("creator") if tag then local killer = tag.Value if killer then killer.leaderstats.Kills.Value = killer.leaderstats.Kills.Value + 1 killer.XP.Value = killer.XP.Value + math.random (5,10) end end end) end) end) game.Players.PlayerRemoving:Connect(function(plr) XpData:SetAsync(plr.userId, plr.XP.Value) KillsData:SetAsync(plr.userId, plr.leaderstats.Kills.Value) DeathsData:SetAsync(plr.userId, plr.leaderstats.Deaths.Value) RebirthData:SetAsync(plr.userId, plr.leaderstats.Rebirths.Value) LvlData:SetAsync(plr.userId, plr.lvl.Value) XpnData:SetAsync(plr.userId, plr.XpNeeded.Value) end)
As you may already know, data stores are used to save data so that they can be loaded in again whenever a player joins the game.
Data stores are like tables, you can set a key to a value. This value can be a string, number, or a table. Conventionally, tables are used as they can store much more than a string or number can.
-- Example of how tables are similar to how datastores work local tab = {} -- a table tab["Key"] = "Value" -- a value can be set to a key local tabValue = tab["Key"] -- the value of a key can be accessed local DsService = game:GetService("DataStoreService") local example = DSService:GetDataStore("Example") example:SetAsync("Key", "Value") -- a value can be set to a key local exValue = example:GetAsync("Key") -- the value of a key can be accessed
This not only means that you can reduce all your data stores into one, but it also helps to solve your issue of data not saving. This is due to the limitations DataStores have. You can only save data to a key a limited amount of times within a time frame. This is to prevent people from sending thousands of requests for Roblox to save their data which would clog up Roblox's servers.
For more detailed information on these limits, click here.
You have to restructure how your data storage system works. Firstly, create a main data store that would contain every player's data. Since the data you have seems to be stats of a player, we'll call it stats.
local DsService = game:GetService("DataStoreService") local Stats = DsService:GetDataStore("Stats")
Then, we set the player's data whenever they join. We will be using their user id as the key. If they have joined the first time, they would not have a value associated with their key, so attempting to use GetAsync would return nil. So we would set their data as the default data, which we would need to create as such:
local DefaultData = { ["Xp"] = 0, ["XpNeeded"] = 0, ["Kills"] = 0, ["Deaths"] = 0, ["Level"] = 0 }
Now we can set up the PlayerAdded event
local Players = game.Players Players.PlayerAdded:Connect(function(plr) -- Set the variable data to be the player's current table of stats -- If they joined for the first time, GetAsync would return nil -- and the variable data will be set to DefaultData local data = Stats:GetAsync(plr.UserId) or DefaultData -- Create the leaderstats folder to store the player's stats local leaderstats = Instance.new("Folder") leaderstats.Parent = plr leaderstats.Name = "leaderstats" end)
We have to add each stat that the player has in their table of data. However, there are 5 pieces of data. Xp, XpNeeded, Kills, Deaths and Level. If we were to create the ValueObject of each stat individually, we would end up with a long series of repeated code which would make it difficult to read.
We can solve this using a for loop that goes through the player's data, create the ValueObjects based on the data type of the value, as such:
Players.PlayerAdded:Connect(function(plr) local data = Stats:GetAsync(plr.UserId) or DefaultData local leaderstats = Instance.new("Folder") leaderstats.Parent = plr leaderstats.Name = "leaderstats" for key, value in pairs(data) do -- Initialise the variable valueObject to store -- the value instance later on based on the value's data type local valueObject if type(value) == "string" then -- If value is a string, create a string value valueObject = Instance.new("StringValue") elseif type(value) == "number" then -- If value is a number, create a number value valueObject = Instance.new("NumberValue") end -- Set the valueObject's parent to leaderstats valueObject.Parent = leaderstats -- Set the valueObject's name to the key, which would be the stat's name valueObject.Name = key -- Set the valueObject's value valueObject.Value = value end end)
Now we have to be able to set their data when it needs to be updated, then save it when they leave. But how can we do this without possibly using SetAsync/GetAsync multiple times within a limited time frame?
We create a table that contains every player's data from when they joined the game, and update it whenever it needs to. We then access this table whenever we need to save someone's data. This removes the need to use SetAsync whenever someone's stat is changed while they are still in-game.
We'll call this table sessionData, since it would hold the data of each player for that session
local sessionData = {} Players.PlayerAdded:Connect(function(plr) local data = Stats:GetAsync(plr.UserId) or DefaultData local leaderstats = Instance.new("Folder") leaderstats.Parent = plr leaderstats.Name = "leaderstats" for key, value in pairs(data) do local valueObject if type(value) == "string" then valueObject = Instance.new("StringValue") elseif type(value) == "number" then valueObject = Instance.new("NumberValue") end valueObject.Parent = leaderstats valueObject.Name = key valueObject.Value = value end -- Set the data as the value to the key (player's user id) in sessionData sessionData[plr.UserId] = data end)
We're almost done! Now all there's left to do is saving the player's data when they leave the game, and automatically save players' data every minute or so while we're at it.
Players.PlayerRemoving:Connect(function(plr) -- Set the player's data by accessing sessionData Stats:SetAsync(plr.UserId, sessionData[plr.UserId]) end) while true do for _, plr in pairs(game.Players:GetPlayers()) do Stats:SetAsync(plr.UserId, sessionData[plr.UserId]) end wait(60) end
And we're done! A simple, though not perfect, data storage system is now complete. There are many ways to improve this data store (catching potential errors from SetAsync/GetAsync, a better way to automatically save without having to worry about limits, and much more), but that's a bit more advanced.
If you're adding on to the code, remember to write your code before the while loop! Otherwise, your code wouldn't run because the while loop would be running forever, not giving your code a chance to run :( (you can use the spawn function on the while loop if you really want to write code after it)
Remember to mark this as the answer if it solved your problem!