Compare commits

..

2 commits

Author SHA1 Message Date
Marcus
8fc5bab9af
Merge 825a8248a7 into 24dddee82e 2025-06-25 19:09:59 +00:00
Ukendio
825a8248a7 temp
Some checks failed
analysis / Run Luau Analyze (push) Has been cancelled
unit-testing / Run Luau Tests (push) Has been cancelled
2025-06-25 21:07:58 +02:00
5 changed files with 1311 additions and 1355 deletions

View file

@ -25,10 +25,9 @@ local function observers_new(world, query, callback)
end end
local entity_index = world.entity_index :: any local entity_index = world.entity_index :: any
local sparse_array = entity_index.sparse_array
local function emplaced(entity, id, value) local function emplaced(entity, id, value)
local r = sparse_array[jecs.ECS_ID(entity)] local r = jecs.entity_index_try_get_fast(
entity_index, entity :: any)
if not r then if not r then
return return
@ -99,11 +98,10 @@ local function monitors_new(world, query, callback)
terms = ids terms = ids
end end
local entity_index = world.entity_index local entity_index = world.entity_index :: any
local sparse_array = entity_index.sparse_array
local function emplaced(entity: jecs.Entity) local function emplaced(entity: jecs.Entity)
local r = sparse_array[jecs.ECS_ID(entity::number)] :: jecs.Record local r = jecs.entity_index_try_get_fast(
entity_index, entity :: any)
if not r then if not r then
return return
@ -117,7 +115,8 @@ local function monitors_new(world, query, callback)
end end
local function removed(entity: jecs.Entity, component: jecs.Id) local function removed(entity: jecs.Entity, component: jecs.Id)
local r = sparse_array[jecs.ECS_ID(entity::number)] :: jecs.Record local r = jecs.entity_index_try_get_fast(
entity_index, entity :: any)
if not r then if not r then
return return

View file

