Hello.
I am trying to make a simple system that will save an array as a datastore.
But I have an issue:
Right now I am using this script:
game.Players.PlayerAdded:connect(function(player)
local CurrentExp = player:WaitForChild(“PlayerGui”):WaitForChild(“EXPBarUP”).CurrentExp
local GetSync = AllDataStores:GetAsync(player.UserId)
if GetSync ~= nil then
CurrentExp.Value = GetSync[3]
DataStoreFunction:FireClient(player, GetSync[1], GetSync[2])
end
DataStoreFunction.OnServerEvent:Connect(function(Player, BlueSizeTransfer, MaxExpTransfer, CurrentExpTransfer)
local TransferValues = {BlueSizeTransfer, MaxExpTransfer, CurrentExpTransfer}
AllDataStores:SetAsync(player.UserId, TransferValues)
end)
end)
It uploads every time the CurrentExp changes, it causes many warnings because the CurrentExp changes every a few seconds, but it works.
I tried making the same with PlayerAdded and PlayerRemoving, which looks like that:
game.Players.PlayerAdded:connect(function(player)
local CurrentExp = player:WaitForChild(“PlayerGui”):WaitForChild(“EXPBarUP”).CurrentExp
local GetSync = AllDataStores:GetAsync(player.UserId)
if GetSync ~= nil then
CurrentExp.Value = GetSync[3]
DataStoreFunction:FireClient(player, GetSync[1], GetSync[2])
end
end)
game.Players.PlayerRemoving:Connect(function(player)
local TransferValues = {BlueSizeTransfer, MaxExpTransfer, CurrentExpTransfer}
AllDataStores:SetAsync(player.UserId, TransferValues)
end)
But no matter of hard I tried, it literally not saves, and everytime sets all the values to 0.
What may be the issue?
I personally think player removing is bad anyway. My experience is that when a player crashes it doesnt fire, when a players internet goes out it doesn’t fire. so I just use game.Players.ChildRemoved:Connect() that seems to always work for me unless they updated player removing.
I think your issue is different though you probably need bind to close which will run right before a server shuts down.
PlayerRemoving isn’t bad. Not only is it the proper way of checking for when a player leaves and not ChildRemoved, but the former fires before the latter. PlayerRemoving fires before the actual Player instance is destroyed and is recommended for use when saving data.
This seems more like an implementation issue, but it’s hard to read because the code is not formatted properly. From what I can see though, the transfer variables are only defined for the RemoteEvent and not for PlayerRemoving, so naturally that function doesn’t know what those values are.
@Araxon Could you supply the code you are working with altogether but formatted correctly? You can format best by using a code block. Above and below your code, add three backticks (`). At the top three backticks, you can also add lua.
game.Players.PlayerAdded:connect(function(player)
local CurrentExp = player:WaitForChild(“PlayerGui”):WaitForChild(“EXPBarUP”).CurrentExp
local GetSync = AllDataStores:GetAsync(player.UserId)
if GetSync ~= nil then
CurrentExp.Value = GetSync[3]
DataStoreFunction:FireClient(player, GetSync[1], GetSync[2])
end
DataStoreFunction.OnServerEvent:Connect(function(Player, BlueSizeTransfer, MaxExpTransfer, CurrentExpTransfer)
local TransferValues = {BlueSizeTransfer, MaxExpTransfer, CurrentExpTransfer}
AllDataStores:SetAsync(player.UserId, TransferValues)
end)
end)
game.Players.PlayerAdded:connect(function(player)
local CurrentExp = player:WaitForChild(“PlayerGui”):WaitForChild(“EXPBarUP”).CurrentExp
local GetSync = AllDataStores:GetAsync(player.UserId)
if GetSync ~= nil then
CurrentExp.Value = GetSync[3]
DataStoreFunction:FireClient(player, GetSync[1], GetSync[2])
end
end)
game.Players.PlayerRemoving:Connect(function(player)
local TransferValues = {BlueSizeTransfer, MaxExpTransfer, CurrentExpTransfer}
AllDataStores:SetAsync(player.UserId, TransferValues)
end)```
First block works perfectly, the second with Player Removing is not
The PlayerRemoving function is inside the PlayerAdded funtion.
Yeah, that’s… that’s the problem. You haven’t set up your events correctly (why is PlayerRemoving even inside PlayerAdded?) and the variables you’re expecting to be available aren’t there so you don’t have anything to actually be saving.
There’s some fundamental flaws in your code that’ll need to be plucked off, such as removing those connections out of PlayerAdded. Another underlying problem here but every time a new player joins, a new connection spawns up, so you’ve also got excess connections too.
PlayerRemoving and the RemoteEvent connection should be divorced from PlayerAdded and please never modify PlayerGuis from the server. Use a RemoteEvent instead to have the server send the client new information to update the Gui with.
I’m not sure where you’re storing values either of if you’re relying on the client to send those, but that seems enormously insecure as well. You should ideally be keeping that kind of data on the server with the client only requesting either for updates which is checked by the server or for the data itself.
If the events are separate, then I’m not quite sure what’s going on here. The PlayerAdded function was posted twice and I think your code block is malformed still. This is also not the full extent of your code. The only thing I know for sure is: in PlayerRemoving, you’re trying to make a table of variables that do not exist for its scope, so it’s not receiving anything.
Okay, thank you so much for that explanation.
I noticed the many issues my script has, and I tried fixing them, saving and loading all the datastores on the server script only:
local DataStoreService = game:GetService("DataStoreService")
local AllDataStores = DataStoreService:GetDataStore("AllDataStores")
local TransferValues
game.Players.PlayerAdded:Connect(function(Player)
local CurrentExp = Player:WaitForChild("PlayerGui"):WaitForChild("EXPBarUP").CurrentExp.Value
local BlueSize = Player:WaitForChild("PlayerGui"):WaitForChild("EXPBarUP").Frame
local GetSync = AllDataStores:GetAsync(Player.UserId)
if GetSync ~= nil then
CurrentExp = GetSync[1]
BlueSize.Size = UDim2.new(GetSync[2], BlueSize.Size.X.Offset, BlueSize.Size.Y.Scale, BlueSize.Size.Y.Offset)
elseif GetSync == nil then
end
end)
game.Players.PlayerRemoving:Connect(function(Player)
local CurrentExp = Player:WaitForChild("PlayerGui"):WaitForChild("EXPBarUP"):WaitForChild("CurrentExp").Value
local BlueSize = Player:WaitForChild("PlayerGui"):WaitForChild("EXPBarUP").Frame.Size.X.Scale
local TransferValues = {CurrentExp, BlueSize}
AllDataStores:SetAsync(Player.UserId, TransferValues)
end)
And of course, the script is not working.
Am I still missing something here?
Yeah, still. You need to stop modifying PlayerGuis from the server and stop relying on the client to report back values. The server will not see client-side changes to a Gui and it should never be interacting with that either. Any Gui changes should only ever be conveyed through by RemoteEvents. The server should also be holding EXP data and giving that to the client to determine the bar fill sizes; the client should not be responsible for its own EXP counting.
--// Variables
local ds = game:GetService("DataStoreService"):GetDataStore("DataWhateverHere")
local Stats = {"TheGoods", "Cash"} -- Doesnt matter what order. just add new ones
--// Functions
game.Players.PlayerAdded:Connect(function(plr)
local UserId = plr.UserId
local leaderstats = Instance.new("Folder", plr)
leaderstats.Name = "leaderstats"
for i=1, #Stats, 1 do -- This will load in each stat stated in the Table
local Inst = Instance.new("IntValue", leaderstats)
Inst.Name = Stats[i]
end
local Data = nil
pcall(function()
Data = ds:GetAsync(UserId)
end)
if Data then
for i,v in pairs(leaderstats:GetChildren()) do
v.Value = LoadedData[v.Name]
end
end
end)
game.Players.PlayerRemoving:Connect(function(plr)
local UserId = plr.UserId
local leaderstats = plr.leaderstats
pcall(function()
local SaveData = {}
for i,v in pairs(leaderstats:GetChildren()) do
SaveData[v.Name] = v.Value
end
ds:SetAsync(UserId, SaveData) -- Some users also recommend :UpdateAsync() but i'm yet to research that. however this works for me. But still.
end)
end)