Add DEBUG mode with special assertions

This commit is contained in:
Ukendio 2025-12-28 11:07:51 +01:00
parent e4d0fb447d
commit ef4d880b0a
6 changed files with 853 additions and 654 deletions

View file

@ -1,4 +1,4 @@
[tools]
wally = "upliftgames/wally@0.3.2"
rojo = "rojo-rbx/rojo@7.4.4"
luau = "luau-lang/luau@0.701"
rojo = "rojo-rbx/rojo@7.7.0-rc.1"
luau = "luau-lang/luau@0.703.0"

File diff suppressed because it is too large Load diff

View file

@ -12,16 +12,16 @@
"ReplicatedStorage": {
"$className": "ReplicatedStorage",
"Lib": {
"$path": "../src/jecs.luau"
"$path": "../../src/jecs.luau"
},
"benches": {
"$path": "benches"
"$path": "visual"
},
"mirror": {
"$path": "mirror.luau"
"$path": "../../src/mirror.luau"
},
"DevPackages": {
"$path": "benches/visual/DevPackages"
"$path": "visual/DevPackages"
}
}
}

View file

@ -27,48 +27,11 @@ do
G: jecs.Id,
H: jecs.Id
)
BENCH("1 component", function()
for _ in world:query(A) do
end
end)
BENCH("2 component", function()
for _ in world:query(B, A) do
end
end)
BENCH("4 component", function()
for _ in world:query(D, C, B, A) do
end
end)
BENCH("8 component", function()
for _ in world:query(H, G, F, E, D, C, B, A) do
end
end)
local e = world:entity()
world:set(e, A, true)
world:set(e, B, true)
world:set(e, C, true)
world:set(e, D, true)
world:set(e, E, true)
world:set(e, F, true)
world:set(e, G, true)
world:set(e, H, true)
BENCH("Update Data", function()
for _ = 1, 100 do
world:set(e, A, false)
world:set(e, B, false)
world:set(e, C, false)
world:set(e, D, false)
world:set(e, E, false)
world:set(e, F, false)
world:set(e, G, false)
world:set(e, H, false)
end
end)
end
local D1 = ecs:component()
@ -86,8 +49,9 @@ do
local added = 0
local archetypes = {}
for i = 1, 2 ^ 16 - 2 do
for i = 1, 2 ^ 12 - 2 do
local entity = ecs:entity()
ecs:add(entity, entity)
local combination = ""
@ -153,48 +117,10 @@ do
G: jecs.Id,
H: jecs.Id
)
BENCH("1 component", function()
for _ in world:query(A) do
end
end)
BENCH("2 component", function()
for _ in world:query(B, A) do
end
end)
BENCH("4 component", function()
for _ in world:query(D, C, B, A) do
end
end)
BENCH("8 component", function()
for _ in world:query(H, G, F, E, D, C, B, A) do
end
end)
local e = world:entity()
world:set(e, A, true)
world:set(e, B, true)
world:set(e, C, true)
world:set(e, D, true)
world:set(e, E, true)
world:set(e, F, true)
world:set(e, G, true)
world:set(e, H, true)
BENCH("Update Data", function()
for _ = 1, 100 do
world:set(e, A, false)
world:set(e, B, false)
world:set(e, C, false)
world:set(e, D, false)
world:set(e, E, false)
world:set(e, F, false)
world:set(e, G, false)
world:set(e, H, false)
end
end)
end
local D1 = ecs:component()
@ -207,13 +133,14 @@ do
local D8 = ecs:component()
local function flip()
return math.random() >= 0.15
return math.random() >= 0.5
end
local added = 0
local archetypes = {}
for i = 1, 2 ^ 16 - 2 do
for i = 1, 2 ^ 12 - 2 do
local entity = ecs:entity()
ecs:add(entity, entity)
local combination = ""
@ -246,11 +173,9 @@ do
ecs:set(entity, D8, { value = true })
end
if #combination == 7 then
added += 1
if flip() then
ecs:set(entity, D1, { value = true })
end
archetypes[combination] = true
end
local a = 0

View file

