deferred spawning support

This commit is contained in:
BlackMATov
2025-01-18 01:31:20 +07:00
parent 76afc420f4
commit 253d9e2246
4 changed files with 584 additions and 446 deletions

View File

@@ -81,8 +81,8 @@ execute :: query -> {execute_state? -> chunk?, entity[]?}, execute_state?
``` ```
``` ```
spawn :: fragment[]?, component[]? -> entity, boolean
spawn_at :: chunk?, fragment[]?, component[]? -> entity, boolean spawn_at :: chunk?, fragment[]?, component[]? -> entity, boolean
spawn_with :: fragment[]?, component[]? -> entity, boolean
``` ```
``` ```

View File

@@ -669,128 +669,6 @@ basics.describe_bench(string.format('create and destroy %d entities with 5 compo
print '----------------------------------------' print '----------------------------------------'
basics.describe_bench(string.format('create and destroy %d entities / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local destroy = evo.destroy
local fragments = {}
local components = {}
for i = 1, N do
entities[i] = spawn(fragments, components)
end
for i = 1, #entities do
destroy(entities[i])
end
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 1 components / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local destroy = evo.destroy
local fragments = { F1 }
local components = { true }
for i = 1, N do
entities[i] = spawn(fragments, components)
end
for i = 1, #entities do
destroy(entities[i])
end
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 2 components / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local destroy = evo.destroy
local fragments = { F1, F2 }
local components = { true, true }
for i = 1, N do
entities[i] = spawn(fragments, components)
end
for i = 1, #entities do
destroy(entities[i])
end
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 3 components / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local destroy = evo.destroy
local fragments = { F1, F2, F3 }
local components = { true, true, true }
for i = 1, N do
entities[i] = spawn(fragments, components)
end
for i = 1, #entities do
destroy(entities[i])
end
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 4 components / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local destroy = evo.destroy
local fragments = { F1, F2, F3, F4 }
local components = { true, true, true, true }
for i = 1, N do
entities[i] = spawn(fragments, components)
end
for i = 1, #entities do
destroy(entities[i])
end
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 5 components / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local destroy = evo.destroy
local fragments = { F1, F2, F3, F4, F5 }
local components = { true, true, true, true, true }
for i = 1, N do
entities[i] = spawn(fragments, components)
end
for i = 1, #entities do
destroy(entities[i])
end
end, function()
return {}
end)
print '----------------------------------------'
basics.describe_bench(string.format('create and destroy %d entities / spawn_at', N), basics.describe_bench(string.format('create and destroy %d entities / spawn_at', N),
---@param entities evolved.id[] ---@param entities evolved.id[]
function(entities) function(entities)
@@ -925,132 +803,124 @@ basics.describe_bench(string.format('create and destroy %d entities with 5 compo
print '----------------------------------------' print '----------------------------------------'
--- basics.describe_bench(string.format('create and destroy %d entities / spawn_with', N),
--- initial ---@param entities evolved.id[]
--- function(entities)
local spawn_with = evo.spawn_with
local destroy = evo.destroy
--[[ lua 5.1 local fragments = {}
| create and destroy 1k entities ... | local components = {}
PASS | us: 312.60 | op/s: 3199.00 | kb/i: 0.05
| create and destroy 1k entities with 1 component ... |
PASS | us: 1570.31 | op/s: 636.82 | kb/i: 0.63
| create and destroy 1k entities with 2 components ... |
PASS | us: 2780.82 | op/s: 359.61 | kb/i: 0.91
| create and destroy 1k entities with 3 components ... |
PASS | us: 4060.00 | op/s: 246.31 | kb/i: 1.67
]]
--[[ luajit 2.1 for i = 1, N do
| create and destroy 1k entities ... | entities[i] = spawn_with(fragments, components)
PASS | us: 12.22 | op/s: 81840.80 | kb/i: 0.00 end
| create and destroy 1k entities with 1 component ... |
PASS | us: 56.22 | op/s: 17786.07 | kb/i: 0.02
| create and destroy 1k entities with 2 components ... |
PASS | us: 412.73 | op/s: 2422.89 | kb/i: 0.11
| create and destroy 1k entities with 3 components ... |
PASS | us: 611.62 | op/s: 1635.00 | kb/i: 0.17
]]
--- for i = 1, #entities do
--- unpack ids without dedicated functions destroy(entities[i])
--- end
end, function()
return {}
end)
--[[ lua 5.1 basics.describe_bench(string.format('create and destroy %d entities with 1 components / spawn_with', N),
| create and destroy 1k entities ... | ---@param entities evolved.id[]
PASS | us: 255.40 | op/s: 3915.42 | kb/i: 0.04 function(entities)
| create and destroy 1k entities with 1 component ... | local spawn_with = evo.spawn_with
PASS | us: 1248.45 | op/s: 801.00 | kb/i: 0.50 local destroy = evo.destroy
| create and destroy 1k entities with 2 components ... |
PASS | us: 2208.79 | op/s: 452.74 | kb/i: 0.73
| create and destroy 1k entities with 3 components ... |
PASS | us: 3278.69 | op/s: 305.00 | kb/i: 1.37
]]
--[[ luajit 2.1 local fragments = { F1 }
| create and destroy 1k entities ... | local components = { true }
PASS | us: 12.12 | op/s: 82482.59 | kb/i: 0.00
| create and destroy 1k entities with 1 component ... |
PASS | us: 69.05 | op/s: 14482.59 | kb/i: 0.03
| create and destroy 1k entities with 2 components ... |
PASS | us: 400.40 | op/s: 2497.51 | kb/i: 0.09
| create and destroy 1k entities with 3 components ... |
PASS | us: 574.71 | op/s: 1740.00 | kb/i: 0.14
]]
--- for i = 1, N do
--- hook flags for chunks entities[i] = spawn_with(fragments, components)
--- end
--[[ lua 5.1 for i = 1, #entities do
| create and destroy 1k entities ... | destroy(entities[i])
PASS | us: 255.40 | op/s: 3915.42 | kb/i: 0.04 end
| create and destroy 1k entities with 1 component ... | end, function()
PASS | us: 1005.03 | op/s: 995.00 | kb/i: 0.41 return {}
| create and destroy 1k entities with 2 components ... | end)
PASS | us: 1747.83 | op/s: 572.14 | kb/i: 0.59
| create and destroy 1k entities with 3 components ... |
PASS | us: 2576.92 | op/s: 388.06 | kb/i: 1.08
]]
--[[ luajit 2.1 basics.describe_bench(string.format('create and destroy %d entities with 2 components / spawn_with', N),
| create and destroy 1k entities ... | ---@param entities evolved.id[]
PASS | us: 12.20 | op/s: 81940.30 | kb/i: 0.00 function(entities)
| create and destroy 1k entities with 1 component ... | local spawn_with = evo.spawn_with
PASS | us: 53.66 | op/s: 18636.82 | kb/i: 0.02 local destroy = evo.destroy
| create and destroy 1k entities with 2 components ... |
PASS | us: 357.02 | op/s: 2801.00 | kb/i: 0.09
| create and destroy 1k entities with 3 components ... |
PASS | us: 533.33 | op/s: 1875.00 | kb/i: 0.15
]]
--- local fragments = { F1, F2 }
--- construct flags for chunks local components = { true, true }
---
--[[ lua 5.1 for i = 1, N do
| create and destroy 1k entities ... | entities[i] = spawn_with(fragments, components)
PASS | us: 253.49 | op/s: 3945.00 | kb/i: 0.04 end
| create and destroy 1k entities with 1 component ... |
PASS | us: 913.64 | op/s: 1094.53 | kb/i: 0.37
| create and destroy 1k entities with 2 components ... |
PASS | us: 1562.50 | op/s: 640.00 | kb/i: 0.53
| create and destroy 1k entities with 3 components ... |
PASS | us: 2280.90 | op/s: 438.42 | kb/i: 0.97
]]
--[[ luajit 2.1 for i = 1, #entities do
| create and destroy 1k entities ... | destroy(entities[i])
PASS | us: 12.05 | op/s: 82995.02 | kb/i: 0.00 end
| create and destroy 1k entities with 1 component ... | end, function()
PASS | us: 53.61 | op/s: 18651.74 | kb/i: 0.02 return {}
| create and destroy 1k entities with 2 components ... | end)
PASS | us: 232.02 | op/s: 4310.00 | kb/i: 0.06
| create and destroy 1k entities with 3 components ... |
PASS | us: 329.49 | op/s: 3035.00 | kb/i: 0.10
]]
--- basics.describe_bench(string.format('create and destroy %d entities with 3 components / spawn_with', N),
--- after chunks refactoring ---@param entities evolved.id[]
--- function(entities)
local spawn_with = evo.spawn_with
local destroy = evo.destroy
--[[ lua 5.1 local fragments = { F1, F2, F3 }
| create and destroy 1k entities ... | local components = { true, true, true }
PASS | us: 254.45 | op/s: 3930.00 | kb/i: 0.04
| create and destroy 1k entities with 1 component ... |
PASS | us: 897.32 | op/s: 1114.43 | kb/i: 0.36
| create and destroy 1k entities with 2 components ... |
PASS | us: 1481.48 | op/s: 675.00 | kb/i: 0.49
| create and destroy 1k entities with 3 components ... |
PASS | us: 2126.32 | op/s: 470.30 | kb/i: 0.90
]]
--[[ luajit 2.1 for i = 1, N do
| create and destroy 1k entities ... | entities[i] = spawn_with(fragments, components)
PASS | us: 12.31 | op/s: 81248.76 | kb/i: 0.00 end
| create and destroy 1k entities with 1 component ... |
PASS | us: 46.97 | op/s: 21288.56 | kb/i: 0.02 for i = 1, #entities do
| create and destroy 1k entities with 2 components ... | destroy(entities[i])
PASS | us: 75.19 | op/s: 13300.00 | kb/i: 0.03 end
| create and destroy 1k entities with 3 components ... | end, function()
PASS | us: 108.28 | op/s: 9235.00 | kb/i: 0.06 return {}
]] end)
basics.describe_bench(string.format('create and destroy %d entities with 4 components / spawn_with', N),
---@param entities evolved.id[]
function(entities)
local spawn_with = evo.spawn_with
local destroy = evo.destroy
local fragments = { F1, F2, F3, F4 }
local components = { true, true, true, true }
for i = 1, N do
entities[i] = spawn_with(fragments, components)
end
for i = 1, #entities do
destroy(entities[i])
end
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 5 components / spawn_with', N),
---@param entities evolved.id[]
function(entities)
local spawn_with = evo.spawn_with
local destroy = evo.destroy
local fragments = { F1, F2, F3, F4, F5 }
local components = { true, true, true, true, true }
for i = 1, N do
entities[i] = spawn_with(fragments, components)
end
for i = 1, #entities do
destroy(entities[i])
end
end, function()
return {}
end)
print '----------------------------------------'

View File

@@ -3153,66 +3153,66 @@ do
evo.set(f3, evo.TAG) evo.set(f3, evo.TAG)
do do
local e = evo.spawn() local e = evo.spawn_with()
assert(evo.is_alive(e) and evo.is_empty(e)) assert(evo.is_alive(e) and evo.is_empty(e))
end end
do do
local e = evo.spawn({}) local e = evo.spawn_with({})
assert(evo.is_alive(e) and evo.is_empty(e)) assert(evo.is_alive(e) and evo.is_empty(e))
end end
do do
local e1 = evo.spawn({ f1 }) local e1 = evo.spawn_with({ f1 })
assert(evo.has(e1, f1) and evo.get(e1, f1) == true) assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
local e2 = evo.spawn({ f1 }, {}) local e2 = evo.spawn_with({ f1 }, {})
assert(evo.has(e2, f1) and evo.get(e2, f1) == true) assert(evo.has(e2, f1) and evo.get(e2, f1) == true)
local e3 = evo.spawn({ f1 }, { 41 }) local e3 = evo.spawn_with({ f1 }, { 41 })
assert(evo.has(e3, f1) and evo.get(e3, f1) == 41) assert(evo.has(e3, f1) and evo.get(e3, f1) == 41)
end end
do do
local e1 = evo.spawn({ f1, f2 }) local e1 = evo.spawn_with({ f1, f2 })
assert(evo.has_all(e1, f1, f2)) assert(evo.has_all(e1, f1, f2))
assert(evo.get(e1, f1) == true and evo.get(e1, f2) == true) assert(evo.get(e1, f1) == true and evo.get(e1, f2) == true)
local e2 = evo.spawn({ f1, f2 }, {}) local e2 = evo.spawn_with({ f1, f2 }, {})
assert(evo.has_all(e2, f1, f2)) assert(evo.has_all(e2, f1, f2))
assert(evo.get(e2, f1) == true and evo.get(e2, f2) == true) assert(evo.get(e2, f1) == true and evo.get(e2, f2) == true)
local e3 = evo.spawn({ f1, f2 }, { 41 }) local e3 = evo.spawn_with({ f1, f2 }, { 41 })
assert(evo.has_all(e3, f1, f2)) assert(evo.has_all(e3, f1, f2))
assert(evo.get(e3, f1) == 41 and evo.get(e3, f2) == true) assert(evo.get(e3, f1) == 41 and evo.get(e3, f2) == true)
local e4 = evo.spawn({ f1, f2 }, { nil, 42 }) local e4 = evo.spawn_with({ f1, f2 }, { nil, 42 })
assert(evo.has_all(e4, f1, f2)) assert(evo.has_all(e4, f1, f2))
assert(evo.get(e4, f1) == true and evo.get(e4, f2) == 42) assert(evo.get(e4, f1) == true and evo.get(e4, f2) == 42)
local e5 = evo.spawn({ f1, f2 }, { 41, 42 }) local e5 = evo.spawn_with({ f1, f2 }, { 41, 42 })
assert(evo.has_all(e5, f1, f2)) assert(evo.has_all(e5, f1, f2))
assert(evo.get(e5, f1) == 41 and evo.get(e5, f2) == 42) assert(evo.get(e5, f1) == 41 and evo.get(e5, f2) == 42)
local e6 = evo.spawn({ f1, f2 }, { 41, 42, 43 }) local e6 = evo.spawn_with({ f1, f2 }, { 41, 42, 43 })
assert(evo.has_all(e6, f1, f2)) assert(evo.has_all(e6, f1, f2))
assert(evo.get(e6, f1) == 41 and evo.get(e6, f2) == 42) assert(evo.get(e6, f1) == 41 and evo.get(e6, f2) == 42)
end end
do do
local e1 = evo.spawn({ f3 }) local e1 = evo.spawn_with({ f3 })
assert(evo.has(e1, f3)) assert(evo.has(e1, f3))
assert(evo.get(e1, f3) == nil) assert(evo.get(e1, f3) == nil)
local e2 = evo.spawn({ f2, f3 }) local e2 = evo.spawn_with({ f2, f3 })
assert(evo.has_all(e2, f2, f3)) assert(evo.has_all(e2, f2, f3))
assert(evo.get(e2, f2) == true and evo.get(e2, f3) == nil) assert(evo.get(e2, f2) == true and evo.get(e2, f3) == nil)
local e3 = evo.spawn({ f2, f3 }, { 42 }) local e3 = evo.spawn_with({ f2, f3 }, { 42 })
assert(evo.has_all(e3, f2, f3)) assert(evo.has_all(e3, f2, f3))
assert(evo.get(e3, f2) == 42 and evo.get(e3, f3) == nil) assert(evo.get(e3, f2) == 42 and evo.get(e3, f3) == nil)
local e4 = evo.spawn({ f2, f3 }, { 42, 43, 44 }) local e4 = evo.spawn_with({ f2, f3 }, { 42, 43, 44 })
assert(evo.has_all(e4, f2, f3)) assert(evo.has_all(e4, f2, f3))
assert(evo.get(e4, f2) == 42 and evo.get(e4, f3) == nil) assert(evo.get(e4, f2) == 42 and evo.get(e4, f3) == nil)
end end
@@ -3225,66 +3225,66 @@ do
evo.set(f3, evo.TAG) evo.set(f3, evo.TAG)
do do
local e = evo.spawn() local e = evo.spawn_with()
assert(evo.is_alive(e) and evo.is_empty(e)) assert(evo.is_alive(e) and evo.is_empty(e))
end end
do do
local e = evo.spawn({}) local e = evo.spawn_with({})
assert(evo.is_alive(e) and evo.is_empty(e)) assert(evo.is_alive(e) and evo.is_empty(e))
end end
do do
local e1 = evo.spawn({ f1 }) local e1 = evo.spawn_with({ f1 })
assert(evo.has(e1, f1) and evo.get(e1, f1) == true) assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
local e2 = evo.spawn({ f1 }, {}) local e2 = evo.spawn_with({ f1 }, {})
assert(evo.has(e2, f1) and evo.get(e2, f1) == true) assert(evo.has(e2, f1) and evo.get(e2, f1) == true)
local e3 = evo.spawn({ f1 }, { 41 }) local e3 = evo.spawn_with({ f1 }, { 41 })
assert(evo.has(e3, f1) and evo.get(e3, f1) == 41) assert(evo.has(e3, f1) and evo.get(e3, f1) == 41)
end end
do do
local e1 = evo.spawn({ f1, f2 }) local e1 = evo.spawn_with({ f1, f2 })
assert(evo.has_all(e1, f1, f2)) assert(evo.has_all(e1, f1, f2))
assert(evo.get(e1, f1) == true and evo.get(e1, f2) == 21) assert(evo.get(e1, f1) == true and evo.get(e1, f2) == 21)
local e2 = evo.spawn({ f1, f2 }, {}) local e2 = evo.spawn_with({ f1, f2 }, {})
assert(evo.has_all(e2, f1, f2)) assert(evo.has_all(e2, f1, f2))
assert(evo.get(e2, f1) == true and evo.get(e2, f2) == 21) assert(evo.get(e2, f1) == true and evo.get(e2, f2) == 21)
local e3 = evo.spawn({ f1, f2 }, { 41 }) local e3 = evo.spawn_with({ f1, f2 }, { 41 })
assert(evo.has_all(e3, f1, f2)) assert(evo.has_all(e3, f1, f2))
assert(evo.get(e3, f1) == 41 and evo.get(e3, f2) == 21) assert(evo.get(e3, f1) == 41 and evo.get(e3, f2) == 21)
local e4 = evo.spawn({ f1, f2 }, { nil, 42 }) local e4 = evo.spawn_with({ f1, f2 }, { nil, 42 })
assert(evo.has_all(e4, f1, f2)) assert(evo.has_all(e4, f1, f2))
assert(evo.get(e4, f1) == true and evo.get(e4, f2) == 42) assert(evo.get(e4, f1) == true and evo.get(e4, f2) == 42)
local e5 = evo.spawn({ f1, f2 }, { 41, 42 }) local e5 = evo.spawn_with({ f1, f2 }, { 41, 42 })
assert(evo.has_all(e5, f1, f2)) assert(evo.has_all(e5, f1, f2))
assert(evo.get(e5, f1) == 41 and evo.get(e5, f2) == 42) assert(evo.get(e5, f1) == 41 and evo.get(e5, f2) == 42)
local e6 = evo.spawn({ f1, f2 }, { 41, 42, 43 }) local e6 = evo.spawn_with({ f1, f2 }, { 41, 42, 43 })
assert(evo.has_all(e6, f1, f2)) assert(evo.has_all(e6, f1, f2))
assert(evo.get(e6, f1) == 41 and evo.get(e6, f2) == 42) assert(evo.get(e6, f1) == 41 and evo.get(e6, f2) == 42)
end end
do do
local e1 = evo.spawn({ f3 }) local e1 = evo.spawn_with({ f3 })
assert(evo.has(e1, f3)) assert(evo.has(e1, f3))
assert(evo.get(e1, f3) == nil) assert(evo.get(e1, f3) == nil)
local e2 = evo.spawn({ f2, f3 }) local e2 = evo.spawn_with({ f2, f3 })
assert(evo.has_all(e2, f2, f3)) assert(evo.has_all(e2, f2, f3))
assert(evo.get(e2, f2) == 21 and evo.get(e2, f3) == nil) assert(evo.get(e2, f2) == 21 and evo.get(e2, f3) == nil)
local e3 = evo.spawn({ f2, f3 }, { 42 }) local e3 = evo.spawn_with({ f2, f3 }, { 42 })
assert(evo.has_all(e3, f2, f3)) assert(evo.has_all(e3, f2, f3))
assert(evo.get(e3, f2) == 42 and evo.get(e3, f3) == nil) assert(evo.get(e3, f2) == 42 and evo.get(e3, f3) == nil)
local e4 = evo.spawn({ f2, f3 }, { 42, 43, 44 }) local e4 = evo.spawn_with({ f2, f3 }, { 42, 43, 44 })
assert(evo.has_all(e4, f2, f3)) assert(evo.has_all(e4, f2, f3))
assert(evo.get(e4, f2) == 42 and evo.get(e4, f3) == nil) assert(evo.get(e4, f2) == 42 and evo.get(e4, f3) == nil)
end end
@@ -3292,12 +3292,14 @@ end
do do
local cf = evo.id() local cf = evo.id()
local f1, f2 = evo.id(2) local f1, f2, f3 = evo.id(3)
evo.set(f1, cf) evo.set(f1, cf)
evo.set(f2, cf) evo.set(f2, cf)
evo.set(f3, cf)
evo.set(f2, evo.DEFAULT, 21) evo.set(f2, evo.DEFAULT, 21)
evo.set(f3, evo.TAG)
local set_count = 0 local set_count = 0
local insert_count = 0 local insert_count = 0
@@ -3311,14 +3313,14 @@ do
evo.batch_set(q, evo.ON_SET, function(e, f, c) evo.batch_set(q, evo.ON_SET, function(e, f, c)
last_set_entity = e last_set_entity = e
assert(f == f1 or f == f2) assert(f == f1 or f == f2 or f == f3)
last_set_component = c last_set_component = c
set_count = set_count + 1 set_count = set_count + 1
end) end)
evo.batch_set(q, evo.ON_INSERT, function(e, f, c) evo.batch_set(q, evo.ON_INSERT, function(e, f, c)
last_insert_entity = e last_insert_entity = e
assert(f == f1 or f == f2) assert(f == f1 or f == f2 or f == f3)
last_insert_component = c last_insert_component = c
insert_count = insert_count + 1 insert_count = insert_count + 1
end) end)
@@ -3331,7 +3333,7 @@ do
set_count, insert_count = 0, 0 set_count, insert_count = 0, 0
last_set_entity, last_set_component = 0, 0 last_set_entity, last_set_component = 0, 0
last_insert_entity, last_insert_component = 0, 0 last_insert_entity, last_insert_component = 0, 0
local e = evo.spawn({ f1 }) local e = evo.spawn_with({ f1 })
assert(set_count == 1 and insert_count == 1) assert(set_count == 1 and insert_count == 1)
assert(last_set_entity == e and last_set_component == true) assert(last_set_entity == e and last_set_component == true)
assert(last_insert_entity == e and last_insert_component == true) assert(last_insert_entity == e and last_insert_component == true)
@@ -3341,7 +3343,7 @@ do
set_count, insert_count = 0, 0 set_count, insert_count = 0, 0
last_set_entity, last_set_component = 0, 0 last_set_entity, last_set_component = 0, 0
last_insert_entity, last_insert_component = 0, 0 last_insert_entity, last_insert_component = 0, 0
local e = evo.spawn({ f2 }) local e = evo.spawn_with({ f2 })
assert(set_count == 1 and insert_count == 1) assert(set_count == 1 and insert_count == 1)
assert(last_set_entity == e and last_set_component == 21) assert(last_set_entity == e and last_set_component == 21)
assert(last_insert_entity == e and last_insert_component == 21) assert(last_insert_entity == e and last_insert_component == 21)
@@ -3351,11 +3353,31 @@ do
set_count, insert_count = 0, 0 set_count, insert_count = 0, 0
last_set_entity, last_set_component = 0, 0 last_set_entity, last_set_component = 0, 0
last_insert_entity, last_insert_component = 0, 0 last_insert_entity, last_insert_component = 0, 0
local e = evo.spawn({ f1, f2 }) local e = evo.spawn_with({ f1, f2 })
assert(set_count == 2 and insert_count == 2) assert(set_count == 2 and insert_count == 2)
assert(last_set_entity == e and last_set_component == 21) assert(last_set_entity == e and last_set_component == 21)
assert(last_insert_entity == e and last_insert_component == 21) assert(last_insert_entity == e and last_insert_component == 21)
end end
do
set_count, insert_count = 0, 0
last_set_entity, last_set_component = 0, 0
last_insert_entity, last_insert_component = 0, 0
local e = evo.spawn_with({ f3 }, { 33 })
assert(set_count == 1 and insert_count == 1)
assert(last_set_entity == e and last_set_component == nil)
assert(last_insert_entity == e and last_insert_component == nil)
end
do
set_count, insert_count = 0, 0
last_set_entity, last_set_component = 0, 0
last_insert_entity, last_insert_component = 0, 0
local e = evo.spawn_with({ f3, f2 }, { 33, 22 })
assert(set_count == 2 and insert_count == 2)
assert(last_set_entity == e and last_set_component == nil)
assert(last_insert_entity == e and last_insert_component == nil)
end
end end
do do
@@ -3469,12 +3491,14 @@ end
do do
local cf = evo.id() local cf = evo.id()
local f1, f2 = evo.id(2) local f1, f2, f3 = evo.id(3)
evo.set(f1, cf) evo.set(f1, cf)
evo.set(f2, cf) evo.set(f2, cf)
evo.set(f3, cf)
evo.set(f2, evo.DEFAULT, 22) evo.set(f2, evo.DEFAULT, 22)
evo.set(f3, evo.TAG)
local set_count = 0 local set_count = 0
local insert_count = 0 local insert_count = 0
@@ -3488,14 +3512,14 @@ do
evo.batch_set(q, evo.ON_SET, function(e, f, c) evo.batch_set(q, evo.ON_SET, function(e, f, c)
last_set_entity = e last_set_entity = e
assert(f == f1 or f == f2) assert(f == f1 or f == f2 or f == f3)
last_set_component = c last_set_component = c
set_count = set_count + 1 set_count = set_count + 1
end) end)
evo.batch_set(q, evo.ON_INSERT, function(e, f, c) evo.batch_set(q, evo.ON_INSERT, function(e, f, c)
last_insert_entity = e last_insert_entity = e
assert(f == f1 or f == f2) assert(f == f1 or f == f2 or f == f3)
last_insert_component = c last_insert_component = c
insert_count = insert_count + 1 insert_count = insert_count + 1
end) end)
@@ -3536,4 +3560,153 @@ do
assert(last_set_entity == e and last_set_component == 22) assert(last_set_entity == e and last_set_component == 22)
assert(last_insert_entity == e and last_insert_component == 22) assert(last_insert_entity == e and last_insert_component == 22)
end end
do
set_count, insert_count = 0, 0
last_set_entity, last_set_component = 0, 0
last_insert_entity, last_insert_component = 0, 0
local c = evo.chunk(f3)
local e = evo.spawn_at(c)
assert(set_count == 1 and insert_count == 1)
assert(last_set_entity == e and last_set_component == nil)
assert(last_insert_entity == e and last_insert_component == nil)
end
do
set_count, insert_count = 0, 0
last_set_entity, last_set_component = 0, 0
last_insert_entity, last_insert_component = 0, 0
local c = evo.chunk(f3, f2)
local e = evo.spawn_at(c, { f3, f2 }, { 33, 22 })
assert(set_count == 2 and insert_count == 2)
assert(last_set_entity == e and last_set_component == nil)
assert(last_insert_entity == e and last_insert_component == nil)
end
end
do
local f1, f2, f3, f4 = evo.id(4)
evo.set(f3, evo.DEFAULT, 3)
evo.set(f4, evo.TAG)
do
assert(evo.defer())
local e, d = evo.spawn_with()
assert(evo.is_alive(e) and evo.is_empty(e))
assert(not d)
assert(evo.commit())
assert(evo.is_alive(e) and evo.is_empty(e))
end
do
assert(evo.defer())
local e, d = evo.spawn_with({})
assert(evo.is_alive(e) and evo.is_empty(e))
assert(not d)
assert(evo.commit())
assert(evo.is_alive(e) and evo.is_empty(e))
end
do
assert(evo.defer())
local e1, d1 = evo.spawn_with({ f1 })
assert(evo.is_alive(e1) and evo.is_empty(e1))
assert(d1)
assert(evo.commit())
assert(evo.is_alive(e1) and not evo.is_empty(e1))
assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
assert(evo.defer())
local e2, d2 = evo.spawn_with({ f1 }, {})
assert(evo.is_alive(e2) and evo.is_empty(e2))
assert(d2)
assert(evo.commit())
assert(evo.is_alive(e2) and not evo.is_empty(e2))
assert(evo.has(e2, f1) and evo.get(e2, f1) == true)
assert(evo.defer())
local e3, d3 = evo.spawn_with({ f1 }, { 41 })
assert(evo.is_alive(e3) and evo.is_empty(e3))
assert(d3)
assert(evo.commit())
assert(evo.is_alive(e3) and not evo.is_empty(e3))
assert(evo.has(e3, f1) and evo.get(e3, f1) == 41)
end
do
assert(evo.defer())
local e1, d1 = evo.spawn_with({ f1, f2 })
assert(evo.is_alive(e1) and evo.is_empty(e1))
assert(d1)
assert(evo.commit())
assert(evo.is_alive(e1) and not evo.is_empty(e1))
assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
assert(evo.has(e1, f2) and evo.get(e1, f2) == true)
assert(evo.defer())
local e2, d2 = evo.spawn_with({ f1, f2 }, {})
assert(evo.is_alive(e2) and evo.is_empty(e2))
assert(d2)
assert(evo.commit())
assert(evo.is_alive(e2) and not evo.is_empty(e2))
assert(evo.has(e2, f1) and evo.get(e2, f1) == true)
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
assert(evo.defer())
local e3, d3 = evo.spawn_with({ f1, f2 }, { 41 })
assert(evo.is_alive(e3) and evo.is_empty(e3))
assert(d3)
assert(evo.commit())
assert(evo.is_alive(e3) and not evo.is_empty(e3))
assert(evo.has(e3, f1) and evo.get(e3, f1) == 41)
assert(evo.has(e3, f2) and evo.get(e3, f2) == true)
assert(evo.defer())
local e4, d4 = evo.spawn_with({ f1, f2 }, { nil, 42 })
assert(evo.is_alive(e4) and evo.is_empty(e4))
assert(d4)
assert(evo.commit())
assert(evo.is_alive(e4) and not evo.is_empty(e4))
assert(evo.has(e4, f1) and evo.get(e4, f1) == true)
assert(evo.has(e4, f2) and evo.get(e4, f2) == 42)
assert(evo.defer())
local e5, d5 = evo.spawn_with({ f1, f2 }, { 41, 42 })
assert(evo.is_alive(e5) and evo.is_empty(e5))
assert(d5)
assert(evo.commit())
assert(evo.is_alive(e5) and not evo.is_empty(e5))
assert(evo.has(e5, f1) and evo.get(e5, f1) == 41)
assert(evo.has(e5, f2) and evo.get(e5, f2) == 42)
assert(evo.defer())
local e6, d6 = evo.spawn_with({ f1, f2 }, { 41, 42, 43 })
assert(evo.is_alive(e6) and evo.is_empty(e6))
assert(d6)
assert(evo.commit())
assert(evo.is_alive(e6) and not evo.is_empty(e6))
assert(evo.has(e6, f1) and evo.get(e6, f1) == 41)
assert(evo.has(e6, f2) and evo.get(e6, f2) == 42)
end
do
assert(evo.defer())
local e1, d1 = evo.spawn_with({ f3, f4 })
assert(evo.is_alive(e1) and evo.is_empty(e1))
assert(d1)
assert(evo.commit())
assert(evo.is_alive(e1) and not evo.is_empty(e1))
assert(evo.has(e1, f3) and evo.get(e1, f3) == 3)
assert(evo.has(e1, f4) and evo.get(e1, f4) == nil)
assert(evo.defer())
local e2, d2 = evo.spawn_with({ f3, f4 }, { 33, 44 })
assert(evo.is_alive(e2) and evo.is_empty(e2))
assert(d2)
assert(evo.commit())
assert(evo.is_alive(e2) and not evo.is_empty(e2))
assert(evo.has(e2, f3) and evo.get(e2, f3) == 33)
assert(evo.has(e2, f4) and evo.get(e2, f4) == nil)
end
end end

View File

@@ -1387,6 +1387,165 @@ local function __detach_entity(entity)
__structural_changes = __structural_changes + 1 __structural_changes = __structural_changes + 1
end end
---@param entity evolved.entity
---@param chunk evolved.chunk
---@param fragments evolved.fragment[]
---@param components evolved.component[]
local function __spawn_entity_at(entity, chunk, fragments, components)
local chunk_entities = chunk.__entities
local chunk_fragment_list = chunk.__fragment_list
local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages
local place = #chunk_entities + 1
chunk_entities[place] = entity
for i = 1, #chunk_fragment_list do
local fragment = chunk_fragment_list[i]
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
if chunk.__has_defaults_or_constructs then
local new_component = evolved.get(fragment, evolved.DEFAULT)
if new_component == nil then
new_component = true
end
component_storage[place] = new_component
else
local new_component = true
component_storage[place] = new_component
end
end
end
for i = 1, #fragments do
local fragment = fragments[i]
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
if chunk.__has_defaults_or_constructs then
local new_component = components[i]
if new_component == nil then
new_component = evolved.get(fragment, evolved.DEFAULT)
end
if new_component == nil then
new_component = true
end
component_storage[place] = new_component
else
local new_component = components[i]
if new_component == nil then
new_component = true
end
component_storage[place] = new_component
end
end
end
if chunk.__has_set_or_insert_hooks then
for i = 1, #chunk_fragment_list do
local fragment = chunk_fragment_list[i]
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
local new_component = component_storage[place]
__fragment_call_set_and_insert_hooks(entity, fragment, new_component)
else
__fragment_call_set_and_insert_hooks(entity, fragment)
end
end
end
local entity_index = entity % 0x100000
__entity_chunks[entity_index] = chunk
__entity_places[entity_index] = place
__structural_changes = __structural_changes + 1
end
---@param entity evolved.entity
---@param chunk evolved.chunk
---@param fragments evolved.fragment[]
---@param components evolved.component[]
local function __spawn_entity_with(entity, chunk, fragments, components)
local chunk_entities = chunk.__entities
local chunk_fragment_list = chunk.__fragment_list
local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages
local place = #chunk_entities + 1
chunk_entities[place] = entity
for i = 1, #fragments do
local fragment = fragments[i]
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
if chunk.__has_defaults_or_constructs then
local new_component = components[i]
if new_component == nil then
new_component = evolved.get(fragment, evolved.DEFAULT)
end
if new_component == nil then
new_component = true
end
component_storage[place] = new_component
else
local new_component = components[i]
if new_component == nil then
new_component = true
end
component_storage[place] = new_component
end
end
end
if chunk.__has_set_or_insert_hooks then
for i = 1, #chunk_fragment_list do
local fragment = chunk_fragment_list[i]
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
local new_component = component_storage[place]
__fragment_call_set_and_insert_hooks(entity, fragment, new_component)
else
__fragment_call_set_and_insert_hooks(entity, fragment)
end
end
end
local entity_index = entity % 0x100000
__entity_chunks[entity_index] = chunk
__entity_places[entity_index] = place
__structural_changes = __structural_changes + 1
end
--- ---
--- ---
--- ---
@@ -1413,6 +1572,9 @@ local __defer_op = {
batch_remove = 14, batch_remove = 14,
batch_clear = 15, batch_clear = 15,
batch_destroy = 16, batch_destroy = 16,
spawn_entity_at = 17,
spawn_entity_with = 18,
} }
---@type table<evolved.defer_op, fun(bytes: any[], index: integer): integer> ---@type table<evolved.defer_op, fun(bytes: any[], index: integer): integer>
@@ -1525,6 +1687,26 @@ local __defer_ops = {
evolved.batch_destroy(query) evolved.batch_destroy(query)
return 1 return 1
end, end,
[__defer_op.spawn_entity_at] = function(bytes, index)
local entity = bytes[index + 0]
local chunk = bytes[index + 1]
local fragments = bytes[index + 2]
local components = bytes[index + 3]
__spawn_entity_at(entity, chunk, fragments, components)
__release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragments)
__release_table(__TABLE_POOL_TAG__COMPONENT_LIST, components)
return 4
end,
[__defer_op.spawn_entity_with] = function(bytes, index)
local entity = bytes[index + 0]
local chunk = bytes[index + 1]
local fragments = bytes[index + 2]
local components = bytes[index + 3]
__spawn_entity_with(entity, chunk, fragments, components)
__release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragments)
__release_table(__TABLE_POOL_TAG__COMPONENT_LIST, components)
return 4
end,
} }
---@return boolean started ---@return boolean started
@@ -1861,6 +2043,56 @@ local function __defer_batch_destroy(query)
__defer_length = length + 2 __defer_length = length + 2
end end
---@param entity evolved.entity
---@param chunk evolved.chunk
---@param fragments evolved.fragment[]
---@param components evolved.component[]
local function __defer_spawn_entity_at(entity, chunk, fragments, components)
local fragment_count = #fragments
local fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragment_count, 0)
__table_move(fragments, 1, fragment_count, 1, fragment_list)
local component_count = #components
local component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, component_count, 0)
__table_move(components, 1, component_count, 1, component_list)
local length = __defer_length
local bytecode = __defer_bytecode
bytecode[length + 1] = __defer_op.spawn_entity_at
bytecode[length + 2] = entity
bytecode[length + 3] = chunk
bytecode[length + 4] = fragment_list
bytecode[length + 5] = component_list
__defer_length = length + 5
end
---@param entity evolved.entity
---@param chunk evolved.chunk
---@param fragments evolved.fragment[]
---@param components evolved.component[]
local function __defer_spawn_entity_with(entity, chunk, fragments, components)
local fragment_count = #fragments
local fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragment_count, 0)
__table_move(fragments, 1, fragment_count, 1, fragment_list)
local component_count = #components
local component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, component_count, 0)
__table_move(components, 1, component_count, 1, component_list)
local length = __defer_length
local bytecode = __defer_bytecode
bytecode[length + 1] = __defer_op.spawn_entity_with
bytecode[length + 2] = entity
bytecode[length + 3] = chunk
bytecode[length + 4] = fragment_list
bytecode[length + 5] = component_list
__defer_length = length + 5
end
--- ---
--- ---
--- ---
@@ -3510,95 +3742,6 @@ end
--- ---
--- ---
---@param fragments? evolved.fragment[]
---@param components? evolved.component[]
---@return evolved.entity entity
---@return boolean is_deferred
function evolved.spawn(fragments, components)
if not fragments then
fragments = __EMPTY_FRAGMENT_LIST
end
if not components then
components = __EMPTY_COMPONENT_LIST
end
local entity = evolved.id()
local chunk = __chunk_fragment_list(fragments)
if not chunk then
return entity, false
end
if __defer_depth > 0 then
error("spawn cannot be deferred yet")
end
__defer()
do
local chunk_entities = chunk.__entities
local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages
local place = #chunk_entities + 1
chunk_entities[place] = entity
for i = 1, #fragments do
local fragment = fragments[i]
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
if chunk.__has_defaults_or_constructs then
local new_component = components[i]
if new_component == nil then
new_component = evolved.get(fragment, evolved.DEFAULT)
end
if new_component == nil then
new_component = true
end
component_storage[place] = new_component
if chunk.__has_set_or_insert_hooks then
__fragment_call_set_and_insert_hooks(entity, fragment, new_component)
end
else
local new_component = components[i]
if new_component == nil then
new_component = true
end
component_storage[place] = new_component
if chunk.__has_set_or_insert_hooks then
__fragment_call_set_and_insert_hooks(entity, fragment, new_component)
end
end
else
if chunk.__has_set_or_insert_hooks then
__fragment_call_set_and_insert_hooks(entity, fragment)
end
end
end
local entity_index = entity % 0x100000
__entity_chunks[entity_index] = chunk
__entity_places[entity_index] = place
__structural_changes = __structural_changes + 1
end
__defer_commit()
return entity, false
end
---@param chunk? evolved.chunk ---@param chunk? evolved.chunk
---@param fragments? evolved.fragment[] ---@param fragments? evolved.fragment[]
---@param components? evolved.component[] ---@param components? evolved.component[]
@@ -3620,96 +3763,48 @@ function evolved.spawn_at(chunk, fragments, components)
end end
if __defer_depth > 0 then if __defer_depth > 0 then
error("spawn cannot be deferred yet") __defer_spawn_entity_at(entity, chunk, fragments, components)
return entity, true
end end
__defer() __defer()
do do
local chunk_entities = chunk.__entities __spawn_entity_at(entity, chunk, fragments, components)
local chunk_fragment_list = chunk.__fragment_list end
local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages
local place = #chunk_entities + 1 __defer_commit()
chunk_entities[place] = entity return entity, false
end
for i = 1, #chunk_fragment_list do ---@param fragments? evolved.fragment[]
local fragment = chunk_fragment_list[i] ---@param components? evolved.component[]
local component_index = chunk_component_indices[fragment] ---@return evolved.entity entity
---@return boolean is_deferred
function evolved.spawn_with(fragments, components)
if not fragments then
fragments = __EMPTY_FRAGMENT_LIST
end
if component_index then if not components then
local component_storage = chunk_component_storages[component_index] components = __EMPTY_COMPONENT_LIST
end
if chunk.__has_defaults_or_constructs then local entity, chunk = evolved.id(), __chunk_fragment_list(fragments)
local new_component = evolved.get(fragment, evolved.DEFAULT)
if new_component == nil then if not chunk then
new_component = true return entity, false
end end
component_storage[place] = new_component if __defer_depth > 0 then
else __defer_spawn_entity_with(entity, chunk, fragments, components)
local new_component = true return entity, true
end
component_storage[place] = new_component __defer()
end
end
end
for i = 1, #fragments do do
local fragment = fragments[i] __spawn_entity_with(entity, chunk, fragments, components)
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
if chunk.__has_defaults_or_constructs then
local new_component = components[i]
if new_component == nil then
new_component = evolved.get(fragment, evolved.DEFAULT)
end
if new_component == nil then
new_component = true
end
component_storage[place] = new_component
else
local new_component = components[i]
if new_component == nil then
new_component = true
end
component_storage[place] = new_component
end
end
end
if chunk.__has_set_or_insert_hooks then
for i = 1, #chunk_fragment_list do
local fragment = chunk_fragment_list[i]
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
local new_component = component_storage[place]
__fragment_call_set_and_insert_hooks(entity, fragment, new_component)
else
__fragment_call_set_and_insert_hooks(entity, fragment)
end
end
end
local entity_index = entity % 0x100000
__entity_chunks[entity_index] = chunk
__entity_places[entity_index] = place
__structural_changes = __structural_changes + 1
end end
__defer_commit() __defer_commit()
@@ -3784,7 +3879,7 @@ function evolved_entity_builder:build()
return evolved.id() return evolved.id()
end end
local entity = evolved.spawn(fragment_list, component_list) local entity = evolved.spawn_with(fragment_list, component_list)
__release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragment_list) __release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragment_list)
__release_table(__TABLE_POOL_TAG__COMPONENT_LIST, component_list) __release_table(__TABLE_POOL_TAG__COMPONENT_LIST, component_list)
@@ -3876,7 +3971,7 @@ function evolved_fragment_builder:build()
return evolved.id() return evolved.id()
end end
local fragment = evolved.spawn(fragment_list, component_list) local fragment = evolved.spawn_with(fragment_list, component_list)
__release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragment_list) __release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragment_list)
__release_table(__TABLE_POOL_TAG__COMPONENT_LIST, component_list) __release_table(__TABLE_POOL_TAG__COMPONENT_LIST, component_list)
@@ -3990,7 +4085,7 @@ function evolved_query_builder:build()
return evolved.id() return evolved.id()
end end
local query = evolved.spawn(fragment_list, component_list) local query = evolved.spawn_with(fragment_list, component_list)
__release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragment_list) __release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragment_list)
__release_table(__TABLE_POOL_TAG__COMPONENT_LIST, component_list) __release_table(__TABLE_POOL_TAG__COMPONENT_LIST, component_list)