diff --git a/README.md b/README.md index b8da5c4..c32fb20 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,8 @@ - [Batch Operations](#batch-operations) - [Systems](#systems) - [Processing Payloads](#processing-payloads) - - [Predefined Traits](#predefined-traits) + - [Predefined Fragments](#predefined-fragments) + - [Entity Names](#entity-names) - [Fragment Tags](#fragment-tags) - [Fragment Hooks](#fragment-hooks) - [Unique Fragments](#unique-fragments) @@ -55,6 +56,7 @@ - [Fragment Requirements](#fragment-requirements) - [Destruction Policies](#destruction-policies) - [Custom Component Storages](#custom-component-storages) + - [Garbage Collection](#garbage-collection) - [Cheat Sheet](#cheat-sheet) - [Aliases](#aliases) - [Predefs](#predefs) @@ -63,6 +65,7 @@ - [Chunk](#chunk) - [Builder](#builder) - [Changelog](#changelog) + - [v1.10.0](#v1100) - [v1.9.0](#v190) - [v1.8.0](#v180) - [v1.7.0](#v170) @@ -488,6 +491,7 @@ When you need to spawn multiple entities with identical fragments, use `multi_sp ---@param component_mapper? evolved.component_mapper ---@return evolved.entity[] entity_list ---@return integer entity_count +---@nodiscard function evolved.multi_spawn(entity_count, component_table, component_mapper) end ---@param entity_count integer @@ -496,6 +500,7 @@ function evolved.multi_spawn(entity_count, component_table, component_mapper) en ---@param component_mapper? evolved.component_mapper ---@return evolved.entity[] entity_list ---@return integer entity_count +---@nodiscard function evolved.multi_clone(entity_count, prefab, component_table, component_mapper) end ``` @@ -526,6 +531,36 @@ end) Of course, you can use `evolved.multi_clone` in the same way. Builders can also be used for multi-entity spawning and cloning by calling the corresponding methods on the builder object. +Also, for all `multi_` functions, the library provides [`_nr`](#evolvedmulti_spawn_nr) and [`_to`](#evolvedmulti_spawn_to) suffix variants that allow you to perform these operations without returning the list of spawned entities or by copying the spawned entities to your own table, which can be more efficient because it avoids the overhead of allocating and returning a new table. + +```lua +local evolved = require 'evolved' + +local position_x, position_y = evolved.id(2) + +do + -- we don't interest in the list of spawned entities, + -- so we use the _nr variant of the multi_spawn function + + evolved.multi_spawn_nr(100, { + [position_x] = 0, + [position_y] = 0, + }) +end + +do + -- store spawned entities in our own table starting at index 1, + -- so we use the _to variant of the multi_spawn function + + local entity_list = {} + + evolved.multi_spawn_to(entity_list, 1, 100, { + [position_x] = 0, + [position_y] = 0, + }) +end +``` + ### Access Operations The library provides all the necessary functions to access entities and their components. I'm not going to cover all the accessor functions here, because they are pretty straightforward and self-explanatory. You can check the [API Reference](#api-reference) for all of them. Here are some of the most important ones: @@ -980,7 +1015,42 @@ evolved.process_with(physics_system, delta_time) `delta_time` in this example is passed as a processing payload to the system's execution callback. Payloads can be of any type and can be multiple values. Also, payloads are passed to prologue and epilogue callbacks if they are defined. Every subsystem in a group will receive the same payload when the group is processed with [`evolved.process_with`](#evolvedprocess_with). -### Predefined Traits +### Predefined Fragments + +#### Entity Names + +The library provides a way to assign names to any id using the [`evolved.NAME`](#evolvedname) fragment. This is useful for debugging and development purposes, as it allows you to identify entities or fragments by their names instead of their identifiers. The name of an entity can be retrieved using the [`evolved.name`](#evolvedname-1) function. + +```lua +local evolved = require 'evolved' + +local player = evolved.builder() + :name('Player') + :build() + +assert(evolved.name(player) == 'Player') +``` + +Names are not unique, so multiple entities can have the same name. Also, the name of an entity can be changed at any time by setting a new name using the [`evolved.NAME`](#evolvedname) fragment as a usual component. + +You can find entities by their names using the [`evolved.lookup`](#evolvedlookup) and [`evolved.multi_lookup`](#evolvedmulti_lookup) functions. The [`evolved.lookup`](#evolvedlookup) function returns the first entity with the specified name, while the [`evolved.multi_lookup`](#evolvedmulti_lookup) function returns a list of all entities with the specified name. + +```lua +local evolved = require 'evolved' + +local player1 = evolved.builder() + :name('Player') + :build() + +local player2 = evolved.builder() + :name('Player') + :build() + +assert(evolved.lookup('Player') == player1) + +local player_list, player_count = evolved.multi_lookup('Player') +assert(player_count == 2 and player_list[1] == player1 and player_list[2] == player2) +``` #### Fragment Tags @@ -1346,6 +1416,24 @@ evolved.builder() evolved.process_with(MOVEMENT_SYSTEM, 0.016) ``` +### Garbage Collection + +While using the library, some internal data structures can become obsolete and should be cleaned up to free memory. For example, empty chunks that no longer contain entities can be removed. Component storages can also have unused capacity that can be shrunk to save memory. The library provides a function to control this garbage collection process. + +```lua +---@param no_shrink? boolean +function evolved.collect_garbage(no_shrink) end +``` + +By default, [`evolved.collect_garbage`](#evolvedcollect_garbage) cleans up obsolete data structures and shrinks component storages to fit their current size. If you pass `true`, it only cleans up obsolete data structures and skips shrinking. This avoids the overhead of resizing storages, which can be expensive. + +Call this function periodically to keep memory usage under control. It is best to call it between levels or during loading screens when performance is not critical. Also, call Lua's built-in garbage collector afterward to ensure all unused memory is freed. + +```lua +evolved.collect_garbage() +collectgarbage('collect') +``` + ## Cheat Sheet ### Aliases @@ -1444,9 +1532,13 @@ cancel :: boolean spawn :: component_table?, component_mapper? -> entity multi_spawn :: integer, component_table?, component_mapper? -> entity[], integer +multi_spawn_nr :: integer, component_table?, component_mapper? -> () +multi_spawn_to :: entity[], integer, integer, component_table?, component_mapper? -> () clone :: entity, component_table?, component_mapper? -> entity multi_clone :: integer, entity, component_table?, component_mapper? -> entity[], integer +multi_clone_nr :: integer, entity, component_table?, component_mapper? -> () +multi_clone_to :: entity[], integer, integer, entity, component_table?, component_mapper? -> () alive :: entity -> boolean alive_all :: entity... -> boolean @@ -1477,11 +1569,15 @@ execute :: query -> {execute_state? -> chunk?, entity[]?, integer?}, execute_sta locate :: entity -> chunk?, integer +lookup :: string -> entity? +multi_lookup :: string -> entity[], integer +multi_lookup_to :: entity[], integer, string -> integer + process :: system... -> () process_with :: system, ... -> () debug_mode :: boolean -> () -collect_garbage :: () +collect_garbage :: boolean? -> () ``` ### Classes @@ -1510,12 +1606,18 @@ builder :: builder builder_mt:build :: entity?, component_mapper? -> entity builder_mt:multi_build :: integer, entity?, component_mapper? -> entity[], integer +builder_mt:multi_build_nr :: integer, entity?, component_mapper? -> () +builder_mt:multi_build_to :: entity[], integer, integer, entity?, component_mapper? -> () builder_mt:spawn :: component_mapper? -> entity builder_mt:multi_spawn :: integer, component_mapper? -> entity[], integer +builder_mt:multi_spawn_nr :: integer, component_mapper? -> () +builder_mt:multi_spawn_to :: entity[], integer, integer, component_mapper? -> () builder_mt:clone :: entity, component_mapper? -> entity builder_mt:multi_clone :: integer, entity, component_mapper? -> entity[], integer +builder_mt:multi_clone_nr :: integer, entity, component_mapper? -> () +builder_mt:multi_clone_to :: entity[], integer, integer, entity, component_mapper? -> () builder_mt:has :: fragment -> boolean builder_mt:has_all :: fragment... -> boolean @@ -1566,6 +1668,12 @@ builder_mt:destruction_policy :: id -> builder ## Changelog +### v1.10.0 + +- Added the new [`evolved.lookup`](#evolvedlookup) and [`evolved.multi_lookup`](#evolvedmulti_lookup) functions that allow finding ids by their names +- Added a non-shrinking version of the [`evolved.collect_garbage`](#evolvedcollect_garbage) function that only collects garbage without shrinking storages +- Added [`_nr`](#evolvedmulti_spawn_nr) and [`_to`](#evolvedmulti_spawn_to) variants of the [`evolved.multi_spawn`](#evolvedmulti_spawn) and [`evolved.multi_clone`](#evolvedmulti_clone) functions that provide more efficient ways to spawn or clone entities in some cases + ### v1.9.0 - Performance improvements of the [`evolved.destroy`](#evolveddestroy) and [`evolved.batch_destroy`](#evolvedbatch_destroy) functions @@ -1771,9 +1879,31 @@ function evolved.spawn(component_table, component_mapper) end ---@param component_mapper? evolved.component_mapper ---@return evolved.entity[] entity_list ---@return integer entity_count +---@nodiscard function evolved.multi_spawn(entity_count, component_table, component_mapper) end ``` +### `evolved.multi_spawn_nr` + +```lua +---@param entity_count integer +---@param component_table? evolved.component_table +---@param component_mapper? evolved.component_mapper +function evolved.multi_spawn_nr(entity_count, component_table, component_mapper) end +``` + +### `evolved.multi_spawn_to` + +```lua +---@param out_entity_list evolved.entity[] +---@param out_entity_first integer +---@param entity_count integer +---@param component_table? evolved.component_table +---@param component_mapper? evolved.component_mapper +function evolved.multi_spawn_to(out_entity_list, out_entity_first, + entity_count, component_table, component_mapper) end +``` + ### `evolved.clone` ```lua @@ -1793,9 +1923,33 @@ function evolved.clone(prefab, component_table, component_mapper) end ---@param component_mapper? evolved.component_mapper ---@return evolved.entity[] entity_list ---@return integer entity_count +---@nodiscard function evolved.multi_clone(entity_count, prefab, component_table, component_mapper) end ``` +### `evolved.multi_clone_nr` + +```lua +---@param entity_count integer +---@param prefab evolved.entity +---@param component_table? evolved.component_table +---@param component_mapper? evolved.component_mapper +function evolved.multi_clone_nr(entity_count, prefab, component_table, component_mapper) end +``` + +### `evolved.multi_clone_to` + +```lua +---@param out_entity_list evolved.entity[] +---@param out_entity_first integer +---@param entity_count integer +---@param prefab evolved.entity +---@param component_table? evolved.component_table +---@param component_mapper? evolved.component_mapper +function evolved.multi_clone_to(out_entity_list, out_entity_first, + entity_count, prefab, component_table, component_mapper) end +``` + ### `evolved.alive` ```lua @@ -1982,6 +2136,35 @@ function evolved.execute(query) end function evolved.locate(entity) end ``` +### `evolved.lookup` + +```lua +---@param name string +---@return evolved.entity? entity +---@nodiscard +function evolved.lookup(name) end +``` + +### `evolved.multi_lookup` + +```lua +---@param name string +---@return evolved.entity[] entity_list +---@return integer entity_count +---@nodiscard +function evolved.multi_lookup(name) end +``` + +### `evolved.multi_lookup_to` + +```lua +---@param out_entity_list evolved.entity[] +---@param out_entity_first integer +---@param name string +---@return integer entity_count +function evolved.multi_lookup_to(out_entity_list, out_entity_first, name) end +``` + ### `evolved.process` ```lua @@ -2007,7 +2190,8 @@ function evolved.debug_mode(yesno) end ### `evolved.collect_garbage` ```lua -function evolved.collect_garbage() end +---@param no_shrink? boolean +function evolved.collect_garbage(no_shrink) end ``` ## Classes @@ -2123,9 +2307,31 @@ function evolved.builder_mt:build(prefab, component_mapper) end ---@param component_mapper? evolved.component_mapper ---@return evolved.entity[] entity_list ---@return integer entity_count +---@nodiscard function evolved.builder_mt:multi_build(entity_count, prefab, component_mapper) end ``` +### `evolved.builder_mt:multi_build_nr` + +```lua +---@param entity_count integer +---@param prefab? evolved.entity +---@param component_mapper? evolved.component_mapper +function evolved.builder_mt:multi_build_nr(entity_count, prefab, component_mapper) end +``` + +### `evolved.builder_mt:multi_build_to` + +```lua +---@param out_entity_list evolved.entity[] +---@param out_entity_first integer +---@param entity_count integer +---@param prefab? evolved.entity +---@param component_mapper? evolved.component_mapper +function evolved.builder_mt:multi_build_to(out_entity_list, out_entity_first, + entity_count, prefab, component_mapper) end +``` + #### `evolved.builder_mt:spawn` ```lua @@ -2141,9 +2347,29 @@ function evolved.builder_mt:spawn(component_mapper) end ---@param component_mapper? evolved.component_mapper ---@return evolved.entity[] entity_list ---@return integer entity_count +---@nodiscard function evolved.builder_mt:multi_spawn(entity_count, component_mapper) end ``` +#### `evolved.builder_mt:multi_spawn_nr` + +```lua +---@param entity_count integer +---@param component_mapper? evolved.component_mapper +function evolved.builder_mt:multi_spawn_nr(entity_count, component_mapper) end +``` + +#### `evolved.builder_mt:multi_spawn_to` + +```lua +---@param out_entity_list evolved.entity[] +---@param out_entity_first integer +---@param entity_count integer +---@param component_mapper? evolved.component_mapper +function evolved.builder_mt:multi_spawn_to(out_entity_list, out_entity_first, + entity_count, component_mapper) end +``` + #### `evolved.builder_mt:clone` ```lua @@ -2161,9 +2387,31 @@ function evolved.builder_mt:clone(prefab, component_mapper) end ---@param component_mapper? evolved.component_mapper ---@return evolved.entity[] entity_list ---@return integer entity_count +---@nodiscard function evolved.builder_mt:multi_clone(entity_count, prefab, component_mapper) end ``` +#### `evolved.builder_mt:multi_clone_nr` + +```lua +---@param entity_count integer +---@param prefab evolved.entity +---@param component_mapper? evolved.component_mapper +function evolved.builder_mt:multi_clone_nr(entity_count, prefab, component_mapper) end +``` + +#### `evolved.builder_mt:multi_clone_to` + +```lua +---@param out_entity_list evolved.entity[] +---@param out_entity_first integer +---@param entity_count integer +---@param prefab evolved.entity +---@param component_mapper? evolved.component_mapper +function evolved.builder_mt:multi_clone_to(out_entity_list, out_entity_first, + entity_count, prefab, component_mapper) end +``` + #### `evolved.builder_mt:has` ```lua diff --git a/develop/ROADMAP.md b/develop/ROADMAP.md index 863bc8d..85b9616 100644 --- a/develop/ROADMAP.md +++ b/develop/ROADMAP.md @@ -9,7 +9,6 @@ ## Thoughts - We should have a way to not copy components on deferred spawn/clone -- Having a light version of the gargabe collector can be useful for some use-cases - Basic default component value as true looks awful, should we use something else? ## Known Issues diff --git a/develop/all.lua b/develop/all.lua index a4ff731..f6c928b 100644 --- a/develop/all.lua +++ b/develop/all.lua @@ -4,6 +4,7 @@ require 'develop.testing.clone_tests' require 'develop.testing.depth_tests' require 'develop.testing.destroy_tests' require 'develop.testing.locate_tests' +require 'develop.testing.lookup_tests' require 'develop.testing.main_tests' require 'develop.testing.mappers_tests' require 'develop.testing.multi_spawn_tests' diff --git a/develop/benchmarks/clone_bmarks.lua b/develop/benchmarks/clone_bmarks.lua index 863f244..e2d297c 100644 --- a/develop/benchmarks/clone_bmarks.lua +++ b/develop/benchmarks/clone_bmarks.lua @@ -307,11 +307,11 @@ print '----------------------------------------' basics.describe_bench( string.format('Clone Benchmarks: Multi Clone | %d entities with 1 component', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [F1] = true } - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.batch_destroy(QF1) end) @@ -319,12 +319,12 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Defer Clone | %d entities with 1 component', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [F1] = true } evo.defer() - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.commit() evo.batch_destroy(QF1) @@ -333,11 +333,11 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Clone With Defaults | %d entities with 1 component', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [D1] = true } - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.batch_destroy(QD1) end) @@ -345,11 +345,11 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Clone | %d entities with 3 components', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true } - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.batch_destroy(QF1) end) @@ -357,12 +357,12 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Defer Clone | %d entities with 3 components', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true } evo.defer() - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.commit() evo.batch_destroy(QF1) @@ -371,11 +371,11 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Clone With Defaults | %d entities with 3 components', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [D1] = true, [D2] = true, [D3] = true } - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.batch_destroy(QD1) end) @@ -383,11 +383,11 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Clone | %d entities with 5 components', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true } - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.batch_destroy(QF1) end) @@ -395,12 +395,12 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Defer Clone | %d entities with 5 components', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true } evo.defer() - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.commit() evo.batch_destroy(QF1) @@ -409,11 +409,11 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Clone With Defaults | %d entities with 5 components', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [D1] = true, [D2] = true, [D3] = true, [D4] = true, [D5] = true } - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.batch_destroy(QD1) end) @@ -423,11 +423,11 @@ print '----------------------------------------' basics.describe_bench( string.format('Clone Benchmarks: Multi Clone | %d entities with 1 required component', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [RF1] = true } - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.batch_destroy(QF1) end) @@ -435,12 +435,12 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Defer Clone | %d entities with 1 required component', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [RF1] = true } evo.defer() - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.commit() evo.batch_destroy(QF1) @@ -449,11 +449,11 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Clone With Defaults | %d entities with 1 required component', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [RD1] = true } - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.batch_destroy(QD1) end) @@ -461,11 +461,11 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Clone | %d entities with 3 required components', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [RF123] = true } - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.batch_destroy(QF1) end) @@ -473,12 +473,12 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Defer Clone | %d entities with 3 required components', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [RF123] = true } evo.defer() - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.commit() evo.batch_destroy(QF1) @@ -487,11 +487,11 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Clone With Defaults | %d entities with 3 required components', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [RD123] = true } - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.batch_destroy(QD1) end) @@ -499,11 +499,11 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Clone | %d entities with 5 required components', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [RF12345] = true } - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.batch_destroy(QF1) end) @@ -511,12 +511,12 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Defer Clone | %d entities with 5 required components', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [RF12345] = true } evo.defer() - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.commit() evo.batch_destroy(QF1) @@ -525,11 +525,11 @@ basics.describe_bench( basics.describe_bench( string.format('Clone Benchmarks: Multi Clone With Defaults | %d entities with 5 required components', N), function() - local multi_clone = evo.multi_clone + local multi_clone_nr = evo.multi_clone_nr local prefab = evo.spawn { [RD12345] = true } - multi_clone(N, prefab) + multi_clone_nr(N, prefab) evo.batch_destroy(QD1) end) diff --git a/develop/benchmarks/common_bmarks.lua b/develop/benchmarks/common_bmarks.lua index 4e5964f..c63f232 100644 --- a/develop/benchmarks/common_bmarks.lua +++ b/develop/benchmarks/common_bmarks.lua @@ -54,7 +54,7 @@ basics.describe_bench(string.format('Common Benchmarks: Evolved Entity Cycle | % local prefab_a = evo.builder():prefab():set(world):set(a, 0):spawn() local prefab_b = evo.builder():prefab():set(world):set(b, 0):spawn() - evo.multi_clone(N, prefab_a) + evo.multi_clone_nr(N, prefab_a) evo.builder() :set(world):group(world):query(query_a) @@ -129,10 +129,10 @@ basics.describe_bench(string.format('Common Benchmarks: Evolved Simple Iteration local query_cd = evo.builder():set(world):include(c, d):spawn() local query_ce = evo.builder():set(world):include(c, e):spawn() - evo.multi_spawn(N, { [world] = true, [a] = 0, [b] = 0 }) - evo.multi_spawn(N, { [world] = true, [a] = 0, [b] = 0, [c] = 0 }) - evo.multi_spawn(N, { [world] = true, [a] = 0, [b] = 0, [c] = 0, [d] = 0 }) - evo.multi_spawn(N, { [world] = true, [a] = 0, [b] = 0, [c] = 0, [e] = 0 }) + evo.multi_spawn_nr(N, { [world] = true, [a] = 0, [b] = 0 }) + evo.multi_spawn_nr(N, { [world] = true, [a] = 0, [b] = 0, [c] = 0 }) + evo.multi_spawn_nr(N, { [world] = true, [a] = 0, [b] = 0, [c] = 0, [d] = 0 }) + evo.multi_spawn_nr(N, { [world] = true, [a] = 0, [b] = 0, [c] = 0, [e] = 0 }) evo.builder() :set(world):group(world):query(query_ab) @@ -223,7 +223,7 @@ basics.describe_bench(string.format('Common Benchmarks: Evolved Packed Iteration local query_d = evo.builder():set(world):include(d):spawn() local query_e = evo.builder():set(world):include(e):spawn() - evo.multi_spawn(N, { [world] = true, [a] = 0, [b] = 0, [c] = 0, [d] = 0, [e] = 0 }) + evo.multi_spawn_nr(N, { [world] = true, [a] = 0, [b] = 0, [c] = 0, [d] = 0, [e] = 0 }) evo.builder() :set(world):group(world):query(query_a) @@ -317,7 +317,7 @@ basics.describe_bench(string.format('Common Benchmarks: Evolved Fragmented Itera local query_z = evo.builder():set(world):include(chars[#chars]):spawn() for i = 1, #chars do - evo.multi_spawn(N, { [world] = true, [chars[i]] = i, [data] = i }) + evo.multi_spawn_nr(N, { [world] = true, [chars[i]] = i, [data] = i }) end evo.builder() diff --git a/develop/benchmarks/process_bmarks.lua b/develop/benchmarks/process_bmarks.lua index ce1e780..287a8dd 100644 --- a/develop/benchmarks/process_bmarks.lua +++ b/develop/benchmarks/process_bmarks.lua @@ -20,7 +20,7 @@ basics.describe_bench(string.format('Process Benchmarks: Evolved AoS Processing local pf = evo.builder():set(wf):spawn() local vf = evo.builder():set(wf):spawn() - evo.multi_spawn(N, { + evo.multi_spawn_nr(N, { [wf] = true, [pf] = { x = 0, y = 0, z = 0, w = 0 }, [vf] = { x = 0, y = 0, z = 0, w = 0 }, @@ -67,7 +67,7 @@ basics.describe_bench(string.format('Process Benchmarks: Evolved SoA Processing local vzf = evo.builder():set(wf):spawn() local vwf = evo.builder():set(wf):spawn() - evo.multi_spawn(N, { + evo.multi_spawn_nr(N, { [wf] = true, [pxf] = 0, [pyf] = 0, diff --git a/develop/benchmarks/spawn_bmarks.lua b/develop/benchmarks/spawn_bmarks.lua index 5725425..a6ee5dc 100644 --- a/develop/benchmarks/spawn_bmarks.lua +++ b/develop/benchmarks/spawn_bmarks.lua @@ -536,11 +536,11 @@ print '----------------------------------------' basics.describe_bench( string.format('Spawn Benchmarks: Multi Spawn | %d entities with 1 component', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [F1] = true } - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.batch_destroy(QF1) end) @@ -548,12 +548,12 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Defer Spawn | %d entities with 1 component', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [F1] = true } evo.defer() - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.commit() evo.batch_destroy(QF1) @@ -562,11 +562,11 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Spawn With Defaults | %d entities with 1 component', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [D1] = true } - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.batch_destroy(QD1) end) @@ -574,11 +574,11 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Spawn | %d entities with 3 components', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [F1] = true, [F2] = true, [F3] = true } - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.batch_destroy(QF1) end) @@ -586,12 +586,12 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Defer Spawn | %d entities with 3 components', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [F1] = true, [F2] = true, [F3] = true } evo.defer() - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.commit() evo.batch_destroy(QF1) @@ -600,11 +600,11 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Spawn With Defaults | %d entities with 3 components', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [D1] = true, [D2] = true, [D3] = true } - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.batch_destroy(QD1) end) @@ -612,11 +612,11 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Spawn | %d entities with 5 components', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true } - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.batch_destroy(QF1) end) @@ -624,12 +624,12 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Defer Spawn | %d entities with 5 components', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true } evo.defer() - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.commit() evo.batch_destroy(QF1) @@ -638,11 +638,11 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Spawn With Defaults | %d entities with 5 components', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [D1] = true, [D2] = true, [D3] = true, [D4] = true, [D5] = true } - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.batch_destroy(QD1) end) @@ -652,11 +652,11 @@ print '----------------------------------------' basics.describe_bench( string.format('Spawn Benchmarks: Multi Spawn | %d entities with 1 required component', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [F1] = true } - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.batch_destroy(QF1) end) @@ -664,12 +664,12 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Defer Spawn | %d entities with 1 required component', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [F1] = true } evo.defer() - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.commit() evo.batch_destroy(QF1) @@ -678,11 +678,11 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Spawn With Defaults | %d entities with 1 required component', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [D1] = true } - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.batch_destroy(QD1) end) @@ -690,11 +690,11 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Spawn | %d entities with 3 required components', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [RF123] = true } - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.batch_destroy(QF1) end) @@ -702,12 +702,12 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Defer Spawn | %d entities with 3 required components', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [RF123] = true } evo.defer() - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.commit() evo.batch_destroy(QF1) @@ -716,11 +716,11 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Spawn With Defaults | %d entities with 3 required components', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [RD123] = true } - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.batch_destroy(QD1) end) @@ -728,11 +728,11 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Spawn | %d entities with 5 required components', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [RF12345] = true } - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.batch_destroy(QF1) end) @@ -740,12 +740,12 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Defer Spawn | %d entities with 5 required components', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [RF12345] = true } evo.defer() - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.commit() evo.batch_destroy(QF1) @@ -754,11 +754,11 @@ basics.describe_bench( basics.describe_bench( string.format('Spawn Benchmarks: Multi Spawn With Defaults | %d entities with 5 required components', N), function() - local multi_spawn = evo.multi_spawn + local multi_spawn_nr = evo.multi_spawn_nr local components = { [RD12345] = true } - multi_spawn(N, components) + multi_spawn_nr(N, components) evo.batch_destroy(QD1) end) diff --git a/develop/fuzzing/batch_destroy_fuzz.lua b/develop/fuzzing/batch_destroy_fuzz.lua index 858270b..c1eba25 100644 --- a/develop/fuzzing/batch_destroy_fuzz.lua +++ b/develop/fuzzing/batch_destroy_fuzz.lua @@ -118,11 +118,11 @@ end --- if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end evo.destroy(__table_unpack(all_entity_list)) if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end diff --git a/develop/fuzzing/destroy_fuzz.lua b/develop/fuzzing/destroy_fuzz.lua index 0414da1..a274c10 100644 --- a/develop/fuzzing/destroy_fuzz.lua +++ b/develop/fuzzing/destroy_fuzz.lua @@ -124,11 +124,11 @@ end --- if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end evo.destroy(__table_unpack(all_entity_list)) if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end diff --git a/develop/fuzzing/execute_fuzz.lua b/develop/fuzzing/execute_fuzz.lua index 044c007..25fa377 100644 --- a/develop/fuzzing/execute_fuzz.lua +++ b/develop/fuzzing/execute_fuzz.lua @@ -296,7 +296,7 @@ end --- if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end evo.destroy(__table_unpack(all_query_list)) @@ -304,5 +304,5 @@ evo.destroy(__table_unpack(all_entity_list)) evo.destroy(__table_unpack(all_fragment_list)) if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end diff --git a/develop/fuzzing/explicit_fuzz.lua b/develop/fuzzing/explicit_fuzz.lua index 2744268..adc17e1 100644 --- a/develop/fuzzing/explicit_fuzz.lua +++ b/develop/fuzzing/explicit_fuzz.lua @@ -78,11 +78,11 @@ end --- if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end evo.destroy(__table_unpack(all_entity_list)) if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end diff --git a/develop/fuzzing/requires_fuzz.lua b/develop/fuzzing/requires_fuzz.lua index 073f2f4..b6822bf 100644 --- a/develop/fuzzing/requires_fuzz.lua +++ b/develop/fuzzing/requires_fuzz.lua @@ -115,17 +115,17 @@ end if math.random(1, 2) == 1 then evo.destroy(__table_unpack(all_entity_list)) if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end evo.destroy(__table_unpack(all_fragment_list)) else evo.destroy(__table_unpack(all_fragment_list)) if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end evo.destroy(__table_unpack(all_entity_list)) end if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end diff --git a/develop/fuzzing/unique_fuzz.lua b/develop/fuzzing/unique_fuzz.lua index a572bd6..e24a4f8 100644 --- a/develop/fuzzing/unique_fuzz.lua +++ b/develop/fuzzing/unique_fuzz.lua @@ -64,11 +64,11 @@ end --- if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end evo.destroy(__table_unpack(all_entity_list)) if math.random(1, 2) == 1 then - evo.collect_garbage() + evo.collect_garbage(math.random(1, 2) == 1) end diff --git a/develop/testing/build_tests.lua b/develop/testing/build_tests.lua index 626b88b..5d74faa 100644 --- a/develop/testing/build_tests.lua +++ b/develop/testing/build_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do local f1, f2 = evo.id(2) diff --git a/develop/testing/cancel_tests.lua b/develop/testing/cancel_tests.lua index 43d8b11..6829172 100644 --- a/develop/testing/cancel_tests.lua +++ b/develop/testing/cancel_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do assert(evo.defer()) assert(evo.cancel()) diff --git a/develop/testing/clone_tests.lua b/develop/testing/clone_tests.lua index 7b9edce..29b3c32 100644 --- a/develop/testing/clone_tests.lua +++ b/develop/testing/clone_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do do local p = evo.spawn() @@ -395,3 +397,165 @@ do end end end + +do + local f1, f2 = evo.id(2) + local p = evo.spawn { [f1] = 42, [f2] = 'hello' } + + do + local entity_list, entity_count = {}, 2 + evo.multi_clone_to(entity_list, 1, entity_count, p) + assert(evo.has_all(entity_list[1], f1, f2)) + assert(evo.has_all(entity_list[2], f1, f2)) + assert(evo.get(entity_list[1], f1) == 42 and evo.get(entity_list[1], f2) == 'hello') + assert(evo.get(entity_list[2], f1) == 42 and evo.get(entity_list[2], f2) == 'hello') + end + + do + local entity_list, entity_count = {}, 2 + evo.multi_clone_to(entity_list, 2, entity_count, p) + assert(evo.has_all(entity_list[2], f1, f2)) + assert(evo.has_all(entity_list[3], f1, f2)) + assert(evo.get(entity_list[2], f1) == 42 and evo.get(entity_list[2], f2) == 'hello') + assert(evo.get(entity_list[3], f1) == 42 and evo.get(entity_list[3], f2) == 'hello') + end + + do + local entity_list, entity_count = {}, 2 + evo.defer() + evo.multi_clone_to(entity_list, 1, entity_count, p) + assert(entity_list[1] and entity_list[2]) + assert(evo.empty_all(entity_list[1], entity_list[2])) + evo.commit() + assert(evo.has_all(entity_list[1], f1, f2)) + assert(evo.has_all(entity_list[2], f1, f2)) + assert(evo.get(entity_list[1], f1) == 42 and evo.get(entity_list[1], f2) == 'hello') + assert(evo.get(entity_list[2], f1) == 42 and evo.get(entity_list[2], f2) == 'hello') + end + + do + local entity_list, entity_count = {}, 2 + evo.defer() + evo.multi_clone_to(entity_list, 2, entity_count, p) + assert(entity_list[2] and entity_list[3]) + assert(evo.empty_all(entity_list[2], entity_list[3])) + evo.commit() + assert(evo.has_all(entity_list[2], f1, f2)) + assert(evo.has_all(entity_list[3], f1, f2)) + assert(evo.get(entity_list[2], f1) == 42 and evo.get(entity_list[2], f2) == 'hello') + assert(evo.get(entity_list[3], f1) == 42 and evo.get(entity_list[3], f2) == 'hello') + end +end + +do + local f1, f2 = evo.id(2) + local q12 = evo.builder():include(f1, f2):build() + local p = evo.spawn { [f1] = 42, [f2] = 'hello' } + + do + assert(select('#', evo.multi_clone_nr(2, p)) == 0) + + do + local entity_count = 0 + + for chunk in evo.execute(q12) do + local _, chunk_entity_count = chunk:entities() + entity_count = entity_count + chunk_entity_count + end + + assert(entity_count == 3) + end + end + + do + local b = evo.builder():set(f1, 42):set(f2, 'hello') + + assert(select('#', b:multi_clone_nr(2, p)) == 0) + + do + local entity_count = 0 + + for chunk in evo.execute(q12) do + local _, chunk_entity_count = chunk:entities() + entity_count = entity_count + chunk_entity_count + end + + assert(entity_count == 5) + end + end + + do + local b = evo.builder():set(f1, 42):set(f2, 'hello') + + assert(select('#', b:multi_build_nr(2, p)) == 0) + + do + local entity_count = 0 + + for chunk in evo.execute(q12) do + local _, chunk_entity_count = chunk:entities() + entity_count = entity_count + chunk_entity_count + end + + assert(entity_count == 7) + end + end +end + +do + local f1, f2 = evo.id(2) + local q12 = evo.builder():include(f1, f2):build() + local p = evo.spawn { [f1] = 42, [f2] = 'hello' } + + do + local entity_list = {} + assert(select('#', evo.multi_clone_to(entity_list, 1, 2, p)) == 0) + + do + local entity_count = 0 + + for chunk in evo.execute(q12) do + local _, chunk_entity_count = chunk:entities() + entity_count = entity_count + chunk_entity_count + end + + assert(entity_count == 3) + end + end + + do + local b = evo.builder():set(f1, 42):set(f2, 'hello') + + local entity_list = {} + assert(select('#', b:multi_clone_to(entity_list, 1, 2, p)) == 0) + + do + local entity_count = 0 + + for chunk in evo.execute(q12) do + local _, chunk_entity_count = chunk:entities() + entity_count = entity_count + chunk_entity_count + end + + assert(entity_count == 5) + end + end + + do + local b = evo.builder():set(f1, 42):set(f2, 'hello') + + local entity_list = {} + assert(select('#', b:multi_build_to(entity_list, 1, 2, p)) == 0) + + do + local entity_count = 0 + + for chunk in evo.execute(q12) do + local _, chunk_entity_count = chunk:entities() + entity_count = entity_count + chunk_entity_count + end + + assert(entity_count == 7) + end + end +end diff --git a/develop/testing/depth_tests.lua b/develop/testing/depth_tests.lua index 15a0e6f..afc08d9 100644 --- a/develop/testing/depth_tests.lua +++ b/develop/testing/depth_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do assert(evo.depth() == 0) diff --git a/develop/testing/destroy_tests.lua b/develop/testing/destroy_tests.lua index 5325533..6b4c72a 100644 --- a/develop/testing/destroy_tests.lua +++ b/develop/testing/destroy_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do local e = evo.id() assert(evo.alive(e)) diff --git a/develop/testing/locate_tests.lua b/develop/testing/locate_tests.lua index 2c0723c..52a4b1a 100644 --- a/develop/testing/locate_tests.lua +++ b/develop/testing/locate_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do local e1, e2, f1, f2 = evo.id(4) diff --git a/develop/testing/lookup_tests.lua b/develop/testing/lookup_tests.lua new file mode 100644 index 0000000..1120662 --- /dev/null +++ b/develop/testing/lookup_tests.lua @@ -0,0 +1,195 @@ +local evo = require 'evolved' + +evo.debug_mode(true) + +do + local e1, e2, e3 = evo.id(3) + + do + assert(evo.lookup('lookup_hello') == nil) + assert(evo.lookup('lookup_world') == nil) + + do + local entity_list, entity_count = evo.multi_lookup('lookup_hello') + assert(entity_list and #entity_list == 0 and entity_count == 0) + end + + do + local entity_list, entity_count = evo.multi_lookup('lookup_world') + assert(entity_list and #entity_list == 0 and entity_count == 0) + end + end + + evo.set(e1, evo.NAME, 'lookup_hello') + + do + assert(evo.lookup('lookup_hello') == e1) + assert(evo.lookup('lookup_world') == nil) + + do + local entity_list, entity_count = evo.multi_lookup('lookup_hello') + assert(entity_list and #entity_list == 1 and entity_count == 1) + assert(entity_list[1] == e1) + end + + do + local entity_list, entity_count = evo.multi_lookup('lookup_world') + assert(entity_list and #entity_list == 0 and entity_count == 0) + end + end + + evo.set(e2, evo.NAME, 'lookup_hello') + evo.set(e3, evo.NAME, 'lookup_hello') + + do + assert(evo.lookup('lookup_hello') == e1) + assert(evo.lookup('lookup_world') == nil) + + do + local entity_list, entity_count = evo.multi_lookup('lookup_hello') + assert(entity_list and #entity_list == 3 and entity_count == 3) + assert(entity_list[1] == e1 and entity_list[2] == e2 and entity_list[3] == e3) + end + end + + evo.set(e2, evo.NAME, 'lookup_world') + + do + assert(evo.lookup('lookup_hello') == e1) + assert(evo.lookup('lookup_world') == e2) + + do + local entity_list, entity_count = evo.multi_lookup('lookup_hello') + assert(entity_list and #entity_list == 2 and entity_count == 2) + assert(entity_list[1] == e1 and entity_list[2] == e3) + end + + do + local entity_list, entity_count = evo.multi_lookup('lookup_world') + assert(entity_list and #entity_list == 1 and entity_count == 1) + assert(entity_list[1] == e2) + end + end + + evo.set(e3, evo.NAME, 'lookup_world') + + do + assert(evo.lookup('lookup_hello') == e1) + assert(evo.lookup('lookup_world') == e2) + + do + local entity_list, entity_count = evo.multi_lookup('lookup_hello') + assert(entity_list and #entity_list == 1 and entity_count == 1) + assert(entity_list[1] == e1) + end + + do + local entity_list, entity_count = evo.multi_lookup('lookup_world') + assert(entity_list and #entity_list == 2 and entity_count == 2) + assert(entity_list[1] == e2 or entity_list[1] == e3) + end + end + + evo.remove(e1, evo.NAME) + + do + assert(evo.lookup('lookup_hello') == nil) + assert(evo.lookup('lookup_world') == e2) + + do + local entity_list, entity_count = evo.multi_lookup('lookup_hello') + assert(entity_list and #entity_list == 0 and entity_count == 0) + end + + do + local entity_list, entity_count = evo.multi_lookup('lookup_world') + assert(entity_list and #entity_list == 2 and entity_count == 2) + assert(entity_list[1] == e2 or entity_list[1] == e3) + end + end +end + +do + local e1, e2, e3 = evo.id(3) + + evo.set(e1, evo.NAME, 'lookup_e') + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 1 and entity_count == 1) + assert(entity_list[1] == e1) + end + + evo.set(e2, evo.NAME, 'lookup_e') + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 2 and entity_count == 2) + assert(entity_list[1] == e1 and entity_list[2] == e2) + end + + evo.set(e3, evo.NAME, 'lookup_e') + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 3 and entity_count == 3) + assert(entity_list[1] == e1 and entity_list[2] == e2 and entity_list[3] == e3) + end + + evo.clear(e1, e2, e3) + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 0 and entity_count == 0) + end + + evo.set(e3, evo.NAME, 'lookup_e') + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 1 and entity_count == 1) + assert(entity_list[1] == e3) + end + + evo.set(e2, evo.NAME, 'lookup_e') + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 2 and entity_count == 2) + assert(entity_list[1] == e3 and entity_list[2] == e2) + end + + evo.set(e1, evo.NAME, 'lookup_e') + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 3 and entity_count == 3) + assert(entity_list[1] == e3 and entity_list[2] == e2 and entity_list[3] == e1) + end + + evo.destroy(e3, e2, e1) + + do + local entity_list, entity_count = evo.multi_lookup('lookup_e') + assert(entity_list and #entity_list == 0 and entity_count == 0) + end +end + +do + local e1, e2 = evo.id(2) + + evo.set(e1, evo.NAME, 'lookup_e') + evo.set(e2, evo.NAME, 'lookup_e') + + do + local entity_list = {} + local entity_count = evo.multi_lookup_to(entity_list, 1, 'lookup_e') + assert(entity_count == 2 and entity_list[1] == e1 and entity_list[2] == e2) + end + + do + local entity_list = {} + local entity_count = evo.multi_lookup_to(entity_list, 2, 'lookup_e') + assert(entity_count == 2 and entity_list[2] == e1 and entity_list[3] == e2) + end +end diff --git a/develop/testing/mappers_tests.lua b/develop/testing/mappers_tests.lua index 1e84950..890e245 100644 --- a/develop/testing/mappers_tests.lua +++ b/develop/testing/mappers_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do local f1, f2 = evo.id(2) diff --git a/develop/testing/multi_spawn_tests.lua b/develop/testing/multi_spawn_tests.lua index 14dbd65..e0d0e7b 100644 --- a/develop/testing/multi_spawn_tests.lua +++ b/develop/testing/multi_spawn_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do local entity_list @@ -605,3 +607,164 @@ do end end end + +do + local f1, f2 = evo.id(2) + + do + local entity_list, entity_count = {}, 2 + evo.multi_spawn_to(entity_list, 1, entity_count, { [f1] = 42, [f2] = "hello" }) + assert(evo.has_all(entity_list[1], f1, f2)) + assert(evo.has_all(entity_list[2], f1, f2)) + assert(evo.get(entity_list[1], f1) == 42 and evo.get(entity_list[1], f2) == "hello") + assert(evo.get(entity_list[2], f1) == 42 and evo.get(entity_list[2], f2) == "hello") + end + + do + local entity_list, entity_count = {}, 2 + evo.multi_spawn_to(entity_list, 2, entity_count, { [f1] = 42, [f2] = "hello" }) + assert(evo.has_all(entity_list[2], f1, f2)) + assert(evo.has_all(entity_list[3], f1, f2)) + assert(evo.get(entity_list[2], f1) == 42 and evo.get(entity_list[2], f2) == "hello") + assert(evo.get(entity_list[3], f1) == 42 and evo.get(entity_list[3], f2) == "hello") + end + + do + local entity_list, entity_count = {}, 2 + evo.defer() + evo.multi_spawn_to(entity_list, 1, entity_count, { [f1] = 42, [f2] = "hello" }) + assert(entity_list[1] and entity_list[2]) + assert(evo.empty_all(entity_list[1], entity_list[2])) + evo.commit() + assert(evo.has_all(entity_list[1], f1, f2)) + assert(evo.has_all(entity_list[2], f1, f2)) + assert(evo.get(entity_list[1], f1) == 42 and evo.get(entity_list[1], f2) == "hello") + assert(evo.get(entity_list[2], f1) == 42 and evo.get(entity_list[2], f2) == "hello") + end + + do + local entity_list, entity_count = {}, 2 + evo.defer() + evo.multi_spawn_to(entity_list, 2, entity_count, { [f1] = 42, [f2] = "hello" }) + assert(entity_list[2] and entity_list[3]) + assert(evo.empty_all(entity_list[2], entity_list[3])) + evo.commit() + assert(evo.has_all(entity_list[2], f1, f2)) + assert(evo.has_all(entity_list[3], f1, f2)) + assert(evo.get(entity_list[2], f1) == 42 and evo.get(entity_list[2], f2) == "hello") + assert(evo.get(entity_list[3], f1) == 42 and evo.get(entity_list[3], f2) == "hello") + end +end + +do + local f1, f2 = evo.id(2) + local q12 = evo.builder():include(f1, f2):spawn() + + do + assert(select('#', evo.multi_spawn_nr(2, { [f1] = 42, [f2] = "hello" })) == 0) + + do + local entity_count = 0 + + for chunk in evo.execute(q12) do + local _, chunk_entity_count = chunk:entities() + entity_count = entity_count + chunk_entity_count + end + + assert(entity_count == 2) + end + end + + do + local b = evo.builder():set(f1, 42):set(f2, "hello") + + assert(select('#', b:multi_spawn_nr(2)) == 0) + + do + local entity_count = 0 + + for chunk in evo.execute(q12) do + local _, chunk_entity_count = chunk:entities() + entity_count = entity_count + chunk_entity_count + end + + assert(entity_count == 4) + end + end + + do + local b = evo.builder():set(f1, 42):set(f2, "hello") + + assert(select('#', b:multi_build_nr(2)) == 0) + + do + local entity_count = 0 + + for chunk in evo.execute(q12) do + local _, chunk_entity_count = chunk:entities() + entity_count = entity_count + chunk_entity_count + end + + assert(entity_count == 6) + end + end +end + +do + local f1, f2 = evo.id(2) + local q12 = evo.builder():include(f1, f2):spawn() + + do + local entity_list = {} + assert(select('#', evo.multi_spawn_to(entity_list, 1, 2, { [f1] = 42, [f2] = "hello" })) == 0) + + do + local entity_count = 0 + + for chunk in evo.execute(q12) do + local _, chunk_entity_count = chunk:entities() + entity_count = entity_count + chunk_entity_count + end + + assert(entity_count == 2) + end + end + + do + local b = evo.builder():set(f1, 42):set(f2, "hello") + + + local entity_list = {} + assert(select('#', b:multi_spawn_to(entity_list, 1, 2)) == 0) + + do + local entity_count = 0 + + for chunk in evo.execute(q12) do + local _, chunk_entity_count = chunk:entities() + entity_count = entity_count + chunk_entity_count + end + + assert(entity_count == 4) + end + end + + do + local b = evo.builder():set(f1, 42):set(f2, "hello") + + + local entity_list = {} + assert(select('#', b:multi_build_to(entity_list, 1, 2)) == 0) + + do + local entity_count = 0 + + for chunk in evo.execute(q12) do + local _, chunk_entity_count = chunk:entities() + entity_count = entity_count + chunk_entity_count + end + + assert(entity_count == 6) + end + end +end diff --git a/develop/testing/name_tests.lua b/develop/testing/name_tests.lua index 21b2e08..5ba6177 100644 --- a/develop/testing/name_tests.lua +++ b/develop/testing/name_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do local id = evo.id() diff --git a/develop/testing/process_with_tests.lua b/develop/testing/process_with_tests.lua index 669eb75..b0fa703 100644 --- a/develop/testing/process_with_tests.lua +++ b/develop/testing/process_with_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do local f = evo.id() local e = evo.builder():set(f, 42):spawn() diff --git a/develop/testing/realloc_tests.lua b/develop/testing/realloc_tests.lua index 2d81905..a54c6aa 100644 --- a/develop/testing/realloc_tests.lua +++ b/develop/testing/realloc_tests.lua @@ -1,10 +1,18 @@ local evo = require 'evolved' +evo.debug_mode(true) + ---@type ffilib? local ffi = (function() - local ffi_loader = package and package.preload and package.preload['ffi'] - local ffi = ffi_loader and ffi_loader() - return ffi + if package and package.loaded then + local loaded_ffi = package.loaded.ffi + if loaded_ffi then return loaded_ffi end + end + + if package and package.preload then + local ffi_loader = package.preload.ffi + if ffi_loader then return ffi_loader() end + end end)() if not ffi then diff --git a/develop/testing/requires_fragment_tests.lua b/develop/testing/requires_fragment_tests.lua index 89312f5..b4f8569 100644 --- a/develop/testing/requires_fragment_tests.lua +++ b/develop/testing/requires_fragment_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do local f1, f2 = evo.id(2) evo.set(f1, evo.REQUIRES) diff --git a/develop/testing/spawn_tests.lua b/develop/testing/spawn_tests.lua index 1927817..4f8272a 100644 --- a/develop/testing/spawn_tests.lua +++ b/develop/testing/spawn_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do do local e = evo.spawn() diff --git a/develop/testing/system_as_query_tests.lua b/develop/testing/system_as_query_tests.lua index 42effca..63d11f2 100644 --- a/develop/testing/system_as_query_tests.lua +++ b/develop/testing/system_as_query_tests.lua @@ -1,5 +1,7 @@ local evo = require 'evolved' +evo.debug_mode(true) + do local f1, f2, f3 = evo.id(3) diff --git a/evolved.d.tl b/evolved.d.tl index 54d3ac4..5f7795f 100644 --- a/evolved.d.tl +++ b/evolved.d.tl @@ -40,6 +40,18 @@ prefab?: Entity, component_mapper?: function(Chunk, integer, integer)): { Entity }, integer + multi_build_nr: function(self: Builder, + entity_count: integer, + prefab?: Entity, + component_mapper?: function(Chunk, integer, integer)) + + multi_build_to: function(self: Builder, + out_entity_list: { Entity }, + out_entity_first: integer, + entity_count: integer, + prefab?: Entity, + component_mapper?: function(Chunk, integer, integer)) + spawn: function(self: Builder, component_mapper?: function(Chunk, integer)): Entity @@ -47,6 +59,16 @@ entity_count: integer, component_mapper?: function(Chunk, integer, integer)): { Entity }, integer + multi_spawn_nr: function(self: Builder, + entity_count: integer, + component_mapper?: function(Chunk, integer, integer)) + + multi_spawn_to: function(self: Builder, + out_entity_list: { Entity }, + out_entity_first: integer, + entity_count: integer, + component_mapper?: function(Chunk, integer, integer)) + clone: function(self: Builder, prefab: Entity, component_mapper?: function(Chunk, integer)): Entity @@ -56,6 +78,18 @@ prefab: Entity, component_mapper?: function(Chunk, integer, integer)): { Entity }, integer + multi_clone_nr: function(self: Builder, + entity_count: integer, + prefab: Entity, + component_mapper?: function(Chunk, integer, integer)) + + multi_clone_to: function(self: Builder, + out_entity_list: { Entity }, + out_entity_first: integer, + entity_count: integer, + prefab: Entity, + component_mapper?: function(Chunk, integer, integer)) + has: function(self: Builder, fragment: Fragment): boolean has_all: function(self: Builder, ...: Fragment): boolean has_any: function(self: Builder, ...: Fragment): boolean @@ -164,6 +198,18 @@ component_table?: { Fragment: any }, component_mapper?: function(Chunk, integer, integer)): { Entity }, integer + multi_spawn_nr: function( + entity_count: integer, + component_table?: { Fragment: any }, + component_mapper?: function(Chunk, integer, integer)) + + multi_spawn_to: function( + out_entity_list: { Entity }, + out_entity_first: integer, + entity_count: integer, + component_table?: { Fragment: any }, + component_mapper?: function(Chunk, integer, integer)) + clone: function( prefab: Entity, component_table?: { Fragment: any }, @@ -175,6 +221,20 @@ component_table?: { Fragment: any }, component_mapper?: function(Chunk, integer, integer)): { Entity }, integer + multi_clone_nr: function( + entity_count: integer, + prefab: Entity, + component_table?: { Fragment: any }, + component_mapper?: function(Chunk, integer, integer)) + + multi_clone_to: function( + out_entity_list: { Entity }, + out_entity_first: integer, + entity_count: integer, + prefab: Entity, + component_table?: { Fragment: any }, + component_mapper?: function(Chunk, integer, integer)) + alive: function(entity: Entity): boolean alive_all: function(...: Entity): boolean alive_any: function(...: Entity): boolean @@ -208,11 +268,15 @@ locate: function(entity: Entity): Chunk | nil, integer + lookup: function(name: string): Entity | nil + multi_lookup: function(name: string): { Entity }, integer + multi_lookup_to: function(out_entity_list: { Entity }, out_entity_first: integer, name: string): integer + process: function(...: System) process_with: function(system: System, ...: any) debug_mode: function(yesno: boolean) - collect_garbage: function() + collect_garbage: function(no_shrink?: boolean) chunk: function(fragment: Fragment, ...: Fragment): Chunk, { Entity }, integer builder: function(): Builder diff --git a/evolved.lua b/evolved.lua index 36efd2d..fc87cf1 100644 --- a/evolved.lua +++ b/evolved.lua @@ -1,7 +1,7 @@ local evolved = { __HOMEPAGE = 'https://github.com/BlackMATov/evolved.lua', __DESCRIPTION = 'Evolved ECS (Entity-Component-System) for Lua', - __VERSION = '1.9.0', + __VERSION = '1.10.0', __LICENSE = [[ MIT License @@ -141,8 +141,11 @@ local __minor_chunks = {} ---@type table> local __major_queries = {} ---@type table> -local __entity_chunks = {} ---@type table -local __entity_places = {} ---@type table +local __entity_chunks = {} ---@type (evolved.chunk|false)[] +local __entity_places = {} ---@type integer[] + +local __named_entity = {} ---@type table +local __named_entities = {} ---@type table> local __sorted_includes = {} ---@type table> local __sorted_excludes = {} ---@type table> @@ -243,8 +246,13 @@ local __lua_table_new = (function() if table_create then return function(nseq) return table_create(nseq or 0) end end end - do - local table_new_loader = package and package.preload and package.preload['table.new'] + if package and package.loaded then + local loaded_table_create = package.loaded.table and package.loaded.table.create + if loaded_table_create then return function(nseq) return loaded_table_create(nseq or 0) end end + end + + if package and package.preload then + local table_new_loader = package.preload['table.new'] local table_new = table_new_loader and table_new_loader() if table_new then return function(nseq) return table_new(nseq or 0, 0) end end end @@ -265,8 +273,13 @@ local __lua_table_clear = (function() if table_clear then return table_clear end end - do - local table_clear_loader = package and package.preload and package.preload['table.clear'] + if package and package.loaded then + local loaded_table_clear = package.loaded.table and package.loaded.table.clear + if loaded_table_clear then return loaded_table_clear end + end + + if package and package.preload then + local table_clear_loader = package.preload['table.clear'] local table_clear = table_clear_loader and table_clear_loader() if table_clear then return table_clear end end @@ -299,8 +312,13 @@ local __lua_table_move = (function() if table_move then return table_move end end - do - local table_move_loader = package and package.preload and package.preload['table.move'] + if package and package.loaded then + local loaded_table_move = package.loaded.table and package.loaded.table.move + if loaded_table_move then return loaded_table_move end + end + + if package and package.preload then + local table_move_loader = package.preload['table.move'] local table_move = table_move_loader and table_move_loader() if table_move then return table_move end end @@ -659,6 +677,9 @@ local function __acquire_id() local acquired_id = acquired_primary + shifted_secondary freelist_ids[acquired_primary] = acquired_id + __entity_chunks[acquired_primary] = false + __entity_places[acquired_primary] = 0 + return acquired_id --[[@as evolved.id]] end end @@ -785,29 +806,28 @@ end --- --- -local __list_new -local __list_dup -local __list_lwr +local __list_fns = {} ---@param reserve? integer ---@return any[] ---@nodiscard -function __list_new(reserve) +function __list_fns.new(reserve) return __lua_table_new(reserve) end ---@generic V ---@param list V[] +---@param size? integer ---@return V[] ---@nodiscard -function __list_dup(list) - local list_size = #list +function __list_fns.dup(list, size) + local list_size = size or #list if list_size == 0 then return {} end - local dup_list = __list_new(list_size) + local dup_list = __list_fns.new(list_size) __lua_table_move( list, 1, list_size, @@ -820,10 +840,11 @@ end ---@param list V[] ---@param item V ---@param comp? fun(a: V, b: V): boolean +---@param size? integer ---@return integer lower_bound_index ---@nodiscard -function __list_lwr(list, item, comp) - local lower, upper = 1, #list +function __list_fns.lwr(list, item, comp, size) + local lower, upper = 1, size or #list if comp then while lower <= upper do @@ -864,20 +885,12 @@ end --- __item_count: integer, --- } -local __assoc_list_new -local __assoc_list_move -local __assoc_list_move_ex -local __assoc_list_sort -local __assoc_list_sort_ex -local __assoc_list_insert -local __assoc_list_insert_ex -local __assoc_list_remove -local __assoc_list_remove_ex +local __assoc_list_fns = {} ---@param reserve? integer ---@return evolved.assoc_list ---@nodiscard -function __assoc_list_new(reserve) +function __assoc_list_fns.new(reserve) ---@type evolved.assoc_list return { __item_set = __lua_table_new(), @@ -886,14 +899,30 @@ function __assoc_list_new(reserve) } end +---@generic K +---@param ... K +---@return evolved.assoc_list +---@nodiscard +function __assoc_list_fns.from(...) + local item_count = __lua_select('#', ...) + + local al = __assoc_list_fns.new(item_count) + + for item_index = 1, item_count do + __assoc_list_fns.insert(al, __lua_select(item_index, ...)) + end + + return al +end + ---@generic K ---@param src_item_list K[] ---@param src_item_first integer ---@param src_item_last integer ---@param dst_al evolved.assoc_list ---@return integer new_dst_item_count -function __assoc_list_move(src_item_list, src_item_first, src_item_last, dst_al) - local new_dst_item_count = __assoc_list_move_ex( +function __assoc_list_fns.move(src_item_list, src_item_first, src_item_last, dst_al) + local new_dst_item_count = __assoc_list_fns.move_ex( src_item_list, src_item_first, src_item_last, dst_al.__item_set, dst_al.__item_list, dst_al.__item_count) @@ -910,8 +939,8 @@ end ---@param dst_item_count integer ---@return integer new_dst_item_count ---@nodiscard -function __assoc_list_move_ex(src_item_list, src_item_first, src_item_last, - dst_item_set, dst_item_list, dst_item_count) +function __assoc_list_fns.move_ex(src_item_list, src_item_first, src_item_last, + dst_item_set, dst_item_list, dst_item_count) if src_item_last < src_item_first then return dst_item_count end @@ -931,8 +960,8 @@ end ---@generic K ---@param al evolved.assoc_list ---@param comp? fun(a: K, b: K): boolean -function __assoc_list_sort(al, comp) - __assoc_list_sort_ex( +function __assoc_list_fns.sort(al, comp) + __assoc_list_fns.sort_ex( al.__item_set, al.__item_list, al.__item_count, comp) end @@ -942,7 +971,7 @@ end ---@param al_item_list K[] ---@param al_item_count integer ---@param comp? fun(a: K, b: K): boolean -function __assoc_list_sort_ex(al_item_set, al_item_list, al_item_count, comp) +function __assoc_list_fns.sort_ex(al_item_set, al_item_list, al_item_count, comp) if al_item_count < 2 then return end @@ -959,8 +988,8 @@ end ---@param al evolved.assoc_list ---@param item K ---@return integer new_al_count -function __assoc_list_insert(al, item) - local new_al_count = __assoc_list_insert_ex( +function __assoc_list_fns.insert(al, item) + local new_al_count = __assoc_list_fns.insert_ex( al.__item_set, al.__item_list, al.__item_count, item) @@ -975,7 +1004,7 @@ end ---@param item K ---@return integer new_al_count ---@nodiscard -function __assoc_list_insert_ex(al_item_set, al_item_list, al_item_count, item) +function __assoc_list_fns.insert_ex(al_item_set, al_item_list, al_item_count, item) local item_index = al_item_set[item] if item_index then @@ -993,8 +1022,8 @@ end ---@param al evolved.assoc_list ---@param item K ---@return integer new_al_count -function __assoc_list_remove(al, item) - local new_al_count = __assoc_list_remove_ex( +function __assoc_list_fns.remove(al, item) + local new_al_count = __assoc_list_fns.remove_ex( al.__item_set, al.__item_list, al.__item_count, item) @@ -1009,7 +1038,7 @@ end ---@param item K ---@return integer new_al_count ---@nodiscard -function __assoc_list_remove_ex(al_item_set, al_item_list, al_item_count, item) +function __assoc_list_fns.remove_ex(al_item_set, al_item_list, al_item_count, item) local item_index = al_item_set[item] if not item_index then @@ -1029,6 +1058,46 @@ function __assoc_list_remove_ex(al_item_set, al_item_list, al_item_count, item) return al_item_count end +---@generic K +---@param al evolved.assoc_list +---@param item K +---@return integer new_al_count +function __assoc_list_fns.unordered_remove(al, item) + local new_al_count = __assoc_list_fns.unordered_remove_ex( + al.__item_set, al.__item_list, al.__item_count, + item) + + al.__item_count = new_al_count + return new_al_count +end + +---@generic K +---@param al_item_set table +---@param al_item_list K[] +---@param al_item_count integer +---@param item K +---@return integer new_al_count +---@nodiscard +function __assoc_list_fns.unordered_remove_ex(al_item_set, al_item_list, al_item_count, item) + local item_index = al_item_set[item] + + if not item_index then + return al_item_count + end + + if item_index ~= al_item_count then + local al_last_item = al_item_list[al_item_count] + al_item_set[al_last_item] = item_index + al_item_list[item_index] = al_last_item + end + + al_item_set[item] = nil + al_item_list[al_item_count] = nil + al_item_count = al_item_count - 1 + + return al_item_count +end + --- --- --- @@ -1110,9 +1179,13 @@ local __evolved_cancel local __evolved_spawn local __evolved_multi_spawn +local __evolved_multi_spawn_nr +local __evolved_multi_spawn_to local __evolved_clone local __evolved_multi_clone +local __evolved_multi_clone_nr +local __evolved_multi_clone_to local __evolved_alive local __evolved_alive_all @@ -1145,6 +1218,10 @@ local __evolved_execute local __evolved_locate +local __evolved_lookup +local __evolved_multi_lookup +local __evolved_multi_lookup_to + local __evolved_process local __evolved_process_with @@ -1280,7 +1357,7 @@ function __new_chunk(chunk_parent, chunk_fragment) local chunk_parent_fragment_list = chunk_parent.__fragment_list local chunk_parent_fragment_count = chunk_parent.__fragment_count - chunk_fragment_count = __assoc_list_move_ex( + chunk_fragment_count = __assoc_list_fns.move_ex( chunk_parent_fragment_list, 1, chunk_parent_fragment_count, chunk_fragment_set, chunk_fragment_list, chunk_fragment_count) end @@ -1345,11 +1422,11 @@ function __new_chunk(chunk_parent, chunk_fragment) if not major_chunks then ---@type evolved.assoc_list - major_chunks = __assoc_list_new(4) + major_chunks = __assoc_list_fns.new(4) __major_chunks[major] = major_chunks end - __assoc_list_insert(major_chunks, chunk) + __assoc_list_fns.insert(major_chunks, chunk) end for chunk_fragment_index = 1, chunk_fragment_count do @@ -1358,11 +1435,11 @@ function __new_chunk(chunk_parent, chunk_fragment) if not minor_chunks then ---@type evolved.assoc_list - minor_chunks = __assoc_list_new(4) + minor_chunks = __assoc_list_fns.new(4) __minor_chunks[minor] = minor_chunks end - __assoc_list_insert(minor_chunks, chunk) + __assoc_list_fns.insert(minor_chunks, chunk) end __update_chunk_caches(chunk) @@ -1405,9 +1482,9 @@ end ---@param root evolved.chunk function __add_root_chunk(root) - local root_index = __list_lwr(__root_list, root, function(a, b) + local root_index = __list_fns.lwr(__root_list, root, function(a, b) return a.__fragment < b.__fragment - end) + end, __root_count) for sib_root_index = __root_count, root_index, -1 do local sib_root = __root_list[sib_root_index] @@ -1450,9 +1527,9 @@ end ---@param child evolved.chunk ---@param parent evolved.chunk function __add_child_chunk(child, parent) - local child_index = __list_lwr(parent.__child_list, child, function(a, b) + local child_index = __list_fns.lwr(parent.__child_list, child, function(a, b) return a.__fragment < b.__fragment - end) + end, parent.__child_count) for sib_child_index = parent.__child_count, child_index, -1 do local sib_child = parent.__child_list[sib_child_index] @@ -1604,9 +1681,9 @@ function __update_chunk_queries(chunk) if major_query_chunks then if __query_major_matches(chunk, major_query) then - __assoc_list_insert(major_query_chunks, chunk) + __assoc_list_fns.insert(major_query_chunks, chunk) else - __assoc_list_remove(major_query_chunks, chunk) + __assoc_list_fns.remove(major_query_chunks, chunk) end end end @@ -1881,7 +1958,7 @@ function __cache_query_chunks(query) local query_variant_count = query_variants and query_variants.__item_count or 0 ---@type evolved.assoc_list - local query_chunks = __assoc_list_new(4) + local query_chunks = __assoc_list_fns.new(4) __query_chunks[query] = query_chunks if query_include_count > 0 then @@ -1895,7 +1972,7 @@ function __cache_query_chunks(query) local major_chunk = major_chunk_list[major_chunk_index] if __query_major_matches(major_chunk, query) then - __assoc_list_insert(query_chunks, major_chunk) + __assoc_list_fns.insert(query_chunks, major_chunk) end end end @@ -1912,7 +1989,7 @@ function __cache_query_chunks(query) local major_chunk = major_chunk_list[major_chunk_index] if __query_major_matches(major_chunk, query) then - __assoc_list_insert(query_chunks, major_chunk) + __assoc_list_fns.insert(query_chunks, major_chunk) end end end @@ -2604,10 +2681,11 @@ end ---@param chunk? evolved.chunk ---@param entity_list evolved.entity[] +---@param entity_first integer ---@param entity_count integer ---@param component_table? evolved.component_table ---@param component_mapper? evolved.component_mapper -function __multi_spawn_entity(chunk, entity_list, entity_count, component_table, component_mapper) +function __multi_spawn_entity(chunk, entity_list, entity_first, entity_count, component_table, component_mapper) if __defer_depth <= 0 then __error_fmt('spawn entity operations should be deferred') end @@ -2655,7 +2733,7 @@ function __multi_spawn_entity(chunk, entity_list, entity_count, component_table, local entity_places = __entity_places for place = b_place, e_place do - local entity = entity_list[place - b_place + 1] + local entity = entity_list[place - b_place + entity_first] chunk_entity_list[place] = entity local entity_primary = entity % 2 ^ 20 @@ -2903,10 +2981,11 @@ end ---@param prefab evolved.entity ---@param entity_list evolved.entity[] +---@param entity_first integer ---@param entity_count integer ---@param component_table? evolved.component_table ---@param component_mapper? evolved.component_mapper -function __multi_clone_entity(prefab, entity_list, entity_count, component_table, component_mapper) +function __multi_clone_entity(prefab, entity_list, entity_first, entity_count, component_table, component_mapper) if __defer_depth <= 0 then __error_fmt('clone entity operations should be deferred') end @@ -2922,7 +3001,9 @@ function __multi_clone_entity(prefab, entity_list, entity_count, component_table end if not prefab_chunk or not prefab_chunk.__without_unique_fragments then - return __multi_spawn_entity(nil, entity_list, entity_count, component_table, component_mapper) + return __multi_spawn_entity(nil, + entity_list, entity_first, entity_count, + component_table, component_mapper) end local chunk = component_table @@ -2971,7 +3052,7 @@ function __multi_clone_entity(prefab, entity_list, entity_count, component_table local entity_places = __entity_places for place = b_place, e_place do - local entity = entity_list[place - b_place + 1] + local entity = entity_list[place - b_place + entity_first] chunk_entity_list[place] = entity local entity_primary = entity % 2 ^ 20 @@ -3098,7 +3179,7 @@ function __purge_chunk(chunk) local major = chunk.__fragment local major_chunks = __major_chunks[major] - if major_chunks and __assoc_list_remove(major_chunks, chunk) == 0 then + if major_chunks and __assoc_list_fns.remove(major_chunks, chunk) == 0 then __major_chunks[major] = nil end end @@ -3107,7 +3188,7 @@ function __purge_chunk(chunk) local minor = chunk.__fragment_list[chunk_fragment_index] local minor_chunks = __minor_chunks[minor] - if minor_chunks and __assoc_list_remove(minor_chunks, chunk) == 0 then + if minor_chunks and __assoc_list_fns.remove(minor_chunks, chunk) == 0 then __minor_chunks[minor] = nil end end @@ -3325,8 +3406,8 @@ function __clear_entity_one(entity) if chunk then __detach_entity(chunk, place) - entity_chunks[entity_primary] = nil - entity_places[entity_primary] = nil + entity_chunks[entity_primary] = false + entity_places[entity_primary] = 0 __structural_changes = __structural_changes + 1 end @@ -3392,8 +3473,8 @@ function __destroy_entity_one(entity) if chunk then __detach_entity(chunk, place) - entity_chunks[entity_primary] = nil - entity_places[entity_primary] = nil + entity_chunks[entity_primary] = false + entity_places[entity_primary] = 0 __structural_changes = __structural_changes + 1 end @@ -4105,8 +4186,8 @@ function __chunk_remove(old_chunk, ...) for old_place = 1, old_entity_count do local entity = old_entity_list[old_place] local entity_primary = entity % 2 ^ 20 - entity_chunks[entity_primary] = nil - entity_places[entity_primary] = nil + entity_chunks[entity_primary] = false + entity_places[entity_primary] = 0 end __detach_all_entities(old_chunk) @@ -4168,8 +4249,8 @@ function __chunk_clear(chunk) for place = 1, chunk_entity_count do local entity = chunk_entity_list[place] local entity_primary = entity % 2 ^ 20 - entity_chunks[entity_primary] = nil - entity_places[entity_primary] = nil + entity_chunks[entity_primary] = false + entity_places[entity_primary] = 0 end __detach_all_entities(chunk) @@ -4302,10 +4383,10 @@ function __defer_spawn_entity(chunk, entity, component_table, component_mapper) end __defer_ops[__defer_op.spawn_entity] = function(bytes, index) - local chunk = bytes[index + 0] - local entity = bytes[index + 1] - local component_table2 = bytes[index + 2] - local component_mapper = bytes[index + 3] + local chunk = bytes[index + 0] ---@type evolved.chunk + local entity = bytes[index + 1] ---@type evolved.entity + local component_table2 = bytes[index + 2] ---@type evolved.component_table? + local component_mapper = bytes[index + 3] ---@type evolved.component_mapper? __evolved_defer() do @@ -4322,15 +4403,16 @@ end ---@param chunk? evolved.chunk ---@param entity_list evolved.entity[] +---@param entity_first integer ---@param entity_count integer ---@param component_table? evolved.component_table ---@param component_mapper? evolved.component_mapper -function __defer_multi_spawn_entity(chunk, entity_list, entity_count, component_table, component_mapper) +function __defer_multi_spawn_entity(chunk, entity_list, entity_first, entity_count, component_table, component_mapper) ---@type evolved.entity[] local entity_list2 = __acquire_table(__table_pool_tag.entity_list) __lua_table_move( - entity_list, 1, entity_count, + entity_list, entity_first, entity_first + entity_count - 1, 1, entity_list2) ---@type evolved.component_table? @@ -4358,15 +4440,17 @@ function __defer_multi_spawn_entity(chunk, entity_list, entity_count, component_ end __defer_ops[__defer_op.multi_spawn_entity] = function(bytes, index) - local chunk = bytes[index + 0] - local entity_count = bytes[index + 1] - local entity_list2 = bytes[index + 2] - local component_table2 = bytes[index + 3] - local component_mapper = bytes[index + 4] + local chunk = bytes[index + 0] ---@type evolved.chunk + local entity_count = bytes[index + 1] ---@type integer + local entity_list2 = bytes[index + 2] ---@type evolved.entity[] + local component_table2 = bytes[index + 3] ---@type evolved.component_table? + local component_mapper = bytes[index + 4] ---@type evolved.component_mapper? __evolved_defer() do - __multi_spawn_entity(chunk, entity_list2, entity_count, component_table2, component_mapper) + __multi_spawn_entity(chunk, + entity_list2, 1, entity_count, + component_table2, component_mapper) if entity_list2 then __release_table(__table_pool_tag.entity_list, entity_list2, false, true) @@ -4410,10 +4494,10 @@ function __defer_clone_entity(prefab, entity, component_table, component_mapper) end __defer_ops[__defer_op.clone_entity] = function(bytes, index) - local prefab = bytes[index + 0] - local entity = bytes[index + 1] - local component_table2 = bytes[index + 2] - local component_mapper = bytes[index + 3] + local prefab = bytes[index + 0] ---@type evolved.entity + local entity = bytes[index + 1] ---@type evolved.entity + local component_table2 = bytes[index + 2] ---@type evolved.component_table? + local component_mapper = bytes[index + 3] ---@type evolved.component_mapper? __evolved_defer() do @@ -4430,15 +4514,16 @@ end ---@param prefab evolved.entity ---@param entity_list evolved.entity[] +---@param entity_first integer ---@param entity_count integer ---@param component_table? evolved.component_table ---@param component_mapper? evolved.component_mapper -function __defer_multi_clone_entity(prefab, entity_list, entity_count, component_table, component_mapper) +function __defer_multi_clone_entity(prefab, entity_list, entity_first, entity_count, component_table, component_mapper) ---@type evolved.entity[] local entity_list2 = __acquire_table(__table_pool_tag.entity_list) __lua_table_move( - entity_list, 1, entity_count, + entity_list, entity_first, entity_first + entity_count - 1, 1, entity_list2) ---@type evolved.component_table? @@ -4466,15 +4551,17 @@ function __defer_multi_clone_entity(prefab, entity_list, entity_count, component end __defer_ops[__defer_op.multi_clone_entity] = function(bytes, index) - local prefab = bytes[index + 0] - local entity_count = bytes[index + 1] - local entity_list2 = bytes[index + 2] - local component_table2 = bytes[index + 3] - local component_mapper = bytes[index + 4] + local prefab = bytes[index + 0] ---@type evolved.entity + local entity_count = bytes[index + 1] ---@type integer + local entity_list2 = bytes[index + 2] ---@type evolved.entity[] + local component_table2 = bytes[index + 3] ---@type evolved.component_table? + local component_mapper = bytes[index + 4] ---@type evolved.component_mapper? __evolved_defer() do - __multi_clone_entity(prefab, entity_list2, entity_count, component_table2, component_mapper) + __multi_clone_entity(prefab, + entity_list2, 1, entity_count, + component_table2, component_mapper) if entity_list2 then __release_table(__table_pool_tag.entity_list, entity_list2, false, true) @@ -4845,11 +4932,49 @@ end ---@param component_mapper? evolved.component_mapper ---@return evolved.entity[] entity_list ---@return integer entity_count +---@nodiscard function __evolved_multi_spawn(entity_count, component_table, component_mapper) if entity_count <= 0 then return {}, 0 end + local entity_list = __lua_table_new(entity_count) + + __evolved_multi_spawn_to( + entity_list, 1, entity_count, + component_table, component_mapper) + + return entity_list, entity_count +end + +---@param entity_count integer +---@param component_table? evolved.component_table +---@param component_mapper? evolved.component_mapper +function __evolved_multi_spawn_nr(entity_count, component_table, component_mapper) + if entity_count <= 0 then + return + end + + local entity_list = __acquire_table(__table_pool_tag.entity_list) + + __evolved_multi_spawn_to( + entity_list, 1, entity_count, + component_table, component_mapper) + + __release_table(__table_pool_tag.entity_list, entity_list, false, true) +end + +---@param out_entity_list evolved.entity[] +---@param out_entity_first integer +---@param entity_count integer +---@param component_table? evolved.component_table +---@param component_mapper? evolved.component_mapper +function __evolved_multi_spawn_to(out_entity_list, out_entity_first, + entity_count, component_table, component_mapper) + if entity_count <= 0 then + return + end + if __debug_mode then if component_table then for fragment in __lua_next, component_table do @@ -4861,27 +4986,27 @@ function __evolved_multi_spawn(entity_count, component_table, component_mapper) end end - local entity_list = __lua_table_new(entity_count) - - for entity_index = 1, entity_count do - entity_list[entity_index] = __acquire_id() + for entity_index = out_entity_first, out_entity_first + entity_count - 1 do + out_entity_list[entity_index] = __acquire_id() end if not component_table or not __lua_next(component_table) then - return entity_list, entity_count + return end if __defer_depth > 0 then - __defer_multi_spawn_entity(nil, entity_list, entity_count, component_table, component_mapper) + __defer_multi_spawn_entity(nil, + out_entity_list, out_entity_first, entity_count, + component_table, component_mapper) else __evolved_defer() do - __multi_spawn_entity(nil, entity_list, entity_count, component_table, component_mapper) + __multi_spawn_entity(nil, + out_entity_list, out_entity_first, entity_count, + component_table, component_mapper) end __evolved_commit() end - - return entity_list, entity_count end ---@param prefab evolved.entity @@ -4926,11 +5051,51 @@ end ---@param component_mapper? evolved.component_mapper ---@return evolved.entity[] entity_list ---@return integer entity_count +---@nodiscard function __evolved_multi_clone(entity_count, prefab, component_table, component_mapper) if entity_count <= 0 then return {}, 0 end + local entity_list = __lua_table_new(entity_count) + + __evolved_multi_clone_to( + entity_list, 1, entity_count, + prefab, component_table, component_mapper) + + return entity_list, entity_count +end + +---@param entity_count integer +---@param prefab evolved.entity +---@param component_table? evolved.component_table +---@param component_mapper? evolved.component_mapper +function __evolved_multi_clone_nr(entity_count, prefab, component_table, component_mapper) + if entity_count <= 0 then + return + end + + local entity_list = __acquire_table(__table_pool_tag.entity_list) + + __evolved_multi_clone_to( + entity_list, 1, entity_count, + prefab, component_table, component_mapper) + + __release_table(__table_pool_tag.entity_list, entity_list, false, true) +end + +---@param out_entity_list evolved.entity[] +---@param out_entity_first integer +---@param entity_count integer +---@param prefab evolved.entity +---@param component_table? evolved.component_table +---@param component_mapper? evolved.component_mapper +function __evolved_multi_clone_to(out_entity_list, out_entity_first, + entity_count, prefab, component_table, component_mapper) + if entity_count <= 0 then + return + end + if __debug_mode then if not __evolved_alive(prefab) then __error_fmt('the prefab (%s) is not alive and cannot be used', @@ -4947,23 +5112,23 @@ function __evolved_multi_clone(entity_count, prefab, component_table, component_ end end - local entity_list = __lua_table_new(entity_count) - - for entity_index = 1, entity_count do - entity_list[entity_index] = __acquire_id() + for entity_index = out_entity_first, out_entity_first + entity_count - 1 do + out_entity_list[entity_index] = __acquire_id() end if __defer_depth > 0 then - __defer_multi_clone_entity(prefab, entity_list, entity_count, component_table, component_mapper) + __defer_multi_clone_entity(prefab, + out_entity_list, out_entity_first, entity_count, + component_table, component_mapper) else __evolved_defer() do - __multi_clone_entity(prefab, entity_list, entity_count, component_table, component_mapper) + __multi_clone_entity(prefab, + out_entity_list, out_entity_first, entity_count, + component_table, component_mapper) end __evolved_commit() end - - return entity_list, entity_count end ---@param entity evolved.entity @@ -5216,11 +5381,11 @@ function __evolved_set(entity, fragment, component) local old_chunk = entity_chunks[entity_primary] local old_place = entity_places[entity_primary] - local new_chunk = __chunk_with_fragment(old_chunk, fragment) + local new_chunk = __chunk_with_fragment(old_chunk or nil, fragment) __evolved_defer() - if old_chunk == new_chunk then + if old_chunk and old_chunk == new_chunk then local old_component_indices = old_chunk.__component_indices local old_component_storages = old_chunk.__component_storages @@ -5440,16 +5605,11 @@ function __evolved_remove(entity, ...) local old_chunk = entity_chunks[entity_primary] local old_place = entity_places[entity_primary] - local new_chunk = __chunk_without_fragments(old_chunk, ...) - - if old_chunk == new_chunk then - -- nothing to remove - return - end + local new_chunk = __chunk_without_fragments(old_chunk or nil, ...) __evolved_defer() - do + if old_chunk and old_chunk ~= new_chunk then local old_fragment_list = old_chunk.__fragment_list local old_fragment_count = old_chunk.__fragment_count local old_component_indices = old_chunk.__component_indices @@ -5511,8 +5671,8 @@ function __evolved_remove(entity, ...) do __detach_entity(old_chunk, old_place) - entity_chunks[entity_primary] = new_chunk - entity_places[entity_primary] = new_chunk and new_chunk.__entity_count + entity_chunks[entity_primary] = new_chunk or false + entity_places[entity_primary] = new_chunk and new_chunk.__entity_count or 0 __structural_changes = __structural_changes + 1 end @@ -6081,6 +6241,53 @@ function __evolved_locate(entity) return entity_chunk, __entity_places[entity_primary] end +---@param name string +---@return evolved.entity? entity +---@nodiscard +function __evolved_lookup(name) + return __named_entity[name] +end + +---@param name string +---@return evolved.entity[] entity_list +---@return integer entity_count +---@nodiscard +function __evolved_multi_lookup(name) + local entity_list = {} + local entity_count = __evolved_multi_lookup_to(entity_list, 1, name) + return entity_list, entity_count +end + +---@param out_entity_list evolved.entity[] +---@param out_entity_first integer +---@param name string +---@return integer entity_count +function __evolved_multi_lookup_to(out_entity_list, out_entity_first, name) + do + local named_entities = __named_entities[name] + local named_entity_list = named_entities and named_entities.__item_list + local named_entity_count = named_entities and named_entities.__item_count or 0 + + if named_entity_count > 0 then + __lua_table_move( + named_entity_list, 1, named_entity_count, + out_entity_first, out_entity_list) + return named_entity_count + end + end + + do + local named_entity = __named_entity[name] + + if named_entity then + out_entity_list[out_entity_first] = named_entity + return 1 + end + end + + return 0 +end + ---@param ... evolved.system systems function __evolved_process(...) local argument_count = __lua_select('#', ...) @@ -6121,7 +6328,8 @@ function __evolved_debug_mode(yesno) __debug_mode = yesno end -function __evolved_collect_garbage() +---@param no_shrink boolean? +function __evolved_collect_garbage(no_shrink) if __defer_depth > 0 then __defer_call_hook(__evolved_collect_garbage) return @@ -6185,16 +6393,16 @@ function __evolved_collect_garbage() local postorder_chunk_entity_count = postorder_chunk.__entity_count local postorder_chunk_entity_capacity = postorder_chunk.__entity_capacity - local should_be_purged = + local can_be_purged = postorder_chunk_child_count == 0 and postorder_chunk_entity_count == 0 - local should_be_shrunk = + local can_be_shrunk = postorder_chunk_entity_count < postorder_chunk_entity_capacity - if should_be_purged then + if can_be_purged then __purge_chunk(postorder_chunk) - elseif should_be_shrunk then + elseif can_be_shrunk and not no_shrink then __shrink_chunk(postorder_chunk, 0) end end @@ -6210,63 +6418,31 @@ function __evolved_collect_garbage() end end - for table_pool_tag = 1, __table_pool_tag.__count do - local table_pool_reserve = __table_pool_reserve[table_pool_tag] + if not no_shrink then + for table_pool_tag = 1, __table_pool_tag.__count do + local table_pool_reserve = __table_pool_reserve[table_pool_tag] - ---@type evolved.table_pool - local new_table_pool = __lua_table_new(table_pool_reserve) + ---@type evolved.table_pool + local new_table_pool = __lua_table_new(table_pool_reserve) - for table_pool_index = 1, table_pool_reserve do - new_table_pool[table_pool_index] = {} - end + for table_pool_index = 1, table_pool_reserve do + new_table_pool[table_pool_index] = {} + end - new_table_pool.__size = table_pool_reserve + new_table_pool.__size = table_pool_reserve - __tagged_table_pools[table_pool_tag] = new_table_pool - end - - do - ---@type table - local new_entity_chunks = {} - - for entity_primary, entity_chunk in __lua_next, __entity_chunks do - new_entity_chunks[entity_primary] = entity_chunk + __tagged_table_pools[table_pool_tag] = new_table_pool end - __entity_chunks = new_entity_chunks - end - - do - ---@type table - local new_entity_places = {} - - for entity_primary, entity_place in __lua_next, __entity_places do - new_entity_places[entity_primary] = entity_place + do + __entity_chunks = __list_fns.dup(__entity_chunks, __acquired_count) + __entity_places = __list_fns.dup(__entity_places, __acquired_count) end - __entity_places = new_entity_places - end - - do - ---@type integer[] - local new_defer_points = __lua_table_new(__defer_depth) - - __lua_table_move( - __defer_points, 1, __defer_depth, - 1, new_defer_points) - - __defer_points = new_defer_points - end - - do - ---@type any[] - local new_defer_bytecode = __lua_table_new(__defer_length) - - __lua_table_move( - __defer_bytecode, 1, __defer_length, - 1, new_defer_bytecode) - - __defer_bytecode = new_defer_bytecode + do + __defer_points = __list_fns.dup(__defer_points, __defer_depth) + __defer_bytecode = __list_fns.dup(__defer_bytecode, __defer_length) + end end __evolved_commit() @@ -6457,6 +6633,7 @@ end ---@param component_mapper? evolved.component_mapper ---@return evolved.entity[] entity_list ---@return integer entity_count +---@nodiscard function __builder_mt:multi_build(entity_count, prefab, component_mapper) if prefab then return self:multi_clone(entity_count, prefab, component_mapper) @@ -6465,6 +6642,31 @@ function __builder_mt:multi_build(entity_count, prefab, component_mapper) end end +---@param entity_count integer +---@param prefab? evolved.entity +---@param component_mapper? evolved.component_mapper +function __builder_mt:multi_build_nr(entity_count, prefab, component_mapper) + if prefab then + self:multi_clone_nr(entity_count, prefab, component_mapper) + else + self:multi_spawn_nr(entity_count, component_mapper) + end +end + +---@param out_entity_list evolved.entity[] +---@param out_entity_first integer +---@param entity_count integer +---@param prefab? evolved.entity +---@param component_mapper? evolved.component_mapper +function __builder_mt:multi_build_to(out_entity_list, out_entity_first, + entity_count, prefab, component_mapper) + if prefab then + self:multi_clone_to(out_entity_list, out_entity_first, entity_count, prefab, component_mapper) + else + self:multi_spawn_to(out_entity_list, out_entity_first, entity_count, component_mapper) + end +end + ---@param component_mapper? evolved.component_mapper ---@return evolved.entity entity function __builder_mt:spawn(component_mapper) @@ -6505,11 +6707,43 @@ end ---@param component_mapper? evolved.component_mapper ---@return evolved.entity[] entity_list ---@return integer entity_count +---@nodiscard function __builder_mt:multi_spawn(entity_count, component_mapper) if entity_count <= 0 then return {}, 0 end + local entity_list = __lua_table_new(entity_count) + + self:multi_spawn_to(entity_list, 1, entity_count, component_mapper) + + return entity_list, entity_count +end + +---@param entity_count integer +---@param component_mapper? evolved.component_mapper +function __builder_mt:multi_spawn_nr(entity_count, component_mapper) + if entity_count <= 0 then + return + end + + local entity_list = __acquire_table(__table_pool_tag.entity_list) + + self:multi_spawn_to(entity_list, 1, entity_count, component_mapper) + + __release_table(__table_pool_tag.entity_list, entity_list, false, true) +end + +---@param out_entity_list evolved.entity[] +---@param out_entity_first integer +---@param entity_count integer +---@param component_mapper? evolved.component_mapper +function __builder_mt:multi_spawn_to(out_entity_list, out_entity_first, + entity_count, component_mapper) + if entity_count <= 0 then + return + end + local chunk = self.__chunk local component_table = self.__component_table @@ -6524,27 +6758,27 @@ function __builder_mt:multi_spawn(entity_count, component_mapper) end end - local entity_list = __lua_table_new(entity_count) - - for entity_index = 1, entity_count do - entity_list[entity_index] = __acquire_id() + for entity_index = out_entity_first, out_entity_first + entity_count - 1 do + out_entity_list[entity_index] = __acquire_id() end if not component_table or not __lua_next(component_table) then - return entity_list, entity_count + return end if __defer_depth > 0 then - __defer_multi_spawn_entity(chunk, entity_list, entity_count, component_table, component_mapper) + __defer_multi_spawn_entity(chunk, + out_entity_list, out_entity_first, entity_count, + component_table, component_mapper) else __evolved_defer() do - __multi_spawn_entity(chunk, entity_list, entity_count, component_table, component_mapper) + __multi_spawn_entity(chunk, + out_entity_list, out_entity_first, entity_count, + component_table, component_mapper) end __evolved_commit() end - - return entity_list, entity_count end ---@param prefab evolved.entity @@ -6589,11 +6823,45 @@ end ---@param component_mapper? evolved.component_mapper ---@return evolved.entity[] entity_list ---@return integer entity_count +---@nodiscard function __builder_mt:multi_clone(entity_count, prefab, component_mapper) if entity_count <= 0 then return {}, 0 end + local entity_list = __lua_table_new(entity_count) + + self:multi_clone_to(entity_list, 1, entity_count, prefab, component_mapper) + + return entity_list, entity_count +end + +---@param entity_count integer +---@param prefab evolved.entity +---@param component_mapper? evolved.component_mapper +function __builder_mt:multi_clone_nr(entity_count, prefab, component_mapper) + if entity_count <= 0 then + return + end + + local entity_list = __acquire_table(__table_pool_tag.entity_list) + + self:multi_clone_to(entity_list, 1, entity_count, prefab, component_mapper) + + __release_table(__table_pool_tag.entity_list, entity_list, false, true) +end + +---@param out_entity_list evolved.entity[] +---@param out_entity_first integer +---@param entity_count integer +---@param prefab evolved.entity +---@param component_mapper? evolved.component_mapper +function __builder_mt:multi_clone_to(out_entity_list, out_entity_first, + entity_count, prefab, component_mapper) + if entity_count <= 0 then + return + end + local component_table = self.__component_table if __debug_mode then @@ -6612,23 +6880,23 @@ function __builder_mt:multi_clone(entity_count, prefab, component_mapper) end end - local entity_list = __lua_table_new(entity_count) - - for entity_index = 1, entity_count do - entity_list[entity_index] = __acquire_id() + for entity_index = out_entity_first, out_entity_first + entity_count - 1 do + out_entity_list[entity_index] = __acquire_id() end if __defer_depth > 0 then - __defer_multi_clone_entity(prefab, entity_list, entity_count, component_table, component_mapper) + __defer_multi_clone_entity(prefab, + out_entity_list, out_entity_first, entity_count, + component_table, component_mapper) else __evolved_defer() do - __multi_clone_entity(prefab, entity_list, entity_count, component_table, component_mapper) + __multi_clone_entity(prefab, + out_entity_list, out_entity_first, entity_count, + component_table, component_mapper) end __evolved_commit() end - - return entity_list, entity_count end ---@param fragment evolved.fragment @@ -6772,7 +7040,7 @@ end ---@return evolved.builder builder function __builder_mt:clear() self.__chunk = nil - __lua_table_clear(self.__component_table) + __lua_table_clear(self.__component_table, true, false) return self end @@ -6849,7 +7117,7 @@ function __builder_mt:include(...) local include_count = include_list and #include_list or 0 if include_count == 0 then - include_list = __list_new(argument_count) + include_list = __list_fns.new(argument_count) end for argument_index = 1, argument_count do @@ -6874,7 +7142,7 @@ function __builder_mt:exclude(...) local exclude_count = exclude_list and #exclude_list or 0 if exclude_count == 0 then - exclude_list = __list_new(argument_count) + exclude_list = __list_fns.new(argument_count) end for argument_index = 1, argument_count do @@ -6899,7 +7167,7 @@ function __builder_mt:variant(...) local variant_count = variant_list and #variant_list or 0 if variant_count == 0 then - variant_list = __list_new(argument_count) + variant_list = __list_fns.new(argument_count) end for argument_index = 1, argument_count do @@ -6924,7 +7192,7 @@ function __builder_mt:require(...) local require_count = require_list and #require_list or 0 if require_count == 0 then - require_list = __list_new(argument_count) + require_list = __list_fns.new(argument_count) end for argument_index = 1, argument_count do @@ -7156,17 +7424,17 @@ __evolved_set(__DISABLED, __TAG) __evolved_set(__DISABLED, __UNIQUE) __evolved_set(__DISABLED, __EXPLICIT) -__evolved_set(__INCLUDES, __DEFAULT, __list_new()) -__evolved_set(__INCLUDES, __DUPLICATE, __list_dup) +__evolved_set(__INCLUDES, __DEFAULT, __list_fns.new()) +__evolved_set(__INCLUDES, __DUPLICATE, __list_fns.dup) -__evolved_set(__EXCLUDES, __DEFAULT, __list_new()) -__evolved_set(__EXCLUDES, __DUPLICATE, __list_dup) +__evolved_set(__EXCLUDES, __DEFAULT, __list_fns.new()) +__evolved_set(__EXCLUDES, __DUPLICATE, __list_fns.dup) -__evolved_set(__VARIANTS, __DEFAULT, __list_new()) -__evolved_set(__VARIANTS, __DUPLICATE, __list_dup) +__evolved_set(__VARIANTS, __DEFAULT, __list_fns.new()) +__evolved_set(__VARIANTS, __DUPLICATE, __list_fns.dup) -__evolved_set(__REQUIRES, __DEFAULT, __list_new()) -__evolved_set(__REQUIRES, __DUPLICATE, __list_dup) +__evolved_set(__REQUIRES, __DEFAULT, __list_fns.new()) +__evolved_set(__REQUIRES, __DUPLICATE, __list_fns.dup) __evolved_set(__ON_SET, __UNIQUE) __evolved_set(__ON_ASSIGN, __UNIQUE) @@ -7179,6 +7447,75 @@ __evolved_set(__ON_REMOVE, __UNIQUE) --- --- +---@param name string +---@param entity evolved.entity +local function __insert_named_entity(name, entity) + ---@type evolved.entity? + local named_entity = __named_entity[name] + + if not named_entity then + __named_entity[name] = entity + return + end + + ---@type evolved.assoc_list? + local named_entities = __named_entities[name] + + if not named_entities then + __named_entities[name] = __assoc_list_fns.from(named_entity, entity) + return + end + + __assoc_list_fns.insert(named_entities, entity) +end + +---@param name string +---@param entity evolved.entity +local function __remove_named_entity(name, entity) + ---@type evolved.assoc_list? + local named_entities = __named_entities[name] + + if named_entities then + if __assoc_list_fns.remove(named_entities, entity) == 0 then + __named_entities[name], named_entities = nil, nil + end + end + + ---@type evolved.entity? + local named_entity = __named_entity[name] + + if named_entity == entity then + __named_entity[name] = named_entities and named_entities.__item_list[1] or nil + end +end + +---@param entity evolved.entity +---@param new_name? string +---@param old_name? string +__evolved_set(__NAME, __ON_SET, function(entity, _, new_name, old_name) + if old_name then + __remove_named_entity(old_name, entity) + end + + if new_name then + __insert_named_entity(new_name, entity) + end +end) + +---@param entity evolved.entity +---@param old_name? string +__evolved_set(__NAME, __ON_REMOVE, function(entity, _, old_name) + if old_name then + __remove_named_entity(old_name, entity) + end +end) + +--- +--- +--- +--- +--- + ---@param query evolved.query local function __insert_query(query) local query_includes = __sorted_includes[query] @@ -7195,11 +7532,11 @@ local function __insert_query(query) if not major_queries then ---@type evolved.assoc_list - major_queries = __assoc_list_new(4) + major_queries = __assoc_list_fns.new(4) __major_queries[query_major] = major_queries end - __assoc_list_insert(major_queries, query) + __assoc_list_fns.insert(major_queries, query) end for query_variant_index = 1, query_variant_count do @@ -7210,11 +7547,11 @@ local function __insert_query(query) if not major_queries then ---@type evolved.assoc_list - major_queries = __assoc_list_new(4) + major_queries = __assoc_list_fns.new(4) __major_queries[query_variant] = major_queries end - __assoc_list_insert(major_queries, query) + __assoc_list_fns.insert(major_queries, query) end end end @@ -7233,7 +7570,7 @@ local function __remove_query(query) local query_major = query_include_list[query_include_count] local major_queries = __major_queries[query_major] - if major_queries and __assoc_list_remove(major_queries, query) == 0 then + if major_queries and __assoc_list_fns.remove(major_queries, query) == 0 then __major_queries[query_major] = nil end end @@ -7244,7 +7581,7 @@ local function __remove_query(query) if query_include_count == 0 or query_variant > query_include_list[query_include_count] then local major_queries = __major_queries[query_variant] - if major_queries and __assoc_list_remove(major_queries, query) == 0 then + if major_queries and __assoc_list_fns.remove(major_queries, query) == 0 then __major_queries[query_variant] = nil end end @@ -7268,10 +7605,10 @@ __evolved_set(__INCLUDES, __ON_SET, function(query, _, include_list) if include_count > 0 then ---@type evolved.assoc_list - local sorted_includes = __assoc_list_new(include_count) + local sorted_includes = __assoc_list_fns.new(include_count) - __assoc_list_move(include_list, 1, include_count, sorted_includes) - __assoc_list_sort(sorted_includes) + __assoc_list_fns.move(include_list, 1, include_count, sorted_includes) + __assoc_list_fns.sort(sorted_includes) __sorted_includes[query] = sorted_includes else @@ -7306,10 +7643,10 @@ __evolved_set(__EXCLUDES, __ON_SET, function(query, _, exclude_list) if exclude_count > 0 then ---@type evolved.assoc_list - local sorted_excludes = __assoc_list_new(exclude_count) + local sorted_excludes = __assoc_list_fns.new(exclude_count) - __assoc_list_move(exclude_list, 1, exclude_count, sorted_excludes) - __assoc_list_sort(sorted_excludes) + __assoc_list_fns.move(exclude_list, 1, exclude_count, sorted_excludes) + __assoc_list_fns.sort(sorted_excludes) __sorted_excludes[query] = sorted_excludes else @@ -7344,10 +7681,10 @@ __evolved_set(__VARIANTS, __ON_SET, function(query, _, variant_list) if variant_count > 0 then ---@type evolved.assoc_list - local sorted_variants = __assoc_list_new(variant_count) + local sorted_variants = __assoc_list_fns.new(variant_count) - __assoc_list_move(variant_list, 1, variant_count, sorted_variants) - __assoc_list_sort(sorted_variants) + __assoc_list_fns.move(variant_list, 1, variant_count, sorted_variants) + __assoc_list_fns.sort(sorted_variants) __sorted_variants[query] = sorted_variants else @@ -7380,10 +7717,10 @@ __evolved_set(__REQUIRES, __ON_SET, function(fragment, _, require_list) if require_count > 0 then ---@type evolved.assoc_list - local sorted_requires = __assoc_list_new(require_count) + local sorted_requires = __assoc_list_fns.new(require_count) - __assoc_list_move(require_list, 1, require_count, sorted_requires) - __assoc_list_sort(sorted_requires) + __assoc_list_fns.move(require_list, 1, require_count, sorted_requires) + __assoc_list_fns.sort(sorted_requires) __sorted_requires[fragment] = sorted_requires else @@ -7413,11 +7750,11 @@ local function __add_subsystem(subsystem) if not group_subsystems then ---@type evolved.assoc_list - group_subsystems = __assoc_list_new(4) + group_subsystems = __assoc_list_fns.new(4) __group_subsystems[subsystem_group] = group_subsystems end - __assoc_list_insert(group_subsystems, subsystem) + __assoc_list_fns.insert(group_subsystems, subsystem) end end @@ -7428,7 +7765,7 @@ local function __remove_subsystem(subsystem) if subsystem_group then local group_subsystems = __group_subsystems[subsystem_group] - if group_subsystems and __assoc_list_remove(group_subsystems, subsystem) == 0 then + if group_subsystems and __assoc_list_fns.remove(group_subsystems, subsystem) == 0 then __group_subsystems[subsystem_group] = nil end end @@ -7517,9 +7854,13 @@ evolved.cancel = __evolved_cancel evolved.spawn = __evolved_spawn evolved.multi_spawn = __evolved_multi_spawn +evolved.multi_spawn_nr = __evolved_multi_spawn_nr +evolved.multi_spawn_to = __evolved_multi_spawn_to evolved.clone = __evolved_clone evolved.multi_clone = __evolved_multi_clone +evolved.multi_clone_nr = __evolved_multi_clone_nr +evolved.multi_clone_to = __evolved_multi_clone_to evolved.alive = __evolved_alive evolved.alive_all = __evolved_alive_all @@ -7550,6 +7891,10 @@ evolved.execute = __evolved_execute evolved.locate = __evolved_locate +evolved.lookup = __evolved_lookup +evolved.multi_lookup = __evolved_multi_lookup +evolved.multi_lookup_to = __evolved_multi_lookup_to + evolved.process = __evolved_process evolved.process_with = __evolved_process_with diff --git a/example/main.lua b/example/main.lua index 84abfec..634084b 100644 --- a/example/main.lua +++ b/example/main.lua @@ -52,7 +52,7 @@ evolved.builder() :name('SYSTEMS.STARTUP') :group(STAGES.ON_SETUP) :prologue(function() - evolved.multi_clone(500, PREFABS.CIRCLE, nil, function(chunk, b_place, e_place) + evolved.multi_clone_nr(500, PREFABS.CIRCLE, nil, function(chunk, b_place, e_place) local screen_width, screen_height = love.graphics.getDimensions() ---@type number[], number[] diff --git a/rockspecs/evolved.lua-1.10.0-0.rockspec b/rockspecs/evolved.lua-1.10.0-0.rockspec new file mode 100644 index 0000000..f3c7b02 --- /dev/null +++ b/rockspecs/evolved.lua-1.10.0-0.rockspec @@ -0,0 +1,34 @@ +rockspec_format = "3.0" +package = "evolved.lua" +version = "1.10.0-0" +source = { + url = "git://github.com/BlackMATov/evolved.lua", + tag = "v1.10.0", +} +description = { + homepage = "https://github.com/BlackMATov/evolved.lua", + summary = "Evolved ECS (Entity-Component-System) for Lua", + detailed = [[ + `evolved.lua` is a fast and flexible ECS (Entity-Component-System) library for Lua. + It is designed to be simple and easy to use, while providing all the features needed to create complex systems with blazing performance. + ]], + license = "MIT", + labels = { + "ecs", + "entity", + "entities", + "component", + "components", + "entity-component", + "entity-component-system", + }, +} +dependencies = { + "lua >= 5.1", +} +build = { + type = "builtin", + modules = { + evolved = "evolved.lua", + } +}