robloxdatastore

Datastore player's data in different order than setasync


I've been having trouble with this, because in the entire script I getAsync and SetAsync Values the exact same order, yet while troubleshooting ,because I got data loss constantly, it apparently says The 1st value it tries to set for the player is nil, although printing the table shows that it's there, just in a different position than i had set it.

local DataStore = game:GetService("DataStoreService"):GetDataStore("Basic")

local template = {
    Money = 0;
    Level = 0;
    XP = 0
}

local MAXIMUM_RETRY_ATTEMPTS = 5
local RETRY_COOLDOWN = 1

game.Players.PlayerAdded:Connect(function(plr)
    local ls = plr:FindFirstChild("leaderstats")
    local retryCount = 0
    local success = false
    local result
    while not success and retryCount < MAXIMUM_RETRY_ATTEMPTS do
        success, result = pcall(function()

            local data = DataStore:GetAsync(tostring(plr.UserId))
            if data == nil then
                print("nothing?")
            else
                ls.Money.Value = data.Money
                ls.Level.Value = data.Level
                ls.XP.Value = data.XP
                print("Success import")
                print(data)
            end
        end)
        if not success then
            retryCount = retryCount + 1
            warn(string.format("Failed to Import %s's data with error : %s", plr.Name, tostring(result or "")))
            local data = DataStore:GetAsync(tostring(plr.UserId))
            print(data)
            task.wait(RETRY_COOLDOWN)
        end
    end
end)

game.Players.PlayerRemoving:Connect(function(plr)
    local result
    local success = false
    local ls = plr:FindFirstChild("leaderstats")
    while not success do
        success, result = pcall(function()
            DataStore:SetAsync(tostring(plr.UserId), {
                Money = ls.Money.Value;
                Level = ls.Level.Value;
                XP = ls.XP.Value
            })
            print("Success export")
        end)
        if not success then
            warn(string.format("Failed to Export %s's data with error : %s", plr.Name, tostring(result or "")))
        end
    end
end)

Solution

  • As you mentioned in your comment, the error you are seeing is :

    Attempt to index nil with Money

    And you've already narrowed it down that it isn't your data table. That means that your leaderstats ls is nil. So looking at where you defined it...

    local ls = plr:FindFirstChild("leaderstats")
    

    It looks like you've got a race-condition. You are trying to fetch the leaderstats, but if it doesn't exist then it will return nil. So if another script is creating it, one simple fix might be to change that line to...

    local ls = plr:WaitForChild("leaderstats", 10)
    

    But a better fix might be to move the code that constructs your leaderstats folder and all of the NumberValues into the top of this function instead. That way, the code that constructs the leaderstats is the same code that populates it with data.

    game.Players.PlayerAdded:Connect(function(plr)
        -- create the leaderstats
        local ls = Instance.new("Folder")
        ls.Name = "leaderstats"
        local moneyVal = Instance.new("NumberValue", ls)
        moneyVal.Name = "Money"
        local levelVal = Instance.new("NumberValue", ls)
        levelVal.Name = "Level"
        local xpVal = Instance.new("NumberValue", ls)
        xpVal.Name = "XP"
        ls.Parent = plr
    
        -- fetch data from the data stores
        local retryCount = 0
        local success = false
        local result
        while not success and retryCount < MAXIMUM_RETRY_ATTEMPTS do