mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Traverse refs for deletion
This commit is contained in:
parent
8aace714fc
commit
ca3cc06400
2 changed files with 103 additions and 59 deletions
100
src/init.luau
100
src/init.luau
|
@ -26,8 +26,7 @@ type GraphEdges = Map<i53, GraphEdge>
|
|||
type GraphNode = {
|
||||
add: GraphEdges,
|
||||
remove: GraphEdges,
|
||||
add_ref: GraphEdge?,
|
||||
remove_ref: GraphEdge?,
|
||||
refs: GraphEdge
|
||||
}
|
||||
|
||||
export type Archetype = {
|
||||
|
@ -521,7 +520,7 @@ local function archetype_create(world: World, types: { i24 }, ty, prev: i53?): A
|
|||
|
||||
local archetype: Archetype = {
|
||||
columns = columns,
|
||||
node = { add = {}, remove = {} },
|
||||
node = { add = {}, remove = {}, refs = {} },
|
||||
entities = {},
|
||||
id = archetype_id,
|
||||
records = records,
|
||||
|
@ -624,17 +623,20 @@ local function archetype_ensure_edge(world, edges, id): GraphEdge
|
|||
return edge
|
||||
end
|
||||
|
||||
local function init_edge_for_add(world, archetype, edge, id, to)
|
||||
local function init_edge_for_add(world, archetype, edge: GraphEdge, id, to)
|
||||
archetype_init_edge(archetype, edge, id, to)
|
||||
archetype_ensure_edge(world, archetype.node.add, id)
|
||||
if archetype ~= to then
|
||||
local to_add_ref = to.node.add_ref
|
||||
edge.next = to_add_ref
|
||||
edge.prev = nil
|
||||
if to_add_ref then
|
||||
to_add_ref.prev = edge
|
||||
local to_refs = to.node.refs
|
||||
local next_edge = to_refs.next
|
||||
|
||||
to_refs.next = edge
|
||||
edge.prev = to_refs
|
||||
edge.next = next_edge
|
||||
|
||||
if next_edge then
|
||||
next_edge.prev = edge
|
||||
end
|
||||
to.node.add_ref = edge
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -642,20 +644,15 @@ local function init_edge_for_remove(world, archetype, edge, id, to)
|
|||
archetype_init_edge(archetype, edge, id, to)
|
||||
archetype_ensure_edge(world, archetype.node.remove, id)
|
||||
if archetype ~= to then
|
||||
local to_remove_ref = to.node.remove_ref
|
||||
local prev
|
||||
if to_remove_ref then
|
||||
prev = to_remove_ref.prev
|
||||
to_remove_ref.prev = edge
|
||||
edge.next = to_remove_ref
|
||||
else
|
||||
to.node.remove_ref = edge
|
||||
edge.next = nil
|
||||
end
|
||||
local to_refs = to.node.refs
|
||||
local prev_edge = to_refs.prev
|
||||
|
||||
edge.prev = prev
|
||||
if prev then
|
||||
prev.next = edge
|
||||
to_refs.prev = edge
|
||||
edge.next = to_refs
|
||||
edge.prev = prev_edge
|
||||
|
||||
if prev_edge then
|
||||
prev_edge.next = edge
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -871,52 +868,47 @@ local function archetype_clear_edges(archetype: Archetype)
|
|||
local node = archetype.node
|
||||
local add = node.add
|
||||
local remove = node.remove
|
||||
for _, edge in add do
|
||||
local node_refs = node.refs
|
||||
for id, edge in add do
|
||||
archetype_disconnect_edge(edge)
|
||||
add[id] = nil
|
||||
end
|
||||
for _, edge in remove do
|
||||
for id, edge in remove do
|
||||
archetype_disconnect_edge(edge)
|
||||
end
|
||||
local node_add_ref = node.add_ref
|
||||
if node_add_ref then
|
||||
local current = node_add_ref.next
|
||||
while current do
|
||||
local edge = current
|
||||
current = current.next
|
||||
local node_add = edge.from.node.add
|
||||
if node_add then
|
||||
archetype_remove_edge(node_add, edge.id, edge)
|
||||
end
|
||||
end
|
||||
remove[id] = nil
|
||||
end
|
||||
|
||||
local node_remove_ref = node.remove_ref
|
||||
if node_remove_ref then
|
||||
local current = node_remove_ref.prev
|
||||
while current do
|
||||
local edge = current
|
||||
current = current.prev
|
||||
local node_remove = edge.from.node.remove
|
||||
if node_remove then
|
||||
archetype_remove_edge(node_remove, edge.id, edge)
|
||||
end
|
||||
end
|
||||
local cur = node_refs.next
|
||||
while cur do
|
||||
local edge = cur
|
||||
local next_edge = edge.next
|
||||
archetype_remove_edge(edge.from.node.add, edge.id, edge)
|
||||
cur = next_edge
|
||||
end
|
||||
|
||||
node.add = nil :: any
|
||||
node.remove = nil :: any
|
||||
node.add_ref = nil :: any
|
||||
node.remove_ref = nil :: any
|
||||
cur = node_refs.prev
|
||||
while cur do
|
||||
local edge = cur
|
||||
local next_edge = edge.prev
|
||||
archetype_remove_edge(edge.from.node.remove, edge.id, edge)
|
||||
cur = next_edge
|
||||
end
|
||||
|
||||
node_refs.next = nil
|
||||
node_refs.prev = nil
|
||||
end
|
||||
|
||||
local function archetype_destroy(world: World, archetype: Archetype)
|
||||
|
||||
if archetype == world.ROOT_ARCHETYPE then
|
||||
return
|
||||
end
|
||||
|
||||
local component_index = world.componentIndex
|
||||
archetype_clear_edges(archetype)
|
||||
local archetype_id = archetype.id
|
||||
if archetype ~= world.ROOT_ARCHETYPE then
|
||||
world.archetypes[archetype_id] = nil
|
||||
world.archetypeIndex[archetype.type] = nil
|
||||
end
|
||||
local records = archetype.records
|
||||
|
||||
for id in records do
|
||||
|
|
|
@ -71,6 +71,58 @@ local function name(world, e)
|
|||
return world:get(e, jecs.Name)
|
||||
end
|
||||
|
||||
TEST("world:cleanup()", function()
|
||||
local world = world_new()
|
||||
local A = world:component()
|
||||
local B = world:component()
|
||||
local C = world:component()
|
||||
|
||||
local e1 = world:entity()
|
||||
local e2 = world:entity()
|
||||
local e3 = world:entity()
|
||||
|
||||
world:set(e1, A, true)
|
||||
|
||||
world:set(e2, A, true)
|
||||
world:set(e2, B, true)
|
||||
|
||||
world:set(e3, A, true)
|
||||
world:set(e3, B, true)
|
||||
world:set(e3, C, true)
|
||||
|
||||
local archetypeIndex = world.archetypeIndex
|
||||
|
||||
CHECK(#archetypeIndex["1"].entities == 1)
|
||||
CHECK(#archetypeIndex["1_2"].entities == 1)
|
||||
CHECK(#archetypeIndex["1_2_3"].entities == 1)
|
||||
|
||||
world:delete(e1)
|
||||
world:delete(e2)
|
||||
world:delete(e3)
|
||||
|
||||
world:cleanup()
|
||||
|
||||
archetypeIndex = world.archetypeIndex
|
||||
|
||||
CHECK(archetypeIndex["1"] == nil)
|
||||
CHECK(archetypeIndex["1_2"] == nil)
|
||||
CHECK(archetypeIndex["1_2_3"] == nil)
|
||||
|
||||
local e4 = world:entity()
|
||||
world:set(e4, A, true)
|
||||
CHECK(#archetypeIndex["1"].entities == 1)
|
||||
CHECK(archetypeIndex["1_2"] == nil)
|
||||
CHECK(archetypeIndex["1_2_3"] == nil)
|
||||
world:set(e4, B, true)
|
||||
CHECK(#archetypeIndex["1"].entities == 0)
|
||||
CHECK(#archetypeIndex["1_2"].entities == 1)
|
||||
CHECK(archetypeIndex["1_2_3"] == nil)
|
||||
world:set(e4, C, true)
|
||||
CHECK(#archetypeIndex["1"].entities == 0)
|
||||
CHECK(#archetypeIndex["1_2"].entities == 0)
|
||||
CHECK(#archetypeIndex["1_2_3"].entities == 1)
|
||||
end)
|
||||
|
||||
TEST("world:entity()", function()
|
||||
do CASE "unique IDs"
|
||||
local world = jecs.World.new()
|
||||
|
|
Loading…
Reference in a new issue