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

How do you serialize data to be saved through datastores?

Asked by 5 years ago

Only way I know to save data is through tables, I seen dozens of posts about serialization but none actually explained in-depth what it was nor provided sufficient examples of it for anyone to use. Roblox doesn't even provide any documentation on serialization so how is anyone supposed to know how to do it?

I want to save data for example shop data, if a player buys a weapon from a shop it saves the data that they own the item. One question I always wanted to know, what would be the best way of saving the items they own? BoolValues or what?

Anyways, how would I easily save and load the items they already own (for example using boolValues that they own that item) without making long long tables which take up memory.

2 answers

Log in to vote
0
Answered by 5 years ago

The way I do it is to have each item containing an IntValue which has the id I have created for the item in it. Then when a player leaves the game I loop through all the items they own and get the id. Once I get the id I add it to a table of other ids. The reason I prefer this method is that the ids can be in any order as long as they are in the table. If I were to use BoolValues instead I would need to put each bool value at a particular index in the table. When the player rejoins the game I check if they have history and if so I loop through the datastore table and also loop through all the items the player could possibly buy. For each item that has an id that is in the datastore I Clone() it and give it to them. As I said earlier the ids can be added to the table in any order because the index does not matter. So if you have multiple locations you are getting data to add to the table you can just use table.insert and you are good to go. I hope this helps and have a great day scripting! Side note: The table that I am creating full of ids may take up memory but it will not be enough to cause any noticeable difference in your game as long as your datastore requests are not being overused.

Ad
Log in to vote
0
Answered by
ozzyDrive 670 Moderation Voter
5 years ago

You don't really have to worry about memory usage since the per-key data limit is quite large (~260000 characters). You can also check the size of the data you're storing by converting the data into a JSON string and calculating its length with the string.len function. You can store any value that can be JSONified.

It really comes down to how your game is set up. If you're storing a player's data as values inside a folder somewhere, simply iterate through it and construct a table. You can then write a function to do the opposite: construct a folder from a data entry for loading the data into the game. For example:

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

local function buildFolderFromDataEntry(dataEntry)
    local folder = Instance.new("Folder")

    for name, info in next, dataEntry do
        local value = Instance.new(info.valueType)
        value.Value = info.value
        value.Parent = folder
    end

    return folder
end

local function savePlayerData(player)
    local dataEntry = buildDataEntryFromFolder(player.dataFolder)
    playerDataStore:SetAsync(player.UserId, dataEntry)
end

local function loadPlayerData(player)
    local dataEntry = playerDataStore: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 = dataTemplate
    end

    local folder = buildFolderFromDataEntry(dataEntry)
    folder.Name = "dataFolder"
    folder.Parent = player

    return dataEntry, folder
end

The dataTemplate table could look like this:

local dataTemplate = {
    kills = {
        valueType = "IntValue",
        value = 0,
    },
    deaths = {
        valueType = "IntValue",
        value = 0,
    },
    customName = {
        valueType = "StringValue",
        value = "data-wizard",
    },
    ownsACoolSword = {
        valueType = "BoolValue",
        value = false,
    },
}

Of course, you could scrap the dataTemplate table and directly clone a pre-built folder structure. There are multiple ways of doing stuff. I personally avoid the value objects all I can and prefer writing my own structures with the functionality I want.

The end result will depend on what kind of data exactly you want to store. The example above doesn't support very organized data-structures as it just throws them all into one table instead of splitting between multiple sub-tables (and -folders), for example.

Anyways, how would I easily save and load the items they already own

You can grab the player data with the "loadPlayerData" function, iterate through the data (this is where the sub-folders would come in handy) , check if they own the item and if so, give it to them.

game.Players.PlayerAdded:Connect(function(player)
    local playerData = loadPlayerData(player)
    --  assuming "playerData" has an "items" sub-table
    for itemIdentifier, info in next, playerData.items do
        if info.value then
            giveItem(player, itemIdentifier)
        end
    end
end)

Answer this question