diff --git a/benches/general.luau b/benches/general.luau index 3f2247b..56529fa 100644 --- a/benches/general.luau +++ b/benches/general.luau @@ -152,10 +152,10 @@ do TITLE "target" world:set(ent, pair(A, B)) world:set(ent, pair(A, C)) world:set(ent, pair(A, D)) - end + end for i = 1, START(N) do - world:target(entities[i], A) + world:target(entities[i], A, 0) end end) @@ -170,7 +170,10 @@ do TITLE(`query {N} entities`) local function view_bench(n: number) BENCH(`{n} entities per archetype`, function() local world = jecs.World.new() - local A, B, C, D = world:entity(), world:entity(), world:entity(), world:entity() + local A = world:component() + local B = world:component() + local C = world:component() + local D = world:component() for i = 1, N, n do local ct = world:entity() @@ -184,15 +187,48 @@ do TITLE(`query {N} entities`) end end + START() for id in world:query(A, B, C, D) do end + end) + BENCH(`inlined query`, function() + local world = jecs.World.new() + local A = world:component() + local B = world:component() + local C = world:component() + local D = world:component() + + for i = 1, N, n do + local ct = world:entity() + for j = 1, n do + local id = world:entity() + world:set(id, A, true) + world:set(id, B, true) + world:set(id, C, true) + world:set(id, D, true) + world:set(id, ct, true) + end + end + + + START() + for _, archetype in world:query(A, B, C, D):archetypes() do + local columns, records = archetype.columns, archetype.records + local a = columns[records[A].column] + local b = columns[records[B].column] + local c = columns[records[C].column] + local d = columns[records[D].column] + for row in archetype.entities do + local _1, _2, _3, _4 = a[row], b[row], c[row], d[row] + end + end end) end for i = 13, 0, -1 do view_bench(2^i) - end + end end diff --git a/src/init.luau b/src/init.luau index 2a8e0e9..ff29be1 100644 --- a/src/init.luau +++ b/src/init.luau @@ -728,8 +728,13 @@ local function world_remove(world: World, entity: i53, id: i53) local to = archetype_traverse_remove(world, id, from) if from and not (from == to) then - invoke_hook(world, EcsOnRemove, id, entity) entity_move(entity_index, entity, record, to) + local idr = world.componentIndex[id] + local flags = idr.flags + local has_on_remove = bit32.band(flags, ECS_ID_HAS_ON_REMOVE) ~= 0 + if has_on_remove then + invoke_hook(world, EcsOnRemove, id, entity) + end end end @@ -955,7 +960,7 @@ local EMPTY_QUERY = { setmetatable(EMPTY_QUERY, EMPTY_QUERY) -local function query_init(query) +local function query_iter(query) local world_query_iter_next if query.should_drain then @@ -1215,12 +1220,8 @@ local function query_init(query) return world_query_iter_next end -local function query_iter(query) - return query_init(query) -end - local function query_drain(query) - local query_iter_next = query_init(query) + local query_iter_next = query_iter(query) query.next = query_iter_next query.should_drain = true return query diff --git a/test/tests.luau b/test/tests.luau index 701946a..68f295e 100644 --- a/test/tests.luau +++ b/test/tests.luau @@ -1284,16 +1284,37 @@ TEST("Hooks", function() end do CASE "OnRemove" - local world = jecs.World.new() - local A = world:component() - local e1 = world:entity() - world:add(e1, A) - world:set(A, jecs.OnRemove, function(entity) - CHECK(e1 == entity) - CHECK(world:has(e1, A)) - end) - world:remove(e1, A) - CHECK(not world:has(e1, A)) + do + -- basic + local world = jecs.World.new() + local A = world:component() + local e1 = world:entity() + world:add(e1, A) + world:set(A, jecs.OnRemove, function(entity) + CHECK(e1 == entity) + CHECK(not world:has(e1, A)) + end) + world:remove(e1, A) + CHECK(not world:has(e1, A)) + end + do + -- [BUG] https://github.com/Ukendio/jecs/issues/118 + local world = world_new() + local A = world:component() + local B = world:component() + local e = world:entity() + + world:set(A, jecs.OnRemove, function(entity) + world:set(entity, B, true) + CHECK(not world:get(entity, A)) + CHECK(world:get(entity, B)) + end) + + world:set(e, A, true) + world:remove(e, A) + CHECK(not world:get(e, A)) + CHECK(world:get(e, B)) + end end do CASE "the filip incident"