diff --git a/jecs.luau b/jecs.luau index 60c77da..095d84c 100755 --- a/jecs.luau +++ b/jecs.luau @@ -2320,13 +2320,44 @@ local function world_new() local to: Archetype local idr: ComponentRecord if ECS_IS_PAIR(id::number) then + local first = ECS_PAIR_FIRST(id::number) + local wc = ECS_PAIR(first, EcsWildcard) + idr = component_index[wc] + local edge = archetype_edges[src.id] to = edge[id] - if not to then - local first = ECS_PAIR_FIRST(id::number) - local wc = ECS_PAIR(first, EcsWildcard) - idr = component_index[wc] - if idr and bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then + if to == nil then + if idr and (bit32.btest(idr.flags) == true) then + local cr = idr.records[src.id] + if cr then + local on_remove = idr.on_remove + local id_types = src.types + if on_remove then + on_remove(entity, id_types[cr]) + + src = record.archetype + id_types = src.types + cr = idr.records[src.id] + end + + local dst = table.clone(id_types) + dst[cr] = id + to = archetype_ensure(world, dst) + end + end + + if not to then + to = find_archetype_with(world, id, src) + end + + if not idr then + idr = component_index[wc] + end + + edge[id] = to + archetype_edges[(to :: Archetype).id][id] = src + else + if bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then local cr = idr.records[src.id] if cr then local on_remove = idr.on_remove @@ -2340,18 +2371,11 @@ local function world_new() local dst = table.clone(id_types) dst[cr] = id to = archetype_ensure(world, dst) - else - to = find_archetype_with(world, id, src) - idr = component_index[id] end - else - to = find_archetype_with(world, id, src) - idr = component_index[id] end - edge[id] = to - archetype_edges[to.id][id] = src - else - idr = component_index[id] + if not to then + to = find_archetype_with(world, id, src) + end end else local edges = archetype_edges @@ -2401,14 +2425,46 @@ local function world_new() end local to: Archetype local idr: ComponentRecord + if ECS_IS_PAIR(id::number) then + local first = ECS_PAIR_FIRST(id::number) + local wc = ECS_PAIR(first, EcsWildcard) + idr = component_index[wc] + local edge = archetype_edges[src.id] to = edge[id] - if not to then - local first = ECS_PAIR_FIRST(id::number) - local wc = ECS_PAIR(first, EcsWildcard) - idr = component_index[wc] - if idr and bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then + if to == nil then + if idr and (bit32.btest(idr.flags) == true) then + local cr = idr.records[src.id] + if cr then + local on_remove = idr.on_remove + local id_types = src.types + if on_remove then + on_remove(entity, id_types[cr]) + + src = record.archetype + id_types = src.types + cr = idr.records[src.id] + end + + local dst = table.clone(id_types) + dst[cr] = id + to = archetype_ensure(world, dst) + end + end + + if not to then + to = find_archetype_with(world, id, src) + end + + if not idr then + idr = component_index[wc] + end + + edge[id] = to + archetype_edges[(to :: Archetype).id][id] = src + else + if bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then local cr = idr.records[src.id] if cr then local on_remove = idr.on_remove @@ -2422,18 +2478,11 @@ local function world_new() local dst = table.clone(id_types) dst[cr] = id to = archetype_ensure(world, dst) - else - to = find_archetype_with(world, id, src) - idr = component_index[id] end - else - to = find_archetype_with(world, id, src) - idr = component_index[id] end - edge[id] = to - archetype_edges[to.id][id] = src - else - idr = component_index[id] + if not to then + to = find_archetype_with(world, id, src) + end end else local edges = archetype_edges diff --git a/test/tests.luau b/test/tests.luau index 21a4167..731af9e 100755 --- a/test/tests.luau +++ b/test/tests.luau @@ -346,23 +346,12 @@ TEST("world:add()", function() world:add(A, jecs.Exclusive) local on_remove_call = false world:set(A, jecs.OnRemove, function(e, id) - CHECK(e == e_ptr) - CHECK(id == jecs.pair(A, B)) on_remove_call = true end) local on_add_call_count = 0 world:set(A, jecs.OnAdd, function(e, id) on_add_call_count += 1 - if on_add_call_count == 1 then - CHECK(e == e_ptr) - CHECK(id == jecs.pair(A, B)) - elseif on_add_call_count == 2 then - CHECK(e == e_ptr) - CHECK(id == jecs.pair(A, C)) - else - CHECK(false) - end end) @@ -377,6 +366,17 @@ TEST("world:add()", function() CHECK(world:has(e, pair(A, B)) == false) CHECK(world:has(e, pair(A, C)) == true) + -- We have to ensure that it actually invokes hooks everytime it + -- traverses the archetype + e = world:entity() + world:add(e, pair(A, B)) + CHECK(on_add_call_count == 3) + world:add(e, pair(A, C)) + CHECK(on_add_call_count == 4) + CHECK(on_remove_call) + + CHECK(world:has(e, pair(A, B)) == false) + CHECK(world:has(e, pair(A, C)) == true) end do CASE "idempotent"