evolved.spawn/spawn_at impl (without deferring support yet)

This commit is contained in:
BlackMATov
2025-01-16 06:41:35 +07:00
parent 1620738b51
commit 76afc420f4
4 changed files with 960 additions and 37 deletions

View File

@@ -80,6 +80,11 @@ each :: entity -> {each_state? -> fragment?, component?}, each_state?
execute :: query -> {execute_state? -> chunk?, entity[]?}, execute_state? execute :: query -> {execute_state? -> chunk?, entity[]?}, execute_state?
``` ```
```
spawn :: fragment[]?, component[]? -> entity, boolean
spawn_at :: chunk?, fragment[]?, component[]? -> entity, boolean
```
``` ```
entity :: entity_builder entity :: entity_builder
entity_builder:set :: fragment, any... -> entity_builder entity_builder:set :: fragment, any... -> entity_builder

View File

@@ -669,6 +669,262 @@ 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),
---@param entities evolved.id[]
function(entities)
local spawn_at = evo.spawn_at
local destroy = evo.destroy
local fragments = {}
local components = {}
local chunk = evo.chunk()
for i = 1, N do
entities[i] = spawn_at(chunk, 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_at', N),
---@param entities evolved.id[]
function(entities)
local spawn_at = evo.spawn_at
local destroy = evo.destroy
local fragments = { F1 }
local components = { true }
local chunk = evo.chunk(F1)
for i = 1, N do
entities[i] = spawn_at(chunk, 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_at', N),
---@param entities evolved.id[]
function(entities)
local spawn_at = evo.spawn_at
local destroy = evo.destroy
local fragments = { F1, F2 }
local components = { true, true }
local chunk = evo.chunk(F1, F2)
for i = 1, N do
entities[i] = spawn_at(chunk, 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_at', N),
---@param entities evolved.id[]
function(entities)
local spawn_at = evo.spawn_at
local destroy = evo.destroy
local fragments = { F1, F2, F3 }
local components = { true, true, true }
local chunk = evo.chunk(F1, F2, F3)
for i = 1, N do
entities[i] = spawn_at(chunk, 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_at', N),
---@param entities evolved.id[]
function(entities)
local spawn_at = evo.spawn_at
local destroy = evo.destroy
local fragments = { F1, F2, F3, F4 }
local components = { true, true, true, true }
local chunk = evo.chunk(F1, F2, F3, F4)
for i = 1, N do
entities[i] = spawn_at(chunk, 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_at', N),
---@param entities evolved.id[]
function(entities)
local spawn_at = evo.spawn_at
local destroy = evo.destroy
local fragments = { F1, F2, F3, F4, F5 }
local components = { true, true, true, true, true }
local chunk = evo.chunk(F1, F2, F3, F4, F5)
for i = 1, N do
entities[i] = spawn_at(chunk, fragments, components)
end
for i = 1, #entities do
destroy(entities[i])
end
end, function()
return {}
end)
print '----------------------------------------'
--- ---
--- initial --- initial
--- ---

View File

@@ -3146,3 +3146,394 @@ do
assert(evo.is_alive(e) and evo.is_empty(e)) assert(evo.is_alive(e) and evo.is_empty(e))
end end
end end
do
local f1, f2, f3 = evo.id(3)
evo.set(f3, evo.TAG)
do
local e = evo.spawn()
assert(evo.is_alive(e) and evo.is_empty(e))
end
do
local e = evo.spawn({})
assert(evo.is_alive(e) and evo.is_empty(e))
end
do
local e1 = evo.spawn({ f1 })
assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
local e2 = evo.spawn({ f1 }, {})
assert(evo.has(e2, f1) and evo.get(e2, f1) == true)
local e3 = evo.spawn({ f1 }, { 41 })
assert(evo.has(e3, f1) and evo.get(e3, f1) == 41)
end
do
local e1 = evo.spawn({ f1, f2 })
assert(evo.has_all(e1, f1, f2))
assert(evo.get(e1, f1) == true and evo.get(e1, f2) == true)
local e2 = evo.spawn({ f1, f2 }, {})
assert(evo.has_all(e2, f1, f2))
assert(evo.get(e2, f1) == true and evo.get(e2, f2) == true)
local e3 = evo.spawn({ f1, f2 }, { 41 })
assert(evo.has_all(e3, f1, f2))
assert(evo.get(e3, f1) == 41 and evo.get(e3, f2) == true)
local e4 = evo.spawn({ f1, f2 }, { nil, 42 })
assert(evo.has_all(e4, f1, f2))
assert(evo.get(e4, f1) == true and evo.get(e4, f2) == 42)
local e5 = evo.spawn({ f1, f2 }, { 41, 42 })
assert(evo.has_all(e5, f1, f2))
assert(evo.get(e5, f1) == 41 and evo.get(e5, f2) == 42)
local e6 = evo.spawn({ f1, f2 }, { 41, 42, 43 })
assert(evo.has_all(e6, f1, f2))
assert(evo.get(e6, f1) == 41 and evo.get(e6, f2) == 42)
end
do
local e1 = evo.spawn({ f3 })
assert(evo.has(e1, f3))
assert(evo.get(e1, f3) == nil)
local e2 = evo.spawn({ f2, f3 })
assert(evo.has_all(e2, f2, f3))
assert(evo.get(e2, f2) == true and evo.get(e2, f3) == nil)
local e3 = evo.spawn({ f2, f3 }, { 42 })
assert(evo.has_all(e3, f2, f3))
assert(evo.get(e3, f2) == 42 and evo.get(e3, f3) == nil)
local e4 = evo.spawn({ f2, f3 }, { 42, 43, 44 })
assert(evo.has_all(e4, f2, f3))
assert(evo.get(e4, f2) == 42 and evo.get(e4, f3) == nil)
end
end
do
local f1, f2, f3 = evo.id(3)
evo.set(f2, evo.DEFAULT, 21)
evo.set(f3, evo.TAG)
do
local e = evo.spawn()
assert(evo.is_alive(e) and evo.is_empty(e))
end
do
local e = evo.spawn({})
assert(evo.is_alive(e) and evo.is_empty(e))
end
do
local e1 = evo.spawn({ f1 })
assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
local e2 = evo.spawn({ f1 }, {})
assert(evo.has(e2, f1) and evo.get(e2, f1) == true)
local e3 = evo.spawn({ f1 }, { 41 })
assert(evo.has(e3, f1) and evo.get(e3, f1) == 41)
end
do
local e1 = evo.spawn({ f1, f2 })
assert(evo.has_all(e1, f1, f2))
assert(evo.get(e1, f1) == true and evo.get(e1, f2) == 21)
local e2 = evo.spawn({ f1, f2 }, {})
assert(evo.has_all(e2, f1, f2))
assert(evo.get(e2, f1) == true and evo.get(e2, f2) == 21)
local e3 = evo.spawn({ f1, f2 }, { 41 })
assert(evo.has_all(e3, f1, f2))
assert(evo.get(e3, f1) == 41 and evo.get(e3, f2) == 21)
local e4 = evo.spawn({ f1, f2 }, { nil, 42 })
assert(evo.has_all(e4, f1, f2))
assert(evo.get(e4, f1) == true and evo.get(e4, f2) == 42)
local e5 = evo.spawn({ f1, f2 }, { 41, 42 })
assert(evo.has_all(e5, f1, f2))
assert(evo.get(e5, f1) == 41 and evo.get(e5, f2) == 42)
local e6 = evo.spawn({ f1, f2 }, { 41, 42, 43 })
assert(evo.has_all(e6, f1, f2))
assert(evo.get(e6, f1) == 41 and evo.get(e6, f2) == 42)
end
do
local e1 = evo.spawn({ f3 })
assert(evo.has(e1, f3))
assert(evo.get(e1, f3) == nil)
local e2 = evo.spawn({ f2, f3 })
assert(evo.has_all(e2, f2, f3))
assert(evo.get(e2, f2) == 21 and evo.get(e2, f3) == nil)
local e3 = evo.spawn({ f2, f3 }, { 42 })
assert(evo.has_all(e3, f2, f3))
assert(evo.get(e3, f2) == 42 and evo.get(e3, f3) == nil)
local e4 = evo.spawn({ f2, f3 }, { 42, 43, 44 })
assert(evo.has_all(e4, f2, f3))
assert(evo.get(e4, f2) == 42 and evo.get(e4, f3) == nil)
end
end
do
local cf = evo.id()
local f1, f2 = evo.id(2)
evo.set(f1, cf)
evo.set(f2, cf)
evo.set(f2, evo.DEFAULT, 21)
local set_count = 0
local insert_count = 0
local last_set_entity = 0
local last_set_component = 0
local last_insert_entity = 0
local last_insert_component = 0
local q = evo.query():include(cf):build()
evo.batch_set(q, evo.ON_SET, function(e, f, c)
last_set_entity = e
assert(f == f1 or f == f2)
last_set_component = c
set_count = set_count + 1
end)
evo.batch_set(q, evo.ON_INSERT, function(e, f, c)
last_insert_entity = e
assert(f == f1 or f == f2)
last_insert_component = c
insert_count = insert_count + 1
end)
assert(set_count == 0 and insert_count == 0)
assert(last_set_entity == 0 and last_set_component == 0)
assert(last_insert_entity == 0 and last_insert_component == 0)
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({ f1 })
assert(set_count == 1 and insert_count == 1)
assert(last_set_entity == e and last_set_component == true)
assert(last_insert_entity == e and last_insert_component == true)
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({ f2 })
assert(set_count == 1 and insert_count == 1)
assert(last_set_entity == e and last_set_component == 21)
assert(last_insert_entity == e and last_insert_component == 21)
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({ f1, f2 })
assert(set_count == 2 and insert_count == 2)
assert(last_set_entity == e and last_set_component == 21)
assert(last_insert_entity == e and last_insert_component == 21)
end
end
do
local f1, f2, f3, f4 = evo.id(4)
evo.set(f3, evo.DEFAULT, 33)
evo.set(f4, evo.TAG)
do
local e = evo.spawn_at()
assert(evo.is_alive(e) and evo.is_empty(e))
end
do
local c = evo.chunk(f1)
local e1 = evo.spawn_at(c)
assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
local e2 = evo.spawn_at(c, { f1 })
assert(evo.has(e2, f1) and evo.get(e2, f1) == true)
local e3 = evo.spawn_at(c, { f1, f2 })
assert(evo.has(e3, f1) and evo.get(e3, f1) == true)
assert(not evo.has(e3, f2) and evo.get(e3, f2) == nil)
local e4 = evo.spawn_at(c, { f1, f2 }, { 41 })
assert(evo.has(e4, f1) and evo.get(e4, f1) == 41)
assert(not evo.has(e4, f2) and evo.get(e4, f2) == nil)
local e5 = evo.spawn_at(c, { f1, f2 }, { 41, 42 })
assert(evo.has(e5, f1) and evo.get(e5, f1) == 41)
assert(not evo.has(e5, f2) and evo.get(e5, f2) == nil)
local e6 = evo.spawn_at(c, { f2 }, { 42 })
assert(evo.has(e6, f1) and evo.get(e6, f1) == true)
assert(not evo.has(e6, f2) and evo.get(e6, f2) == nil)
end
do
local c = evo.chunk(f1, f2)
local e1 = evo.spawn_at(c)
assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
assert(evo.has(e1, f2) and evo.get(e1, f2) == true)
local e2 = evo.spawn_at(c, { f1 })
assert(evo.has(e2, f1) and evo.get(e2, f1) == true)
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
local e3 = evo.spawn_at(c, { f1, f2 })
assert(evo.has(e3, f1) and evo.get(e3, f1) == true)
assert(evo.has(e3, f2) and evo.get(e3, f2) == true)
local e4 = evo.spawn_at(c, { f1, f2, f3 })
assert(evo.has(e4, f1) and evo.get(e4, f1) == true)
assert(evo.has(e4, f2) and evo.get(e4, f2) == true)
assert(not evo.has(e4, f3) and evo.get(e4, f3) == nil)
local e5 = evo.spawn_at(c, { f1, f2 }, { 41 })
assert(evo.has(e5, f1) and evo.get(e5, f1) == 41)
assert(evo.has(e5, f2) and evo.get(e5, f2) == true)
local e6 = evo.spawn_at(c, { f1, f2 }, { 41, 42 })
assert(evo.has(e6, f1) and evo.get(e6, f1) == 41)
assert(evo.has(e6, f2) and evo.get(e6, f2) == 42)
local e7 = evo.spawn_at(c, { f1, f2, f3 }, { 41, 42, 43 })
assert(evo.has(e7, f1) and evo.get(e7, f1) == 41)
assert(evo.has(e7, f2) and evo.get(e7, f2) == 42)
assert(not evo.has(e7, f3) and evo.get(e7, f3) == nil)
local e8 = evo.spawn_at(c, { f3 }, { 43 })
assert(evo.has(e8, f1) and evo.get(e8, f1) == true)
assert(evo.has(e8, f2) and evo.get(e8, f2) == true)
assert(not evo.has(e8, f3) and evo.get(e8, f3) == nil)
local e9 = evo.spawn_at(c, { f2 }, { 42 })
assert(evo.has(e9, f1) and evo.get(e9, f1) == true)
assert(evo.has(e9, f2) and evo.get(e9, f2) == 42)
assert(not evo.has(e9, f3) and evo.get(e9, f3) == nil)
end
do
local c = evo.chunk(f2, f3, f4)
local e1 = evo.spawn_at(c)
assert(evo.has(e1, f2) and evo.get(e1, f2) == true)
assert(evo.has(e1, f3) and evo.get(e1, f3) == 33)
assert(evo.has(e1, f4) and evo.get(e1, f4) == nil)
local e2 = evo.spawn_at(c, { f1 })
assert(not evo.has(e2, f1) and evo.get(e2, f1) == nil)
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
assert(evo.has(e2, f3) and evo.get(e2, f3) == 33)
assert(evo.has(e2, f4) and evo.get(e2, f4) == nil)
local e3 = evo.spawn_at(c, { f1 }, { 41 })
assert(not evo.has(e3, f1) and evo.get(e3, f1) == nil)
assert(evo.has(e3, f2) and evo.get(e3, f2) == true)
assert(evo.has(e3, f3) and evo.get(e3, f3) == 33)
assert(evo.has(e3, f4) and evo.get(e3, f4) == nil)
local e4 = evo.spawn_at(c, { f1, f3, f4 }, { 41, 43, 44 })
assert(not evo.has(e4, f1) and evo.get(e4, f1) == nil)
assert(evo.has(e4, f2) and evo.get(e4, f2) == true)
assert(evo.has(e4, f3) and evo.get(e4, f3) == 43)
assert(evo.has(e4, f4) and evo.get(e4, f4) == nil)
end
end
do
local cf = evo.id()
local f1, f2 = evo.id(2)
evo.set(f1, cf)
evo.set(f2, cf)
evo.set(f2, evo.DEFAULT, 22)
local set_count = 0
local insert_count = 0
local last_set_entity = 0
local last_set_component = 0
local last_insert_entity = 0
local last_insert_component = 0
local q = evo.query():include(cf):build()
evo.batch_set(q, evo.ON_SET, function(e, f, c)
last_set_entity = e
assert(f == f1 or f == f2)
last_set_component = c
set_count = set_count + 1
end)
evo.batch_set(q, evo.ON_INSERT, function(e, f, c)
last_insert_entity = e
assert(f == f1 or f == f2)
last_insert_component = c
insert_count = insert_count + 1
end)
assert(set_count == 0 and insert_count == 0)
assert(last_set_entity == 0 and last_set_component == 0)
assert(last_insert_entity == 0 and last_insert_component == 0)
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(f1)
local e = evo.spawn_at(c)
assert(set_count == 1 and insert_count == 1)
assert(last_set_entity == e and last_set_component == true)
assert(last_insert_entity == e and last_insert_component == true)
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(f2)
local e = evo.spawn_at(c)
assert(set_count == 1 and insert_count == 1)
assert(last_set_entity == e and last_set_component == 22)
assert(last_insert_entity == e and last_insert_component == 22)
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(f2, f1)
local e = evo.spawn_at(c)
assert(set_count == 2 and insert_count == 2)
assert(last_set_entity == e and last_set_component == 22)
assert(last_insert_entity == e and last_insert_component == 22)
end
end

View File

@@ -751,6 +751,58 @@ end
--- ---
--- ---
---@param ... evolved.fragment fragments
---@return evolved.chunk?
---@nodiscard
local function __chunk_fragments(...)
local fragment_count = select('#', ...)
if fragment_count == 0 then
return
end
local root_fragment = select(1, ...)
local chunk = __root_chunks[root_fragment]
or __root_chunk(root_fragment)
for i = 2, fragment_count do
local child_fragment = select(i, ...)
chunk = chunk.__with_fragment_edges[child_fragment]
or __chunk_with_fragment(chunk, child_fragment)
end
return chunk
end
---@param fragment_list evolved.fragment[]
---@return evolved.chunk?
---@nodiscard
local function __chunk_fragment_list(fragment_list)
local fragment_count = #fragment_list
if fragment_count == 0 then
return
end
local root_fragment = fragment_list[1]
local chunk = __root_chunks[root_fragment]
or __root_chunk(root_fragment)
for i = 2, fragment_count do
local child_fragment = fragment_list[i]
chunk = chunk.__with_fragment_edges[child_fragment]
or __chunk_with_fragment(chunk, child_fragment)
end
return chunk
end
---
---
---
---
---
---@param chunk evolved.chunk ---@param chunk evolved.chunk
---@param fragment evolved.fragment ---@param fragment evolved.fragment
---@return boolean ---@return boolean
@@ -3310,24 +3362,14 @@ end)
---@param ... evolved.fragment fragments ---@param ... evolved.fragment fragments
---@return evolved.chunk? chunk ---@return evolved.chunk? chunk
---@return evolved.entity[]? chunk_entities ---@return evolved.entity[]? entities
function evolved.chunk(...) function evolved.chunk(...)
local fragment_count = select('#', ...) local chunk = __chunk_fragments(...)
if fragment_count == 0 then if not chunk then
return return
end end
local root_fragment = select(1, ...)
local chunk = __root_chunks[root_fragment]
or __root_chunk(root_fragment)
for i = 2, fragment_count do
local child_fragment = select(i, ...)
chunk = chunk.__with_fragment_edges[child_fragment]
or __chunk_with_fragment(chunk, child_fragment)
end
return chunk, chunk.__entities return chunk, chunk.__entities
end end
@@ -3468,9 +3510,222 @@ 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 fragments? evolved.fragment[]
---@param components? evolved.component[]
---@return evolved.entity entity
---@return boolean is_deferred
function evolved.spawn_at(chunk, fragments, components)
if not fragments then
fragments = __EMPTY_FRAGMENT_LIST
end
if not components then
components = __EMPTY_COMPONENT_LIST
end
local entity = evolved.id()
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_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
__defer_commit()
return entity, false
end
---
---
---
---
---
---@class (exact) evolved.__entity_builder ---@class (exact) evolved.__entity_builder
---@field package __fragment_list? evolved.fragment[] ---@field package __fragment_list? evolved.fragment[]
---@field package __component_list? evolved.component[] ---@field package __component_list? evolved.component[]
---@field package __component_count integer
---@class evolved.entity_builder : evolved.__entity_builder ---@class evolved.entity_builder : evolved.__entity_builder
local evolved_entity_builder = {} local evolved_entity_builder = {}
@@ -3483,6 +3738,7 @@ function evolved.entity()
local builder = { local builder = {
__fragment_list = nil, __fragment_list = nil,
__component_list = nil, __component_list = nil,
__component_count = 0,
} }
---@cast builder evolved.entity_builder ---@cast builder evolved.entity_builder
return setmetatable(builder, evolved_entity_builder) return setmetatable(builder, evolved_entity_builder)
@@ -3496,16 +3752,20 @@ function evolved_entity_builder:set(fragment, ...)
local fragment_list = self.__fragment_list local fragment_list = self.__fragment_list
local component_list = self.__component_list local component_list = self.__component_list
local component_count = self.__component_count
if not fragment_list then if component_count == 0 then
fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 8, 0) fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 8, 0)
component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, 8, 0) component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, 8, 0)
self.__fragment_list = fragment_list self.__fragment_list = fragment_list
self.__component_list = component_list self.__component_list = component_list
end end
fragment_list[#fragment_list + 1] = fragment component_count = component_count + 1
component_list[#component_list + 1] = component self.__component_count = component_count
fragment_list[component_count] = fragment
component_list[component_count] = component
return self return self
end end
@@ -3514,17 +3774,17 @@ end
function evolved_entity_builder:build() function evolved_entity_builder:build()
local fragment_list = self.__fragment_list local fragment_list = self.__fragment_list
local component_list = self.__component_list local component_list = self.__component_list
local component_count = self.__component_count
self.__fragment_list = nil self.__fragment_list = nil
self.__component_list = nil self.__component_list = nil
self.__component_count = 0
local entity = evolved.id() if component_count == 0 then
return evolved.id()
if not fragment_list then
return entity
end end
evolved.multi_set(entity, fragment_list, component_list) local entity = evolved.spawn(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)
@@ -3590,27 +3850,33 @@ function evolved_fragment_builder:build()
self.__default = nil self.__default = nil
self.__construct = nil self.__construct = nil
local fragment = evolved.id()
local fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 3, 0) local fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 3, 0)
local component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, 3, 0) local component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, 3, 0)
local component_count = 0
if tag then if tag then
fragment_list[#fragment_list + 1] = evolved.TAG component_count = component_count + 1
component_list[#component_list + 1] = true fragment_list[component_count] = evolved.TAG
component_list[component_count] = true
end end
if default ~= nil then if default ~= nil then
fragment_list[#fragment_list + 1] = evolved.DEFAULT component_count = component_count + 1
component_list[#component_list + 1] = default fragment_list[component_count] = evolved.DEFAULT
component_list[component_count] = default
end end
if construct ~= nil then if construct ~= nil then
fragment_list[#fragment_list + 1] = evolved.CONSTRUCT component_count = component_count + 1
component_list[#component_list + 1] = construct fragment_list[component_count] = evolved.CONSTRUCT
component_list[component_count] = construct
end end
evolved.multi_set(fragment, fragment_list, component_list) if component_count == 0 then
return evolved.id()
end
local fragment = evolved.spawn(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)
@@ -3704,22 +3970,27 @@ function evolved_query_builder:build()
self.__include_list = nil self.__include_list = nil
self.__exclude_list = nil self.__exclude_list = nil
local query = evolved.id()
local fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 2, 0) local fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 2, 0)
local component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, 2, 0) local component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, 2, 0)
local component_count = 0
if include_list then if include_list then
fragment_list[#fragment_list + 1] = evolved.INCLUDES component_count = component_count + 1
component_list[#component_list + 1] = include_list fragment_list[component_count] = evolved.INCLUDES
component_list[component_count] = include_list
end end
if exclude_list then if exclude_list then
fragment_list[#fragment_list + 1] = evolved.EXCLUDES component_count = component_count + 1
component_list[#component_list + 1] = exclude_list fragment_list[component_count] = evolved.EXCLUDES
component_list[component_count] = exclude_list
end end
evolved.multi_set(query, fragment_list, component_list) if component_count == 0 then
return evolved.id()
end
local query = evolved.spawn(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)