diff --git a/jecs.luau b/jecs.luau index 6874e0c..356626b 100755 --- a/jecs.luau +++ b/jecs.luau @@ -929,18 +929,6 @@ local function find_archetype_with(world: World, id: Id, from: Archetype): Arche local id_types = from.types local dst = table.clone(id_types) - if ECS_IS_PAIR(id::number) then - local first = ECS_PAIR_FIRST(id::number) - local idr = world.component_index[ECS_PAIR(first, EcsWildcard)] - if idr and bit32.btest(idr.flags, EcsExclusive) then - local cr = idr.records[from.id] - if cr then - dst[cr] = id - return archetype_ensure(world, dst) - end - end - end - local at = find_insert(id_types :: { number } , id :: number) table.insert(dst, at, id) @@ -2204,6 +2192,90 @@ local function world_new() return r end + local function inner_world_add( + world: World, + entity: Entity, + id: Id + ): () + local entity_index = world.entity_index + local record = inner_entity_index_try_get_unsafe(entity :: number) + if not record then + return + end + + local from = record.archetype + if ECS_IS_PAIR(id::number) then + local src = from or ROOT_ARCHETYPE + local edge = archetype_edges[src.id] + local to = edge[id] + local idr: ComponentRecord + 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 + local cr = idr.records[src.id] + if cr then + local on_remove = idr.hooks.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) + 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 + else + idr = component_index[id] + end + if from == to then + return + end + if from then + entity_move(entity_index, entity, record, to) + else + if #to.types > 0 then + new_entity(entity, record, to) + end + end + + local on_add = idr.hooks.on_add + + if on_add then + on_add(entity, id) + end + return + end + local to = archetype_traverse_add(world, id, from) + if from == to then + return + end + if from then + entity_move(entity_index, entity, record, to) + else + if #to.types > 0 then + new_entity(entity, record, to) + end + end + + local idr = world.component_index[id] + local on_add = idr.hooks.on_add + + if on_add then + on_add(entity, id) + end + end local function inner_world_get(world: World, entity: Entity, a: Id, b: Id?, c: Id?, d: Id?, e: Id?): ...any @@ -2319,38 +2391,6 @@ local function world_new() return to end - local function inner_world_add( - world: World, - entity: Entity, - id: Id - ): () - local entity_index = world.entity_index - local record = inner_entity_index_try_get_unsafe(entity :: number) - if not record then - return - end - - local from = record.archetype - local to = archetype_traverse_add(world, id, from) - if from == to then - return - end - if from then - entity_move(entity_index, entity, record, to) - else - if #to.types > 0 then - new_entity(entity, record, to) - end - end - - local idr = world.component_index[id] - local on_add = idr.hooks.on_add - - if on_add then - on_add(entity, id) - end - end - local function inner_world_set(world: World, entity: Entity, id: Id, data: a): () local record = inner_entity_index_try_get_unsafe(entity :: number) if not record then diff --git a/test/tests.luau b/test/tests.luau index 3c20fdc..b9c09dd 100755 --- a/test/tests.luau +++ b/test/tests.luau @@ -159,7 +159,6 @@ TEST("repro", function() end) TEST("world:add()", function() - print("-----") do CASE "idempotent" local world = jecs.world() local d = dwi(world) @@ -211,6 +210,9 @@ TEST("world:children()", function() local e3 = world:entity() world:add(e3, pair(ChildOf, e1)) + CHECK(world:has(e2, pair(ChildOf, e1))) + CHECK(world:has(e3, pair(ChildOf, e1))) + local count = 0 for entity in world:children(e1) do count += 1