How to save folder of values

i want to go through a folder full of a varying amount of values. Basically go through the values and save the actual value and then the name of each one. I have never been good with data stores and especially when saving and loading more than one value. Thank you for any help and here is a script i have for saving one value. Basically i want to turn it into a script for saving more than one value

-- this script works for saving one value and i want to have one like this that can go through a folder and save all the values in the folder and then load them

local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("CoinsDataStore")
local PlayersToSave = {}   -- setup a table to hold players that the data has changed on 
local TimeBetweenAutoSave = 60 -- the time between each autosave checking if they are in table above to save

function SavePlayersData(player)
--- it won't save unless the coins loaded correctly so that it doesn't overwrite the save with 0
	if player.Currencies.coins.LoadedCorrectly.Value == true then
		local key = "Coins_"..player.UserId

		local data = player.Currencies:FindFirstChild("coins").Value

		local success, errormessage = pcall(function()
			DataStore:SetAsync(key, data)
		end)

		if success then
		else
			print("Error")
			warn(errormessage)
-- give the player a pop up warning them it failed
			local ErrorMessage = game.ReplicatedStorage.Extras.Message:Clone()
			ErrorMessage.Parent = player.PlayerGui.PopUps
			ErrorMessage.Message.Text = ("Coins failed to save. This is usually due to Roblox data stores failing. If you leave now, your data from this play session may be lost")
		end
	end
end

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

	local key = "Coins_"..player.UserId

	-- Load data
	local data
	local success, errormessage = pcall(function()
		data = DataStore:GetAsync(key) -- if data has never been set this will return successful and data will be nil
	end)

	local Value = player.Currencies.coins

	if success then
-- set a value to true so that the game knows it can save without overwriting data with 0
		player.Currencies.coins.LoadedCorrectly.Value = true
		Value.Value = data or 0 -- this will set a default to the value incase they don't have any data which would be nil
		-- Set value equal to the data
	else
-- a popup telling the player the coins didn't load
		local ErrorMessage = game.ReplicatedStorage.Extras.Message:Clone()
		ErrorMessage.Parent = player.PlayerGui.PopUps
		ErrorMessage.Message.Text = ("Coins failed to load. This is usually due to Roblox data stores failing. You might have to rejoin")
	end

	Value.Changed:Connect(function() -- this catches if the value changed and it will then add it to the autosave table for the next loop to save the data
		table.insert(PlayersToSave,player) -- adds the player to this table because their data has changed
	end)
end)

-- Save when leaving
game.Players.PlayerRemoving:Connect(function(player)
	if table.find(PlayersToSave,player) then
		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)

-- Auto save
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)
			table.remove(PlayersToSave,table.find(PlayersToSave,player))
			-- after save then remove player from table
		end
	end)
end
local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("ValuesDataStore")
local PlayersToSave = {}  
local TimeBetweenAutoSave = 60
local Players = game:GetService("Players")
local RS = game:GetService("ReplicatedStorage")
local Extras = RS:WaitForChild("Extras")
local Message = Extras:WaitForChild("Message")

function SavePlayersData(player)
	local playerStats = player:WaitForChild("PlayerStats")
	if #playerStats:GetChildren() >= 1 then
		local key = "Stats_"..player.UserId
		local statsTable = {}
		for _, stat in ipairs(playerStats:GetChildren()) do
			statsTable[stat.Name.."|"..stat.ClassName] = stat.Value
		end
		if #statsTable >= 1 then
			local success, errormessage = pcall(function()
				DataStore:SetAsync(key, statsTable)
			end)
			
			if success then
				print("Successfully saved!")
			else
				print("Save failed!")
				warn(errormessage)
				local ErrorMessage = Message:Clone()
				ErrorMessage.Parent = player.PlayerGui.PopUps
				ErrorMessage.Message.Text = ("...")
			end
		end
	end
end

