mirror of
https://github.com/Ukendio/jecs.git
synced 2025-08-04 11:19:17 +00:00
Compare commits
2 commits
7c8358656a
...
9b57189c3a
Author | SHA1 | Date | |
---|---|---|---|
|
9b57189c3a | ||
|
4ff492ceaf |
3 changed files with 95 additions and 87 deletions
|
@ -74,11 +74,12 @@ return function(world: types.World)
|
||||||
local removed = map.removed
|
local removed = map.removed
|
||||||
|
|
||||||
if removed then
|
if removed then
|
||||||
for i, e in removed do
|
for _, entity in removed do
|
||||||
if not world:contains(e) then
|
entity = ecs_map_get(world, entity)
|
||||||
|
if not world:contains(entity) then
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
world:remove(e, id)
|
world:remove(entity, id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
43
jecs.luau
43
jecs.luau
|
@ -439,6 +439,7 @@ end
|
||||||
|
|
||||||
local function archetype_move(
|
local function archetype_move(
|
||||||
entity_index: EntityIndex,
|
entity_index: EntityIndex,
|
||||||
|
entity: Entity,
|
||||||
to: Archetype,
|
to: Archetype,
|
||||||
dst_row: i24,
|
dst_row: i24,
|
||||||
from: Archetype,
|
from: Archetype,
|
||||||
|
@ -452,6 +453,9 @@ local function archetype_move(
|
||||||
local id_types = from.types
|
local id_types = from.types
|
||||||
local columns_map = to.columns_map
|
local columns_map = to.columns_map
|
||||||
|
|
||||||
|
if src_row ~= last then
|
||||||
|
-- If the entity is the last row in the archetype then swapping it would be meaningless.
|
||||||
|
|
||||||
for i, column in src_columns do
|
for i, column in src_columns do
|
||||||
if column == NULL_ARRAY then
|
if column == NULL_ARRAY then
|
||||||
continue
|
continue
|
||||||
|
@ -465,35 +469,42 @@ local function archetype_move(
|
||||||
dst_column[dst_row] = column[src_row]
|
dst_column[dst_row] = column[src_row]
|
||||||
end
|
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.
|
-- Swap rempves columns to ensure there are no holes in the archetype.
|
||||||
column[src_row] = column[last]
|
column[src_row] = column[last]
|
||||||
end
|
|
||||||
column[last] = nil
|
column[last] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local moved = #src_entities
|
|
||||||
|
|
||||||
-- Move the entity from the source to the destination archetype.
|
-- Move the entity from the source to the destination archetype.
|
||||||
-- Because we have swapped columns we now have to update the records
|
-- Because we have swapped columns we now have to update the records
|
||||||
-- corresponding to the entities' rows that were swapped.
|
-- corresponding to the entities' rows that were swapped.
|
||||||
local e1 = src_entities[src_row]
|
|
||||||
local e2 = src_entities[moved]
|
|
||||||
|
|
||||||
if src_row ~= moved then
|
local e2 = src_entities[last]
|
||||||
src_entities[src_row] = e2
|
src_entities[src_row] = e2
|
||||||
end
|
|
||||||
|
|
||||||
src_entities[moved] = nil :: any
|
|
||||||
dst_entities[dst_row] = e1
|
|
||||||
|
|
||||||
local sparse_array = entity_index.sparse_array
|
local sparse_array = entity_index.sparse_array
|
||||||
|
|
||||||
local record1 = sparse_array[ECS_ENTITY_T_LO(e1 :: number)]
|
|
||||||
local record2 = sparse_array[ECS_ENTITY_T_LO(e2 :: number)]
|
local record2 = sparse_array[ECS_ENTITY_T_LO(e2 :: number)]
|
||||||
record1.row = dst_row
|
|
||||||
record2.row = src_row
|
record2.row = src_row
|
||||||
|
else
|
||||||
|
for i, column in src_columns do
|
||||||
|
if column == NULL_ARRAY then
|
||||||
|
continue
|
||||||
|
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 dst_column = columns_map[id_types[i]]
|
||||||
|
|
||||||
|
-- Sometimes target column may not exist, e.g. when you remove a component.
|
||||||
|
if dst_column then
|
||||||
|
dst_column[dst_row] = column[src_row]
|
||||||
|
end
|
||||||
|
|
||||||
|
column[last] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
src_entities[last] = nil :: any
|
||||||
|
dst_entities[dst_row] = entity
|
||||||
end
|
end
|
||||||
|
|
||||||
local function archetype_append(
|
local function archetype_append(
|
||||||
|
@ -526,7 +537,7 @@ local function entity_move(
|
||||||
local sourceRow = record.row
|
local sourceRow = record.row
|
||||||
local from = record.archetype
|
local from = record.archetype
|
||||||
local dst_row = archetype_append(entity, to)
|
local dst_row = archetype_append(entity, to)
|
||||||
archetype_move(entity_index, to, dst_row, from, sourceRow)
|
archetype_move(entity_index, entity, to, dst_row, from, sourceRow)
|
||||||
record.archetype = to
|
record.archetype = to
|
||||||
record.row = dst_row
|
record.row = dst_row
|
||||||
end
|
end
|
||||||
|
@ -2459,8 +2470,8 @@ local function world_new()
|
||||||
local idr_archetype = archetypes[archetype_id]
|
local idr_archetype = archetypes[archetype_id]
|
||||||
local entities = idr_archetype.entities
|
local entities = idr_archetype.entities
|
||||||
local n = #entities
|
local n = #entities
|
||||||
|
table.move(entities, 1, n, count + 1, queue)
|
||||||
count += n
|
count += n
|
||||||
table.move(entities, 1, n, #queue + 1, queue)
|
|
||||||
end
|
end
|
||||||
for _, e in queue do
|
for _, e in queue do
|
||||||
inner_world_remove(world, e, entity)
|
inner_world_remove(world, e, entity)
|
||||||
|
|
|
@ -22,57 +22,10 @@ type Entity<T=nil> = jecs.Entity<T>
|
||||||
type Id<T=unknown> = jecs.Id<T>
|
type Id<T=unknown> = jecs.Id<T>
|
||||||
|
|
||||||
local entity_visualiser = require("@tools/entity_visualiser")
|
local entity_visualiser = require("@tools/entity_visualiser")
|
||||||
local lifetime_tracker_add = require("@tools/lifetime_tracker")
|
|
||||||
local dwi = entity_visualiser.stringify
|
local dwi = entity_visualiser.stringify
|
||||||
|
|
||||||
TEST("repro#", function()
|
TEST("repro", function()
|
||||||
do CASE "pair(OnDelete, Delete)"
|
|
||||||
local world = jecs.world()
|
|
||||||
local ct = world:component()
|
|
||||||
world:add(ct, jecs.pair(jecs.OnDelete, jecs.Delete))
|
|
||||||
|
|
||||||
local e1 = world:entity()
|
|
||||||
local e2 = world:entity()
|
|
||||||
|
|
||||||
local dummy = world:entity()
|
|
||||||
|
|
||||||
world:add(e1, ct)
|
|
||||||
world:add(e2, jecs.pair(ct, dummy))
|
|
||||||
|
|
||||||
world:delete(dummy)
|
|
||||||
|
|
||||||
CHECK(world:contains(e2))
|
|
||||||
|
|
||||||
world:delete(ct)
|
|
||||||
|
|
||||||
CHECK(not world:contains(e1))
|
|
||||||
end
|
|
||||||
|
|
||||||
do CASE "pair(OnDeleteTarget, Delete)"
|
|
||||||
print("start")
|
|
||||||
local world = jecs.world()
|
|
||||||
local ct = world:component()
|
|
||||||
world:add(ct, jecs.pair(jecs.OnDeleteTarget, jecs.Delete))
|
|
||||||
|
|
||||||
local e1 = world:entity()
|
|
||||||
local e2 = world:entity()
|
|
||||||
|
|
||||||
-- local dummy = world:entity()
|
|
||||||
|
|
||||||
print("flags")
|
|
||||||
world:add(e1, ct)
|
|
||||||
|
|
||||||
print(world.component_index[ct].flags)
|
|
||||||
-- world:add(e2, jecs.pair(ct, dummy))
|
|
||||||
|
|
||||||
-- world:delete(dummy)
|
|
||||||
|
|
||||||
-- CHECK(not world:contains(e2))
|
|
||||||
|
|
||||||
world:delete(ct)
|
|
||||||
|
|
||||||
CHECK(world:contains(e1))
|
|
||||||
end
|
|
||||||
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -433,8 +386,51 @@ TEST("world:contains()", function()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
TEST("world:delete()", function()
|
TEST("world:delete()", function()
|
||||||
|
do CASE "pair(OnDelete, Delete)"
|
||||||
|
local world = jecs.world()
|
||||||
|
local ct = world:component()
|
||||||
|
world:add(ct, jecs.pair(jecs.OnDelete, jecs.Delete))
|
||||||
|
|
||||||
|
local e1 = world:entity()
|
||||||
|
local e2 = world:entity()
|
||||||
|
|
||||||
|
local dummy = world:entity()
|
||||||
|
|
||||||
|
world:add(e1, ct)
|
||||||
|
world:add(e2, jecs.pair(ct, dummy))
|
||||||
|
|
||||||
|
world:delete(dummy)
|
||||||
|
|
||||||
|
CHECK(world:contains(e2))
|
||||||
|
|
||||||
|
world:delete(ct)
|
||||||
|
|
||||||
|
CHECK(not world:contains(e1))
|
||||||
|
end
|
||||||
|
|
||||||
|
do CASE "pair(OnDeleteTarget, Delete)"
|
||||||
|
local world = jecs.world()
|
||||||
|
local ct = world:component()
|
||||||
|
world:add(ct, jecs.pair(jecs.OnDeleteTarget, jecs.Delete))
|
||||||
|
|
||||||
|
local e1 = world:entity()
|
||||||
|
local e2 = world:entity()
|
||||||
|
|
||||||
|
local dummy = world:entity()
|
||||||
|
|
||||||
|
world:add(e1, ct)
|
||||||
|
|
||||||
|
world:add(e2, jecs.pair(ct, dummy))
|
||||||
|
|
||||||
|
world:delete(dummy)
|
||||||
|
|
||||||
|
CHECK(not world:contains(e2))
|
||||||
|
|
||||||
|
world:delete(ct)
|
||||||
|
|
||||||
|
CHECK(world:contains(e1))
|
||||||
|
end
|
||||||
do CASE "remove (*, R) pairs when relationship is invalidated"
|
do CASE "remove (*, R) pairs when relationship is invalidated"
|
||||||
print("-------")
|
|
||||||
local world = jecs.world()
|
local world = jecs.world()
|
||||||
local e1 = world:entity()
|
local e1 = world:entity()
|
||||||
local e2 = world:entity()
|
local e2 = world:entity()
|
||||||
|
|
Loading…
Reference in a new issue