@ -2,7 +2,8 @@
--!native --!native
local ReplicatedStorage = game:GetService("ReplicatedStorage") local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Matter = require(ReplicatedStorage.DevPackages.Matter) local Matter = require(ReplicatedStorage.DevPackages.matter)
local ecr = require(ReplicatedStorage.DevPackages.ecr)
local newWorld = Matter.World.new() local newWorld = Matter.World.new()
local jecs = require(ReplicatedStorage.Lib:Clone()) local jecs = require(ReplicatedStorage.Lib:Clone())
@ -19,6 +20,15 @@ local A6 = Matter.component()
local A7 = Matter.component() local A7 = Matter.component()
local A8 = Matter.component() local A8 = Matter.component()
local B1 = ecr.component()
local B2 = ecr.component()
local B3 = ecr.component()
local B4 = ecr.component()
local B5 = ecr.component()
local B6 = ecr.component()
local B7 = ecr.component()
local B8 = ecr.component()
local D1 = ecs:component() local D1 = ecs:component()
local D2 = ecs:component() local D2 = ecs:component()
local D3 = ecs:component() local D3 = ecs:component()
@ -37,6 +47,8 @@ local E6 = mcs:component()
local E7 = mcs:component() local E7 = mcs:component()
local E8 = mcs:component() local E8 = mcs:component()
local registry2 = ecr.registry()
local function flip() local function flip()
return math.random() >= 0.25 return math.random() >= 0.25
end end
@ -44,42 +56,37 @@ end
local N = 2 ^ 16 - 2 local N = 2 ^ 16 - 2
local archetypes = {} local archetypes = {}
for i = 1, 1000 do
ecs:entity()
mcs:entity()
end
local hm = 0 local hm = 0
for i = 1, N do for i = 1, N do
local id = registry2.create()
local combination = "" local combination = ""
local n = newWorld:spawn() local n = newWorld:spawn()
local entity = ecs:entity() local entity = ecs:entity()
local m = mcs:entity() local m = mcs:entity()
if flip() then if flip() then
ecs:add(entity, math.random(1, 1000) + jecs.Rest + 1) registry2:set(id, B1, { value = true })
mcs:add(m, math.random(1, 1000) + jecs.Rest + 1)
end
if flip() then
ecs:set(entity, D1, { value = true }) ecs:set(entity, D1, { value = true })
newWorld:insert(n, A1({ value = true })) newWorld:insert(n, A1({ value = true }))
mcs:set(m, E1, { value = 2 }) mcs:set(m, E1, { value = 2 })
end end
if flip() then if flip() then
combination ..= "B" combination ..= "B"
registry2:set(id, B2, { value = true })
ecs:set(entity, D2, { value = true }) ecs:set(entity, D2, { value = true })
mcs:set(m, E2, { value = 2 }) mcs:set(m, E2, { value = 2 })
newWorld:insert(n, A2({ value = true })) newWorld:insert(n, A2({ value = true }))
end end
if flip() then if flip() then
combination ..= "C" combination ..= "C"
registry2:set(id, B3, { value = true })
ecs:set(entity, D3, { value = true }) ecs:set(entity, D3, { value = true })
mcs:set(m, E3, { value = 2 }) mcs:set(m, E3, { value = 2 })
newWorld:insert(n, A3({ value = true })) newWorld:insert(n, A3({ value = true }))
end end
if flip() then if flip() then
combination ..= "D" combination ..= "D"
registry2:set(id, B4, { value = true })
ecs:set(entity, D4, { value = true }) ecs:set(entity, D4, { value = true })
mcs:set(m, E4, { value = 2 }) mcs:set(m, E4, { value = 2 })
@ -87,6 +94,7 @@ for i = 1, N do
end end
if flip() then if flip() then
combination ..= "E" combination ..= "E"
registry2:set(id, B5, { value = true })
ecs:set(entity, D5, { value = true }) ecs:set(entity, D5, { value = true })
mcs:set(m, E5, { value = 2 }) mcs:set(m, E5, { value = 2 })
@ -94,18 +102,21 @@ for i = 1, N do
end end
if flip() then if flip() then
combination ..= "F" combination ..= "F"
registry2:set(id, B6, { value = true })
ecs:set(entity, D6, { value = true }) ecs:set(entity, D6, { value = true })
mcs:set(m, E6, { value = 2 }) mcs:set(m, E6, { value = 2 })
newWorld:insert(n, A6({ value = true })) newWorld:insert(n, A6({ value = true }))
end end
if flip() then if flip() then
combination ..= "G" combination ..= "G"
registry2:set(id, B7, { value = true })
ecs:set(entity, D7, { value = true }) ecs:set(entity, D7, { value = true })
mcs:set(m, E7, { value = 2 }) mcs:set(m, E7, { value = 2 })
newWorld:insert(n, A7({ value = true })) newWorld:insert(n, A7({ value = true }))
end end
if flip() then if flip() then
combination ..= "H" combination ..= "H"
registry2:set(id, B8, { value = true })
newWorld:insert(n, A8({ value = true })) newWorld:insert(n, A8({ value = true }))
ecs:set(entity, D8, { value = true }) ecs:set(entity, D8, { value = true })
mcs:set(m, E8, { value = 2 }) mcs:set(m, E8, { value = 2 })
@ -123,15 +134,12 @@ print("TEST", hm)
local count = 0 local count = 0
for _, archetype in ecs:query(D2, D4):archetypes() do for _, archetype in ecs:query(D2, D4, D6, D8):archetypes() do
count += 1 count += #archetype.entities
end end
print(count) print(count)
local mq = ecs:query(E2, E4, D6, D8, 500):cached()
local jq = ecs:query(D2, D4, D6, D8, 500):cached()
return { return {
ParameterGenerator = function() ParameterGenerator = function()
return return
@ -149,24 +157,13 @@ return {
-- end, -- end,
-- --
Mirror = function() Mirror = function()
for _, archetype in mq:archetypes() do for entityId, firstComponent in mcs:query(E2, E4, E6, E8) do
if mirror.query_match(mq, archetype) then
end
end end
-- for entityId, firstComponent in mcs:query(E2, E4) do
-- end
end, end,
Jecs = function() Jecs = function()
for _, archetype in jq:archetypes() do for entityId, firstComponent in ecs:query(D2, D4, D6, D8) do
if jecs.query_match(jq, archetype) then
end end
end end,
-- for entityId, firstComponent in ecs:query(D2, D4) do
-- end
end,
}, },
} }

218
jecs.luau
View file