@ -50,85 +50,54 @@ local E8 = mcs:component()
local registry2 = ecr.registry()
local function flip()
return math.random() >= 0.25
return math.random() >= 0.5
end
local N = 2 ^ 16 - 2
local N = 2 ^ 12- 2
local archetypes = {}
local hm = 0
for i = 1, N do
local id = registry2.create()
local combination = ""
local n = newWorld:spawn()
local entity = ecs:entity()
local m = mcs:entity()
if flip() then
ecs:add(entity, entity)
mcs:add(m, m)
end
if flip() then
registry2:set(id, B1, { value = true })
ecs:set(entity, D1, { value = true })
newWorld:insert(n, A1({ value = true }))
mcs:set(m, E1, { value = 2 })
ecs:set(entity, D1, {value = true})
end
if flip() then
combination ..= "B"
registry2:set(id, B2, { value = true })
ecs:set(entity, D2, { value = true })
mcs:set(m, E2, { value = 2 })
newWorld:insert(n, A2({ value = true }))
end
if flip() then
combination ..= "C"
registry2:set(id, B3, { value = true })
ecs:set(entity, D3, { value = true })
mcs:set(m, E3, { value = 2 })
newWorld:insert(n, A3({ value = true }))
end
if flip() then
combination ..= "D"
registry2:set(id, B4, { value = true })
ecs:set(entity, D4, { value = true })
mcs:set(m, E4, { value = 2 })
newWorld:insert(n, A4({ value = true }))
end
if flip() then
combination ..= "E"
registry2:set(id, B5, { value = true })
ecs:set(entity, D5, { value = true })
mcs:set(m, E5, { value = 2 })
newWorld:insert(n, A5({ value = true }))
end
if flip() then
combination ..= "F"
registry2:set(id, B6, { value = true })
ecs:set(entity, D6, { value = true })
mcs:set(m, E6, { value = 2 })
newWorld:insert(n, A6({ value = true }))
end
if flip() then
combination ..= "G"
registry2:set(id, B7, { value = true })
ecs:set(entity, D7, { value = true })
mcs:set(m, E7, { value = 2 })
newWorld:insert(n, A7({ value = true }))
end
if flip() then
combination ..= "H"
registry2:set(id, B8, { value = true })
newWorld:insert(n, A8({ value = true }))
ecs:set(entity, D8, { value = true })
mcs:set(m, E8, { value = 2 })
end
if combination:find("BCDF") then
if not archetypes[combination] then
print(combination)
end
hm += 1
end
archetypes[combination] = true
end
print("TEST", hm)
@ -140,30 +109,38 @@ end
print(count)
local mq = mcs:query(E1, E2, E3, E4)
local jq = ecs:query(D1, D2, D3, D4)
return {
ParameterGenerator = function()
return
end,
Functions = {
Matter = function()
for entityId, firstComponent in newWorld:query(A2, A4, A6, A8) do
end
end,
ECR = function()
for entityId, firstComponent in registry2:view(B2, B4, B6, B8) do
end
end,
-- Mirror = function()
-- for entityId, firstComponent in mcs:query(E2, E4, E6, E8) do
-- Matter = function()
-- for entityId, firstComponent in newWorld:query(A2, A4, A6, A8) do
-- end
-- end,
Jecs = function()
for entityId, firstComponent in ecs:query(D2, D4, D6, D8) do
-- ECR = function()
-- for entityId, firstComponent in registry2:view(B2, B4, B6, B8) do
-- end
-- end,
Mirror = function()
for i = 1, 10 do
for entityId, firstComponent in mq:iter() do
end
end
end,
Jecs = function()
for i = 1, 10 do
for entityId, firstComponent in jq:iter() do
end
end
end,
},
}

View file

