mirror of
https://github.com/Ukendio/jecs.git
synced 2025-07-20 04:59:16 +00:00
Remove archetype recycling
This commit is contained in:
parent
210d62d463
commit
7b253e1c2a
2 changed files with 113 additions and 138 deletions
238
jecs.luau
238
jecs.luau
|
@ -19,8 +19,7 @@ export type Archetype = {
|
||||||
type: string,
|
type: string,
|
||||||
entities: { Entity },
|
entities: { Entity },
|
||||||
columns: { Column },
|
columns: { Column },
|
||||||
columns_map: { [Id]: Column },
|
columns_map: { [Id]: Column }
|
||||||
dead: boolean,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type QueryInner = {
|
export type QueryInner = {
|
||||||
|
@ -861,8 +860,7 @@ local function archetype_create(world: World, id_types: { Id }, ty, prev: i53?):
|
||||||
entities = {},
|
entities = {},
|
||||||
id = archetype_id,
|
id = archetype_id,
|
||||||
type = ty,
|
type = ty,
|
||||||
types = id_types,
|
types = id_types
|
||||||
dead = false,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
archetype_register(world, archetype, false)
|
archetype_register(world, archetype, false)
|
||||||
|
@ -901,10 +899,6 @@ local function archetype_ensure(world: World, id_types: { Id }): Archetype
|
||||||
local ty = hash(id_types)
|
local ty = hash(id_types)
|
||||||
local archetype = world.archetype_index[ty]
|
local archetype = world.archetype_index[ty]
|
||||||
if archetype then
|
if archetype then
|
||||||
if archetype.dead then
|
|
||||||
archetype_register(world, archetype)
|
|
||||||
archetype.dead = false :: any
|
|
||||||
end
|
|
||||||
return archetype
|
return archetype
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1076,14 +1070,16 @@ local function archetype_destroy(world: World, archetype: Archetype)
|
||||||
local component_index = world.component_index
|
local component_index = world.component_index
|
||||||
local archetype_edges = world.archetype_edges
|
local archetype_edges = world.archetype_edges
|
||||||
local edges = archetype_edges[archetype.id]
|
local edges = archetype_edges[archetype.id]
|
||||||
|
print("delete archetype id", archetype.id, archetype.type)
|
||||||
for id, node in edges do
|
for id, node in edges do
|
||||||
|
print("node id", node.id)
|
||||||
archetype_edges[node.id][id] = nil
|
archetype_edges[node.id][id] = nil
|
||||||
edges[id] = nil
|
edges[id] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local archetype_id = archetype.id
|
local archetype_id = archetype.id
|
||||||
-- world.archetypes[archetype_id] = nil :: any
|
world.archetypes[archetype_id] = nil :: any
|
||||||
-- world.archetype_index[archetype.type] = nil :: any
|
world.archetype_index[archetype.type] = nil :: any
|
||||||
local columns_map = archetype.columns_map
|
local columns_map = archetype.columns_map
|
||||||
|
|
||||||
for id in columns_map do
|
for id in columns_map do
|
||||||
|
@ -1104,8 +1100,6 @@ local function archetype_destroy(world: World, archetype: Archetype)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
archetype.dead = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function NOOP() end
|
local function NOOP() end
|
||||||
|
@ -2307,23 +2301,31 @@ local function world_new()
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
||||||
local function inner_world_add<T, a>(
|
local function inner_world_set<T, a>(world: World, entity: Entity<T>, id: Id<a>, data: a): ()
|
||||||
world: World,
|
|
||||||
entity: Entity<T>,
|
|
||||||
id: Id<a>
|
|
||||||
): ()
|
|
||||||
local entity_index = world.entity_index
|
|
||||||
local record = inner_entity_index_try_get_unsafe(entity :: number)
|
local record = inner_entity_index_try_get_unsafe(entity :: number)
|
||||||
if not record then
|
if not record then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local from = record.archetype
|
local from: Archetype = record.archetype
|
||||||
if ECS_IS_PAIR(id::number) then
|
|
||||||
local src = from or ROOT_ARCHETYPE
|
local src = from or ROOT_ARCHETYPE
|
||||||
local edge = archetype_edges[src.id]
|
local column = src.columns_map[id]
|
||||||
local to = edge[id]
|
if column then
|
||||||
|
local idr = component_index[id]
|
||||||
|
column[record.row] = data
|
||||||
|
|
||||||
|
-- If the archetypes are the same it can avoid moving the entity
|
||||||
|
-- and just set the data directly.
|
||||||
|
local on_change = idr.on_change
|
||||||
|
if on_change then
|
||||||
|
on_change(entity, id, data)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local to: Archetype
|
||||||
local idr: ComponentRecord
|
local idr: ComponentRecord
|
||||||
|
if ECS_IS_PAIR(id::number) then
|
||||||
|
local edge = archetype_edges[src.id]
|
||||||
|
to = edge[id]
|
||||||
if not to then
|
if not to then
|
||||||
local first = ECS_PAIR_FIRST(id::number)
|
local first = ECS_PAIR_FIRST(id::number)
|
||||||
local wc = ECS_PAIR(first, EcsWildcard)
|
local wc = ECS_PAIR(first, EcsWildcard)
|
||||||
|
@ -2351,38 +2353,105 @@ local function world_new()
|
||||||
idr = component_index[id]
|
idr = component_index[id]
|
||||||
end
|
end
|
||||||
edge[id] = to
|
edge[id] = to
|
||||||
else
|
|
||||||
if to.dead then
|
|
||||||
archetype_register(world, to, true)
|
|
||||||
edge[id] = to
|
|
||||||
archetype_edges[to.id][id] = src
|
archetype_edges[to.id][id] = src
|
||||||
to.dead = false
|
else
|
||||||
|
idr = component_index[id]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local edges = archetype_edges
|
||||||
|
local edge = edges[src.id]
|
||||||
|
|
||||||
|
to = edge[id] :: Archetype
|
||||||
|
if not to then
|
||||||
|
to = find_archetype_with(world, id, src)
|
||||||
|
edge[id] = to
|
||||||
|
edges[to.id][id] = src
|
||||||
end
|
end
|
||||||
idr = component_index[id]
|
idr = component_index[id]
|
||||||
end
|
end
|
||||||
if from == to then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if from then
|
if from then
|
||||||
|
-- If there was a previous archetype, then the entity needs to move the archetype
|
||||||
inner_entity_move(entity_index, entity, record, to)
|
inner_entity_move(entity_index, entity, record, to)
|
||||||
else
|
else
|
||||||
if #to.types > 0 then
|
|
||||||
new_entity(entity, record, to)
|
new_entity(entity, record, to)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
column = to.columns_map[id]
|
||||||
|
column[record.row] = data
|
||||||
|
|
||||||
local on_add = idr.on_add
|
local on_add = idr.on_add
|
||||||
|
|
||||||
if on_add then
|
if on_add then
|
||||||
on_add(entity, id)
|
on_add(entity, id, data)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function inner_world_add<T, a>(
|
||||||
|
world: World,
|
||||||
|
entity: Entity<T>,
|
||||||
|
id: Id<a>
|
||||||
|
): ()
|
||||||
|
local entity_index = world.entity_index
|
||||||
|
local record = inner_entity_index_try_get_unsafe(entity :: number)
|
||||||
|
if not record then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local to = archetype_traverse_add(world, id, from)
|
|
||||||
if from == to then
|
local from = record.archetype
|
||||||
|
local src = from or ROOT_ARCHETYPE
|
||||||
|
if src.columns_map[id] then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
local to: Archetype
|
||||||
|
local idr: ComponentRecord
|
||||||
|
if ECS_IS_PAIR(id::number) then
|
||||||
|
local edge = archetype_edges[src.id]
|
||||||
|
to = edge[id]
|
||||||
|
if not to then
|
||||||
|
local first = ECS_PAIR_FIRST(id::number)
|
||||||
|
local wc = ECS_PAIR(first, EcsWildcard)
|
||||||
|
idr = component_index[wc]
|
||||||
|
if idr and bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then
|
||||||
|
local cr = idr.records[src.id]
|
||||||
|
if cr then
|
||||||
|
local on_remove = idr.on_remove
|
||||||
|
local id_types = src.types
|
||||||
|
if on_remove then
|
||||||
|
on_remove(entity, id_types[cr])
|
||||||
|
src = record.archetype
|
||||||
|
id_types = src.types
|
||||||
|
cr = idr.records[src.id]
|
||||||
|
end
|
||||||
|
local dst = table.clone(id_types)
|
||||||
|
dst[cr] = id
|
||||||
|
to = archetype_ensure(world, dst)
|
||||||
|
else
|
||||||
|
to = find_archetype_with(world, id, src)
|
||||||
|
idr = component_index[id]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
to = find_archetype_with(world, id, src)
|
||||||
|
idr = component_index[id]
|
||||||
|
end
|
||||||
|
edge[id] = to
|
||||||
|
archetype_edges[to.id][id] = src
|
||||||
|
else
|
||||||
|
idr = component_index[id]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local edges = archetype_edges
|
||||||
|
local edge = edges[src.id]
|
||||||
|
|
||||||
|
to = edge[id] :: Archetype
|
||||||
|
if not to then
|
||||||
|
to = find_archetype_with(world, id, src)
|
||||||
|
edge[id] = to
|
||||||
|
edges[to.id][id] = src
|
||||||
|
end
|
||||||
|
idr = component_index[id]
|
||||||
|
end
|
||||||
|
|
||||||
if from then
|
if from then
|
||||||
inner_entity_move(entity_index, entity, record, to)
|
inner_entity_move(entity_index, entity, record, to)
|
||||||
else
|
else
|
||||||
|
@ -2391,7 +2460,6 @@ local function world_new()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local idr = component_index[id]
|
|
||||||
local on_add = idr.on_add
|
local on_add = idr.on_add
|
||||||
|
|
||||||
if on_add then
|
if on_add then
|
||||||
|
@ -2495,102 +2563,6 @@ local function world_new()
|
||||||
return inner_world_target(world, entity, EcsChildOf, 0)
|
return inner_world_target(world, entity, EcsChildOf, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function inner_archetype_traverse_add(id: Id, from: Archetype): Archetype
|
|
||||||
from = from or ROOT_ARCHETYPE
|
|
||||||
if from.columns_map[id] then
|
|
||||||
return from
|
|
||||||
end
|
|
||||||
local edges = archetype_edges
|
|
||||||
local edge = edges[from.id]
|
|
||||||
|
|
||||||
local to = edge[id] :: Archetype
|
|
||||||
if not to then
|
|
||||||
to = find_archetype_with(world, id, from)
|
|
||||||
edge[id] = to
|
|
||||||
edges[to.id][id] = from
|
|
||||||
end
|
|
||||||
|
|
||||||
return to
|
|
||||||
end
|
|
||||||
|
|
||||||
local function inner_world_set<T, a>(world: World, entity: Entity<T>, id: Id<a>, data: a): ()
|
|
||||||
local record = inner_entity_index_try_get_unsafe(entity :: number)
|
|
||||||
if not record then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local from: Archetype = record.archetype
|
|
||||||
local src = from or ROOT_ARCHETYPE
|
|
||||||
local column = src.columns_map[id]
|
|
||||||
if column then
|
|
||||||
local idr = component_index[id]
|
|
||||||
column[record.row] = data
|
|
||||||
|
|
||||||
-- If the archetypes are the same it can avoid moving the entity
|
|
||||||
-- and just set the data directly.
|
|
||||||
local on_change = idr.on_change
|
|
||||||
if on_change then
|
|
||||||
on_change(entity, id, data)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local to: Archetype
|
|
||||||
local idr: ComponentRecord
|
|
||||||
if ECS_IS_PAIR(id::number) then
|
|
||||||
local edge = archetype_edges[src.id]
|
|
||||||
to = edge[id]
|
|
||||||
if not to then
|
|
||||||
local first = ECS_PAIR_FIRST(id::number)
|
|
||||||
local wc = ECS_PAIR(first, EcsWildcard)
|
|
||||||
idr = component_index[wc]
|
|
||||||
if idr and bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then
|
|
||||||
local cr = idr.records[src.id]
|
|
||||||
if cr then
|
|
||||||
local on_remove = idr.on_remove
|
|
||||||
local id_types = src.types
|
|
||||||
if on_remove then
|
|
||||||
on_remove(entity, id_types[cr])
|
|
||||||
src = record.archetype
|
|
||||||
id_types = src.types
|
|
||||||
cr = idr.records[src.id]
|
|
||||||
end
|
|
||||||
local dst = table.clone(id_types)
|
|
||||||
dst[cr] = id
|
|
||||||
to = archetype_ensure(world, dst)
|
|
||||||
else
|
|
||||||
to = find_archetype_with(world, id, src)
|
|
||||||
idr = component_index[id]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
to = find_archetype_with(world, id, src)
|
|
||||||
idr = component_index[id]
|
|
||||||
end
|
|
||||||
edge[id] = to
|
|
||||||
archetype_edges[to.id][id] = src
|
|
||||||
else
|
|
||||||
idr = component_index[id]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
to = inner_archetype_traverse_add(id, from)
|
|
||||||
idr = component_index[id]
|
|
||||||
end
|
|
||||||
|
|
||||||
if from then
|
|
||||||
-- If there was a previous archetype, then the entity needs to move the archetype
|
|
||||||
inner_entity_move(entity_index, entity, record, to)
|
|
||||||
else
|
|
||||||
new_entity(entity, record, to)
|
|
||||||
end
|
|
||||||
|
|
||||||
column = to.columns_map[id]
|
|
||||||
column[record.row] = data
|
|
||||||
|
|
||||||
local on_add = idr.on_add
|
|
||||||
if on_add then
|
|
||||||
on_add(entity, id, data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function inner_world_entity<T>(world: World, entity: Entity<T>?): Entity<T>
|
local function inner_world_entity<T>(world: World, entity: Entity<T>?): Entity<T>
|
||||||
if entity then
|
if entity then
|
||||||
local index = ECS_ID(entity :: number)
|
local index = ECS_ID(entity :: number)
|
||||||
|
|
|
@ -129,6 +129,7 @@ TEST("repeated pairs", function()
|
||||||
CHECK(count == 1)
|
CHECK(count == 1)
|
||||||
CHECK(world:each(p2)() == e2) -- Fails
|
CHECK(world:each(p2)() == e2) -- Fails
|
||||||
end)
|
end)
|
||||||
|
|
||||||
TEST("repro", function()
|
TEST("repro", function()
|
||||||
local world = jecs.world()
|
local world = jecs.world()
|
||||||
local data = world:component()
|
local data = world:component()
|
||||||
|
@ -157,6 +158,7 @@ TEST("repro", function()
|
||||||
end
|
end
|
||||||
CHECK(count == 1)
|
CHECK(count == 1)
|
||||||
count = 0
|
count = 0
|
||||||
|
print("----")
|
||||||
world:add(e2v1, jecs.pair(relation, e1v1))
|
world:add(e2v1, jecs.pair(relation, e1v1))
|
||||||
CHECK(world:has(e2v1, jecs.pair(relation, e1v1)))
|
CHECK(world:has(e2v1, jecs.pair(relation, e1v1)))
|
||||||
|
|
||||||
|
@ -164,6 +166,7 @@ TEST("repro", function()
|
||||||
count += 1
|
count += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
print(count)
|
||||||
CHECK(count==1)
|
CHECK(count==1)
|
||||||
end)
|
end)
|
||||||
TEST("bulk", function()
|
TEST("bulk", function()
|
||||||
|
|
Loading…
Reference in a new issue