Hello. My data saving script isn’t working, and I can’t figure out what’s wrong with it.
local DSS = game:GetService("DataStoreService")
local DS = DSS:GetDataStore("ArksieData", "Players")
local function GenerateDataKey(Player)
local Key = "UID_" .. Player.UserId
return Key
end
game.Players.PlayerAdded:connect(function(Player)
local ls = Instance.new("Folder")
ls.Name = "leaderstats"
ls.Parent = Player
local bits = Instance.new("IntValue")
bits.Name = "Bits"
bits.Value = 10 --starter amt
bits.Parent = ls
local key = GenerateDataKey(Player)
local data = DS:GetAsync(key)
if data then
bits.Value = data.Bits
end
end)
game.Players.PlayerRemoving:Connect(function(Player)
local key = GenerateDataKey(Player)
local data = {
Bits = Player.leaderstats.Bits.Value,
}
local success,err = pcall(function()
DS:SetAsync(key, data)
end)
if not success then
warn('ArksieData Error: '..err)
end
end)
Did you try adding prints statements? I.E. printing out the player.leaderstats.Bits.Value right before set aysnc to see if its an issue with your leaderstats not being updated correctly vs the data itself? Is there any errors besides its not working?
Datastores almost never work in studio, even if you are sure that it should work in studio, try testing it in roblox, and not roblox studio if you haven’t already.
Thanks @Babybunnyiscute19. But 1 more question. How do I use GlobalDataStore. Here’s the code I have right now. (The game is a place inside the main game)
local DSS = game:GetService("DataStoreService")
local DS = DSS:GetGlobalDataStore("ArksieData")
local function GenerateDataKey(Player)
local Key = "UID_" .. Player.UserId
return Key
end
game.Players.PlayerAdded:Connect(function(player)
local ls = Instance.new("Folder")
ls.Name = "leaderstats"
ls.Parent = player
local bits = Instance.new("IntValue")
bits.Name = "Bits"
bits.Value = 10 --starter amt
bits.Parent = ls
local key = GenerateDataKey(player)
local data = nil
local success,err = pcall(function()
data = DS:GetAsync(key)
end)
if not success then
warn(err)
end
if data then
print(data.Bits)
bits.Value = data.Bits
else
print('no data')
end
end)
game.Players.PlayerRemoving:Connect(function(player)
local key = GenerateDataKey(player)
local data = {
Bits = player.leaderstats.Bits.Value,
}
local success, err = pcall(function()
DS:SetAsync(key, data)
end)
if not success then
warn(err)
end
end)
Well every function you add to game:BindToClose once the server starts to shutdown. 30 seconds after that the server just kills any code that was running anyway if it took longer than that.
Basically :BindToClose is used for doing stuff when a server is about to shutdown and make it so that you can finish everything and make it so that the server takes a bit longer to shutdown.
What you wanna do on a :BindToClose callback is save everyone’s data and make the function yield until that finishes.
Here’s a pseudo code example for that:
game:BindToClose(function()
local players = Players:GetPlayers()
local leftToSave = #players
for _, player in ipairs(players) do
coroutine.wrap(function()
local success, errorMessage = pcall(function()
DataStore:SetAsync("Player_".. player.UserId, "data")
end)
leftToSave -= 1
end)()
end
while leftToSave >= 1 do
RunService.Heartbeat:Wait()
end
end)
There are more factors and improvements you can do, but this is the basis
game:BindToClose(function()
local players = game.Players:GetPlayers()
local leftToSave = #players
for _, player in ipairs(players) do
coroutine.wrap(function()
local data = {
Bits = player.leaderstats.Bits.Value,
}
local success, errorMessage = pcall(function()
DS:SetAsync(GenerateDataKey(player), data)
end)
leftToSave -= 1
end)()
end
while leftToSave >= 1 do
game:GetService("RunService").Heartbeat:Wait()
end
end)
Is this everytime you close the game?
Well, what you can do is store what players have their data loaded, which is better anyways.
You should be only saving their data if their data was even loaded anyways
Otherwise you would be replacing their data with empty data accidentally!
If you want more improvements to your saving like using :UpdateAsync and other things (handling OnPlayerAdded function properly on startup), you can ask on DMs :P
Example:
--\\ pseudo code hehee
local LOADED_PLAYERS = {}
Players.PlayerAdded:Connect(function(player)
--\\ Loads data and stuff
LOADED_PLAYERS[player] = true
end)
Players.PlayerRemoving:Connect(function(player)
if not LOADED_PLAYERS[player] then return end;
LOADED_PLAYERS[player] = nil
--\\ try saving data
end)
game:BindToClose(function()
local leftToSave = 0
for player in pairs(LOADED_PLAYERS) do
LOADED_PLAYERS[player] = nil
leftToSave += 1
coroutine.wrap(function()
--\\ Try saving data
leftToSave -= 1
end)()
end
while leftToSave > 0 do
RunService.Heartbeat:Wait()
end
end)
Now it doesn’t seem to be saving. Here’s the full code.
local DSS = game:GetService("DataStoreService")
local DS = DSS:GetGlobalDataStore("ArksieData")
local LOADED_PLAYERS = {}
local function GenerateDataKey(Player)
local Key = "UID_" .. Player.UserId
return Key
end
game.Players.PlayerAdded:Connect(function(player)
LOADED_PLAYERS[player] = true
local ls = Instance.new("Folder")
ls.Name = "leaderstats"
ls.Parent = player
local bits = Instance.new("IntValue")
bits.Name = "Bits"
bits.Value = 10 --starter amt
bits.Parent = ls
local key = GenerateDataKey(player)
local data = nil
local success,err = pcall(function()
data = DS:GetAsync(key)
end)
if not success then
warn(err)
end
if data then
print(data.Bits)
bits.Value = data.Bits
else
print('no data')
end
end)
game.Players.PlayerRemoving:Connect(function(player)
if not LOADED_PLAYERS[player] then return end;
LOADED_PLAYERS[player] = nil
local key = GenerateDataKey(player)
local data = {
Bits = player.leaderstats.Bits.Value,
}
local success, err = pcall(function()
DS:SetAsync(key, data)
end)
if not success then
warn(err)
end
end)
game:BindToClose(function()
local leftToSave = 0
for player in pairs(LOADED_PLAYERS) do
LOADED_PLAYERS[player] = nil
leftToSave += 1
coroutine.wrap(function()
local data = {
Bits = player.leaderstats.Bits.Value,
}
local success, errorMessage = pcall(function()
DS:SetAsync(GenerateDataKey(player), data)
end)
leftToSave -= 1
end)()
end
local RunService = game:GetService("RunService")
while leftToSave > 0 do
RunService.Heartbeat:Wait()
end
end)
Oh sorry! I don’t know if you edited it or something or I just didn’t notice.
Can you do some printing? Add some prints to when PlayerAdded fires, PlayerRemoving fires, BindToClose and maybe print LOADED_PLAYERS…
also you’re supposed to do LOADED_PLAYERS[player] = true AFTER the data is loaded
Also if you can, make it so that the PlayerAdded function is a local variable instead (called OnPlayerAdded in this case) and make it handle already loaded players like this.
local function OnPlayerAdded(player)
--// lol code
end
for _, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(OnPlayerAdded)(player)
end
Players.PlayerAdded:Connect(OnPlayerAdded)