Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

Why does this return an empty folder?

Asked by
Fatul 9
4 years ago
local DSService = game:GetService('DataStoreService'):GetDataStore('WOOPPOLICE1')
local HttpService = game:GetService('HttpService')

local defaultData = {
    PlayerStats = {
        Name = "None",
        Title = "None",
        Rank = "None",
        Race = "None",
        Birth = "None",
        Shirt = "None",
        Pants = "None",
        Class = "None",
        Lives = 5,
        Days = 0,
        Money = 0,
        Karma = 0,
        Gender = "None",
        LastRewardTick = "",
        }, 
    Skills = {
        Skill1 = {
            SkillEXP = 0,
            SkillLevel = 1,
            SkillRank = "Novice",           
        },
    },
    Equipment = {
        Armor = "None",
        MainHand = "None",
        OffHand = "None",
        Epautlet = "None",
    },
    Inventory = {
        Tools = {},
        Materials = {},     
    }
}

local function buildDataEntryFromFolder(folder)
    local dataEntry = {}

    for _, valueObject in next, folder:GetChildren() do
        if valueObject:IsA("ValueBase") then
            dataEntry[valueObject.Name] = {valueType = valueObject.ClassName, value = valueObject.Value}
        end
    end

    return dataEntry
end

function unloadData(player, data)
    local newDataFolder = Instance.new("Folder", player)
    newDataFolder.Name = "PlayerData"
    local function recursive(folder, children)
        for x, y in pairs (children) do
            if typeof(y) == 'table' then
                local newFolder = Instance.new("Folder", folder)
                newFolder.Name = x
                recursive(newFolder, y)
            elseif typeof(y) == 'number' then
                local value = Instance.new("NumberValue", folder)
                value.Name = x
                value.Value = y
            elseif typeof(y) == 'string' then
                local value = Instance.new("StringValue", folder)
                value.Name = x
                value.Value = y
            elseif typeof(y) == 'boolean' then
                local value = Instance.new("BoolValue", folder)
                value.Name = x
                value.Value = y
            else
                local value = Instance.new("StringValue", folder)
                value.Name = x
                value.Value = y
            end
        end
    end
    recursive(newDataFolder, data)
end

local function savePlayerData(player)
    local dataEntry = buildDataEntryFromFolder(player.PlayerData)
    DSService:SetAsync(player.UserId, dataEntry)
end

local function loadPlayerData(player)
    local dataEntry = DSService:GetAsync(player.UserId)

    --  In case there's no data found for the player, construct the data folder from a blank template
    if not dataEntry then
        dataEntry = defaultData
    end

    unloadData(player, dataEntry)

end

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

game.Players.PlayerRemoving:Connect(function(player)
    savePlayerData(player)
end)

Fresh data reset, it makes my folder. I change a value to see if it saves or not, I rejoin, and it makes the PlayerData folder, but nothing in it. Been working with this for 6'ish hours with so many different variations and at this point i'm just lost. Any help is VERY much appreciated.

0
To clear things up you are saying it creates an accurate player data folder when it is fresh data and it only creates an empty folder after rejoining? Wafflecow321 457 — 4y

2 answers

Log in to vote
0
Answered by 4 years ago

Ok, so the function for turning the data into a folder and value based hierarchy works perfectly. However the problem is that when you go to parse that back into a dictionary you are making an error. The problem is you are looping through the top folder and only inserting data if the children are values. That's why see nothing in the folder because it excludes other folders and there are only folders in the top level. To solve this you should apply what you did in the unload function. Just use recursion and treat the folders as the tables and convert them. Heres my solution:

local DSService = game:GetService('DataStoreService'):GetDataStore('WOOPPOLICE1')
local HttpService = game:GetService('HttpService')

local defaultData = {
    PlayerStats = {
        Name = "None",
        Title = "None",
        Rank = "None",
        Race = "None",
        Birth = "None",
        Shirt = "None",
        Pants = "None",
        Class = "None",
        Lives = 5,
        Days = 0,
        Money = 0,
        Karma = 0,
        Gender = "None",
        LastRewardTick = "",
        }, 
    Skills = {
        Skill1 = {
            SkillEXP = 0,
            SkillLevel = 1,
            SkillRank = "Novice",           
        },
    },
    Equipment = {
        Armor = "None",
        MainHand = "None",
        OffHand = "None",
        Epautlet = "None",
    },
    Inventory = {
        Tools = {},
        Materials = {},     
    }
}

