Data saving and getting should be wrapped around a pcall() and repeat until loop since data saving can not work sometimes
I believe SetAsync()
only takes 2 parameters - The player and the data being saved. Because of this, it would be best to use tables and simply store your Cash & Diamond values in the table:
game.Players.PlayerRemoving:Connect(function(player)
local data1 = player.leaderstats.Cash.Value
local data2 = player.leaderstats.Diamonds.Value
myDataStore:SetAsync(player.UserId, {
Cash = data1,
Diamonds = data2
})
end)
Noticed how I removed the playerUserId
here. The player’s userId itself will suffice as the key for the data, adding an additional string will do you no good.
Now that the data is being properly saved, upon doing GetAsync()
on the player’s UserId, this is the data that will be returned:
{
Cash = 123, -- Example value
Diamonds = 321
}
It is the exact same table you saved using SetAsync()
in the PlayerRemoving event. Now you can use this to set the value of the Cash and Diamonds when the player joins like this:
game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local Cash = Instance.new("IntValue")
Cash.Name = "Cash"
Cash.Parent = leaderstats
local Diamonds = Instance.new("IntValue")
Diamonds.Name = "Diamonds"
Diamonds.Parent = leaderstats
local data
local success, err = pcall(function()
data = myDataStore:GetAsync(player.UserId)
end)
if success then
--// Get the saved values and set them as the value of Cash & Diamonds
Cash.Value = data.Cash
Diamonds.Value = data.Diamonds
else
--// Warn the error. Alternatively, you can also kick the player if you want
warn(err)
end
while true do
player.leaderstats.Cash.Value += 1
player.leaderstats.Diamonds.Value += 1
task.wait(1)
end
end)
Notice how I also changed the while loop at the end. People say its bad practice to do “while wait do” because it’s just worse on the backend of things, so I did “while true do” and put the wait inside of the loop. Something better to do would be to have one loop that increments everyone’s Cash and Diamonds, but this will suffice here.
You should also use the operators +=, -=, /=, *= to make your calculations faster as I did here.
Keep in mind that data most likely won’t save in Studio, meaning that you’ll need to test data saving & loading by playing the game through the Roblox app.
You can use BindToClose() to save people’s data even when the game shuts down. I won’t be going over this now, but there are tutorials that do.
Hopefully this helps.
So I copied the script and replaced it with my old one, but im receiving an errror.
I have this:
and this:
Btw, thanks for the time and details you put into making a great reply
You forgot to paste the two lines at the top (u actually used that in ur own script just paste them at the top)
local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")
Right, thank you! I did that, and I got this error:
The cash and diamonds isn’t going up each second either.
I forgot to set the data to the table, whoops.
Change this:
if success then
--// Get the saved values and set them as the value of Cash & Diamonds
Cash.Value = data.Cash
Diamonds.Value = data.Diamonds
else
--// Warn the error. Alternatively, you can also kick the player if you want
warn(err)
end
To this:
if success then
--// If they don't have the table as a data, then give them it
if not data or data and typeof(data) ~= "table" then
data = {
Cash = 0,
Diamonds = 0
}
end
--// Get the saved values and set them as the value of Cash & Diamonds
Cash.Value = data.Cash
Diamonds.Value = data.Diamonds
else
--// Warn the error. Alternatively, you can also kick the player if you want
warn(err)
end
Great. It fixed the errors.
Unfortunately, it still doesn’t save…
Sometimes you can’t test things on Studio, sometimes you must test in live-game
I tried in studio and in live game, neither work.
Then try this
-- this is getting the data, put data outside the functions as local data
local success
local playerdata
local attempt = 0
repeat
success, playerdata = pcall(function()
data = myDataStore:GetAsync(player.UserId)
end)
attempt += 1
if not success then
warn(playerdata)
task.wait(3)
end
until success or attempt == 5
if success then
if not playerdata then
playerdata = {
["Cash"] = 0
["Diamonds"] = 0
}
end
data = playerdata
else
warn(err)
end
Cash.Value = data.Cash
Diamonds.Value = data.Diamonds
Cash.Changed:Connect(function()
data.Cash = Cash.Value
end)
Diamonds.Changed:Connect(function(
data.Diamonds = Diamonds.Value
end)
Should I add it to the script?
There is a reason why I wrote that, yes
I meant do you want me to replace the the entire script with it, or just the certain lines of code?
You accidentally set the GetAsync to the wrong variable, change it to this
playerdata = myDataStore:GetAsync(player.UserId)
Edit: Didn’t see the pcall variable lol
No, the second variable is the value it returns
Hi there, I posted something similar regarding leaderstats and datastore: Consider checking this out…
It is well written and you can learn more about datastore and the problem you are currently facing if any
Leaderstats Datastore
Don’t you have to put a return before that though?
success, playerdata = pcall(function()
return myDataStore:GetAsync(player.UserId)
end)
Yea you usually do but in his way it is a bit different but that way you used is way more efficient
Aahh after reading the code you gave, it seems that it does not save when the server is closed (probably how you exit when you are testing the game). You have to consider adding this event:
local Players = game:GetService("Players")
-- fires when the server crashed or closes
game:BindToClose(function()
for _, player in ipairs(Players:GetPlayers()) do
save(player) -- create a function save that saves the data of a player (one at a time)
-- that way you can also use the function save() for when a player leaves the game
end
end)
You’ll need to follow these steps carefully:
- Make sure that the place you’re using/testing the DataStore is published to Roblox. You can’t use/test DataStores in unpublished places like local files
- Go to the Home tab, then click on the Game Settings. When the popup opens, go to Security then make sure you have “Enable Studio Access to API Services” turned on (the switch is colored green when on)
- Finally after making sure you’ve followed the steps above correctly, I made this script you can use for your DataStore:
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")
Players.PlayerAdded:Connect(function(player)
local success, values = pcall(myDataStore.GetAsync, myDataStore, "Player"..player.UserId)
if success then
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local Cash = Instance.new("IntValue")
Cash.Name = "Cash"
Cash.Value = values.Cash
Cash.Parent = leaderstats
local Diamonds = Instance.new("IntValue")
Diamonds.Name = "Diamonds"
Diamonds.Value = values.Diamonds
Diamonds.Parent = leaderstats
while true do
Cash.Value += 1
Diamonds.Value += 1
task.wait()
end
else
warn(values)
end
end)
local function saveData(player)
local leaderstats = player:FindFirstChild("leaderstats")
if leaderstats then
local success, result = pcall(myDataStore.SetAsync, myDataStore, "Player"..player.UserId, {
Cash = leaderstats.Cash.Value,
Diamonds = leaderstats.Diamonds.Value
})
if not success then warn(result) end
end
end
Players.PlayerRemoving:Connect(saveData)
if RunService:IsStudio() then
game:BindToClose(function()
task.wait(4)
end)
else
game:BindToClose(function()
local x, y = 0, 0
for _, player in Players:GetPlayers() do
x += 1
coroutine.wrap(function()
saveData(player)
y += 1
end)()
end
repeat task.wait() until y == x
end)
end