improve perf of cloning prefabs with many unique fragments

This commit is contained in:
BlackMATov
2025-09-23 07:53:11 +07:00
parent 281866cf6e
commit b1b627b677
4 changed files with 64 additions and 9 deletions

View File

@@ -1303,6 +1303,7 @@ builder_mt:destruction_policy :: id -> builder
- The internal garbage collector now collects more garbage
- Improved system processing debugging experience with stack traces on errors
- [`SET/ASSIGN hooks`](#fragment-hooks) are not invoked for tags on override operations anymore
- Improved performance of cloning prefabs with many [`Unique Fragments`](#unique-fragments)
### v1.2.0

View File

@@ -14,4 +14,3 @@
- We can return deferred status from modifying operations and spawn/clone methods.
- Should we make one builder:build method instead of :spawn and :clone?
- Should we cache the result of without_unique_fragments to clone faster?

View File

@@ -6373,3 +6373,48 @@ do
assert(evo.get(e, f) ~= v2_default)
end
end
do
local f1, f2 = evo.id(2)
local prefab = evo.builder():prefab():set(f1, 11):set(f2, 22):spawn()
do
local entity = evo.clone(prefab)
assert(evo.has(entity, f1) and evo.get(entity, f1) == 11)
assert(evo.has(entity, f2) and evo.get(entity, f2) == 22)
end
evo.set(f2, evo.UNIQUE)
do
local entity = evo.clone(prefab)
assert(evo.has(entity, f1) and evo.get(entity, f1) == 11)
assert(not evo.has(entity, f2) and evo.get(entity, f2) == nil)
end
evo.remove(f2, evo.UNIQUE)
do
local entity = evo.clone(prefab)
assert(evo.has(entity, f1) and evo.get(entity, f1) == 11)
assert(evo.has(entity, f2) and evo.get(entity, f2) == 22)
end
evo.set(f1, evo.UNIQUE)
evo.set(f2, evo.UNIQUE)
do
local entity = evo.clone(prefab)
assert(evo.empty(entity))
end
evo.remove(f1, evo.UNIQUE)
evo.remove(f2, evo.UNIQUE)
do
local entity = evo.clone(prefab)
assert(evo.has(entity, f1) and evo.get(entity, f1) == 11)
assert(evo.has(entity, f2) and evo.get(entity, f2) == 22)
end
end

View File

@@ -160,6 +160,7 @@ local __group_subsystems = {} ---@type table<evolved.system, evolved.assoc_list<
---@field package __component_fragments evolved.fragment[]
---@field package __with_fragment_edges table<evolved.fragment, evolved.chunk>
---@field package __without_fragment_edges table<evolved.fragment, evolved.chunk>
---@field package __without_unique_fragments? evolved.chunk
---@field package __unreachable_or_collected boolean
---@field package __has_setup_hooks boolean
---@field package __has_assign_hooks boolean
@@ -998,6 +999,7 @@ function __new_chunk(chunk_parent, chunk_fragment)
__component_fragments = {},
__with_fragment_edges = {},
__without_fragment_edges = {},
__without_unique_fragments = nil,
__unreachable_or_collected = false,
__has_setup_hooks = false,
__has_assign_hooks = false,
@@ -1116,6 +1118,12 @@ function __update_chunk_caches(chunk)
chunk.__has_internal_fragments = has_internal_fragments
chunk.__has_required_fragments = has_required_fragments
if has_unique_fragments then
chunk.__without_unique_fragments = nil
else
chunk.__without_unique_fragments = chunk
end
end
---@param chunk evolved.chunk
@@ -2240,13 +2248,14 @@ function __clone_entity(entity, prefab, components)
__error_fmt('clone entity operations should be deferred')
end
local prefab_primary = prefab % 2 ^ 20
local prefab_chunk, prefab_place = __evolved_locate(prefab)
local prefab_chunk = __entity_chunks[prefab_primary]
local prefab_place = __entity_places[prefab_primary]
if prefab_chunk and prefab_chunk.__has_unique_fragments and not prefab_chunk.__without_unique_fragments then
prefab_chunk.__without_unique_fragments = __chunk_without_unique_fragments(prefab_chunk)
end
local chunk = __chunk_with_components(
__chunk_without_unique_fragments(prefab_chunk),
prefab_chunk and prefab_chunk.__without_unique_fragments,
components)
if not chunk then
@@ -2491,13 +2500,14 @@ function __multi_clone_entity(entity_list, entity_count, prefab, components)
__error_fmt('clone entity operations should be deferred')
end
local prefab_primary = prefab % 2 ^ 20
local prefab_chunk, prefab_place = __evolved_locate(prefab)
local prefab_chunk = __entity_chunks[prefab_primary]
local prefab_place = __entity_places[prefab_primary]
if prefab_chunk and prefab_chunk.__has_unique_fragments and not prefab_chunk.__without_unique_fragments then
prefab_chunk.__without_unique_fragments = __chunk_without_unique_fragments(prefab_chunk)
end
local chunk = __chunk_with_components(
__chunk_without_unique_fragments(prefab_chunk),
prefab_chunk and prefab_chunk.__without_unique_fragments,
components)
if not chunk then