local function buildDataEntryFromFolder(folder)

    local function recursive(folder)
        local parentTable = {}
        for key,value in pairs(folder:GetChildren()) do -- go through all the primary children of the folder first
             if value:IsA("ValueBase") then
                  parentTable[key] = value.Value -- if is a normal value put it in its assigned data table
             elseif value:IsA("Folder") then
                local t = recursive(value)
                parentTable[key] = t -- treat folder like a new table
            end
        end
        return parentTable
    end
    local dataEntry = recursive(folder)
        -- i hope this makes sense how i kind of reversed the recursion process in the unloadData function
    return dataEntry
end

function unloadData(player, data)
    local newDataFolder = Instance.new("Folder", player)
    newDataFolder.Name = "PlayerData"
    local function recursive(folder, children)
        for x, y in pairs (children) do
            if typeof(y) == 'table' then
                local newFolder = Instance.new("Folder", folder)
                newFolder.Name = x
                recursive(newFolder, y)
            elseif typeof(y) == 'number' then
                local value = Instance.new("NumberValue", folder)
                value.Name = x
                value.Value = y
            elseif typeof(y) == 'string' then
                local value = Instance.new("StringValue", folder)
                value.Name = x
                value.Value = y
            elseif typeof(y) == 'boolean' then
                local value = Instance.new("BoolValue", folder)
                value.Name = x
                value.Value = y
            else
                local value = Instance.new("StringValue", folder)
                value.Name = x
                value.Value = y
            end
        end
    end
    recursive(newDataFolder, data)
end

local function savePlayerData(player)
    local dataEntry = buildDataEntryFromFolder(player.PlayerData)
    DSService:SetAsync(player.UserId, dataEntry)
end

local function loadPlayerData(player)
    local dataEntry = DSService:GetAsync(player.UserId)

    --  In case there's no data found for the player, construct the data folder from a blank template
    if not dataEntry then
        dataEntry = defaultData
    end

    unloadData(player, dataEntry)

end

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

game.Players.PlayerRemoving:Connect(function(player)
    savePlayerData(player)
end)
0
This did it! I never thought about the way you did the recursion. Excellent fix for sure. Fatul 9 — 4y
Ad
Log in to vote
0
Answered by 4 years ago
Edited 4 years ago

Your save data was messed up, heres your fix (look into buildDataEntryFromFolder)

local DSService = game:GetService('DataStoreService'):GetDataStore('WOOPPOLICE1')

local defaultData = {
    PlayerStats = {
        Name = "None",
        Title = "None",
        Rank = "None",
        Race = "None",
        Birth = "None",
        Shirt = "None",
        Pants = "None",
        Class = "None",
        Lives = 5,
        Days = 0,
        Money = 0,
        Karma = 0,
        Gender = "None",
        LastRewardTick = "",
        }, 
    Skills = {
        Skill1 = {
            SkillEXP = 0,
            SkillLevel = 1,
            SkillRank = "Novice",           
        },
    },
    Equipment = {
        Armor = "None",
        MainHand = "None",
        OffHand = "None",
        Epautlet = "None",
    },
    Inventory = {
        Tools = {},
        Materials = {},     
    }
}

local function buildDataEntryFromFolder(folder)

    local dataEntry = {}

    local total = 0
    recursive = function(tFolder, pFolder) --tableFolder, parentFolder

        for _, data in pairs(pFolder:GetChildren()) do

            print(data, data:IsA("ValueBase"), data:IsA("ValueBase") and data.Value or false)
            tFolder[data.Name] = data:IsA("ValueBase") and data.Value or {}

            if #data:GetChildren() > 0 then

                recursive(tFolder[data.Name], data)

            end

        end

    end

    recursive(dataEntry, folder)

    return dataEntry

end

function unloadData(Player, tFolder)

    Instance.new("Folder", Player).Name = "PlayerData"

   function recursive(folder, children)
        for k, v in pairs(children) do

            local child = Instance.new(typeof(v), folder)
            child.Name = k

            if type(v) ~= "table" then
                child.Value = v
            else
                recursive(child, v)
            end

        end
    end

    recursive(Player.PlayerData, tFolder)

end

local function savePlayerData(player)
    local dataEntry = buildDataEntryFromFolder(player.PlayerData)
    local success, err = pcall(function() DSService:SetAsync(player.UserId, dataEntry) end)

    if success then
        print("Saved Successfully")
    else
        print("Error: " .. err)
    end

end

local function loadPlayerData(player)

    local dataEntry = DSService:GetAsync(player.UserId)

    --  In case there's no data found for the player, construct the data folder from a blank template
    if not dataEntry then
        dataEntry = defaultData
    end

    unloadData(player, dataEntry)

end

game.Players.PlayerAdded:Connect(loadPlayerData)

game.Players.PlayerRemoving:Connect(savePlayerData)
0
Made an edit, this will save when you change value in **SERVER** not client, and load it DragonSkyye 517 — 4y

Answer this question