diff --git a/README.md b/README.md index 1969593..2551797 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,8 @@ registry.has -> entity -> entity -> (boolean) registry.has_all -> entity -> entity... -> (boolean) registry.has_any -> entity -> entity... -> (boolean) registry.assign -> entity -> entity -> any -> () -registry.insert -> entity -> entity -> any -> () -registry.remove -> entity -> entity -> () +registry.insert -> entity -> entity -> any -> (boolean) +registry.remove -> entity -> entity... -> (boolean) registry.query -> entity -> entity... -> (query) registry.execute -> query -> (() -> (chunk?)) registry.chunk -> entity -> entity... -> (chunk) @@ -55,8 +55,8 @@ entity:has -> entity -> (boolean) entity:has_all -> entity... -> (boolean) entity:has_any -> entity... -> (boolean) entity:assign -> entity -> any -> () -entity:insert -> entity -> any -> () -entity:remove -> entity -> () +entity:insert -> entity -> any -> (boolean) +entity:remove -> entity... -> (boolean) ``` ### Instance `query` diff --git a/ROADMAP.md b/ROADMAP.md index a08cf0e..5d1643d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -7,7 +7,9 @@ - [ ] add blocklist of fragments for queries - [ ] add checks of prohibited changes while querying - [ ] add check inserts and removes after destroying entity -- [ ] add multi remove fragments function from entities +- [x] add multi remove fragments function from entities +- [ ] add multi get fragments function from entities +- [ ] add multi entity creation function - [ ] cache matched chunks in queries - [x] cache transitions between chunks - [x] chunk's children should be stored in an array instead of a table \ No newline at end of file diff --git a/develop/untests/registry_untests.lua b/develop/untests/registry_untests.lua index a24a7d8..000363d 100644 --- a/develop/untests/registry_untests.lua +++ b/develop/untests/registry_untests.lua @@ -2,26 +2,53 @@ local evo = require 'evolved.evolved' do - local f1, f2 = evo.registry.entity(), evo.registry.entity() + local f1, f2, f3 = + evo.registry.entity(), + evo.registry.entity(), + evo.registry.entity() local e = evo.registry.entity() assert(e.__chunk == nil) - e:insert(f1) + assert(e:insert(f1)) assert(e:has(f1)) assert(not e:has(f2)) - e:insert(f2) + assert(e:insert(f2)) assert(e:has(f1)) assert(e:has(f2)) - e:remove(f1) + assert(e:remove(f1)) assert(not e:has(f1)) assert(e:has(f2)) - e:remove(f2) + assert(e:remove(f2)) assert(not e:has(f1)) assert(not e:has(f2)) + + assert(e:insert(f3)) + assert(not e:remove(f2)) + assert(not e:remove()) +end + +do + local f1, f2, f3, f4, f5 = + evo.registry.entity(), + evo.registry.entity(), + evo.registry.entity(), + evo.registry.entity(), + evo.registry.entity() + + local e = evo.registry.entity() + + assert(e:insert(f1, f1:guid())) + assert(e:insert(f2, f2:guid())) + assert(e:insert(f3, f3:guid())) + assert(e:insert(f4, f4:guid())) + + assert(e:remove(f1, f2, f5)) + + assert(e.__chunk == evo.registry.chunk(f3, f4)) end do @@ -36,15 +63,14 @@ do assert(e:get_or(f) == nil) assert(e:get_or(f, 42) == 42) - e:insert(f, 84) + assert(e:insert(f, 84)) assert(e:get(f) == 84) assert(e:get_or(f) == 84) assert(e:get_or(f, 42) == 84) - if not os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") then - assert(not pcall(e.insert, e, f, 42)) - end + assert(not e:insert(f, 42)) + assert(e:get(f) == 42) e:assign(f) assert(e:get(f) == true) @@ -102,7 +128,7 @@ end for _ = 1, 100 do local insert_fragments = {} ---@type evolved.entity[] - local insert_fragment_count = math.random(1, 10) + local insert_fragment_count = math.random(0, 10) for _ = 1, insert_fragment_count do local fragment = evo.registry.entity() @@ -110,7 +136,7 @@ for _ = 1, 100 do end local remove_fragments = {} ---@type evolved.entity[] - local remove_fragment_count = math.random(1, insert_fragment_count) + local remove_fragment_count = math.random(0, insert_fragment_count) for _ = 1, remove_fragment_count do local fragment = insert_fragments[math.random(1, #insert_fragments)] diff --git a/evolved/registry.lua b/evolved/registry.lua index 7bef438..2c648f9 100644 --- a/evolved/registry.lua +++ b/evolved/registry.lua @@ -334,7 +334,8 @@ end ---@return boolean ---@nodiscard function registry.has(entity, fragment) - return entity.__chunk ~= nil and __chunk_has_fragment(entity.__chunk, fragment) + if entity.__chunk == nil then return false end + return __chunk_has_fragment(entity.__chunk, fragment) end ---@param entity evolved.entity @@ -373,6 +374,7 @@ end ---@param entity evolved.entity ---@param fragment evolved.entity ---@param component any +---@return boolean is_inserted function registry.insert(entity, fragment, component) component = component == nil and true or component @@ -380,62 +382,71 @@ function registry.insert(entity, fragment, component) local new_chunk = __chunk_with_fragment(old_chunk, fragment) if old_chunk == new_chunk then - error(string.format('entity %s already has fragment %s', entity, fragment), 2) + local chunk_components = new_chunk.__components[fragment] + chunk_components[entity.__index_in_chunk] = component + return false end local old_index_in_chunk = entity.__index_in_chunk - local new_index_in_chunk = new_chunk and #new_chunk.__entities + 1 or 0 + local new_index_in_chunk = #new_chunk.__entities + 1 - if new_chunk ~= nil then - new_chunk.__entities[new_index_in_chunk] = entity - new_chunk.__components[fragment][new_index_in_chunk] = component - - if old_chunk ~= nil then - for old_f, old_cs in pairs(old_chunk.__components) do - local new_cs = new_chunk.__components[old_f] - new_cs[new_index_in_chunk] = old_cs[old_index_in_chunk] - end - end - end + new_chunk.__entities[new_index_in_chunk] = entity + new_chunk.__components[fragment][new_index_in_chunk] = component if old_chunk ~= nil then + for old_f, old_cs in pairs(old_chunk.__components) do + local new_cs = new_chunk.__components[old_f] + new_cs[new_index_in_chunk] = old_cs[old_index_in_chunk] + end + __detach_entity(entity) end entity.__chunk = new_chunk entity.__index_in_chunk = new_index_in_chunk + + return true end ---@param entity evolved.entity ----@param fragment evolved.entity -function registry.remove(entity, fragment) +---@param ... evolved.entity fragments +---@return boolean is_removed +function registry.remove(entity, ...) local old_chunk = entity.__chunk - local new_chunk = __chunk_without_fragment(old_chunk, fragment) + local new_chunk = entity.__chunk + + for i = 1, select('#', ...) do + local fragment = select(i, ...) + new_chunk = __chunk_without_fragment(new_chunk, fragment) + end if old_chunk == new_chunk then - error(string.format('entity %s does not have fragment %s', entity, fragment), 2) + return false + end + + if new_chunk == nil then + __detach_entity(entity) + return true end local old_index_in_chunk = entity.__index_in_chunk - local new_index_in_chunk = new_chunk and #new_chunk.__entities + 1 or 0 + local new_index_in_chunk = #new_chunk.__entities + 1 - if new_chunk ~= nil then - new_chunk.__entities[new_index_in_chunk] = entity - - if old_chunk ~= nil then - for new_f, new_cs in pairs(new_chunk.__components) do - local old_cs = old_chunk.__components[new_f] - new_cs[new_index_in_chunk] = old_cs[old_index_in_chunk] - end - end - end + new_chunk.__entities[new_index_in_chunk] = entity if old_chunk ~= nil then + for new_f, new_cs in pairs(new_chunk.__components) do + local old_cs = old_chunk.__components[new_f] + new_cs[new_index_in_chunk] = old_cs[old_index_in_chunk] + end + __detach_entity(entity) end entity.__chunk = new_chunk entity.__index_in_chunk = new_index_in_chunk + + return true end ---@param fragment evolved.entity