improve performance of the clone operations

This commit is contained in:
BlackMATov
2025-11-19 08:51:26 +07:00
parent 55e444ca63
commit de73881f63
2 changed files with 161 additions and 283 deletions

View File

@@ -11,6 +11,8 @@
- We can return deferred status from modifying operations and spawn/clone methods. - We can return deferred status from modifying operations and spawn/clone methods.
- We should have a way to not copy components on deferred spawn/clone. - We should have a way to not copy components on deferred spawn/clone.
- We can cache default/duplicate per chunk to speed up entity creation with setup hooks.
- We need spawn/clone fuzzy tests!
## Known Issues ## Known Issues

View File

@@ -2055,34 +2055,40 @@ function __spawn_entity(chunk, entity, components)
local fragment_default, fragment_duplicate = local fragment_default, fragment_duplicate =
__evolved_get(component_fragment, __DEFAULT, __DUPLICATE) __evolved_get(component_fragment, __DEFAULT, __DUPLICATE)
local new_component = components[component_fragment] local ini_component = components[component_fragment]
if new_component == nil then if ini_component == nil then
new_component = fragment_default ini_component = fragment_default
end end
if new_component ~= nil and fragment_duplicate then if ini_component ~= nil and fragment_duplicate then
new_component = fragment_duplicate(new_component) local new_component = fragment_duplicate(ini_component)
end
if new_component == nil then if new_component == nil then
new_component = true new_component = true
end end
component_storage[place] = new_component component_storage[place] = new_component
else
if ini_component == nil then
ini_component = true
end
component_storage[place] = ini_component
end
end end
else else
for component_index = 1, chunk_component_count do for component_index = 1, chunk_component_count do
local component_storage = chunk_component_storages[component_index] local component_storage = chunk_component_storages[component_index]
local component_fragment = chunk_component_fragments[component_index] local component_fragment = chunk_component_fragments[component_index]
local new_component = components[component_fragment] local ini_component = components[component_fragment]
if new_component == nil then if ini_component == nil then
new_component = true ini_component = true
end end
component_storage[place] = new_component component_storage[place] = ini_component
end end
end end
@@ -2206,20 +2212,29 @@ function __multi_spawn_entity(chunk, entity_list, entity_count, components)
local fragment_default, fragment_duplicate = local fragment_default, fragment_duplicate =
__evolved_get(component_fragment, __DEFAULT, __DUPLICATE) __evolved_get(component_fragment, __DEFAULT, __DUPLICATE)
if fragment_duplicate then local ini_component = components[component_fragment]
if ini_component == nil then
ini_component = fragment_default
end
if ini_component ~= nil and fragment_duplicate then
for place = b_place, e_place do for place = b_place, e_place do
local new_component = components[component_fragment] local new_component = fragment_duplicate(ini_component)
if new_component == nil then new_component = fragment_default end
if new_component ~= nil then new_component = fragment_duplicate(new_component) end if new_component == nil then
if new_component == nil then new_component = true end new_component = true
end
component_storage[place] = new_component component_storage[place] = new_component
end end
else else
local new_component = components[component_fragment] if ini_component == nil then
if new_component == nil then new_component = fragment_default end ini_component = true
if new_component == nil then new_component = true end end
for place = b_place, e_place do for place = b_place, e_place do
component_storage[place] = new_component component_storage[place] = ini_component
end end
end end
end end
@@ -2228,10 +2243,14 @@ function __multi_spawn_entity(chunk, entity_list, entity_count, components)
local component_storage = chunk_component_storages[component_index] local component_storage = chunk_component_storages[component_index]
local component_fragment = chunk_component_fragments[component_index] local component_fragment = chunk_component_fragments[component_index]
local new_component = components[component_fragment] local ini_component = components[component_fragment]
if new_component == nil then new_component = true end
if ini_component == nil then
ini_component = true
end
for place = b_place, e_place do for place = b_place, e_place do
component_storage[place] = new_component component_storage[place] = ini_component
end end
end end
end end
@@ -2312,8 +2331,12 @@ function __clone_entity(prefab, entity, components)
prefab_chunk.__without_unique_fragments = __chunk_without_unique_fragments(prefab_chunk) prefab_chunk.__without_unique_fragments = __chunk_without_unique_fragments(prefab_chunk)
end end
if not prefab_chunk or not prefab_chunk.__without_unique_fragments then
return __spawn_entity(nil, entity, components)
end
local chunk = __chunk_with_components( local chunk = __chunk_with_components(
prefab_chunk and prefab_chunk.__without_unique_fragments, prefab_chunk.__without_unique_fragments,
components) components)
if not chunk then if not chunk then
@@ -2324,9 +2347,6 @@ function __clone_entity(prefab, entity, components)
local req_fragment_list local req_fragment_list
local req_fragment_count = 0 local req_fragment_count = 0
local ini_chunk = chunk
local ini_fragment_set = ini_chunk.__fragment_set
if chunk.__has_required_fragments then if chunk.__has_required_fragments then
---@type table<evolved.fragment, integer> ---@type table<evolved.fragment, integer>
req_fragment_set = __acquire_table(__table_pool_tag.fragment_set) req_fragment_set = __acquire_table(__table_pool_tag.fragment_set)
@@ -2334,7 +2354,7 @@ function __clone_entity(prefab, entity, components)
---@type evolved.fragment[] ---@type evolved.fragment[]
req_fragment_list = __acquire_table(__table_pool_tag.fragment_list) req_fragment_list = __acquire_table(__table_pool_tag.fragment_list)
req_fragment_count = __chunk_required_fragments(ini_chunk, req_fragment_count = __chunk_required_fragments(chunk,
req_fragment_set, req_fragment_list, req_fragment_count) req_fragment_set, req_fragment_list, req_fragment_count)
for req_fragment_index = 1, req_fragment_count do for req_fragment_index = 1, req_fragment_count do
@@ -2346,8 +2366,13 @@ function __clone_entity(prefab, entity, components)
local chunk_entity_list = chunk.__entity_list local chunk_entity_list = chunk.__entity_list
local chunk_entity_count = chunk.__entity_count local chunk_entity_count = chunk.__entity_count
local chunk_component_count = chunk.__component_count
local chunk_component_indices = chunk.__component_indices local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages local chunk_component_storages = chunk.__component_storages
local chunk_component_fragments = chunk.__component_fragments
local prefab_component_indices = prefab_chunk.__component_indices
local prefab_component_storages = prefab_chunk.__component_storages
local place = chunk_entity_count + 1 local place = chunk_entity_count + 1
@@ -2362,144 +2387,69 @@ function __clone_entity(prefab, entity, components)
__entity_places[entity_primary] = place __entity_places[entity_primary] = place
end 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
local component_storage = chunk_component_storages[component_index]
---@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]
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
component_storage[place] = new_component
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 component_storage = chunk_component_storages[component_index]
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
component_storage[place] = new_component
end
end
end
end
if chunk.__has_setup_hooks then if chunk.__has_setup_hooks then
for fragment, component in __lua_next, components do for component_index = 1, chunk_component_count do
local component_index = chunk_component_indices[fragment] local component_storage = chunk_component_storages[component_index]
local component_fragment = chunk_component_fragments[component_index]
if component_index then ---@type evolved.default?, evolved.duplicate?
local component_storage = chunk_component_storages[component_index] local fragment_default, fragment_duplicate =
__evolved_get(component_fragment, __DEFAULT, __DUPLICATE)
---@type evolved.duplicate? local ini_component = components[component_fragment]
local fragment_duplicate =
__evolved_get(fragment, __DUPLICATE)
local new_component = component if ini_component == nil then
if chunk == prefab_chunk then
if new_component ~= nil and fragment_duplicate then ini_component = component_storage[prefab_place]
new_component = fragment_duplicate(new_component) else
local prefab_component_index = prefab_component_indices[component_fragment]
if prefab_component_index then
local prefab_component_storage = prefab_component_storages[prefab_component_index]
ini_component = prefab_component_storage[prefab_place]
else
ini_component = fragment_default
end
end end
end
if ini_component ~= nil and fragment_duplicate then
local new_component = fragment_duplicate(ini_component)
if new_component == nil then if new_component == nil then
new_component = true new_component = true
end end
component_storage[place] = new_component component_storage[place] = new_component
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 else
local req_component_index = chunk_component_indices[req_fragment] if ini_component == nil then
ini_component = true
if req_component_index then
local req_component_storage = chunk_component_storages[req_component_index]
---@type evolved.default?, evolved.duplicate?
local req_fragment_default, req_fragment_duplicate =
__evolved_get(req_fragment, __DEFAULT, __DUPLICATE)
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
req_component_storage[place] = req_component
end end
component_storage[place] = ini_component
end end
end end
else else
for fragment, component in __lua_next, components do for component_index = 1, chunk_component_count do
local component_index = chunk_component_indices[fragment] local component_storage = chunk_component_storages[component_index]
local component_fragment = chunk_component_fragments[component_index]
if component_index then local ini_component = components[component_fragment]
local component_storage = chunk_component_storages[component_index]
local new_component = component if ini_component == nil then
if new_component == nil then new_component = true end if chunk == prefab_chunk then
component_storage[place] = new_component ini_component = component_storage[prefab_place]
end else
end local prefab_component_index = prefab_component_indices[component_fragment]
if prefab_component_index then
for req_fragment_index = 1, req_fragment_count do local prefab_component_storage = prefab_component_storages[prefab_component_index]
local req_fragment = req_fragment_list[req_fragment_index] ini_component = prefab_component_storage[prefab_place]
else
if ini_fragment_set[req_fragment] then ini_component = true
-- this fragment has already been initialized end
else
local req_component_index = chunk_component_indices[req_fragment]
if req_component_index then
local req_component_storage = chunk_component_storages[req_component_index]
local req_component = true
req_component_storage[place] = req_component
end end
end end
component_storage[place] = ini_component
end end
end end
@@ -2564,8 +2514,12 @@ function __multi_clone_entity(prefab, entity_list, entity_count, components)
prefab_chunk.__without_unique_fragments = __chunk_without_unique_fragments(prefab_chunk) prefab_chunk.__without_unique_fragments = __chunk_without_unique_fragments(prefab_chunk)
end end
if not prefab_chunk or not prefab_chunk.__without_unique_fragments then
return __multi_spawn_entity(nil, entity_list, entity_count, components)
end
local chunk = __chunk_with_components( local chunk = __chunk_with_components(
prefab_chunk and prefab_chunk.__without_unique_fragments, prefab_chunk.__without_unique_fragments,
components) components)
if not chunk then if not chunk then
@@ -2576,9 +2530,6 @@ function __multi_clone_entity(prefab, entity_list, entity_count, components)
local req_fragment_list local req_fragment_list
local req_fragment_count = 0 local req_fragment_count = 0
local ini_chunk = chunk
local ini_fragment_set = ini_chunk.__fragment_set
if chunk.__has_required_fragments then if chunk.__has_required_fragments then
---@type table<evolved.fragment, integer> ---@type table<evolved.fragment, integer>
req_fragment_set = __acquire_table(__table_pool_tag.fragment_set) req_fragment_set = __acquire_table(__table_pool_tag.fragment_set)
@@ -2586,7 +2537,7 @@ function __multi_clone_entity(prefab, entity_list, entity_count, components)
---@type evolved.fragment[] ---@type evolved.fragment[]
req_fragment_list = __acquire_table(__table_pool_tag.fragment_list) req_fragment_list = __acquire_table(__table_pool_tag.fragment_list)
req_fragment_count = __chunk_required_fragments(ini_chunk, req_fragment_count = __chunk_required_fragments(chunk,
req_fragment_set, req_fragment_list, req_fragment_count) req_fragment_set, req_fragment_list, req_fragment_count)
for req_fragment_index = 1, req_fragment_count do for req_fragment_index = 1, req_fragment_count do
@@ -2598,8 +2549,13 @@ function __multi_clone_entity(prefab, entity_list, entity_count, components)
local chunk_entity_list = chunk.__entity_list local chunk_entity_list = chunk.__entity_list
local chunk_entity_count = chunk.__entity_count local chunk_entity_count = chunk.__entity_count
local chunk_component_count = chunk.__component_count
local chunk_component_indices = chunk.__component_indices local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages local chunk_component_storages = chunk.__component_storages
local chunk_component_fragments = chunk.__component_fragments
local prefab_component_indices = prefab_chunk.__component_indices
local prefab_component_storages = prefab_chunk.__component_storages
local b_place = chunk_entity_count + 1 local b_place = chunk_entity_count + 1
local e_place = chunk_entity_count + entity_count local e_place = chunk_entity_count + entity_count
@@ -2621,155 +2577,75 @@ function __multi_clone_entity(prefab, entity_list, entity_count, components)
end end
end 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
local component_storage = chunk_component_storages[component_index]
---@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]
if fragment_duplicate then
for place = b_place, e_place do
local new_component = prefab_component
if new_component ~= nil then new_component = fragment_duplicate(new_component) end
if new_component == nil then new_component = true end
component_storage[place] = new_component
end
else
local new_component = prefab_component
if new_component == nil then new_component = true end
for place = b_place, e_place do
component_storage[place] = new_component
end
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 component_storage = chunk_component_storages[component_index]
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
for place = b_place, e_place do
component_storage[place] = new_component
end
end
end
end
end
if chunk.__has_setup_hooks then if chunk.__has_setup_hooks then
for fragment, component in __lua_next, components do for component_index = 1, chunk_component_count do
local component_index = chunk_component_indices[fragment] local component_storage = chunk_component_storages[component_index]
local component_fragment = chunk_component_fragments[component_index]
if component_index then ---@type evolved.default?, evolved.duplicate?
local component_storage = chunk_component_storages[component_index] local fragment_default, fragment_duplicate =
__evolved_get(component_fragment, __DEFAULT, __DUPLICATE)
---@type evolved.duplicate? local ini_component = components[component_fragment]
local fragment_duplicate =
__evolved_get(fragment, __DUPLICATE)
if fragment_duplicate then if ini_component == nil then
for place = b_place, e_place do if chunk == prefab_chunk then
local new_component = component ini_component = component_storage[prefab_place]
if new_component ~= nil then new_component = fragment_duplicate(new_component) end
if new_component == nil then new_component = true end
component_storage[place] = new_component
end
else else
local new_component = component local prefab_component_index = prefab_component_indices[component_fragment]
if new_component == nil then new_component = true end if prefab_component_index then
for place = b_place, e_place do local prefab_component_storage = prefab_component_storages[prefab_component_index]
component_storage[place] = new_component ini_component = prefab_component_storage[prefab_place]
else
ini_component = fragment_default
end end
end end
end end
end
for req_fragment_index = 1, req_fragment_count do if ini_component ~= nil and fragment_duplicate then
local req_fragment = req_fragment_list[req_fragment_index] for place = b_place, e_place do
local new_component = fragment_duplicate(ini_component)
if ini_fragment_set[req_fragment] then if new_component == nil then
-- this fragment has already been initialized new_component = true
else
local req_component_index = chunk_component_indices[req_fragment]
if req_component_index then
local req_component_storage = chunk_component_storages[req_component_index]
---@type evolved.default?, evolved.duplicate?
local req_fragment_default, req_fragment_duplicate =
__evolved_get(req_fragment, __DEFAULT, __DUPLICATE)
if req_fragment_duplicate then
for place = b_place, e_place do
local req_component = req_fragment_default
if req_component ~= nil then req_component = req_fragment_duplicate(req_component) end
if req_component == nil then req_component = true end
req_component_storage[place] = req_component
end
else
local req_component = req_fragment_default
if req_component == nil then req_component = true end
for place = b_place, e_place do
req_component_storage[place] = req_component
end
end end
component_storage[place] = new_component
end
else
if ini_component == nil then
ini_component = true
end
for place = b_place, e_place do
component_storage[place] = ini_component
end end
end end
end end
else else
for fragment, component in __lua_next, components do for component_index = 1, chunk_component_count do
local component_index = chunk_component_indices[fragment] local component_storage = chunk_component_storages[component_index]
local component_fragment = chunk_component_fragments[component_index]
if component_index then local ini_component = components[component_fragment]
local component_storage = chunk_component_storages[component_index]
local new_component = component if ini_component == nil then
if new_component == nil then new_component = true end if chunk == prefab_chunk then
for place = b_place, e_place do ini_component = component_storage[prefab_place]
component_storage[place] = new_component else
end local prefab_component_index = prefab_component_indices[component_fragment]
end if prefab_component_index then
end local prefab_component_storage = prefab_component_storages[prefab_component_index]
ini_component = prefab_component_storage[prefab_place]
for req_fragment_index = 1, req_fragment_count do else
local req_fragment = req_fragment_list[req_fragment_index] ini_component = true
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_storage = chunk_component_storages[req_component_index]
local req_component = true
for place = b_place, e_place do
req_component_storage[place] = req_component
end end
end end
end end
for place = b_place, e_place do
component_storage[place] = ini_component
end
end end
end end