Hello devforum, I’ve been dying to figure this out. Let me explain:
I have a way to convert a table to a tree of instances, but how do I do the opposite? To give you an idea of what I’m struggling with here’s what it looks like converting a table to a tree of instances:
local function createData(data, parent)
for index, value in pairs(data) do
if typeof(value) == "table" then
local folder = Instance.new("Folder")
folder.Name = index
folder.Parent = parent
createData(value, folder)
end
if typeof(value) == "string" then
local stringValue = Instance.new("StringValue")
stringValue.Name = index
stringValue.Value = value
stringValue.Parent = parent
end
if typeof(value) == "boolean" then
local boolValue = Instance.new("BoolValue")
boolValue.Name = index
boolValue.Value = value
boolValue.Parent = parent
end
if typeof(value) == "number" then
local boolValue = Instance.new("NumberValue")
boolValue.Name = index
boolValue.Value = value
boolValue.Parent = parent
end
end
end
The other topic only shows how to create one layer of children, I want a way to do this infinitely.
You first use GetDescendants() which returns a table of instances. Then use a for loop to iterate through all the instances to create tables with the the information (table.insert() will help)
To elaborate, when I was writing the code I didn’t know how to keep the hierarchy of the table within the instance. I want a way to keep the hierarchy of the folder.
Its pretty easy to reverse it using the function you provided. Since the function operates recursively you can go as deep as you want into it. Really all you need to do is switch the arguments in the if statements with what you are creating in the if statements. So essentially it would be like this
local function createData(datafolder,datatable)
-- we will create a new table to hold the data
for index, value in pairs(datafolder:GetChildren()) do
if value:IsA("Folder") then
local t = {} -- this table represents the folder
-- since you had it that the index in the original table was the name of the value we will put the values in the table at the index which is their name
datatable[value.Name] = t
-- do the recursion
createData(value,t)
end
-- since the type of the value doesn't matter when were inserting it we can just use on if statement
-- we can determine if a instance value is a value by checking if it has a .Value property and not a child named "Value"(ik its kind of hacky but i dont want to type our like 3 more ifstatements)
if value["Value"] and not value:FindFirstChild("Value") then
datatable[value.Name] = value.Value
end
end
end
You essentially want to do the exact opposite of what you’re doing. That is, something like this:
local function instanceToTree(obj)
local tree = {}
for _, v in ipairs(obj:GetChildren()) do
if v:IsA("Folder") then
tree[v.Name] = {}
elseif v:IsA("StringValue") then
tree[v.Name] = v.Value
elseif v:IsA("NumberValue") then
-- And so on
end
return tree
end
There’s an obvious problem to solve though: that only handles the root of the Instance, which isn’t good enough. It also doesn’t account for when you want an array (though at this point I’d like to take a moment and ask you if you think this is a good idea; how do you tell whether you mean the key 1 or the key “1”?).
The easiest way to handle the first issue would be with recursion, which you already have in the OP. The easiest way I can think of to implement this is something like this:
local function instanceToTree(obj)
local tree = {}
for _, v in ipairs(obj:GetChildren()) do
if v:IsA("Folder") then
tree[v.Name] = instanceToTree(v) -- This ensures that whenever a folder shows up, it and its children get added
elseif v:IsA("StringValue") then
tree[v.Name] = v.Value
elseif v:IsA("NumberValue") then
-- And so on
end
return tree
end
There’s a better way to do this which @wafflecow321 touched on in his code snippet where you can actually just put all Value objects in their own branch of the if-statement. Rather than doing what he did though, I would check if an object is a ValueBase, which all Value objects inherit from. You can do that with v:IsA("ValueBase") but I’ll leave the full implementation to you if you want to experiment with it.
For the sake of brevity I’m also not touching on how to check for arrays, since that’s simple enough. I just wanted you to think about that while implementing this.
I wish I knew about ValueBase before lol. Is there a source of information where you can get superclass names for things like values? In the Roblox Dev Hub theres a class tree but it doesnt show base classes like ValueBase.
I believe that’s because ValueBase is just an empty identifier superclass. No ValueObject actually inherits from it if you check their pages and the ValueBase class doesn’t have any items common to a ValueObject, given that each Value’s use case is unique and all other properties are either unique to that type of ValueObject or just inherited from Instance.
You can request for its addition to the Class Tree via the Developer Hub category in Platform Feedback.
I tend to use a site Anaminus hosts, Roblox API Reference. It’s automatically generated from the API dump so it’s as up to date as anything can be. It’s super helpful for when you need more esoteric knowledge of the API like what super classes something has.
It’s a bit of a shame that this info isn’t on the devhub, though I suppose some things inevitably get lost. Like Colbert said, I encourage you to make a documentation request for ValueBase at the very least since it can save people a lot of grief.