@ -24,81 +24,7 @@ type Id<T=unknown> = jecs.Id<T>
local entity_visualiser = require("@modules/entity_visualiser")
local dwi = entity_visualiser.stringify
TEST("optimize idr_r removal", function()
local pair = jecs.pair
local world = jecs.world()
local rel = world:component()
local A = world:component()
local B = world:component()
local t1 = world:entity()
local t2 = world:entity()
local entities = {} :: { jecs.Entity }
for i = 1, 10 do
local e1 = world:entity()
local e2 = world:entity()
world:set(e1, A, true)
world:set(e2, A, true)
world:add(e1, pair(B, t1))
world:add(e1, pair(B, t2))
world:add(e2, pair(B, t1))
world:add(e2, pair(B, t2))
table.insert(entities, e1)
table.insert(entities, e2)
end
local e1 = world:entity()
local e2 = world:entity()
table.insert(entities, e1)
table.insert(entities, e2)
world:set(e1, A, true)
world:set(e2, A, true)
world:add(e1, pair(B, t1))
world:add(e1, pair(B, t2))
world:add(e2, pair(B, t1))
world:add(e2, pair(B, t2))
BENCH("delete B", function()
world:delete(B)
end)
for _, e in entities do
CHECK(world:has(e, A))
CHECK(not world:target(e, B))
CHECK(not world:target(e, B))
end
end)
TEST("deleting t1's archetype before invoking its onremove hooks", function()
local pair = jecs.pair
local world = jecs.world()
local rel = world:component()
local t1 = world:entity()
local t2 = world:entity()
--[[
weirdly enough if i do this (only when adding childof relation after adding (rel, t2) to t1) it does not error. Probably a red herring
world:add(t2, pair(rel, t1))
world:add(t1, pair(rel, t2))
world:add(t2, pair(jecs.ChildOf, t1))
--]]
-- this causes world:delete to error
world:add(t2, pair(jecs.ChildOf, t1))
world:add(t1, pair(rel, t2))
world:delete(t1)
end)
FOCUS()
TEST("reproduce idr_t nil archetype bug", function()
local world = jecs.world()
@ -124,43 +50,56 @@ TEST("reproduce idr_t nil archetype bug", function()
local dst = src and jecs.archetype_traverse_remove(world, id, src)
end)
local batches = 10
local batchSize = 20
local batchSize = 200
local trackedEntities: { [number]: { parentId: number? } } = {}
for batch = 1, batches do
for i = 1, batchSize do
local root = world:entity()
world:add(root, jecs.pair(jecs.ChildOf, char))
for i = 1, batchSize do
-- Removing animator from trackEntity1 causes it to stop happening
local trackEntity1 = world:entity()
world:set(trackEntity1, cts.Animator, 0)
world:add(trackEntity1, jecs.pair(jecs.ChildOf, root))
trackedEntities[trackEntity1] = { parentId = root }
local root = world:entity()
-- world:add(root, jecs.pair(jecs.ChildOf, char))
-- Removing animator from trackEntity2 causes it to happen less frequently
local trackEntity2 = world:entity()
world:set(trackEntity2, cts.Animator, 0)
world:add(trackEntity2, jecs.pair(jecs.ChildOf, root))
trackedEntities[trackEntity2] = { parentId = root }
-- Removing animator from trackEntity1 causes it to stop happening
local trackEntity1 = world:entity()
world:set(trackEntity1, cts.Animator, 0)
world:add(trackEntity1, jecs.pair(jecs.ChildOf, root))
world:set(trackEntity1, jecs.Name, "trackEntity1v"..i)
trackedEntities[trackEntity1] = { parentId = root }
-- Removing this, but keeping Animator on the other 2 causes it to stop happening
world:set(trackEntity1, cts.VelocitizeAnimationWeight, 0)
-- Removing animator from trackEntity2 causes it to happen less frequently
local trackEntity2 = world:entity()
world:set(trackEntity2, cts.Animator, 0)
world:add(trackEntity2, jecs.pair(jecs.ChildOf, root))
world:set(trackEntity2, jecs.Name, "trackEntity2v"..i)
trackedEntities[trackEntity2] = { parentId = root }
for entityId, info in trackedEntities do
if world:contains(entityId) and not world:parent(entityId :: any) then
print(`bugged entity found: {entityId}`)
print(`original parent: {info.parentId}`)
print(`batch = {batch}, i = {i}`)
print("==========================================")
trackedEntities[entityId] = nil
world:delete(entityId)
end
end
end
end
-- Removing this, but keeping Animator on the other 2 causes it to stop happening
world:set(trackEntity1, cts.VelocitizeAnimationWeight, 0)
local q = world:query(jecs.pair(jecs.ChildOf, jecs.w)):cached()
print("---- delete start root")
print("--- root", world:contains(root), root, jecs.ECS_ID(root), jecs.ECS_GENERATION(root))
world:delete(root)
print("---- delete end root")
for entity in q do
local parent = world:parent(entity) :: jecs.Entity
print("--- root", world:contains(root), jecs.ECS_ID(root), jecs.ECS_GENERATION(root))
print(world:get(entity, jecs.Name), jecs.ECS_ID(parent), jecs.ECS_GENERATION(parent), "root ->", root)
CHECK(world:parent(entity) == nil)
end
for entityId, info in trackedEntities do
if world:contains(entityId) and not world:parent(entityId :: any) then
print(`bugged entity found: {entityId}`)
print(`original parent: {info.parentId}`)
print(`batch = {batch}, i = {i}`)
print("==========================================")
trackedEntities[entityId] = nil
end
end
end
end)
TEST("Ensure archetype edges get cleaned", function()