Pretty cool datastore system i made

-- customizable default stats
local defaultstats = {
	cash = 3,
	inventory = {pet1 = 34,pet2 = 93},
	settingslist = {true,false,false,true}
	items = {
			sword = {damage = 25,durability = 5,["type"] = steel},
			axe = {weight = 43,["type"] = wood}
		     }
}
-- end of customizable defaultstats

-- settings(dont change if your not sure you know what your doing)
local statfilling = true -- if you add a new stat to default stats that wasn't already in the players datastores this adds it for you
local foldername = "playerdata" -- name of the folder storing all of the players data
local autosave = true
local autosavetime = 100 -- dont make it too low or itll lag 
-- end settings



local Data = game:GetService("DataStoreService"):GetDataStore("DataStore8")

function recurget(folder) -- recursively gets a players stats
	local temp = {}
	local children = folder:GetChildren()
	
	for i,v in pairs(children) do
		if (v.ClassName == "Folder") then
			temp[v.Name] = recurget(v)
		else
			temp[v.Name] = v.Value
		end
	end
	return(temp)
end


function recuradd(folder,values) -- recursively adds the instances from the table
	local existingstats = recurget(folder) -- instead of check if instance is in folder it uses a table of the values that it finds at the start which is more efficient
	
	
	for i,v in values do
		if (type(v) == "table") then
			local statfolder = ""
			
			if (existingstats[i] == nil) then
				statfolder = Instance.new("Folder",folder)
				statfolder.Name = i
			else
				statfolder = folder[i]
			end
			
			recuradd(statfolder,v)
		else
			local types = {["boolean"] = "BoolValue",["string"] = "StringValue",["number"] = "NumberValue"}
			local stat = ""
			
			if (not (existingstats[i] == nil)) then -- prevents it from having two instances with the same name and instead replacing the instance thatt already exists
				stat = folder[i]
			else
				stat = Instance.new(types[type(v)],folder)
				stat.Name = i
			end
			
			stat.Value = v
		end
	end
end


game.Players.PlayerAdded:Connect(function(plr)
	print("startedloading")
	local datafolder = Instance.new("Folder",plr)
	datafolder.Name = foldername

	local dataload = Data:GetAsync(tostring(plr.UserId))
	print(dataload)
	if dataload then
		if (statfilling == true) then
			recuradd(datafolder,defaultstats)
		end
		recuradd(datafolder,dataload)	
	else
		recuradd(datafolder,defaultstats) -- this gives the player default data if they have no data yet (not to be confused with statfilling)
	end	
	print("endedloading")
	while wait(1) do -- just a demo showing that it saves the value you can remove if you want
		plr.playerdata.cash.Value += 1
	end
end)

game.Players.PlayerRemoving:Connect(function(plr)
	Data:SetAsync(tostring(plr.UserId),recurget(plr[foldername])) 
end)


while wait(autosavetime) do
	local players = game:GetService("Players"):GetChildren()
	
	for i,v in pairs(players) do
		Data:SetAsync(tostring(v.UserId),recurget(v[foldername]))
	end
end

this datastore system is pretty cool because it can support tables nested as far as you want (basically for tables it creates a folder with the tables name and puts everything in the table in that folder)

so you really only have to change the customizable default stats to add new values

please give feedback( btw i made this system)