Help with saving data script

So I am trying to make a rank system that saves your exp and rank, I’ve already made the ranks save, but I haven’t gotten the exp to save.

Script:

local DSS = game:GetService("DataStoreService")
local RankDS = DSS:GetDataStore("RankData")

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

	local expValue = Instance.new("NumberValue")
	expValue.Name = "expValue"
	expValue.Parent = plr
	
	local maxExp = Instance.new("NumberValue")
	maxExp.Name = "maxExp"
	maxExp.Parent = plr

	local function LevelUp()
		levelValue.Value += 1
		expValue.Value = 0
		maxExp.Value = 1000
		
	end

	local function GainExp(gain)
		expValue.Value += gain
		if expValue.Value > maxExp.Value then
			LevelUp()
		end
	end
	
	
	--Load data
	
	local PlrId = plr.UserId
	print("First ID var has been set.")
	
	
	local data
	local data2 = nil
	local success, errormessage = pcall(function()
		data = RankDS:GetAsync(PlrId)
	end)
	print("First pcall has been fired.")
	
	if success then
		print("Success = true!")
		levelValue.Value = data
		expValue.Value = data2
	end
	
end)

--Save data

game.Players.PlayerRemoving:Connect(function(plr)
	local PlrId = plr.UserId

	
	local data = plr.leaderstats.Rank.Value
	local data2 = plr.expValue.Value
	print("Second variables has been set!")
	
	local success, errormessage = pcall(function()
		RankDS:SetAsync(PlrId,data,data2)
	end)
	print("Second pcall has been fired!")
	
	if success then
		print("Data has been saved successfully")
	else
		print("There has been an error")
		warn(errormessage)
	end
		
end)

I really have no idea on how to save multiple values in one script, so any help would be appreciated.

I’ve been recommending to people in your situation to save this information in a table. This allows you to save this data and any other stats that you may add in the future development of your game.

A module that makes this easier is DataStore2, you can easily save values and it does the table work for you. :slight_smile:

ProfileService is a great alternative from what I hear, but I haven’t really looked into it.

1 Like

You can save the data inside a table or use multiple keys.

1 Like

I don’t really know anything about data stores, or how to put the information into a table, I learned about data stores 1-2 weeks ago, so could you show me on how to do this? Thank you. Do I just make the data variables hold a table?

Piggybacking off of this, here is a dynamic solution I’ve made for saving folders or singular values alike :slight_smile:

DS2 Automatically saves data, so all you really need to do is tell it what to load and it handles the rest.

local DataStorage = {}

local DS2 = require(game.ServerScriptService.ExternalLib.Datastore2)

local keys = game.ReplicatedStorage.Configuration.Constants.DataKeys
local SaveDataKey = keys.PlayerDataKey.Value

local saveableData = game.ReplicatedStorage.Configuration.PlayerStats

DataStorage.init = function(player)
	local stats = player.Stats
	
	for _, item in ipairs(saveableData:GetChildren()) do
		wait(1)
		if not item:IsA("Folder") then -- If it's a data value
			DS2.Combine(SaveDataKey, item.Name)
			local store = DS2(item.Name, player)
			local playerStat = stats:FindFirstChild(item.Name)
			
			playerStat.Value = store:Get(item.Value)
			
			playerStat.Changed:Connect(function(value)
				store:Set(value)
			end)
		else -- if Folder..
			local info = folderIndexTable[item.Name]
			DS2.Combine(info.key, info.name)
			local store = DS2(info.name, player)
			local default = {}
			
			local playerFolder = stats:FindFirstChild(item.Name)
			
			for _, i in ipairs(item:GetChildren()) do
				table.insert(default, i.Value)
			end
			
			local data = store:Get(default)
						
			local objects = info.format(data)
			
			playerFolder:ClearAllChildren()
			
			for _, newItem in ipairs(objects) do
				newItem.Parent = playerFolder
			end
			
			local function update(folder)
				local new = {}
				
				for _, i in ipairs(folder:GetChildren()) do
					table.insert(new, i.Value)
				end
				
				store:Set(new)
			end
			
			playerFolder.ChildAdded:Connect(function(child)
				update(playerFolder)
			end)
			
			playerFolder.ChildRemoved:Connect(function()
				update(playerFolder)
			end)
		end
	end
end

return DataStorage
1 Like

It’s pretty simple, you just need to put a table into SetAsync’s 2nd argument.

local DSS = game:GetService("DataStoreService")
local RankDS = DSS:GetDataStore("RankData")

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

	local expValue = Instance.new("NumberValue")
	expValue.Name = "expValue"
	expValue.Parent = plr
	
	local maxExp = Instance.new("NumberValue")
	maxExp.Name = "maxExp"
	maxExp.Parent = plr

	local function LevelUp()
		levelValue.Value += 1
		expValue.Value = 0
		maxExp.Value = 1000
		
	end

	local function GainExp(gain)
		expValue.Value += gain
		if expValue.Value > maxExp.Value then
			LevelUp()
		end
	end
	
	
	--Load data
	
	local PlrId = plr.UserId
	print("First ID var has been set.")
	
	
	local data
	local success, errormessage = pcall(function()
		data = RankDS:GetAsync(PlrId)
	end)
	print("First pcall has been fired.")
	
	if success then
		print("Success = true!")
		levelValue.Value = data[1]
		expValue.Value = data[2]
	end
	
end)

--Save data

game.Players.PlayerRemoving:Connect(function(plr)
	local PlrId = plr.UserId

	
	local data = plr.leaderstats.Rank.Value
	local data2 = plr.expValue.Value
	print("Second variables has been set!")
	
	local success, errormessage = pcall(function()
		RankDS:SetAsync(PlrId, {data,data2})
	end)
	print("Second pcall has been fired!")
	
	if success then
		print("Data has been saved successfully")
	else
		print("There has been an error")
		warn(errormessage)
	end
		
end)
2 Likes

It worked on the first test, I am going to test some more to see if it breaks.