Is there a way to collect the children in a Folder and save the values to the DataStore using :GetChildren() or some other method that will collect the values and save them?
I have a folder that is empty, players collect items and the items are sent to that folder. I want to save what the user has collected.
You will need to do the get and save requests where shown, but this should help convert your folders into a saleable and load able format.
Be sure to define playerFolder
Saving:
--Saving data
local dataToSave = {}
for i,v in pairs(playerFolder:GetChildren()) do
table.insert(dataToSave, v.Name)
end
--Save the table to a key
dataStore:UpdateAsync(key, function(oldValue)
--Do some kind of check if you want
return dataToSave
end)
Loading:
local loadedData = --Load data from key
local loadedData = dataStore:GetAsync(key) --Example
for i,v in pairs(loadedData) do
local n = Instance.new('Folder')
n.Name = v
n.Parent = playerFolder
end
Instead of saving the whole instances, I recommend saving them through serialization or identifications of each item. Maybe even through the objects’ name.
After loading, or DataStore:GetAsync(), a table is returned from the data store which contains the items’ IDs, follows up by reading off the IDs but also important data with the object. The game will create the objects using the data read from the matching data.
To clarify exactly what do you do with the strings or numbers inside the table, you’ll need another table which is a structure containing the key which matches the contents of the table. Run a for loop throughout the table, and use the value to read the table’s key’s values.
-- table storing the key to respective contents
local coolTable = {
[1] = {"cool contents bro"};
[2] = {"cooler contents bro"};
[3] = {"epic contents bro"}
}
-- load data
local success, data = pcall(DataStore.GetAsync, DataStore, key) -- key is associated key to the player
if success then
for _, value in next, data["contents bro"] do
print(value, coolTable[value]) -- if the value was 1, it would print out "cool contents bro"
end
end
local key = -- Set your Key
local datastore = game:GetService("DataStoreService"):GetDataStore("") -- DataStore Name
local datatable = {}
local tablenum = 0
local folder = -- Folder
for _,value in pairs(folder:GetChildren()) do --Only Values can be in the Folder
tablenum = tablenum + 1
table.insert(datatable,tablenum,{["Value"] = value.Value;["Name"] = value.Name})
end
local success, err = pcall(function()
datastore:UpdateAsync(key, function(old) -- Updates Data
local new = old or nil
new = datatable
return new
end)
end)
Loading
--Create Values
local datastore = game:GetService("DataStoreService"):GetDataStore("") -- DataStore Name
local datatable = datastore:GetAsync(player.userId)
if datatable then
local folder = -- Folder
local tablenum = 0
for _,value in pairs(folder:GetChildren()) do --Only Values can be in the Folder
local data = nil
for i = 1, #datatable do
local check = datatable[i]
local name = check["Name"]
if name and value.Name == name then
data = check
end
end
if data ~= nil then
if value.Name == data.Name then
value.Value = data.Value
end
end
end
end
UpdateAsync is always better practice, and setAsync overrides the value directly. I wanted to make sure the @OP knew that there was a ability to do so; I didn’t want them to lose data later on because they didn’t know about it. That’s why I added that you could do a check if you wanted.
UpdateAsync is only a better practice because it gives you the old value. The function itself is not inherently better to use. If you don’t use the old value, it’s just as bad, if not worse, since you’re creating a pointless function that just returns one value.
Saying “Do some kind of check if you want” can be a bit misleading, since there’s no reason to use UpdateAsync it you aren’t doing any kind of checks.
There’s a point on the other thread about the inherent benefits of UpdateAsync that are skipped over, primarily the operations done on the backend, the workflow of Get-Set-Update and caching.
UpdateAsync isn’t pointless, even if you throw away the oldValue (which really you shouldn’t).
I actually use this same method. After my DataService loads a player’s data from the datastores and validates it, it converts the data table containing the player’s data (mind you the table has many sub-tables as well) into a folder/value structure, and places it in ReplicatedStorage.
When the data is saved, I simply convert the data from its folder/value structure back into a table structure.
I do this so Roblox replication can handle the replication of any changes to my player’s data, mainly because I’m too lazy to write my own replication system to replicate data changes to the client.
I have two useful functions in my table util module called ConvertTableToFolder and ConvertFolderToTable that allow me to do this. Please keep in mind that the code is old, so it’s a bit ugly.
ConvertFolderToTable.lua:
local function ConvertFolderToTable(Folder)
local Tab={}
local Keyname;
local Value;
for i,v in pairs(Folder:GetChildren()) do
if v:IsA("Folder") then
Value=ConvertFolderToTable(v)
Keyname=v.Name
else
Keyname=v.Name
Value=v.Value
end
Tab[Keyname]=Value
end
return Tab
end
return ConvertFolderToTable
ConvertTableToFolder.lua:
local function ConvertTableToFolder(Original_Table)
local Folder=Instance.new('Folder')
local Object;
for Index,Value in pairs(Original_Table) do
if typeof(Value)=="table" then
Object=ConvertTableToFolder(Value)
else
if typeof(Value)=="number" then
Object=Instance.new('NumberValue')
end
if typeof(Value)=="string" then
Object=Instance.new('StringValue')
end
if typeof(Value)=="boolean" then
Object=Instance.new('BoolValue')
end
if typeof(Value)=="Instance" then
Object=Instance.new('ObjectValue')
end
Object.Value=Value
end
Object.Name=Index
Object.Parent=Folder
end
return Folder
end
return ConvertTableToFolder