Search code examples
luaentity-component-systemdata-oriented-design

How To Copy Nested Table Values on Matching Keys


I'm trying to implement the concept of assemblages using pure Lua tables. Assemblages are larger tables while archetypes/classes are smaller tables with matching keys meant to modify the default values in an assemblage. This has been working fine, but all the components sat at the same level within the entity. Now I'm trying to organize components by category like so:

archetype = {
   physics = {
        accel = 100, vel = {50, 50}, jump = 80
        },

The assemblage just has an empty table under physics (physics = {})

My function to assemble an entity was this:

function assemble_entity(assemblage, arch, x, y)
    new_ent = deepcopy(assemblage)
    for pkey, pvalue in pairs(new_ent) do
        for ckey, cvalue in pairs(arch) do
            if pkey == ckey then
                if type(cvalue) == 'table' then
                    new_ent[pkey] = deepcopy(cvalue)
                else
                    new_ent[pkey] = cvalue
                end
            end
        end
    end
end

(deepcopy is just taken from the lua users wiki)

However, because an archetype table only contains modified values, copying the archetype's components to the assemblage will overwrite the assemblage's default values. I tried my hand at recursion:

function assemble_entity(assemblage, arch)
    new_ent = deepcopy(assemblage)
    for pkey, pvalue in pairs(new_ent) do
        for ckey, cvalue in pairs(arch) do
            if pkey == ckey then
                if type(cvalue) == 'table' then
                    new_ent[pkey] = assemble_entity(pvalue, cvalue)
                else
                    new_ent[pkey] = cvalue
                end
            end
        end
    end
    return new_ent
end

(just swapped deepcopy with assemble_entity)

The problem I'm finding is that most components return nil (and it's conspicuously inefficient, but it's not called every frame), so it's definitely wrong. I've never messed with recursion before, so any help is appreciated.

I could just solve this by storing every value in the archetypes, but then there'd be no point in using assemblages and I'd have a lotof typing ahead of me.


Solution

  • After a fresh look at it, I realized that I only want to modify a single copy of the assemblage table's contents, so deepcopy() is necessary only on the first iteration of assemble_entity. Creating a copy of its nested components in recursive calls is unnecessary, so I changed my function call to:

    new_ent = deepcopy(assemblage)
    new_ent = assemble_entity(new_ent, archetype)
    

    And now it works