Add tests for archetypes (#139)

* Add stylua

* Align HI_COMPONENT_ID
This commit is contained in:
Marcus 2024-10-06 03:36:36 +02:00 committed by GitHub
parent 1e633d4563
commit c80bb0e2fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 123 additions and 79 deletions

View file

@ -26,7 +26,7 @@ type GraphEdges = Map<i53, GraphEdge>
type GraphNode = { type GraphNode = {
add: GraphEdges, add: GraphEdges,
remove: GraphEdges, remove: GraphEdges,
refs: GraphEdge refs: GraphEdge,
} }
export type Archetype = { export type Archetype = {
@ -69,34 +69,34 @@ type ArchetypeDiff = {
removed: Ty, removed: Ty,
} }
local HI_COMPONENT_ID = _G.__JECS_HI_COMPONENT_ID or 256 local HI_COMPONENT_ID = _G.__JECS_HI_COMPONENT_ID or 256
local EcsOnAdd = HI_COMPONENT_ID + 1 local EcsOnAdd = HI_COMPONENT_ID + 1
local EcsOnRemove = HI_COMPONENT_ID + 2 local EcsOnRemove = HI_COMPONENT_ID + 2
local EcsOnSet = HI_COMPONENT_ID + 3 local EcsOnSet = HI_COMPONENT_ID + 3
local EcsWildcard = HI_COMPONENT_ID + 4 local EcsWildcard = HI_COMPONENT_ID + 4
local EcsChildOf = HI_COMPONENT_ID + 5 local EcsChildOf = HI_COMPONENT_ID + 5
local EcsComponent = HI_COMPONENT_ID + 6 local EcsComponent = HI_COMPONENT_ID + 6
local EcsOnDelete = HI_COMPONENT_ID + 7 local EcsOnDelete = HI_COMPONENT_ID + 7
local EcsOnDeleteTarget = HI_COMPONENT_ID + 8 local EcsOnDeleteTarget = HI_COMPONENT_ID + 8
local EcsDelete = HI_COMPONENT_ID + 9 local EcsDelete = HI_COMPONENT_ID + 9
local EcsRemove = HI_COMPONENT_ID + 10 local EcsRemove = HI_COMPONENT_ID + 10
local EcsName = HI_COMPONENT_ID + 11 local EcsName = HI_COMPONENT_ID + 11
local EcsRest = HI_COMPONENT_ID + 12 local EcsRest = HI_COMPONENT_ID + 12
local ECS_PAIR_FLAG = 0x8 local ECS_PAIR_FLAG = 0x8
local ECS_ID_FLAGS_MASK = 0x10 local ECS_ID_FLAGS_MASK = 0x10
local ECS_ENTITY_MASK = bit32.lshift(1, 24) local ECS_ENTITY_MASK = bit32.lshift(1, 24)
local ECS_GENERATION_MASK = bit32.lshift(1, 16) local ECS_GENERATION_MASK = bit32.lshift(1, 16)
local ECS_ID_DELETE = 0b0000_0001 local ECS_ID_DELETE = 0b0000_0001
local ECS_ID_IS_TAG = 0b0000_0010 local ECS_ID_IS_TAG = 0b0000_0010
local ECS_ID_HAS_ON_ADD = 0b0000_0100 local ECS_ID_HAS_ON_ADD = 0b0000_0100
local ECS_ID_HAS_ON_SET = 0b0000_1000 local ECS_ID_HAS_ON_SET = 0b0000_1000
local ECS_ID_HAS_ON_REMOVE = 0b0001_0000 local ECS_ID_HAS_ON_REMOVE = 0b0001_0000
local ECS_ID_MASK = 0b0000_0000 local ECS_ID_MASK = 0b0000_0000
local NULL_ARRAY = table.freeze({}) local NULL_ARRAY = table.freeze({})
local function FLAGS_ADD(is_pair: boolean): number local function FLAGS_ADD(is_pair: boolean): number
local flags = 0x0 local flags = 0x0
@ -389,9 +389,9 @@ local function world_has(world: World, entity: number, ...: i53): boolean
end end
local function world_target(world: World, entity: i53, relation: i24, index): i24? local function world_target(world: World, entity: i53, relation: i24, index): i24?
if index == nil then if index == nil then
index = 0 index = 0
end end
local record = world.entityIndex.sparse[entity] local record = world.entityIndex.sparse[entity]
local archetype = record.archetype local archetype = record.archetype
if not archetype then if not archetype then
@ -621,16 +621,16 @@ 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_refs = to.node.refs local to_refs = to.node.refs
local next_edge = to_refs.next local next_edge = to_refs.next
to_refs.next = edge to_refs.next = edge
edge.prev = to_refs edge.prev = to_refs
edge.next = next_edge edge.next = next_edge
if next_edge then if next_edge then
next_edge.prev = edge next_edge.prev = edge
end end
end end
end end
@ -638,16 +638,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_refs = to.node.refs local to_refs = to.node.refs
local prev_edge = to_refs.prev local prev_edge = to_refs.prev
to_refs.prev = edge to_refs.prev = edge
edge.next = to_refs edge.next = to_refs
edge.prev = prev_edge edge.prev = prev_edge
if prev_edge then if prev_edge then
prev_edge.next = edge prev_edge.next = edge
end end
end end
end end
@ -873,35 +873,34 @@ local function archetype_clear_edges(archetype: Archetype)
end end
local cur = node_refs.next local cur = node_refs.next
while cur do while cur do
local edge = cur local edge = cur
local next_edge = edge.next local next_edge = edge.next
archetype_remove_edge(edge.from.node.add, edge.id, edge) archetype_remove_edge(edge.from.node.add, edge.id, edge)
cur = next_edge cur = next_edge
end end
cur = node_refs.prev cur = node_refs.prev
while cur do while cur do
local edge = cur local edge = cur
local next_edge = edge.prev local next_edge = edge.prev
archetype_remove_edge(edge.from.node.remove, edge.id, edge) archetype_remove_edge(edge.from.node.remove, edge.id, edge)
cur = next_edge cur = next_edge
end end
node_refs.next = nil node_refs.next = nil
node_refs.prev = 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
if archetype == world.ROOT_ARCHETYPE then return
return end
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
world.archetypes[archetype_id] = nil world.archetypes[archetype_id] = nil
world.archetypeIndex[archetype.type] = nil world.archetypeIndex[archetype.type] = nil
local records = archetype.records local records = archetype.records
@ -917,7 +916,7 @@ local function archetype_destroy(world: World, archetype: Archetype)
end end
local function world_cleanup(world) local function world_cleanup(world)
local archetypes = world.archetypes local archetypes = world.archetypes
for _, archetype in archetypes do for _, archetype in archetypes do
if #archetype.entities == 0 then if #archetype.entities == 0 then
@ -929,7 +928,7 @@ local function world_cleanup(world)
local new_archetype_map = {} local new_archetype_map = {}
for index, archetype in archetypes do for index, archetype in archetypes do
new_archetypes[index] = archetype new_archetypes[index] = archetype
new_archetype_map[archetype.type] = archetype new_archetype_map[archetype.type] = archetype
end end
@ -1036,24 +1035,23 @@ do
end end
local object = ECS_ENTITY_T_LO(id) local object = ECS_ENTITY_T_LO(id)
if object == delete then if object == delete then
local id_record = component_index[id] local id_record = component_index[id]
local flags = id_record.flags local flags = id_record.flags
if bit32.band(flags, ECS_ID_DELETE) ~= 0 then if bit32.band(flags, ECS_ID_DELETE) ~= 0 then
for _, child in children do for _, child in children do
-- Cascade deletions of it has Delete as component trait -- Cascade deletions of it has Delete as component trait
world_delete(world, child, destruct) world_delete(world, child, destruct)
end end
break break
else else
for _, child in children do for _, child in children do
world_remove(world, child, id) world_remove(world, child, id)
end end
end end
end end
end end
archetype_destroy(world, idr_t_archetype) archetype_destroy(world, idr_t_archetype)
end end
end end
@ -1329,11 +1327,11 @@ local function query_iter_init(query)
end end
local function query_iter(query) local function query_iter(query)
local query_next = query.next local query_next = query.next
if not query_next then if not query_next then
query_next = query_iter_init(query) query_next = query_iter_init(query)
end end
return query_next return query_next
end end
local function query_without(query, ...) local function query_without(query, ...)
@ -1800,4 +1798,20 @@ return {
pair_first = ecs_pair_first, pair_first = ecs_pair_first,
pair_second = ecs_pair_second, pair_second = ecs_pair_second,
entity_index_get_alive = entity_index_get_alive, entity_index_get_alive = entity_index_get_alive,
archetype_append_to_records = archetype_append_to_records,
id_record_ensure = id_record_ensure,
archetype_create = archetype_create,
archetype_ensure = archetype_ensure,
find_insert = find_insert,
find_archetype_with = find_archetype_with,
find_archetype_without = find_archetype_without,
archetype_init_edge = archetype_init_edge,
archetype_ensure_edge = archetype_ensure_edge,
init_edge_for_add = init_edge_for_add,
init_edge_for_remove = init_edge_for_remove,
create_edge_for_add = create_edge_for_add,
create_edge_for_remove = create_edge_for_remove,
archetype_traverse_add = archetype_traverse_add,
archetype_traverse_remove = archetype_traverse_remove,
} }

View file

@ -1,5 +1,6 @@
local jecs = require("@jecs") local jecs: typeof(require("../jecs/src")) = require("@jecs");
local testkit = require("@testkit") local testkit = require("@testkit")
local BENCH, START = testkit.benchmark() local BENCH, START = testkit.benchmark()
local __ = jecs.Wildcard local __ = jecs.Wildcard
@ -71,6 +72,35 @@ local function name(world, e)
return world:get(e, jecs.Name) return world:get(e, jecs.Name)
end end
TEST("archetype", function()
local archetype_append_to_records = jecs.archetype_append_to_records
local id_record_ensure = jecs.id_record_ensure
local archetype_create = jecs.archetype_create
local archetype_ensure = jecs.archetype_ensure
local find_insert = jecs.find_insert
local find_archetype_with = jecs.find_archetype_with
local find_archetype_without = jecs.find_archetype_without
local archetype_init_edge = jecs.archetype_init_edge
local archetype_ensure_edge = jecs.archetype_ensure_edge
local init_edge_for_add = jecs.init_edge_for_add
local init_edge_for_remove = jecs.init_edge_for_remove
local create_edge_for_add = jecs.create_edge_for_add
local create_edge_for_remove = jecs.create_edge_for_remove
local archetype_traverse_add = jecs.archetype_traverse_add
local archetype_traverse_remove = jecs.archetype_traverse_remove
local world = world_new()
local root = world.ROOT_ARCHETYPE
local c1 = world:component()
local c2 = world:component()
local c3 = world:component()
local a1 = archetype_traverse_add(world, c1, nil)
local a2 = archetype_traverse_remove(world, c1, a1)
CHECK(root.node.add[c1].to == a1)
CHECK(root == a2)
end)
TEST("world:cleanup()", function() TEST("world:cleanup()", function()
local world = world_new() local world = world_new()
local A = world:component() local A = world:component()