Hey, so I’ve made many data store scripts following many YouTube videos. I have API Services on, I have the place published to Roblox, and I am 99% sure that I didn’t mis spell or incorrectly capitalize anything. The problem is that when I leave the game, it doesn’t save and I have tried many different script styles. I would very much appreciate any help, thanks
Here is my script:
local DSS = game:GetService("DataStoreService")
local myDS = DSS:GetDataStore("myDataStore")
game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
print("Made leaderstats!")
local Coins = Instance.new("IntValue")
Coins.Name = "Coins"
Coins.Parent = leaderstats
print("Made Coins!")
local playerUserId = "Player_"..player.UserId
print(playerUserId)
-- Load data
local data -- Makes it work in the WHOLE script
local success, errormessage = pcall(function()
data = myDS:GetAsync(playerUserId)
end)
if success then
Coins.Value = data
-- Set Coins = to the data
print("Loaded data!")
end
end)
game.Players.PlayerRemoving:Connect(function(player)
local playerUserId = "Player_"..player.UserId
local data = player.leaderstats.Coins.Value
local success, errormessage = pcall(function()
myDS:SetAsync(playerUserId, data)
end)
if success then
print("Data save was successfull!")
else
print("Data save failed :(")
warn(errormessage)
end
end)
I believe you’ll want to do a return statement here instead of data =
Try it like this…
local data -- Makes it work in the WHOLE script
local success, results = pcall(function()
return myDS:GetAsync(playerUserId)
end)
if success then
if results then
Coins.Value = results
-- Set Coins = to the data
print("Loaded data!")
end
This could resolve your issue as long as the data is being set into the datastore. One thing to note is that using UpdateAsync is safer than just strictly using SetAsync as you can check the old data before you modify the values.
Inside PlayerAdded…
local initialCoins = 50
local data -- Makes it work in the WHOLE script
local success, results = pcall(function()
return myDS:GetAsync(playerUserId)
end)
if success then
if results then
Coins.Value = results
-- Set Coins = to the data
print("Loaded data!")
else
--If interested in setting the initial value into the datastore immediately if the player doesn't have the value yet set (hasn't joined before)
local s, r = pcall(function()
myDS:SetAsync(playerUserId, initialValue)
end)
end
Inside PlayerRemoving
local success, errormessage = pcall(function()
myDS:UpdateAsync(playerUserId, function(oldValue)
--Inside here you could compare the old data before setting the new data. Good if you don't want players to go backwards in some instances. What if there was a quest they shouldn't be able to do again? We can do this by checking our old values vs the new ones. For our purposes though...
local newValue = player.leaderstats.Coins.Value
return newValue
end)
end)
And as @RareFeeling stated, Game:BindToClose() should be used. Since you’re on studio, it’s closing the game before it can write to the Datastore, which also could happen when published if the last player leaves your server.
Alot of ppl have trouble with trying to save on player removing instead of just that you should do autosave but not just autosave every minute or so only save players data that has changed so it doesn’t overload the datastores as much to do this I edited your code some by moveing your save into a function and calling it on remove and in while loop
also i fixed your Coins.Value = data to Coins.Value = data or 0 because if the player has never had data it can come back nil so set it to 0 as default if you want them to start with 100 coins put the value there
local DSS = game:GetService("DataStoreService")
local myDS = DSS:GetDataStore("myDataStore")
local PlayersToSave = {} -- setup a table to hold players that the data has changed on
local TimeBetweenAutoSave = 60 -- the time between each autosave check if they are in table above to save
function SavePlayersData(player) -- the save function itself call by remove and by autosave
local playerUserId = "Player_"..player.UserId
local data = player.leaderstats.Coins.Value
local success, errormessage = pcall(function()
myDS:SetAsync(playerUserId, data)
end)
if success then
print("Data save was successfull!")
else
print("Data save failed :(")
warn(errormessage)
end
end
game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
print("Made leaderstats!")
local Coins = Instance.new("IntValue")
Coins.Name = "Coins"
Coins.Parent = leaderstats
print("Made Coins!")
local playerUserId = "Player_"..player.UserId
print(playerUserId)
-- Load data
local data -- Makes it work in the WHOLE script
local success, errormessage = pcall(function()
data = myDS:GetAsync(playerUserId) -- !!!! if data has never been set this will return successful and data will be nil
end)
if success then
Coins.Value = data or 0 -- !!!! this will set a default to the coins incase they don't have any data which would be nil
-- Set Coins = to the data
print("Loaded data!")
end
Coins.Changed:Connect(function() -- this catches the change of the coins value either add or subtracted any change to it will then add them to the autosave table for next loop to save the data
table.insert(PlayersToSave,player) -- add the player to this table because their data has changed
end)
end)
game.Players.PlayerRemoving:Connect(function(player)
if table.find(PlayersToSave,player) then -- if the players data changed they will be in this table so save their data on remove else don't -- you can remove this and just do a save here if you want but may overload datastore
SavePlayersData(player) -- save when they leave if it can sometimes this doesn't save in studio
table.remove(PlayersToSave,table.find(PlayersToSave,player)) -- after save then remove them from the table
end
end)
while true do -- this autosave loop only saves player data if it has changed
wait(TimeBetweenAutoSave)
spawn(function() -- spawn incase of error
for _, player in ipairs(PlayersToSave) do -- go through all the players in the PlayersToSave because their data changed and save them
SavePlayersData(player) -- save when they leave if it can sometimes this doesn't save in studio
table.remove(PlayersToSave,table.find(PlayersToSave,player)) -- after save then remove them from the table
end
end)
end
Just to make sure you are changing your coins value on the server correct? if not it will save the value that the server has which would be the default.
as @Nyonic said PlayerRemoving isn’t very reliable in my experience. I haven’t used it in a while so they may have fixed some of the issues but, when the player crashes be it from internet connection going out, pc crashing, or Roblox crashing it doesn’t always fire before the player object is removed. So, typically you would get cases of data loss, but it should still work in your case if you are just leaving. As mentioned several times its probably the server shutting down before the data gets saved so you should try bindtoclose to fix this issue. If you wish to change playerremoving you would have to use game.Players.ChildRemoved:Connect() and you would store your stats somewhere else like replicated storage. This will make it so if the player object is removed you are still able to reference it and the players data.
Yea this is just me using his code and adding the auto save with auto save at 60 seconds they can only lose data up to 1 min ago if crash I have a lot of experience in dealing with datastore on game that was crashing. you can bind to close but either way the best option is to hold a table like the one for saving the player with each players data then access the data with the players name when the removing or bind function is called which allows data access even when player isn’t present in the game only reason it wont totally save is on a server crash out which then your autosave feature would cover this in most cases
This is how my systems are setup and no one has lost data yet on them that I know of
so in his code he could add PlayerData = {} – table then initial PlayerData[Player.Name] = Coins.Value
and when it changes in that function for coins set it there also with PlayerData[Player.Name] = Coins.Value
then in the save function instead of saving the coins value just save the PlayerData[Player.Name]
on playerremoving remove them from the table with PlayerData[Player.Name] = nil
I even have exp with datastore2 which imo isn’t a very good or reliable system in many ways its limited and more complicated than it needs to be (unless it has gotten some good updates over the last year)
Thank you very much Nyonic! I am a beginner but I will try to fully understand this. Your game, Club Nyonic is one of the first games I ever played and I really like it
Nyonic, thank you very much for the script! I used it in my game. I named it CoinsSave and put it in ServerScriptService. I published my place and went on to it via Roblox and increased my coins and it didn’t save I almost think it is a problem with Roblox or something but probably not.
local DSS = game:GetService("DataStoreService")
local myDS = DSS:GetDataStore("myDataStore")
local PlayersToSave = {} -- setup a table to hold players that the data has changed on
local TimeBetweenAutoSave = 60 -- the time between each autosave check if they are in table above to save
function SavePlayersData(player) -- the save function itself call by remove and by autosave
local playerUserId = "Player_"..player.UserId
local data = player.leaderstats.Coins.Value
local success, errormessage = pcall(function()
myDS:SetAsync(playerUserId, data)
end)
if success then
print("Data save was successfull!")
else
print("Data save failed :(")
warn(errormessage)
end
end
game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
print("Made leaderstats!")
local Coins = Instance.new("IntValue")
Coins.Name = "Coins"
Coins.Parent = leaderstats
print("Made Coins!")
local playerUserId = "Player_"..player.UserId
print(playerUserId)
-- Load data
local data -- Makes it work in the WHOLE script
local success, errormessage = pcall(function()
data = myDS:GetAsync(playerUserId) -- !!!! if data has never been set this will return successful and data will be nil
end)
if success then
Coins.Value = data or 0 -- !!!! this will set a default to the coins incase they don't have any data which would be nil
-- Set Coins = to the data
print("Loaded data!")
end
Coins.Changed:Connect(function() -- this catches the change of the coins value either add or subtracted any change to it will then add them to the autosave table for next loop to save the data
table.insert(PlayersToSave,player) -- add the player to this table because their data has changed
end)
end)
game.Players.PlayerRemoving:Connect(function(player)
if table.find(PlayersToSave,player) then -- if the players data changed they will be in this table so save their data on remove else don't -- you can remove this and just do a save here if you want but may overload datastore
SavePlayersData(player) -- save when they leave if it can sometimes this doesn't save in studio
table.remove(PlayersToSave,table.find(PlayersToSave,player)) -- after save then remove them from the table
end
end)
while true do -- this autosave loop only saves player data if it has changed
wait(TimeBetweenAutoSave)
spawn(function() -- spawn incase of error
for _, player in ipairs(PlayersToSave) do -- go through all the players in the PlayersToSave because their data changed and save them
SavePlayersData(player) -- save when they leave if it can sometimes this doesn't save in studio
table.remove(PlayersToSave,table.find(PlayersToSave,player)) -- after save then remove them from the table
end
end)
end
this works fine even in studio it saved for me (which sometimes if you don’t let autosave run studio doesnt save on stop)
i think what your doing wrong here is this is probably a client side or local script
so if you are changing the value with the client you will visually see it change but on the server it is still 0 because it wasn’t changed by the server
to fix this in that mouse click function you should fire a remove event that then changes the value on the server
In studio you can change stuff on the server by toggling the Current: Client button and to get back to client toggle Current: Server button (which it changes into)