@ -21,7 +21,6 @@ export type Archetype = {
columns: { Column }, columns: { Column },
columns_map: { [Id]: Column }, columns_map: { [Id]: Column },
dead: boolean, dead: boolean,
bloom_filter: number
} }
export type QueryInner = { export type QueryInner = {
@ -31,12 +30,12 @@ export type QueryInner = {
filter_without: { i53 }, filter_without: { i53 },
next: () -> (number, ...any), next: () -> (number, ...any),
world: World, world: World,
bloom_filter: number
} }
export type Entity<T = any> = number | { __T: T } export type Entity<T = any> = number | { __T: T }
export type Id<T = any> = number | { __T: T } export type Id<T = any> = number | { __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>
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...)
@ -49,13 +48,13 @@ export type Query<T...> = typeof(setmetatable(
cached: (self: Query<T...>) -> Query<T...>, cached: (self: Query<T...>) -> Query<T...>,
}, },
{} :: { {} :: {
__iter: Iter<T...>, __iter: Iter<T...>
} }
)) ))
export type Observer = { export type Observer = {
callback: (archetype: Archetype) -> (), callback: (archetype: Archetype) -> (),
query: QueryInner, query: QueryInner,
} }
export type World = { export type World = {
@ -103,7 +102,7 @@ export type World = {
--- Returns whether the entity has the ID. --- Returns whether the entity has the ID.
has: (<T, a>(World, Entity<T>, Id<a>) -> boolean) has: (<T, a>(World, Entity<T>, Id<a>) -> boolean)
& (<T, a, b>(World, Entity<T>, Id<a>, Id<a>) -> boolean) & (<T, a, b >(World, Entity<T>, Id<a>, Id<a>) -> boolean)
& (<T, a, b, c>(World, Entity<T>, Id<a>, Id<b>, Id<c>) -> boolean) & (<T, a, b, c>(World, Entity<T>, Id<a>, Id<b>, Id<c>) -> boolean)
& <T, a, b, c, d>(World, Entity<T>, Id<a>, Id<b>, Id<c>, Id<d>) -> boolean, & <T, a, b, c, d>(World, Entity<T>, Id<a>, Id<b>, Id<c>, Id<d>) -> boolean,
@ -127,28 +126,8 @@ export type World = {
& (<A, B, C, D>(World, Id<A>, Id<B>, Id<C>, Id<D>) -> Query<A, B, C, D>) & (<A, B, C, D>(World, Id<A>, Id<B>, Id<C>, Id<D>) -> Query<A, B, C, D>)
& (<A, B, C, D, E>(World, Id<A>, Id<B>, Id<C>, Id<D>, Id<E>) -> Query<A, B, C, D, E>) & (<A, B, C, D, E>(World, Id<A>, Id<B>, Id<C>, Id<D>, Id<E>) -> Query<A, B, C, D, E>)
& (<A, B, C, D, E, F>(World, Id<A>, Id<B>, Id<C>, Id<D>, Id<E>, Id<F>) -> Query<A, B, C, D, E, F>) & (<A, B, C, D, E, F>(World, Id<A>, Id<B>, Id<C>, Id<D>, Id<E>, Id<F>) -> Query<A, B, C, D, E, F>)
& (<A, B, C, D, E, F, G>( & (<A, B, C, D, E, F, G>(World, Id<A>, Id<B>, Id<C>, Id<D>, Id<E>, Id<F>, Id<G>) -> Query<A, B, C, D, E, F, G>)
World, & (<A, B, C, D, E, F, G, H>(World, Id<A>, Id<B>, Id<C>, Id<D>, Id<E>, Id<F>, Id<G>, Id<H>, ...Id<any>) -> Query<A, B, C, D, E, F, G, H>)
Id<A>,
Id<B>,
Id<C>,
Id<D>,
Id<E>,
Id<F>,
Id<G>
) -> Query<A, B, C, D, E, F, G>)
& (<A, B, C, D, E, F, G, H>(
World,
Id<A>,
Id<B>,
Id<C>,
Id<D>,
Id<E>,
Id<F>,
Id<G>,
Id<H>,
...Id<any>
) -> Query<A, B, C, D, E, F, G, H>),
} }
export type Record = { export type Record = {
@ -176,7 +155,7 @@ export type EntityIndex = {
alive_count: number, alive_count: number,
max_id: number, max_id: number,
range_begin: number?, range_begin: number?,
range_end: number?, range_end: number?
} }
-- stylua: ignore start -- stylua: ignore start
@ -205,8 +184,6 @@ local EcsOnArchetypeCreate = HI_COMPONENT_ID + 12
local EcsOnArchetypeDelete = HI_COMPONENT_ID + 13 local EcsOnArchetypeDelete = HI_COMPONENT_ID + 13
local EcsRest = HI_COMPONENT_ID + 14 local EcsRest = HI_COMPONENT_ID + 14
-- stylua: ignore end
local NULL_ARRAY = table.freeze({}) :: Column local NULL_ARRAY = table.freeze({}) :: Column
local NULL = newproxy(false) local NULL = newproxy(false)
@ -308,7 +285,10 @@ local function ECS_PAIR_SECOND(e: i53): i24
return (e - ECS_PAIR_OFFSET) % ECS_ENTITY_MASK return (e - ECS_PAIR_OFFSET) % ECS_ENTITY_MASK
end end
local function entity_index_try_get_any(entity_index: EntityIndex, entity: number): Record? local function entity_index_try_get_any(
entity_index: EntityIndex,
entity: number
): Record?
local r = entity_index.sparse_array[ECS_ENTITY_T_LO(entity)] local r = entity_index.sparse_array[ECS_ENTITY_T_LO(entity)]
if not r or r.dense == 0 then if not r or r.dense == 0 then
@ -405,18 +385,10 @@ local function ecs_pair_second(world: World, e: i53)
return ecs_get_alive(world, obj) return ecs_get_alive(world, obj)
end end
local function bloom_filter_check(bloom: number, filter: number): boolean
return (bloom % (filter * 2)) >= filter
end
local function query_match(query: QueryInner, archetype: Archetype) local function query_match(query: QueryInner, archetype: Archetype)
local columns_map = archetype.columns_map local columns_map = archetype.columns_map
local with = query.filter_with local with = query.filter_with
if not bloom_filter_check(query.bloom_filter, archetype.bloom_filter) then
return false
end
for _, id in with do for _, id in with do
if not columns_map[id] then if not columns_map[id] then
return false return false
@ -443,8 +415,13 @@ local function find_observers(world: World, event: Id, component: Id): { Observe
return cache[component] :: any return cache[component] :: any
end end
local function archetype_move(
local function archetype_move(entity_index: EntityIndex, to: Archetype, dst_row: i24, from: Archetype, src_row: i24) entity_index: EntityIndex,
to: Archetype,
dst_row: i24,
from: Archetype,
src_row: i24
)
local src_columns = from.columns local src_columns = from.columns
local dst_entities = to.entities local dst_entities = to.entities
local src_entities = from.entities local src_entities = from.entities
@ -497,21 +474,33 @@ local function archetype_move(entity_index: EntityIndex, to: Archetype, dst_row:
record2.row = src_row record2.row = src_row
end end
local function archetype_append(entity: Entity, archetype: Archetype): number local function archetype_append(
entity: Entity,
archetype: Archetype
): number
local entities = archetype.entities local entities = archetype.entities
local length = #entities + 1 local length = #entities + 1
entities[length] = entity entities[length] = entity
return length return length
end end
local function new_entity(entity: Entity, record: Record, archetype: Archetype): Record local function new_entity(
entity: Entity,
record: Record,
archetype: Archetype
): Record
local row = archetype_append(entity, archetype) local row = archetype_append(entity, archetype)
record.archetype = archetype record.archetype = archetype
record.row = row record.row = row
return record return record
end end
local function entity_move(entity_index: EntityIndex, entity: Entity, record: Record, to: Archetype) local function entity_move(
entity_index: EntityIndex,
entity: Entity,
record: Record,
to: Archetype
)
local sourceRow = record.row local sourceRow = record.row
local from = record.archetype local from = record.archetype
local dst_row = archetype_append(entity, to) local dst_row = archetype_append(entity, to)
@ -534,7 +523,8 @@ local function fetch(id: Id, columns_map: { [Entity]: Column }, row: number): an
return column[row] return column[row]
end end
local function world_get(world: World, entity: Entity, a: Id, b: Id?, c: Id?, d: Id?, e: Id?): ...any local function world_get(world: World, entity: Entity,
a: Id, b: Id?, c: Id?, d: Id?, e: Id?): ...any
local record = entity_index_try_get(world.entity_index, entity) local record = entity_index_try_get(world.entity_index, entity)
if not record then if not record then
return nil return nil
@ -614,7 +604,8 @@ local function world_target(world: World, entity: Entity, relation: Id, index: n
return nil return nil
end end
return entity_index_get_alive(entity_index, ECS_PAIR_SECOND(nth :: number)) return entity_index_get_alive(entity_index,
ECS_PAIR_SECOND(nth :: number))
end end
local function ECS_ID_IS_WILDCARD(e: i53): boolean local function ECS_ID_IS_WILDCARD(e: i53): boolean
@ -649,9 +640,11 @@ local function id_record_ensure(world: World, id: Entity): ComponentRecord
local is_pair = ECS_IS_PAIR(id :: number) local is_pair = ECS_IS_PAIR(id :: number)
if is_pair then if is_pair then
relation = entity_index_get_alive(entity_index, ECS_PAIR_FIRST(id :: number)) :: i53 relation = entity_index_get_alive(entity_index, ECS_PAIR_FIRST(id :: number)) :: i53
ecs_assert(relation and entity_index_is_alive(entity_index, relation), ECS_INTERNAL_ERROR) ecs_assert(relation and entity_index_is_alive(
entity_index, relation), ECS_INTERNAL_ERROR)
target = entity_index_get_alive(entity_index, ECS_PAIR_SECOND(id :: number)) :: i53 target = entity_index_get_alive(entity_index, ECS_PAIR_SECOND(id :: number)) :: i53
ecs_assert(target and entity_index_is_alive(entity_index, target), ECS_INTERNAL_ERROR) ecs_assert(target and entity_index_is_alive(
entity_index, target), ECS_INTERNAL_ERROR)
end end
local cleanup_policy = world_target(world, relation, EcsOnDelete, 0) local cleanup_policy = world_target(world, relation, EcsOnDelete, 0)
@ -663,15 +656,21 @@ local function id_record_ensure(world: World, id: Entity): ComponentRecord
has_delete = true has_delete = true
end end
local on_add, on_change, on_remove = world_get(world, relation, EcsOnAdd, EcsOnChange, EcsOnRemove) 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) local is_tag = not world_has_one_inline(world,
relation, EcsComponent)
if is_tag and is_pair then if is_tag and is_pair then
is_tag = not world_has_one_inline(world, target, EcsComponent) is_tag = not world_has_one_inline(world, target, EcsComponent)
end end
flags = bit32.bor(flags, if has_delete then ECS_ID_DELETE else 0, if is_tag then ECS_ID_IS_TAG else 0) flags = bit32.bor(
flags,
if has_delete then ECS_ID_DELETE else 0,
if is_tag then ECS_ID_IS_TAG else 0
)
idr = { idr = {
size = 0, size = 0,
@ -739,15 +738,6 @@ local function archetype_register(world: World, archetype: Archetype)
end end
end end
local function bloom_filter_add(filter: number, value: number): number
local shift = value % 53
local bit = 2 ^ shift
if filter % (bit * 2) < bit then
filter = filter + bit
end
return filter
end
local function archetype_create(world: World, id_types: { Id }, ty, prev: i53?): Archetype local function archetype_create(world: World, id_types: { Id }, ty, prev: i53?): Archetype
local archetype_id = (world.max_archetype_id :: number) + 1 local archetype_id = (world.max_archetype_id :: number) + 1
world.max_archetype_id = archetype_id world.max_archetype_id = archetype_id
@ -757,12 +747,6 @@ local function archetype_create(world: World, id_types: { Id }, ty, prev: i53?):
local columns_map: { [Id]: Column } = {} local columns_map: { [Id]: Column } = {}
local filter = 0
for _, id in id_types do
filter = bloom_filter_add(filter, id :: number)
end
local archetype: Archetype = { local archetype: Archetype = {
columns = columns, columns = columns,
columns_map = columns_map, columns_map = columns_map,
@ -771,7 +755,6 @@ local function archetype_create(world: World, id_types: { Id }, ty, prev: i53?):
type = ty, type = ty,
types = id_types, types = id_types,
dead = false, dead = false,
bloom_filter = filter,
} }
archetype_register(world, archetype) archetype_register(world, archetype)
@ -810,7 +793,7 @@ local function world_range(world: World, range_begin: number, range_end: number?
for i = max_id + 1, range_begin do for i = max_id + 1, range_begin do
dense_array[i] = i dense_array[i] = i
sparse_array[i] = { sparse_array[i] = {
dense = 0, dense = 0
} :: Record } :: Record
end end
entity_index.max_id = range_begin - 1 entity_index.max_id = range_begin - 1
@ -849,7 +832,11 @@ local function find_insert(id_types: { i53 }, toAdd: i53): number
return #id_types + 1 return #id_types + 1
end end
local function find_archetype_without(world: World, node: Archetype, id: Id): Archetype local function find_archetype_without(
world: World,
node: Archetype,
id: Id
): Archetype
local id_types = node.types local id_types = node.types
local at = table.find(id_types, id) local at = table.find(id_types, id)
@ -859,7 +846,13 @@ local function find_archetype_without(world: World, node: Archetype, id: Id): Ar
return archetype_ensure(world, dst) return archetype_ensure(world, dst)
end end
local function create_edge_for_remove(world: World, node: Archetype, edge: Map<Id, Archetype>, id: Id): Archetype
local function create_edge_for_remove(
world: World,
node: Archetype,
edge: Map<Id, Archetype>,
id: Id
): Archetype
local to = find_archetype_without(world, node, id) local to = find_archetype_without(world, node, id)
local edges = world.archetype_edges local edges = world.archetype_edges
local archetype_id = node.id local archetype_id = node.id
@ -868,7 +861,11 @@ local function create_edge_for_remove(world: World, node: Archetype, edge: Map<I
return to return to
end end
local function archetype_traverse_remove(world: World, id: Id, from: Archetype): Archetype local function archetype_traverse_remove(
world: World,
id: Id,
from: Archetype
): Archetype
local edges = world.archetype_edges local edges = world.archetype_edges
local edge = edges[from.id] local edge = edges[from.id]
@ -885,7 +882,7 @@ end
local function find_archetype_with(world: World, id: Id, from: Archetype): Archetype local function find_archetype_with(world: World, id: Id, from: Archetype): Archetype
local id_types = from.types local id_types = from.types
local at = find_insert(id_types :: { number }, id :: number) local at = find_insert(id_types :: { number } , id :: number)
local dst = table.clone(id_types) local dst = table.clone(id_types)
table.insert(dst, at, id) table.insert(dst, at, id)
@ -922,6 +919,8 @@ local function world_component(world: World): i53
return id return id
end end
local function archetype_fast_delete_last(columns: { Column }, column_count: number) local function archetype_fast_delete_last(columns: { Column }, column_count: number)
for i, column in columns do for i, column in columns do
if column ~= NULL_ARRAY then if column ~= NULL_ARRAY then
@ -978,6 +977,7 @@ local function archetype_delete(world: World, archetype: Archetype, row: number)
end end
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
@ -1020,6 +1020,7 @@ end
local function NOOP() end local function NOOP() end
local function query_iter_init(query: QueryInner): () -> (number, ...any) local function query_iter_init(query: QueryInner): () -> (number, ...any)
local world_query_iter_next local world_query_iter_next
@ -1861,14 +1862,10 @@ local function world_query(world: World, ...)
world = world, world = world,
}, Query) }, Query)
local filter = 0
for _, id in ids do for _, id in ids do
filter = bloom_filter_add(filter, id)
local map = component_index[id] local map = component_index[id]
if not map then if not map then
continue return q
end end
if idr == nil or (map.size :: number) < (idr.size :: number) then if idr == nil or (map.size :: number) < (idr.size :: number) then
@ -1876,17 +1873,12 @@ local function world_query(world: World, ...)
end end
end end
q.bloom_filter = filter
if idr == nil then if idr == nil then
return q return q
end end
for archetype_id in idr.records do for archetype_id in idr.records do
local compatibleArchetype = archetypes[archetype_id] local compatibleArchetype = archetypes[archetype_id]
if not bloom_filter_check(compatibleArchetype.bloom_filter, filter) then
continue
end
if #compatibleArchetype.entities == 0 then if #compatibleArchetype.entities == 0 then
continue continue
end end
@ -1948,7 +1940,7 @@ local function world_each<a>(world: World, id: Id<a>): () -> Entity
end end
local function world_children<a>(world: World, parent: Id<a>) 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 world_new() local function world_new()
@ -1987,6 +1979,7 @@ local function world_new()
observable = observable, observable = observable,
} :: World } :: World
local ROOT_ARCHETYPE = archetype_create(world, {}, "") local ROOT_ARCHETYPE = archetype_create(world, {}, "")
world.ROOT_ARCHETYPE = ROOT_ARCHETYPE world.ROOT_ARCHETYPE = ROOT_ARCHETYPE
@ -2024,7 +2017,12 @@ local function world_new()
return r return r
end end
local function inner_world_add<T, a>(world: World, entity: Entity<T>, id: Id<a>): ()
local function inner_world_add<T, a>(
world: World,
entity: Entity<T>,
id: Id<a>
): ()
local entity_index = world.entity_index local entity_index = world.entity_index
local record = inner_entity_index_try_get(entity :: number) local record = inner_entity_index_try_get(entity :: number)
if not record then if not record then
@ -2052,8 +2050,9 @@ local function world_new()
end end
end end
local function inner_world_get(world: World, entity: Entity, a: Id, b: Id?, c: Id?, d: Id?, e: Id?): ...any local function inner_world_get(world: World, entity: Entity,
local record = inner_entity_index_try_get(entity :: number) a: Id, b: Id?, c: Id?, d: Id?, e: Id?): ...any
local record = inner_entity_index_try_get(entity::number)
if not record then if not record then
return nil return nil
end end
@ -2081,7 +2080,9 @@ local function world_new()
end end
end end
local function inner_world_has(world: World, entity: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?): boolean local function inner_world_has(world: World, entity: i53,
a: i53, b: i53?, c: i53?, d: i53?, e: i53?): boolean
local record = inner_entity_index_try_get(entity) local record = inner_entity_index_try_get(entity)
if not record then if not record then
return false return false
@ -2094,11 +2095,11 @@ local function world_new()
local columns_map = archetype.columns_map local columns_map = archetype.columns_map
return columns_map[a] ~= nil return columns_map[a] ~= nil and
and (b == nil or columns_map[b] ~= nil) (b == nil or columns_map[b] ~= nil) and
and (c == nil or columns_map[c] ~= nil) (c == nil or columns_map[c] ~= nil) and
and (d == nil or columns_map[d] ~= nil) (d == nil or columns_map[d] ~= nil) and
and (e == nil or error("args exceeded")) (e == nil or error("args exceeded"))
end end
local function inner_world_target<T, a>(world: World, entity: Entity<T>, relation: Id<a>, index: number?): Entity? local function inner_world_target<T, a>(world: World, entity: Entity<T>, relation: Id<a>, index: number?): Entity?
@ -2112,7 +2113,7 @@ local function world_new()
return nil return nil
end end
local r = ECS_PAIR(relation :: number, EcsWildcard) local r = ECS_PAIR(relation::number, EcsWildcard)
local idr = world.component_index[r] local idr = world.component_index[r]
if not idr then if not idr then
@ -2137,7 +2138,8 @@ local function world_new()
return nil return nil
end end
return entity_index_get_alive(world.entity_index, ECS_PAIR_SECOND(nth :: number)) return entity_index_get_alive(world.entity_index,
ECS_PAIR_SECOND(nth :: number))
end end
local function inner_world_parent<T>(world: World, entity: Entity<T>): Entity? local function inner_world_parent<T>(world: World, entity: Entity<T>): Entity?
@ -2239,7 +2241,7 @@ local function world_new()
return entity return entity
else else
for i = eindex_max_id + 1, index do for i = eindex_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
entity_index.max_id = index entity_index.max_id = index
@ -2291,10 +2293,10 @@ local function world_new()
end end
local function inner_world_clear<T>(world: World, entity: Entity<T>) local function inner_world_clear<T>(world: World, entity: Entity<T>)
local tgt = ECS_PAIR(EcsWildcard, entity :: number) local tgt = ECS_PAIR(EcsWildcard, entity::number)
local idr_t = component_index[tgt] local idr_t = component_index[tgt]
local idr = component_index[entity] local idr = component_index[entity]
local rel = ECS_PAIR(entity :: number, EcsWildcard) local rel = ECS_PAIR(entity::number, EcsWildcard)
local idr_r = component_index[rel] local idr_r = component_index[rel]
if idr then if idr then
@ -2325,10 +2327,11 @@ local function world_new()
local removal_queued = false local removal_queued = false
for _, id in idr_t_types do for _, id in idr_t_types do
if not ECS_IS_PAIR(id :: number) then if not ECS_IS_PAIR(id::number) then
continue continue
end end
local object = entity_index_get_alive(entity_index, ECS_PAIR_SECOND(id :: number)) local object = entity_index_get_alive(
entity_index, ECS_PAIR_SECOND(id::number))
if object ~= entity then if object ~= entity then
continue continue
end end
@ -2390,7 +2393,7 @@ local function world_new()
local function inner_world_delete<T>(world: World, entity: Entity<T>) local function inner_world_delete<T>(world: World, entity: Entity<T>)
local entity_index = world.entity_index local entity_index = world.entity_index
local record = inner_entity_index_try_get(entity :: number) local record = inner_entity_index_try_get(entity::number)
if not record then if not record then
return return
end end
@ -2406,11 +2409,11 @@ local function world_new()
local component_index = world.component_index local component_index = world.component_index
local archetypes = world.archetypes local archetypes = world.archetypes
local tgt = ECS_PAIR(EcsWildcard, entity :: number) local tgt = ECS_PAIR(EcsWildcard, entity::number)
local rel = ECS_PAIR(entity :: number, EcsWildcard) local rel = ECS_PAIR(entity::number, EcsWildcard)
local idr_t = component_index[tgt] local idr_t = component_index[tgt]
local idr = component_index[entity :: number] local idr = component_index[entity::number]
local idr_r = component_index[rel] local idr_r = component_index[rel]
if idr then if idr then
@ -2454,10 +2457,11 @@ local function world_new()
local removal_queued = false local removal_queued = false
for _, id in idr_t_types do for _, id in idr_t_types do
if not ECS_IS_PAIR(id :: number) then if not ECS_IS_PAIR(id::number) then
continue continue
end end
local object = entity_index_get_alive(entity_index, ECS_PAIR_SECOND(id :: number)) local object = entity_index_get_alive(
entity_index, ECS_PAIR_SECOND(id::number))
if object ~= entity then if object ~= entity then
continue continue
end end
@ -2696,7 +2700,7 @@ return {
meta = (ECS_META :: any) :: <T>(id: Entity, id: Id<T>, value: T) -> Entity<T>, meta = (ECS_META :: any) :: <T>(id: Entity, id: Id<T>, value: T) -> Entity<T>,
is_tag = (ecs_is_tag :: any) :: <T>(World, Id<T>) -> boolean, is_tag = (ecs_is_tag :: any) :: <T>(World, Id<T>) -> boolean,
OnAdd = (EcsOnAdd :: any) :: Entity<<T>(entity: Entity, id: Id<T>, data: T) -> ()>, OnAdd = (EcsOnAdd :: any) :: Entity<<T>(entity: Entity, id: Id<T>, data: T) -> ()>,
OnRemove = (EcsOnRemove :: any) :: Entity<(entity: Entity, id: Id) -> ()>, OnRemove = (EcsOnRemove :: any) :: Entity<(entity: Entity, id: Id) -> ()>,
OnChange = (EcsOnChange :: any) :: Entity<<T>(entity: Entity, id: Id<T>, data: T) -> ()>, OnChange = (EcsOnChange :: any) :: Entity<<T>(entity: Entity, id: Id<T>, data: T) -> ()>,
ChildOf = (EcsChildOf :: any) :: Entity, ChildOf = (EcsChildOf :: any) :: Entity,

File diff suppressed because it is too large Load diff

View file

@ -4,4 +4,3 @@ rojo = "rojo-rbx/rojo@7.4.4"
stylua = "johnnymorganz/stylua@2.0.1" stylua = "johnnymorganz/stylua@2.0.1"
Blink = "1Axen/Blink@0.14.1" Blink = "1Axen/Blink@0.14.1"
wally-package-types = "JohnnyMorganz/wally-package-types@1.4.2" wally-package-types = "JohnnyMorganz/wally-package-types@1.4.2"
StyLua = "JohnnyMorganz/StyLua@2.1.0"