proof of concept multi_clone/spawn optimizations

This commit is contained in:
BlackMATov
2025-09-12 01:52:33 +07:00
parent de7d1a6674
commit 5184b39f4e
5 changed files with 847 additions and 38 deletions

View File

@@ -5,6 +5,9 @@ require 'develop.testing.name_tests'
require 'develop.testing.requires_fragment_tests'
require 'develop.testing.system_as_query_tests'
require 'develop.benchmarks.multi_clone_bmarks'
require 'develop.benchmarks.multi_spawn_bmarks'
require 'develop.untests'
require 'develop.unbench'

View File

@@ -0,0 +1,57 @@
local evo = require 'evolved'
local basics = require 'develop.basics'
local N = 1000
local F1, F2, F3, F4, F5 = evo.id(5)
local Q1 = evo.builder():include(F1):spawn()
print '----------------------------------------'
basics.describe_bench(string.format('Multi Clone Benchmarks: Simple Clone | %d entities with 1 component', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [F1] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Multi Clone Benchmarks: Simple Clone | %d entities with 5 components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Multi Clone Benchmarks: Multi Clone | %d entities with 1 component', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [F1] = true }
multi_clone(N, prefab)
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Multi Clone Benchmarks: Multi Clone | %d entities with 5 components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
multi_clone(N, prefab)
evo.batch_destroy(Q1)
end)

View File

@@ -0,0 +1,57 @@
local evo = require 'evolved'
local basics = require 'develop.basics'
local N = 1000
local F1, F2, F3, F4, F5 = evo.id(5)
local Q1 = evo.builder():include(F1):spawn()
print '----------------------------------------'
basics.describe_bench(string.format('Multi Spawn Benchmarks: Simple Spawn | %d entities with 1 component', N),
function()
local spawn = evo.spawn
local components = { [F1] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Multi Spawn Benchmarks: Simple Spawn | %d entities with 5 components', N),
function()
local spawn = evo.spawn
local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Multi Spawn Benchmarks: Multi Spawn | %d entities with 1 component', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [F1] = true }
multi_spawn(N, components)
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Multi Spawn Benchmarks: Multi Spawn | %d entities with 5 components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
multi_spawn(N, components)
evo.batch_destroy(Q1)
end)

View File

@@ -192,3 +192,117 @@ do
assert(entity_list[2] and evo.get(entity_list[2], f1) == false and evo.get(entity_list[2], f2) == 456)
end
end
do
local f1, f2, f3 = evo.id(3)
do
local entity_list1, entity_list2
evo.defer()
do
entity_list1 = evo.multi_spawn(2, { [f1] = 42, [f2] = "hello", [f3] = false })
assert(entity_list1 and #entity_list1 == 2)
assert(entity_list1[1] and evo.empty(entity_list1[1]))
assert(entity_list1[2] and evo.empty(entity_list1[2]))
assert(not entity_list1[3])
entity_list2 = evo.multi_spawn(3, { [f2] = "world", [f3] = true })
assert(entity_list2 and #entity_list2 == 3)
assert(entity_list2[1] and evo.empty(entity_list2[1]))
assert(entity_list2[2] and evo.empty(entity_list2[2]))
assert(entity_list2[3] and evo.empty(entity_list2[3]))
end
evo.commit()
do
assert(entity_list1 and #entity_list1 == 2)
assert(entity_list1[1] and not evo.empty(entity_list1[1]))
assert(entity_list1[2] and not evo.empty(entity_list1[2]))
assert(not entity_list1[3])
assert(
evo.get(entity_list1[1], f1) == 42 and
evo.get(entity_list1[1], f2) == "hello" and
evo.get(entity_list1[1], f3) == false)
assert(
evo.get(entity_list1[2], f1) == 42 and
evo.get(entity_list1[2], f2) == "hello" and
evo.get(entity_list1[2], f3) == false)
assert(entity_list2 and #entity_list2 == 3)
assert(entity_list2[1] and not evo.empty(entity_list2[1]))
assert(entity_list2[2] and not evo.empty(entity_list2[2]))
assert(entity_list2[3] and not evo.empty(entity_list2[3]))
assert(not entity_list2[4])
assert(
evo.get(entity_list2[1], f1) == nil and
evo.get(entity_list2[1], f2) == "world" and
evo.get(entity_list2[1], f3) == true)
assert(
evo.get(entity_list2[2], f1) == nil and
evo.get(entity_list2[2], f2) == "world" and
evo.get(entity_list2[2], f3) == true)
assert(
evo.get(entity_list2[3], f1) == nil and
evo.get(entity_list2[3], f2) == "world" and
evo.get(entity_list2[3], f3) == true)
end
end
end
do
local f1, f2, f3 = evo.id(3)
do
local prefab = evo.builder():set(f1, false):set(f2, 123):spawn()
local entity_list1, entity_list2
evo.defer()
do
entity_list1 = evo.multi_clone(2, prefab)
assert(entity_list1 and #entity_list1 == 2)
assert(entity_list1[1] and evo.empty(entity_list1[1]))
assert(entity_list1[2] and evo.empty(entity_list1[2]))
assert(not entity_list1[3])
entity_list2 = evo.multi_clone(3, prefab, { [f2] = 456, [f3] = "world" })
assert(entity_list2 and #entity_list2 == 3)
assert(entity_list2[1] and evo.empty(entity_list2[1]))
assert(entity_list2[2] and evo.empty(entity_list2[2]))
assert(entity_list2[3] and evo.empty(entity_list2[3]))
end
evo.commit()
do
assert(entity_list1 and #entity_list1 == 2)
assert(entity_list1[1] and not evo.empty(entity_list1[1]))
assert(entity_list1[2] and not evo.empty(entity_list1[2]))
assert(not entity_list1[3])
assert(
evo.get(entity_list1[1], f1) == false and
evo.get(entity_list1[1], f2) == 123 and
evo.get(entity_list1[1], f3) == nil)
assert(
evo.get(entity_list1[2], f1) == false and
evo.get(entity_list1[2], f2) == 123 and
evo.get(entity_list1[2], f3) == nil)
assert(entity_list2 and #entity_list2 == 3)
assert(entity_list2[1] and not evo.empty(entity_list2[1]))
assert(entity_list2[2] and not evo.empty(entity_list2[2]))
assert(entity_list2[3] and not evo.empty(entity_list2[3]))
assert(not entity_list2[4])
assert(
evo.get(entity_list2[1], f1) == false and
evo.get(entity_list2[1], f2) == 456 and
evo.get(entity_list2[1], f3) == "world")
assert(
evo.get(entity_list2[2], f1) == false and
evo.get(entity_list2[2], f2) == 456 and
evo.get(entity_list2[2], f3) == "world")
assert(
evo.get(entity_list2[3], f1) == false and
evo.get(entity_list2[3], f2) == 456 and
evo.get(entity_list2[3], f3) == "world")
end
end
end

View File

@@ -877,7 +877,10 @@ local __detach_entity
local __detach_all_entities
local __spawn_entity
local __multi_spawn_entity
local __clone_entity
local __multi_clone_entity
local __purge_chunk
local __clear_chunk_list
@@ -899,7 +902,10 @@ local __defer_batch_clear
local __defer_batch_destroy
local __defer_spawn_entity
local __defer_multi_spawn_entity
local __defer_clone_entity
local __defer_multi_clone_entity
local __defer_call_hook
@@ -1986,6 +1992,216 @@ function __spawn_entity(entity, components)
end
end
---@param entity_list evolved.entity[]
---@param entity_count integer
---@param components table<evolved.fragment, evolved.component>
function __multi_spawn_entity(entity_list, entity_count, components)
if __defer_depth <= 0 then
__error_fmt('spawn entity operations should be deferred')
end
local chunk = __chunk_components(components)
if not chunk then
return
end
local req_fragment_set
local req_fragment_list
local req_fragment_count = 0
local ini_chunk = chunk
local ini_fragment_set = ini_chunk.__fragment_set
if chunk.__has_required_fragments then
---@type table<evolved.fragment, integer>
req_fragment_set = __acquire_table(__table_pool_tag.fragment_set)
---@type evolved.fragment[]
req_fragment_list = __acquire_table(__table_pool_tag.fragment_list)
req_fragment_count = __chunk_required_fragments(ini_chunk,
req_fragment_set, req_fragment_list, req_fragment_count)
for req_fragment_index = 1, req_fragment_count do
local req_fragment = req_fragment_list[req_fragment_index]
chunk = __chunk_with_fragment(chunk, req_fragment)
end
end
local chunk_entity_list = chunk.__entity_list
local chunk_entity_count = chunk.__entity_count
local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages
local b_place = chunk_entity_count + 1
local e_place = chunk_entity_count + entity_count
chunk.__entity_count = e_place
for place = b_place, e_place do
local entity = entity_list[place - b_place + 1]
local entity_primary = entity % 2 ^ 20
chunk_entity_list[place] = entity
__entity_chunks[entity_primary] = chunk
__entity_places[entity_primary] = place
__structural_changes = __structural_changes + 1
end
if chunk.__has_setup_hooks then
for fragment, component in __lua_next, components do
local component_index = chunk_component_indices[fragment]
if component_index then
---@type evolved.duplicate?
local fragment_duplicate =
__evolved_get(fragment, __DUPLICATE)
for place = b_place, e_place do
local new_component = component
if new_component ~= nil and fragment_duplicate then
new_component = fragment_duplicate(new_component)
end
if new_component == nil then
new_component = true
end
local component_storage = chunk_component_storages[component_index]
component_storage[place] = new_component
end
end
end
for req_fragment_index = 1, req_fragment_count do
local req_fragment = req_fragment_list[req_fragment_index]
if ini_fragment_set[req_fragment] then
-- this fragment has already been initialized
else
local req_component_index = chunk_component_indices[req_fragment]
if req_component_index then
---@type evolved.default?, evolved.duplicate?
local req_fragment_default, req_fragment_duplicate =
__evolved_get(req_fragment, __DEFAULT, __DUPLICATE)
for place = b_place, e_place do
local req_component = req_fragment_default
if req_component ~= nil and req_fragment_duplicate then
req_component = req_fragment_duplicate(req_component)
end
if req_component == nil then
req_component = true
end
local req_component_storage = chunk_component_storages[req_component_index]
req_component_storage[place] = req_component
end
end
end
end
else
for fragment, component in __lua_next, components do
local component_index = chunk_component_indices[fragment]
if component_index then
local new_component = component
local component_storage = chunk_component_storages[component_index]
for place = b_place, e_place do
component_storage[place] = new_component
end
end
end
for req_fragment_index = 1, req_fragment_count do
local req_fragment = req_fragment_list[req_fragment_index]
if ini_fragment_set[req_fragment] then
-- this fragment has already been initialized
else
local req_component_index = chunk_component_indices[req_fragment]
if req_component_index then
local req_component = true
local req_component_storage = chunk_component_storages[req_component_index]
for place = b_place, e_place do
req_component_storage[place] = req_component
end
end
end
end
end
if chunk.__has_insert_hooks then
local chunk_fragment_list = chunk.__fragment_list
local chunk_fragment_count = chunk.__fragment_count
for chunk_fragment_index = 1, chunk_fragment_count do
local fragment = chunk_fragment_list[chunk_fragment_index]
---@type evolved.set_hook?, evolved.insert_hook?
local fragment_on_set, fragment_on_insert =
__evolved_get(fragment, __ON_SET, __ON_INSERT)
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
for place = b_place, e_place do
local entity = chunk_entity_list[place]
local new_component = component_storage[place]
if fragment_on_set then
__defer_call_hook(fragment_on_set, entity, fragment, new_component)
end
if fragment_on_insert then
__defer_call_hook(fragment_on_insert, entity, fragment, new_component)
end
end
else
if fragment_on_set then
for place = b_place, e_place do
local entity = chunk_entity_list[place]
__defer_call_hook(fragment_on_set, entity, fragment)
end
end
if fragment_on_insert then
for place = b_place, e_place do
local entity = chunk_entity_list[place]
__defer_call_hook(fragment_on_insert, entity, fragment)
end
end
end
end
end
if req_fragment_set then
__release_table(__table_pool_tag.fragment_set, req_fragment_set)
end
if req_fragment_list then
__release_table(__table_pool_tag.fragment_list, req_fragment_list)
end
end
---@param entity evolved.entity
---@param prefab evolved.entity
---@param components table<evolved.fragment, evolved.component>
@@ -2238,6 +2454,284 @@ function __clone_entity(entity, prefab, components)
end
end
---@param entity_list evolved.entity[]
---@param entity_count integer
---@param prefab evolved.entity
---@param components table<evolved.fragment, evolved.component>
function __multi_clone_entity(entity_list, entity_count, prefab, components)
if __defer_depth <= 0 then
__error_fmt('clone entity operations should be deferred')
end
local prefab_primary = prefab % 2 ^ 20
local prefab_chunk = __entity_chunks[prefab_primary]
local prefab_place = __entity_places[prefab_primary]
local chunk = __chunk_with_components(
__chunk_without_unique_fragments(prefab_chunk),
components)
if not chunk then
return
end
local req_fragment_set
local req_fragment_list
local req_fragment_count = 0
local ini_chunk = chunk
local ini_fragment_set = ini_chunk.__fragment_set
if chunk.__has_required_fragments then
---@type table<evolved.fragment, integer>
req_fragment_set = __acquire_table(__table_pool_tag.fragment_set)
---@type evolved.fragment[]
req_fragment_list = __acquire_table(__table_pool_tag.fragment_list)
req_fragment_count = __chunk_required_fragments(ini_chunk,
req_fragment_set, req_fragment_list, req_fragment_count)
for req_fragment_index = 1, req_fragment_count do
local req_fragment = req_fragment_list[req_fragment_index]
chunk = __chunk_with_fragment(chunk, req_fragment)
end
end
local chunk_entity_list = chunk.__entity_list
local chunk_entity_count = chunk.__entity_count
local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages
local b_place = chunk_entity_count + 1
local e_place = chunk_entity_count + entity_count
chunk.__entity_count = e_place
for place = b_place, e_place do
local entity = entity_list[place - b_place + 1]
local entity_primary = entity % 2 ^ 20
chunk_entity_list[place] = entity
__entity_chunks[entity_primary] = chunk
__entity_places[entity_primary] = place
__structural_changes = __structural_changes + 1
end
if prefab_chunk then
local prefab_component_count = prefab_chunk.__component_count
local prefab_component_storages = prefab_chunk.__component_storages
local prefab_component_fragments = prefab_chunk.__component_fragments
if prefab_chunk.__has_setup_hooks then
for prefab_component_index = 1, prefab_component_count do
local fragment = prefab_component_fragments[prefab_component_index]
local component_index = chunk_component_indices[fragment]
if component_index then
---@type evolved.duplicate?
local fragment_duplicate =
__evolved_get(fragment, __DUPLICATE)
local prefab_component_storage = prefab_component_storages[prefab_component_index]
local prefab_component = prefab_component_storage[prefab_place]
for place = b_place, e_place do
local new_component = prefab_component
if new_component ~= nil and fragment_duplicate then
new_component = fragment_duplicate(new_component)
end
if new_component == nil then
new_component = true
end
local component_storage = chunk_component_storages[component_index]
component_storage[place] = new_component
end
end
end
else
for prefab_component_index = 1, prefab_component_count do
local fragment = prefab_component_fragments[prefab_component_index]
local component_index = chunk_component_indices[fragment]
if component_index then
local prefab_component_storage = prefab_component_storages[prefab_component_index]
local prefab_component = prefab_component_storage[prefab_place]
local new_component = prefab_component
if new_component == nil then
new_component = true
end
local component_storage = chunk_component_storages[component_index]
for place = b_place, e_place do
component_storage[place] = new_component
end
end
end
end
end
if chunk.__has_setup_hooks then
for fragment, component in __lua_next, components do
local component_index = chunk_component_indices[fragment]
if component_index then
---@type evolved.duplicate?
local fragment_duplicate =
__evolved_get(fragment, __DUPLICATE)
for place = b_place, e_place do
local new_component = component
if new_component ~= nil and fragment_duplicate then
new_component = fragment_duplicate(new_component)
end
if new_component == nil then
new_component = true
end
local component_storage = chunk_component_storages[component_index]
component_storage[place] = new_component
end
end
end
for req_fragment_index = 1, req_fragment_count do
local req_fragment = req_fragment_list[req_fragment_index]
if ini_fragment_set[req_fragment] then
-- this fragment has already been initialized
else
local req_component_index = chunk_component_indices[req_fragment]
if req_component_index then
---@type evolved.default?, evolved.duplicate?
local req_fragment_default, req_fragment_duplicate =
__evolved_get(req_fragment, __DEFAULT, __DUPLICATE)
for place = b_place, e_place do
local req_component = req_fragment_default
if req_component ~= nil and req_fragment_duplicate then
req_component = req_fragment_duplicate(req_component)
end
if req_component == nil then
req_component = true
end
local req_component_storage = chunk_component_storages[req_component_index]
req_component_storage[place] = req_component
end
end
end
end
else
for fragment, component in __lua_next, components do
local component_index = chunk_component_indices[fragment]
if component_index then
local new_component = component
local component_storage = chunk_component_storages[component_index]
for place = b_place, e_place do
component_storage[place] = new_component
end
end
end
for req_fragment_index = 1, req_fragment_count do
local req_fragment = req_fragment_list[req_fragment_index]
if ini_fragment_set[req_fragment] then
-- this fragment has already been initialized
else
local req_component_index = chunk_component_indices[req_fragment]
if req_component_index then
local req_component = true
local req_component_storage = chunk_component_storages[req_component_index]
for place = b_place, e_place do
req_component_storage[place] = req_component
end
end
end
end
end
if chunk.__has_insert_hooks then
local chunk_fragment_list = chunk.__fragment_list
local chunk_fragment_count = chunk.__fragment_count
for chunk_fragment_index = 1, chunk_fragment_count do
local fragment = chunk_fragment_list[chunk_fragment_index]
---@type evolved.set_hook?, evolved.insert_hook?
local fragment_on_set, fragment_on_insert =
__evolved_get(fragment, __ON_SET, __ON_INSERT)
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
for place = b_place, e_place do
local entity = chunk_entity_list[place]
local new_component = component_storage[place]
if fragment_on_set then
__defer_call_hook(fragment_on_set, entity, fragment, new_component)
end
if fragment_on_insert then
__defer_call_hook(fragment_on_insert, entity, fragment, new_component)
end
end
else
if fragment_on_set then
for place = b_place, e_place do
local entity = chunk_entity_list[place]
__defer_call_hook(fragment_on_set, entity, fragment)
end
end
if fragment_on_insert then
for place = b_place, e_place do
local entity = chunk_entity_list[place]
__defer_call_hook(fragment_on_insert, entity, fragment)
end
end
end
end
end
if req_fragment_set then
__release_table(__table_pool_tag.fragment_set, req_fragment_set)
end
if req_fragment_list then
__release_table(__table_pool_tag.fragment_list, req_fragment_list)
end
end
---@param chunk evolved.chunk
function __purge_chunk(chunk)
if __defer_depth <= 0 then
@@ -3104,11 +3598,14 @@ local __defer_op = {
batch_destroy = 8,
spawn_entity = 9,
clone_entity = 10,
multi_spawn_entity = 10,
call_hook = 11,
clone_entity = 11,
multi_clone_entity = 12,
__count = 11,
call_hook = 13,
__count = 13,
}
---@type table<evolved.defer_op, fun(bytes: any[], index: integer): integer>
@@ -3596,13 +4093,13 @@ __defer_ops[__defer_op.batch_destroy] = function(bytes, index)
end
---@param entity evolved.entity
---@param components table<evolved.fragment, evolved.component>
function __defer_spawn_entity(entity, components)
---@param component_map table<evolved.fragment, evolved.component>
function __defer_spawn_entity(entity, component_map)
---@type table<evolved.fragment, evolved.component>
local component_map = __acquire_table(__table_pool_tag.component_map)
local component_map_dup = __acquire_table(__table_pool_tag.component_map)
for fragment, component in __lua_next, components do
component_map[fragment] = component
for fragment, component in __lua_next, component_map do
component_map_dup[fragment] = component
end
local length = __defer_length
@@ -3610,62 +4107,155 @@ function __defer_spawn_entity(entity, components)
bytecode[length + 1] = __defer_op.spawn_entity
bytecode[length + 2] = entity
bytecode[length + 3] = component_map
bytecode[length + 3] = component_map_dup
__defer_length = length + 3
end
__defer_ops[__defer_op.spawn_entity] = function(bytes, index)
local entity = bytes[index + 0]
local component_map = bytes[index + 1]
local component_map_dup = bytes[index + 1]
__evolved_defer()
do
__spawn_entity(entity, component_map)
__release_table(__table_pool_tag.component_map, component_map)
__spawn_entity(entity, component_map_dup)
__release_table(__table_pool_tag.component_map, component_map_dup)
end
__evolved_commit()
return 2
end
---@param entity_list evolved.entity[]
---@param entity_count integer
---@param component_map table<evolved.fragment, evolved.component>
function __defer_multi_spawn_entity(entity_list, entity_count, component_map)
---@type evolved.entity[]
local entity_list_dup = __acquire_table(__table_pool_tag.entity_list)
__lua_table_move(
entity_list, 1, entity_count,
1, entity_list_dup)
---@type table<evolved.fragment, evolved.component>
local component_map_dup = __acquire_table(__table_pool_tag.component_map)
for fragment, component in __lua_next, component_map do
component_map_dup[fragment] = component
end
local length = __defer_length
local bytecode = __defer_bytecode
bytecode[length + 1] = __defer_op.multi_spawn_entity
bytecode[length + 2] = entity_count
bytecode[length + 3] = entity_list_dup
bytecode[length + 4] = component_map_dup
__defer_length = length + 4
end
__defer_ops[__defer_op.multi_spawn_entity] = function(bytes, index)
local entity_count = bytes[index + 0]
local entity_list_dup = bytes[index + 1]
local component_map_dup = bytes[index + 2]
__evolved_defer()
do
__multi_spawn_entity(entity_list_dup, entity_count, component_map_dup)
__release_table(__table_pool_tag.entity_list, entity_list_dup)
__release_table(__table_pool_tag.component_map, component_map_dup)
end
__evolved_commit()
return 3
end
---@param entity evolved.entity
---@param prefab evolved.entity
---@param components table<evolved.fragment, evolved.component>
function __defer_clone_entity(entity, prefab, components)
---@type table<evolved.fragment, evolved.component>
local component_map = __acquire_table(__table_pool_tag.component_map)
local component_map_dup = __acquire_table(__table_pool_tag.component_map)
for fragment, component in __lua_next, components do
component_map[fragment] = component
component_map_dup[fragment] = component
end
local length = __defer_length
local bytecode = __defer_bytecode
bytecode[length + 1] = __defer_op.clone_entity
bytecode[length + 2] = entity
bytecode[length + 3] = prefab
bytecode[length + 4] = component_map
bytecode[length + 2] = prefab
bytecode[length + 3] = entity
bytecode[length + 4] = component_map_dup
__defer_length = length + 4
end
__defer_ops[__defer_op.clone_entity] = function(bytes, index)
local entity = bytes[index + 0]
local prefab = bytes[index + 1]
local component_map = bytes[index + 2]
local prefab = bytes[index + 0]
local entity = bytes[index + 1]
local component_map_dup = bytes[index + 2]
__evolved_defer()
do
__clone_entity(entity, prefab, component_map)
__release_table(__table_pool_tag.component_map, component_map)
__clone_entity(entity, prefab, component_map_dup)
__release_table(__table_pool_tag.component_map, component_map_dup)
end
__evolved_commit()
return 3
end
---@param entity_list evolved.entity[]
---@param entity_count integer
---@param prefab evolved.entity
---@param components table<evolved.fragment, evolved.component>
function __defer_multi_clone_entity(entity_list, entity_count, prefab, components)
---@type evolved.entity[]
local entity_list_dup = __acquire_table(__table_pool_tag.entity_list)
__lua_table_move(
entity_list, 1, entity_count,
1, entity_list_dup)
---@type table<evolved.fragment, evolved.component>
local component_map_dup = __acquire_table(__table_pool_tag.component_map)
for fragment, component in __lua_next, components do
component_map_dup[fragment] = component
end
local length = __defer_length
local bytecode = __defer_bytecode
bytecode[length + 1] = __defer_op.multi_clone_entity
bytecode[length + 2] = prefab
bytecode[length + 3] = entity_count
bytecode[length + 4] = entity_list_dup
bytecode[length + 5] = component_map_dup
__defer_length = length + 5
end
__defer_ops[__defer_op.multi_clone_entity] = function(bytes, index)
local prefab = bytes[index + 0]
local entity_count = bytes[index + 1]
local entity_list_dup = bytes[index + 2]
local component_map_dup = bytes[index + 3]
__evolved_defer()
do
__multi_clone_entity(entity_list_dup, entity_count, prefab, component_map_dup)
__release_table(__table_pool_tag.entity_list, entity_list_dup)
__release_table(__table_pool_tag.component_map, component_map_dup)
end
__evolved_commit()
return 4
end
---@param hook fun(...)
---@param ... any hook arguments
function __defer_call_hook(hook, ...)
@@ -4083,17 +4673,11 @@ function __evolved_multi_spawn(entity_count, components)
end
if __defer_depth > 0 then
for entity_index = 1, entity_count do
local entity = entity_list[entity_index]
__defer_spawn_entity(entity, components)
end
__defer_multi_spawn_entity(entity_list, entity_count, components)
else
__evolved_defer()
do
for entity_index = 1, entity_count do
local entity = entity_list[entity_index]
__spawn_entity(entity, components)
end
__multi_spawn_entity(entity_list, entity_count, components)
end
__evolved_commit()
end
@@ -4174,17 +4758,11 @@ function __evolved_multi_clone(entity_count, prefab, components)
end
if __defer_depth > 0 then
for entity_index = 1, entity_count do
local entity = entity_list[entity_index]
__defer_clone_entity(entity, prefab, components)
end
__defer_multi_clone_entity(entity_list, entity_count, prefab, components)
else
__evolved_defer()
do
for entity_index = 1, entity_count do
local entity = entity_list[entity_index]
__clone_entity(entity, prefab, components)
end
__multi_clone_entity(entity_list, entity_count, prefab, components)
end
__evolved_commit()
end