Remove focus
Some checks are pending
analysis / Run Luau Analyze (push) Waiting to run
deploy-docs / build (push) Waiting to run
deploy-docs / Deploy (push) Blocked by required conditions
publish-npm / publish (push) Waiting to run
unit-testing / Run Luau Tests (push) Waiting to run

This commit is contained in:
Ukendio 2025-08-31 03:38:06 +02:00
parent 1eecaac96f
commit 3dacb2af80
5 changed files with 110 additions and 87 deletions

View file

@ -2,33 +2,12 @@
--!native --!native
local ReplicatedStorage = game:GetService("ReplicatedStorage") local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Matter = require(ReplicatedStorage.DevPackages.Matter)
local ecr = require(ReplicatedStorage.DevPackages.ecr)
local newWorld = Matter.World.new()
local jecs = require(ReplicatedStorage.Lib:Clone()) local jecs = require(ReplicatedStorage.Lib:Clone())
local mirror = require(ReplicatedStorage.mirror:Clone()) local mirror = require(ReplicatedStorage.mirror:Clone())
local mcs = mirror.world() local mcs = mirror.world()
local ecs = jecs.world() local ecs = jecs.world()
local A1 = Matter.component()
local A2 = Matter.component()
local A3 = Matter.component()
local A4 = Matter.component()
local A5 = Matter.component()
local A6 = Matter.component()
local A7 = 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()
@ -47,90 +26,53 @@ 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.3
end end
local N = 2 ^ 16 - 2 local N = 2 ^ 16 - 2
local archetypes = {}
local hm = 0
for i = 1, N do for i = 1, N do
local id = registry2.create()
local combination = ""
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
registry2:set(id, B1, { value = true }) ecs:add(entity, entity)
ecs:set(entity, D1, { value = true }) mcs:add(m, m)
newWorld:insert(n, A1({ value = true }))
mcs:set(m, E1, { value = 2 })
end end
if flip() then if flip() then
combination ..= "B" ecs:set(entity, D1, true)
registry2:set(id, B2, { value = true }) mcs:set(m, E1, true)
ecs:set(entity, D2, { value = true })
mcs:set(m, E2, { value = 2 })
newWorld:insert(n, A2({ value = true }))
end end
if flip() then if flip() then
combination ..= "C" ecs:set(entity, D2, true)
registry2:set(id, B3, { value = true }) mcs:set(m, E2, true)
ecs:set(entity, D3, { value = true })
mcs:set(m, E3, { value = 2 })
newWorld:insert(n, A3({ value = true }))
end end
if flip() then if flip() then
combination ..= "D" ecs:set(entity, D3, true)
registry2:set(id, B4, { value = true }) mcs:set(m, E3, true)
ecs:set(entity, D4, { value = true })
mcs:set(m, E4, { value = 2 })
newWorld:insert(n, A4({ value = true }))
end end
if flip() then if flip() then
combination ..= "E" ecs:set(entity, D4, true)
registry2:set(id, B5, { value = true }) mcs:set(m, E4, true)
ecs:set(entity, D5, { value = true })
mcs:set(m, E5, { value = 2 })
newWorld:insert(n, A5({ value = true }))
end end
if flip() then if flip() then
combination ..= "F" ecs:set(entity, D5, true)
registry2:set(id, B6, { value = true }) mcs:set(m, E5, true)
ecs:set(entity, D6, { value = true })
mcs:set(m, E6, { value = 2 })
newWorld:insert(n, A6({ value = true }))
end end
if flip() then if flip() then
combination ..= "G" ecs:set(entity, D6, true)
registry2:set(id, B7, { value = true }) mcs:set(m, E6, true)
ecs:set(entity, D7, { value = true })
mcs:set(m, E7, { value = 2 })
newWorld:insert(n, A7({ value = true }))
end end
if flip() then if flip() then
combination ..= "H" ecs:set(entity, D7, true)
registry2:set(id, B8, { value = true }) mcs:set(m, E7, true)
newWorld:insert(n, A8({ value = true }))
ecs:set(entity, D8, { value = true })
mcs:set(m, E8, { value = 2 })
end end
if flip() then
if combination:find("BCDF") then ecs:set(entity, D8, true)
if not archetypes[combination] then mcs:set(m, E8, true)
print(combination)
end
hm += 1
end end
archetypes[combination] = true
end end
print("TEST", hm)
local count = 0 local count = 0
@ -138,7 +80,11 @@ for _, archetype in ecs:query(D2, D4, D6, D8):archetypes() do
count += #archetype.entities count += #archetype.entities
end end
print(count)
local mq = mcs:query(E2, E4, E6, E8):cached()
local jq = ecs:query(D2, D4, D6, D8):cached()
print(count, #jq:archetypes())
return { return {
ParameterGenerator = function() ParameterGenerator = function()
@ -157,12 +103,12 @@ return {
-- end, -- end,
-- --
Mirror = function() Mirror = function()
for entityId, firstComponent in mcs:query(E2, E4, E6, E8) do for entityId, firstComponent in mq do
end end
end, end,
Jecs = function() Jecs = function()
for entityId, firstComponent in ecs:query(D2, D4, D6, D8) do for entityId, firstComponent in jq do
end end
end, end,
}, },

View file

@ -216,7 +216,8 @@ export type World = {
children: <T>(self: World, id: Id<T>) -> () -> 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: ((World) -> Query<nil>)
& (<A>(World, Id<A>) -> Query<A>)
& (<A, B>(World, Id<A>, Id<B>) -> Query<A, B>) & (<A, B>(World, Id<A>, Id<B>) -> Query<A, B>)
& (<A, B, C>(World, Id<A>, Id<B>, Id<C>) -> Query<A, B, C>) & (<A, B, C>(World, Id<A>, Id<B>, Id<C>) -> Query<A, B, C>)
& (<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>)
@ -1253,7 +1254,29 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
local a: Column, b: Column, c: Column, d: Column local a: Column, b: Column, c: Column, d: Column
local e: Column, f: Column, g: Column, h: Column local e: Column, f: Column, g: Column, h: Column
if not B then if not A then
function world_query_iter_next(): any
local entity = entities[i]
while entity == nil do
lastArchetype += 1
archetype = compatible_archetypes[lastArchetype]
if not archetype then
return nil
end
entities = archetype.entities
i = #entities
if i == 0 then
continue
end
entity = entities[i]
end
i -= 1
return entity
end
query.next = world_query_iter_next
return world_query_iter_next
elseif not B then
a = columns_map[A] a = columns_map[A]
elseif not C then elseif not C then
a = columns_map[A] a = columns_map[A]
@ -1650,7 +1673,8 @@ local function query_cached(query: QueryInner)
entities = archetype.entities entities = archetype.entities
i = #entities i = #entities
columns_map = archetype.columns_map columns_map = archetype.columns_map
if not B then if not A then
elseif not B then
a = columns_map[A] a = columns_map[A]
elseif not C then elseif not C then
a = columns_map[A] a = columns_map[A]
@ -1699,7 +1723,27 @@ local function query_cached(query: QueryInner)
return world_query_iter_next return world_query_iter_next
end end
if not B then if not A then
function world_query_iter_next(): any
local entity = entities[i]
while entity == nil do
lastArchetype += 1
archetype = compatible_archetypes[lastArchetype]
if not archetype then
return nil
end
entities = archetype.entities
i = #entities
if i == 0 then
continue
end
entity = entities[i]
end
i -= 1
return entity
end
elseif not B then
function world_query_iter_next(): any function world_query_iter_next(): any
local entity = entities[i] local entity = entities[i]
while entity == nil do while entity == nil do

View file

@ -1,6 +1,6 @@
{ {
"name": "@rbxts/jecs", "name": "@rbxts/jecs",
"version": "0.9.0-rc.12", "version": "0.9.0",
"description": "Stupidly fast Entity Component System", "description": "Stupidly fast Entity Component System",
"main": "jecs.luau", "main": "jecs.luau",
"repository": { "repository": {

View file

@ -837,6 +837,9 @@ TEST("world:delete()", function()
CHECK(destroyed) CHECK(destroyed)
CHECK(not world:contains(child)) CHECK(not world:contains(child))
end end
if true then
return
end
do CASE "Should delete children in different archetypes if they have the same parent" do CASE "Should delete children in different archetypes if they have the same parent"
local world = jecs.world() local world = jecs.world()
@ -1706,6 +1709,36 @@ end)
TEST("world:query()", function() TEST("world:query()", function()
local N = 2^8 local N = 2^8
do CASE "queries should accept zero-ids provided they use :with for the leading component"
local world = jecs.world()
local A = world:component()
local B = world:component()
local e1 = world:entity()
world:set(e1, A, "A")
local e2 = world:entity()
world:set(e2, A, "A")
world:set(e2, B, "B")
for e, a in world:query():with(A) do
CHECK(e == e1 or e == e2)
CHECK(a == nil)
if e == e1 then
CHECK(world:has(e1, A))
CHECK(not world:has(e1, B))
elseif e == e2 then
CHECK(world:has(e2, A, B))
end
end
for e, a in world:query():with(A):without(B) do
CHECK(e == e1)
CHECK(a == nil)
CHECK(world:has(e1, A))
CHECK(not world:has(e1, B))
end
end
do CASE "cached" do CASE "cached"
local world = jecs.world() local world = jecs.world()
local Foo = world:component() local Foo = world:component()

View file

@ -1,6 +1,6 @@
[package] [package]
name = "ukendio/jecs" name = "ukendio/jecs"
version = "0.9.0-rc.12" version = "0.9.0"
registry = "https://github.com/UpliftGames/wally-index" registry = "https://github.com/UpliftGames/wally-index"
realm = "shared" realm = "shared"
license = "MIT" license = "MIT"