diff --git a/README.md b/README.md index 74897c5..3bc90cf 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ ON_SET :: fragment ON_ASSIGN :: fragment ON_INSERT :: fragment ON_REMOVE :: fragment +ON_DESTROY :: fragment PHASE :: fragment AFTER :: fragment @@ -43,6 +44,9 @@ EXECUTE :: fragment PROLOGUE :: fragment EPILOGUE :: fragment + +DESTROY_ENTITY_POLICY :: id +REMOVE_FRAGMENT_POLICY :: id ``` ## Functions @@ -90,6 +94,7 @@ batch_multi_remove :: query, fragment[] -> integer, boolean chunk :: fragment... -> chunk?, entity[]?, integer? select :: chunk, fragment... -> component[]... +entities :: chunk -> entity[], integer each :: entity -> {each_state? -> fragment?, component?}, each_state? execute :: query -> {execute_state? -> chunk?, entity[]?, integer?}, execute_state? @@ -119,6 +124,7 @@ fragment_builder:on_set :: {entity, fragment, component, component?} -> fragment 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:on_destroy :: id -> fragment_builder fragment_builder:build :: fragment, boolean ``` diff --git a/ROADMAP.md b/ROADMAP.md index c0181bd..2030052 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,6 +2,7 @@ ## Backlog +- add manual gc for unreachable chunks - add destroing policies (fragments, phases, systems) - add debug view for chunks with help of NAME fragment traits diff --git a/develop/untests.lua b/develop/untests.lua index 1997500..4a49246 100644 --- a/develop/untests.lua +++ b/develop/untests.lua @@ -6651,3 +6651,471 @@ do assert(evo.get(s, s) == nil) end end + +do + local f1, f2 = evo.id(2) + + local c1 = assert(evo.chunk(f1)) + local c2 = assert(evo.chunk(f2)) + local c12 = assert(evo.chunk(f1, f2)) + + local e1a = evo.entity():set(f1, 1):build() + local e1b = evo.entity():set(f1, 2):build() + + local e12a = evo.entity():set(f1, 3):set(f2, 4):build() + local e12b = evo.entity():set(f1, 5):set(f2, 6):build() + + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 2 and c1_ec == 2) + assert(c1_es[1] == e1a and c1_es[2] == e1b) + + local c2_es, c2_ec = evo.entities(c2) + assert(c2_es and #c2_es == 0 and c2_ec == 0) + + local c12_es, c12_ec = evo.entities(c12) + assert(c12_es and #c12_es == 2 and c12_ec == 2) + assert(c12_es[1] == e12a and c12_es[2] == e12b) + end + + assert(evo.remove(e12a, f1) and evo.remove(e12b, f1)) + assert(evo.insert(e1a, f2, 7) and evo.insert(e1b, f2, 8)) + + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 0 and c1_ec == 0) + + local c2_es, c2_ec = evo.entities(c2) + assert(c2_es and #c2_es == 2 and c2_ec == 2) + assert(c2_es[1] == e12a and c2_es[2] == e12b) + + local c12_es, c12_ec = evo.entities(c12) + assert(c12_es and #c12_es == 2 and c12_ec == 2) + assert(c12_es[1] == e1a and c12_es[2] == e1b) + end +end + +do + local f1, f2 = evo.id(2) + local c1 = assert(evo.chunk(f1)) + assert(evo.set(f2, f1)) + assert(evo.destroy(f1)) + do + assert(not evo.is_alive(f1)) + assert(evo.is_alive(f2)) + assert(evo.is_empty(f2)) + + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 0 and c1_ec == 0) + end +end + +do + local f1 = evo.id() + local c1 = assert(evo.chunk(f1)) + assert(evo.set(f1, f1)) + assert(evo.destroy(f1)) + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 0 and c1_ec == 0) + end +end + +do + local f1, f2 = evo.id(2) + local c1 = assert(evo.chunk(f1)) + local c2 = assert(evo.chunk(f2)) + local c12 = assert(evo.chunk(f1, f2)) + assert(evo.set(f1, evo.ON_DESTROY, evo.REMOVE_FRAGMENT_POLICY)) + assert(evo.set(f1, f1)) + assert(evo.set(f2, f1)) + assert(evo.set(f2, f2)) + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 0 and c1_ec == 0) + + local c2_es, c2_ec = evo.entities(c2) + assert(c2_es and #c2_es == 0 and c2_ec == 0) + + local c12_es, c12_ec = evo.entities(c12) + assert(c12_es and #c12_es == 1 and c12_ec == 1) + assert(c12_es[1] == f2) + end + assert(evo.destroy(f1)) + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 0 and c1_ec == 0) + + local c2_es, c2_ec = evo.entities(c2) + assert(c2_es and #c2_es == 1 and c2_ec == 1) + assert(c2_es[1] == f2) + + local c12_es, c12_ec = evo.entities(c12) + assert(c12_es and #c12_es == 0 and c12_ec == 0) + end +end + +do + local f1, f2 = evo.id(2) + local c1 = assert(evo.chunk(f1)) + local c2 = assert(evo.chunk(f2)) + local c12 = assert(evo.chunk(f1, f2)) + assert(evo.set(f1, evo.ON_DESTROY, evo.DESTROY_ENTITY_POLICY)) + assert(evo.set(f1, f1)) + assert(evo.set(f2, f1)) + assert(evo.set(f2, f2)) + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 0 and c1_ec == 0) + + local c2_es, c2_ec = evo.entities(c2) + assert(c2_es and #c2_es == 0 and c2_ec == 0) + + local c12_es, c12_ec = evo.entities(c12) + assert(c12_es and #c12_es == 1 and c12_ec == 1) + assert(c12_es[1] == f2) + end + assert(evo.destroy(f1)) + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 0 and c1_ec == 0) + + local c2_es, c2_ec = evo.entities(c2) + assert(c2_es and #c2_es == 0 and c2_ec == 0) + + local c12_es, c12_ec = evo.entities(c12) + assert(c12_es and #c12_es == 0 and c12_ec == 0) + end +end + +do + local f1, f2, f3 = evo.id(3) + local c1 = assert(evo.chunk(f1)) + local c2 = assert(evo.chunk(f2)) + assert(evo.set(f2, f1)) + assert(evo.set(f3, f2)) + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 1 and c1_ec == 1) + assert(c1_es[1] == f2) + + local c2_es, c2_ec = evo.entities(c2) + assert(c2_es and #c2_es == 1 and c2_ec == 1) + assert(c2_es[1] == f3) + end + assert(evo.destroy(f1)) + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 0 and c1_ec == 0) + + local c2_es, c2_ec = evo.entities(c2) + assert(c2_es and #c2_es == 1 and c2_ec == 1) + assert(c2_es[1] == f3) + end +end + +do + local f1, f2, f3 = evo.id(3) + local c1 = assert(evo.chunk(f1)) + local c2 = assert(evo.chunk(f2)) + assert(evo.set(f1, evo.ON_DESTROY, evo.REMOVE_FRAGMENT_POLICY)) + assert(evo.set(f2, f1)) + assert(evo.set(f3, f2)) + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 1 and c1_ec == 1) + assert(c1_es[1] == f2) + + local c2_es, c2_ec = evo.entities(c2) + assert(c2_es and #c2_es == 1 and c2_ec == 1) + assert(c2_es[1] == f3) + end + assert(evo.destroy(f1)) + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 0 and c1_ec == 0) + + local c2_es, c2_ec = evo.entities(c2) + assert(c2_es and #c2_es == 1 and c2_ec == 1) + assert(c2_es[1] == f3) + end +end + +do + local f1, f2, f3 = evo.id(3) + local c1 = assert(evo.chunk(f1)) + local c2 = assert(evo.chunk(f2)) + assert(evo.set(f1, evo.ON_DESTROY, evo.DESTROY_ENTITY_POLICY)) + assert(evo.set(f2, f1)) + assert(evo.set(f3, f2)) + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 1 and c1_ec == 1) + assert(c1_es[1] == f2) + + local c2_es, c2_ec = evo.entities(c2) + assert(c2_es and #c2_es == 1 and c2_ec == 1) + assert(c2_es[1] == f3) + end + assert(evo.destroy(f1)) + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 0 and c1_ec == 0) + + local c2_es, c2_ec = evo.entities(c2) + assert(c2_es and #c2_es == 0 and c2_ec == 0) + end +end + +do + local f1, f2, f3, f4, ft = evo.id(5) + assert(evo.set(f1, ft)) + assert(evo.set(f2, ft)) + assert(evo.set(f3, ft)) + assert(evo.set(f3, evo.ON_DESTROY, evo.DESTROY_ENTITY_POLICY)) + local qt = evo.query():include(ft):build() + + local c4 = assert(evo.chunk(f4)) + local c14 = assert(evo.chunk(f1, f4)) + local c24 = assert(evo.chunk(f2, f4)) + local c234 = assert(evo.chunk(f2, f3, f4)) + local c124 = assert(evo.chunk(f1, f2, f4)) + + local e14 = evo.entity():set(f1, 1):set(f4, 2):build() + local e24 = evo.entity():set(f2, 3):set(f4, 4):build() + local e234 = evo.entity():set(f2, 5):set(f3, 6):set(f4, 7):build() + local e124 = evo.entity():set(f1, 8):set(f2, 6):set(f4, 9):build() + + assert(evo.batch_destroy(qt)) + + do + local c4_es, c4_ec = evo.entities(c4) + assert(c4_es and #c4_es == 3 and c4_ec == 3) + assert(c4_es[1] == e14 and c4_es[2] == e24 and c4_es[3] == e124) + end + + assert(#evo.entities(c14) == 0) + assert(#evo.entities(c24) == 0) + assert(#evo.entities(c124) == 0) + assert(#evo.entities(c234) == 0) + + assert(evo.is_alive(e14) and not evo.is_empty(e14)) + assert(evo.is_alive(e24) and not evo.is_empty(e24)) + assert(not evo.is_alive(e234) and evo.is_empty(e234)) + assert(evo.is_alive(e124) and not evo.is_empty(e124)) +end + +do + local f1 = evo.id() + assert(evo.set(f1, evo.ON_DESTROY, evo.DESTROY_ENTITY_POLICY)) + assert(evo.set(f1, f1, f1)) + + local remove_count = 0 + assert(evo.set(f1, evo.ON_REMOVE, function(e, f, c) + assert(e == f1) + assert(f == f1) + assert(c == f1) + remove_count = remove_count + 1 + end)) + + local c1 = assert(evo.chunk(f1)) + + assert(evo.destroy(f1)) + + do + assert(not evo.is_alive(f1)) + assert(remove_count == 1) + + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 0 and c1_ec == 0) + end +end + +do + local f1 = evo.id() + assert(evo.set(f1, evo.ON_DESTROY, evo.REMOVE_FRAGMENT_POLICY)) + assert(evo.set(f1, f1, f1)) + + local remove_count = 0 + assert(evo.set(f1, evo.ON_REMOVE, function(e, f, c) + assert(e == f1) + assert(f == f1) + assert(c == f1) + remove_count = remove_count + 1 + end)) + + local c1 = assert(evo.chunk(f1)) + + assert(evo.destroy(f1)) + + do + assert(not evo.is_alive(f1)) + assert(remove_count == 1) + + local c1_es, c1_ec = evo.entities(c1) + assert(c1_es and #c1_es == 0 and c1_ec == 0) + end +end + +do + local f1, f2, f3 = evo.id(3) + + assert(evo.set(f1, evo.NAME, 'f1')) + assert(evo.set(f2, evo.NAME, 'f2')) + assert(evo.set(f3, evo.NAME, 'f3')) + + local c1 = evo.chunk(f1) + local c12 = evo.chunk(f1, f2) + local c13 = evo.chunk(f1, f3) + local c123 = evo.chunk(f1, f2, f3) + + local e1a = evo.entity():set(f1, 1):build() + local e1b = evo.entity():set(f1, 2):build() + + local e12a = evo.entity():set(f1, 3):set(f2, 4):build() + local e12b = evo.entity():set(f1, 5):set(f2, 6):build() + + local e123a = evo.entity():set(f1, 7):set(f2, 8):set(f3, 9):build() + local e123b = evo.entity():set(f1, 10):set(f2, 11):set(f3, 12):build() + + assert(evo.destroy(f2)) + + do + assert(c1 and c12 and c13 and c123) + end + + do + local c1_es, c1_ec = evo.entities(c1) + assert(c1 and c1_es and c1_ec) + assert(c1_ec == 4 and #c1_es == 4) + assert(c1_es[1] == e1a and c1_es[2] == e1b and c1_es[3] == e12a and c1_es[4] == e12b) + end + + do + local c12_es, c12_ec = evo.entities(c12) + assert(c12 and c12_es and c12_ec) + assert(c12_ec == 0 and #c12_es == 0) + end + + do + local c13_es, c13_ec = evo.entities(c13) + assert(c13 and c13_es and c13_ec) + assert(c13_ec == 2 and #c13_es == 2) + assert(c13_es[1] == e123a and c13_es[2] == e123b) + end + + do + local c123_es, c123_ec = evo.entities(c123) + assert(c123 and c123_es and c123_ec) + assert(c123_ec == 0 and #c123_es == 0) + end +end + +do + do + local f1, f2 = evo.id(2) + evo.set(f1, f1) + evo.set(f2, f1) + evo.set(f1, evo.ON_DESTROY, evo.DESTROY_ENTITY_POLICY) + assert(evo.destroy(f1)) + assert(not evo.is_alive(f1)) + assert(not evo.is_alive(f2)) + end + + do + local f1, f2 = evo.id(2) + evo.set(f1, f1) + evo.set(f2, f1) + evo.set(f1, evo.ON_DESTROY, evo.REMOVE_FRAGMENT_POLICY) + assert(evo.destroy(f1)) + assert(not evo.is_alive(f1)) + assert(evo.is_alive(f2) and evo.is_empty(f2)) + end +end + +do + local f1, f2 = evo.id(2) + + evo.set(f1, evo.ON_DESTROY, evo.DESTROY_ENTITY_POLICY) + + local e12a = evo.entity():set(f1, 1):set(f2, 2):build() + local e12b = evo.entity():set(f1, 3):set(f2, 4):build() + local e_e12a_e12b = evo.entity():set(e12a, 11):set(e12b, 22):build() + + local e2a = evo.entity():set(f2, 5):build() + local e2b = evo.entity():set(f2, 6):build() + local e_e2a_e2b = evo.entity():set(e2a, 55):set(e2b, 66):build() + + assert(evo.destroy(f1)) + + do + assert(not evo.is_alive(e12a) and not evo.is_alive(e12b)) + assert(evo.is_alive(e_e12a_e12b) and evo.is_empty(e_e12a_e12b)) + + assert(evo.is_alive(e2a) and evo.is_alive(e2b)) + assert(evo.is_alive(e_e2a_e2b) and not evo.is_empty(e_e2a_e2b)) + end + + do + local c2, c2_es, c2_ec = evo.chunk(f2) + assert(c2 and c2_es and c2_ec) + assert(#c2_es == 2 and c2_ec == 2) + assert(c2_es[1] == e2a and c2_es[2] == e2b) + end +end + +do + local f1, f2 = evo.id(2) + + evo.set(f1, evo.NAME, "f1") + evo.set(f2, evo.NAME, "f2") + + do + local c12 = evo.chunk(f1, f2) + + local f3 = evo.id() + evo.set(f3, evo.TAG) + local c123 = evo.chunk(f2, f1, f3) + evo.spawn_at(c123) + + assert(c12, c123) + end + + evo.set(f1, evo.ON_DESTROY, evo.REMOVE_FRAGMENT_POLICY) + + local e12a = evo.entity():set(f1, 1):set(f2, 2):build() + local e12b = evo.entity():set(f1, 3):set(f2, 4):build() + local e_e12a_e12b = evo.entity():set(e12a, 11):set(e12b, 22):build() + + local e2a = evo.entity():set(f2, 5):build() + local e2b = evo.entity():set(f2, 6):build() + local e_e2a_e2b = evo.entity():set(e2a, 55):set(e2b, 66):build() + + assert(evo.destroy(f1)) + + do + assert(evo.is_alive(e12a) and evo.is_alive(e12b)) + assert(evo.is_alive(e_e12a_e12b) and not evo.is_empty(e_e12a_e12b)) + assert(evo.is_alive(e2a) and evo.is_alive(e2b)) + assert(evo.is_alive(e_e2a_e2b) and not evo.is_empty(e_e2a_e2b)) + end + + do + local c2, c2_es, c2_ec = evo.chunk(f2) + assert(c2 and c2_es and c2_ec) + assert(#c2_es == 4 and c2_ec == 4) + assert(c2_es[1] == e2a and c2_es[2] == e2b and c2_es[3] == e12a and c2_es[4] == e12b) + end +end + +do + local fb = evo.fragment() + + local f1 = fb:build() + local f2 = fb:on_destroy(evo.DESTROY_ENTITY_POLICY):build() + local f3 = fb:on_destroy(evo.REMOVE_FRAGMENT_POLICY):build() + + assert(evo.get(f1, evo.ON_DESTROY) == nil) + assert(evo.get(f2, evo.ON_DESTROY) == evo.DESTROY_ENTITY_POLICY) + assert(evo.get(f3, evo.ON_DESTROY) == evo.REMOVE_FRAGMENT_POLICY) +end diff --git a/evolved.lua b/evolved.lua index fa79891..3a9ce73 100644 --- a/evolved.lua +++ b/evolved.lua @@ -1,6 +1,3 @@ ----@diagnostic disable: unused-function ----@diagnostic disable: unused-local - local evolved = { __HOMEPAGE = 'https://github.com/BlackMATov/evolved.lua', __DESCRIPTION = 'Evolved ECS (Entity-Component-System) for Lua', @@ -60,7 +57,7 @@ local evolved = { ---@field package __entities evolved.entity[] ---@field package __entity_count integer ---@field package __fragment evolved.fragment ----@field package __fragment_set table +---@field package __fragment_set table ---@field package __fragment_list evolved.fragment[] ---@field package __fragment_count integer ---@field package __component_count integer @@ -127,11 +124,15 @@ local __query_sorted_excludes = {} ---@type table +---@type table local __EMPTY_FRAGMENT_SET = __lua_setmetatable({}, { __newindex = function() __lua_error('attempt to modify empty fragment set') end }) @@ -628,6 +634,7 @@ local __evolved_batch_multi_remove local __evolved_chunk local __evolved_select +local __evolved_entities local __evolved_each local __evolved_execute @@ -649,6 +656,21 @@ local __evolved_system --- --- +---@param id evolved.id +---@return string +---@nodiscard +local function __id_name(id) + ---@type string? + local id_name = __evolved_get(id, __NAME) + + if id_name then + return id_name + end + + local id_index, id_version = __evolved_unpack(id) + return __lua_string_format('$%d#%d:%d', id, id_index, id_version) +end + ---@param ... any component arguments ---@return evolved.component local function __component_list(...) @@ -727,55 +749,116 @@ local function __trace_fragment_chunks(fragment, trace, ...) __release_table(__table_pool_tag.chunk_stack, chunk_stack, true) end ----@param entity evolved.entity ----@param fragment evolved.fragment ----@param new_component evolved.component ----@param old_component evolved.component -local function __call_fragment_set_and_assign_hooks(entity, fragment, new_component, old_component) - ---@type evolved.set_hook?, evolved.assign_hook? - local on_set, on_assign = __evolved_get(fragment, __ON_SET, __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 +--- +--- +--- +--- +--- + +local __chunk_mt = {} ---@type metatable + +local __chunk_fragment_set_mt = {} ---@type metatable +local __chunk_fragment_list_mt = {} ---@type metatable + +local __chunk_component_indices_mt = {} ---@type metatable +local __chunk_component_storages_mt = {} ---@type metatable +local __chunk_component_fragments_mt = {} ---@type metatable + +---@param self evolved.chunk +function __chunk_mt.__tostring(self) + local items = {} ---@type string[] + + for fragment_index, fragment in __lua_ipairs(self.__fragment_list) do + items[fragment_index] = __id_name(fragment) + end + + return __lua_string_format('<%s>', __lua_table_concat(items, ', ')) end ----@param entity evolved.entity ----@param fragment evolved.fragment ----@param new_component evolved.component -local function __call_fragment_set_and_insert_hooks(entity, fragment, new_component) - ---@type evolved.set_hook?, evolved.insert_hook? - local on_set, on_insert = __evolved_get(fragment, __ON_SET, __ON_INSERT) - if on_set then on_set(entity, fragment, new_component) end - if on_insert then on_insert(entity, fragment, new_component) end +---@param self table +function __chunk_fragment_set_mt.__tostring(self) + local items = {} ---@type string[] + + for fragment, fragment_index in __lua_pairs(self) do + items[fragment_index] = __lua_string_format('(%s -> %d)', + __id_name(fragment), fragment_index) + end + + return __lua_string_format('{%s}', __lua_table_concat(items, ', ')) end ----@param entity evolved.entity ----@param fragment evolved.fragment ----@param old_component evolved.component -local function __call_fragment_remove_hook(entity, fragment, old_component) - ---@type evolved.remove_hook? - local on_remove = __evolved_get(fragment, __ON_REMOVE) - if on_remove then on_remove(entity, fragment, old_component) end +---@param self evolved.fragment[] +function __chunk_fragment_list_mt.__tostring(self) + local items = {} ---@type string[] + + for fragment_index, fragment in __lua_ipairs(self) do + items[fragment_index] = __lua_string_format('(%d -> %s)', + fragment_index, __id_name(fragment)) + end + + return __lua_string_format('[%s]', __lua_table_concat(items, ', ')) end ---- ---- ---- ---- ---- +---@param self table +function __chunk_component_indices_mt.__tostring(self) + local items = {} ---@type string[] + + for component_fragment, component_index in __lua_pairs(self) do + items[component_index] = __lua_string_format('(%s -> %d)', + __id_name(component_fragment), component_index) + end + + return __lua_string_format('{%s}', __lua_table_concat(items, ', ')) +end + +---@param self evolved.component_storage[] +function __chunk_component_storages_mt.__tostring(self) + local items = {} ---@type string[] + + for component_index, component_storage in __lua_ipairs(self) do + items[component_index] = __lua_string_format('(%d -> #%d)', + component_index, #component_storage) + end + + return __lua_string_format('[%s]', __lua_table_concat(items, ', ')) +end + +---@param self evolved.fragment[] +function __chunk_component_fragments_mt.__tostring(self) + local items = {} ---@type string[] + + for component_index, component_fragment in __lua_ipairs(self) do + items[component_index] = __lua_string_format('(%d -> %s)', + component_index, __id_name(component_fragment)) + end + + return __lua_string_format('[%s]', __lua_table_concat(items, ', ')) +end ---@param chunk_parent? evolved.chunk ---@param chunk_fragment evolved.fragment ---@return evolved.chunk local function __new_chunk(chunk_parent, chunk_fragment) - local chunk_fragment_set = {} ---@type table - local chunk_fragment_list = {} ---@type evolved.fragment[] + ---@type table + local chunk_fragment_set = __lua_setmetatable({}, __chunk_fragment_set_mt) - local chunk_fragment_count = 0 ---@type integer - local chunk_component_count = 0 ---@type integer + ---@type evolved.fragment[] + local chunk_fragment_list = __lua_setmetatable({}, __chunk_fragment_list_mt) - local chunk_component_indices = {} ---@type table - local chunk_component_storages = {} ---@type evolved.component_storage[] - local chunk_component_fragments = {} ---@type evolved.fragment[] + ---@type integer + local chunk_fragment_count = 0 + + ---@type integer + local chunk_component_count = 0 + + ---@type table + local chunk_component_indices = __lua_setmetatable({}, __chunk_component_indices_mt) + + ---@type evolved.component_storage[] + local chunk_component_storages = __lua_setmetatable({}, __chunk_component_storages_mt) + + ---@type evolved.fragment[] + local chunk_component_fragments = __lua_setmetatable({}, __chunk_component_fragments_mt) local has_defaults_or_constructs = (chunk_parent and chunk_parent.__has_defaults_or_constructs) or __evolved_has_any(chunk_fragment, __DEFAULT, __CONSTRUCT) @@ -790,7 +873,7 @@ local function __new_chunk(chunk_parent, chunk_fragment) or __evolved_has(chunk_fragment, __ON_REMOVE) ---@type evolved.chunk - local chunk = { + local chunk = __lua_setmetatable({ __parent = chunk_parent, __children = {}, __child_count = 0, @@ -810,7 +893,7 @@ local function __new_chunk(chunk_parent, chunk_fragment) __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, - } + }, __chunk_mt) if chunk_parent then local parent_fragment_list = chunk_parent.__fragment_list @@ -820,7 +903,7 @@ local function __new_chunk(chunk_parent, chunk_fragment) local parent_fragment = parent_fragment_list[parent_fragment_index] chunk_fragment_count = chunk_fragment_count + 1 - chunk_fragment_set[parent_fragment] = true + chunk_fragment_set[parent_fragment] = chunk_fragment_count chunk_fragment_list[chunk_fragment_count] = parent_fragment if not __evolved_has(parent_fragment, __TAG) then @@ -843,7 +926,7 @@ local function __new_chunk(chunk_parent, chunk_fragment) do chunk_fragment_count = chunk_fragment_count + 1 - chunk_fragment_set[chunk_fragment] = true + chunk_fragment_set[chunk_fragment] = chunk_fragment_count chunk_fragment_list[chunk_fragment_count] = chunk_fragment if not __evolved_has(chunk_fragment, __TAG) then @@ -1059,7 +1142,7 @@ end ---@return boolean ---@nodiscard local function __chunk_has_fragment(chunk, fragment) - return chunk.__fragment_set[fragment] + return chunk.__fragment_set[fragment] ~= nil end ---@param chunk evolved.chunk @@ -1230,9 +1313,6 @@ local __defer_spawn_entity_at local __defer_spawn_entity_with local __defer_call_hook -local __defer_assign_hook -local __defer_insert_hook -local __defer_remove_hook --- --- @@ -1316,6 +1396,15 @@ local function __spawn_entity_at(entity, chunk, fragments, components) chunk_entities[place] = entity + do + local entity_index = entity % 0x100000 + + __entity_chunks[entity_index] = chunk + __entity_places[entity_index] = place + + __structural_changes = __structural_changes + 1 + end + if chunk_has_defaults_or_constructs then for component_index = 1, chunk_component_count do local fragment = chunk_component_fragments[component_index] @@ -1385,6 +1474,10 @@ local function __spawn_entity_at(entity, chunk, fragments, components) for fragment_index = 1, chunk_fragment_count do local fragment = chunk_fragment_list[fragment_index] + + ---@type evolved.set_hook?, evolved.insert_hook? + local fragment_on_set, fragment_on_insert = __evolved_get(fragment, __ON_SET, __ON_INSERT) + local component_index = chunk_component_indices[fragment] if component_index then @@ -1392,19 +1485,24 @@ local function __spawn_entity_at(entity, chunk, fragments, components) local new_component = component_storage[place] - __defer_insert_hook(entity, fragment, new_component) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment, new_component) + end else - __defer_insert_hook(entity, fragment) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment) + end end end end - - local entity_index = entity % 0x100000 - - __entity_chunks[entity_index] = chunk - __entity_places[entity_index] = place - - __structural_changes = __structural_changes + 1 end ---@param entity evolved.entity @@ -1430,6 +1528,15 @@ local function __spawn_entity_with(entity, chunk, fragments, components) chunk_entities[place] = entity + do + local entity_index = entity % 0x100000 + + __entity_chunks[entity_index] = chunk + __entity_places[entity_index] = place + + __structural_changes = __structural_changes + 1 + end + if chunk_has_defaults_or_constructs then for i = 1, #fragments do local fragment = fragments[i] @@ -1476,6 +1583,10 @@ local function __spawn_entity_with(entity, chunk, fragments, components) for fragment_index = 1, chunk_fragment_count do local fragment = chunk_fragment_list[fragment_index] + + ---@type evolved.set_hook?, evolved.insert_hook? + local fragment_on_set, fragment_on_insert = __evolved_get(fragment, __ON_SET, __ON_INSERT) + local component_index = chunk_component_indices[fragment] if component_index then @@ -1483,19 +1594,108 @@ local function __spawn_entity_with(entity, chunk, fragments, components) local new_component = component_storage[place] - __defer_insert_hook(entity, fragment, new_component) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment, new_component) + end else - __defer_insert_hook(entity, fragment) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment) + end end end end +end - local entity_index = entity % 0x100000 +--- +--- +--- +--- +--- - __entity_chunks[entity_index] = chunk - __entity_places[entity_index] = place +local __chunk_assign +local __chunk_insert +local __chunk_remove +local __chunk_clear +local __chunk_destroy - __structural_changes = __structural_changes + 1 +local __chunk_multi_set +local __chunk_multi_assign +local __chunk_multi_insert +local __chunk_multi_remove + +--- +--- +--- +--- +--- + +---@param fragment evolved.fragment +---@param policy evolved.id +---@return integer purged_count +local function __purge_fragment(fragment, policy) + if __defer_depth <= 0 then + __lua_error('purge operations should be deferred') + end + + local minor_chunks = __minor_chunks[fragment] + + if not minor_chunks then + return 0 + end + + local purged_count = 0 + + if policy == __DESTROY_ENTITY_POLICY then + for minor_chunk_index = #minor_chunks, 1, -1 do + local minor_chunk = minor_chunks[minor_chunk_index] + purged_count = purged_count + __chunk_destroy(minor_chunk) + end + elseif policy == __REMOVE_FRAGMENT_POLICY then + for minor_chunk_index = #minor_chunks, 1, -1 do + local minor_chunk = minor_chunks[minor_chunk_index] + purged_count = purged_count + __chunk_remove(minor_chunk, fragment) + end + else + __lua_print(__lua_string_format('| evolved.lua | unknown ON_DESTROY policy (%s) on (%s)', + __id_name(policy), __id_name(fragment))) + end + + return purged_count +end + +---@param fragments evolved.fragment[] +---@param policies evolved.id[] +---@param count integer +---@return integer purged_count +local function __purge_fragments(fragments, policies, count) + if __defer_depth <= 0 then + __lua_error('purge operations should be deferred') + end + + local purged_count = 0 + + for index = 1, count do + local fragment, policy = fragments[index], policies[index] + + if policy == __DESTROY_ENTITY_POLICY then + purged_count = purged_count + __purge_fragment(fragment, __DESTROY_ENTITY_POLICY) + elseif policy == __REMOVE_FRAGMENT_POLICY then + purged_count = purged_count + __purge_fragment(fragment, __REMOVE_FRAGMENT_POLICY) + else + __lua_print(__lua_string_format('| evolved.lua | unknown ON_DESTROY policy (%s) on (%s)', + __id_name(policy), __id_name(fragment))) + end + end + + return purged_count end --- @@ -1509,7 +1709,7 @@ end ---@param ... any component arguments ---@return integer assigned_count ---@nodiscard -local function __chunk_assign(chunk, fragment, ...) +__chunk_assign = function(chunk, fragment, ...) if __defer_depth <= 0 then __lua_error('batched chunk operations should be deferred') end @@ -1521,6 +1721,10 @@ local function __chunk_assign(chunk, fragment, ...) local chunk_entities = chunk.__entities local chunk_entity_count = chunk.__entity_count + if chunk_entity_count == 0 then + return 0 + end + local chunk_component_indices = chunk.__component_indices local chunk_component_storages = chunk.__component_storages @@ -1633,7 +1837,7 @@ end ---@param ... any component arguments ---@return integer inserted_count ---@nodiscard -local function __chunk_insert(old_chunk, fragment, ...) +__chunk_insert = function(old_chunk, fragment, ...) if __defer_depth <= 0 then __lua_error('batched chunk operations should be deferred') end @@ -1647,6 +1851,10 @@ local function __chunk_insert(old_chunk, fragment, ...) local old_entities = old_chunk.__entities local old_entity_count = old_chunk.__entity_count + if old_entity_count == 0 then + return 0 + end + local old_component_count = old_chunk.__component_count local old_component_storages = old_chunk.__component_storages local old_component_fragments = old_chunk.__component_fragments @@ -1704,6 +1912,20 @@ local function __chunk_insert(old_chunk, fragment, ...) new_chunk.__entity_count = new_entity_count + old_entity_count end + do + local entity_chunks = __entity_chunks + local entity_places = __entity_places + + for new_place = new_entity_count + 1, new_entity_count + old_entity_count do + local entity = new_entities[new_place] + local entity_index = entity % 0x100000 + entity_chunks[entity_index] = new_chunk + entity_places[entity_index] = new_place + end + + __detach_all_entities(old_chunk) + end + if fragment_on_set or fragment_on_insert then local new_component_index = new_component_indices[fragment] @@ -1787,19 +2009,7 @@ local function __chunk_insert(old_chunk, fragment, ...) end end - local entity_chunks = __entity_chunks - local entity_places = __entity_places - - for new_place = new_entity_count + 1, new_entity_count + old_entity_count do - local entity = new_entities[new_place] - local entity_index = entity % 0x100000 - entity_chunks[entity_index] = new_chunk - entity_places[entity_index] = new_place - end - - __detach_all_entities(old_chunk) - - __structural_changes = __structural_changes + old_entity_count + __structural_changes = __structural_changes + 1 return old_entity_count end @@ -1807,7 +2017,7 @@ end ---@param ... evolved.fragment fragments ---@return integer removed_count ---@nodiscard -local function __chunk_remove(old_chunk, ...) +__chunk_remove = function(old_chunk, ...) if __defer_depth <= 0 then __lua_error('batched chunk operations should be deferred') end @@ -1827,6 +2037,10 @@ local function __chunk_remove(old_chunk, ...) local old_entities = old_chunk.__entities local old_entity_count = old_chunk.__entity_count + if old_entity_count == 0 then + return 0 + end + local old_fragment_set = old_chunk.__fragment_set local old_component_indices = old_chunk.__component_indices local old_component_storages = old_chunk.__component_storages @@ -1867,9 +2081,6 @@ local function __chunk_remove(old_chunk, ...) __release_table(__table_pool_tag.fragment_set, removed_set) end - local entity_chunks = __entity_chunks - local entity_places = __entity_places - if new_chunk then local new_entities = new_chunk.__entities local new_entity_count = new_chunk.__entity_count @@ -1909,31 +2120,41 @@ local function __chunk_remove(old_chunk, ...) new_chunk.__entity_count = new_entity_count + old_entity_count end - for new_place = new_entity_count + 1, new_entity_count + old_entity_count do - local entity = new_entities[new_place] - local entity_index = entity % 0x100000 - entity_chunks[entity_index] = new_chunk - entity_places[entity_index] = new_place + do + local entity_chunks = __entity_chunks + local entity_places = __entity_places + + for new_place = new_entity_count + 1, new_entity_count + old_entity_count do + local entity = new_entities[new_place] + local entity_index = entity % 0x100000 + entity_chunks[entity_index] = new_chunk + entity_places[entity_index] = new_place + end + + __detach_all_entities(old_chunk) end else + local entity_chunks = __entity_chunks + local entity_places = __entity_places + for old_place = 1, old_entity_count do local entity = old_entities[old_place] local entity_index = entity % 0x100000 entity_chunks[entity_index] = nil entity_places[entity_index] = nil end + + __detach_all_entities(old_chunk) end - __detach_all_entities(old_chunk) - - __structural_changes = __structural_changes + old_entity_count + __structural_changes = __structural_changes + 1 return old_entity_count end ---@param chunk evolved.chunk ---@return integer cleared_count ---@nodiscard -local function __chunk_clear(chunk) +__chunk_clear = function(chunk) if __defer_depth <= 0 then __lua_error('batched chunk operations should be deferred') end @@ -1941,6 +2162,10 @@ local function __chunk_clear(chunk) local chunk_entities = chunk.__entities local chunk_entity_count = chunk.__entity_count + if chunk_entity_count == 0 then + return 0 + end + local chunk_component_indices = chunk.__component_indices local chunk_component_storages = chunk.__component_storages @@ -1975,26 +2200,28 @@ local function __chunk_clear(chunk) end end - local entity_chunks = __entity_chunks - local entity_places = __entity_places + do + local entity_chunks = __entity_chunks + local entity_places = __entity_places - for place = 1, chunk_entity_count do - local entity = chunk_entities[place] - local entity_index = entity % 0x100000 - entity_chunks[entity_index] = nil - entity_places[entity_index] = nil + for place = 1, chunk_entity_count do + local entity = chunk_entities[place] + local entity_index = entity % 0x100000 + entity_chunks[entity_index] = nil + entity_places[entity_index] = nil + end + + __detach_all_entities(chunk) end - __detach_all_entities(chunk) - - __structural_changes = __structural_changes + chunk_entity_count + __structural_changes = __structural_changes + 1 return chunk_entity_count end ---@param chunk evolved.chunk ---@return integer destroyed_count ---@nodiscard -local function __chunk_destroy(chunk) +__chunk_destroy = function(chunk) if __defer_depth <= 0 then __lua_error('batched chunk operations should be deferred') end @@ -2002,6 +2229,10 @@ local function __chunk_destroy(chunk) local chunk_entities = chunk.__entities local chunk_entity_count = chunk.__entity_count + if chunk_entity_count == 0 then + return 0 + end + local chunk_component_indices = chunk.__component_indices local chunk_component_storages = chunk.__component_storages @@ -2036,20 +2267,42 @@ local function __chunk_destroy(chunk) end end - local entity_chunks = __entity_chunks - local entity_places = __entity_places + do + local purging_fragments = __acquire_table(__table_pool_tag.fragment_list) + local purging_policies = __acquire_table(__table_pool_tag.fragment_list) + local purging_count = 0 - for place = 1, chunk_entity_count do - local entity = chunk_entities[place] - local entity_index = entity % 0x100000 - entity_chunks[entity_index] = nil - entity_places[entity_index] = nil - __release_id(entity) + local entity_chunks = __entity_chunks + local entity_places = __entity_places + + for place = 1, chunk_entity_count do + local entity = chunk_entities[place] + local entity_index = entity % 0x100000 + + if __minor_chunks[entity] then + purging_count = purging_count + 1 + purging_policies[purging_count] = __chunk_get_components(chunk, place, __ON_DESTROY) + or __REMOVE_FRAGMENT_POLICY + purging_fragments[purging_count] = entity + end + + entity_chunks[entity_index] = nil + entity_places[entity_index] = nil + + __release_id(entity) + end + + __detach_all_entities(chunk) + + if purging_count > 0 then + __purge_fragments(purging_fragments, purging_policies, purging_count) + end + + __release_table(__table_pool_tag.fragment_list, purging_fragments) + __release_table(__table_pool_tag.fragment_list, purging_policies) end - __detach_all_entities(chunk) - - __structural_changes = __structural_changes + chunk_entity_count + __structural_changes = __structural_changes + 1 return chunk_entity_count end @@ -2057,7 +2310,7 @@ end ---@param fragments evolved.fragment[] ---@param components evolved.component[] ---@return integer set_count -local function __chunk_multi_set(old_chunk, fragments, components) +__chunk_multi_set = function(old_chunk, fragments, components) if __defer_depth <= 0 then __lua_error('batched chunk operations should be deferred') end @@ -2077,6 +2330,10 @@ local function __chunk_multi_set(old_chunk, fragments, components) local old_entities = old_chunk.__entities local old_entity_count = old_chunk.__entity_count + if old_entity_count == 0 then + return 0 + end + local old_fragment_set = old_chunk.__fragment_set local old_component_count = old_chunk.__component_count local old_component_indices = old_chunk.__component_indices @@ -2203,6 +2460,20 @@ local function __chunk_multi_set(old_chunk, fragments, components) new_chunk.__entity_count = new_entity_count + old_entity_count end + do + local entity_chunks = __entity_chunks + local entity_places = __entity_places + + for new_place = new_entity_count + 1, new_entity_count + old_entity_count do + local entity = new_entities[new_place] + local entity_index = entity % 0x100000 + entity_chunks[entity_index] = new_chunk + entity_places[entity_index] = new_place + end + + __detach_all_entities(old_chunk) + end + local inserted_set = __acquire_table(__table_pool_tag.fragment_set) for i = 1, fragment_count do @@ -2355,19 +2626,7 @@ local function __chunk_multi_set(old_chunk, fragments, components) __release_table(__table_pool_tag.fragment_set, inserted_set) - local entity_chunks = __entity_chunks - local entity_places = __entity_places - - for new_place = new_entity_count + 1, new_entity_count + old_entity_count do - local entity = new_entities[new_place] - local entity_index = entity % 0x100000 - entity_chunks[entity_index] = new_chunk - entity_places[entity_index] = new_place - end - - __detach_all_entities(old_chunk) - - __structural_changes = __structural_changes + old_entity_count + __structural_changes = __structural_changes + 1 end return old_entity_count @@ -2377,7 +2636,7 @@ end ---@param fragments evolved.fragment[] ---@param components evolved.component[] ---@return integer assigned_count -local function __chunk_multi_assign(chunk, fragments, components) +__chunk_multi_assign = function(chunk, fragments, components) if __defer_depth <= 0 then __lua_error('batched chunk operations should be deferred') end @@ -2395,6 +2654,10 @@ local function __chunk_multi_assign(chunk, fragments, components) local chunk_entities = chunk.__entities local chunk_entity_count = chunk.__entity_count + if chunk_entity_count == 0 then + return 0 + end + local chunk_fragment_set = chunk.__fragment_set local chunk_component_indices = chunk.__component_indices local chunk_component_storages = chunk.__component_storages @@ -2486,7 +2749,7 @@ end ---@param fragments evolved.fragment[] ---@param components evolved.component[] ---@return integer inserted_count -local function __chunk_multi_insert(old_chunk, fragments, components) +__chunk_multi_insert = function(old_chunk, fragments, components) if __defer_depth <= 0 then __lua_error('batched chunk operations should be deferred') end @@ -2506,6 +2769,10 @@ local function __chunk_multi_insert(old_chunk, fragments, components) local old_entities = old_chunk.__entities local old_entity_count = old_chunk.__entity_count + if old_entity_count == 0 then + return 0 + end + local old_fragment_set = old_chunk.__fragment_set local old_component_count = old_chunk.__component_count local old_component_storages = old_chunk.__component_storages @@ -2551,6 +2818,20 @@ local function __chunk_multi_insert(old_chunk, fragments, components) new_chunk.__entity_count = new_entity_count + old_entity_count end + do + local entity_chunks = __entity_chunks + local entity_places = __entity_places + + for new_place = new_entity_count + 1, new_entity_count + old_entity_count do + local entity = new_entities[new_place] + local entity_index = entity % 0x100000 + entity_chunks[entity_index] = new_chunk + entity_places[entity_index] = new_place + end + + __detach_all_entities(old_chunk) + end + local inserted_set = __acquire_table(__table_pool_tag.fragment_set) for i = 1, fragment_count do @@ -2633,26 +2914,14 @@ local function __chunk_multi_insert(old_chunk, fragments, components) __release_table(__table_pool_tag.fragment_set, inserted_set) - local entity_chunks = __entity_chunks - local entity_places = __entity_places - - for new_place = new_entity_count + 1, new_entity_count + old_entity_count do - local entity = new_entities[new_place] - local entity_index = entity % 0x100000 - entity_chunks[entity_index] = new_chunk - entity_places[entity_index] = new_place - end - - __detach_all_entities(old_chunk) - - __structural_changes = __structural_changes + old_entity_count + __structural_changes = __structural_changes + 1 return old_entity_count end ---@param old_chunk evolved.chunk ---@param fragments evolved.fragment[] ---@return integer removed_count -local function __chunk_multi_remove(old_chunk, fragments) +__chunk_multi_remove = function(old_chunk, fragments) if __defer_depth <= 0 then __lua_error('batched chunk operations should be deferred') end @@ -2672,6 +2941,10 @@ local function __chunk_multi_remove(old_chunk, fragments) local old_entities = old_chunk.__entities local old_entity_count = old_chunk.__entity_count + if old_entity_count == 0 then + return 0 + end + local old_fragment_set = old_chunk.__fragment_set local old_component_indices = old_chunk.__component_indices local old_component_storages = old_chunk.__component_storages @@ -2712,9 +2985,6 @@ local function __chunk_multi_remove(old_chunk, fragments) __release_table(__table_pool_tag.fragment_set, removed_set) end - local entity_chunks = __entity_chunks - local entity_places = __entity_places - if new_chunk then local new_entities = new_chunk.__entities local new_entity_count = new_chunk.__entity_count @@ -2754,24 +3024,34 @@ local function __chunk_multi_remove(old_chunk, fragments) new_chunk.__entity_count = new_entity_count + old_entity_count end - for new_place = new_entity_count + 1, new_entity_count + old_entity_count do - local entity = new_entities[new_place] - local entity_index = entity % 0x100000 - entity_chunks[entity_index] = new_chunk - entity_places[entity_index] = new_place + do + local entity_chunks = __entity_chunks + local entity_places = __entity_places + + for new_place = new_entity_count + 1, new_entity_count + old_entity_count do + local entity = new_entities[new_place] + local entity_index = entity % 0x100000 + entity_chunks[entity_index] = new_chunk + entity_places[entity_index] = new_place + end + + __detach_all_entities(old_chunk) end else + local entity_chunks = __entity_chunks + local entity_places = __entity_places + for old_place = 1, old_entity_count do local entity = old_entities[old_place] local entity_index = entity % 0x100000 entity_chunks[entity_index] = nil entity_places[entity_index] = nil end + + __detach_all_entities(old_chunk) end - __detach_all_entities(old_chunk) - - __structural_changes = __structural_changes + old_entity_count + __structural_changes = __structural_changes + 1 return old_entity_count end @@ -2962,11 +3242,8 @@ local __defer_op = { spawn_entity_with = 22, call_hook = 23, - assign_hook = 24, - insert_hook = 25, - remove_hook = 26, - __count = 26, + __count = 23, } ---@type table @@ -4065,78 +4342,6 @@ __defer_ops[__defer_op.call_hook] = function(bytes, index) return 2 + argument_count end ----@param entity evolved.entity ----@param fragment evolved.fragment ----@param new_component evolved.component ----@param old_component evolved.component -__defer_assign_hook = function(entity, fragment, new_component, old_component) - local length = __defer_length - local bytecode = __defer_bytecode - - bytecode[length + 1] = __defer_op.assign_hook - bytecode[length + 2] = entity - bytecode[length + 3] = fragment - bytecode[length + 4] = new_component - bytecode[length + 5] = old_component - - __defer_length = length + 5 -end - -__defer_ops[__defer_op.assign_hook] = function(bytes, index) - local entity = bytes[index + 0] - local fragment = bytes[index + 1] - local new_component = bytes[index + 2] - local old_component = bytes[index + 3] - __call_fragment_set_and_assign_hooks(entity, fragment, new_component, old_component) - return 4 -end - ----@param entity evolved.entity ----@param fragment evolved.fragment ----@param new_component evolved.component -__defer_insert_hook = function(entity, fragment, new_component) - local length = __defer_length - local bytecode = __defer_bytecode - - bytecode[length + 1] = __defer_op.insert_hook - bytecode[length + 2] = entity - bytecode[length + 3] = fragment - bytecode[length + 4] = new_component - - __defer_length = length + 4 -end - -__defer_ops[__defer_op.insert_hook] = function(bytes, index) - local entity = bytes[index + 0] - local fragment = bytes[index + 1] - local new_component = bytes[index + 2] - __call_fragment_set_and_insert_hooks(entity, fragment, new_component) - return 3 -end - ----@param entity evolved.entity ----@param fragment evolved.fragment ----@param old_component evolved.component -__defer_remove_hook = function(entity, fragment, old_component) - local length = __defer_length - local bytecode = __defer_bytecode - - bytecode[length + 1] = __defer_op.remove_hook - bytecode[length + 2] = entity - bytecode[length + 3] = fragment - bytecode[length + 4] = old_component - - __defer_length = length + 4 -end - -__defer_ops[__defer_op.remove_hook] = function(bytes, index) - local entity = bytes[index + 0] - local fragment = bytes[index + 1] - local old_component = bytes[index + 2] - __call_fragment_remove_hook(entity, fragment, old_component) - return 3 -end - --- --- --- @@ -4348,6 +4553,14 @@ __evolved_set = function(entity, fragment, ...) local new_chunk = __chunk_with_fragment(old_chunk, fragment) + ---@type evolved.set_hook?, evolved.assign_hook?, evolved.insert_hook? + local fragment_on_set, fragment_on_assign, fragment_on_insert + + if new_chunk.__has_set_or_assign_hooks or new_chunk.__has_set_or_insert_hooks then + fragment_on_set, fragment_on_assign, fragment_on_insert = __evolved_get(fragment, + __ON_SET, __ON_ASSIGN, __ON_INSERT) + end + __defer() if old_chunk == new_chunk then @@ -4362,10 +4575,18 @@ __evolved_set = function(entity, fragment, ...) if old_chunk.__has_defaults_or_constructs then local new_component = __component_construct(fragment, ...) - if old_chunk.__has_set_or_assign_hooks then + if fragment_on_set or fragment_on_assign then local old_component = old_component_storage[old_place] + old_component_storage[old_place] = new_component - __defer_assign_hook(entity, fragment, new_component, old_component) + + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component, old_component) + end + + if fragment_on_assign then + __defer_call_hook(fragment_on_assign, entity, fragment, new_component, old_component) + end else old_component_storage[old_place] = new_component end @@ -4376,17 +4597,29 @@ __evolved_set = function(entity, fragment, ...) new_component = true end - if old_chunk.__has_set_or_assign_hooks then + if fragment_on_set or fragment_on_assign then local old_component = old_component_storage[old_place] + old_component_storage[old_place] = new_component - __defer_assign_hook(entity, fragment, new_component, old_component) + + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component, old_component) + end + + if fragment_on_assign then + __defer_call_hook(fragment_on_assign, entity, fragment, new_component, old_component) + end else old_component_storage[old_place] = new_component end end else - if old_chunk.__has_set_or_assign_hooks then - __defer_assign_hook(entity, fragment) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment) + end + + if fragment_on_assign then + __defer_call_hook(fragment_on_assign, entity, fragment) end end else @@ -4417,6 +4650,13 @@ __evolved_set = function(entity, fragment, ...) __detach_entity(old_chunk, old_place) end + do + entity_chunks[entity_index] = new_chunk + entity_places[entity_index] = new_place + + __structural_changes = __structural_changes + 1 + end + do local new_component_index = new_component_indices[fragment] @@ -4428,8 +4668,12 @@ __evolved_set = function(entity, fragment, ...) new_component_storage[new_place] = new_component - if new_chunk.__has_set_or_insert_hooks then - __defer_insert_hook(entity, fragment, new_component) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment, new_component) end else local new_component = ... @@ -4440,21 +4684,24 @@ __evolved_set = function(entity, fragment, ...) new_component_storage[new_place] = new_component - if new_chunk.__has_set_or_insert_hooks then - __defer_insert_hook(entity, fragment, new_component) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment, new_component) end end else - if new_chunk.__has_set_or_insert_hooks then - __defer_insert_hook(entity, fragment) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment) end end end - - entity_chunks[entity_index] = new_chunk - entity_places[entity_index] = new_place - - __structural_changes = __structural_changes + 1 end __commit() @@ -4496,6 +4743,14 @@ __evolved_assign = function(entity, fragment, ...) return false, false end + ---@type evolved.set_hook?, evolved.assign_hook? + local fragment_on_set, fragment_on_assign + + if chunk.__has_set_or_assign_hooks then + fragment_on_set, fragment_on_assign = __evolved_get(fragment, + __ON_SET, __ON_ASSIGN) + end + __defer() do @@ -4510,10 +4765,18 @@ __evolved_assign = function(entity, fragment, ...) if chunk.__has_defaults_or_constructs then local new_component = __component_construct(fragment, ...) - if chunk.__has_set_or_assign_hooks then + if fragment_on_set or fragment_on_assign then local old_component = component_storage[place] + component_storage[place] = new_component - __defer_assign_hook(entity, fragment, new_component, old_component) + + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component, old_component) + end + + if fragment_on_assign then + __defer_call_hook(fragment_on_assign, entity, fragment, new_component, old_component) + end else component_storage[place] = new_component end @@ -4524,17 +4787,29 @@ __evolved_assign = function(entity, fragment, ...) new_component = true end - if chunk.__has_set_or_assign_hooks then + if fragment_on_set or fragment_on_assign then local old_component = component_storage[place] + component_storage[place] = new_component - __defer_assign_hook(entity, fragment, new_component, old_component) + + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component, old_component) + end + + if fragment_on_assign then + __defer_call_hook(fragment_on_assign, entity, fragment, new_component, old_component) + end else component_storage[place] = new_component end end else - if chunk.__has_set_or_assign_hooks then - __defer_assign_hook(entity, fragment) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment) + end + + if fragment_on_assign then + __defer_call_hook(fragment_on_assign, entity, fragment) end end end @@ -4580,6 +4855,14 @@ __evolved_insert = function(entity, fragment, ...) return false, false end + ---@type evolved.set_hook?, evolved.insert_hook? + local fragment_on_set, fragment_on_insert + + if new_chunk.__has_set_or_insert_hooks then + fragment_on_set, fragment_on_insert = __evolved_get(fragment, + __ON_SET, __ON_INSERT) + end + __defer() do @@ -4610,6 +4893,13 @@ __evolved_insert = function(entity, fragment, ...) __detach_entity(old_chunk, old_place) end + do + entity_chunks[entity_index] = new_chunk + entity_places[entity_index] = new_place + + __structural_changes = __structural_changes + 1 + end + do local new_component_index = new_component_indices[fragment] @@ -4621,8 +4911,12 @@ __evolved_insert = function(entity, fragment, ...) new_component_storage[new_place] = new_component - if new_chunk.__has_set_or_insert_hooks then - __defer_insert_hook(entity, fragment, new_component) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment, new_component) end else local new_component = ... @@ -4633,21 +4927,24 @@ __evolved_insert = function(entity, fragment, ...) new_component_storage[new_place] = new_component - if new_chunk.__has_set_or_insert_hooks then - __defer_insert_hook(entity, fragment, new_component) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment, new_component) end end else - if new_chunk.__has_set_or_insert_hooks then - __defer_insert_hook(entity, fragment) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment) end end end - - entity_chunks[entity_index] = new_chunk - entity_places[entity_index] = new_place - - __structural_changes = __structural_changes + 1 end __commit() @@ -4715,14 +5012,19 @@ __evolved_remove = function(entity, ...) if not removed_set[fragment] and old_fragment_set[fragment] then removed_set[fragment] = true - local old_component_index = old_component_indices[fragment] + ---@type evolved.remove_hook? + local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE) - if old_component_index then - local old_component_storage = old_component_storages[old_component_index] - local old_component = old_component_storage[old_place] - __defer_remove_hook(entity, fragment, old_component) - else - __defer_remove_hook(entity, fragment) + if fragment_on_remove then + local old_component_index = old_component_indices[fragment] + + if old_component_index then + local old_component_storage = old_component_storages[old_component_index] + local old_component = old_component_storage[old_place] + __defer_call_hook(fragment_on_remove, entity, fragment, old_component) + else + __defer_call_hook(fragment_on_remove, entity, fragment) + end end end end @@ -4750,19 +5052,16 @@ __evolved_remove = function(entity, ...) local old_cs = old_component_storages[old_ci] new_cs[new_place] = old_cs[old_place] end + end + do __detach_entity(old_chunk, old_place) entity_chunks[entity_index] = new_chunk - entity_places[entity_index] = new_place - else - __detach_entity(old_chunk, old_place) + entity_places[entity_index] = new_chunk and new_chunk.__entity_count - entity_chunks[entity_index] = nil - entity_places[entity_index] = nil + __structural_changes = __structural_changes + 1 end - - __structural_changes = __structural_changes + 1 end __commit() @@ -4790,14 +5089,10 @@ __evolved_clear = function(entity) local chunk = entity_chunks[entity_index] local place = entity_places[entity_index] - if not chunk then - return true, false - end - __defer() do - if chunk.__has_remove_hooks then + if chunk and chunk.__has_remove_hooks then local chunk_fragment_list = chunk.__fragment_list local chunk_fragment_count = chunk.__fragment_count local chunk_component_indices = chunk.__component_indices @@ -4805,24 +5100,32 @@ __evolved_clear = function(entity) for fragment_index = 1, chunk_fragment_count do local fragment = chunk_fragment_list[fragment_index] - local component_index = chunk_component_indices[fragment] - if component_index then - local component_storage = chunk_component_storages[component_index] - local old_component = component_storage[place] - __defer_remove_hook(entity, fragment, old_component) - else - __defer_remove_hook(entity, fragment) + ---@type evolved.remove_hook? + local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE) + + if fragment_on_remove then + local component_index = chunk_component_indices[fragment] + + if component_index then + local component_storage = chunk_component_storages[component_index] + local old_component = component_storage[place] + __defer_call_hook(fragment_on_remove, entity, fragment, old_component) + else + __defer_call_hook(fragment_on_remove, entity, fragment) + end end end end - __detach_entity(chunk, place) + if chunk then + __detach_entity(chunk, place) - entity_chunks[entity_index] = nil - entity_places[entity_index] = nil + entity_chunks[entity_index] = nil + entity_places[entity_index] = nil - __structural_changes = __structural_changes + 1 + __structural_changes = __structural_changes + 1 + end end __commit() @@ -4850,15 +5153,10 @@ __evolved_destroy = function(entity) local chunk = entity_chunks[entity_index] local place = entity_places[entity_index] - if not chunk then - __release_id(entity) - return true, false - end - __defer() do - if chunk.__has_remove_hooks then + if chunk and chunk.__has_remove_hooks then local chunk_fragment_list = chunk.__fragment_list local chunk_fragment_count = chunk.__fragment_count local chunk_component_indices = chunk.__component_indices @@ -4866,25 +5164,49 @@ __evolved_destroy = function(entity) for fragment_index = 1, chunk_fragment_count do local fragment = chunk_fragment_list[fragment_index] - local component_index = chunk_component_indices[fragment] - if component_index then - local component_storage = chunk_component_storages[component_index] - local old_component = component_storage[place] - __defer_remove_hook(entity, fragment, old_component) - else - __defer_remove_hook(entity, fragment) + ---@type evolved.remove_hook? + local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE) + + if fragment_on_remove then + local component_index = chunk_component_indices[fragment] + + if component_index then + local component_storage = chunk_component_storages[component_index] + local old_component = component_storage[place] + __defer_call_hook(fragment_on_remove, entity, fragment, old_component) + else + __defer_call_hook(fragment_on_remove, entity, fragment) + end end end end - __detach_entity(chunk, place) - __release_id(entity) + do + local purging_fragment ---@type evolved.fragment? + local purging_policy ---@type evolved.id? - entity_chunks[entity_index] = nil - entity_places[entity_index] = nil + if __minor_chunks[entity] then + purging_fragment = entity + purging_policy = chunk and __chunk_get_components(chunk, place, __ON_DESTROY) + or __REMOVE_FRAGMENT_POLICY + end - __structural_changes = __structural_changes + 1 + if chunk then + __detach_entity(chunk, place) + + entity_chunks[entity_index] = nil + entity_places[entity_index] = nil + + __structural_changes = __structural_changes + 1 + end + + __release_id(entity) + + if purging_fragment then + __purge_fragment(purging_fragment, purging_policy) + end + end end __commit() @@ -4953,6 +5275,13 @@ __evolved_multi_set = function(entity, fragments, components) for i = 1, fragment_count do local fragment = fragments[i] + ---@type evolved.set_hook?, evolved.assign_hook? + local fragment_on_set, fragment_on_assign + + if old_chunk_has_set_or_assign_hooks then + fragment_on_set, fragment_on_assign = __evolved_get(fragment, __ON_SET, __ON_ASSIGN) + end + local old_component_index = old_component_indices[fragment] if old_component_index then @@ -4968,16 +5297,28 @@ __evolved_multi_set = function(entity, fragments, components) new_component = true end - if old_chunk_has_set_or_assign_hooks then + if fragment_on_set or fragment_on_assign then local old_component = old_component_storage[old_place] + old_component_storage[old_place] = new_component - __defer_assign_hook(entity, fragment, new_component, old_component) + + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component, old_component) + end + + if fragment_on_assign then + __defer_call_hook(fragment_on_assign, entity, fragment, new_component, old_component) + end else old_component_storage[old_place] = new_component end else - if old_chunk_has_set_or_assign_hooks then - __defer_assign_hook(entity, fragment) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment) + end + + if fragment_on_assign then + __defer_call_hook(fragment_on_assign, entity, fragment) end end end @@ -5015,12 +5356,26 @@ __evolved_multi_set = function(entity, fragments, components) __detach_entity(old_chunk, old_place) end + do + entity_chunks[entity_index] = new_chunk + entity_places[entity_index] = new_place + + __structural_changes = __structural_changes + 1 + end + local inserted_set = __acquire_table(__table_pool_tag.fragment_set) for i = 1, fragment_count do local fragment = fragments[i] if inserted_set[fragment] or old_fragment_set[fragment] then + ---@type evolved.set_hook?, evolved.assign_hook? + local fragment_on_set, fragment_on_assign + + if new_chunk_has_set_or_assign_hooks then + fragment_on_set, fragment_on_assign = __evolved_get(fragment, __ON_SET, __ON_ASSIGN) + end + local new_component_index = new_component_indices[fragment] if new_component_index then @@ -5036,21 +5391,40 @@ __evolved_multi_set = function(entity, fragments, components) new_component = true end - if new_chunk_has_set_or_assign_hooks then + if fragment_on_set or fragment_on_assign then local old_component = new_component_storage[new_place] + new_component_storage[new_place] = new_component - __defer_assign_hook(entity, fragment, new_component, old_component) + + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component, old_component) + end + + if fragment_on_assign then + __defer_call_hook(fragment_on_assign, entity, fragment, new_component, old_component) + end else new_component_storage[new_place] = new_component end else - if new_chunk_has_set_or_assign_hooks then - __defer_assign_hook(entity, fragment) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment) + end + + if fragment_on_assign then + __defer_call_hook(fragment_on_assign, entity, fragment) end end else inserted_set[fragment] = true + ---@type evolved.set_hook?, evolved.insert_hook? + local fragment_on_set, fragment_on_insert + + if new_chunk_has_set_or_insert_hooks then + fragment_on_set, fragment_on_insert = __evolved_get(fragment, __ON_SET, __ON_INSERT) + end + local new_component_index = new_component_indices[fragment] if new_component_index then @@ -5068,23 +5442,26 @@ __evolved_multi_set = function(entity, fragments, components) new_component_storage[new_place] = new_component - if new_chunk_has_set_or_insert_hooks then - __defer_insert_hook(entity, fragment, new_component) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment, new_component) end else - if new_chunk_has_set_or_insert_hooks then - __defer_insert_hook(entity, fragment) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment) end end end end __release_table(__table_pool_tag.fragment_set, inserted_set) - - entity_chunks[entity_index] = new_chunk - entity_places[entity_index] = new_place - - __structural_changes = __structural_changes + 1 end __commit() @@ -5153,6 +5530,13 @@ __evolved_multi_assign = function(entity, fragments, components) local fragment = fragments[i] if chunk_fragment_set[fragment] then + ---@type evolved.set_hook?, evolved.assign_hook? + local fragment_on_set, fragment_on_assign + + if chunk_has_set_or_assign_hooks then + fragment_on_set, fragment_on_assign = __evolved_get(fragment, __ON_SET, __ON_ASSIGN) + end + local component_index = chunk_component_indices[fragment] if component_index then @@ -5168,16 +5552,28 @@ __evolved_multi_assign = function(entity, fragments, components) new_component = true end - if chunk_has_set_or_assign_hooks then + if fragment_on_set or fragment_on_assign then local old_component = component_storage[place] + component_storage[place] = new_component - __defer_assign_hook(entity, fragment, new_component, old_component) + + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component, old_component) + end + + if fragment_on_assign then + __defer_call_hook(fragment_on_assign, entity, fragment, new_component, old_component) + end else component_storage[place] = new_component end else - if chunk_has_set_or_assign_hooks then - __defer_assign_hook(entity, fragment) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment) + end + + if fragment_on_assign then + __defer_call_hook(fragment_on_assign, entity, fragment) end end end @@ -5273,6 +5669,13 @@ __evolved_multi_insert = function(entity, fragments, components) __detach_entity(old_chunk, old_place) end + do + entity_chunks[entity_index] = new_chunk + entity_places[entity_index] = new_place + + __structural_changes = __structural_changes + 1 + end + local inserted_set = __acquire_table(__table_pool_tag.fragment_set) for i = 1, fragment_count do @@ -5281,6 +5684,13 @@ __evolved_multi_insert = function(entity, fragments, components) if not inserted_set[fragment] and not old_fragment_set[fragment] then inserted_set[fragment] = true + ---@type evolved.set_hook?, evolved.insert_hook? + local fragment_on_set, fragment_on_insert + + if new_chunk_has_set_or_insert_hooks then + fragment_on_set, fragment_on_insert = __evolved_get(fragment, __ON_SET, __ON_INSERT) + end + local new_component_index = new_component_indices[fragment] if new_component_index then @@ -5298,23 +5708,26 @@ __evolved_multi_insert = function(entity, fragments, components) new_component_storage[new_place] = new_component - if new_chunk_has_set_or_insert_hooks then - __defer_insert_hook(entity, fragment, new_component) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment, new_component) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment, new_component) end else - if new_chunk_has_set_or_insert_hooks then - __defer_insert_hook(entity, fragment) + if fragment_on_set then + __defer_call_hook(fragment_on_set, entity, fragment) + end + + if fragment_on_insert then + __defer_call_hook(fragment_on_insert, entity, fragment) end end end end __release_table(__table_pool_tag.fragment_set, inserted_set) - - entity_chunks[entity_index] = new_chunk - entity_places[entity_index] = new_place - - __structural_changes = __structural_changes + 1 end __commit() @@ -5382,14 +5795,19 @@ __evolved_multi_remove = function(entity, fragments) if not removed_set[fragment] and old_fragment_set[fragment] then removed_set[fragment] = true - local old_component_index = old_component_indices[fragment] + ---@type evolved.remove_hook? + local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE) - if old_component_index then - local old_component_storage = old_component_storages[old_component_index] - local old_component = old_component_storage[old_place] - __defer_remove_hook(entity, fragment, old_component) - else - __defer_remove_hook(entity, fragment) + if fragment_on_remove then + local old_component_index = old_component_indices[fragment] + + if old_component_index then + local old_component_storage = old_component_storages[old_component_index] + local old_component = old_component_storage[old_place] + __defer_call_hook(fragment_on_remove, entity, fragment, old_component) + else + __defer_call_hook(fragment_on_remove, entity, fragment) + end end end end @@ -5417,19 +5835,16 @@ __evolved_multi_remove = function(entity, fragments) local old_cs = old_component_storages[old_ci] new_cs[new_place] = old_cs[old_place] end + end + do __detach_entity(old_chunk, old_place) entity_chunks[entity_index] = new_chunk - entity_places[entity_index] = new_place - else - __detach_entity(old_chunk, old_place) + entity_places[entity_index] = new_chunk and new_chunk.__entity_count - entity_chunks[entity_index] = nil - entity_places[entity_index] = nil + __structural_changes = __structural_changes + 1 end - - __structural_changes = __structural_changes + 1 end __commit() @@ -5915,6 +6330,7 @@ end ---@return evolved.chunk? chunk ---@return evolved.entity[]? entities ---@return integer? entity_count +---@nodiscard __evolved_chunk = function(...) local fragment_count = __lua_select('#', ...) @@ -6019,6 +6435,14 @@ __evolved_select = function(chunk, ...) end end +---@param chunk evolved.chunk +---@return evolved.entity[] entities +---@return integer entity_count +---@nodiscard +__evolved_entities = function(chunk) + return chunk.__entities, chunk.__entity_count +end + ---@param entity evolved.entity ---@return evolved.each_iterator iterator ---@return evolved.each_state? iterator_state @@ -6330,6 +6754,7 @@ end ---@field package __on_assign? evolved.set_hook ---@field package __on_insert? evolved.set_hook ---@field package __on_remove? evolved.remove_hook +---@field package __on_destroy? evolved.id ---@class evolved.fragment_builder : evolved.__fragment_builder local evolved_fragment_builder = {} @@ -6349,6 +6774,7 @@ __evolved_fragment = function() __on_assign = nil, __on_insert = nil, __on_remove = nil, + __on_destroy = nil, } ---@cast builder evolved.fragment_builder return __lua_setmetatable(builder, evolved_fragment_builder) @@ -6416,6 +6842,13 @@ function evolved_fragment_builder:on_remove(on_remove) return self end +---@param on_destroy evolved.id +---@return evolved.fragment_builder builder +function evolved_fragment_builder:on_destroy(on_destroy) + self.__on_destroy = on_destroy + return self +end + ---@return evolved.fragment fragment ---@return boolean is_deferred function evolved_fragment_builder:build() @@ -6429,6 +6862,7 @@ function evolved_fragment_builder:build() local on_assign = self.__on_assign local on_insert = self.__on_insert local on_remove = self.__on_remove + local on_destroy = self.__on_destroy self.__tag = false self.__name = nil @@ -6440,6 +6874,7 @@ function evolved_fragment_builder:build() self.__on_assign = nil self.__on_insert = nil self.__on_remove = nil + self.__on_destroy = nil local fragment = __evolved_id() @@ -6501,6 +6936,12 @@ function evolved_fragment_builder:build() component_list[component_count] = on_remove end + if on_destroy then + component_count = component_count + 1 + fragment_list[component_count] = __ON_DESTROY + component_list[component_count] = on_destroy + end + local _, is_deferred = __evolved_multi_set(fragment, fragment_list, component_list) __release_table(__table_pool_tag.fragment_list, fragment_list) @@ -7069,6 +7510,7 @@ __lua_assert(__evolved_insert(__ON_SET, __NAME, 'ON_SET')) __lua_assert(__evolved_insert(__ON_ASSIGN, __NAME, 'ON_ASSIGN')) __lua_assert(__evolved_insert(__ON_INSERT, __NAME, 'ON_INSERT')) __lua_assert(__evolved_insert(__ON_REMOVE, __NAME, 'ON_REMOVE')) +__lua_assert(__evolved_insert(__ON_DESTROY, __NAME, 'ON_DESTROY')) __lua_assert(__evolved_insert(__PHASE, __NAME, 'PHASE')) __lua_assert(__evolved_insert(__AFTER, __NAME, 'AFTER')) @@ -7079,6 +7521,9 @@ __lua_assert(__evolved_insert(__EXECUTE, __NAME, 'EXECUTE')) __lua_assert(__evolved_insert(__PROLOGUE, __NAME, 'PROLOGUE')) __lua_assert(__evolved_insert(__EPILOGUE, __NAME, 'EPILOGUE')) +__lua_assert(__evolved_insert(__DESTROY_ENTITY_POLICY, __NAME, 'DESTROY_ENTITY_POLICY')) +__lua_assert(__evolved_insert(__REMOVE_FRAGMENT_POLICY, __NAME, 'REMOVE_FRAGMENT_POLICY')) + --- --- --- @@ -7254,6 +7699,7 @@ evolved.ON_SET = __ON_SET evolved.ON_ASSIGN = __ON_ASSIGN evolved.ON_INSERT = __ON_INSERT evolved.ON_REMOVE = __ON_REMOVE +evolved.ON_DESTROY = __ON_DESTROY evolved.PHASE = __PHASE evolved.AFTER = __AFTER @@ -7264,6 +7710,9 @@ evolved.EXECUTE = __EXECUTE evolved.PROLOGUE = __PROLOGUE evolved.EPILOGUE = __EPILOGUE +evolved.DESTROY_ENTITY_POLICY = __DESTROY_ENTITY_POLICY +evolved.REMOVE_FRAGMENT_POLICY = __REMOVE_FRAGMENT_POLICY + evolved.id = __evolved_id evolved.pack = __evolved_pack @@ -7306,6 +7755,7 @@ evolved.batch_multi_remove = __evolved_batch_multi_remove evolved.chunk = __evolved_chunk evolved.select = __evolved_select +evolved.entities = __evolved_entities evolved.each = __evolved_each evolved.execute = __evolved_execute