From 4b13b167c0988bb61288531134486bc2c09e8bff Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 28 Jan 2025 09:34:16 +0700 Subject: [PATCH] add fragment_builder:on_set/on_assign/on_insert/on_remove --- README.md | 4 + ROADMAP.md | 1 - develop/untests.lua | 77 ++++++++++++++++ evolved.lua | 208 ++++++++++++++++++++++++++++++-------------- 4 files changed, 224 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 473c0ec..6f2485f 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,10 @@ fragment :: fragment_builder fragment_builder:tag :: fragment_builder fragment_builder:default :: component -> fragment_builder fragment_builder:construct :: {any... -> component} -> fragment_builder +fragment_builder:on_set :: {entity, fragment, component, component?} -> fragment_builder +fragment_builder:on_assign :: {entity, fragment, component, component} -> fragment_builder +fragment_builder:on_insert :: {entity, fragment, component} -> fragment_builder +fragment_builder:on_remove :: {entity, fragment} -> fragment_builder fragment_builder:build :: fragment, boolean ``` diff --git a/ROADMAP.md b/ROADMAP.md index a2733f3..fccd016 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -5,7 +5,6 @@ - optimize batch operations for cases with moving entities to empty chunks - should we clear chunk's components by on_insert tag callback? - try to keep entity_chunks/places tables as arrays -- add fragment_builder:on_set/on_assign/on_insert/on_remove ## After first release diff --git a/develop/untests.lua b/develop/untests.lua index a66f42d..8f29ce2 100644 --- a/develop/untests.lua +++ b/develop/untests.lua @@ -2549,6 +2549,83 @@ do end end +do + local f1_assign_count = 0 + local f1_insert_count = 0 + local f2_set_count = 0 + local f2_remove_count = 0 + + local FB = evo.fragment() + + local f1 = FB + :on_assign(function(e, f, nc, oc) + f1_assign_count = f1_assign_count + 1 + assert(evo.is_alive(e)) + assert(evo.is_alive(f)) + assert(nc == 42) + assert(oc == 41) + end) + :on_insert(function(e, f, nc) + f1_insert_count = f1_insert_count + 1 + assert(evo.is_alive(e)) + assert(evo.is_alive(f)) + assert(nc == 41) + end) + :build() + + local f2 = FB + :on_set(function(e, f, nc, oc) + f2_set_count = f2_set_count + 1 + assert(evo.is_alive(e)) + assert(evo.is_alive(f)) + if oc then + assert(oc == 81) + assert(nc == 82) + else + assert(nc == 81) + end + end) + :on_remove(function(e, f, c) + f2_remove_count = f2_remove_count + 1 + assert(evo.is_alive(e)) + assert(evo.is_alive(f)) + assert(c == 82) + end) + :build() + + local e1 = evo.entity():set(f1, 41):build() + assert(f1_assign_count == 0 and f1_insert_count == 1) + + local e2 = evo.entity():set(f1, 42):set(f1, 41):build() + assert(f1_assign_count == 0 and f1_insert_count == 2) + + assert(evo.assign(e1, f1, 42)) + assert(f1_assign_count == 1 and f1_insert_count == 2) + + assert(evo.assign(e2, f1, 42)) + assert(f1_assign_count == 2 and f1_insert_count == 2) + + assert(evo.get(e1, f1) == 42 and evo.get(e2, f1) == 42) + + assert(evo.set(e1, f2, 81)) + assert(f2_set_count == 1) + assert(evo.set(e1, f2, 82)) + assert(f2_set_count == 2) + + assert(evo.set(e2, f2, 81)) + assert(f2_set_count == 3) + assert(evo.set(e2, f2, 82)) + assert(f2_set_count == 4) + + assert(evo.get(e1, f2) == 82 and evo.get(e2, f2) == 82) + + assert(evo.remove(e1, f1, f1, f2, f2) and evo.remove(e1, f1, f1, f2, f2)) + assert(f2_remove_count == 1) + + assert(evo.destroy(e2) and evo.destroy(e2)) + assert(f2_remove_count == 2) +end + do local f1, f2, f3 = evo.id(3) diff --git a/evolved.lua b/evolved.lua index b7b4811..7b833fd 100644 --- a/evolved.lua +++ b/evolved.lua @@ -38,8 +38,10 @@ local evolved = { ---@alias evolved.default evolved.component ---@alias evolved.construct fun(...: any): evolved.component ----@alias evolved.set_or_assign_hook fun(e: evolved.entity, f: evolved.fragment, nc: evolved.component, oc: evolved.component) ----@alias evolved.set_or_insert_hook fun(e: evolved.entity, f: evolved.fragment, nc: evolved.component) + +---@alias evolved.set_hook fun(e: evolved.entity, f: evolved.fragment, nc: evolved.component, oc?: evolved.component) +---@alias evolved.assign_hook fun(e: evolved.entity, f: evolved.fragment, nc: evolved.component, oc: evolved.component) +---@alias evolved.insert_hook fun(e: evolved.entity, f: evolved.fragment, nc: evolved.component) ---@alias evolved.remove_hook fun(e: evolved.entity, f: evolved.fragment, c: evolved.component) ---@class (exact) evolved.chunk @@ -444,7 +446,7 @@ local function __component_construct(fragment, ...) local component = ... - if construct ~= nil then + if construct then component = construct(...) end @@ -460,7 +462,7 @@ end ---@param new_component evolved.component ---@param old_component evolved.component local function __fragment_call_set_and_assign_hooks(entity, fragment, new_component, old_component) - ---@type evolved.set_or_assign_hook, evolved.set_or_assign_hook + ---@type evolved.set_hook?, evolved.assign_hook? 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 @@ -470,7 +472,7 @@ end ---@param fragment evolved.fragment ---@param new_component evolved.component local function __fragment_call_set_and_insert_hooks(entity, fragment, new_component) - ---@type evolved.set_or_insert_hook, evolved.set_or_insert_hook + ---@type evolved.set_hook?, evolved.insert_hook? 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 @@ -480,7 +482,7 @@ end ---@param fragment evolved.fragment ---@param old_component evolved.component local function __fragment_call_remove_hook(entity, fragment, old_component) - ---@type evolved.remove_hook + ---@type evolved.remove_hook? local on_remove = evolved.get(fragment, evolved.ON_REMOVE) if on_remove then on_remove(entity, fragment, old_component) end end @@ -1288,7 +1290,7 @@ local function __chunk_assign(chunk, fragment, ...) ---@type evolved.default?, evolved.construct? local fragment_default, fragment_construct - ---@type evolved.set_or_assign_hook?, evolved.set_or_assign_hook? + ---@type evolved.set_hook?, evolved.assign_hook? local fragment_on_set, fragment_on_assign do @@ -1301,29 +1303,29 @@ local function __chunk_assign(chunk, fragment, ...) end end - if fragment_on_set ~= nil or fragment_on_assign ~= nil then + if fragment_on_set or fragment_on_assign then local component_index = chunk_component_indices[fragment] if component_index then local component_storage = chunk_component_storages[component_index] - if fragment_default ~= nil or fragment_construct ~= nil then + if fragment_default ~= nil or fragment_construct then for place = 1, chunk_entity_count do local entity = chunk_entities[place] local old_component = component_storage[place] local new_component = ... - if fragment_construct ~= nil then new_component = fragment_construct(...) end + if fragment_construct then new_component = fragment_construct(...) end if new_component == nil then new_component = fragment_default end if new_component == nil then new_component = true end component_storage[place] = new_component - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment, new_component, old_component) end - if fragment_on_assign ~= nil then + if fragment_on_assign then fragment_on_assign(entity, fragment, new_component, old_component) end end @@ -1337,11 +1339,11 @@ local function __chunk_assign(chunk, fragment, ...) component_storage[place] = new_component - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment, new_component, old_component) end - if fragment_on_assign ~= nil then + if fragment_on_assign then fragment_on_assign(entity, fragment, new_component, old_component) end end @@ -1350,11 +1352,11 @@ local function __chunk_assign(chunk, fragment, ...) for place = 1, chunk_entity_count do local entity = chunk_entities[place] - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment) end - if fragment_on_assign ~= nil then + if fragment_on_assign then fragment_on_assign(entity, fragment) end end @@ -1365,10 +1367,10 @@ local function __chunk_assign(chunk, fragment, ...) if component_index then local component_storage = chunk_component_storages[component_index] - if fragment_default ~= nil or fragment_construct ~= nil then + if fragment_default ~= nil or fragment_construct then for place = 1, chunk_entity_count do local new_component = ... - if fragment_construct ~= nil then new_component = fragment_construct(...) end + if fragment_construct then new_component = fragment_construct(...) end if new_component == nil then new_component = fragment_default end if new_component == nil then new_component = true end component_storage[place] = new_component @@ -1421,7 +1423,7 @@ local function __chunk_insert(old_chunk, fragment, ...) ---@type evolved.default?, evolved.construct? local fragment_default, fragment_construct - ---@type evolved.set_or_insert_hook?, evolved.set_or_insert_hook? + ---@type evolved.set_hook?, evolved.insert_hook? local fragment_on_set, fragment_on_insert do @@ -1452,28 +1454,28 @@ local function __chunk_insert(old_chunk, fragment, ...) end end - if fragment_on_set ~= nil or fragment_on_insert ~= nil then + if fragment_on_set or fragment_on_insert then local new_component_index = new_component_indices[fragment] if new_component_index then local new_component_storage = new_component_storages[new_component_index] - if fragment_default ~= nil or fragment_construct ~= nil then + if fragment_default ~= nil or fragment_construct then for new_place = new_entity_count + 1, new_entity_count + old_entity_count do local entity = new_entities[new_place] local new_component = ... - if fragment_construct ~= nil then new_component = fragment_construct(...) end + if fragment_construct then new_component = fragment_construct(...) end if new_component == nil then new_component = fragment_default end if new_component == nil then new_component = true end new_component_storage[new_place] = new_component - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment, new_component) end - if fragment_on_insert ~= nil then + if fragment_on_insert then fragment_on_insert(entity, fragment, new_component) end end @@ -1486,11 +1488,11 @@ local function __chunk_insert(old_chunk, fragment, ...) new_component_storage[new_place] = new_component - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment, new_component) end - if fragment_on_insert ~= nil then + if fragment_on_insert then fragment_on_insert(entity, fragment, new_component) end end @@ -1498,8 +1500,14 @@ local function __chunk_insert(old_chunk, fragment, ...) else for new_place = new_entity_count + 1, new_entity_count + old_entity_count do local entity = new_entities[new_place] - if fragment_on_set ~= nil then fragment_on_set(entity, fragment) end - if fragment_on_insert ~= nil then fragment_on_insert(entity, fragment) end + + if fragment_on_set then + fragment_on_set(entity, fragment) + end + + if fragment_on_insert then + fragment_on_insert(entity, fragment) + end end end else @@ -1508,10 +1516,10 @@ local function __chunk_insert(old_chunk, fragment, ...) if new_component_index then local new_component_storage = new_component_storages[new_component_index] - if fragment_default ~= nil or fragment_construct ~= nil then + if fragment_default ~= nil or fragment_construct then for new_place = new_entity_count + 1, new_entity_count + old_entity_count do local new_component = ... - if fragment_construct ~= nil then new_component = fragment_construct(...) end + if fragment_construct then new_component = fragment_construct(...) end if new_component == nil then new_component = fragment_default end if new_component == nil then new_component = true end new_component_storage[new_place] = new_component @@ -1585,7 +1593,7 @@ local function __chunk_remove(old_chunk, ...) ---@type evolved.remove_hook? local fragment_on_remove = evolved.get(fragment, evolved.ON_REMOVE) - if fragment_on_remove ~= nil then + if fragment_on_remove then local old_component_index = old_component_indices[fragment] if old_component_index then @@ -1681,7 +1689,7 @@ local function __chunk_clear(chunk) ---@type evolved.remove_hook? local fragment_on_remove = evolved.get(fragment, evolved.ON_REMOVE) - if fragment_on_remove ~= nil then + if fragment_on_remove then local component_index = chunk_component_indices[fragment] if component_index then @@ -1742,7 +1750,7 @@ local function __chunk_destroy(chunk) ---@type evolved.remove_hook? local fragment_on_remove = evolved.get(fragment, evolved.ON_REMOVE) - if fragment_on_remove ~= nil then + if fragment_on_remove then local component_index = chunk_component_indices[fragment] if component_index then @@ -1820,7 +1828,7 @@ local function __chunk_multi_set(old_chunk, fragments, components) ---@type evolved.default? local fragment_default - ---@type evolved.set_or_assign_hook?, evolved.set_or_assign_hook? + ---@type evolved.set_hook?, evolved.assign_hook? local fragment_on_set, fragment_on_assign do @@ -1833,7 +1841,7 @@ local function __chunk_multi_set(old_chunk, fragments, components) end end - if fragment_on_set ~= nil or fragment_on_assign ~= nil then + if fragment_on_set or fragment_on_assign then local old_component_index = old_component_indices[fragment] if old_component_index then @@ -1849,11 +1857,11 @@ local function __chunk_multi_set(old_chunk, fragments, components) old_component_storage[place] = new_component - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment, new_component, old_component) end - if fragment_on_assign ~= nil then + if fragment_on_assign then fragment_on_assign(entity, fragment, new_component, old_component) end end @@ -1861,11 +1869,11 @@ local function __chunk_multi_set(old_chunk, fragments, components) for place = 1, old_entity_count do local entity = old_entities[place] - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment) end - if fragment_on_assign ~= nil then + if fragment_on_assign then fragment_on_assign(entity, fragment) end end @@ -1926,7 +1934,7 @@ local function __chunk_multi_set(old_chunk, fragments, components) ---@type evolved.default? local fragment_default - ---@type evolved.set_or_assign_hook?, evolved.set_or_assign_hook? + ---@type evolved.set_hook?, evolved.assign_hook? local fragment_on_set, fragment_on_assign do @@ -1939,7 +1947,7 @@ local function __chunk_multi_set(old_chunk, fragments, components) end end - if fragment_on_set ~= nil or fragment_on_assign ~= nil then + if fragment_on_set or fragment_on_assign then local new_component_index = new_component_indices[fragment] if new_component_index then local new_component_storage = new_component_storages[new_component_index] @@ -1954,11 +1962,11 @@ local function __chunk_multi_set(old_chunk, fragments, components) new_component_storage[new_place] = new_component - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment, new_component, old_component) end - if fragment_on_assign ~= nil then + if fragment_on_assign then fragment_on_assign(entity, fragment, new_component, old_component) end end @@ -1966,11 +1974,11 @@ local function __chunk_multi_set(old_chunk, fragments, components) for new_place = new_entity_count + 1, new_entity_count + old_entity_count do local entity = new_entities[new_place] - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment) end - if fragment_on_assign ~= nil then + if fragment_on_assign then fragment_on_assign(entity, fragment) end end @@ -1998,7 +2006,7 @@ local function __chunk_multi_set(old_chunk, fragments, components) ---@type evolved.default? local fragment_default - ---@type evolved.set_or_insert_hook?, evolved.set_or_insert_hook? + ---@type evolved.set_hook?, evolved.insert_hook? local fragment_on_set, fragment_on_insert do @@ -2011,7 +2019,7 @@ local function __chunk_multi_set(old_chunk, fragments, components) end end - if fragment_on_set ~= nil or fragment_on_insert ~= nil then + if fragment_on_set or fragment_on_insert then local new_component_index = new_component_indices[fragment] if new_component_index then @@ -2026,11 +2034,11 @@ local function __chunk_multi_set(old_chunk, fragments, components) new_component_storage[new_place] = new_component - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment, new_component) end - if fragment_on_insert ~= nil then + if fragment_on_insert then fragment_on_insert(entity, fragment, new_component) end end @@ -2038,11 +2046,11 @@ local function __chunk_multi_set(old_chunk, fragments, components) for new_place = new_entity_count + 1, new_entity_count + old_entity_count do local entity = new_entities[new_place] - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment) end - if fragment_on_insert ~= nil then + if fragment_on_insert then fragment_on_insert(entity, fragment) end end @@ -2122,7 +2130,7 @@ local function __chunk_multi_assign(chunk, fragments, components) ---@type evolved.default? local fragment_default - ---@type evolved.set_or_assign_hook?, evolved.set_or_assign_hook? + ---@type evolved.set_hook?, evolved.assign_hook? local fragment_on_set, fragment_on_assign do @@ -2135,7 +2143,7 @@ local function __chunk_multi_assign(chunk, fragments, components) end end - if fragment_on_set ~= nil or fragment_on_assign ~= nil then + if fragment_on_set or fragment_on_assign then local component_index = chunk_component_indices[fragment] if component_index then @@ -2151,11 +2159,11 @@ local function __chunk_multi_assign(chunk, fragments, components) component_storage[place] = new_component - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment, new_component, old_component) end - if fragment_on_assign ~= nil then + if fragment_on_assign then fragment_on_assign(entity, fragment, new_component, old_component) end end @@ -2163,11 +2171,11 @@ local function __chunk_multi_assign(chunk, fragments, components) for place = 1, chunk_entity_count do local entity = chunk_entities[place] - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment) end - if fragment_on_assign ~= nil then + if fragment_on_assign then fragment_on_assign(entity, fragment) end end @@ -2261,7 +2269,7 @@ local function __chunk_multi_insert(old_chunk, fragments, components) ---@type evolved.default? local fragment_default - ---@type evolved.set_or_insert_hook?, evolved.set_or_insert_hook? + ---@type evolved.set_hook?, evolved.insert_hook? local fragment_on_set, fragment_on_insert do @@ -2274,7 +2282,7 @@ local function __chunk_multi_insert(old_chunk, fragments, components) end end - if fragment_on_set ~= nil or fragment_on_insert ~= nil then + if fragment_on_set or fragment_on_insert then local new_component_index = new_component_indices[fragment] if new_component_index then @@ -2289,11 +2297,11 @@ local function __chunk_multi_insert(old_chunk, fragments, components) new_component_storage[new_place] = new_component - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment, new_component) end - if fragment_on_insert ~= nil then + if fragment_on_insert then fragment_on_insert(entity, fragment, new_component) end end @@ -2301,11 +2309,11 @@ local function __chunk_multi_insert(old_chunk, fragments, components) for new_place = new_entity_count + 1, new_entity_count + old_entity_count do local entity = new_entities[new_place] - if fragment_on_set ~= nil then + if fragment_on_set then fragment_on_set(entity, fragment) end - if fragment_on_insert ~= nil then + if fragment_on_insert then fragment_on_insert(entity, fragment) end end @@ -2387,7 +2395,7 @@ local function __chunk_multi_remove(old_chunk, fragments) ---@type evolved.remove_hook? local fragment_on_remove = evolved.get(fragment, evolved.ON_REMOVE) - if fragment_on_remove ~= nil then + if fragment_on_remove then local old_component_index = old_component_indices[fragment] if old_component_index then @@ -5453,6 +5461,10 @@ end ---@field package __tag boolean ---@field package __default? evolved.component ---@field package __construct? fun(...): evolved.component +---@field package __on_set? evolved.set_hook +---@field package __on_assign? evolved.set_hook +---@field package __on_insert? evolved.set_hook +---@field package __on_remove? evolved.remove_hook ---@class evolved.fragment_builder : evolved.__fragment_builder local evolved_fragment_builder = {} @@ -5466,6 +5478,10 @@ function evolved.fragment() __tag = false, __default = nil, __construct = nil, + __on_set = nil, + __on_assign = nil, + __on_insert = nil, + __on_remove = nil, } ---@cast builder evolved.fragment_builder return setmetatable(builder, evolved_fragment_builder) @@ -5491,6 +5507,34 @@ function evolved_fragment_builder:construct(construct) return self end +---@param on_set evolved.set_hook +---@return evolved.fragment_builder builder +function evolved_fragment_builder:on_set(on_set) + self.__on_set = on_set + return self +end + +---@param on_assign evolved.assign_hook +---@return evolved.fragment_builder builder +function evolved_fragment_builder:on_assign(on_assign) + self.__on_assign = on_assign + return self +end + +---@param on_insert evolved.insert_hook +---@return evolved.fragment_builder builder +function evolved_fragment_builder:on_insert(on_insert) + self.__on_insert = on_insert + return self +end + +---@param on_remove evolved.remove_hook +---@return evolved.fragment_builder builder +function evolved_fragment_builder:on_remove(on_remove) + self.__on_remove = on_remove + return self +end + ---@return evolved.fragment fragment ---@return boolean is_deferred function evolved_fragment_builder:build() @@ -5498,10 +5542,20 @@ function evolved_fragment_builder:build() local default = self.__default local construct = self.__construct + local on_set = self.__on_set + local on_assign = self.__on_assign + local on_insert = self.__on_insert + local on_remove = self.__on_remove + self.__tag = false self.__default = nil self.__construct = nil + self.__on_set = nil + self.__on_assign = nil + self.__on_insert = nil + self.__on_remove = nil + local fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST) local component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST) local component_count = 0 @@ -5518,12 +5572,36 @@ function evolved_fragment_builder:build() component_list[component_count] = default end - if construct ~= nil then + if construct then component_count = component_count + 1 fragment_list[component_count] = evolved.CONSTRUCT component_list[component_count] = construct end + if on_set then + component_count = component_count + 1 + fragment_list[component_count] = evolved.ON_SET + component_list[component_count] = on_set + end + + if on_assign then + component_count = component_count + 1 + fragment_list[component_count] = evolved.ON_ASSIGN + component_list[component_count] = on_assign + end + + if on_insert then + component_count = component_count + 1 + fragment_list[component_count] = evolved.ON_INSERT + component_list[component_count] = on_insert + end + + if on_remove then + component_count = component_count + 1 + fragment_list[component_count] = evolved.ON_REMOVE + component_list[component_count] = on_remove + end + if component_count == 0 then return evolved.id(), false end