Help with saving/loading multiple values

Hello! I’m currently working on a game where I have a LOT of values I’d like to save whenever the player leaves/joins the game.

The values simply don’t save/load properly.

I’ve tried so many different scripts that just don’t work, and I’ve done a lot of research. But for some reason it won’t work. For some scripts it saves them but doesn’t load properly. With some it doesn’t even save. I’ve been having this issue for more than a year without a save system, but it’s about time I get one but I can’t get it right.

Whenever the server starts, it makes a folder in ReplicatedStorage called “PlayerFolders”. Then, whenever a player joins the game, it makes a folder inside of PlayerFolders with their username. Inside of the usernames folder it has a lot of different values such as “Currency”. I’d like to save all of these values whenever the player leaves the game, then load them in again whenever they join back.

I do not currently have a “set” script, just the default one that makes the values.

local RP = game:GetService(“ReplicatedStorage”)

local Folder = Instance.new(“Folder”)
Folder.Parent = RP
Folder.Name = “PlayerFolders”

game.Players.PlayerAdded:Connect(function(Player)
if game.ReplicatedStorage.PlayerFolders:FindFirstChild(Player.Name) then

else
	local PlayerFolder = Instance.new("Folder")
	PlayerFolder.Parent = Folder
	PlayerFolder.Name = Player.Name
	
	local Currency = Instance.new("NumberValue")
	Currency.Parent = PlayerFolder
	Currency.Name = "Currency"
	Currency.Value = 2000
	
	local FireDefense = Instance.new("NumberValue")
	FireDefense.Parent = PlayerFolder
	FireDefense.Name = "FireDefense"
	FireDefense.Value = 1
	
	local FireDamageTaken = Instance.new("NumberValue")
	FireDamageTaken.Parent = PlayerFolder
	FireDamageTaken.Name = "FireDamageTaken"
	FireDamageTaken.Value = 0
	
	local TimedMeditating = Instance.new("NumberValue")
	TimedMeditating.Parent = PlayerFolder
	TimedMeditating.Name = "TimedMeditating"
	TimedMeditating.Value = 0
end
end)

I know that I’m not supposed to ask for code, but again I’ve tried a lot of different approaches and scripts that just don’t work, so I’d really appreciate some help.

Use datastores.

Where and how are you saving your values?

I have tried to use datastores with a bunch of different scripts, but again they don’t work. I don’t have a specific example, but it doesn’t load once it’s been saved.

The script above is just the values, I don’t have a saving script because I kind of deleted them all out of frustration.

Were you trying to save the NumberValues themselves or just the values? Because DataStores can’t store instances alone

Ok, I can provide an easier example. Let’s say you had “Coins” as a value. Here is how you would load and save it:

local dss = game:GetService("DataStoreService")
local ds = dss:GetDataStore("MainData")

game.Players.PlayerAdded:Connect(function(plr)
    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = plr

    local data = dss:GetAsync(plr.UserId) --get player's saved data

    local Coins = Instance.new("NumberValue")
    Coins.Name = "Coins"
    Coins.Value = data or 0 --set to 0 if there is no data, else use saved data
    Coins.Parent = leaderstats
end)

game.Players.PlayerRemoving:Connect(function(plr) --when player is leaving
    ds:SetAsync(plr.UserId, plr.leaderstats.Coins.Value) --save the player's data
end)

game:BindToClose(function() --to save data when game closes
    for i,plr in pairs(game.Players:GetPlayers()) do --go through all players
        ds:SetAsync(plr.UserId, plr.leaderstats.Coins.Value) --save the player's data
    end
end)

I changed up the script a little bit to match where I hold the values, but I am getting this error.:
GetAsync is not a valid member of DataStoreService “DataStoreService”, Line 12

local dss = game:GetService("DataStoreService")

local ds = dss:GetDataStore("MainData")

local RP = game:GetService("ReplicatedStorage")

local Folder = Instance.new("Folder")

Folder.Parent = RP

Folder.Name = "PlayerFolders"

game.Players.PlayerAdded:Connect(function(Player)

local data = dss:GetAsync(Player.UserId)

local PlayerFolder = Instance.new("Folder")

PlayerFolder.Parent = Folder

PlayerFolder.Name = Player.Name

local Currency = Instance.new("NumberValue")

Currency.Parent = PlayerFolder

Currency.Name = "Currency"

Currency.Value = data or 2000

end)

game.Players.PlayerRemoving:Connect(function(Player)

ds:SetAsync(Player.UserId, Folder:FindFirstChild(Player.Name).Currency.Value)

end)

game:BindToClose(function()

for i,Player in pairs(game.Players:GetPlayers()) do

ds:SetAsync(Player.UserId, Folder:FindFirstChild(Player.Name).Currency.Value)

end

end)

Change the dss on line 12 to ds. Had that error in my script, so my fault lol.

LETS GOOO YOU JUST SOLVED MY 1 YEAR MYSTERY!!!

You are awesome thanks :slight_smile:

1 Like

Although, I do have a few questions about the script. For multiple values do I write

	ds:SetAsync(Player.UserId, Folder:FindFirstChild(Player.Name).Currency.Value)
	ds:SetAsync(Player.UserId, Folder:FindFirstChild(Player.Name).FireDefense.Value)

