diff --git a/.github/workflows/styling.yaml b/.github/workflows/styling.yaml deleted file mode 100644 index 4d28cabb..00000000 --- a/.github/workflows/styling.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: Styling - -on: [push, pull_request, workflow_dispatch] - -jobs: - run: - name: Run Stylua - runs-on: ubuntu-latest - - steps: - - name: Checkout Project - uses: actions/checkout@v4 - - - name: Run Stylua - uses: JohnnyMorganz/stylua-action@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - version: latest # NOTE: we recommend pinning to a specific version in case of formatting changes - # CLI arguments - args: --check jecs.luau diff --git a/jecs.luau b/jecs.luau index ff93b00b..832763cb 100644 --- a/jecs.luau +++ b/jecs.luau @@ -257,7 +257,7 @@ local function archetype_move(entity_index: EntityIndex, to: Archetype, dst_row: local src_entities = from.entities local last = #src_entities - local types = from.types + local id_types = from.types local records = to.records for i, column in src_columns do @@ -266,12 +266,13 @@ local function archetype_move(entity_index: EntityIndex, to: Archetype, dst_row: end -- Retrieves the new column index from the source archetype's record from each component -- We have to do this because the columns are tightly packed and indexes may not correspond to each other. - local tr = records[types[i]] + local tr = records[id_types[i]] -- Sometimes target column may not exist, e.g. when you remove a component. if tr then dst_columns[tr.column][dst_row] = column[src_row] end + -- If the entity is the last row in the archetype then swapping it would be meaningless. if src_row ~= last then -- Swap rempves columns to ensure there are no holes in the archetype. @@ -475,7 +476,8 @@ local function id_record_ensure(world: World, id: number): IdRecord if not idr then local flags = ECS_ID_MASK local relation = id - if ECS_IS_PAIR(id) then + local is_pair = ECS_IS_PAIR(id) + if is_pair then relation = ecs_pair_first(world, id) end @@ -492,6 +494,10 @@ local function id_record_ensure(world: World, id: number): IdRecord local is_tag = not world_has_one_inline(world, relation, EcsComponent) + if is_tag and is_pair then + is_tag = not world_has_one_inline(world, ecs_pair_second(world, id), EcsComponent) + end + flags = bit32.bor( flags, if on_add then ECS_ID_HAS_ON_ADD else 0, @@ -535,15 +541,15 @@ local function archetype_append_to_records( end end -local function archetype_create(world: World, types: { i24 }, ty, prev: i53?): Archetype +local function archetype_create(world: World, id_types: { i24 }, ty, prev: i53?): Archetype local archetype_id = (world.nextArchetypeId :: number) + 1 world.nextArchetypeId = archetype_id - local length = #types + local length = #id_types local columns = (table.create(length) :: any) :: { Column } local records: { ArchetypeRecord } = {} - for i, componentId in types do + for i, componentId in id_types do local idr = id_record_ensure(world, componentId) archetype_append_to_records(idr, archetype_id, records, componentId, i) @@ -572,7 +578,7 @@ local function archetype_create(world: World, types: { i24 }, ty, prev: i53?): A id = archetype_id, records = records, type = ty, - types = types, + types = id_types, add = {}, remove = {}, @@ -593,22 +599,22 @@ local function world_parent(world: World, entity: i53) return world_target(world, entity, EcsChildOf, 0) end -local function archetype_ensure(world: World, types): Archetype - if #types < 1 then +local function archetype_ensure(world: World, id_types): Archetype + if #id_types < 1 then return world.ROOT_ARCHETYPE end - local ty = hash(types) + local ty = hash(id_types) local archetype = world.archetypeIndex[ty] if archetype then return archetype end - return archetype_create(world, types, ty) + return archetype_create(world, id_types, ty) end -local function find_insert(types: { i53 }, toAdd: i53): number - for i, id in types do +local function find_insert(id_types: { i53 }, toAdd: i53): number + for i, id in id_types do if id == toAdd then return -1 end @@ -616,7 +622,7 @@ local function find_insert(types: { i53 }, toAdd: i53): number return i end end - return #types + 1 + return #id_types + 1 end local function find_archetype_with(world: World, node: Archetype, id: i53): Archetype @@ -886,7 +892,7 @@ end local function archetype_delete(world: World, archetype: Archetype, row: number, destruct: boolean?) local entityIndex = world.entity_index local columns = archetype.columns - local types = archetype.types + local id_types = archetype.types local entities = archetype.entities local column_count = #entities local last = #entities @@ -905,7 +911,7 @@ local function archetype_delete(world: World, archetype: Archetype, row: number, -- TODO: if last == 0 then deactivate table - for _, id in types do + for _, id in id_types do local on_remove: (entity: i53) -> () = world_get_one_inline(world, id, EcsOnRemove) if on_remove then on_remove(delete) @@ -913,9 +919,9 @@ local function archetype_delete(world: World, archetype: Archetype, row: number, end if row == last then - archetype_fast_delete_last(columns, column_count, types, delete) + archetype_fast_delete_last(columns, column_count, id_types, delete) else - archetype_fast_delete(columns, column_count, row, types, delete) + archetype_fast_delete(columns, column_count, row, id_types, delete) end end @@ -1769,23 +1775,19 @@ function World.new() return self end -export type Id = Entity | Pair, Entity> +export type Id = Entity -export type Pair = number & { - __relation: First, -} +type function _Pair(first, second) + local thing = first:components()[2] --- type function _Pair(first, second) --- local thing = first:components()[2] - --- if thing:readproperty(types.singleton("__T")):is("nil") then --- return second --- else --- return first --- end --- end + if thing:readproperty(types.singleton("__T")):is("nil") then + return second + else + return first + end +end --- type TestPair = _Pair, Entity> +export type Pair = _Pair type Item = (self: Query) -> (Entity, T...) diff --git a/test/tests.luau b/test/tests.luau index 2f47089c..12d60b13 100644 --- a/test/tests.luau +++ b/test/tests.luau @@ -165,8 +165,7 @@ TEST("world:entity()", function() CHECK(ECS_GENERATION(e) == 1) -- 1 end - do - CASE("pairs") + do CASE("pairs") local world = jecs.World.new() local _e = world:entity() local e2 = world:entity() @@ -175,11 +174,17 @@ TEST("world:entity()", function() -- Incomplete pair, must have a bit flag that notes it is a pair CHECK(IS_PAIR(world:entity()) == false) - local pair = pair(e2, e3) - CHECK(IS_PAIR(pair) == true) + local p = pair(e2, e3) + CHECK(IS_PAIR(p) == true) + + CHECK(ecs_pair_first(world, p) == e2) + CHECK(ecs_pair_second(world, p) == e3) + + world:delete(e2) + local e2v2 = world:entity() + CHECK(IS_PAIR(e2v2) == false) - CHECK(ecs_pair_first(world, pair) == e2) - CHECK(ecs_pair_second(world, pair) == e3) + CHECK(IS_PAIR(pair(e2v2, e3)) == true) end do CASE "Recycling" @@ -281,7 +286,7 @@ TEST("world:set()", function() CHECK(world:get(e, pair(C1, C2))) CHECK(world:get(e, pair(C1, T1))) - CHECK(not world:get(e, pair(T1, C1))) + CHECK(world:get(e, pair(T1, C1))) CHECK(not world:get(e, pair(T1, T2))) local e2 = world:entity() @@ -399,7 +404,7 @@ TEST("world:query()", function() for id, a, b, c, d in world:query(pair(C1, C2), pair(C1, T1), pair(T1, C1), pair(T1, T2)) do CHECK(a == true) CHECK(b == true) - CHECK(c == nil) + CHECK(c == true) CHECK(d == nil) end end