Non-Defined Datastore System

I am currently trying to work on a datastore system which will be able to save all data from the leaderboards without defining the stat (ex. gold.Value = data). The reason I am trying to do this is because I have a lot of stats to save in a lot of different places, and manually writing them all would be tedious and difficult to edit, seeing as the code comes out at 500+ lines. The issue is that with the current code it will only save the Player.Name and not the Player.UserId. Player.Name could result in loss of data if a player were to change their username. That is certainly not acceptable considering that my game is based around leveling up. The code is below.

	local datastore = game:GetService("DataStoreService"):GetDataStore(player.Name.."Stats")

local statstorage = player:FindFirstChild("leaderstats"):GetChildren()
for i =  1, #statstorage do
	datastore:SetAsync(statstorage[i].Name, statstorage[i].Value)
	print("Saves Data: "..i)
	
end
print("Stats Have Been Saved")	
end)

game.Players.PlayerAdded:connect(function(player)
		local datastore = game:GetService("DataStoreService"):GetDataStore(player.Name.."Stats")
	
	player:WaitForChild("leaderstats")
	wait(1)
	local stats = player:FindFirstChild("leaderstats"):GetChildren()
	for i = 1, #stats do			
	stats[i].Value = datastore:GetAsync(stats[i].Name)
	print("Stat "..i.." is identified")
		end
end)

I have tried to make the storage defined differently, although to no appeal. I understand that Player.UserId is not a member of “Stats”, however I do not understand why the Player.Name is allowed. Essentially, I have a script which currently works at saving the player’s data by their name, and not their userid, which is far more im,portant. However, while I know what needs to be accomplished, I do not know how to do it. If any help can be offered, that would be greatly appreciated!

NOTE: This is my first DevForum post, so I apologize if I am not doing it correctly.

Your key seems to be set as the name of the value in the leaderstats folder. Rather than setting separate data saves for each value, you can store the player’s data as a dictionary in the datastore. You should also use UpdateAsync as it’s more reliable than SetAsync. Finally, it’s best to wrap functions like these in a pcall() due to the possibility of failure, and further control over how you can handle this.

Example:

local success = pcall(datastore.UpdateAsync, datastore, "Player_"..player.UserId, function()
    return {
        Level = player.leaderstats.Level.Value,
        XP = player.leaderstats.XP.Value
    }
end)

You can then use :GetAsync in your PlayerAdded event to correctly retrieve the player’s data, and it will return the data as a dictionary. I’d suggest kicking the player if their data failed to load.

local success, data = pcall(datastore.GetAsync, datastore, "Player_"..player.UserId)

if success == true then
    -- set the data here, again, it will be returned as a dictionary
else
    player:Kick("Your data failed to load, please rejoin")
end

I should certainly use UpdateAsync, although I am trying to allow script to save all data despite not actually defining it, (ex. XP = player.leaderstats.XP.Value)

Then you can just use the for loop and add to a table which will be the data like this:

local leaderstats = player:FindFirstChild("leaderstats")

if leaderstats ~= nil then
    local data = {}

    for _, stat in ipairs(leaderstats:GetChildren()) do
        data[stat.Name] = stat.Value
    end

    local success = pcall(datastore.UpdateAsync, datastore, "Player_"..player.UserId, function()
        return data
    end)
end

It still doesn’t seem to be working. I guess i’ll keep looking into it.

Have you gotten any errors in the output? Also, please show your code.