From 46d11856a6f5618769e5fb72d8d16c0921ef19c4 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 3 Jan 2025 03:34:29 +0700 Subject: [PATCH] opt: has_set/assign/insert/remove_hooks flags for chunks --- ROADMAP.md | 1 - evolved.lua | 231 +++++++++++++++++++++++++++++++--------------------- 2 files changed, 140 insertions(+), 92 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index db86606..1a8299f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,7 +4,6 @@ - should insert/assign throw errors on failure? - add auto chunk count reducing -- every chunk can hold has_on_assign/has_on_insert/has_on_remove tags - optimize batch operations for cases with moving entities to empty chunks - should we clear chunk's components by on_insert tag callback? - replace id type aliases with separated types to hide implementation details diff --git a/evolved.lua b/evolved.lua index f8865f3..5d66187 100644 --- a/evolved.lua +++ b/evolved.lua @@ -42,6 +42,9 @@ local evolved = { ---@field package __components table ---@field package __with_fragment_edges table ---@field package __without_fragment_edges table +---@field package __has_set_or_assign_hooks boolean +---@field package __has_set_or_insert_hooks boolean +---@field package __has_remove_hooks boolean ---@class (exact) evolved.each_state ---@field package [1] integer structural_changes @@ -368,7 +371,7 @@ end ---@param fragment evolved.fragment ---@param new_component evolved.component ---@param old_component evolved.component -local function __fragment_on_set_and_assign(entity, fragment, new_component, old_component) +local function __fragment_call_set_and_assign_hooks(entity, fragment, new_component, old_component) local on_set, on_assign = evolved.get(fragment, evolved.ON_SET, evolved.ON_ASSIGN) if on_set then on_set(entity, fragment, new_component, old_component) end if on_assign then on_assign(entity, fragment, new_component, old_component) end @@ -377,7 +380,7 @@ end ---@param entity evolved.entity ---@param fragment evolved.fragment ---@param new_component evolved.component -local function __fragment_on_set_and_insert(entity, fragment, new_component) +local function __fragment_call_set_and_insert_hooks(entity, fragment, new_component) local on_set, on_insert = evolved.get(fragment, evolved.ON_SET, evolved.ON_INSERT) if on_set then on_set(entity, fragment, new_component) end if on_insert then on_insert(entity, fragment, new_component) end @@ -386,7 +389,7 @@ end ---@param entity evolved.entity ---@param fragment evolved.fragment ---@param old_component evolved.component -local function __fragment_on_remove(entity, fragment, old_component) +local function __fragment_call_remove_hook(entity, fragment, old_component) local on_remove = evolved.get(fragment, evolved.ON_REMOVE) if on_remove then on_remove(entity, fragment, old_component) end end @@ -401,21 +404,21 @@ end ---@param fragment evolved.fragment ---@return boolean ---@nodiscard -local function __fragment_has_on_set_or_assign(fragment) +local function __fragment_has_set_or_assign_hooks(fragment) return evolved.has_any(fragment, evolved.ON_SET, evolved.ON_ASSIGN) end ---@param fragment evolved.fragment ---@return boolean ---@nodiscard -local function __fragment_has_on_set_or_insert(fragment) +local function __fragment_has_set_or_insert_hooks(fragment) return evolved.has_any(fragment, evolved.ON_SET, evolved.ON_INSERT) end ---@param fragment evolved.fragment ---@return boolean ---@nodiscard -local function __fragment_has_on_remove(fragment) +local function __fragment_has_remove_hook(fragment) return evolved.has(fragment, evolved.ON_REMOVE) end @@ -434,6 +437,10 @@ local function __root_chunk(fragment) if root_chunk then return root_chunk end end + local has_set_or_assign_hooks = __fragment_has_set_or_assign_hooks(fragment) + local has_set_or_insert_hooks = __fragment_has_set_or_insert_hooks(fragment) + local has_remove_hooks = __fragment_has_remove_hook(fragment) + ---@type evolved.chunk local root_chunk = { __parent = nil, @@ -444,6 +451,9 @@ local function __root_chunk(fragment) __components = {}, __with_fragment_edges = {}, __without_fragment_edges = {}, + __has_set_or_assign_hooks = has_set_or_assign_hooks, + __has_set_or_insert_hooks = has_set_or_insert_hooks, + __has_remove_hooks = has_remove_hooks, } do @@ -506,6 +516,10 @@ local function __chunk_with_fragment(chunk, fragment) return sibling_chunk end + local has_set_or_assign_hooks = chunk.__has_set_or_assign_hooks or __fragment_has_set_or_assign_hooks(fragment) + local has_set_or_insert_hooks = chunk.__has_set_or_insert_hooks or __fragment_has_set_or_insert_hooks(fragment) + local has_remove_hooks = chunk.__has_remove_hooks or __fragment_has_remove_hook(fragment) + ---@type evolved.chunk local child_chunk = { __parent = chunk, @@ -516,6 +530,9 @@ local function __chunk_with_fragment(chunk, fragment) __components = {}, __with_fragment_edges = {}, __without_fragment_edges = {}, + __has_set_or_assign_hooks = has_set_or_assign_hooks, + __has_set_or_insert_hooks = has_set_or_insert_hooks, + __has_remove_hooks = has_remove_hooks, } do @@ -758,7 +775,7 @@ local function __chunk_assign(chunk, fragment, ...) local chunk_size = #chunk_entities local chunk_fragment_components = chunk_components[fragment] - if __fragment_has_on_set_or_assign(fragment) then + if chunk.__has_set_or_assign_hooks and __fragment_has_set_or_assign_hooks(fragment) then if chunk_fragment_components then if __fragment_has_default_or_construct(fragment) then for place = 1, chunk_size do @@ -766,7 +783,7 @@ local function __chunk_assign(chunk, fragment, ...) local old_component = chunk_fragment_components[place] local new_component = __component_construct(entity, fragment, ...) chunk_fragment_components[place] = new_component - __fragment_on_set_and_assign(entity, fragment, new_component, old_component) + __fragment_call_set_and_assign_hooks(entity, fragment, new_component, old_component) end else local new_component = ... @@ -779,13 +796,13 @@ local function __chunk_assign(chunk, fragment, ...) local entity = chunk_entities[place] local old_component = chunk_fragment_components[place] chunk_fragment_components[place] = new_component - __fragment_on_set_and_assign(entity, fragment, new_component, old_component) + __fragment_call_set_and_assign_hooks(entity, fragment, new_component, old_component) end end else for place = 1, chunk_size do local entity = chunk_entities[place] - __fragment_on_set_and_assign(entity, fragment) + __fragment_call_set_and_assign_hooks(entity, fragment) end end else @@ -853,14 +870,14 @@ local function __chunk_insert(chunk, fragment, ...) end end - if __fragment_has_on_set_or_insert(fragment) then + if new_chunk.__has_set_or_insert_hooks and __fragment_has_set_or_insert_hooks(fragment) then if new_chunk_fragment_components then if __fragment_has_default_or_construct(fragment) then for new_place = new_chunk_size + 1, new_chunk_size + old_chunk_size do local entity = new_chunk_entities[new_place] local new_component = __component_construct(entity, fragment, ...) new_chunk_fragment_components[new_place] = new_component - __fragment_on_set_and_insert(entity, fragment, new_component) + __fragment_call_set_and_insert_hooks(entity, fragment, new_component) end else local new_component = ... @@ -872,13 +889,13 @@ local function __chunk_insert(chunk, fragment, ...) for new_place = new_chunk_size + 1, new_chunk_size + old_chunk_size do local entity = new_chunk_entities[new_place] new_chunk_fragment_components[new_place] = new_component - __fragment_on_set_and_insert(entity, fragment, new_component) + __fragment_call_set_and_insert_hooks(entity, fragment, new_component) end end else for new_place = new_chunk_size + 1, new_chunk_size + old_chunk_size do local entity = new_chunk_entities[new_place] - __fragment_on_set_and_insert(entity, fragment) + __fragment_call_set_and_insert_hooks(entity, fragment) end end else @@ -946,20 +963,24 @@ local function __chunk_remove(chunk, ...) local old_chunk_size = #old_chunk_entities - for i = 1, select('#', ...) do - local fragment = select(i, ...) - if old_chunk_fragments[fragment] and __fragment_has_on_remove(fragment) then - local old_chunk_fragment_components = old_chunk_components[fragment] - if old_chunk_fragment_components then - for old_place = 1, old_chunk_size do - local entity = old_chunk_entities[old_place] - local old_component = old_chunk_fragment_components[old_place] - __fragment_on_remove(entity, fragment, old_component) - end - else - for old_place = 1, old_chunk_size do - local entity = old_chunk_entities[old_place] - __fragment_on_remove(entity, fragment) + if old_chunk.__has_remove_hooks then + for i = 1, select('#', ...) do + local fragment = select(i, ...) + if old_chunk_fragments[fragment] then + if __fragment_has_remove_hook(fragment) then + local old_chunk_fragment_components = old_chunk_components[fragment] + if old_chunk_fragment_components then + for old_place = 1, old_chunk_size do + local entity = old_chunk_entities[old_place] + local old_component = old_chunk_fragment_components[old_place] + __fragment_call_remove_hook(entity, fragment, old_component) + end + else + for old_place = 1, old_chunk_size do + local entity = old_chunk_entities[old_place] + __fragment_call_remove_hook(entity, fragment) + end + end end end end @@ -1023,19 +1044,21 @@ local function __chunk_clear(chunk) local chunk_size = #chunk_entities - for fragment, _ in pairs(chunk_fragments) do - if __fragment_has_on_remove(fragment) then - local chunk_fragment_components = chunk_components[fragment] - if chunk_fragment_components then - for place = 1, chunk_size do - local entity = chunk_entities[place] - local old_component = chunk_fragment_components[place] - __fragment_on_remove(entity, fragment, old_component) - end - else - for place = 1, chunk_size do - local entity = chunk_entities[place] - __fragment_on_remove(entity, fragment) + if chunk.__has_remove_hooks then + for fragment, _ in pairs(chunk_fragments) do + if __fragment_has_remove_hook(fragment) then + local chunk_fragment_components = chunk_components[fragment] + if chunk_fragment_components then + for place = 1, chunk_size do + local entity = chunk_entities[place] + local old_component = chunk_fragment_components[place] + __fragment_call_remove_hook(entity, fragment, old_component) + end + else + for place = 1, chunk_size do + local entity = chunk_entities[place] + __fragment_call_remove_hook(entity, fragment) + end end end end @@ -1074,19 +1097,21 @@ local function __chunk_destroy(chunk) local chunk_size = #chunk_entities - for fragment, _ in pairs(chunk_fragments) do - if __fragment_has_on_remove(fragment) then - local chunk_fragment_components = chunk_components[fragment] - if chunk_fragment_components then - for place = 1, chunk_size do - local entity = chunk_entities[place] - local old_component = chunk_fragment_components[place] - __fragment_on_remove(entity, fragment, old_component) - end - else - for place = 1, chunk_size do - local entity = chunk_entities[place] - __fragment_on_remove(entity, fragment) + if chunk.__has_remove_hooks then + for fragment, _ in pairs(chunk_fragments) do + if __fragment_has_remove_hook(fragment) then + local chunk_fragment_components = chunk_components[fragment] + if chunk_fragment_components then + for place = 1, chunk_size do + local entity = chunk_entities[place] + local old_component = chunk_fragment_components[place] + __fragment_call_remove_hook(entity, fragment, old_component) + end + else + for place = 1, chunk_size do + local entity = chunk_entities[place] + __fragment_call_remove_hook(entity, fragment) + end end end end @@ -1713,9 +1738,13 @@ function evolved.set(entity, fragment, ...) local old_component = old_chunk_fragment_components[old_place] local new_component = __component_construct(entity, fragment, ...) old_chunk_fragment_components[old_place] = new_component - __fragment_on_set_and_assign(entity, fragment, new_component, old_component) + if old_chunk.__has_set_or_assign_hooks then + __fragment_call_set_and_assign_hooks(entity, fragment, new_component, old_component) + end else - __fragment_on_set_and_assign(entity, fragment) + if old_chunk.__has_set_or_assign_hooks then + __fragment_call_set_and_assign_hooks(entity, fragment) + end end return true, false @@ -1732,9 +1761,13 @@ function evolved.set(entity, fragment, ...) if new_chunk_fragment_components then local new_component = __component_construct(entity, fragment, ...) new_chunk_fragment_components[new_place] = new_component - __fragment_on_set_and_insert(entity, fragment, new_component) + if new_chunk.__has_set_or_insert_hooks then + __fragment_call_set_and_insert_hooks(entity, fragment, new_component) + end else - __fragment_on_set_and_insert(entity, fragment) + if new_chunk.__has_set_or_insert_hooks then + __fragment_call_set_and_insert_hooks(entity, fragment) + end end if old_chunk then @@ -1790,9 +1823,13 @@ function evolved.assign(entity, fragment, ...) local old_component = chunk_fragment_components[place] local new_component = __component_construct(entity, fragment, ...) chunk_fragment_components[place] = new_component - __fragment_on_set_and_assign(entity, fragment, new_component, old_component) + if chunk.__has_set_or_assign_hooks then + __fragment_call_set_and_assign_hooks(entity, fragment, new_component, old_component) + end else - __fragment_on_set_and_assign(entity, fragment) + if chunk.__has_set_or_assign_hooks then + __fragment_call_set_and_assign_hooks(entity, fragment) + end end return true, false @@ -1836,9 +1873,13 @@ function evolved.insert(entity, fragment, ...) if new_chunk_fragment_components then local new_component = __component_construct(entity, fragment, ...) new_chunk_fragment_components[new_place] = new_component - __fragment_on_set_and_insert(entity, fragment, new_component) + if new_chunk.__has_set_or_insert_hooks then + __fragment_call_set_and_insert_hooks(entity, fragment, new_component) + end else - __fragment_on_set_and_insert(entity, fragment) + if new_chunk.__has_set_or_insert_hooks then + __fragment_call_set_and_insert_hooks(entity, fragment) + end end if old_chunk then @@ -1893,15 +1934,19 @@ function evolved.remove(entity, ...) local old_chunk_fragments = old_chunk.__fragments local old_chunk_components = old_chunk.__components - for i = 1, select('#', ...) do - local fragment = select(i, ...) - if old_chunk_fragments[fragment] and __fragment_has_on_remove(fragment) then - local old_chunk_fragment_components = old_chunk_components[fragment] - if old_chunk_fragment_components then - local old_component = old_chunk_fragment_components[old_place] - __fragment_on_remove(entity, fragment, old_component) - else - __fragment_on_remove(entity, fragment) + if old_chunk.__has_remove_hooks then + for i = 1, select('#', ...) do + local fragment = select(i, ...) + if old_chunk_fragments[fragment] then + if __fragment_has_remove_hook(fragment) then + local old_chunk_fragment_components = old_chunk_components[fragment] + if old_chunk_fragment_components then + local old_component = old_chunk_fragment_components[old_place] + __fragment_call_remove_hook(entity, fragment, old_component) + else + __fragment_call_remove_hook(entity, fragment) + end + end end end end @@ -1959,17 +2004,19 @@ function evolved.clear(entity) __defer() do - local chunk_fragments = chunk.__fragments - local chunk_components = chunk.__components + if chunk.__has_remove_hooks then + local chunk_fragments = chunk.__fragments + local chunk_components = chunk.__components - for fragment, _ in pairs(chunk_fragments) do - if __fragment_has_on_remove(fragment) then - local chunk_fragment_components = chunk_components[fragment] - if chunk_fragment_components then - local old_component = chunk_fragment_components[place] - __fragment_on_remove(entity, fragment, old_component) - else - __fragment_on_remove(entity, fragment) + for fragment, _ in pairs(chunk_fragments) do + if __fragment_has_remove_hook(fragment) then + local chunk_fragment_components = chunk_components[fragment] + if chunk_fragment_components then + local old_component = chunk_fragment_components[place] + __fragment_call_remove_hook(entity, fragment, old_component) + else + __fragment_call_remove_hook(entity, fragment) + end end end end @@ -2007,17 +2054,19 @@ function evolved.destroy(entity) __defer() do - local chunk_fragments = chunk.__fragments - local chunk_components = chunk.__components + if chunk.__has_remove_hooks then + local chunk_fragments = chunk.__fragments + local chunk_components = chunk.__components - for fragment, _ in pairs(chunk_fragments) do - if __fragment_has_on_remove(fragment) then - local chunk_fragment_components = chunk_components[fragment] - if chunk_fragment_components then - local old_component = chunk_fragment_components[place] - __fragment_on_remove(entity, fragment, old_component) - else - __fragment_on_remove(entity, fragment) + for fragment, _ in pairs(chunk_fragments) do + if __fragment_has_remove_hook(fragment) then + local chunk_fragment_components = chunk_components[fragment] + if chunk_fragment_components then + local old_component = chunk_fragment_components[place] + __fragment_call_remove_hook(entity, fragment, old_component) + else + __fragment_call_remove_hook(entity, fragment) + end end end end