mirror of
https://github.com/Ukendio/jecs.git
synced 2026-02-04 15:15:21 +00:00
Add DEBUG mode with special assertions
This commit is contained in:
parent
e4d0fb447d
commit
ef4d880b0a
6 changed files with 853 additions and 654 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
[tools]
|
[tools]
|
||||||
wally = "upliftgames/wally@0.3.2"
|
wally = "upliftgames/wally@0.3.2"
|
||||||
rojo = "rojo-rbx/rojo@7.4.4"
|
rojo = "rojo-rbx/rojo@7.7.0-rc.1"
|
||||||
luau = "luau-lang/luau@0.701"
|
luau = "luau-lang/luau@0.703.0"
|
||||||
|
|
|
||||||
1174
src/jecs.luau
1174
src/jecs.luau
File diff suppressed because it is too large
Load diff
|
|
@ -12,16 +12,16 @@
|
||||||
"ReplicatedStorage": {
|
"ReplicatedStorage": {
|
||||||
"$className": "ReplicatedStorage",
|
"$className": "ReplicatedStorage",
|
||||||
"Lib": {
|
"Lib": {
|
||||||
"$path": "../src/jecs.luau"
|
"$path": "../../src/jecs.luau"
|
||||||
},
|
},
|
||||||
"benches": {
|
"benches": {
|
||||||
"$path": "benches"
|
"$path": "visual"
|
||||||
},
|
},
|
||||||
"mirror": {
|
"mirror": {
|
||||||
"$path": "mirror.luau"
|
"$path": "../../src/mirror.luau"
|
||||||
},
|
},
|
||||||
"DevPackages": {
|
"DevPackages": {
|
||||||
"$path": "benches/visual/DevPackages"
|
"$path": "visual/DevPackages"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,48 +27,11 @@ do
|
||||||
G: jecs.Id,
|
G: jecs.Id,
|
||||||
H: 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()
|
BENCH("4 component", function()
|
||||||
for _ in world:query(D, C, B, A) do
|
for _ in world:query(D, C, B, A) do
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
local D1 = ecs:component()
|
local D1 = ecs:component()
|
||||||
|
|
@ -86,8 +49,9 @@ do
|
||||||
|
|
||||||
local added = 0
|
local added = 0
|
||||||
local archetypes = {}
|
local archetypes = {}
|
||||||
for i = 1, 2 ^ 16 - 2 do
|
for i = 1, 2 ^ 12 - 2 do
|
||||||
local entity = ecs:entity()
|
local entity = ecs:entity()
|
||||||
|
ecs:add(entity, entity)
|
||||||
|
|
||||||
local combination = ""
|
local combination = ""
|
||||||
|
|
||||||
|
|
@ -153,48 +117,10 @@ do
|
||||||
G: jecs.Id,
|
G: jecs.Id,
|
||||||
H: 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()
|
BENCH("4 component", function()
|
||||||
for _ in world:query(D, C, B, A) do
|
for _ in world:query(D, C, B, A) do
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
local D1 = ecs:component()
|
local D1 = ecs:component()
|
||||||
|
|
@ -207,13 +133,14 @@ do
|
||||||
local D8 = ecs:component()
|
local D8 = ecs:component()
|
||||||
|
|
||||||
local function flip()
|
local function flip()
|
||||||
return math.random() >= 0.15
|
return math.random() >= 0.5
|
||||||
end
|
end
|
||||||
|
|
||||||
local added = 0
|
local added = 0
|
||||||
local archetypes = {}
|
local archetypes = {}
|
||||||
for i = 1, 2 ^ 16 - 2 do
|
for i = 1, 2 ^ 12 - 2 do
|
||||||
local entity = ecs:entity()
|
local entity = ecs:entity()
|
||||||
|
ecs:add(entity, entity)
|
||||||
|
|
||||||
local combination = ""
|
local combination = ""
|
||||||
|
|
||||||
|
|
@ -246,11 +173,9 @@ do
|
||||||
ecs:set(entity, D8, { value = true })
|
ecs:set(entity, D8, { value = true })
|
||||||
end
|
end
|
||||||
|
|
||||||
if #combination == 7 then
|
if flip() then
|
||||||
added += 1
|
|
||||||
ecs:set(entity, D1, { value = true })
|
ecs:set(entity, D1, { value = true })
|
||||||
end
|
end
|
||||||
archetypes[combination] = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local a = 0
|
local a = 0
|
||||||
|
|
|
||||||
|
|
@ -50,85 +50,54 @@ local E8 = mcs:component()
|
||||||
local registry2 = ecr.registry()
|
local registry2 = ecr.registry()
|
||||||
|
|
||||||
local function flip()
|
local function flip()
|
||||||
return math.random() >= 0.25
|
return math.random() >= 0.5
|
||||||
end
|
end
|
||||||
|
|
||||||
local N = 2 ^ 16 - 2
|
local N = 2 ^ 12- 2
|
||||||
local archetypes = {}
|
local archetypes = {}
|
||||||
|
|
||||||
local hm = 0
|
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
|
||||||
|
ecs:add(entity, entity)
|
||||||
|
mcs:add(m, m)
|
||||||
|
end
|
||||||
|
|
||||||
if flip() then
|
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 })
|
mcs:set(m, E1, { value = 2 })
|
||||||
|
ecs:set(entity, D1, {value = true})
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
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 }))
|
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
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 }))
|
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
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 })
|
||||||
|
|
||||||
newWorld:insert(n, A4({ value = true }))
|
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
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 })
|
||||||
|
|
||||||
newWorld:insert(n, A5({ value = true }))
|
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
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 }))
|
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
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 }))
|
|
||||||
end
|
end
|
||||||
if flip() then
|
if flip() then
|
||||||
combination ..= "H"
|
|
||||||
registry2:set(id, B8, { 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 })
|
||||||
end
|
end
|
||||||
|
|
||||||
if combination:find("BCDF") then
|
|
||||||
if not archetypes[combination] then
|
|
||||||
print(combination)
|
|
||||||
end
|
|
||||||
hm += 1
|
|
||||||
end
|
|
||||||
archetypes[combination] = true
|
|
||||||
end
|
end
|
||||||
print("TEST", hm)
|
print("TEST", hm)
|
||||||
|
|
||||||
|
|
@ -140,30 +109,38 @@ end
|
||||||
|
|
||||||
print(count)
|
print(count)
|
||||||
|
|
||||||
|
local mq = mcs:query(E1, E2, E3, E4)
|
||||||
|
local jq = ecs:query(D1, D2, D3, D4)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ParameterGenerator = function()
|
ParameterGenerator = function()
|
||||||
return
|
return
|
||||||
end,
|
end,
|
||||||
|
|
||||||
Functions = {
|
Functions = {
|
||||||
Matter = function()
|
-- Matter = function()
|
||||||
for entityId, firstComponent in newWorld:query(A2, A4, A6, A8) do
|
-- 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
|
|
||||||
-- end
|
-- end
|
||||||
-- end,
|
-- end,
|
||||||
|
|
||||||
Jecs = function()
|
-- ECR = function()
|
||||||
for entityId, firstComponent in ecs:query(D2, D4, D6, D8) do
|
-- 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
|
||||||
|
end,
|
||||||
|
|
||||||
|
Jecs = function()
|
||||||
|
for i = 1, 10 do
|
||||||
|
for entityId, firstComponent in jq:iter() do
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
101
test/tests.luau
101
test/tests.luau
|
|
@ -24,81 +24,7 @@ type Id<T=unknown> = jecs.Id<T>
|
||||||
local entity_visualiser = require("@modules/entity_visualiser")
|
local entity_visualiser = require("@modules/entity_visualiser")
|
||||||
local dwi = entity_visualiser.stringify
|
local dwi = entity_visualiser.stringify
|
||||||
|
|
||||||
TEST("optimize idr_r removal", function()
|
FOCUS()
|
||||||
|
|
||||||
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)
|
|
||||||
TEST("reproduce idr_t nil archetype bug", function()
|
TEST("reproduce idr_t nil archetype bug", function()
|
||||||
local world = jecs.world()
|
local world = jecs.world()
|
||||||
|
|
||||||
|
|
@ -124,31 +50,46 @@ TEST("reproduce idr_t nil archetype bug", function()
|
||||||
local dst = src and jecs.archetype_traverse_remove(world, id, src)
|
local dst = src and jecs.archetype_traverse_remove(world, id, src)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local batches = 10
|
local batchSize = 200
|
||||||
local batchSize = 20
|
|
||||||
|
|
||||||
local trackedEntities: { [number]: { parentId: number? } } = {}
|
local trackedEntities: { [number]: { parentId: number? } } = {}
|
||||||
|
|
||||||
for batch = 1, batches do
|
|
||||||
for i = 1, batchSize do
|
for i = 1, batchSize do
|
||||||
|
|
||||||
local root = world:entity()
|
local root = world:entity()
|
||||||
world:add(root, jecs.pair(jecs.ChildOf, char))
|
-- world:add(root, jecs.pair(jecs.ChildOf, char))
|
||||||
|
|
||||||
-- Removing animator from trackEntity1 causes it to stop happening
|
-- Removing animator from trackEntity1 causes it to stop happening
|
||||||
local trackEntity1 = world:entity()
|
local trackEntity1 = world:entity()
|
||||||
world:set(trackEntity1, cts.Animator, 0)
|
world:set(trackEntity1, cts.Animator, 0)
|
||||||
world:add(trackEntity1, jecs.pair(jecs.ChildOf, root))
|
world:add(trackEntity1, jecs.pair(jecs.ChildOf, root))
|
||||||
|
world:set(trackEntity1, jecs.Name, "trackEntity1v"..i)
|
||||||
trackedEntities[trackEntity1] = { parentId = root }
|
trackedEntities[trackEntity1] = { parentId = root }
|
||||||
|
|
||||||
-- Removing animator from trackEntity2 causes it to happen less frequently
|
-- Removing animator from trackEntity2 causes it to happen less frequently
|
||||||
local trackEntity2 = world:entity()
|
local trackEntity2 = world:entity()
|
||||||
world:set(trackEntity2, cts.Animator, 0)
|
world:set(trackEntity2, cts.Animator, 0)
|
||||||
world:add(trackEntity2, jecs.pair(jecs.ChildOf, root))
|
world:add(trackEntity2, jecs.pair(jecs.ChildOf, root))
|
||||||
|
world:set(trackEntity2, jecs.Name, "trackEntity2v"..i)
|
||||||
trackedEntities[trackEntity2] = { parentId = root }
|
trackedEntities[trackEntity2] = { parentId = root }
|
||||||
|
|
||||||
-- Removing this, but keeping Animator on the other 2 causes it to stop happening
|
-- Removing this, but keeping Animator on the other 2 causes it to stop happening
|
||||||
world:set(trackEntity1, cts.VelocitizeAnimationWeight, 0)
|
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
|
for entityId, info in trackedEntities do
|
||||||
if world:contains(entityId) and not world:parent(entityId :: any) then
|
if world:contains(entityId) and not world:parent(entityId :: any) then
|
||||||
print(`bugged entity found: {entityId}`)
|
print(`bugged entity found: {entityId}`)
|
||||||
|
|
@ -156,8 +97,6 @@ TEST("reproduce idr_t nil archetype bug", function()
|
||||||
print(`batch = {batch}, i = {i}`)
|
print(`batch = {batch}, i = {i}`)
|
||||||
print("==========================================")
|
print("==========================================")
|
||||||
trackedEntities[entityId] = nil
|
trackedEntities[entityId] = nil
|
||||||
world:delete(entityId)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue