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
110
src/init.luau
110
src/init.luau
|
@ -26,8 +26,7 @@ type GraphEdges = Map<i53, GraphEdge>
|
||||||
type GraphNode = {
|
type GraphNode = {
|
||||||
add: GraphEdges,
|
add: GraphEdges,
|
||||||
remove: GraphEdges,
|
remove: GraphEdges,
|
||||||
add_ref: GraphEdge?,
|
refs: GraphEdge
|
||||||
remove_ref: GraphEdge?,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Archetype = {
|
export type Archetype = {
|
||||||
|
@ -521,7 +520,7 @@ local function archetype_create(world: World, types: { i24 }, ty, prev: i53?): A
|
||||||
|
|
||||||
local archetype: Archetype = {
|
local archetype: Archetype = {
|
||||||
columns = columns,
|
columns = columns,
|
||||||
node = { add = {}, remove = {} },
|
node = { add = {}, remove = {}, refs = {} },
|
||||||
entities = {},
|
entities = {},
|
||||||
id = archetype_id,
|
id = archetype_id,
|
||||||
records = records,
|
records = records,
|
||||||
|
@ -624,17 +623,20 @@ local function archetype_ensure_edge(world, edges, id): GraphEdge
|
||||||
return edge
|
return edge
|
||||||
end
|
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_init_edge(archetype, edge, id, to)
|
||||||
archetype_ensure_edge(world, archetype.node.add, id)
|
archetype_ensure_edge(world, archetype.node.add, id)
|
||||||
if archetype ~= to then
|
if archetype ~= to then
|
||||||
local to_add_ref = to.node.add_ref
|
local to_refs = to.node.refs
|
||||||
edge.next = to_add_ref
|
local next_edge = to_refs.next
|
||||||
edge.prev = nil
|
|
||||||
if to_add_ref then
|
to_refs.next = edge
|
||||||
to_add_ref.prev = edge
|
edge.prev = to_refs
|
||||||
end
|
edge.next = next_edge
|
||||||
to.node.add_ref = edge
|
|
||||||
|
if next_edge then
|
||||||
|
next_edge.prev = edge
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -642,21 +644,16 @@ local function init_edge_for_remove(world, archetype, edge, id, to)
|
||||||
archetype_init_edge(archetype, edge, id, to)
|
archetype_init_edge(archetype, edge, id, to)
|
||||||
archetype_ensure_edge(world, archetype.node.remove, id)
|
archetype_ensure_edge(world, archetype.node.remove, id)
|
||||||
if archetype ~= to then
|
if archetype ~= to then
|
||||||
local to_remove_ref = to.node.remove_ref
|
local to_refs = to.node.refs
|
||||||
local prev
|
local prev_edge = to_refs.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
|
|
||||||
|
|
||||||
edge.prev = prev
|
to_refs.prev = edge
|
||||||
if prev then
|
edge.next = to_refs
|
||||||
prev.next = edge
|
edge.prev = prev_edge
|
||||||
end
|
|
||||||
|
if prev_edge then
|
||||||
|
prev_edge.next = edge
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -871,52 +868,47 @@ local function archetype_clear_edges(archetype: Archetype)
|
||||||
local node = archetype.node
|
local node = archetype.node
|
||||||
local add = node.add
|
local add = node.add
|
||||||
local remove = node.remove
|
local remove = node.remove
|
||||||
for _, edge in add do
|
local node_refs = node.refs
|
||||||
|
for id, edge in add do
|
||||||
archetype_disconnect_edge(edge)
|
archetype_disconnect_edge(edge)
|
||||||
|
add[id] = nil
|
||||||
end
|
end
|
||||||
for _, edge in remove do
|
for id, edge in remove do
|
||||||
archetype_disconnect_edge(edge)
|
archetype_disconnect_edge(edge)
|
||||||
end
|
remove[id] = nil
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local node_remove_ref = node.remove_ref
|
local cur = node_refs.next
|
||||||
if node_remove_ref then
|
while cur do
|
||||||
local current = node_remove_ref.prev
|
local edge = cur
|
||||||
while current do
|
local next_edge = edge.next
|
||||||
local edge = current
|
archetype_remove_edge(edge.from.node.add, edge.id, edge)
|
||||||
current = current.prev
|
cur = next_edge
|
||||||
local node_remove = edge.from.node.remove
|
end
|
||||||
if node_remove then
|
|
||||||
archetype_remove_edge(node_remove, edge.id, edge)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
node.add = nil :: any
|
cur = node_refs.prev
|
||||||
node.remove = nil :: any
|
while cur do
|
||||||
node.add_ref = nil :: any
|
local edge = cur
|
||||||
node.remove_ref = nil :: any
|
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
|
end
|
||||||
|
|
||||||
local function archetype_destroy(world: World, archetype: Archetype)
|
local function archetype_destroy(world: World, archetype: Archetype)
|
||||||
|
|
||||||
|
if archetype == world.ROOT_ARCHETYPE then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local component_index = world.componentIndex
|
local component_index = world.componentIndex
|
||||||
archetype_clear_edges(archetype)
|
archetype_clear_edges(archetype)
|
||||||
local archetype_id = archetype.id
|
local archetype_id = archetype.id
|
||||||
if archetype ~= world.ROOT_ARCHETYPE then
|
world.archetypes[archetype_id] = nil
|
||||||
world.archetypes[archetype_id] = nil
|
world.archetypeIndex[archetype.type] = nil
|
||||||
world.archetypeIndex[archetype.type] = nil
|
|
||||||
end
|
|
||||||
local records = archetype.records
|
local records = archetype.records
|
||||||
|
|
||||||
for id in records do
|
for id in records do
|
||||||
|
|
|
@ -71,6 +71,58 @@ local function name(world, e)
|
||||||
return world:get(e, jecs.Name)
|
return world:get(e, jecs.Name)
|
||||||
end
|
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()
|
TEST("world:entity()", function()
|
||||||
do CASE "unique IDs"
|
do CASE "unique IDs"
|
||||||
local world = jecs.World.new()
|
local world = jecs.World.new()
|
||||||
|
|
Loading…
Reference in a new issue