From 9f1de727ad0ed49e312b34183093231442f96eae Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sun, 29 Dec 2024 14:21:04 +0700 Subject: [PATCH] new evolved.chunk function --- README.md | 3 ++- ROADMAP.md | 4 +++ develop/untests.lua | 51 ++++++++++++++++++++++++++++++++++++ evolved.lua | 64 ++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 115 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2aea55f..75d9ebe 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,8 @@ batch_remove :: query, fragment... -> integer, boolean batch_clear :: query -> integer, boolean batch_destroy :: query -> integer, boolean -select :: chunk, fragment... -> component[]... +chunk :: fragment... -> chunk?, entity[]? +select :: chunk, fragment... -> component[]?... execute :: query -> {execution_state? -> chunk?, entity[]?}, execution_state? ``` diff --git a/ROADMAP.md b/ROADMAP.md index 0014cc3..f21cd4a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -7,3 +7,7 @@ - add auto chunk count reducing - batching api for set/assign/insert/remove/clear/destroy - every chunk can hold has_on_assign/has_on_insert/has_on_remove tags +- rename alive/empty to is_alive/is_empty +- optimize batch operations for cases with moving entities to empty chunks +- optimize batch operations for cases with fragments without constructs +- don't create empty exclude_set in execution every time when it's not exist diff --git a/develop/untests.lua b/develop/untests.lua index 6ed9a3e..72a74c9 100644 --- a/develop/untests.lua +++ b/develop/untests.lua @@ -578,6 +578,57 @@ do end end +do + local f1, f2, f3 = evo.id(3) + + local e0 = evo.id() + + local e1 = evo.id() + assert(evo.insert(e1, f1, 41)) + + local e2 = evo.id() + assert(evo.insert(e2, f1, 42)) + assert(evo.insert(e2, f2, 43)) + + local e2b = evo.id() + assert(evo.insert(e2b, f1, 44)) + assert(evo.insert(e2b, f2, 45)) + + do + local chunk, entities = evo.chunk() + assert(not chunk and not entities) + end + + do + local chunk, entities = evo.chunk(f1) + assert(entities and entities[1] == e1) + assert(chunk and evo.select(chunk, f1)[1] == 41) + end + + do + local chunk, entities = evo.chunk(f1, f2) + assert(chunk == evo.chunk(f1, f2)) + assert(chunk == evo.chunk(f1, f1, f2)) + assert(chunk == evo.chunk(f1, f1, f2, f2)) + assert(chunk == evo.chunk(f1, f2, f2, f1)) + assert(chunk == evo.chunk(f2, f1)) + assert(chunk == evo.chunk(f2, f1, f2, f1)) + assert(entities and entities[1] == e2 and entities[2] == e2b) + assert(chunk and evo.select(chunk, f1)[1] == 42 and evo.select(chunk, f2)[1] == 43) + assert(chunk and evo.select(chunk, f1)[2] == 44 and evo.select(chunk, f2)[2] == 45) + end + + do + local chunk, entities = evo.chunk(f1, f2, f3) + assert(not chunk and not entities) + end + + do + local chunk, entities = evo.chunk(f3, f2, f1) + assert(not chunk and not entities) + end +end + do local f1, f2, f3 = evo.id(3) diff --git a/evolved.lua b/evolved.lua index 408154f..c991e76 100644 --- a/evolved.lua +++ b/evolved.lua @@ -17,11 +17,8 @@ local evolved = {} ---@field package __with_fragment_edges table ---@field package __without_fragment_edges table ----@alias evolved.include_set table ----@alias evolved.exclude_set table - ---@alias evolved.execution_stack evolved.chunk[] ----@alias evolved.execution_state [integer, evolved.exclude_set, evolved.execution_stack] +---@alias evolved.execution_state [integer, table, evolved.execution_stack] ---@alias evolved.execution_iterator fun(state: evolved.execution_state?): evolved.chunk?, evolved.entity[]? --- @@ -43,6 +40,7 @@ local __major_chunks = {} ---@type table local __entity_chunks = {} ---@type table local __entity_places = {} ---@type table +local __fragment_lists = {} ---@type evolved.fragment[][] local __execution_stacks = {} ---@type evolved.execution_stack[] local __execution_states = {} ---@type evolved.execution_state[] @@ -151,6 +149,25 @@ end --- --- +---@return evolved.fragment[] +---@nodiscard +local function __acquire_fragment_list() + if #__fragment_lists == 0 then + return {} + end + + local list = __fragment_lists[#__fragment_lists] + __fragment_lists[#__fragment_lists] = nil + + return list +end + +---@param list evolved.fragment[] +local function __release_fragment_list(list) + for i = #list, 1, -1 do list[i] = nil end + __fragment_lists[#__fragment_lists + 1] = list +end + ---@return evolved.execution_stack ---@nodiscard local function __acquire_execution_stack() @@ -170,7 +187,7 @@ local function __release_execution_stack(stack) __execution_stacks[#__execution_stacks + 1] = stack end ----@param exclude_set evolved.exclude_set +---@param exclude_set table ---@return evolved.execution_state ---@return evolved.execution_stack ---@nodiscard @@ -1564,9 +1581,43 @@ end)) --- --- +---@param ... evolved.fragment fragments +---@return evolved.chunk?, evolved.entity[]? +function evolved.chunk(...) + local fragment_count = select('#', ...) + + if fragment_count == 0 then + return + end + + local sorted_fragment_list = __acquire_fragment_list() + + for i = 1, fragment_count do + local fragment = select(i, ...) + sorted_fragment_list[#sorted_fragment_list + 1] = fragment + end + + table.sort(sorted_fragment_list) + + local root_fragment = sorted_fragment_list[1] + local chunk = __root_chunks[root_fragment] + if not chunk then return end + + for i = 2, fragment_count do + local child_fragment = sorted_fragment_list[i] + if child_fragment > sorted_fragment_list[i - 1] then + chunk = chunk.__with_fragment_edges[child_fragment] + if not chunk then return end + end + end + + __release_fragment_list(sorted_fragment_list) + return chunk, chunk.__entities +end + ---@param chunk evolved.chunk ---@param ... evolved.fragment fragments ----@return evolved.component[] ... components +---@return evolved.component[]? ... components ---@nodiscard function evolved.select(chunk, ...) local fragment_count = select('#', ...) @@ -1622,6 +1673,7 @@ function evolved.execute(query) return __execution_iterator, nil end + ---@type table local exclude_set = evolved.get(query, __EXCLUDE_SET) or {} local execution_state, execution_stack = __acquire_execution_state(exclude_set)