mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Reuse archetype_delete on world:clear (#141)
* Reuse archetype_delete on world:clear * Add tests
This commit is contained in:
parent
11f9615495
commit
c5e20aaf50
2 changed files with 97 additions and 50 deletions
105
src/init.luau
105
src/init.luau
|
@ -808,23 +808,6 @@ local function world_remove(world: World, entity: i53, id: i53)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function world_clear(world: World, entity: i53)
|
|
||||||
--TODO: use sparse_get (stashed)
|
|
||||||
local record = world.entityIndex.sparse[entity]
|
|
||||||
if not record then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local ROOT_ARCHETYPE = world.ROOT_ARCHETYPE
|
|
||||||
local archetype = record.archetype
|
|
||||||
|
|
||||||
if archetype == nil or archetype == ROOT_ARCHETYPE then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
entity_move(world.entityIndex, entity, record, ROOT_ARCHETYPE)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function archetype_fast_delete_last(columns: { Column }, column_count: number, types: { i53 }, entity: i53)
|
local function archetype_fast_delete_last(columns: { Column }, column_count: number, types: { i53 }, entity: i53)
|
||||||
for i, column in columns do
|
for i, column in columns do
|
||||||
if column ~= NULL_ARRAY then
|
if column ~= NULL_ARRAY then
|
||||||
|
@ -842,6 +825,59 @@ local function archetype_fast_delete(columns: { Column }, column_count: number,
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function archetype_delete(world: World, archetype: Archetype, row: number, destruct: boolean?)
|
||||||
|
local entityIndex = world.entityIndex
|
||||||
|
local columns = archetype.columns
|
||||||
|
local types = archetype.types
|
||||||
|
local entities = archetype.entities
|
||||||
|
local column_count = #entities
|
||||||
|
local last = #entities
|
||||||
|
local move = entities[last]
|
||||||
|
local delete = entities[row]
|
||||||
|
entities[row] = move
|
||||||
|
entities[last] = nil
|
||||||
|
|
||||||
|
if row ~= last then
|
||||||
|
-- TODO: should be "entity_index_sparse_get(entityIndex, move)"
|
||||||
|
local record_to_move = entityIndex.sparse[move]
|
||||||
|
if record_to_move then
|
||||||
|
record_to_move.row = row
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: if last == 0 then deactivate table
|
||||||
|
|
||||||
|
for _, id in types do
|
||||||
|
invoke_hook(world, EcsOnRemove, id, delete)
|
||||||
|
end
|
||||||
|
|
||||||
|
if row == last then
|
||||||
|
archetype_fast_delete_last(columns, column_count, types, delete)
|
||||||
|
else
|
||||||
|
archetype_fast_delete(columns, column_count, row, types, delete)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function world_clear(world: World, entity: i53)
|
||||||
|
--TODO: use sparse_get (stashed)
|
||||||
|
local record = world.entityIndex.sparse[entity]
|
||||||
|
if not record then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local archetype = record.archetype
|
||||||
|
local row = record.row
|
||||||
|
|
||||||
|
if archetype then
|
||||||
|
-- In the future should have a destruct mode for
|
||||||
|
-- deleting archetypes themselves. Maybe requires recycling
|
||||||
|
archetype_delete(world, archetype, row)
|
||||||
|
end
|
||||||
|
|
||||||
|
record.archetype = nil
|
||||||
|
record.row = nil
|
||||||
|
end
|
||||||
|
|
||||||
local function archetype_disconnect_edge(edge: GraphEdge)
|
local function archetype_disconnect_edge(edge: GraphEdge)
|
||||||
local edge_next = edge.next
|
local edge_next = edge.next
|
||||||
local edge_prev = edge.prev
|
local edge_prev = edge.prev
|
||||||
|
@ -936,41 +972,10 @@ local function world_cleanup(world)
|
||||||
world.archetypeIndex = new_archetype_map
|
world.archetypeIndex = new_archetype_map
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local world_delete: (world: World, entity: i53, destruct: boolean?) -> ()
|
local world_delete: (world: World, entity: i53, destruct: boolean?) -> ()
|
||||||
do
|
do
|
||||||
local function archetype_delete(world: World, archetype: Archetype, row: number, destruct: boolean?)
|
|
||||||
local entityIndex = world.entityIndex
|
|
||||||
local columns = archetype.columns
|
|
||||||
local types = archetype.types
|
|
||||||
local entities = archetype.entities
|
|
||||||
local column_count = #entities
|
|
||||||
local last = #entities
|
|
||||||
local move = entities[last]
|
|
||||||
local delete = entities[row]
|
|
||||||
entities[row] = move
|
|
||||||
entities[last] = nil
|
|
||||||
|
|
||||||
if row ~= last then
|
|
||||||
-- TODO: should be "entity_index_sparse_get(entityIndex, move)"
|
|
||||||
local record_to_move = entityIndex.sparse[move]
|
|
||||||
if record_to_move then
|
|
||||||
record_to_move.row = row
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- TODO: if last == 0 then deactivate table
|
|
||||||
|
|
||||||
for _, id in types do
|
|
||||||
invoke_hook(world, EcsOnRemove, id, delete)
|
|
||||||
end
|
|
||||||
|
|
||||||
if row == last then
|
|
||||||
archetype_fast_delete_last(columns, column_count, types, delete)
|
|
||||||
else
|
|
||||||
archetype_fast_delete(columns, column_count, row, types, delete)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function world_delete(world: World, entity: i53, destruct: boolean?)
|
function world_delete(world: World, entity: i53, destruct: boolean?)
|
||||||
local entityIndex = world.entityIndex
|
local entityIndex = world.entityIndex
|
||||||
local sparse_array = entityIndex.sparse
|
local sparse_array = entityIndex.sparse
|
||||||
|
|
|
@ -827,6 +827,48 @@ TEST("world:clear()", function()
|
||||||
CHECK(world:get(e, A) == nil)
|
CHECK(world:get(e, A) == nil)
|
||||||
CHECK(world:get(e, B) == nil)
|
CHECK(world:get(e, B) == nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
do CASE "should move last record"
|
||||||
|
local world = world_new()
|
||||||
|
local A = world:component()
|
||||||
|
|
||||||
|
local e = world:entity()
|
||||||
|
local e1 = world:entity()
|
||||||
|
|
||||||
|
world:add(e, A)
|
||||||
|
world:add(e1, A)
|
||||||
|
|
||||||
|
local archetype = world.archetypeIndex["1"]
|
||||||
|
local archetype_entities = archetype.entities
|
||||||
|
|
||||||
|
local _e = e :: number
|
||||||
|
local _e1 = e1 :: number
|
||||||
|
|
||||||
|
CHECK(archetype_entities[1] == _e)
|
||||||
|
CHECK(archetype_entities[2] == _e1)
|
||||||
|
|
||||||
|
local sparse_array = world.entityIndex.sparse
|
||||||
|
local e_record = sparse_array[e]
|
||||||
|
local e1_record = sparse_array[e1]
|
||||||
|
CHECK(e_record.archetype == archetype)
|
||||||
|
CHECK(e1_record.archetype == archetype)
|
||||||
|
CHECK(e1_record.row == 2)
|
||||||
|
|
||||||
|
world:clear(e)
|
||||||
|
|
||||||
|
CHECK(e_record.archetype == nil)
|
||||||
|
CHECK(e_record.row == nil)
|
||||||
|
CHECK(e1_record.archetype == archetype)
|
||||||
|
CHECK(e1_record.row == 1)
|
||||||
|
|
||||||
|
CHECK(archetype_entities[1] == _e1)
|
||||||
|
CHECK(archetype_entities[2] == nil)
|
||||||
|
|
||||||
|
CHECK(world:contains(e) == true)
|
||||||
|
CHECK(world:has(e, A) == false)
|
||||||
|
CHECK(world:contains(e1) == true)
|
||||||
|
CHECK(world:has(e1, A) == true)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
TEST("world:has()", function()
|
TEST("world:has()", function()
|
||||||
|
|
Loading…
Reference in a new issue