mirror of
https://github.com/Ukendio/jecs.git
synced 2025-08-04 11:19:17 +00:00
Compare commits
16 commits
ed8f05b902
...
e34352477d
Author | SHA1 | Date | |
---|---|---|---|
|
e34352477d | ||
|
78fe5338cf | ||
|
ca0689c92b | ||
|
117a5e0ca7 | ||
|
d99088ea1e | ||
|
012b5e2bfa | ||
|
54b21001ab | ||
|
9c09686a69 | ||
|
ebc39c8b28 | ||
|
7b86084b94 | ||
|
25ceda5cee | ||
|
fc56b6f716 | ||
|
c30328527a | ||
|
c3853023d0 | ||
|
7b253e1c2a | ||
|
96bed9bd7e |
5 changed files with 260 additions and 201 deletions
3
jecs.d.ts
vendored
3
jecs.d.ts
vendored
|
@ -321,3 +321,6 @@ export type ComponentRecord = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function component_record(world: World, id: Id): ComponentRecord
|
export function component_record(world: World, id: Id): ComponentRecord
|
||||||
|
|
||||||
|
export function bulk_insert<const C extends Id[]>(world: World, entity: Entity, ids: C, values: InferComponents<C>): void
|
||||||
|
export function bulk_remove(world: World, entity: Entity, ids: Id[]): void
|
347
jecs.luau
347
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 = {
|
||||||
|
@ -715,13 +714,13 @@ local function id_record_ensure(world: World, id: Entity): ComponentRecord
|
||||||
if world_has_one_inline(world, relation, EcsExclusive) then
|
if world_has_one_inline(world, relation, EcsExclusive) then
|
||||||
is_exclusive = true
|
is_exclusive = true
|
||||||
end
|
end
|
||||||
else
|
end
|
||||||
|
|
||||||
local cleanup_policy = world_target(world, relation, EcsOnDelete, 0)
|
local cleanup_policy = world_target(world, relation, EcsOnDelete, 0)
|
||||||
|
|
||||||
if cleanup_policy == EcsDelete then
|
if cleanup_policy == EcsDelete then
|
||||||
has_delete = true
|
has_delete = true
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
local on_add, on_change, on_remove = world_get(world,
|
local on_add, on_change, on_remove = world_get(world,
|
||||||
relation, EcsOnAdd, EcsOnChange, EcsOnRemove)
|
relation, EcsOnAdd, EcsOnChange, EcsOnRemove)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -1082,8 +1076,8 @@ local function archetype_destroy(world: World, archetype: Archetype)
|
||||||
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 +1098,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
|
||||||
|
@ -2033,7 +2025,7 @@ local function world_children<a>(world: World, parent: Id<a>)
|
||||||
return world_each(world, ECS_PAIR(EcsChildOf, parent::number))
|
return world_each(world, ECS_PAIR(EcsChildOf, parent::number))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ecs_bulk_insert(world: World, entity: Entity, ids: { Entity }, values: { any })
|
local function ecs_bulk_insert(world: World, entity: Entity, ids: { Id }, values: { any })
|
||||||
local entity_index = world.entity_index
|
local entity_index = world.entity_index
|
||||||
local r = entity_index_try_get(entity_index, entity)
|
local r = entity_index_try_get(entity_index, entity)
|
||||||
if not r then
|
if not r then
|
||||||
|
@ -2111,7 +2103,7 @@ local function ecs_bulk_insert(world: World, entity: Entity, ids: { Entity }, va
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ecs_bulk_remove(world: World, entity: Entity, ids: { Entity })
|
local function ecs_bulk_remove(world: World, entity: Entity, ids: { Id })
|
||||||
local entity_index = world.entity_index
|
local entity_index = world.entity_index
|
||||||
local r = entity_index_try_get(entity_index, entity)
|
local r = entity_index_try_get(entity_index, entity)
|
||||||
if not r then
|
if not r then
|
||||||
|
@ -2123,7 +2115,7 @@ local function ecs_bulk_remove(world: World, entity: Entity, ids: { Entity })
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local remove: { [Entity]: boolean } = {}
|
local remove: { [Id]: boolean } = {}
|
||||||
|
|
||||||
local columns_map = from.columns_map
|
local columns_map = from.columns_map
|
||||||
|
|
||||||
|
@ -2162,14 +2154,12 @@ end
|
||||||
local function world_new()
|
local function world_new()
|
||||||
local eindex_dense_array = {} :: { Entity }
|
local eindex_dense_array = {} :: { Entity }
|
||||||
local eindex_sparse_array = {} :: { Record }
|
local eindex_sparse_array = {} :: { Record }
|
||||||
local eindex_alive_count = 0
|
|
||||||
local eindex_max_id = 0
|
|
||||||
|
|
||||||
local entity_index = {
|
local entity_index = {
|
||||||
dense_array = eindex_dense_array,
|
dense_array = eindex_dense_array,
|
||||||
sparse_array = eindex_sparse_array,
|
sparse_array = eindex_sparse_array,
|
||||||
alive_count = eindex_alive_count,
|
alive_count = 0,
|
||||||
max_id = eindex_max_id,
|
max_id = 0,
|
||||||
} :: EntityIndex
|
} :: EntityIndex
|
||||||
|
|
||||||
local component_index = {} :: ComponentIndex
|
local component_index = {} :: ComponentIndex
|
||||||
|
@ -2307,28 +2297,66 @@ 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 not to then
|
if ECS_IS_PAIR(id::number) 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)
|
||||||
idr = component_index[wc]
|
idr = component_index[wc]
|
||||||
if idr and bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then
|
|
||||||
|
local edge = archetype_edges[src.id]
|
||||||
|
to = edge[id]
|
||||||
|
if to == nil then
|
||||||
|
if idr and (bit32.btest(idr.flags) == true) 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)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not to then
|
||||||
|
to = find_archetype_with(world, id, src)
|
||||||
|
if not idr then
|
||||||
|
idr = component_index[wc]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
edge[id] = to
|
||||||
|
archetype_edges[(to :: Archetype).id][id] = src
|
||||||
|
else
|
||||||
|
if bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then
|
||||||
local cr = idr.records[src.id]
|
local cr = idr.records[src.id]
|
||||||
if cr then
|
if cr then
|
||||||
local on_remove = idr.on_remove
|
local on_remove = idr.on_remove
|
||||||
|
@ -2342,47 +2370,131 @@ local function world_new()
|
||||||
local dst = table.clone(id_types)
|
local dst = table.clone(id_types)
|
||||||
dst[cr] = id
|
dst[cr] = id
|
||||||
to = archetype_ensure(world, dst)
|
to = archetype_ensure(world, dst)
|
||||||
else
|
end
|
||||||
|
end
|
||||||
|
if not to then
|
||||||
to = find_archetype_with(world, id, src)
|
to = find_archetype_with(world, id, src)
|
||||||
idr = component_index[id]
|
end
|
||||||
end
|
end
|
||||||
else
|
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)
|
to = find_archetype_with(world, id, src)
|
||||||
idr = component_index[id]
|
|
||||||
end
|
|
||||||
edge[id] = to
|
edge[id] = to
|
||||||
else
|
edges[to.id][id] = src
|
||||||
if to.dead then
|
|
||||||
archetype_register(world, to, true)
|
|
||||||
edge[id] = to
|
|
||||||
archetype_edges[to.id][id] = src
|
|
||||||
to.dead = false
|
|
||||||
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 first = ECS_PAIR_FIRST(id::number)
|
||||||
|
local wc = ECS_PAIR(first, EcsWildcard)
|
||||||
|
idr = component_index[wc]
|
||||||
|
|
||||||
|
local edge = archetype_edges[src.id]
|
||||||
|
to = edge[id]
|
||||||
|
if to == nil then
|
||||||
|
if idr and (bit32.btest(idr.flags) == true) 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)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not to then
|
||||||
|
to = find_archetype_with(world, id, src)
|
||||||
|
if not idr then
|
||||||
|
idr = component_index[wc]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
edge[id] = to
|
||||||
|
archetype_edges[(to :: Archetype).id][id] = src
|
||||||
|
else
|
||||||
|
if 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)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not to then
|
||||||
|
to = find_archetype_with(world, id, src)
|
||||||
|
end
|
||||||
|
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 +2503,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 +2606,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)
|
||||||
|
@ -2602,8 +2617,6 @@ local function world_new()
|
||||||
if not dense or r.dense == 0 then
|
if not dense or r.dense == 0 then
|
||||||
r.dense = index
|
r.dense = index
|
||||||
dense = index
|
dense = index
|
||||||
local any = eindex_dense_array[dense]
|
|
||||||
if any == entity then
|
|
||||||
local e_swap = eindex_dense_array[dense]
|
local e_swap = eindex_dense_array[dense]
|
||||||
local r_swap = inner_entity_index_try_get_any(e_swap :: number) :: Record
|
local r_swap = inner_entity_index_try_get_any(e_swap :: number) :: Record
|
||||||
|
|
||||||
|
@ -2614,7 +2627,6 @@ local function world_new()
|
||||||
|
|
||||||
eindex_dense_array[dense] = e_swap
|
eindex_dense_array[dense] = e_swap
|
||||||
eindex_dense_array[alive_count] = entity
|
eindex_dense_array[alive_count] = entity
|
||||||
end
|
|
||||||
return entity
|
return entity
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2636,7 +2648,7 @@ local function world_new()
|
||||||
|
|
||||||
return entity
|
return entity
|
||||||
else
|
else
|
||||||
for i = eindex_max_id + 1, index do
|
for i = entity_index.max_id + 1, index do
|
||||||
eindex_sparse_array[i] = { dense = i } :: Record
|
eindex_sparse_array[i] = { dense = i } :: Record
|
||||||
eindex_dense_array[i] = i
|
eindex_dense_array[i] = i
|
||||||
end
|
end
|
||||||
|
@ -2801,7 +2813,7 @@ local function world_new()
|
||||||
|
|
||||||
if idr then
|
if idr then
|
||||||
local flags = idr.flags
|
local flags = idr.flags
|
||||||
if bit32.btest(flags, ECS_ID_DELETE) then
|
if (bit32.btest(flags, ECS_ID_DELETE) == true) then
|
||||||
for archetype_id in idr.records do
|
for archetype_id in idr.records do
|
||||||
local idr_archetype = archetypes[archetype_id]
|
local idr_archetype = archetypes[archetype_id]
|
||||||
|
|
||||||
|
@ -2908,7 +2920,8 @@ local function world_new()
|
||||||
if idr_r then
|
if idr_r then
|
||||||
local archetype_ids = idr_r.records
|
local archetype_ids = idr_r.records
|
||||||
local flags = idr_r.flags
|
local flags = idr_r.flags
|
||||||
if bit32.btest(flags, ECS_ID_DELETE) then
|
local has_delete_policy = bit32.btest(flags, ECS_ID_DELETE)
|
||||||
|
if has_delete_policy then
|
||||||
for archetype_id in archetype_ids do
|
for archetype_id in archetype_ids do
|
||||||
local idr_r_archetype = archetypes[archetype_id]
|
local idr_r_archetype = archetypes[archetype_id]
|
||||||
local entities = idr_r_archetype.entities
|
local entities = idr_r_archetype.entities
|
||||||
|
@ -3038,8 +3051,10 @@ local function world_new()
|
||||||
inner_world_set(world, EcsWildcard, EcsName, "jecs.Wildcard")
|
inner_world_set(world, EcsWildcard, EcsName, "jecs.Wildcard")
|
||||||
inner_world_set(world, EcsChildOf, EcsName, "jecs.ChildOf")
|
inner_world_set(world, EcsChildOf, EcsName, "jecs.ChildOf")
|
||||||
inner_world_set(world, EcsComponent, EcsName, "jecs.Component")
|
inner_world_set(world, EcsComponent, EcsName, "jecs.Component")
|
||||||
|
|
||||||
inner_world_set(world, EcsOnDelete, EcsName, "jecs.OnDelete")
|
inner_world_set(world, EcsOnDelete, EcsName, "jecs.OnDelete")
|
||||||
inner_world_set(world, EcsOnDeleteTarget, EcsName, "jecs.OnDeleteTarget")
|
inner_world_set(world, EcsOnDeleteTarget, EcsName, "jecs.OnDeleteTarget")
|
||||||
|
|
||||||
inner_world_set(world, EcsDelete, EcsName, "jecs.Delete")
|
inner_world_set(world, EcsDelete, EcsName, "jecs.Delete")
|
||||||
inner_world_set(world, EcsRemove, EcsName, "jecs.Remove")
|
inner_world_set(world, EcsRemove, EcsName, "jecs.Remove")
|
||||||
inner_world_set(world, EcsName, EcsName, "jecs.Name")
|
inner_world_set(world, EcsName, EcsName, "jecs.Name")
|
||||||
|
@ -3048,6 +3063,9 @@ local function world_new()
|
||||||
inner_world_add(world, EcsChildOf, ECS_PAIR(EcsOnDeleteTarget, EcsDelete))
|
inner_world_add(world, EcsChildOf, ECS_PAIR(EcsOnDeleteTarget, EcsDelete))
|
||||||
inner_world_add(world, EcsChildOf, EcsExclusive)
|
inner_world_add(world, EcsChildOf, EcsExclusive)
|
||||||
|
|
||||||
|
inner_world_add(world, EcsOnDelete, EcsExclusive)
|
||||||
|
inner_world_add(world, EcsOnDeleteTarget, EcsExclusive)
|
||||||
|
|
||||||
for i = EcsRest + 1, ecs_max_tag_id do
|
for i = EcsRest + 1, ecs_max_tag_id do
|
||||||
entity_index_new_id(entity_index)
|
entity_index_new_id(entity_index)
|
||||||
end
|
end
|
||||||
|
@ -3121,14 +3139,6 @@ return {
|
||||||
|
|
||||||
pair = (ECS_PAIR :: any) :: <P, O>(first: Id<P>, second: Id<O>) -> Pair<P, O>,
|
pair = (ECS_PAIR :: any) :: <P, O>(first: Id<P>, second: Id<O>) -> Pair<P, O>,
|
||||||
|
|
||||||
-- Inwards facing API for testing
|
|
||||||
ECS_ID = ECS_ENTITY_T_LO,
|
|
||||||
ECS_GENERATION_INC = ECS_GENERATION_INC,
|
|
||||||
ECS_GENERATION = ECS_GENERATION,
|
|
||||||
ECS_ID_IS_WILDCARD = ECS_ID_IS_WILDCARD,
|
|
||||||
ECS_ID_DELETE = ECS_ID_DELETE,
|
|
||||||
ECS_META_RESET = ECS_META_RESET,
|
|
||||||
|
|
||||||
IS_PAIR = (ECS_IS_PAIR :: any) :: <P, O>(pair: Pair<P, O>) -> boolean,
|
IS_PAIR = (ECS_IS_PAIR :: any) :: <P, O>(pair: Pair<P, O>) -> boolean,
|
||||||
ECS_PAIR_FIRST = ECS_PAIR_FIRST :: <P, O>(pair: Pair<P, O>) -> Id<P>,
|
ECS_PAIR_FIRST = ECS_PAIR_FIRST :: <P, O>(pair: Pair<P, O>) -> Id<P>,
|
||||||
ECS_PAIR_SECOND = ECS_PAIR_SECOND :: <P, O>(pair: Pair<P, O>) -> Id<O>,
|
ECS_PAIR_SECOND = ECS_PAIR_SECOND :: <P, O>(pair: Pair<P, O>) -> Id<O>,
|
||||||
|
@ -3136,6 +3146,17 @@ return {
|
||||||
pair_second = (ecs_pair_second :: any) :: <P, O>(world: World, pair: Pair<P, O>) -> Id<O>,
|
pair_second = (ecs_pair_second :: any) :: <P, O>(world: World, pair: Pair<P, O>) -> Id<O>,
|
||||||
entity_index_get_alive = entity_index_get_alive,
|
entity_index_get_alive = entity_index_get_alive,
|
||||||
|
|
||||||
|
-- Inwards facing API for testing
|
||||||
|
ECS_ID = ECS_ENTITY_T_LO,
|
||||||
|
ECS_GENERATION_INC = ECS_GENERATION_INC,
|
||||||
|
ECS_GENERATION = ECS_GENERATION,
|
||||||
|
ECS_ID_IS_WILDCARD = ECS_ID_IS_WILDCARD,
|
||||||
|
ECS_ID_IS_EXCLUSIVE = ECS_ID_IS_EXCLUSIVE,
|
||||||
|
ECS_ID_DELETE = ECS_ID_DELETE,
|
||||||
|
ECS_META_RESET = ECS_META_RESET,
|
||||||
|
ECS_COMBINE = ECS_COMBINE,
|
||||||
|
ECS_ENTITY_MASK = ECS_ENTITY_MASK,
|
||||||
|
|
||||||
archetype_append_to_records = archetype_append_to_records,
|
archetype_append_to_records = archetype_append_to_records,
|
||||||
id_record_ensure = id_record_ensure,
|
id_record_ensure = id_record_ensure,
|
||||||
component_record = id_record_get,
|
component_record = id_record_get,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@rbxts/jecs",
|
"name": "@rbxts/jecs",
|
||||||
"version": "0.8.3",
|
"version": "0.9.0-rc.3",
|
||||||
"description": "Stupidly fast Entity Component System",
|
"description": "Stupidly fast Entity Component System",
|
||||||
"main": "jecs.luau",
|
"main": "jecs.luau",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -24,6 +24,38 @@ type Id<T=unknown> = jecs.Id<T>
|
||||||
local entity_visualiser = require("@tools/entity_visualiser")
|
local entity_visualiser = require("@tools/entity_visualiser")
|
||||||
local dwi = entity_visualiser.stringify
|
local dwi = entity_visualiser.stringify
|
||||||
|
|
||||||
|
TEST("ardi", function()
|
||||||
|
local world = jecs.world()
|
||||||
|
local r = world:entity()
|
||||||
|
world:add(r, jecs.pair(jecs.OnDelete, jecs.Delete))
|
||||||
|
|
||||||
|
local e = world:entity()
|
||||||
|
local e1 = world:entity()
|
||||||
|
world:add(e, jecs.pair(r, e1))
|
||||||
|
|
||||||
|
world:delete(r)
|
||||||
|
CHECK(not world:contains(e))
|
||||||
|
end)
|
||||||
|
|
||||||
|
TEST("dai", function()
|
||||||
|
local world = jecs.world()
|
||||||
|
local C = world:component()
|
||||||
|
|
||||||
|
world:set(C, jecs.Name, "C")
|
||||||
|
CHECK(world:get(C, jecs.Name) == "C")
|
||||||
|
world:entity(2000)
|
||||||
|
CHECK(world:get(C, jecs.Name) == "C")
|
||||||
|
end)
|
||||||
|
|
||||||
|
TEST("another axen banger", function()
|
||||||
|
-- taken from jecs.luau
|
||||||
|
local world = jecs.world()
|
||||||
|
world:range(2000, 3000)
|
||||||
|
|
||||||
|
local e0v1_id = jecs.ECS_COMBINE(1000, 1) -- id can be both within or outside the world's range
|
||||||
|
local e0v1 = world:entity(e0v1_id)
|
||||||
|
assert(world:contains(e0v1)) -- fails
|
||||||
|
end)
|
||||||
TEST("Ensure archetype edges get cleaned", function()
|
TEST("Ensure archetype edges get cleaned", function()
|
||||||
local A = jecs.component()
|
local A = jecs.component()
|
||||||
local B = jecs.component()
|
local B = jecs.component()
|
||||||
|
@ -129,6 +161,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 +190,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 +198,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()
|
||||||
|
@ -311,23 +346,12 @@ TEST("world:add()", function()
|
||||||
world:add(A, jecs.Exclusive)
|
world:add(A, jecs.Exclusive)
|
||||||
local on_remove_call = false
|
local on_remove_call = false
|
||||||
world:set(A, jecs.OnRemove, function(e, id)
|
world:set(A, jecs.OnRemove, function(e, id)
|
||||||
CHECK(e == e_ptr)
|
|
||||||
CHECK(id == jecs.pair(A, B))
|
|
||||||
on_remove_call = true
|
on_remove_call = true
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local on_add_call_count = 0
|
local on_add_call_count = 0
|
||||||
world:set(A, jecs.OnAdd, function(e, id)
|
world:set(A, jecs.OnAdd, function(e, id)
|
||||||
on_add_call_count += 1
|
on_add_call_count += 1
|
||||||
if on_add_call_count == 1 then
|
|
||||||
CHECK(e == e_ptr)
|
|
||||||
CHECK(id == jecs.pair(A, B))
|
|
||||||
elseif on_add_call_count == 2 then
|
|
||||||
CHECK(e == e_ptr)
|
|
||||||
CHECK(id == jecs.pair(A, C))
|
|
||||||
else
|
|
||||||
CHECK(false)
|
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
@ -342,6 +366,17 @@ TEST("world:add()", function()
|
||||||
CHECK(world:has(e, pair(A, B)) == false)
|
CHECK(world:has(e, pair(A, B)) == false)
|
||||||
CHECK(world:has(e, pair(A, C)) == true)
|
CHECK(world:has(e, pair(A, C)) == true)
|
||||||
|
|
||||||
|
-- We have to ensure that it actually invokes hooks everytime it
|
||||||
|
-- traverses the archetype
|
||||||
|
e = world:entity()
|
||||||
|
world:add(e, pair(A, B))
|
||||||
|
CHECK(on_add_call_count == 3)
|
||||||
|
world:add(e, pair(A, C))
|
||||||
|
CHECK(on_add_call_count == 4)
|
||||||
|
CHECK(on_remove_call)
|
||||||
|
|
||||||
|
CHECK(world:has(e, pair(A, B)) == false)
|
||||||
|
CHECK(world:has(e, pair(A, C)) == true)
|
||||||
end
|
end
|
||||||
|
|
||||||
do CASE "idempotent"
|
do CASE "idempotent"
|
||||||
|
@ -599,9 +634,9 @@ TEST("world:delete()", function()
|
||||||
world:add(e1, ct)
|
world:add(e1, ct)
|
||||||
world:add(e2, jecs.pair(ct, dummy))
|
world:add(e2, jecs.pair(ct, dummy))
|
||||||
|
|
||||||
world:delete(dummy)
|
-- world:delete(dummy)
|
||||||
|
|
||||||
CHECK(world:contains(e2))
|
-- CHECK(world:contains(e2))
|
||||||
|
|
||||||
world:delete(ct)
|
world:delete(ct)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "ukendio/jecs"
|
name = "ukendio/jecs"
|
||||||
version = "0.8.3"
|
version = "0.9.0-rc.3"
|
||||||
registry = "https://github.com/UpliftGames/wally-index"
|
registry = "https://github.com/UpliftGames/wally-index"
|
||||||
realm = "shared"
|
realm = "shared"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
Loading…
Reference in a new issue