Players.PlayerAdded:Connect(function(player)
	local playerStats = Instance.new("Folder")
	playerStats.Name = "PlayerStats"
	playerStats.Parent = player
	local key = "Stats_"..player.UserId
	local dataStats
	local success, errormessage = pcall(function()
		dataStats = DataStore:GetAsync(key)
	end)
	
	if success then
		print("Successfully saved!")
	else
		print("Save failed!")
		print("Error")
		warn(errormessage)
		local ErrorMessage = Message:Clone()
		ErrorMessage.Parent = player.PlayerGui.PopUps
		ErrorMessage.Message.Text = ("...")
	end
	
	if type(dataStats) == "table" then
		for field, value in pairs(dataStats) do
			local name = string.split(field, "|")[1]
			local class = string.split(field, "|")[2]
			local instanceValue = Instance.new(class)
			instanceValue.Parent = playerStats
			instanceValue.Value = value
		end
	end
end)

Players.PlayerRemoving:Connect(function(player)
	SavePlayersData(player)
end)

game:BindToClose(function()
	for _, player in ipairs(Players:GetPlayers()) do
		SavePlayersData(player)
	end
end)

while task.wait(TimeBetweenAutoSave) do
	for _, player in ipairs(Players:GetPlayers()) do
		SavePlayersData(player)
	end
end

Stayed as true as possible to the original source material.

1 Like

Thanks palπŸ™‚ I made some changes to it to but your script helped a lot. I think I almost, partly understand table saving now. Here is my final script just for anyone looking at this in the future

local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("AvatarDataStore")
local PlayersToSave = {}  
local TimeBetweenAutoSave = 60
local Players = game:GetService("Players")
local RS = game:GetService("ReplicatedStorage")
local Extras = RS:WaitForChild("Extras")
local Message = Extras:WaitForChild("Message")

function SavePlayersData(player)
	local Wearing = player:WaitForChild("Wearing")
	local key = "Wearing_"..player.UserId
	local itemTable = {}
	for _, item in ipairs(Wearing:GetChildren()) do
		itemTable[item.Name.."|"..item.ClassName] = item.Value
	end
	local success, errormessage = pcall(function()
		DataStore:SetAsync(key, itemTable)
	end)

	if success then
	else
		print("Avatar save failed")
		warn(errormessage)
		local ErrorMessage = Message:Clone()
		ErrorMessage.Parent = player.PlayerGui.PopUps
		ErrorMessage.Message.Text = ("Your avatar failed to save. This will not cause you to lose any items. You may have to reapply them to your avatar though")
	end
end

Players.PlayerAdded:Connect(function(player)
	local key = "Wearing_"..player.UserId
	local itemsEquipped
	local success, errormessage = pcall(function()
		itemsEquipped = DataStore:GetAsync(key)
	end)

	if success then
	else
		print("Avatar failed to load!")
		warn(errormessage)
		local ErrorMessage = Message:Clone()
		ErrorMessage.Parent = player.PlayerGui.PopUps
		ErrorMessage.Message.Text = ("Your avatar failed to load")
	end

	if type(itemsEquipped) == "table" then
		for field, value in pairs(itemsEquipped) do
			local name = string.split(field, "|")[1]
			local class = string.split(field, "|")[2]
			local instanceValue = Instance.new(class)
			instanceValue.Parent = player.Wearing
			instanceValue.Value = value
			instanceValue.Name = name
		end
	end
end)

Players.PlayerRemoving:Connect(function(player)
	SavePlayersData(player)
end)

while task.wait(TimeBetweenAutoSave) do
	for _, player in ipairs(Players:GetPlayers()) do
		SavePlayersData(player)
	end
end

game:BindToClose(function()
	if not game:GetService("RunService"):IsStudio() and #Players:GetPlayers() > 1 then
		for _, player in ipairs(Players:GetPlayers()) do
			SavePlayersData(player)
		end
	end
end)