Datastore not working / not existing?

You aren’t using a pcall, so the print statement is only an indication that your code ran without issues, not that your DataStore calls were successfully performed. You should be sure to use pcalls when working with DataStore calls at nearly every opportunity.

The function connected to PlayerAdded may not run due to GetDataStore being a yielding function. The best case scenario for this is to assign the function to a variable, hook it to PlayerAdded and then call it for all existing players of the game. This will ensure that everything in terms of initialisation occurs.

Next huge problem is in relation to the way you’re creating values. Avoid using the parent argument if you’re setting properties immediately after creating an instance and try to consolidate where possible to lessen how much code you actually have to write out. Consider scalability and being able to handle arbitrary amounts of information.

And the cherry on top, my favourite nitpick against developers: use GetService to fetch services as opposed to using dot syntax. It is canonically correct and holds up consistency when working with services as you need to use GetService for a lot of them anyway.

Here is some code that incorporates my feedback accordingly. I have changed a few things that may interrupt how your DataStore workflow originally went, in regards to:

  • Spelling and naming conventions on code
  • Shortened a lot of bloat text for the DataStore
  • Generally focused on readability and scalability

(Code sample below, hidden for thread viewing convenience. It has been changed since initial posting to fix bugs and such.)

View code sample
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local PlayerDataStore = DataStoreService:GetDataStore("PlayerData")

local DATA_VALUES = {
    "Rank", "Weapon", "Accessory1", "Accessory2",
    "Armor1", "Armor2", "Ability1", "Ability2",
    "Ability3", "Ability4", "Ability5", "Ability6"
}

local function playerAdded(player)
    -- Set parent of this after all child values are created
    local dataFolder = Instance.new("Folder")
    dataFolder.Name = "Data"

    -- Ditto
    local mainFolder = Instance.new("Folder")
    mainFolder.Name = "Main"

    for _, datumName in ipairs(DATA_VALUES) do
        local datum = Instance.new("StringValue")
        datum.Name = datumName
        datum.Parent = mainFolder
    end

    local success, playerData = pcall(function ()
        return PlayerDataStore:GetAsync(player.UserId)
    end)

    -- Came up a bit lazy on this part
    if success then
        if playerData then
            for key, value in pairs(playerData) do
                mainFolder[key].Value = value
            end
        else
            mainFolder["Rank"].Value = "F-"
        end
    else
        warn(("%s (%d)'s data could not be loaded!\n\t%s"):format(player.Name, player.UserId, playerData))
    end

    mainFolder.Parent = dataFolder
    dataFolder.Parent = player
end

local function playerRemoving(player) -- Consistency and organisation's sake
    -- No need to error handle: let this pass or fail organically
    local mainFolder = player.Data.Main
    local mainFolderContents = mainFolder:GetChildren()
    local data = table.create(#mainFolderContents)

    for _, datum in ipairs(mainFolderContents) do
        data[datum.Name] = datum.Value
    end

    local success, exception = pcall(function ()
        return PlayerDataStore:SetAsync(player.UserId, data)
    end)

    if not success then
        warn(("%s (%d)'s data was not saved!\n\t%s"):format(player.Name, player.UserId, exception))
    end
end

Players.PlayerAdded:Connect(playerAdded)
Players.PlayerRemoving:Connect(playerRemoving)

for _, player in ipairs(Players:GetPlayers()) do
    playerAdded(player)
end

When testing that your DataStore works by setting values directly from the Studio window, ensure that you are using the Server view and not the Client view. Changes from the client view will be simulated as the client making changes to the DataModel and will follow standard replication patterns (the change will not be received by the server). If you are testing it with game systems, then just play normally enough to receive data and you’re good to go.

1 Like