mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Add component registration and metadata API
This commit is contained in:
parent
6ec8ed69e9
commit
a6c53c9de8
2 changed files with 179 additions and 99 deletions
238
jecs.luau
238
jecs.luau
|
@ -116,13 +116,47 @@ local ECS_ID_MASK = 0b00
|
||||||
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 NULL_ARRAY = table.freeze({})
|
local NULL_ARRAY = table.freeze({}) :: Column
|
||||||
|
local NULL = newproxy(false)
|
||||||
|
|
||||||
local ECS_INTERNAL_ERROR = [[
|
local ECS_INTERNAL_ERROR = [[
|
||||||
This is an internal error, please file a bug report via the following link:
|
This is an internal error, please file a bug report via the following link:
|
||||||
|
|
||||||
https://github.com/Ukendio/jecs/issues/new?template=BUG-REPORT.md
|
https://github.com/Ukendio/jecs/issues/new?template=BUG-REPORT.md
|
||||||
]]
|
]]
|
||||||
|
|
||||||
|
local ecs_metadata: Map<i53, Map<i53, any>> = {}
|
||||||
|
local ecs_max_component_id = 0
|
||||||
|
local ecs_max_tag_id = EcsRest
|
||||||
|
|
||||||
|
local function ECS_COMPONENT()
|
||||||
|
ecs_max_component_id += 1
|
||||||
|
if ecs_max_component_id > HI_COMPONENT_ID then
|
||||||
|
error("Too many components")
|
||||||
|
end
|
||||||
|
return ecs_max_component_id
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ECS_TAG()
|
||||||
|
ecs_max_tag_id += 1
|
||||||
|
return ecs_max_tag_id
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ECS_META(id: i53, ty: i53, value: any?)
|
||||||
|
local bundle = ecs_metadata[id]
|
||||||
|
if bundle then
|
||||||
|
bundle = {}
|
||||||
|
ecs_metadata[id] = bundle
|
||||||
|
end
|
||||||
|
bundle[ty] = if value == nil then NULL else value
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ECS_META_RESET()
|
||||||
|
ecs_metadata = {}
|
||||||
|
ecs_max_component_id = 0
|
||||||
|
ecs_max_tag_id = EcsRest
|
||||||
|
end
|
||||||
|
|
||||||
local function ECS_COMBINE(id: number, generation: number): i53
|
local function ECS_COMBINE(id: number, generation: number): i53
|
||||||
return id + (generation * ECS_ENTITY_MASK)
|
return id + (generation * ECS_ENTITY_MASK)
|
||||||
end
|
end
|
||||||
|
@ -529,62 +563,64 @@ end
|
||||||
local function id_record_ensure(world: ecs_world_t, id: number): ecs_id_record_t
|
local function id_record_ensure(world: ecs_world_t, id: number): ecs_id_record_t
|
||||||
local component_index = world.component_index
|
local component_index = world.component_index
|
||||||
local entity_index = world.entity_index
|
local entity_index = world.entity_index
|
||||||
local idr: ecs_id_record_t = component_index[id]
|
local idr: ecs_id_record_t? = component_index[id]
|
||||||
|
|
||||||
if not idr then
|
if idr then
|
||||||
local flags = ECS_ID_MASK
|
return idr
|
||||||
local relation = id
|
|
||||||
local target = 0
|
|
||||||
local is_pair = ECS_IS_PAIR(id)
|
|
||||||
if is_pair then
|
|
||||||
relation = entity_index_get_alive(entity_index, ECS_PAIR_FIRST(id)) :: i53
|
|
||||||
assert(relation and entity_index_is_alive(
|
|
||||||
entity_index, relation), ECS_INTERNAL_ERROR)
|
|
||||||
target = entity_index_get_alive(entity_index, ECS_PAIR_SECOND(id)) :: i53
|
|
||||||
assert(target and entity_index_is_alive(
|
|
||||||
entity_index, target), ECS_INTERNAL_ERROR)
|
|
||||||
end
|
|
||||||
|
|
||||||
local cleanup_policy = world_target(world, relation, EcsOnDelete, 0)
|
|
||||||
local cleanup_policy_target = world_target(world, relation, EcsOnDeleteTarget, 0)
|
|
||||||
|
|
||||||
local has_delete = false
|
|
||||||
|
|
||||||
if cleanup_policy == EcsDelete or cleanup_policy_target == EcsDelete then
|
|
||||||
has_delete = true
|
|
||||||
end
|
|
||||||
|
|
||||||
local on_add, on_change, on_remove = world_get(world,
|
|
||||||
relation, EcsOnAdd, EcsOnChange, EcsOnRemove)
|
|
||||||
|
|
||||||
local is_tag = not world_has_one_inline(world,
|
|
||||||
relation, EcsComponent)
|
|
||||||
|
|
||||||
if is_tag and is_pair then
|
|
||||||
is_tag = not world_has_one_inline(world, target, EcsComponent)
|
|
||||||
end
|
|
||||||
|
|
||||||
flags = bit32.bor(
|
|
||||||
flags,
|
|
||||||
if has_delete then ECS_ID_DELETE else 0,
|
|
||||||
if is_tag then ECS_ID_IS_TAG else 0
|
|
||||||
)
|
|
||||||
|
|
||||||
idr = {
|
|
||||||
size = 0,
|
|
||||||
cache = {},
|
|
||||||
counts = {},
|
|
||||||
flags = flags,
|
|
||||||
hooks = {
|
|
||||||
on_add = on_add,
|
|
||||||
on_change = on_change,
|
|
||||||
on_remove = on_remove,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
component_index[id] = idr
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local flags = ECS_ID_MASK
|
||||||
|
local relation = id
|
||||||
|
local target = 0
|
||||||
|
local is_pair = ECS_IS_PAIR(id)
|
||||||
|
if is_pair then
|
||||||
|
relation = entity_index_get_alive(entity_index, ECS_PAIR_FIRST(id)) :: i53
|
||||||
|
assert(relation and entity_index_is_alive(
|
||||||
|
entity_index, relation), ECS_INTERNAL_ERROR)
|
||||||
|
target = entity_index_get_alive(entity_index, ECS_PAIR_SECOND(id)) :: i53
|
||||||
|
assert(target and entity_index_is_alive(
|
||||||
|
entity_index, target), ECS_INTERNAL_ERROR)
|
||||||
|
end
|
||||||
|
|
||||||
|
local cleanup_policy = world_target(world, relation, EcsOnDelete, 0)
|
||||||
|
local cleanup_policy_target = world_target(world, relation, EcsOnDeleteTarget, 0)
|
||||||
|
|
||||||
|
local has_delete = false
|
||||||
|
|
||||||
|
if cleanup_policy == EcsDelete or cleanup_policy_target == EcsDelete then
|
||||||
|
has_delete = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local on_add, on_change, on_remove = world_get(world,
|
||||||
|
relation, EcsOnAdd, EcsOnChange, EcsOnRemove)
|
||||||
|
|
||||||
|
local is_tag = not world_has_one_inline(world,
|
||||||
|
relation, EcsComponent)
|
||||||
|
|
||||||
|
if is_tag and is_pair then
|
||||||
|
is_tag = not world_has_one_inline(world, target, EcsComponent)
|
||||||
|
end
|
||||||
|
|
||||||
|
flags = bit32.bor(
|
||||||
|
flags,
|
||||||
|
if has_delete then ECS_ID_DELETE else 0,
|
||||||
|
if is_tag then ECS_ID_IS_TAG else 0
|
||||||
|
)
|
||||||
|
|
||||||
|
idr = {
|
||||||
|
size = 0,
|
||||||
|
cache = {},
|
||||||
|
counts = {},
|
||||||
|
flags = flags,
|
||||||
|
hooks = {
|
||||||
|
on_add = on_add,
|
||||||
|
on_change = on_change,
|
||||||
|
on_remove = on_remove,
|
||||||
|
},
|
||||||
|
} :: ecs_id_record_t
|
||||||
|
|
||||||
|
component_index[id] = idr
|
||||||
|
|
||||||
return idr
|
return idr
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -621,7 +657,7 @@ local function archetype_create(world: ecs_world_t, id_types: { i24 }, ty, prev:
|
||||||
local columns = (table.create(length) :: any) :: { Column }
|
local columns = (table.create(length) :: any) :: { Column }
|
||||||
|
|
||||||
local records: { number } = {}
|
local records: { number } = {}
|
||||||
local counts: {number} = {}
|
local counts: { number } = {}
|
||||||
|
|
||||||
local archetype: ecs_archetype_t = {
|
local archetype: ecs_archetype_t = {
|
||||||
columns = columns,
|
columns = columns,
|
||||||
|
@ -670,7 +706,7 @@ local function archetype_create(world: ecs_world_t, id_types: { i24 }, ty, prev:
|
||||||
|
|
||||||
world.archetype_index[ty] = archetype
|
world.archetype_index[ty] = archetype
|
||||||
world.archetypes[archetype_id] = archetype
|
world.archetypes[archetype_id] = archetype
|
||||||
world.archetype_edges[archetype.id] = {}
|
world.archetype_edges[archetype.id] = {} :: Map<i53, ecs_archetype_t>
|
||||||
|
|
||||||
return archetype
|
return archetype
|
||||||
end
|
end
|
||||||
|
@ -747,17 +783,17 @@ local function archetype_traverse_remove(
|
||||||
local edges = world.archetype_edges
|
local edges = world.archetype_edges
|
||||||
local edge = edges[from.id]
|
local edge = edges[from.id]
|
||||||
|
|
||||||
local to = edge[id]
|
local to: ecs_archetype_t = edge[id]
|
||||||
if not to then
|
if to == nil then
|
||||||
to = find_archetype_without(world, from, id)
|
to = find_archetype_without(world, from, id)
|
||||||
edge[id] = to
|
edge[id] = to
|
||||||
edges[to.id][id] = from
|
edges[to.id][id] = from
|
||||||
end
|
end
|
||||||
|
|
||||||
return to :: ecs_archetype_t
|
return to
|
||||||
end
|
end
|
||||||
|
|
||||||
local function find_archetype_with(world, id, from)
|
local function find_archetype_with(world, id, from): ecs_archetype_t
|
||||||
local id_types = from.types
|
local id_types = from.types
|
||||||
|
|
||||||
local at = find_insert(id_types, id)
|
local at = find_insert(id_types, id)
|
||||||
|
@ -767,7 +803,7 @@ local function find_archetype_with(world, id, from)
|
||||||
return archetype_ensure(world, dst)
|
return archetype_ensure(world, dst)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function archetype_traverse_add(world, id, from: ecs_archetype_t)
|
local function archetype_traverse_add(world, id, from: ecs_archetype_t): ecs_archetype_t
|
||||||
from = from or world.ROOT_ARCHETYPE
|
from = from or world.ROOT_ARCHETYPE
|
||||||
if from.records[id] then
|
if from.records[id] then
|
||||||
return from
|
return from
|
||||||
|
@ -830,7 +866,7 @@ local function world_set(world: ecs_world_t, entity: i53, id: i53, data: unknown
|
||||||
local idr_hooks = idr.hooks
|
local idr_hooks = idr.hooks
|
||||||
|
|
||||||
if from == to then
|
if from == to then
|
||||||
local tr = to.records[id]
|
local tr = (to :: ecs_archetype_t).records[id]
|
||||||
local column = from.columns[tr]
|
local column = from.columns[tr]
|
||||||
column[record.row] = data
|
column[record.row] = data
|
||||||
|
|
||||||
|
@ -984,8 +1020,8 @@ local function world_clear(world: ecs_world_t, entity: i53)
|
||||||
end
|
end
|
||||||
|
|
||||||
if idr_t then
|
if idr_t then
|
||||||
local queue
|
local queue: { i53 }
|
||||||
local ids
|
local ids: Map<i53, boolean>
|
||||||
|
|
||||||
local count = 0
|
local count = 0
|
||||||
local archetype_ids = idr_t.cache
|
local archetype_ids = idr_t.cache
|
||||||
|
@ -1175,8 +1211,8 @@ local function world_delete(world: ecs_world_t, entity: i53)
|
||||||
end
|
end
|
||||||
|
|
||||||
if idr_t then
|
if idr_t then
|
||||||
local children
|
local children: { i53 }
|
||||||
local ids
|
local ids: Map<i53, boolean>
|
||||||
|
|
||||||
local count = 0
|
local count = 0
|
||||||
local archetype_ids = idr_t.cache
|
local archetype_ids = idr_t.cache
|
||||||
|
@ -1240,7 +1276,7 @@ local function world_delete(world: ecs_world_t, entity: i53)
|
||||||
if idr_r then
|
if idr_r then
|
||||||
local archetype_ids = idr_r.cache
|
local archetype_ids = idr_r.cache
|
||||||
local flags = idr_r.flags
|
local flags = idr_r.flags
|
||||||
if bit32.band(flags, ECS_ID_DELETE) ~= 0 then
|
if (bit32.band(flags, ECS_ID_DELETE) :: number) ~= 0 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
|
||||||
|
@ -1754,7 +1790,7 @@ local function query_cached(query: ecs_query_data_t)
|
||||||
local observable = world.observable :: ecs_observable_t
|
local observable = world.observable :: ecs_observable_t
|
||||||
local on_create_action = observable[EcsOnArchetypeCreate]
|
local on_create_action = observable[EcsOnArchetypeCreate]
|
||||||
if not on_create_action then
|
if not on_create_action then
|
||||||
on_create_action = {}
|
on_create_action = {} :: Map<i53, { ecs_observer_t }>
|
||||||
observable[EcsOnArchetypeCreate] = on_create_action
|
observable[EcsOnArchetypeCreate] = on_create_action
|
||||||
end
|
end
|
||||||
local query_cache_on_create = on_create_action[A]
|
local query_cache_on_create = on_create_action[A]
|
||||||
|
@ -1765,7 +1801,7 @@ local function query_cached(query: ecs_query_data_t)
|
||||||
|
|
||||||
local on_delete_action = observable[EcsOnArchetypeDelete]
|
local on_delete_action = observable[EcsOnArchetypeDelete]
|
||||||
if not on_delete_action then
|
if not on_delete_action then
|
||||||
on_delete_action = {}
|
on_delete_action = {} :: Map<i53, { ecs_observer_t }>
|
||||||
observable[EcsOnArchetypeDelete] = on_delete_action
|
observable[EcsOnArchetypeDelete] = on_delete_action
|
||||||
end
|
end
|
||||||
local query_cache_on_delete = on_delete_action[A]
|
local query_cache_on_delete = on_delete_action[A]
|
||||||
|
@ -2168,12 +2204,12 @@ local function world_query(world: ecs_world_t, ...)
|
||||||
return q
|
return q
|
||||||
end
|
end
|
||||||
|
|
||||||
if idr == nil or map.size < idr.size then
|
if idr == nil or (map.size :: number) < (idr.size :: number) then
|
||||||
idr = map
|
idr = map
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not idr then
|
if idr == nil then
|
||||||
return q
|
return q
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2306,7 +2342,7 @@ local function world_new()
|
||||||
ROOT_ARCHETYPE = (nil :: any) :: Archetype,
|
ROOT_ARCHETYPE = (nil :: any) :: Archetype,
|
||||||
|
|
||||||
max_archetype_id = 0,
|
max_archetype_id = 0,
|
||||||
max_component_id = 0,
|
max_component_id = ecs_max_component_id,
|
||||||
|
|
||||||
observable = {} :: Observable,
|
observable = {} :: Observable,
|
||||||
}, World) :: any
|
}, World) :: any
|
||||||
|
@ -2323,6 +2359,21 @@ local function world_new()
|
||||||
entity_index_new_id(entity_index)
|
entity_index_new_id(entity_index)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
for i = EcsRest + 1, ecs_max_tag_id do
|
||||||
|
-- Initialize built-in components
|
||||||
|
entity_index_new_id(entity_index)
|
||||||
|
end
|
||||||
|
|
||||||
|
for i, bundle in ecs_metadata do
|
||||||
|
for ty, value in bundle do
|
||||||
|
if value == NULL then
|
||||||
|
world_add(self, i, ty)
|
||||||
|
else
|
||||||
|
world_set(self, i, ty, value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
world_add(self, EcsName, EcsComponent)
|
world_add(self, EcsName, EcsComponent)
|
||||||
world_add(self, EcsOnChange, EcsComponent)
|
world_add(self, EcsOnChange, EcsComponent)
|
||||||
world_add(self, EcsOnAdd, EcsComponent)
|
world_add(self, EcsOnAdd, EcsComponent)
|
||||||
|
@ -2350,22 +2401,25 @@ end
|
||||||
|
|
||||||
World.new = world_new
|
World.new = world_new
|
||||||
|
|
||||||
export type Entity<T = unknown> = { __T: T }
|
export type Entity<T = any> = { __T: T }
|
||||||
export type Id<T = unknown> = { __T: T }
|
export type Id<T = any> = { __T: T }
|
||||||
export type Pair<P, O> = Id<P>
|
export type Pair<P, O> = Id<P>
|
||||||
type ecs_id_t<T=unknown> = Id<T> | Pair<T, "Tag"> | Pair<"Tag", T>
|
type ecs_id_t<T=unknown> = Id<T> | Pair<T, "Tag"> | Pair<"Tag", T>
|
||||||
export type Item<T...> = (self: Query<T...>) -> (Entity, T...)
|
export type Item<T...> = (self: Query<T...>) -> (Entity, T...)
|
||||||
export type Iter<T...> = (query: Query<T...>) -> () -> (Entity, T...)
|
export type Iter<T...> = (query: Query<T...>) -> () -> (Entity, T...)
|
||||||
|
|
||||||
export type Query<T...> = typeof(setmetatable({}, {
|
export type Query<T...> = typeof(setmetatable(
|
||||||
__iter = (nil :: any) :: Iter<T...>,
|
{} :: {
|
||||||
})) & {
|
iter: Iter<T...>,
|
||||||
iter: Iter<T...>,
|
with: (self: Query<T...>, ...Id) -> Query<T...>,
|
||||||
with: (self: Query<T...>, ...Id) -> Query<T...>,
|
without: (self: Query<T...>, ...Id) -> Query<T...>,
|
||||||
without: (self: Query<T...>, ...Id) -> Query<T...>,
|
archetypes: (self: Query<T...>) -> { Archetype },
|
||||||
archetypes: (self: Query<T...>) -> { Archetype },
|
cached: (self: Query<T...>) -> Query<T...>,
|
||||||
cached: (self: Query<T...>) -> Query<T...>,
|
},
|
||||||
}
|
{} :: {
|
||||||
|
__iter: Iter<T...>
|
||||||
|
}
|
||||||
|
))
|
||||||
|
|
||||||
export type Observer = {
|
export type Observer = {
|
||||||
callback: (archetype: Archetype) -> (),
|
callback: (archetype: Archetype) -> (),
|
||||||
|
@ -2399,20 +2453,20 @@ export type World = {
|
||||||
component: <T>(self: World) -> Entity<T>,
|
component: <T>(self: World) -> Entity<T>,
|
||||||
--- Gets the target of an relationship. For example, when a user calls
|
--- Gets the target of an relationship. For example, when a user calls
|
||||||
--- `world:target(id, ChildOf(parent), 0)`, you will obtain the parent entity.
|
--- `world:target(id, ChildOf(parent), 0)`, you will obtain the parent entity.
|
||||||
target: (self: World, id: Entity, relation: Id, index: number?) -> Entity?,
|
target: <T>(self: World, id: Entity, relation: Id<T>, index: number?) -> Entity?,
|
||||||
--- Deletes an entity and all it's related components and relationships.
|
--- Deletes an entity and all it's related components and relationships.
|
||||||
delete: (self: World, id: Entity) -> (),
|
delete: (self: World, id: Entity) -> (),
|
||||||
|
|
||||||
--- Adds a component to the entity with no value
|
--- Adds a component to the entity with no value
|
||||||
add: <T>(self: World, id: Entity, component: Id) -> (),
|
add: <T>(self: World, id: Entity, component: Id<T>) -> (),
|
||||||
--- Assigns a value to a component on the given entity
|
--- Assigns a value to a component on the given entity
|
||||||
set: <T>(self: World, id: Entity, component: Id<T>, data: T) -> (),
|
set: <T>(self: World, id: Entity, component: Id<T>, data: T) -> (),
|
||||||
|
|
||||||
cleanup: (self: World) -> (),
|
cleanup: (self: World) -> (),
|
||||||
-- Clears an entity from the world
|
-- Clears an entity from the world
|
||||||
clear: (self: World, id: Entity) -> (),
|
clear: <T>(self: World, id: Id<T>) -> (),
|
||||||
--- Removes a component from the given entity
|
--- Removes a component from the given entity
|
||||||
remove: (self: World, id: Entity, component: Id) -> (),
|
remove: <T>(self: World, id: Entity, component: Id<T>) -> (),
|
||||||
--- Retrieves the value of up to 4 components. These values may be nil.
|
--- Retrieves the value of up to 4 components. These values may be nil.
|
||||||
get: (<A>(self: World, id: Entity, Id<A>) -> A?)
|
get: (<A>(self: World, id: Entity, Id<A>) -> A?)
|
||||||
& (<A, B>(self: World, id: Entity, Id<A>, Id<B>) -> (A?, B?))
|
& (<A, B>(self: World, id: Entity, Id<A>, Id<B>) -> (A?, B?))
|
||||||
|
@ -2431,9 +2485,9 @@ export type World = {
|
||||||
--- Checks if the world contains the given entity
|
--- Checks if the world contains the given entity
|
||||||
contains:(self: World, entity: Entity) -> boolean,
|
contains:(self: World, entity: Entity) -> boolean,
|
||||||
|
|
||||||
each: (self: World, id: Id) -> () -> Entity,
|
each: <T>(self: World, id: Id<T>) -> () -> Entity,
|
||||||
|
|
||||||
children: (self: World, id: Id) -> () -> Entity,
|
children: <T>(self: World, id: Id<T>) -> () -> Entity,
|
||||||
|
|
||||||
--- Searches the world for entities that match a given query
|
--- Searches the world for entities that match a given query
|
||||||
query: (<A>(World, Id<A>) -> Query<A>)
|
query: (<A>(World, Id<A>) -> Query<A>)
|
||||||
|
@ -2461,10 +2515,14 @@ export type World = {
|
||||||
-- return first
|
-- return first
|
||||||
-- end
|
-- end
|
||||||
-- end
|
-- end
|
||||||
|
--
|
||||||
|
|
||||||
return {
|
return {
|
||||||
World = World :: { new: () -> World },
|
World = World :: { new: () -> World },
|
||||||
world = world_new :: () -> World,
|
world = world_new :: () -> World,
|
||||||
|
component = (ECS_COMPONENT :: any) :: <T>() -> Entity<T>,
|
||||||
|
tag = (ECS_TAG :: any) :: <T>() -> Entity<T>,
|
||||||
|
meta = (ECS_META :: any) :: <T>(id: Entity, id: Id<T>, value: T) -> Entity<T>,
|
||||||
|
|
||||||
OnAdd = EcsOnAdd :: Entity<(entity: Entity) -> ()>,
|
OnAdd = EcsOnAdd :: Entity<(entity: Entity) -> ()>,
|
||||||
OnRemove = EcsOnRemove :: Entity<(entity: Entity) -> ()>,
|
OnRemove = EcsOnRemove :: Entity<(entity: Entity) -> ()>,
|
||||||
|
@ -2487,8 +2545,8 @@ return {
|
||||||
ECS_GENERATION_INC = ECS_GENERATION_INC,
|
ECS_GENERATION_INC = ECS_GENERATION_INC,
|
||||||
ECS_GENERATION = ECS_GENERATION,
|
ECS_GENERATION = ECS_GENERATION,
|
||||||
ECS_ID_IS_WILDCARD = ECS_ID_IS_WILDCARD,
|
ECS_ID_IS_WILDCARD = ECS_ID_IS_WILDCARD,
|
||||||
|
|
||||||
ECS_ID_DELETE = ECS_ID_DELETE,
|
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,
|
||||||
pair_first = (ecs_pair_first :: any) :: <P, O>(world: World, pair: Pair<P, O>) -> Id<P>,
|
pair_first = (ecs_pair_first :: any) :: <P, O>(world: World, pair: Pair<P, O>) -> Id<P>,
|
||||||
|
|
|
@ -62,8 +62,8 @@ end)
|
||||||
|
|
||||||
TEST("world:children()", function()
|
TEST("world:children()", function()
|
||||||
local world = jecs.world()
|
local world = jecs.world()
|
||||||
local C = world:component()
|
local C = jecs.component()
|
||||||
local T = world:entity()
|
local T = jecs.tag()
|
||||||
|
|
||||||
local e1 = world:entity()
|
local e1 = world:entity()
|
||||||
world:set(e1, C, true)
|
world:set(e1, C, true)
|
||||||
|
@ -95,6 +95,8 @@ TEST("world:children()", function()
|
||||||
end
|
end
|
||||||
|
|
||||||
CHECK(count == 1)
|
CHECK(count == 1)
|
||||||
|
|
||||||
|
jecs.ECS_META_RESET()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
TEST("world:clear()", function()
|
TEST("world:clear()", function()
|
||||||
|
@ -195,6 +197,26 @@ TEST("world:clear()", function()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
TEST("world:component()", function()
|
TEST("world:component()", function()
|
||||||
|
do CASE "allow IDs to be registered"
|
||||||
|
local A = jecs.component()
|
||||||
|
local B = jecs.component()
|
||||||
|
|
||||||
|
local world = jecs.world()
|
||||||
|
local C = world:component()
|
||||||
|
CHECK((A :: any) == 1)
|
||||||
|
CHECK((B :: any) == 2)
|
||||||
|
CHECK((C :: any) == 3)
|
||||||
|
|
||||||
|
local e = world:entity()
|
||||||
|
|
||||||
|
world:set(e, A, "foo")
|
||||||
|
world:set(e, B, "foo")
|
||||||
|
world:set(e, C, "foo")
|
||||||
|
|
||||||
|
CHECK(world:has(e, A, B, C))
|
||||||
|
|
||||||
|
jecs.ECS_META_RESET() -- Reset the ECS metadata because they may have side effects
|
||||||
|
end
|
||||||
do CASE "only components should have EcsComponent trait"
|
do CASE "only components should have EcsComponent trait"
|
||||||
local world = jecs.world()
|
local world = jecs.world()
|
||||||
local A = world:component()
|
local A = world:component()
|
||||||
|
@ -720,21 +742,21 @@ TEST("world:query()", function()
|
||||||
local i = 0
|
local i = 0
|
||||||
|
|
||||||
local iter = 0
|
local iter = 0
|
||||||
for _, e in q:iter() do
|
for _ in q:iter() do
|
||||||
iter += 1
|
iter += 1
|
||||||
i=1
|
i=1
|
||||||
end
|
end
|
||||||
CHECK (iter == 1)
|
CHECK (iter == 1)
|
||||||
CHECK(i == 1)
|
CHECK(i == 1)
|
||||||
for _, e in q:iter() do
|
for _ in q:iter() do
|
||||||
i=2
|
i=2
|
||||||
end
|
end
|
||||||
CHECK(i == 2)
|
CHECK(i == 2)
|
||||||
for _, e in q :: any do
|
for _ in q do
|
||||||
i=3
|
i=3
|
||||||
end
|
end
|
||||||
CHECK(i == 3)
|
CHECK(i == 3)
|
||||||
for _, e in q :: any do
|
for _ in q do
|
||||||
i=4
|
i=4
|
||||||
end
|
end
|
||||||
CHECK(i == 4)
|
CHECK(i == 4)
|
||||||
|
@ -746,8 +768,8 @@ TEST("world:query()", function()
|
||||||
end
|
end
|
||||||
do CASE "multiple iter"
|
do CASE "multiple iter"
|
||||||
local world = jecs.World.new()
|
local world = jecs.World.new()
|
||||||
local A = world:component()
|
local A = world:component() :: jecs.Entity<string>
|
||||||
local B = world:component()
|
local B = world:component() :: jecs.Entity<string>
|
||||||
local e = world:entity()
|
local e = world:entity()
|
||||||
world:add(e, A)
|
world:add(e, A)
|
||||||
world:add(e, B)
|
world:add(e, B)
|
||||||
|
@ -756,7 +778,7 @@ TEST("world:query()", function()
|
||||||
for x in q:iter() do
|
for x in q:iter() do
|
||||||
counter += 1
|
counter += 1
|
||||||
end
|
end
|
||||||
for x in q:iter() do
|
for x, tets in q do
|
||||||
counter += 1
|
counter += 1
|
||||||
end
|
end
|
||||||
CHECK(counter == 2)
|
CHECK(counter == 2)
|
||||||
|
|
Loading…
Reference in a new issue