Or do I put them all together into one?

Also, why are all the values now 0?

Also, with the script I have right now (Basically what you gave me but I just have the new FireDefense, both of the values are now the same, when they are supposed to be different.

For multiple values, I would put them into a table. Using “Coins” and “Money” as a reference, this is what it would look like:

local dss = game:GetService("DataStoreService")
local ds = dss:GetDataStore("MainData")

game.Players.PlayerAdded:Connect(function(plr)
    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = plr

    local data = dss:GetAsync(plr.UserId) or {} --get player's saved data

    local Coins = Instance.new("NumberValue")
    Coins.Name = "Coins"
    Coins.Value = data.Coins or 0 --set to 0 if there is no data, else use saved data
    Coins.Parent = leaderstats

    local Money = Instance.new("NumberValue")
    Money.Name = "Money"
    Money.Value = data.Money or 0
    Money.Parent = leaderstats
end)

game.Players.PlayerRemoving:Connect(function(plr) --when player is leaving
    ds:SetAsync(plr.UserId, {
        Coins = plr.leaderstats.Coins.Value,
        Money = plr.leaderstats.Money.Value
    }) --save the player's data
end)

game:BindToClose(function() --to save data when game closes
    for i,plr in pairs(game.Players:GetPlayers()) do --go through all players
        ds:SetAsync(plr.UserId, {
            Coins = plr.leaderstats.Coins.Value,
            Money = plr.leaderstats.Money.Value
        }) --save the player's data
    end
end)

I made the changes to match the game, but now both values are 0 whenever you join the game. The code:

local dss = game:GetService("DataStoreService")
local ds = dss:GetDataStore("MainData")

local RP = game:GetService("ReplicatedStorage")

local Folder = Instance.new("Folder")
Folder.Parent = RP
Folder.Name = "PlayerFolders"


game.Players.PlayerAdded:Connect(function(Player)
	local data = ds:GetAsync(Player.UserId) or {}

	local PlayerFolder = Instance.new("Folder")
	PlayerFolder.Parent = Folder
	PlayerFolder.Name = Player.Name

	local Currency = Instance.new("NumberValue")
	Currency.Parent = PlayerFolder
	Currency.Name = "Currency"
	Currency.Value = data or 2000

	local FireDefense = Instance.new("NumberValue")
	FireDefense.Parent = PlayerFolder
	FireDefense.Name = "FireDefense"
	FireDefense.Value = data or 1
end)

game.Players.PlayerRemoving:Connect(function(Player)
	ds:SetAsync(Player.UserId, {
		Currency = Folder:FindFirstChild(Player.Name).Currency.Value,
		FireDefense = Folder:FindFirstChild(Player.Name).FireDefense.Value
	})
end)

game:BindToClose(function()
	for i,Player in pairs(game.Players:GetPlayers()) do
		ds:SetAsync(Player.UserId, {
			Currency = Folder:FindFirstChild(Player.Name).Currency.Value,
			FireDefense = Folder:FindFirstChild(Player.Name).FireDefense.Value
		})
	end
end)

I change the values in the server. For example, if I change the currency to 200, if you join it is 0.

That’s because you are trying to set the values to the table itself. You never reference the index in the table.

local dss = game:GetService("DataStoreService")
local ds = dss:GetDataStore("MainData")

local RP = game:GetService("ReplicatedStorage")

local Folder = Instance.new("Folder")
Folder.Parent = RP
Folder.Name = "PlayerFolders"


game.Players.PlayerAdded:Connect(function(Player)
	local data = ds:GetAsync(Player.UserId) or {}

	local PlayerFolder = Instance.new("Folder")
	PlayerFolder.Parent = Folder
	PlayerFolder.Name = Player.Name

	local Currency = Instance.new("NumberValue")
	Currency.Parent = PlayerFolder
	Currency.Name = "Currency"
	Currency.Value = data.Currency or 2000

	local FireDefense = Instance.new("NumberValue")
	FireDefense.Parent = PlayerFolder
	FireDefense.Name = "FireDefense"
	FireDefense.Value = data.FireDefense or 1
end)

game.Players.PlayerRemoving:Connect(function(Player)
	ds:SetAsync(Player.UserId, {
		Currency = Folder:FindFirstChild(Player.Name).Currency.Value,
		FireDefense = Folder:FindFirstChild(Player.Name).FireDefense.Value
	})
end)

game:BindToClose(function()
	for i,Player in pairs(game.Players:GetPlayers()) do
		ds:SetAsync(Player.UserId, {
			Currency = Folder:FindFirstChild(Player.Name).Currency.Value,
			FireDefense = Folder:FindFirstChild(Player.Name).FireDefense.Value
		})
	end
end)
1 Like

You might be the best person on earth. Thank you so much for helping me, you are amazing!!!

1 Like

For anybody reading this in the future, just make sure to always get/save data in a pcall. Without a pcall, if the data saving/recieving fails, it will throw an error and stop data saving entirely.

It should look like this when you are saving/recieving data:

--Recieving data
local data
local success,  err = pcall(function()
    data = datastore:GetAsync(UserId)
end)

if not success then
    warn(err)
end

--Saving Data
local success, err = pcall(function()
    datastore:SetAsync(UserId, dataToSave)
end)

if not success then
    warn(err)
end