From de73881f63c259d0a2e08f3fbf0b9c835dfb7525 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Wed, 19 Nov 2025 08:51:26 +0700 Subject: [PATCH] improve performance of the clone operations --- develop/ROADMAP.md | 2 + evolved.lua | 442 ++++++++++++++++----------------------------- 2 files changed, 161 insertions(+), 283 deletions(-) diff --git a/develop/ROADMAP.md b/develop/ROADMAP.md index 1be8b05..943bb0b 100644 --- a/develop/ROADMAP.md +++ b/develop/ROADMAP.md @@ -11,6 +11,8 @@ - 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 can cache default/duplicate per chunk to speed up entity creation with setup hooks. +- We need spawn/clone fuzzy tests! ## Known Issues diff --git a/evolved.lua b/evolved.lua index e332392..54ce874 100644 --- a/evolved.lua +++ b/evolved.lua @@ -2055,34 +2055,40 @@ function __spawn_entity(chunk, entity, components) local fragment_default, fragment_duplicate = __evolved_get(component_fragment, __DEFAULT, __DUPLICATE) - local new_component = components[component_fragment] + local ini_component = components[component_fragment] - if new_component == nil then - new_component = fragment_default + if ini_component == nil then + ini_component = fragment_default end - if new_component ~= nil and fragment_duplicate then - new_component = fragment_duplicate(new_component) - end + if ini_component ~= nil and fragment_duplicate then + local new_component = fragment_duplicate(ini_component) - if new_component == nil then - new_component = true - end + if new_component == nil then + new_component = true + 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 else for component_index = 1, chunk_component_count do local component_storage = chunk_component_storages[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 + if ini_component == nil then + ini_component = true end - component_storage[place] = new_component + component_storage[place] = ini_component end end @@ -2206,20 +2212,29 @@ function __multi_spawn_entity(chunk, entity_list, entity_count, components) local fragment_default, fragment_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 - local new_component = components[component_fragment] - 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 new_component = true end + local new_component = fragment_duplicate(ini_component) + + if new_component == nil then + new_component = true + end + component_storage[place] = new_component end else - local new_component = components[component_fragment] - if new_component == nil then new_component = fragment_default end - 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 - component_storage[place] = new_component + component_storage[place] = ini_component 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_fragment = chunk_component_fragments[component_index] - local new_component = components[component_fragment] - if new_component == nil then new_component = true end + local ini_component = components[component_fragment] + + if ini_component == nil then + ini_component = true + end + for place = b_place, e_place do - component_storage[place] = new_component + component_storage[place] = ini_component end end end @@ -2312,8 +2331,12 @@ function __clone_entity(prefab, entity, components) prefab_chunk.__without_unique_fragments = __chunk_without_unique_fragments(prefab_chunk) 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( - prefab_chunk and prefab_chunk.__without_unique_fragments, + prefab_chunk.__without_unique_fragments, components) if not chunk then @@ -2324,9 +2347,6 @@ function __clone_entity(prefab, entity, components) 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 req_fragment_set = __acquire_table(__table_pool_tag.fragment_set) @@ -2334,7 +2354,7 @@ function __clone_entity(prefab, entity, components) ---@type evolved.fragment[] 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) 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_count = chunk.__entity_count + local chunk_component_count = chunk.__component_count local chunk_component_indices = chunk.__component_indices 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 @@ -2362,144 +2387,69 @@ function __clone_entity(prefab, entity, components) __entity_places[entity_primary] = place 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 - for fragment, component in __lua_next, components do - local component_index = chunk_component_indices[fragment] + for component_index = 1, chunk_component_count do + local component_storage = chunk_component_storages[component_index] + local component_fragment = chunk_component_fragments[component_index] - if component_index then - local component_storage = chunk_component_storages[component_index] + ---@type evolved.default?, evolved.duplicate? + local fragment_default, fragment_duplicate = + __evolved_get(component_fragment, __DEFAULT, __DUPLICATE) - ---@type evolved.duplicate? - local fragment_duplicate = - __evolved_get(fragment, __DUPLICATE) + local ini_component = components[component_fragment] - local new_component = component - - if new_component ~= nil and fragment_duplicate then - new_component = fragment_duplicate(new_component) + if ini_component == nil then + if chunk == prefab_chunk then + ini_component = component_storage[prefab_place] + 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 + + if ini_component ~= nil and fragment_duplicate then + local new_component = fragment_duplicate(ini_component) if new_component == nil then new_component = true end 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 - 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) - - 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 + if ini_component == nil then + ini_component = true end + + component_storage[place] = ini_component end end else - for fragment, component in __lua_next, components do - local component_index = chunk_component_indices[fragment] + for component_index = 1, chunk_component_count do + local component_storage = chunk_component_storages[component_index] + local component_fragment = chunk_component_fragments[component_index] - if component_index then - local component_storage = chunk_component_storages[component_index] + local ini_component = components[component_fragment] - local new_component = component - if new_component == nil then new_component = true end - 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 - 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 + if ini_component == nil then + if chunk == prefab_chunk then + ini_component = component_storage[prefab_place] + 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 = true + end end end + + component_storage[place] = ini_component 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) 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( - prefab_chunk and prefab_chunk.__without_unique_fragments, + prefab_chunk.__without_unique_fragments, components) 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_count = 0 - local ini_chunk = chunk - local ini_fragment_set = ini_chunk.__fragment_set - if chunk.__has_required_fragments then ---@type table 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[] 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) 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_count = chunk.__entity_count + local chunk_component_count = chunk.__component_count local chunk_component_indices = chunk.__component_indices 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 e_place = chunk_entity_count + entity_count @@ -2621,155 +2577,75 @@ function __multi_clone_entity(prefab, entity_list, entity_count, components) 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 - for fragment, component in __lua_next, components do - local component_index = chunk_component_indices[fragment] + for component_index = 1, chunk_component_count do + local component_storage = chunk_component_storages[component_index] + local component_fragment = chunk_component_fragments[component_index] - if component_index then - local component_storage = chunk_component_storages[component_index] + ---@type evolved.default?, evolved.duplicate? + local fragment_default, fragment_duplicate = + __evolved_get(component_fragment, __DEFAULT, __DUPLICATE) - ---@type evolved.duplicate? - local fragment_duplicate = - __evolved_get(fragment, __DUPLICATE) + local ini_component = components[component_fragment] - if fragment_duplicate then - for place = b_place, e_place do - local new_component = 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 + if ini_component == nil then + if chunk == prefab_chunk then + ini_component = component_storage[prefab_place] else - local new_component = component - if new_component == nil then new_component = true end - for place = b_place, e_place do - component_storage[place] = new_component + 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 - for req_fragment_index = 1, req_fragment_count do - local req_fragment = req_fragment_list[req_fragment_index] + if ini_component ~= nil and fragment_duplicate then + for place = b_place, e_place do + local new_component = fragment_duplicate(ini_component) - 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] - - ---@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 + if new_component == nil then + new_component = true 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 else - for fragment, component in __lua_next, components do - local component_index = chunk_component_indices[fragment] + for component_index = 1, chunk_component_count do + local component_storage = chunk_component_storages[component_index] + local component_fragment = chunk_component_fragments[component_index] - if component_index then - local component_storage = chunk_component_storages[component_index] + local ini_component = components[component_fragment] - local new_component = 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 - - 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_storage = chunk_component_storages[req_component_index] - - local req_component = true - for place = b_place, e_place do - req_component_storage[place] = req_component + if ini_component == nil then + if chunk == prefab_chunk then + ini_component = component_storage[prefab_place] + 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 = true end end end + + for place = b_place, e_place do + component_storage[place] = ini_component + end end end