89 Commits

Author SHA1 Message Date
2903b077fe Merge pull request #24 from BlackMATov/dev
Dev
2025-09-26 17:30:35 +07:00
BlackMATov
d3b14a6741 v1.3.0 2025-09-26 17:27:49 +07:00
BlackMATov
fdf5a03a02 improve performance of builders that are used for spawning multiple times 2025-09-26 17:21:50 +07:00
BlackMATov
9221da6ea7 slightly improve required fragments perf 2025-09-24 18:16:01 +07:00
BlackMATov
0aa57f6b5b benchmarks refactoring 2 2025-09-24 00:51:25 +07:00
BlackMATov
7e38e43d7c benchmarks refactoring 2025-09-23 17:37:29 +07:00
BlackMATov
b1b627b677 improve perf of cloning prefabs with many unique fragments 2025-09-23 07:53:11 +07:00
BlackMATov
281866cf6e set/assign hooks are not invoked for tags on override operations anymore 2025-09-23 07:24:26 +07:00
BlackMATov
4ad7fec26d update readme 2025-09-23 05:05:30 +07:00
BlackMATov
f15118be05 the new evolved.locate public function
ref: #23
2025-09-23 04:58:10 +07:00
BlackMATov
964ea45f48 use xpcall to process systems 2025-09-22 21:27:57 +07:00
BlackMATov
b2c08e1127 cancel deferring ops in systems on error 2025-09-22 05:51:21 +07:00
BlackMATov
2250bd64ce the new evolved.cancel public function 2025-09-22 02:34:37 +07:00
BlackMATov
e564be46fb collect garbage from old bytecode 2025-09-22 01:56:08 +07:00
BlackMATov
521ad94278 the internal garbage collector now collects more garbage 2025-09-20 03:11:12 +07:00
BlackMATov
7f6909e48c remove some unused code about pinned chunks 2025-09-20 01:53:29 +07:00
BlackMATov
ec745f6ad7 Merge branch 'feature/schemes' into dev 2025-09-19 19:51:02 +07:00
BlackMATov
b3eec59f8b update readme 2025-09-19 19:50:50 +07:00
BlackMATov
1635dd66b1 remove schemes temporary 2025-09-19 18:58:18 +07:00
BlackMATov
b420085ed5 proof of concept ffi component storages
fast batch ops storage swapping was temporary removed
2025-09-19 07:04:19 +07:00
BlackMATov
6d5f810d45 experimental scheme creation 2025-09-15 17:56:44 +07:00
BlackMATov
5447f50090 dummy SCHEME class and readme 2025-09-12 05:58:41 +07:00
BlackMATov
e6d79dc600 Merge branch 'dev' into feature/schemes 2025-09-12 05:45:33 +07:00
7b6ac89c8a Merge pull request #21 from BlackMATov/dev
Dev
2025-09-12 05:30:07 +07:00
BlackMATov
91b3910eda v1.2.0 2025-09-12 05:27:17 +07:00
BlackMATov
7f5ac62a79 Merge branch 'feature/multi_spawn' into dev 2025-09-12 05:13:55 +07:00
BlackMATov
327a6bcbce final tweaks of the multi_spawn/clone functions 2025-09-12 05:11:29 +07:00
BlackMATov
5184b39f4e proof of concept multi_clone/spawn optimizations 2025-09-12 01:52:33 +07:00
BlackMATov
de7d1a6674 dirty proof of concept multi_spawn impl (without any optimization) 2025-09-11 06:57:13 +07:00
BlackMATov
632232b9b1 dummy multi spawn api 2025-09-11 01:27:54 +07:00
BlackMATov
fbc61a8895 style fixes 2025-09-10 16:27:50 +07:00
BlackMATov
e3ed2d89a6 style fixes 2025-09-09 14:46:54 +07:00
BlackMATov
bb7f469288 inline internal ids unpacking 2025-09-09 05:02:27 +07:00
BlackMATov
8417cecbbe little test fixes 2025-09-08 17:42:31 +07:00
BlackMATov
eb31ed247b little test fixes 2025-09-08 17:41:18 +07:00
BlackMATov
9400401161 dummy SCHEME fragment trait 2025-09-03 15:07:32 +07:00
BlackMATov
59fb4d8ea4 update readme 2025-09-01 16:09:35 +07:00
BlackMATov
001e6f2956 Merge branch 'feature/pairs' into dev 2025-09-01 15:49:46 +07:00
BlackMATov
fb6d13ca74 temp remove pairs to merge other changes to dev 2025-09-01 15:34:03 +07:00
BlackMATov
8f61a14db6 update pairs todos 2025-09-01 15:09:29 +07:00
BlackMATov
0c016f1b67 return xxx_set debug mode 2025-09-01 01:59:00 +07:00
BlackMATov
26bf586140 primary/secondary functon set doesn't work with pairs as entity now 2025-09-01 01:53:29 +07:00
BlackMATov
46f1516a55 style fixes 2025-09-01 01:10:17 +07:00
BlackMATov
4cd8393546 public api works only with non-pair ids in has/get functions 2025-09-01 00:33:10 +07:00
BlackMATov
22302cee75 primary/secondary iterators for pair entities 2025-08-29 18:19:19 +07:00
BlackMATov
d4a7c7b77c more pair checks 2025-08-29 05:56:23 +07:00
BlackMATov
12beee6eec debug mode for pack/unpack and pair/unpair 2025-08-26 05:42:04 +07:00
BlackMATov
71a7d382c1 more type annots 2025-08-26 04:13:50 +07:00
BlackMATov
f2a8ee5b83 little style fixes 2025-08-24 16:14:26 +07:00
BlackMATov
81bf1d91e9 Revert "temp remove pairs to merge other changes to dev" 2025-08-20 23:27:08 +07:00
BlackMATov
6b4c6f2a9a update changelog 2025-08-20 23:17:12 +07:00
BlackMATov
7eb4bfd62d Merge branch 'feature/temp_remove_pairs' into dev 2025-08-20 23:11:55 +07:00
BlackMATov
1b49f4fcd0 temp remove pairs to merge other changes to dev 2025-08-20 23:04:11 +07:00
BlackMATov
77bc6c298e remove 'options' param from evolved.pack 2025-08-20 22:23:25 +07:00
BlackMATov
008df17ee6 fix readme formatting 2025-08-20 05:41:06 +07:00
BlackMATov
ba3018213e builder wildcard has/remove first impl 2025-08-20 05:16:18 +07:00
6bf13890ef Merge pull request #14 from BlackMATov/dev
Dev
2025-06-06 21:28:17 +07:00
db191b805f Merge pull request #13 from BlackMATov/dev
Dev
2025-05-23 20:07:43 +07:00
5ab963022c Merge pull request #12 from BlackMATov/dev
Dev
2025-05-21 20:48:59 +07:00
7de95207d6 Merge pull request #11 from BlackMATov/dev
Dev
2025-05-21 17:34:13 +07:00
4d3b909efb Merge pull request #10 from BlackMATov/dev
Dev
2025-05-21 06:20:38 +07:00
52b3cbeb20 Merge pull request #9 from BlackMATov/dev
Dev
2025-05-21 03:38:16 +07:00
fec193f4f0 Merge pull request #8 from BlackMATov/dev
Dev
2025-05-21 02:11:39 +07:00
e672b0291a Merge pull request #7 from BlackMATov/dev
Dev
2025-05-02 07:28:38 +07:00
4624f2e603 Merge pull request #6 from BlackMATov/dev
Dev
2025-04-30 23:47:13 +07:00
c25769f64f Merge pull request #5 from BlackMATov/dev
Dev
2025-04-19 18:40:25 +07:00
d7274765cb Merge pull request #4 from BlackMATov/dev
Dev
2025-04-09 03:04:19 +07:00
ef033e7a0c Merge pull request #3 from BlackMATov/dev
Dev
2025-04-09 00:58:14 +07:00
3638dedca5 Merge pull request #2 from BlackMATov/dev
Dev
2025-04-06 21:27:33 +07:00
d025ea039b Merge pull request #1 from BlackMATov/dev
Dev
2025-04-05 02:12:18 +07:00
BlackMATov
6c0df71f17 Merge branch 'dev' 2025-03-27 15:36:58 +07:00
BlackMATov
730bffc3ad Merge branch 'dev' 2025-03-19 06:52:10 +07:00
BlackMATov
4bbd7ee60a Merge branch 'dev' 2025-03-18 07:08:27 +07:00
BlackMATov
79aecc8db3 Merge branch 'dev' 2025-03-17 00:23:36 +07:00
BlackMATov
b803faea63 Merge branch 'dev' 2025-03-16 07:46:26 +07:00
BlackMATov
722eda0b9b Merge branch 'dev' 2025-03-16 02:06:17 +07:00
BlackMATov
c6def51830 Merge branch 'dev' 2025-03-10 08:14:38 +07:00
BlackMATov
65312f79dd Merge branch 'dev' 2025-03-08 06:07:06 +07:00
BlackMATov
9877e41705 Merge branch 'dev' 2025-03-02 12:09:33 +07:00
BlackMATov
3b8367d5c4 Merge branch 'dev' 2025-02-24 06:06:26 +07:00
BlackMATov
419a6b6c45 Merge branch 'dev' 2025-02-23 03:54:56 +07:00
BlackMATov
368b50770c Merge branch 'dev' 2025-02-22 00:31:27 +07:00
BlackMATov
0d49802235 Merge branch 'dev' 2025-02-08 04:52:56 +07:00
BlackMATov
f096d747f3 Merge branch 'dev' 2025-01-31 22:14:13 +07:00
BlackMATov
4d88063c10 Merge branch 'dev' 2025-01-31 12:51:30 +07:00
BlackMATov
bf135534c0 Merge branch 'dev' 2025-01-25 08:37:55 +07:00
BlackMATov
177ea7f180 Merge branch 'dev' 2025-01-21 10:52:19 +07:00
BlackMATov
b98b5f9c42 Merge branch 'dev' 2025-01-18 01:39:27 +07:00
BlackMATov
c7120e8608 opt: get chunk by fragments without sorting 2025-01-16 06:42:03 +07:00
24 changed files with 4026 additions and 5560 deletions

View File

@@ -8,7 +8,6 @@
"markdown.extension.toc.levels": "2..6", "markdown.extension.toc.levels": "2..6",
"markdown.extension.toc.omittedFromToc": { "markdown.extension.toc.omittedFromToc": {
"README.md": [ "README.md": [
"# Changelog",
"# API Reference" "# API Reference"
] ]
} }

333
README.md
View File

@@ -31,6 +31,7 @@
- [Traits](#traits) - [Traits](#traits)
- [Singletons](#singletons) - [Singletons](#singletons)
- [Chunks](#chunks) - [Chunks](#chunks)
- [Entity Location](#entity-location)
- [Structural Changes](#structural-changes) - [Structural Changes](#structural-changes)
- [Spawning Entities](#spawning-entities) - [Spawning Entities](#spawning-entities)
- [Entity Builders](#entity-builders) - [Entity Builders](#entity-builders)
@@ -54,10 +55,14 @@
- [Aliases](#aliases) - [Aliases](#aliases)
- [Predefs](#predefs) - [Predefs](#predefs)
- [Functions](#functions) - [Functions](#functions)
- [Relations](#relations)
- [Classes](#classes) - [Classes](#classes)
- [Chunk](#chunk) - [Chunk](#chunk)
- [Builder](#builder) - [Builder](#builder)
- [Changelog](#changelog)
- [v1.3.0](#v130)
- [v1.2.0](#v120)
- [v1.1.0](#v110)
- [v1.0.0](#v100)
- [License](#license) - [License](#license)
## Introduction ## Introduction
@@ -148,17 +153,15 @@ function evolved.alive_any(...) end
Sometimes (for debugging purposes, for example), it is necessary to extract the index and version from an identifier or to pack them back into an identifier. The [`evolved.pack`](#evolvedpack) and [`evolved.unpack`](#evolvedunpack) functions can be used for this purpose. Sometimes (for debugging purposes, for example), it is necessary to extract the index and version from an identifier or to pack them back into an identifier. The [`evolved.pack`](#evolvedpack) and [`evolved.unpack`](#evolvedunpack) functions can be used for this purpose.
```lua ```lua
---@param primary integer ---@param index integer
---@param secondary integer ---@param version integer
---@param options? integer
---@return evolved.id id ---@return evolved.id id
---@nodiscard ---@nodiscard
function evolved.pack(primary, secondary, options) end function evolved.pack(index, version) end
---@param id evolved.id ---@param id evolved.id
---@return integer primary ---@return integer primary
---@return integer secondary ---@return integer secondary
---@return integer options
---@nodiscard ---@nodiscard
function evolved.unpack(id) end function evolved.unpack(id) end
``` ```
@@ -363,6 +366,43 @@ end
-- Entity: 1048603, Health: 75, Stamina: 40 -- Entity: 1048603, Health: 75, Stamina: 40
``` ```
#### Entity Location
Sometimes it is useful to know which chunk a specific entity is in and its position within that chunk. The [`evolved.locate`](#evolvedlocate) function provides this information.
```lua
---@param entity evolved.entity
---@return evolved.chunk? chunk
---@return integer place
function evolved.locate(entity) end
```
This function takes an entity and returns the chunk that contains it and the entitys position (index) within that chunk. If the entity is not alive or is empty, the function returns `nil` for the chunk and `0` for the place.
This is low-level functionality that you will rarely need. However, it can be useful in specific cases. For example, when you need to modify an entitys component directly to avoid unnecessary [Deferred Operations](#deferred-operations) or [Fragment Hooks](#fragment-hooks), instead of using a higher-level function like [`evolved.set`](#evolvedset).
```lua
local evolved = require 'evolved'
local health, stamina = evolved.id(2)
local player = evolved.id()
evolved.set(player, health, 100)
evolved.set(player, stamina, 50)
local player_chunk, player_place = evolved.locate(player)
local health_components = player_chunk:components(health)
local stamina_components = player_chunk:components(stamina)
health_components[player_place] = 75
stamina_components[player_place] = 42
```
> [!WARNING]
> Do not use [`evolved.locate`](#evolvedlocate) to manipulate components directly unless you fully understand what you are doing. Because it is low-level functionality, incorrect use can lead to inconsistencies, as it bypasses the librarys safety checks and hook mechanisms. Use it only when you are certain it is safe and necessary.
### Structural Changes ### Structural Changes
Every time we insert or remove a fragment from an entity, the entity will be migrated to a new chunk. This is done automatically by the library, of course. However, you should be aware of this because it can affect performance, especially if you have many fragments on the entity. This is called a `structural change`. Every time we insert or remove a fragment from an entity, the entity will be migrated to a new chunk. This is done automatically by the library, of course. However, you should be aware of this because it can affect performance, especially if you have many fragments on the entity. This is called a `structural change`.
@@ -602,6 +642,9 @@ function evolved.defer() end
---@return boolean committed ---@return boolean committed
function evolved.commit() end function evolved.commit() end
---@return boolean cancelled
function evolved.cancel() end
``` ```
The [`evolved.defer`](#evolveddefer) function starts a deferred scope. This means that all changes made inside the scope will be queued and applied after leaving the scope. The [`evolved.commit`](#evolvedcommit) function closes the last deferred scope and applies all queued changes. These functions can be nested, so you can start a new deferred scope inside an existing one. The [`evolved.commit`](#evolvedcommit) function will apply all queued changes only when the last deferred scope is closed. The [`evolved.defer`](#evolveddefer) function starts a deferred scope. This means that all changes made inside the scope will be queued and applied after leaving the scope. The [`evolved.commit`](#evolvedcommit) function closes the last deferred scope and applies all queued changes. These functions can be nested, so you can start a new deferred scope inside an existing one. The [`evolved.commit`](#evolvedcommit) function will apply all queued changes only when the last deferred scope is closed.
@@ -632,6 +675,34 @@ evolved.commit()
assert(not evolved.has(player, poisoned)) assert(not evolved.has(player, poisoned))
``` ```
The [`evolved.cancel`](#evolvedcancel) function can be used to cancel all queued changes in the current deferred scope. This is useful if you want to discard all changes made inside the scope and revert to the previous state on an error or some other condition.
```lua
local evolved = require 'evolved'
local health, poisoned = evolved.id(2)
local player = evolved.builder()
:set(health, 100)
:set(poisoned, true)
:spawn()
-- start a deferred scope
evolved.defer()
-- this removal will be queued, not applied immediately
evolved.remove(player, poisoned)
-- the player still has the poisoned fragment inside the deferred scope
assert(evolved.has(player, poisoned))
-- cancel the deferred operations
evolved.cancel()
-- the poisoned fragment is still there
assert(evolved.has(player, poisoned))
```
#### Batch Operations #### Batch Operations
The library provides a set of functions for batch operations. These functions are used to perform modifying operations on multiple chunks at once. This is very useful for performance reasons. The library provides a set of functions for batch operations. These functions are used to perform modifying operations on multiple chunks at once. This is very useful for performance reasons.
@@ -842,6 +913,9 @@ evolved.set(player, health, 200) -- prints "health set to 200"
Use [`evolved.ON_SET`](#evolvedon_set) for callbacks on fragment insert or override, [`evolved.ON_ASSIGN`](#evolvedon_assign) for overrides, and [`evolved.ON_INSERT`](#evolvedon_insert)/[`evolved.ON_REMOVE`](#evolvedon_remove) for insertions or removals. Use [`evolved.ON_SET`](#evolvedon_set) for callbacks on fragment insert or override, [`evolved.ON_ASSIGN`](#evolvedon_assign) for overrides, and [`evolved.ON_INSERT`](#evolvedon_insert)/[`evolved.ON_REMOVE`](#evolvedon_remove) for insertions or removals.
> [!NOTE]
> Because fragments marked with [`evolved.TAG`](#evolvedtag) (also called [Fragment Tags](#fragment-tags)) have no components, their [`evolved.ON_SET`](#evolvedon_set) hooks are invoked only when the tag is inserted, not when it is overridden, as there is nothing to override. Their [`evolved.ON_ASSIGN`](#evolvedon_assign) hooks are never invoked for such tags for the same reason.
#### Unique Fragments #### Unique Fragments
Some fragments should not be cloned when cloning entities. For example, `evolved.lua` has a special fragment called `evolved.PREFAB`, which marks entities used as sources for cloning. This fragment should not be present on the cloned entities. To prevent a fragment from being cloned, mark it as unique using the [`evolved.UNIQUE`](#evolvedunique) fragment trait. This ensures the fragment will not be copied when cloning entities. Some fragments should not be cloned when cloning entities. For example, `evolved.lua` has a special fragment called `evolved.PREFAB`, which marks entities used as sources for cloning. This fragment should not be present on the cloned entities. To prevent a fragment from being cloned, mark it as unique using the [`evolved.UNIQUE`](#evolvedunique) fragment trait. This ensures the fragment will not be copied when cloning entities.
@@ -1043,27 +1117,21 @@ execute :: {chunk, entity[], integer}
prologue :: {} prologue :: {}
epilogue :: {} epilogue :: {}
set_hook :: {entity, fragment, component, component?} set_hook :: {entity, fragment, component, component}
assign_hook :: {entity, fragment, component, component} assign_hook :: {entity, fragment, component, component}
insert_hook :: {entity, fragment, component} insert_hook :: {entity, fragment, component}
remove_hook :: {entity, fragment, component} remove_hook :: {entity, fragment, component}
each_state :: implementation-specific each_state :: implementation-specific
execute_state :: implementation-specific execute_state :: implementation-specific
primaries_state :: implementation-specific
secondaries_state :: implementation-specific
each_iterator :: {each_state? -> fragment?, component?} each_iterator :: {each_state? -> fragment?, component?}
execute_iterator :: {execute_state? -> chunk?, entity[]?, integer?} execute_iterator :: {execute_state? -> chunk?, entity[]?, integer?}
primaries_iterator :: {primaries_state? -> fragment?, component?}
secondaries_iterator :: {secondaries_state? -> fragment?, component?}
``` ```
### Predefs ### Predefs
``` ```
ANY :: fragment
TAG :: fragment TAG :: fragment
NAME :: fragment NAME :: fragment
@@ -1105,14 +1173,18 @@ DESTRUCTION_POLICY_REMOVE_FRAGMENT :: id
id :: integer? -> id... id :: integer? -> id...
name :: id... -> string... name :: id... -> string...
pack :: integer, integer, integer? -> id pack :: integer, integer -> id
unpack :: id -> integer, integer, integer unpack :: id -> integer, integer
defer :: boolean defer :: boolean
commit :: boolean commit :: boolean
cancel :: boolean
spawn :: <fragment, component>? -> entity spawn :: <fragment, component>? -> entity
clone :: entity -> <fragment, component>? -> entity multi_spawn :: integer, <fragment, component>? -> entity[]
clone :: entity, <fragment, component>? -> entity
multi_clone :: integer, entity, <fragment, component>? -> entity[]
alive :: entity -> boolean alive :: entity -> boolean
alive_all :: entity... -> boolean alive_all :: entity... -> boolean
@@ -1141,29 +1213,14 @@ batch_destroy :: query... -> ()
each :: entity -> {each_state? -> fragment?, component?}, each_state? each :: entity -> {each_state? -> fragment?, component?}, each_state?
execute :: query -> {execute_state? -> chunk?, entity[]?, integer?}, execute_state? execute :: query -> {execute_state? -> chunk?, entity[]?, integer?}, execute_state?
locate :: entity -> chunk?, integer
process :: system... -> () process :: system... -> ()
debug_mode :: boolean -> () debug_mode :: boolean -> ()
collect_garbage :: () collect_garbage :: ()
``` ```
### Relations
pair :: id, id -> id
unpair :: id -> id, id
is_pair :: id -> boolean
is_wildcard :: id -> boolean
primary :: entity, fragment, integer? -> fragment?, component?
secondary :: entity, fragment, integer? -> fragment?, component?
primaries :: entity, fragment -> {primaries_state? -> fragment?, component?}, primaries_state?
secondaries :: entity, fragment -> {secondaries_state? -> fragment?, component?}, secondaries_state?
primary_count :: entity, fragment -> integer
secondary_count :: entity, fragment -> integer
### Classes ### Classes
#### Chunk #### Chunk
@@ -1189,7 +1246,10 @@ chunk_mt:components :: fragment... -> storage...
builder :: builder builder :: builder
builder_mt:spawn :: entity builder_mt:spawn :: entity
builder_mt:multi_spawn :: integer -> entity[]
builder_mt:clone :: entity -> entity builder_mt:clone :: entity -> entity
builder_mt:multi_clone :: integer, entity -> entity[]
builder_mt:has :: fragment -> boolean builder_mt:has :: fragment -> boolean
builder_mt:has_all :: fragment... -> boolean builder_mt:has_all :: fragment... -> boolean
@@ -1218,7 +1278,7 @@ builder_mt:include :: fragment... -> builder
builder_mt:exclude :: fragment... -> builder builder_mt:exclude :: fragment... -> builder
builder_mt:require :: fragment... -> builder builder_mt:require :: fragment... -> builder
builder_mt:on_set :: {entity, fragment, component, component?} -> builder builder_mt:on_set :: {entity, fragment, component, component} -> builder
builder_mt:on_assign :: {entity, fragment, component, component} -> builder builder_mt:on_assign :: {entity, fragment, component, component} -> builder
builder_mt:on_insert :: {entity, fragment, component} -> builder builder_mt:on_insert :: {entity, fragment, component} -> builder
builder_mt:on_remove :: {entity, fragment} -> builder builder_mt:on_remove :: {entity, fragment} -> builder
@@ -1234,27 +1294,41 @@ builder_mt:epilogue :: {} -> builder
builder_mt:destruction_policy :: id -> builder builder_mt:destruction_policy :: id -> builder
``` ```
## License ## Changelog
`evolved.lua` is licensed under the [MIT License][license]. For more details, see the [LICENSE.md](./LICENSE.md) file in the repository. ### v1.3.0
# Changelog - Added the new [`evolved.cancel`](#evolvedcancel) function
- Added the new [`evolved.locate`](#evolvedlocate) function
- The internal garbage collector now collects more garbage
- Improved system processing debugging experience with stack traces on errors
- [`SET/ASSIGN hooks`](#fragment-hooks) are not invoked for tags on override operations anymore
- Improved performance of cloning prefabs with many [`Unique Fragments`](#unique-fragments)
- Improved performance of builders that are used for spawning multiple times
## v1.1.0 ### v1.2.0
- Added the new [`evolved.name`](#evolvedname-1) function
- Added the new [`evolved.multi_spawn`](#evolvedmulti_spawn) and [`evolved.multi_clone`](#evolvedmulti_clone) functions
- Added the new [`evolved.INTERNAL`](#evolvedinternal) fragment trait
### v1.1.0
- [`Systems`](#systems) can be queries themselves now - [`Systems`](#systems) can be queries themselves now
- Added the new [`evolved.REQUIRES`](#evolvedrequires) fragment trait - Added the new [`evolved.REQUIRES`](#evolvedrequires) fragment trait
## v1.0.0 ### v1.0.0
- Initial release - Initial release
## License
`evolved.lua` is licensed under the [MIT License][license]. For more details, see the [LICENSE.md](./LICENSE.md) file in the repository.
# API Reference # API Reference
## Predefs ## Predefs
### `evolved.ANY`
### `evolved.TAG` ### `evolved.TAG`
### `evolved.NAME` ### `evolved.NAME`
@@ -1303,7 +1377,7 @@ builder_mt:destruction_policy :: id -> builder
### `evolved.DESTRUCTION_POLICY_REMOVE_FRAGMENT` ### `evolved.DESTRUCTION_POLICY_REMOVE_FRAGMENT`
## Core Functions ## Functions
### `evolved.id` ### `evolved.id`
@@ -1326,12 +1400,11 @@ function evolved.name(...) end
### `evolved.pack` ### `evolved.pack`
```lua ```lua
---@param primary integer ---@param index integer
---@param secondary integer ---@param version integer
---@param options? integer
---@return evolved.id id ---@return evolved.id id
---@nodiscard ---@nodiscard
function evolved.pack(primary, secondary, options) end function evolved.pack(index, version) end
``` ```
### `evolved.unpack` ### `evolved.unpack`
@@ -1340,7 +1413,6 @@ function evolved.pack(primary, secondary, options) end
---@param id evolved.id ---@param id evolved.id
---@return integer primary ---@return integer primary
---@return integer secondary ---@return integer secondary
---@return integer options
---@nodiscard ---@nodiscard
function evolved.unpack(id) end function evolved.unpack(id) end
``` ```
@@ -1359,23 +1431,49 @@ function evolved.defer() end
function evolved.commit() end function evolved.commit() end
``` ```
### `evolved.cancel`
```lua
---@return boolean cancelled
function evolved.cancel() end
```
### `evolved.spawn` ### `evolved.spawn`
```lua ```lua
---@param components? table<evolved.fragment, evolved.component> ---@param components? table<evolved.fragment, evolved.component>
---@return evolved.entity ---@return evolved.entity entity
function evolved.spawn(components) end function evolved.spawn(components) end
``` ```
### `evolved.multi_spawn`
```lua
---@param entity_count integer
---@param components? table<evolved.fragment, evolved.component>
---@return evolved.entity[] entity_list
function evolved.multi_spawn(entity_count, components) end
```
### `evolved.clone` ### `evolved.clone`
```lua ```lua
---@param prefab evolved.entity ---@param prefab evolved.entity
---@param components? table<evolved.fragment, evolved.component> ---@param components? table<evolved.fragment, evolved.component>
---@return evolved.entity ---@return evolved.entity entity
function evolved.clone(prefab, components) end function evolved.clone(prefab, components) end
``` ```
### `evolved.multi_clone`
```lua
---@param entity_count integer
---@param prefab evolved.entity
---@param components? table<evolved.fragment, evolved.component>
---@return evolved.entity[] entity_list
function evolved.multi_clone(entity_count, prefab, components) end
```
### `evolved.alive` ### `evolved.alive`
```lua ```lua
@@ -1552,6 +1650,16 @@ function evolved.each(entity) end
function evolved.execute(query) end function evolved.execute(query) end
``` ```
### `evolved.locate`
```lua
---@param entity evolved.entity
---@return evolved.chunk? chunk
---@return integer place
---@nodiscard
function evolved.locate(entity) end
```
### `evolved.process` ### `evolved.process`
```lua ```lua
@@ -1572,112 +1680,6 @@ function evolved.debug_mode(yesno) end
function evolved.collect_garbage() end function evolved.collect_garbage() end
``` ```
## Relation Functions
### `evolved.pair`
```lua
---@param primary evolved.id
---@param secondary evolved.id
---@return evolved.id pair
---@nodiscard
function evolved.pair(primary, secondary) end
```
### `evolved.unpair`
```lua
---@param pair evolved.id
---@return evolved.id primary
---@return evolved.id secondary
---@nodiscard
function evolved.unpair(pair) end
```
### `evolved.is_pair`
```lua
---@param id evolved.id
---@return boolean
---@nodiscard
function evolved.is_pair(id) end
```
### `evolved.is_wildcard`
```lua
---@param id evolved.id
---@return boolean
---@nodiscard
function evolved.is_wildcard(id) end
```
### `evolved.primary`
```lua
---@param entity evolved.entity
---@param secondary evolved.fragment
---@param index? integer
---@return evolved.fragment? primary
---@return evolved.component? component
---@nodiscard
function evolved.primary(entity, secondary, index) end
```
### `evolved.secondary`
```lua
---@param entity evolved.entity
---@param primary evolved.fragment
---@param index? integer
---@return evolved.fragment? secondary
---@return evolved.component? component
---@nodiscard
function evolved.secondary(entity, primary, index) end
```
### `evolved.primaries`
```lua
---@param entity evolved.entity
---@param secondary evolved.fragment
---@return evolved.primaries_iterator iterator
---@return evolved.primaries_state? iterator_state
---@nodiscard
function evolved.primaries(entity, secondary) end
```
### `evolved.secondaries`
```lua
---@param entity evolved.entity
---@param primary evolved.fragment
---@return evolved.secondaries_iterator iterator
---@return evolved.secondaries_state? iterator_state
---@nodiscard
function evolved.secondaries(entity, primary) end
```
### `evolved.primary_count`
```lua
---@param entity evolved.entity
---@param secondary evolved.fragment
---@return integer
---@nodiscard
function evolved.primary_count(entity, secondary) end
```
### `evolved.secondary_count`
```lua
---@param entity evolved.entity
---@param primary evolved.fragment
---@return integer
---@nodiscard
function evolved.secondary_count(entity, primary) end
```
## Classes ## Classes
### Chunk ### Chunk
@@ -1777,18 +1779,35 @@ function evolved.builder() end
#### `evolved.builder_mt:spawn` #### `evolved.builder_mt:spawn`
```lua ```lua
---@return evolved.entity ---@return evolved.entity entity
function evolved.builder_mt:spawn() end function evolved.builder_mt:spawn() end
``` ```
#### `evolved.builder_mt:multi_spawn`
```lua
---@param entity_count integer
---@return evolved.entity[] entity_list
function evolved.builder_mt:multi_spawn(entity_count) end
```
#### `evolved.builder_mt:clone` #### `evolved.builder_mt:clone`
```lua ```lua
---@param prefab evolved.entity ---@param prefab evolved.entity
---@return evolved.entity ---@return evolved.entity entity
function evolved.builder_mt:clone(prefab) end function evolved.builder_mt:clone(prefab) end
``` ```
#### `evolved.builder_mt:multi_clone`
```lua
---@param entity_count integer
---@param prefab evolved.entity
---@return evolved.entity[] entity_list
function evolved.builder_mt:multi_clone(entity_count, prefab) end
```
#### `evolved.builder_mt:has` #### `evolved.builder_mt:has`
```lua ```lua

View File

@@ -2,19 +2,17 @@
## Backlog ## Backlog
- Improve the performance of required fragments by caching first-level required chunks.
- Improve the performance of builders that are used multiple times by caching hint chunks.
- Queries can cache major chunks to avoid finding them every time. - Queries can cache major chunks to avoid finding them every time.
- Add multi-spawn to the builder to spawn multiple entities at once.
- Add a function to shrink storages to free unused memory.
- observers and events - observers and events
- add INDEX fragment trait - add INDEX fragment trait
- use compact prefix-tree for chunks - use compact prefix-tree for chunks
- optional ffi component storages - optional ffi component storages
- add EXCLUSIVE fragment trait
## Thoughts ## Thoughts
- We can return deferred status from modifying operations and spawn/clone methods. - We can return deferred status from modifying operations and spawn/clone methods.
- Should we make one builder:build method instead of :spawn and :clone? - Should we make one builder:build method instead of :spawn and :clone?
- Should we cache the result of without_unique_fragments to clone faster?
## Known Issues
- Required fragments are slower than they should be

View File

@@ -1,15 +1,20 @@
require 'develop.samples.relations'
require 'develop.samples.systems' require 'develop.samples.systems'
require 'develop.testing.cancel_tests'
require 'develop.testing.locate_tests'
require 'develop.testing.multi_spawn_tests'
require 'develop.testing.name_tests' require 'develop.testing.name_tests'
require 'develop.testing.pairs_tests'
require 'develop.testing.requires_fragment_tests' require 'develop.testing.requires_fragment_tests'
require 'develop.testing.system_as_query_tests' require 'develop.testing.system_as_query_tests'
require 'develop.untests' require 'develop.benchmarks.clone_bmarks'
require 'develop.benchmarks.common_bmarks'
require 'develop.benchmarks.migration_bmarks'
require 'develop.benchmarks.process_bmarks'
require 'develop.benchmarks.spawn_bmarks'
require 'develop.benchmarks.table_bmarks'
require 'develop.unbench' require 'develop.untests'
require 'develop.usbench'
local basics = require 'develop.basics' local basics = require 'develop.basics'
@@ -25,5 +30,3 @@ print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.requires_fuzz' basics.describe_fuzz 'develop.fuzzing.requires_fuzz'
print '----------------------------------------' print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.unique_fuzz' basics.describe_fuzz 'develop.fuzzing.unique_fuzz'
print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.wildcard_fuzz'

View File

@@ -0,0 +1,166 @@
local evo = require 'evolved'
local basics = require 'develop.basics'
evo.debug_mode(false)
local N = 1000
local F1, F2, F3, F4, F5 = evo.id(5)
local Q1 = evo.builder():include(F1):spawn()
local R1 = evo.builder():require(F1):spawn()
local R3 = evo.builder():require(F1, F2, F3):spawn()
local R5 = evo.builder():require(F1, F2, F3, F4, F5):spawn()
print '----------------------------------------'
basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entities with 1 component', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [F1] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entities with 3 components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entities with 5 components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(Q1)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entities with 1 required component', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [R1] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entities with 3 required components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [R3] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entities with 5 required components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [R5] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(Q1)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Clone Benchmarks: Multi Clone | %d entities with 1 component', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [F1] = true }
multi_clone(N, prefab)
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Multi Clone | %d entities with 3 components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true }
multi_clone(N, prefab)
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Multi Clone | %d entities with 5 components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
multi_clone(N, prefab)
evo.batch_destroy(Q1)
end)
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 prefab = evo.spawn { [R1] = true }
multi_clone(N, prefab)
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Multi Clone | %d entities with 3 required components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [R3] = true }
multi_clone(N, prefab)
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Multi Clone | %d entities with 5 required components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [R5] = true }
multi_clone(N, prefab)
evo.batch_destroy(Q1)
end)

View File

@@ -0,0 +1,340 @@
local evo = require 'evolved'
local basics = require 'develop.basics'
local tiny = require 'develop.3rdparty.tiny'
evo.debug_mode(false)
local N = 1000
print '----------------------------------------'
basics.describe_bench(string.format('Common Benchmarks: Tiny Entity Cycle | %d entities', N),
function(world)
world:update()
end, function()
local world = tiny.world()
for _ = 1, N do
world:addEntity({ a = 0 })
end
local A = tiny.processingSystem()
A.filter = tiny.requireAll('a')
A.process = function(_, e) world:addEntity({ b = e.a }) end
A.postProcess = function(_) world:refresh() end
local B = tiny.processingSystem()
B.filter = tiny.requireAll('b')
B.process = function(_, e) world:removeEntity(e) end
B.postProcess = function(_) world:refresh() end
world:addSystem(A)
world:addSystem(B)
world:refresh()
return world
end)
basics.describe_bench(string.format('Common Benchmarks: Evolved Entity Cycle | %d entities', N),
function(world)
evo.process(world)
end, function()
local world = evo.builder()
:destruction_policy(evo.DESTRUCTION_POLICY_DESTROY_ENTITY)
:spawn()
local a = evo.builder():set(world):spawn()
local b = evo.builder():set(world):spawn()
local query_a = evo.builder():set(world):include(a):spawn()
local query_b = evo.builder():set(world):include(b):spawn()
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.builder()
:set(world):group(world):query(query_a)
:execute(function(chunk, _, entity_count)
local as = chunk:components(a)
local entity_bs = evo.multi_clone(entity_count, prefab_b)
for i = 1, entity_count do evo.set(entity_bs[i], b, as[i]) end
end):spawn()
evo.builder()
:set(world):group(world):query(query_b)
:prologue(function()
evo.batch_destroy(query_b)
end):spawn()
return world
end, function(world)
evo.destroy(world)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Common Benchmarks: Tiny Simple Iteration | %d entities', N),
function(world)
world:update()
end, function()
local world = tiny.world()
for _ = 1, N do
world:addEntity({ a = 0, b = 0 })
world:addEntity({ a = 0, b = 0, c = 0 })
world:addEntity({ a = 0, b = 0, c = 0, d = 0 })
world:addEntity({ a = 0, b = 0, c = 0, e = 0 })
end
local AB = tiny.processingSystem()
AB.filter = tiny.requireAll('a', 'b')
AB.process = function(_, e) e.a, e.b = e.b, e.a end
local CD = tiny.processingSystem()
CD.filter = tiny.requireAll('c', 'd')
CD.process = function(_, e) e.c, e.d = e.d, e.c end
local CE = tiny.processingSystem()
CE.filter = tiny.requireAll('c', 'e')
CE.process = function(_, e) e.c, e.e = e.e, e.c end
world:addSystem(AB)
world:addSystem(CD)
world:addSystem(CE)
world:refresh()
return world
end)
basics.describe_bench(string.format('Common Benchmarks: Evolved Simple Iteration | %d entities', N),
function(world)
evo.process(world)
end, function()
local world = evo.builder()
:destruction_policy(evo.DESTRUCTION_POLICY_DESTROY_ENTITY)
:spawn()
local a = evo.builder():set(world):spawn()
local b = evo.builder():set(world):spawn()
local c = evo.builder():set(world):spawn()
local d = evo.builder():set(world):spawn()
local e = evo.builder():set(world):spawn()
local query_ab = evo.builder():set(world):include(a, b):spawn()
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.builder()
:set(world):group(world):query(query_ab)
:execute(function(chunk, _, entity_count)
local as, bs = chunk:components(a, b)
for i = 1, entity_count do as[i], bs[i] = bs[i], as[i] end
end):spawn()
evo.builder()
:set(world):group(world):query(query_cd)
:execute(function(chunk, _, entity_count)
local cs, ds = chunk:components(c, d)
for i = 1, entity_count do cs[i], ds[i] = ds[i], cs[i] end
end):spawn()
evo.builder()
:set(world):group(world):query(query_ce)
:execute(function(chunk, _, entity_count)
local cs, es = chunk:components(c, e)
for i = 1, entity_count do cs[i], es[i] = es[i], cs[i] end
end):spawn()
return world
end, function(world)
evo.destroy(world)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Common Benchmarks: Tiny Packed Iteration | %d entities', N),
function(world)
world:update()
end, function()
local world = tiny.world()
for _ = 1, N do
world:addEntity({ a = 0, b = 0, c = 0, d = 0, e = 0 })
end
local A = tiny.processingSystem()
A.filter = tiny.requireAll('a')
A.process = function(_, e) e.a = e.a * 2 end
local B = tiny.processingSystem()
B.filter = tiny.requireAll('b')
B.process = function(_, e) e.b = e.b * 2 end
local C = tiny.processingSystem()
C.filter = tiny.requireAll('c')
C.process = function(_, e) e.c = e.c * 2 end
local D = tiny.processingSystem()
D.filter = tiny.requireAll('d')
D.process = function(_, e) e.d = e.d * 2 end
local E = tiny.processingSystem()
E.filter = tiny.requireAll('e')
E.process = function(_, e) e.e = e.e * 2 end
world:addSystem(A)
world:addSystem(B)
world:addSystem(C)
world:addSystem(D)
world:addSystem(E)
world:refresh()
return world
end)
basics.describe_bench(string.format('Common Benchmarks: Evolved Packed Iteration | %d entities', N),
function(world)
evo.process(world)
end, function()
local world = evo.builder()
:destruction_policy(evo.DESTRUCTION_POLICY_DESTROY_ENTITY)
:spawn()
local a = evo.builder():set(world):spawn()
local b = evo.builder():set(world):spawn()
local c = evo.builder():set(world):spawn()
local d = evo.builder():set(world):spawn()
local e = evo.builder():set(world):spawn()
local query_a = evo.builder():set(world):include(a):spawn()
local query_b = evo.builder():set(world):include(b):spawn()
local query_c = evo.builder():set(world):include(c):spawn()
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.builder()
:set(world):group(world):query(query_a)
:execute(function(chunk, _, entity_count)
local as = chunk:components(a)
for i = 1, entity_count do as[i] = as[i] * 2 end
end):spawn()
evo.builder()
:set(world):group(world):query(query_b)
:execute(function(chunk, _, entity_count)
local bs = chunk:components(b)
for i = 1, entity_count do bs[i] = bs[i] * 2 end
end):spawn()
evo.builder()
:set(world):group(world):query(query_c)
:execute(function(chunk, _, entity_count)
local cs = chunk:components(c)
for i = 1, entity_count do cs[i] = cs[i] * 2 end
end):spawn()
evo.builder()
:set(world):group(world):query(query_d)
:execute(function(chunk, _, entity_count)
local ds = chunk:components(d)
for i = 1, entity_count do ds[i] = ds[i] * 2 end
end):spawn()
evo.builder()
:set(world):group(world):query(query_e)
:execute(function(chunk, _, entity_count)
local es = chunk:components(e)
for i = 1, entity_count do es[i] = es[i] * 2 end
end):spawn()
return world
end, function(world)
evo.destroy(world)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Common Benchmarks: Tiny Fragmented Iteration | %d entities', N),
function(world)
world:update()
end, function()
local world = tiny.world()
---@type string[]
local chars = {}
for i = 1, 26 do
chars[i] = string.char(string.byte('a') + i - 1)
end
for i, char in ipairs(chars) do
for _ = 1, N do
world:addEntity({ [char] = i, data = i })
end
end
local Data = tiny.processingSystem()
Data.filter = tiny.requireAll('data')
Data.process = function(_, e) e.data = e.data * 2 end
local Last = tiny.processingSystem()
Last.filter = tiny.requireAll('z')
Last.process = function(_, e) e.z = e.z * 2 end
world:addSystem(Data)
world:addSystem(Last)
world:refresh()
return world
end)
basics.describe_bench(string.format('Common Benchmarks: Evolved Fragmented Iteration | %d entities', N),
function(world)
evo.process(world)
end, function()
local world = evo.builder()
:destruction_policy(evo.DESTRUCTION_POLICY_DESTROY_ENTITY)
:spawn()
local data = evo.spawn { [world] = true }
local chars = evo.multi_spawn(26, { [world] = true })
local query_data = evo.builder():set(world):include(data):spawn()
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 })
end
evo.builder()
:set(world):group(world):query(query_data)
:execute(function(chunk, _, entity_count)
local datas = chunk:components(data)
for i = 1, entity_count do datas[i] = datas[i] * 2 end
end):spawn()
evo.builder()
:set(world):group(world):query(query_z)
:execute(function(chunk, _, entity_count)
local zs = chunk:components(chars[#chars])
for i = 1, entity_count do zs[i] = zs[i] * 2 end
end):spawn()
return world
end, function(world)
evo.destroy(world)
end)

View File

@@ -0,0 +1,104 @@
local evo = require 'evolved'
local basics = require 'develop.basics'
evo.debug_mode(false)
local N = 1000
local F1, F2, F3, F4, F5 = evo.id(5)
local Q1 = evo.builder():include(F1):spawn()
print '----------------------------------------'
basics.describe_bench(string.format('Migration Benchmarks: Defer Set | %d entities with 1 component', N),
function()
local id, set = evo.id, evo.set
evo.defer()
for _ = 1, N do
local e = id()
set(e, F1)
end
evo.commit()
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Migration Benchmarks: Defer Set | %d entities with 3 components', N),
function()
local id, set = evo.id, evo.set
evo.defer()
for _ = 1, N do
local e = id()
set(e, F1)
set(e, F2)
set(e, F3)
end
evo.commit()
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Migration Benchmarks: Defer Set | %d entities with 5 components', N),
function()
local id, set = evo.id, evo.set
evo.defer()
for _ = 1, N do
local e = id()
set(e, F1)
set(e, F2)
set(e, F3)
set(e, F4)
set(e, F5)
end
evo.commit()
evo.batch_destroy(Q1)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Migration Benchmarks: Simple Set | %d entities with 1 component', N),
function()
local id, set = evo.id, evo.set
for _ = 1, N do
local e = id()
set(e, F1)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Migration Benchmarks: Simple Set | %d entities with 3 components', N),
function()
local id, set = evo.id, evo.set
for _ = 1, N do
local e = id()
set(e, F1)
set(e, F2)
set(e, F3)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Migration Benchmarks: Simple Set | %d entities with 5 components', N),
function()
local id, set = evo.id, evo.set
for _ = 1, N do
local e = id()
set(e, F1)
set(e, F2)
set(e, F3)
set(e, F4)
set(e, F5)
end
evo.batch_destroy(Q1)
end)

View File

@@ -0,0 +1,102 @@
local evo = require 'evolved'
local basics = require 'develop.basics'
evo.debug_mode(false)
local N = 10000
print '----------------------------------------'
basics.describe_bench(string.format('Process Benchmarks: Evolved AoS Processing | %d entities', N),
function(w)
evo.process(w)
end,
function()
local wf = evo.builder()
:set(evo.DESTRUCTION_POLICY, evo.DESTRUCTION_POLICY_DESTROY_ENTITY)
:spawn()
local pf = evo.builder():set(wf):spawn()
local vf = evo.builder():set(wf):spawn()
evo.multi_spawn(N, {
[wf] = true,
[pf] = { x = 0, y = 0, z = 0, w = 0 },
[vf] = { x = 0, y = 0, z = 0, w = 0 },
})
evo.builder()
:set(wf)
:set(evo.GROUP, wf)
:set(evo.QUERY, evo.builder():set(wf):include(pf, vf):spawn())
:set(evo.EXECUTE, function(chunk, _, entity_count)
local ps, vs = chunk:components(pf, vf)
for i = 1, entity_count do
local p, s = ps[i], vs[i]
p.x = p.x + s.x
p.y = p.y + s.y
end
end)
:spawn()
return wf
end,
function(w)
evo.destroy(w)
end)
basics.describe_bench(string.format('Process Benchmarks: Evolved SoA Processing | %d entities', N),
function(w)
evo.process(w)
end,
function()
local wf = evo.builder()
:set(evo.DESTRUCTION_POLICY, evo.DESTRUCTION_POLICY_DESTROY_ENTITY)
:spawn()
local pxf = evo.builder():set(wf):spawn()
local pyf = evo.builder():set(wf):spawn()
local pzf = evo.builder():set(wf):spawn()
local pwf = evo.builder():set(wf):spawn()
local vxf = evo.builder():set(wf):spawn()
local vyf = evo.builder():set(wf):spawn()
local vzf = evo.builder():set(wf):spawn()
local vwf = evo.builder():set(wf):spawn()
evo.multi_spawn(N, {
[wf] = true,
[pxf] = 0,
[pyf] = 0,
[pzf] = 0,
[pwf] = 0,
[vxf] = 0,
[vyf] = 0,
[vzf] = 0,
[vwf] = 0,
})
evo.builder()
:set(wf)
:set(evo.GROUP, wf)
:set(evo.QUERY, evo.builder():set(wf):include(pxf, pyf, vxf, vyf):spawn())
:set(evo.EXECUTE, function(chunk, _, entity_count)
local pxs, pys = chunk:components(pxf, pyf)
local vxs, vys = chunk:components(vxf, vyf)
for i = 1, entity_count do
pxs[i] = pxs[i] + vxs[i]
pys[i] = pys[i] + vys[i]
end
end)
:spawn()
return wf
end,
function(w)
evo.destroy(w)
end)

View File

@@ -0,0 +1,236 @@
local evo = require 'evolved'
local basics = require 'develop.basics'
evo.debug_mode(false)
local N = 1000
local F1, F2, F3, F4, F5 = evo.id(5)
local Q1 = evo.builder():include(F1):spawn()
local R1 = evo.builder():require(F1):spawn()
local R3 = evo.builder():require(F1, F2, F3):spawn()
local R5 = evo.builder():require(F1, F2, F3, F4, F5):spawn()
print '----------------------------------------'
basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entities with 1 component', N),
function()
local spawn = evo.spawn
local components = { [F1] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entities with 3 components', N),
function()
local spawn = evo.spawn
local components = { [F1] = true, [F2] = true, [F3] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entities with 5 components', N),
function()
local spawn = evo.spawn
local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(Q1)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entities with 1 required component', N),
function()
local spawn = evo.spawn
local components = { [R1] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entities with 3 required components', N),
function()
local spawn = evo.spawn
local components = { [R3] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entities with 5 required components', N),
function()
local spawn = evo.spawn
local components = { [R5] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(Q1)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entities with 1 component', N),
function()
local builder = evo.builder():set(F1)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entities with 3 components', N),
function()
local builder = evo.builder():set(F1):set(F2):set(F3)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entities with 5 components', N),
function()
local builder = evo.builder():set(F1):set(F2):set(F3):set(F4):set(F5)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(Q1)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entities with 1 required component', N),
function()
local builder = evo.builder():set(R1)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entities with 3 required components', N),
function()
local builder = evo.builder():set(R3)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entities with 5 required components', N),
function()
local builder = evo.builder():set(R5)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(Q1)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities with 1 component', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [F1] = true }
multi_spawn(N, components)
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities with 3 components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [F1] = true, [F2] = true, [F3] = true }
multi_spawn(N, components)
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities with 5 components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
multi_spawn(N, components)
evo.batch_destroy(Q1)
end)
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 components = { [F1] = true }
multi_spawn(N, components)
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities with 3 required components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [R3] = true }
multi_spawn(N, components)
evo.batch_destroy(Q1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities with 5 required components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [R5] = true }
multi_spawn(N, components)
evo.batch_destroy(Q1)
end)

View File

@@ -0,0 +1,136 @@
local evo = require 'evolved'
local basics = require 'develop.basics'
evo.debug_mode(false)
local N = 1000
local F1, F2, F3, F4, F5 = evo.id(5)
print '----------------------------------------'
basics.describe_bench(string.format('Table Benchmarks: Allocate %d tables', N),
function(tables)
for i = 1, N do
local t = {}
tables[i] = t
end
end, function()
return {}
end)
basics.describe_bench(string.format('Table Benchmarks: Allocate and Collect %d tables', N),
function(tables)
for i = 1, N do
local t = {}
tables[i] = t
end
for i = 1, N do
tables[i] = nil
end
collectgarbage('collect')
end, function()
return {}
end)
print '----------------------------------------'
basics.describe_bench(string.format('Table Benchmarks: Allocate %d tables with 1 component / AoS', N),
function(tables)
for i = 1, N do
local e = {}
e[F1] = true
tables[i] = e
end
end, function()
return {}
end)
basics.describe_bench(string.format('Table Benchmarks: Allocate %d tables with 3 components / AoS', N),
function(tables)
for i = 1, N do
local e = {}
e[F1] = true
e[F2] = true
e[F3] = true
tables[i] = e
end
end, function()
return {}
end)
basics.describe_bench(string.format('Table Benchmarks: Allocate %d tables with 5 components / AoS', N),
function(tables)
for i = 1, N do
local e = {}
e[F1] = true
e[F2] = true
e[F3] = true
e[F4] = true
e[F5] = true
tables[i] = e
end
end, function()
return {}
end)
print '----------------------------------------'
basics.describe_bench(string.format('Table Benchmarks: Allocate %d tables with 1 component / SoA', N),
function(tables)
local fs1 = {}
for i = 1, N do
local e = {}
fs1[i] = true
tables[i] = e
end
tables[F1] = fs1
end, function()
return {}
end)
basics.describe_bench(string.format('Table Benchmarks: Allocate %d tables with 3 components / SoA', N),
function(tables)
local fs1 = {}
local fs2 = {}
local fs3 = {}
for i = 1, N do
local e = {}
fs1[i] = true
fs2[i] = true
fs3[i] = true
tables[i] = e
end
tables[F1] = fs1
tables[F2] = fs2
tables[F3] = fs3
end, function()
return {}
end)
basics.describe_bench(string.format('Table Benchmarks: Allocate %d tables with 5 components / SoA', N),
function(tables)
local fs1 = {}
local fs2 = {}
local fs3 = {}
local fs4 = {}
local fs5 = {}
for i = 1, N do
local e = {}
fs1[i] = true
fs2[i] = true
fs3[i] = true
fs4[i] = true
fs5[i] = true
tables[i] = e
end
tables[F1] = fs1
tables[F2] = fs2
tables[F3] = fs3
tables[F4] = fs4
tables[F5] = fs5
end, function()
return {}
end)

View File

@@ -13,35 +13,8 @@ for _ = 1, 1000 do
local initial_secondary = math.random(1, 2 ^ 20 - 1) local initial_secondary = math.random(1, 2 ^ 20 - 1)
local packed_id = evo.pack(initial_primary, initial_secondary) local packed_id = evo.pack(initial_primary, initial_secondary)
local unpacked_primary, unpacked_secondary, unpacked_options = evo.unpack(packed_id) local unpacked_primary, unpacked_secondary = evo.unpack(packed_id)
assert(initial_primary == unpacked_primary) assert(initial_primary == unpacked_primary)
assert(initial_secondary == unpacked_secondary) assert(initial_secondary == unpacked_secondary)
assert(0 == unpacked_options)
end
for _ = 1, 1000 do
local initial_primary = math.random(1, 2 ^ 20 - 1)
local initial_secondary = math.random(1, 2 ^ 20 - 1)
local initial_options = math.random(1, 2 ^ 12 - 1)
local packed_id = evo.pack(initial_primary, initial_secondary, initial_options)
local unpacked_primary, unpacked_secondary, unpacked_options = evo.unpack(packed_id)
assert(initial_primary == unpacked_primary)
assert(initial_secondary == unpacked_secondary)
assert(initial_options == unpacked_options)
end
for _ = 1, 1000 do
local initial_primary = math.random(1, 2 ^ 31 - 1)
local initial_secondary = math.random(1, 2 ^ 31 - 1)
local initial_options = math.random(1, 2 ^ 31 - 1)
local packed_id = evo.pack(initial_primary, initial_secondary, initial_options)
local unpacked_primary, unpacked_secondary, unpacked_options = evo.unpack(packed_id)
assert(initial_primary % 2 ^ 20 == unpacked_primary)
assert(initial_secondary % 2 ^ 20 == unpacked_secondary)
assert(initial_options % 2 ^ 12 == unpacked_options)
end end

View File

@@ -1,254 +0,0 @@
local evo = require 'evolved'
evo.debug_mode(true)
---
---
---
---
---
local __table_unpack = (function()
---@diagnostic disable-next-line: deprecated
return table.unpack or unpack
end)()
---
---
---
---
---
local all_entity_list = {} ---@type evolved.entity[]
local all_fragment_list = {} ---@type evolved.fragment[]
for i = 1, math.random(1, 5) do
local fragment_builder = evo.builder()
if math.random(1, 3) == 1 then
fragment_builder:explicit()
end
if math.random(1, 3) == 1 then
if math.random(1, 2) == 1 then
fragment_builder:destruction_policy(evo.DESTRUCTION_POLICY_DESTROY_ENTITY)
else
fragment_builder:destruction_policy(evo.DESTRUCTION_POLICY_REMOVE_FRAGMENT)
end
end
all_fragment_list[i] = fragment_builder:spawn()
end
for i = 1, math.random(50, 100) do
local entity_builder = evo.builder()
for _ = 0, math.random(0, #all_fragment_list) do
if math.random(1, 2) == 1 then
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
entity_builder:set(fragment)
else
local primary = all_fragment_list[math.random(1, #all_fragment_list)]
local secondary = all_fragment_list[math.random(1, #all_fragment_list)]
entity_builder:set(evo.pair(primary, secondary))
end
end
all_entity_list[i] = entity_builder:spawn()
end
---
---
---
---
---
for _ = 1, math.random(1, 100) do
local query_builder = evo.builder()
local query_include_set = {} ---@type table<evolved.fragment, integer>
local query_include_list = {} ---@type evolved.entity[]
local query_include_count = 0 ---@type integer
local query_exclude_set = {} ---@type table<evolved.fragment, integer>
local query_exclude_list = {} ---@type evolved.entity[]
local query_exclude_count = 0 ---@type integer
for _ = 1, math.random(0, 2) do
if math.random(1, 2) == 1 then
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
query_builder:include(fragment)
if not query_include_set[fragment] then
query_include_count = query_include_count + 1
query_include_set[fragment] = query_include_count
query_include_list[query_include_count] = fragment
end
else
local primary = all_fragment_list[math.random(1, #all_fragment_list)]
local secondary = all_fragment_list[math.random(1, #all_fragment_list)]
if math.random(1, 3) == 1 then
primary = evo.ANY
end
if math.random(1, 3) == 1 then
secondary = evo.ANY
end
local pair = evo.pair(primary, secondary)
query_builder:include(pair)
if not query_include_set[pair] then
query_include_count = query_include_count + 1
query_include_set[pair] = query_include_count
query_include_list[query_include_count] = pair
end
end
end
for _ = 1, math.random(0, 2) do
if math.random(1, 2) == 1 then
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
query_builder:exclude(fragment)
if not query_exclude_set[fragment] then
query_exclude_count = query_exclude_count + 1
query_exclude_set[fragment] = query_exclude_count
query_exclude_list[query_exclude_count] = fragment
end
else
local primary = all_fragment_list[math.random(1, #all_fragment_list)]
local secondary = all_fragment_list[math.random(1, #all_fragment_list)]
if math.random(1, 3) == 1 then
primary = evo.ANY
end
if math.random(1, 3) == 1 then
secondary = evo.ANY
end
local pair = evo.pair(primary, secondary)
query_builder:exclude(pair)
if not query_exclude_set[pair] then
query_exclude_count = query_exclude_count + 1
query_exclude_set[pair] = query_exclude_count
query_exclude_list[query_exclude_count] = pair
end
end
end
local query_entity_set = {} ---@type table<evolved.entity, integer>
local query_entity_count = 0 ---@type integer
do
local query = query_builder:spawn()
for chunk, entity_list, entity_count in evo.execute(query) do
if not chunk:has(evo.INTERNAL) then
for i = 1, entity_count do
local entity = entity_list[i]
assert(not query_entity_set[entity])
query_entity_count = query_entity_count + 1
query_entity_set[entity] = query_entity_count
end
end
end
if query_entity_set[query] then
query_entity_set[query] = nil
query_entity_count = query_entity_count - 1
end
evo.destroy(query)
end
do
local expected_entity_count = 0
for _, entity in ipairs(all_entity_list) do
local is_entity_expected =
not evo.empty(entity) and
evo.has_all(entity, __table_unpack(query_include_list)) and
not evo.has_any(entity, __table_unpack(query_exclude_list))
for fragment in evo.each(entity) do
if evo.has(fragment, evo.EXPLICIT) then
local is_fragment_included =
query_include_set[fragment] ~= nil or
query_include_set[evo.pair(fragment, evo.ANY)] ~= nil
if not is_fragment_included then
is_entity_expected = false
break
end
end
end
if is_entity_expected then
assert(query_entity_set[entity])
expected_entity_count = expected_entity_count + 1
else
assert(not query_entity_set[entity])
end
end
for _, entity in ipairs(all_fragment_list) do
local is_entity_expected =
not evo.empty(entity) and
evo.has_all(entity, __table_unpack(query_include_list)) and
not evo.has_any(entity, __table_unpack(query_exclude_list))
for fragment in evo.each(entity) do
if evo.has(fragment, evo.EXPLICIT) then
is_entity_expected = is_entity_expected and
(query_include_set[fragment] ~= nil) or
(evo.is_pair(fragment) and query_include_set[evo.pair(fragment, evo.ANY)] ~= nil)
end
end
if is_entity_expected then
assert(query_entity_set[entity])
expected_entity_count = expected_entity_count + 1
else
assert(not query_entity_set[entity])
end
end
assert(query_entity_count == expected_entity_count)
end
end
---
---
---
---
---
if math.random(1, 2) == 1 then
evo.collect_garbage()
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()
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()
end
evo.destroy(__table_unpack(all_entity_list))
end
if math.random(1, 2) == 1 then
evo.collect_garbage()
end

View File

@@ -1,79 +0,0 @@
---@diagnostic disable: unused-local
local evo = require 'evolved'
evo.debug_mode(true)
local fragments = {
planet = evo.builder()
:name('planet')
:tag()
:spawn(),
spaceship = evo.builder()
:name('spaceship')
:tag()
:spawn(),
}
local relations = {
docked_to = evo.builder()
:name('docked_to')
:tag()
:spawn(),
}
local planets = {
mars = evo.builder()
:name('Mars')
:set(fragments.planet)
:spawn(),
venus = evo.builder()
:name('Venus')
:set(fragments.planet)
:spawn(),
}
local spaceships = {
falcon = evo.builder()
:name('Millennium Falcon')
:set(fragments.spaceship)
:set(evo.pair(relations.docked_to, planets.mars))
:spawn(),
enterprise = evo.builder()
:name('USS Enterprise')
:set(fragments.spaceship)
:set(evo.pair(relations.docked_to, planets.venus))
:spawn(),
}
local queries = {
all_docked_spaceships = evo.builder()
:include(fragments.spaceship)
:include(evo.pair(relations.docked_to, evo.ANY))
:spawn(),
docked_spaceships_to_mars = evo.builder()
:include(fragments.spaceship)
:include(evo.pair(relations.docked_to, planets.mars))
:spawn(),
}
print '-= | All Docked Spaceships | =-'
for chunk, entity_list, entity_count in evo.execute(queries.all_docked_spaceships) do
for i = 1, entity_count do
local entity = entity_list[i]
local planet = evo.secondary(entity, relations.docked_to)
print(string.format('%s is docked to %s', evo.name(entity), evo.name(planet)))
end
end
print '-= | Docked Spaceships to Mars | =-'
for chunk, entity_list, entity_count in evo.execute(queries.docked_spaceships_to_mars) do
for i = 1, entity_count do
local entity = entity_list[i]
local planet = evo.secondary(entity, relations.docked_to)
print(string.format('%s is docked to %s', evo.name(entity), evo.name(planet)))
end
end

View File

@@ -0,0 +1,105 @@
local evo = require 'evolved'
do
assert(evo.defer())
assert(evo.cancel())
end
do
assert(evo.defer())
assert(not evo.defer())
assert(not evo.cancel())
assert(evo.commit())
end
do
assert(evo.defer())
assert(not evo.defer())
assert(not evo.cancel())
assert(evo.cancel())
end
do
assert(evo.defer())
assert(not evo.defer())
assert(not evo.cancel())
assert(not evo.defer())
assert(not evo.cancel())
assert(evo.commit())
end
do
local e, f = evo.id(2)
assert(evo.defer())
do
evo.set(e, f)
assert(not evo.has(e, f))
end
assert(evo.cancel())
assert(not evo.has(e, f))
end
do
local e, f1, f2 = evo.id(3)
assert(evo.defer())
do
evo.set(e, f1)
assert(not evo.has(e, f1))
assert(not evo.defer())
do
evo.set(e, f2)
assert(not evo.has(e, f2))
end
assert(not evo.cancel())
end
assert(evo.commit())
assert(evo.has(e, f1))
assert(not evo.has(e, f2))
end
do
local e, f1, f2 = evo.id(3)
assert(evo.defer())
do
evo.set(e, f1)
assert(not evo.has(e, f1))
assert(not evo.defer())
do
evo.set(e, f2)
assert(not evo.has(e, f2))
end
assert(not evo.cancel())
end
assert(evo.cancel())
assert(not evo.has(e, f1))
assert(not evo.has(e, f2))
end
do
local e, f1, f2 = evo.id(3)
assert(evo.defer())
do
evo.set(e, f1)
assert(not evo.has(e, f1))
assert(not evo.defer())
do
evo.set(e, f2)
assert(not evo.has(e, f2))
end
assert(not evo.commit())
end
assert(evo.cancel())
assert(not evo.has(e, f1))
assert(not evo.has(e, f2))
end

View File

@@ -0,0 +1,48 @@
local evo = require 'evolved'
do
local e1, e2, f1, f2 = evo.id(4)
do
local chunk, place = evo.locate(e1)
assert(chunk == nil and place == 0)
end
evo.set(e1, f1, 42)
do
local chunk, place = evo.locate(e1)
assert(chunk and chunk == evo.chunk(f1) and place == 1)
assert(chunk:components(f1)[place] == 42)
chunk, place = evo.locate(e2)
assert(chunk == nil and place == 0)
end
evo.set(e1, f2, 'hello')
do
local chunk, place = evo.locate(e1)
assert(chunk and chunk == evo.chunk(f1, f2) and place == 1)
assert(chunk:components(f1)[place] == 42)
assert(chunk:components(f2)[place] == 'hello')
chunk, place = evo.locate(e2)
assert(chunk == nil and place == 0)
end
evo.set(e2, f1, 84)
evo.set(e2, f2, 'world')
do
local chunk, place = evo.locate(e1)
assert(chunk and chunk == evo.chunk(f1, f2) and place == 1)
assert(chunk:components(f1)[place] == 42)
assert(chunk:components(f2)[place] == 'hello')
chunk, place = evo.locate(e2)
assert(chunk and chunk == evo.chunk(f1, f2) and place == 2)
assert(chunk:components(f1)[place] == 84)
assert(chunk:components(f2)[place] == 'world')
end
end

View File

@@ -0,0 +1,308 @@
local evo = require 'evolved'
do
local entity_list
do
entity_list = evo.multi_spawn(0)
assert(entity_list and #entity_list == 0)
entity_list = evo.multi_spawn(0, {})
assert(entity_list and #entity_list == 0)
end
do
entity_list = evo.multi_spawn(-1)
assert(entity_list and #entity_list == 0)
entity_list = evo.multi_spawn(-1, {})
assert(entity_list and #entity_list == 0)
end
do
entity_list = evo.builder():multi_spawn(0)
assert(entity_list and #entity_list == 0)
end
do
entity_list = evo.builder():multi_spawn(-1)
assert(entity_list and #entity_list == 0)
end
end
do
local entity_list
do
entity_list = evo.multi_spawn(1)
assert(entity_list and #entity_list == 1)
assert(entity_list[1] and evo.empty(entity_list[1]))
assert(not entity_list[2])
entity_list = evo.multi_spawn(1, {})
assert(entity_list and #entity_list == 1)
assert(entity_list[1] and evo.empty(entity_list[1]))
assert(not entity_list[2])
end
do
entity_list = evo.multi_spawn(2)
assert(entity_list and #entity_list == 2)
assert(entity_list[1] and evo.empty(entity_list[1]))
assert(entity_list[2] and evo.empty(entity_list[2]))
assert(not entity_list[3])
entity_list = evo.multi_spawn(2, {})
assert(entity_list and #entity_list == 2)
assert(entity_list[1] and evo.empty(entity_list[1]))
assert(entity_list[2] and evo.empty(entity_list[2]))
assert(not entity_list[3])
end
do
entity_list = evo.builder():multi_spawn(1)
assert(entity_list and #entity_list == 1)
assert(entity_list[1] and evo.empty(entity_list[1]))
assert(not entity_list[2])
end
do
entity_list = evo.builder():multi_spawn(2)
assert(entity_list and #entity_list == 2)
assert(entity_list[1] and evo.empty(entity_list[1]))
assert(entity_list[2] and evo.empty(entity_list[2]))
assert(not entity_list[3])
end
end
do
local entity_list
local prefab = evo.id()
do
entity_list = evo.multi_clone(0, prefab)
assert(entity_list and #entity_list == 0)
entity_list = evo.multi_clone(0, prefab, {})
assert(entity_list and #entity_list == 0)
end
do
entity_list = evo.multi_clone(-1, prefab)
assert(entity_list and #entity_list == 0)
entity_list = evo.multi_clone(-1, prefab, {})
assert(entity_list and #entity_list == 0)
end
do
entity_list = evo.builder():multi_clone(0, prefab)
assert(entity_list and #entity_list == 0)
end
do
entity_list = evo.builder():multi_clone(-1, prefab)
assert(entity_list and #entity_list == 0)
end
end
do
local entity_list
local prefab = evo.id()
do
entity_list = evo.multi_clone(1, prefab)
assert(entity_list and #entity_list == 1)
assert(entity_list[1] and evo.empty(entity_list[1]))
assert(not entity_list[2])
entity_list = evo.multi_clone(1, prefab, {})
assert(entity_list and #entity_list == 1)
assert(entity_list[1] and evo.empty(entity_list[1]))
assert(not entity_list[2])
end
do
entity_list = evo.multi_clone(2, prefab)
assert(entity_list and #entity_list == 2)
assert(entity_list[1] and evo.empty(entity_list[1]))
assert(entity_list[2] and evo.empty(entity_list[2]))
assert(not entity_list[3])
entity_list = evo.multi_clone(2, prefab, {})
assert(entity_list and #entity_list == 2)
assert(entity_list[1] and evo.empty(entity_list[1]))
assert(entity_list[2] and evo.empty(entity_list[2]))
assert(not entity_list[3])
end
do
entity_list = evo.builder():multi_clone(1, prefab)
assert(entity_list and #entity_list == 1)
assert(entity_list[1] and evo.empty(entity_list[1]))
assert(not entity_list[2])
end
do
entity_list = evo.builder():multi_clone(2, prefab)
assert(entity_list and #entity_list == 2)
assert(entity_list[1] and evo.empty(entity_list[1]))
assert(entity_list[2] and evo.empty(entity_list[2]))
assert(not entity_list[3])
end
end
do
local f1, f2 = evo.id(2)
do
local entity_list
entity_list = evo.multi_spawn(2, { [f1] = true, [f2] = 123 })
assert(entity_list and #entity_list == 2)
assert(entity_list[1] and evo.get(entity_list[1], f1) == true and evo.get(entity_list[1], f2) == 123)
assert(entity_list[2] and evo.get(entity_list[2], f1) == true and evo.get(entity_list[2], f2) == 123)
entity_list = evo.multi_spawn(2, { [f1] = false, [f2] = 456 })
assert(entity_list and #entity_list == 2)
assert(entity_list[1] and evo.get(entity_list[1], f1) == false and evo.get(entity_list[1], f2) == 456)
assert(entity_list[2] and evo.get(entity_list[2], f1) == false and evo.get(entity_list[2], f2) == 456)
end
do
local prefab = evo.builder():set(f1, true):set(f2, 123):spawn()
local entity_list
entity_list = evo.multi_clone(2, prefab)
assert(entity_list and #entity_list == 2)
assert(entity_list[1] and evo.get(entity_list[1], f1) == true and evo.get(entity_list[1], f2) == 123)
assert(entity_list[2] and evo.get(entity_list[2], f1) == true and evo.get(entity_list[2], f2) == 123)
entity_list = evo.multi_clone(2, prefab, {})
assert(entity_list and #entity_list == 2)
assert(entity_list[1] and evo.get(entity_list[1], f1) == true and evo.get(entity_list[1], f2) == 123)
assert(entity_list[2] and evo.get(entity_list[2], f1) == true and evo.get(entity_list[2], f2) == 123)
entity_list = evo.multi_clone(2, prefab, { [f1] = false, [f2] = 456 })
assert(entity_list and #entity_list == 2)
assert(entity_list[1] and evo.get(entity_list[1], f1) == false and evo.get(entity_list[1], f2) == 456)
assert(entity_list[2] and evo.get(entity_list[2], f1) == false and evo.get(entity_list[2], f2) == 456)
end
end
do
local f1, f2, f3 = evo.id(3)
do
local entity_list1, entity_list2
evo.defer()
do
entity_list1 = evo.multi_spawn(2, { [f1] = 42, [f2] = "hello", [f3] = false })
assert(entity_list1 and #entity_list1 == 2)
assert(entity_list1[1] and evo.empty(entity_list1[1]))
assert(entity_list1[2] and evo.empty(entity_list1[2]))
assert(not entity_list1[3])
entity_list2 = evo.multi_spawn(3, { [f2] = "world", [f3] = true })
assert(entity_list2 and #entity_list2 == 3)
assert(entity_list2[1] and evo.empty(entity_list2[1]))
assert(entity_list2[2] and evo.empty(entity_list2[2]))
assert(entity_list2[3] and evo.empty(entity_list2[3]))
end
evo.commit()
do
assert(entity_list1 and #entity_list1 == 2)
assert(entity_list1[1] and not evo.empty(entity_list1[1]))
assert(entity_list1[2] and not evo.empty(entity_list1[2]))
assert(not entity_list1[3])
assert(
evo.get(entity_list1[1], f1) == 42 and
evo.get(entity_list1[1], f2) == "hello" and
evo.get(entity_list1[1], f3) == false)
assert(
evo.get(entity_list1[2], f1) == 42 and
evo.get(entity_list1[2], f2) == "hello" and
evo.get(entity_list1[2], f3) == false)
assert(entity_list2 and #entity_list2 == 3)
assert(entity_list2[1] and not evo.empty(entity_list2[1]))
assert(entity_list2[2] and not evo.empty(entity_list2[2]))
assert(entity_list2[3] and not evo.empty(entity_list2[3]))
assert(not entity_list2[4])
assert(
evo.get(entity_list2[1], f1) == nil and
evo.get(entity_list2[1], f2) == "world" and
evo.get(entity_list2[1], f3) == true)
assert(
evo.get(entity_list2[2], f1) == nil and
evo.get(entity_list2[2], f2) == "world" and
evo.get(entity_list2[2], f3) == true)
assert(
evo.get(entity_list2[3], f1) == nil and
evo.get(entity_list2[3], f2) == "world" and
evo.get(entity_list2[3], f3) == true)
end
end
end
do
local f1, f2, f3 = evo.id(3)
do
local prefab = evo.builder():set(f1, false):set(f2, 123):spawn()
local entity_list1, entity_list2
evo.defer()
do
entity_list1 = evo.multi_clone(2, prefab)
assert(entity_list1 and #entity_list1 == 2)
assert(entity_list1[1] and evo.empty(entity_list1[1]))
assert(entity_list1[2] and evo.empty(entity_list1[2]))
assert(not entity_list1[3])
entity_list2 = evo.multi_clone(3, prefab, { [f2] = 456, [f3] = "world" })
assert(entity_list2 and #entity_list2 == 3)
assert(entity_list2[1] and evo.empty(entity_list2[1]))
assert(entity_list2[2] and evo.empty(entity_list2[2]))
assert(entity_list2[3] and evo.empty(entity_list2[3]))
end
evo.commit()
do
assert(entity_list1 and #entity_list1 == 2)
assert(entity_list1[1] and not evo.empty(entity_list1[1]))
assert(entity_list1[2] and not evo.empty(entity_list1[2]))
assert(not entity_list1[3])
assert(
evo.get(entity_list1[1], f1) == false and
evo.get(entity_list1[1], f2) == 123 and
evo.get(entity_list1[1], f3) == nil)
assert(
evo.get(entity_list1[2], f1) == false and
evo.get(entity_list1[2], f2) == 123 and
evo.get(entity_list1[2], f3) == nil)
assert(entity_list2 and #entity_list2 == 3)
assert(entity_list2[1] and not evo.empty(entity_list2[1]))
assert(entity_list2[2] and not evo.empty(entity_list2[2]))
assert(entity_list2[3] and not evo.empty(entity_list2[3]))
assert(not entity_list2[4])
assert(
evo.get(entity_list2[1], f1) == false and
evo.get(entity_list2[1], f2) == 456 and
evo.get(entity_list2[1], f3) == "world")
assert(
evo.get(entity_list2[2], f1) == false and
evo.get(entity_list2[2], f2) == 456 and
evo.get(entity_list2[2], f3) == "world")
assert(
evo.get(entity_list2[3], f1) == false and
evo.get(entity_list2[3], f2) == 456 and
evo.get(entity_list2[3], f3) == "world")
end
end
end

View File

@@ -3,8 +3,8 @@ local evo = require 'evolved'
do do
local id = evo.id() local id = evo.id()
local index, version, options = evo.unpack(id) local index, version = evo.unpack(id)
assert(evo.name(id) == string.format('$%d#%d:%d:%d', id, index, version, options)) assert(evo.name(id) == string.format('$%d#%d:%d', id, index, version))
evo.set(id, evo.NAME, 'hello') evo.set(id, evo.NAME, 'hello')
assert(evo.name(id) == 'hello') assert(evo.name(id) == 'hello')
@@ -13,7 +13,7 @@ do
assert(evo.name(id) == 'world') assert(evo.name(id) == 'world')
evo.destroy(id) evo.destroy(id)
assert(evo.name(id) == string.format('$%d#%d:%d:%d', id, index, version, options)) assert(evo.name(id) == string.format('$%d#%d:%d', id, index, version))
end end
do do

File diff suppressed because it is too large Load Diff

View File

@@ -1,860 +0,0 @@
local basics = require 'develop.basics'
basics.unload 'evolved'
local evo = require 'evolved'
local N = 1000
local B = evo.builder()
local F1, F2, F3, F4, F5 = evo.id(5)
local Q1 = evo.builder():include(F1):spawn()
local R1 = evo.builder():require(F1):spawn()
local R2 = evo.builder():require(F1, F2):spawn()
local R3 = evo.builder():require(F1, F2, F3):spawn()
local R4 = evo.builder():require(F1, F2, F3, F4):spawn()
local R5 = evo.builder():require(F1, F2, F3, F4, F5):spawn()
print '----------------------------------------'
basics.describe_bench(string.format('create %d tables', N),
---@param tables table[]
function(tables)
for i = 1, N do
local t = {}
tables[i] = t
end
end, function()
return {}
end)
basics.describe_bench(string.format('create and collect %d tables', N),
---@param tables table[]
function(tables)
for i = 1, N do
local t = {}
tables[i] = t
end
for i = 1, #tables do
tables[i] = nil
end
collectgarbage('collect')
end, function()
return {}
end)
print '----------------------------------------'
basics.describe_bench(string.format('create %d tables with 1 component / AoS', N),
---@param tables table
function(tables)
for i = 1, N do
local e = {}
e[F1] = true
tables[i] = e
end
end, function()
return {}
end)
basics.describe_bench(string.format('create %d tables with 2 component / AoS', N),
---@param tables table
function(tables)
for i = 1, N do
local e = {}
e[F1] = true
e[F2] = true
tables[i] = e
end
end, function()
return {}
end)
basics.describe_bench(string.format('create %d tables with 3 component / AoS', N),
---@param tables table
function(tables)
for i = 1, N do
local e = {}
e[F1] = true
e[F2] = true
e[F3] = true
tables[i] = e
end
end, function()
return {}
end)
basics.describe_bench(string.format('create %d tables with 4 component / AoS', N),
---@param tables table
function(tables)
for i = 1, N do
local e = {}
e[F1] = true
e[F2] = true
e[F3] = true
e[F4] = true
tables[i] = e
end
end, function()
return {}
end)
basics.describe_bench(string.format('create %d tables with 5 component / AoS', N),
---@param tables table
function(tables)
for i = 1, N do
local e = {}
e[F1] = true
e[F2] = true
e[F3] = true
e[F4] = true
e[F5] = true
tables[i] = e
end
end, function()
return {}
end)
print '----------------------------------------'
basics.describe_bench(string.format('create %d tables with 1 component / SoA', N),
---@param tables table
function(tables)
local fs1 = {}
for i = 1, N do
local e = {}
fs1[i] = true
tables[i] = e
end
tables[F1] = fs1
end, function()
return {}
end)
basics.describe_bench(string.format('create %d tables with 2 component / SoA', N),
---@param tables table
function(tables)
local fs1 = {}
local fs2 = {}
for i = 1, N do
local e = {}
fs1[i] = true
fs2[i] = true
tables[i] = e
end
tables[F1] = fs1
tables[F2] = fs2
end, function()
return {}
end)
basics.describe_bench(string.format('create %d tables with 3 component / SoA', N),
---@param tables table
function(tables)
local fs1 = {}
local fs2 = {}
local fs3 = {}
for i = 1, N do
local e = {}
fs1[i] = true
fs2[i] = true
fs3[i] = true
tables[i] = e
end
tables[F1] = fs1
tables[F2] = fs2
tables[F3] = fs3
end, function()
return {}
end)
basics.describe_bench(string.format('create %d tables with 4 component / SoA', N),
---@param tables table
function(tables)
local fs1 = {}
local fs2 = {}
local fs3 = {}
local fs4 = {}
for i = 1, N do
local e = {}
fs1[i] = i
fs2[i] = i
fs3[i] = i
fs4[i] = i
tables[i] = e
end
tables[F1] = fs1
tables[F2] = fs2
tables[F3] = fs3
tables[F4] = fs4
end, function()
return {}
end)
basics.describe_bench(string.format('create %d tables with 5 component / SoA', N),
---@param tables table
function(tables)
local fs1 = {}
local fs2 = {}
local fs3 = {}
local fs4 = {}
local fs5 = {}
for i = 1, N do
local e = {}
fs1[i] = i
fs2[i] = i
fs3[i] = i
fs4[i] = i
fs5[i] = i
tables[i] = e
end
tables[F1] = fs1
tables[F2] = fs2
tables[F3] = fs3
tables[F4] = fs4
tables[F5] = fs5
end, function()
return {}
end)
print '----------------------------------------'
basics.describe_bench(string.format('create and destroy %d entities', N),
---@param entities evolved.id[]
function(entities)
local id = evo.id
local destroy = evo.destroy
for i = 1, N do
local e = id()
entities[i] = e
end
for i = #entities, 1, -1 do
destroy(entities[i])
end
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 1 component', N),
---@param entities evolved.id[]
function(entities)
local id = evo.id
local set = evo.set
for i = 1, N do
local e = id()
set(e, F1)
entities[i] = e
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 2 components', N),
---@param entities evolved.id[]
function(entities)
local id = evo.id
local set = evo.set
for i = 1, N do
local e = id()
set(e, F1)
set(e, F2)
entities[i] = e
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 3 components', N),
---@param entities evolved.id[]
function(entities)
local id = evo.id
local set = evo.set
for i = 1, N do
local e = id()
set(e, F1)
set(e, F2)
set(e, F3)
entities[i] = e
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 4 components', N),
---@param entities evolved.id[]
function(entities)
local id = evo.id
local set = evo.set
for i = 1, N do
local e = id()
set(e, F1)
set(e, F2)
set(e, F3)
set(e, F4)
entities[i] = e
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 5 components', N),
---@param entities evolved.id[]
function(entities)
local id = evo.id
local set = evo.set
for i = 1, N do
local e = id()
set(e, F1)
set(e, F2)
set(e, F3)
set(e, F4)
set(e, F5)
entities[i] = e
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
print '----------------------------------------'
basics.describe_bench(string.format('create and destroy %d entities with 1 components / defer', N),
---@param entities evolved.id[]
function(entities)
local id = evo.id
local set = evo.set
evo.defer()
for i = 1, N do
local e = id()
set(e, F1)
entities[i] = e
end
evo.commit()
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 2 components / defer', N),
---@param entities evolved.id[]
function(entities)
local id = evo.id
local set = evo.set
evo.defer()
for i = 1, N do
local e = id()
set(e, F1)
set(e, F2)
entities[i] = e
end
evo.commit()
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 3 components / defer', N),
---@param entities evolved.id[]
function(entities)
local id = evo.id
local set = evo.set
evo.defer()
for i = 1, N do
local e = id()
set(e, F1)
set(e, F2)
set(e, F3)
entities[i] = e
end
evo.commit()
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 4 components / defer', N),
---@param entities evolved.id[]
function(entities)
local id = evo.id
local set = evo.set
evo.defer()
for i = 1, N do
local e = id()
set(e, F1)
set(e, F2)
set(e, F3)
set(e, F4)
entities[i] = e
end
evo.commit()
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 5 components / defer', N),
---@param entities evolved.id[]
function(entities)
local id = evo.id
local set = evo.set
evo.defer()
for i = 1, N do
local e = id()
set(e, F1)
set(e, F2)
set(e, F3)
set(e, F4)
set(e, F5)
entities[i] = e
end
evo.commit()
evo.batch_destroy(Q1)
end, function()
return {}
end)
print '----------------------------------------'
basics.describe_bench(string.format('create and destroy %d entities with 1 components / builder', N),
---@param entities evolved.id[]
function(entities)
local set = B.set
local spawn = B.spawn
for i = 1, N do
set(B, F1)
entities[i] = spawn(B)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 2 components / builder', N),
---@param entities evolved.id[]
function(entities)
local set = B.set
local spawn = B.spawn
for i = 1, N do
set(B, F1)
set(B, F2)
entities[i] = spawn(B)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 3 components / builder', N),
---@param entities evolved.id[]
function(entities)
local set = B.set
local spawn = B.spawn
for i = 1, N do
set(B, F1)
set(B, F2)
set(B, F3)
entities[i] = spawn(B)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 4 components / builder', N),
---@param entities evolved.id[]
function(entities)
local set = B.set
local spawn = B.spawn
for i = 1, N do
set(B, F1)
set(B, F2)
set(B, F3)
set(B, F4)
entities[i] = spawn(B)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 5 components / builder', N),
---@param entities evolved.id[]
function(entities)
local set = B.set
local spawn = B.spawn
for i = 1, N do
set(B, F1)
set(B, F2)
set(B, F3)
set(B, F4)
set(B, F5)
entities[i] = spawn(B)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
print '----------------------------------------'
basics.describe_bench(string.format('create and destroy %d entities with 1 components / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local components = { [F1] = true }
for i = 1, N do
entities[i] = spawn(components)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 2 components / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local components = { [F1] = true, [F2] = true }
for i = 1, N do
entities[i] = spawn(components)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 3 components / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local components = { [F1] = true, [F2] = true, [F3] = true }
for i = 1, N do
entities[i] = spawn(components)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 4 components / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true }
for i = 1, N do
entities[i] = spawn(components)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 5 components / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
for i = 1, N do
entities[i] = spawn(components)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
print '----------------------------------------'
basics.describe_bench(string.format('create and destroy %d entities with 1 components / clone', N),
---@param entities evolved.id[]
function(entities)
local clone = evo.clone
local prefab = evo.spawn({ [F1] = true })
for i = 1, N do
entities[i] = clone(prefab)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 2 components / clone', N),
---@param entities evolved.id[]
function(entities)
local clone = evo.clone
local prefab = evo.spawn({ [F1] = true, [F2] = true })
for i = 1, N do
entities[i] = clone(prefab)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 3 components / clone', N),
---@param entities evolved.id[]
function(entities)
local clone = evo.clone
local prefab = evo.spawn({ [F1] = true, [F2] = true, [F3] = true })
for i = 1, N do
entities[i] = clone(prefab)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 4 components / clone', N),
---@param entities evolved.id[]
function(entities)
local clone = evo.clone
local prefab = evo.spawn({ [F1] = true, [F2] = true, [F3] = true, [F4] = true })
for i = 1, N do
entities[i] = clone(prefab)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 5 components / clone', N),
---@param entities evolved.id[]
function(entities)
local clone = evo.clone
local prefab = evo.spawn({ [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true })
for i = 1, N do
entities[i] = clone(prefab)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
print '----------------------------------------'
basics.describe_bench(string.format('create and destroy %d entities with 1 requires / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local components = { [R1] = true }
for i = 1, N do
entities[i] = spawn(components)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 2 requires / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local components = { [R2] = true }
for i = 1, N do
entities[i] = spawn(components)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 3 requires / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local components = { [R3] = true }
for i = 1, N do
entities[i] = spawn(components)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 4 requires / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local components = { [R4] = true }
for i = 1, N do
entities[i] = spawn(components)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 5 requires / spawn', N),
---@param entities evolved.id[]
function(entities)
local spawn = evo.spawn
local components = { [R5] = true }
for i = 1, N do
entities[i] = spawn(components)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
print '----------------------------------------'
basics.describe_bench(string.format('create and destroy %d entities with 1 requires / clone', N),
---@param entities evolved.id[]
function(entities)
local clone = evo.clone
local prefab = evo.spawn({ [R1] = true })
for i = 1, N do
entities[i] = clone(prefab)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 2 requires / clone', N),
---@param entities evolved.id[]
function(entities)
local clone = evo.clone
local prefab = evo.spawn({ [R2] = true })
for i = 1, N do
entities[i] = clone(prefab)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 3 requires / clone', N),
---@param entities evolved.id[]
function(entities)
local clone = evo.clone
local prefab = evo.spawn({ [R3] = true })
for i = 1, N do
entities[i] = clone(prefab)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 4 requires / clone', N),
---@param entities evolved.id[]
function(entities)
local clone = evo.clone
local prefab = evo.spawn({ [R4] = true })
for i = 1, N do
entities[i] = clone(prefab)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)
basics.describe_bench(string.format('create and destroy %d entities with 5 requires / clone', N),
---@param entities evolved.id[]
function(entities)
local clone = evo.clone
local prefab = evo.spawn({ [R5] = true })
for i = 1, N do
entities[i] = clone(prefab)
end
evo.batch_destroy(Q1)
end, function()
return {}
end)

View File

@@ -598,29 +598,31 @@ do
evo.set(e2b, f2, 45) evo.set(e2b, f2, 45)
do do
local chunk, entities = evo.chunk(f1) local chunk, entity_list, entity_count = evo.chunk(f1)
assert(entities and entities[1] == e1) assert(entity_list and entity_list[1] == e1)
assert(entity_count and entity_count == 1)
assert(chunk and chunk:components(f1)[1] == 41) assert(chunk and chunk:components(f1)[1] == 41)
end end
do do
local chunk, entities = evo.chunk(f1, f2) local chunk, entity_list, entity_count = evo.chunk(f1, f2)
assert(chunk == evo.chunk(f1, f2)) assert(chunk == evo.chunk(f1, f2))
assert(chunk == evo.chunk(f1, f1, f2)) assert(chunk == evo.chunk(f1, f1, f2))
assert(chunk == evo.chunk(f1, f1, f2, f2)) assert(chunk == evo.chunk(f1, f1, f2, f2))
assert(chunk == evo.chunk(f1, f2, f2, f1)) assert(chunk == evo.chunk(f1, f2, f2, f1))
assert(chunk == evo.chunk(f2, f1)) assert(chunk == evo.chunk(f2, f1))
assert(chunk == evo.chunk(f2, f1, f2, f1)) assert(chunk == evo.chunk(f2, f1, f2, f1))
assert(entities and entities[1] == e2 and entities[2] == e2b) assert(entity_list and entity_list[1] == e2 and entity_list[2] == e2b)
assert(entity_count and entity_count == 2)
assert(chunk and chunk:components(f1)[1] == 42 and chunk:components(f2)[1] == 43) assert(chunk and chunk:components(f1)[1] == 42 and chunk:components(f2)[1] == 43)
assert(chunk and chunk:components(f1)[2] == 44 and chunk:components(f2)[2] == 45) assert(chunk and chunk:components(f1)[2] == 44 and chunk:components(f2)[2] == 45)
end end
do do
local chunk123, entities123 = evo.chunk(f1, f2, f3) local chunk123, entities123, entity123_count = evo.chunk(f1, f2, f3)
local chunk321, entities321 = evo.chunk(f3, f2, f1) local chunk321, entities321, entity321_count = evo.chunk(f3, f2, f1)
assert(chunk123 and #entities123 == 0) assert(chunk123 and #entities123 >= 0 and entity123_count == 0)
assert(chunk321 and #entities321 == 0) assert(chunk321 and #entities321 >= 0 and entity321_count == 0)
assert(chunk123 == chunk321 and entities123 == entities321) assert(chunk123 == chunk321 and entities123 == entities321)
end end
end end
@@ -1523,7 +1525,7 @@ do
do do
last_set_entity = 0 last_set_entity = 0
evo.set(e, f1, 41) evo.set(e, f1, 41)
assert(last_set_entity == e) assert(last_set_entity == 0)
assert(evo.has(e, f1) and not evo.has(e, f2)) assert(evo.has(e, f1) and not evo.has(e, f2))
assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil) assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil)
end end
@@ -1537,13 +1539,13 @@ do
do do
last_set_entity = 0 last_set_entity = 0
evo.set(e, f1, 42) evo.set(e, f1, 42)
assert(last_set_entity == e) assert(last_set_entity == 0)
assert(evo.has(e, f1) and evo.has(e, f2)) assert(evo.has(e, f1) and evo.has(e, f2))
assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil) assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil)
last_set_entity = 0 last_set_entity = 0
evo.set(e, f2, 42) evo.set(e, f2, 42)
assert(last_set_entity == e) assert(last_set_entity == 0)
assert(evo.has(e, f1) and evo.has(e, f2)) assert(evo.has(e, f1) and evo.has(e, f2))
assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil) assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil)
end end
@@ -1557,13 +1559,13 @@ do
do do
last_set_entity = 0 last_set_entity = 0
evo.set(e, f1, 42) evo.set(e, f1, 42)
assert(last_set_entity == e) assert(last_set_entity == 0)
assert(evo.has(e, f1) and evo.has(e, f2) and evo.has(e, f3)) assert(evo.has(e, f1) and evo.has(e, f2) and evo.has(e, f3))
assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil and evo.get(e, f3) == 43) assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil and evo.get(e, f3) == 43)
last_set_entity = 0 last_set_entity = 0
evo.set(e, f2, 42) evo.set(e, f2, 42)
assert(last_set_entity == e) assert(last_set_entity == 0)
assert(evo.has(e, f1) and evo.has(e, f2) and evo.has(e, f3)) assert(evo.has(e, f1) and evo.has(e, f2) and evo.has(e, f3))
assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil and evo.get(e, f3) == 43) assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil and evo.get(e, f3) == 43)
@@ -1608,7 +1610,7 @@ do
last_assign_entity = 0 last_assign_entity = 0
evo.set(e, f1) evo.set(e, f1)
assert(last_assign_entity == e) assert(last_assign_entity == 0)
assert(evo.has(e, f1) and not evo.has(e, f2)) assert(evo.has(e, f1) and not evo.has(e, f2))
assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil) assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil)
end end
@@ -1621,7 +1623,7 @@ do
last_assign_entity = 0 last_assign_entity = 0
evo.set(e, f2, 44) evo.set(e, f2, 44)
assert(last_assign_entity == e) assert(last_assign_entity == 0)
assert(evo.has(e, f1) and evo.has(e, f2)) assert(evo.has(e, f1) and evo.has(e, f2))
assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil) assert(evo.get(e, f1) == nil and evo.get(e, f2) == nil)
end end
@@ -1864,13 +1866,13 @@ do
assert(evo.get(e3, f1) == nil and evo.get(e3, f2) == nil and evo.get(e3, f3) == 43) assert(evo.get(e3, f1) == nil and evo.get(e3, f2) == nil and evo.get(e3, f3) == 43)
do do
local chunk, chunk_entities = evo.chunk(f1, f2, f3) local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f1, f2, f3)
assert(chunk and chunk_entities) assert(chunk and chunk_entity_list and chunk_entity_count == 2)
assert(chunk_entities[1] == e3 and chunk_entities[2] == e1) assert(chunk_entity_list[1] == e3 and chunk_entity_list[2] == e1)
assert(#chunk:components(f1) == 0) assert(#chunk:components(f1) >= 0)
assert(#chunk:components(f2) == 0) assert(#chunk:components(f2) >= 0)
assert(chunk:components(f3)[1] == 43 and chunk:components(f3)[2] == 50) assert(chunk:components(f3)[1] == 43 and chunk:components(f3)[2] == 50)
end end
end end
@@ -1906,22 +1908,22 @@ do
assert(not evo.has(e3, f1) and evo.has(e3, f2) and evo.has(e3, f3)) assert(not evo.has(e3, f1) and evo.has(e3, f2) and evo.has(e3, f3))
do do
local chunk, chunk_entities = evo.chunk(f2) local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f2)
assert(chunk and chunk_entities) assert(chunk and chunk_entity_list and chunk_entity_count == 1)
assert(chunk_entities[1] == e1) assert(chunk_entity_list[1] == e1)
assert(#chunk:components(f1) == 0) assert(#chunk:components(f1) >= 0)
assert(#chunk:components(f2) == 0) assert(#chunk:components(f2) >= 0)
assert(#chunk:components(f3) == 0) assert(#chunk:components(f3) >= 0)
end end
do do
local chunk, chunk_entities = evo.chunk(f2, f3) local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f2, f3)
assert(chunk and chunk_entities) assert(chunk and chunk_entity_list and chunk_entity_count == 1)
assert(chunk_entities[1] == e3) assert(chunk_entity_list[1] == e3)
assert(#chunk:components(f1) == 0) assert(#chunk:components(f1) >= 0)
assert(#chunk:components(f2) == 0) assert(#chunk:components(f2) >= 0)
assert(chunk:components(f3)[1] == 43) assert(chunk:components(f3)[1] == 43)
end end
end end
@@ -1961,13 +1963,13 @@ do
assert(not evo.has(e3, f1) and not evo.has(e3, f2) and not evo.has(e3, f3)) assert(not evo.has(e3, f1) and not evo.has(e3, f2) and not evo.has(e3, f3))
do do
local chunk, chunk_entities = evo.chunk(f1, f2, f3) local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f1, f2, f3)
assert(chunk and chunk_entities) assert(chunk and chunk_entity_list and chunk_entity_count == 0)
assert(next(chunk_entities) == nil) assert(#chunk_entity_list >= 0)
assert(#chunk:components(f1) == 0) assert(#chunk:components(f1) >= 0)
assert(#chunk:components(f2) == 0) assert(#chunk:components(f2) >= 0)
assert(#chunk:components(f3) == 0) assert(#chunk:components(f3) >= 0)
end end
end end
end end
@@ -2006,13 +2008,13 @@ do
assert(not evo.has(e3, f1) and not evo.has(e3, f2) and not evo.has(e3, f3)) assert(not evo.has(e3, f1) and not evo.has(e3, f2) and not evo.has(e3, f3))
do do
local chunk, chunk_entities = evo.chunk(f1, f2, f3) local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f1, f2, f3)
assert(chunk and chunk_entities) assert(chunk and chunk_entity_list and chunk_entity_count == 0)
assert(next(chunk_entities) == nil) assert(#chunk_entity_list >= 0)
assert(#chunk:components(f1) == 0) assert(#chunk:components(f1) >= 0)
assert(#chunk:components(f2) == 0) assert(#chunk:components(f2) >= 0)
assert(#chunk:components(f3) == 0) assert(#chunk:components(f3) >= 0)
end end
end end
end end
@@ -2197,13 +2199,15 @@ do
do do
local iter, state = evo.execute(q) local iter, state = evo.execute(q)
local chunk, entities = iter(state) local chunk, entity_list, entity_count = iter(state)
assert(chunk == evo.chunk(f2)) assert(chunk == evo.chunk(f2))
assert(entities and entities[1] == e2) assert(entity_list and entity_list[1] == e2)
assert(entity_count == 1)
chunk, entities = iter(state) chunk, entity_list, entity_count = iter(state)
assert(not chunk) assert(not chunk)
assert(not entities) assert(not entity_list)
assert(not entity_count)
end end
end end
@@ -2224,9 +2228,9 @@ do
do do
local entity_sum = 0 local entity_sum = 0
for _, entities in evo.execute(q) do for _, entity_list, entity_count in evo.execute(q) do
assert(#entities > 0) assert(entity_count > 0)
for _, e in ipairs(entities) do for _, e in ipairs(entity_list) do
entity_sum = entity_sum + e entity_sum = entity_sum + e
end end
end end
@@ -2253,30 +2257,35 @@ do
do do
local iter, state = evo.execute(q) local iter, state = evo.execute(q)
local chunk, entities = iter(state) local chunk, entity_list, entity_count = iter(state)
assert(chunk == evo.chunk(f1)) assert(chunk == evo.chunk(f1))
assert(entities and entities[1] == e1) assert(entity_list and entity_list[1] == e1)
assert(entity_count == 1)
chunk, entities = iter(state) chunk, entity_list, entity_count = iter(state)
assert(not chunk) assert(not chunk)
assert(not entities) assert(not entity_list)
assert(not entity_count)
end end
evo.set(q, evo.EXCLUDES) evo.set(q, evo.EXCLUDES)
do do
local iter, state = evo.execute(q) local iter, state = evo.execute(q)
local chunk, entities = iter(state) local chunk, entity_list, entity_count = iter(state)
assert(chunk == evo.chunk(f1)) assert(chunk == evo.chunk(f1))
assert(entities and entities[1] == e1) assert(entity_list and entity_list[1] == e1)
assert(entity_count == 1)
chunk, entities = iter(state) chunk, entity_list, entity_count = iter(state)
assert(chunk == evo.chunk(f1, f2)) assert(chunk == evo.chunk(f1, f2))
assert(entities and entities[1] == e2) assert(entity_list and entity_list[1] == e2)
assert(entity_count == 1)
chunk, entities = iter(state) chunk, entity_list, entity_count = iter(state)
assert(not chunk) assert(not chunk)
assert(not entities) assert(not entity_list)
assert(not entity_count)
end end
end end
@@ -2310,9 +2319,10 @@ do
do do
local iter, state = evo.execute(q) local iter, state = evo.execute(q)
local chunk, entities = iter(state) local chunk, entity_list, entity_count = iter(state)
assert(chunk == evo.chunk(f1)) assert(chunk == evo.chunk(f1))
assert(entities and entities[1] == e1) assert(entity_list and entity_list[1] == e1)
assert(entity_count == 1)
end end
end end
@@ -2448,7 +2458,7 @@ do
local function collect_entities(q) local function collect_entities(q)
local entities = {} local entities = {}
for _, es, es_count in evo.execute(q) do for _, es, es_count in evo.execute(q) do
assert(#es == es_count) assert(#es >= es_count)
for _, e in ipairs(es) do for _, e in ipairs(es) do
entities[#entities + 1] = e entities[#entities + 1] = e
end end
@@ -2462,7 +2472,7 @@ do
do do
local entities = collect_entities(q1) local entities = collect_entities(q1)
assert(#entities == 3) assert(#entities >= 3)
assert(entities[1] == e1) assert(entities[1] == e1)
assert(entities[2] == e2) assert(entities[2] == e2)
assert(entities[3] == e3) assert(entities[3] == e3)
@@ -2470,14 +2480,14 @@ do
do do
local entities = collect_entities(q2) local entities = collect_entities(q2)
assert(#entities == 2) assert(#entities >= 2)
assert(entities[1] == e2) assert(entities[1] == e2)
assert(entities[2] == e3) assert(entities[2] == e3)
end end
do do
local entities = collect_entities(q3) local entities = collect_entities(q3)
assert(#entities == 1) assert(#entities >= 1)
assert(entities[1] == e2) assert(entities[1] == e2)
end end
end end
@@ -3246,36 +3256,36 @@ do
local e = evo.spawn({ [f1] = 1, [f2] = 2, [f3] = 3, [f4] = 4, [f5] = 5 }) local e = evo.spawn({ [f1] = 1, [f2] = 2, [f3] = 3, [f4] = 4, [f5] = 5 })
local c, es = evo.chunk(f1, f2, f3, f4, f5) local c, es = evo.chunk(f1, f2, f3, f4, f5)
assert(c and es and #es == 1 and es[1] == e) assert(c and es and #es >= 1 and es[1] == e)
do do
local c1, c2 = c:components(f1, f2) local c1, c2 = c:components(f1, f2)
assert(c1 and #c1 == 1 and c1[1] == 1) assert(c1 and #c1 >= 1 and c1[1] == 1)
assert(c2 and #c2 == 1 and c2[1] == 2) assert(c2 and #c2 >= 1 and c2[1] == 2)
end end
do do
local c1, c2, c3 = c:components(f1, f2, f3) local c1, c2, c3 = c:components(f1, f2, f3)
assert(c1 and #c1 == 1 and c1[1] == 1) assert(c1 and #c1 >= 1 and c1[1] == 1)
assert(c2 and #c2 == 1 and c2[1] == 2) assert(c2 and #c2 >= 1 and c2[1] == 2)
assert(c3 and #c3 == 1 and c3[1] == 3) assert(c3 and #c3 >= 1 and c3[1] == 3)
end end
do do
local c1, c2, c3, c4 = c:components(f1, f2, f3, f4) local c1, c2, c3, c4 = c:components(f1, f2, f3, f4)
assert(c1 and #c1 == 1 and c1[1] == 1) assert(c1 and #c1 >= 1 and c1[1] == 1)
assert(c2 and #c2 == 1 and c2[1] == 2) assert(c2 and #c2 >= 1 and c2[1] == 2)
assert(c3 and #c3 == 1 and c3[1] == 3) assert(c3 and #c3 >= 1 and c3[1] == 3)
assert(c4 and #c4 == 1 and c4[1] == 4) assert(c4 and #c4 >= 1 and c4[1] == 4)
end end
do do
local c1, c2, c3, c4, c5 = c:components(f1, f2, f3, f4, f5) local c1, c2, c3, c4, c5 = c:components(f1, f2, f3, f4, f5)
assert(c1 and #c1 == 1 and c1[1] == 1) assert(c1 and #c1 >= 1 and c1[1] == 1)
assert(c2 and #c2 == 1 and c2[1] == 2) assert(c2 and #c2 >= 1 and c2[1] == 2)
assert(c3 and #c3 == 1 and c3[1] == 3) assert(c3 and #c3 >= 1 and c3[1] == 3)
assert(c4 and #c4 == 1 and c4[1] == 4) assert(c4 and #c4 >= 1 and c4[1] == 4)
assert(c5 and #c5 == 1 and c5[1] == 5) assert(c5 and #c5 >= 1 and c5[1] == 5)
end end
end end
@@ -3722,7 +3732,7 @@ do
do do
local c1, c1_es = evo.chunk(f1) local c1, c1_es = evo.chunk(f1)
assert(c1 and c1_es and #c1_es == 2) assert(c1 and c1_es and #c1_es >= 2)
assert(c1_es[1] == e1a and c1_es[2] == e1b) assert(c1_es[1] == e1a and c1_es[2] == e1b)
assert(c1:components(f1)[1] == 1 and c1:components(f1)[2] == 11) assert(c1:components(f1)[1] == 1 and c1:components(f1)[2] == 11)
end end
@@ -3731,10 +3741,10 @@ do
do do
local c1, c1_es = evo.chunk(f1) local c1, c1_es = evo.chunk(f1)
assert(c1 and c1_es and #c1_es == 0) assert(c1 and c1_es and #c1_es >= 0)
local c12, c12_es = evo.chunk(f1, f2) local c12, c12_es = evo.chunk(f1, f2)
assert(c12 and c12_es and #c12_es == 2) assert(c12 and c12_es and #c12_es >= 2)
assert(c12_es[1] == e1a and c12_es[2] == e1b) assert(c12_es[1] == e1a and c12_es[2] == e1b)
assert(c12:components(f1)[1] == 1 and c12:components(f1)[2] == 11) assert(c12:components(f1)[1] == 1 and c12:components(f1)[2] == 11)
assert(c12:components(f2)[1] == 2 and c12:components(f2)[2] == 2) assert(c12:components(f2)[1] == 2 and c12:components(f2)[2] == 2)
@@ -3745,7 +3755,7 @@ do
do do
local c1, c1_es = evo.chunk(f1) local c1, c1_es = evo.chunk(f1)
assert(c1 and c1_es and #c1_es == 2) assert(c1 and c1_es and #c1_es >= 2)
assert(c1_es[1] == e1c and c1_es[2] == e1d) assert(c1_es[1] == e1c and c1_es[2] == e1d)
assert(c1:components(f1)[1] == 111 and c1:components(f1)[2] == 1111) assert(c1:components(f1)[1] == 111 and c1:components(f1)[2] == 1111)
end end
@@ -3755,10 +3765,10 @@ do
do do
local c1, c1_es = evo.chunk(f1) local c1, c1_es = evo.chunk(f1)
assert(c1 and c1_es and #c1_es == 0) assert(c1 and c1_es and #c1_es >= 0)
local c12, c12_es = evo.chunk(f1, f2) local c12, c12_es = evo.chunk(f1, f2)
assert(c12 and c12_es and #c12_es == 4) assert(c12 and c12_es and #c12_es >= 4)
assert(c12_es[1] == e1a and c12_es[2] == e1b) assert(c12_es[1] == e1a and c12_es[2] == e1b)
assert(c12_es[3] == e1c and c12_es[4] == e1d) assert(c12_es[3] == e1c and c12_es[4] == e1d)
assert(c12:components(f1)[1] == 1 and c12:components(f1)[2] == 11) assert(c12:components(f1)[1] == 1 and c12:components(f1)[2] == 11)
@@ -3778,7 +3788,7 @@ do
do do
local c123, c123_es = evo.chunk(f1, f2, f3) local c123, c123_es = evo.chunk(f1, f2, f3)
assert(c123 and c123_es and #c123_es == 2) assert(c123 and c123_es and #c123_es >= 2)
assert(c123_es[1] == e123a and c123_es[2] == e123b) assert(c123_es[1] == e123a and c123_es[2] == e123b)
assert(c123:components(f1)[1] == 1 and c123:components(f1)[2] == 11) assert(c123:components(f1)[1] == 1 and c123:components(f1)[2] == 11)
assert(c123:components(f2)[1] == 2 and c123:components(f2)[2] == 22) assert(c123:components(f2)[1] == 2 and c123:components(f2)[2] == 22)
@@ -3789,7 +3799,7 @@ do
do do
local c13, c13_es = evo.chunk(f3, f1) local c13, c13_es = evo.chunk(f3, f1)
assert(c13 and c13_es and #c13_es == 2) assert(c13 and c13_es and #c13_es >= 2)
assert(c13_es[1] == e123a and c13_es[2] == e123b) assert(c13_es[1] == e123a and c13_es[2] == e123b)
assert(c13:components(f1)[1] == 1 and c13:components(f1)[2] == 11) assert(c13:components(f1)[1] == 1 and c13:components(f1)[2] == 11)
assert(c13:components(f2)[1] == nil and c13:components(f2)[2] == nil) assert(c13:components(f2)[1] == nil and c13:components(f2)[2] == nil)
@@ -3801,7 +3811,7 @@ do
do do
local c3, c3_es = evo.chunk(f3) local c3, c3_es = evo.chunk(f3)
assert(c3 and c3_es and #c3_es == 2) assert(c3 and c3_es and #c3_es >= 2)
assert(c3_es[1] == e3a and c3_es[2] == e3b) assert(c3_es[1] == e3a and c3_es[2] == e3b)
assert(c3:components(f3)[1] == 3 and c3:components(f3)[2] == 33) assert(c3:components(f3)[1] == 3 and c3:components(f3)[2] == 33)
end end
@@ -3810,7 +3820,7 @@ do
do do
local c3, c3_es = evo.chunk(f3) local c3, c3_es = evo.chunk(f3)
assert(c3 and c3_es and #c3_es == 4) assert(c3 and c3_es and #c3_es >= 4)
assert(c3_es[1] == e3a and c3_es[2] == e3b) assert(c3_es[1] == e3a and c3_es[2] == e3b)
assert(c3_es[3] == e123a and c3_es[4] == e123b) assert(c3_es[3] == e123a and c3_es[4] == e123b)
assert(c3:components(f1)[1] == nil and c3:components(f1)[2] == nil) assert(c3:components(f1)[1] == nil and c3:components(f1)[2] == nil)
@@ -3833,13 +3843,13 @@ do
do do
local c1, c1_es, c1_ec = evo.chunk(f1) local c1, c1_es, c1_ec = evo.chunk(f1)
assert(c1 and c1_es and c1_ec) assert(c1 and c1_es and c1_ec)
assert(c1_ec == 2 and #c1_es == 2 and c1_es[1] == e1a and c1_es[2] == e1b) assert(c1_ec == 2 and #c1_es >= 2 and c1_es[1] == e1a and c1_es[2] == e1b)
end end
do do
local c12, c12_es, c12_ec = evo.chunk(f1, f2) local c12, c12_es, c12_ec = evo.chunk(f1, f2)
assert(c12 and c12_es and c12_ec) assert(c12 and c12_es and c12_ec)
assert(c12_ec == 1 and #c12_es == 1 and c12_es[1] == e12) assert(c12_ec == 1 and #c12_es >= 1 and c12_es[1] == e12)
end end
end end
@@ -3897,14 +3907,14 @@ do
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 2 and c1_ec == 2) assert(c1_es and #c1_es >= 2 and c1_ec == 2)
assert(c1_es[1] == e1a and c1_es[2] == e1b) assert(c1_es[1] == e1a and c1_es[2] == e1b)
local c2_es, c2_ec = c2:entities() local c2_es, c2_ec = c2:entities()
assert(c2_es and #c2_es == 0 and c2_ec == 0) assert(c2_es and #c2_es >= 0 and c2_ec == 0)
local c12_es, c12_ec = c12:entities() local c12_es, c12_ec = c12:entities()
assert(c12_es and #c12_es == 2 and c12_ec == 2) assert(c12_es and #c12_es >= 2 and c12_ec == 2)
assert(c12_es[1] == e12a and c12_es[2] == e12b) assert(c12_es[1] == e12a and c12_es[2] == e12b)
end end
@@ -3915,14 +3925,14 @@ do
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 0 and c1_ec == 0) assert(c1_es and #c1_es >= 0 and c1_ec == 0)
local c2_es, c2_ec = c2:entities() local c2_es, c2_ec = c2:entities()
assert(c2_es and #c2_es == 2 and c2_ec == 2) assert(c2_es and #c2_es >= 2 and c2_ec == 2)
assert(c2_es[1] == e12a and c2_es[2] == e12b) assert(c2_es[1] == e12a and c2_es[2] == e12b)
local c12_es, c12_ec = c12:entities() local c12_es, c12_ec = c12:entities()
assert(c12_es and #c12_es == 2 and c12_ec == 2) assert(c12_es and #c12_es >= 2 and c12_ec == 2)
assert(c12_es[1] == e1a and c12_es[2] == e1b) assert(c12_es[1] == e1a and c12_es[2] == e1b)
end end
end end
@@ -3938,7 +3948,7 @@ do
assert(evo.empty(f2)) assert(evo.empty(f2))
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 0 and c1_ec == 0) assert(c1_es and #c1_es >= 0 and c1_ec == 0)
end end
end end
@@ -3949,7 +3959,7 @@ do
evo.destroy(f1) evo.destroy(f1)
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 0 and c1_ec == 0) assert(c1_es and #c1_es >= 0 and c1_ec == 0)
end end
end end
@@ -3964,26 +3974,26 @@ do
evo.set(f2, f2) evo.set(f2, f2)
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 0 and c1_ec == 0) assert(c1_es and #c1_es >= 0 and c1_ec == 0)
local c2_es, c2_ec = c2:entities() local c2_es, c2_ec = c2:entities()
assert(c2_es and #c2_es == 0 and c2_ec == 0) assert(c2_es and #c2_es >= 0 and c2_ec == 0)
local c12_es, c12_ec = c12:entities() local c12_es, c12_ec = c12:entities()
assert(c12_es and #c12_es == 1 and c12_ec == 1) assert(c12_es and #c12_es >= 1 and c12_ec == 1)
assert(c12_es[1] == f2) assert(c12_es[1] == f2)
end end
evo.destroy(f1) evo.destroy(f1)
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 0 and c1_ec == 0) assert(c1_es and #c1_es >= 0 and c1_ec == 0)
local c2_es, c2_ec = c2:entities() local c2_es, c2_ec = c2:entities()
assert(c2_es and #c2_es == 1 and c2_ec == 1) assert(c2_es and #c2_es >= 1 and c2_ec == 1)
assert(c2_es[1] == f2) assert(c2_es[1] == f2)
local c12_es, c12_ec = c12:entities() local c12_es, c12_ec = c12:entities()
assert(c12_es and #c12_es == 0 and c12_ec == 0) assert(c12_es and #c12_es >= 0 and c12_ec == 0)
end end
end end
@@ -3998,25 +4008,25 @@ do
evo.set(f2, f2) evo.set(f2, f2)
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 0 and c1_ec == 0) assert(c1_es and #c1_es >= 0 and c1_ec == 0)
local c2_es, c2_ec = c2:entities() local c2_es, c2_ec = c2:entities()
assert(c2_es and #c2_es == 0 and c2_ec == 0) assert(c2_es and #c2_es >= 0 and c2_ec == 0)
local c12_es, c12_ec = c12:entities() local c12_es, c12_ec = c12:entities()
assert(c12_es and #c12_es == 1 and c12_ec == 1) assert(c12_es and #c12_es >= 1 and c12_ec == 1)
assert(c12_es[1] == f2) assert(c12_es[1] == f2)
end end
evo.destroy(f1) evo.destroy(f1)
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 0 and c1_ec == 0) assert(c1_es and #c1_es >= 0 and c1_ec == 0)
local c2_es, c2_ec = c2:entities() local c2_es, c2_ec = c2:entities()
assert(c2_es and #c2_es == 0 and c2_ec == 0) assert(c2_es and #c2_es >= 0 and c2_ec == 0)
local c12_es, c12_ec = c12:entities() local c12_es, c12_ec = c12:entities()
assert(c12_es and #c12_es == 0 and c12_ec == 0) assert(c12_es and #c12_es >= 0 and c12_ec == 0)
end end
end end
@@ -4028,20 +4038,20 @@ do
evo.set(f3, f2) evo.set(f3, f2)
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 1 and c1_ec == 1) assert(c1_es and #c1_es >= 1 and c1_ec == 1)
assert(c1_es[1] == f2) assert(c1_es[1] == f2)
local c2_es, c2_ec = c2:entities() local c2_es, c2_ec = c2:entities()
assert(c2_es and #c2_es == 1 and c2_ec == 1) assert(c2_es and #c2_es >= 1 and c2_ec == 1)
assert(c2_es[1] == f3) assert(c2_es[1] == f3)
end end
evo.destroy(f1) evo.destroy(f1)
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 0 and c1_ec == 0) assert(c1_es and #c1_es >= 0 and c1_ec == 0)
local c2_es, c2_ec = c2:entities() local c2_es, c2_ec = c2:entities()
assert(c2_es and #c2_es == 1 and c2_ec == 1) assert(c2_es and #c2_es >= 1 and c2_ec == 1)
assert(c2_es[1] == f3) assert(c2_es[1] == f3)
end end
end end
@@ -4055,20 +4065,20 @@ do
evo.set(f3, f2) evo.set(f3, f2)
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 1 and c1_ec == 1) assert(c1_es and #c1_es >= 1 and c1_ec == 1)
assert(c1_es[1] == f2) assert(c1_es[1] == f2)
local c2_es, c2_ec = c2:entities() local c2_es, c2_ec = c2:entities()
assert(c2_es and #c2_es == 1 and c2_ec == 1) assert(c2_es and #c2_es >= 1 and c2_ec == 1)
assert(c2_es[1] == f3) assert(c2_es[1] == f3)
end end
evo.destroy(f1) evo.destroy(f1)
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 0 and c1_ec == 0) assert(c1_es and #c1_es >= 0 and c1_ec == 0)
local c2_es, c2_ec = c2:entities() local c2_es, c2_ec = c2:entities()
assert(c2_es and #c2_es == 1 and c2_ec == 1) assert(c2_es and #c2_es >= 1 and c2_ec == 1)
assert(c2_es[1] == f3) assert(c2_es[1] == f3)
end end
end end
@@ -4082,20 +4092,20 @@ do
evo.set(f3, f2) evo.set(f3, f2)
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 1 and c1_ec == 1) assert(c1_es and #c1_es >= 1 and c1_ec == 1)
assert(c1_es[1] == f2) assert(c1_es[1] == f2)
local c2_es, c2_ec = c2:entities() local c2_es, c2_ec = c2:entities()
assert(c2_es and #c2_es == 1 and c2_ec == 1) assert(c2_es and #c2_es >= 1 and c2_ec == 1)
assert(c2_es[1] == f3) assert(c2_es[1] == f3)
end end
evo.destroy(f1) evo.destroy(f1)
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 0 and c1_ec == 0) assert(c1_es and #c1_es >= 0 and c1_ec == 0)
local c2_es, c2_ec = c2:entities() local c2_es, c2_ec = c2:entities()
assert(c2_es and #c2_es == 0 and c2_ec == 0) assert(c2_es and #c2_es >= 0 and c2_ec == 0)
end end
end end
@@ -4122,14 +4132,14 @@ do
do do
local c4_es, c4_ec = c4:entities() local c4_es, c4_ec = c4:entities()
assert(c4_es and #c4_es == 3 and c4_ec == 3) assert(c4_es and #c4_es >= 3 and c4_ec == 3)
assert(c4_es[1] == e24 and c4_es[2] == e14 and c4_es[3] == e124) assert(c4_es[1] == e24 and c4_es[2] == e14 and c4_es[3] == e124)
end end
assert(#c14:entities() == 0) assert(#c14:entities() >= 0)
assert(#c24:entities() == 0) assert(#c24:entities() >= 0)
assert(#c124:entities() == 0) assert(#c124:entities() >= 0)
assert(#c234:entities() == 0) assert(#c234:entities() >= 0)
assert(evo.alive(e14) and not evo.empty(e14)) assert(evo.alive(e14) and not evo.empty(e14))
assert(evo.alive(e24) and not evo.empty(e24)) assert(evo.alive(e24) and not evo.empty(e24))
@@ -4159,7 +4169,7 @@ do
assert(remove_count == 1) assert(remove_count == 1)
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 0 and c1_ec == 0) assert(c1_es and #c1_es >= 0 and c1_ec == 0)
end end
end end
@@ -4185,7 +4195,7 @@ do
assert(remove_count == 1) assert(remove_count == 1)
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1_es and #c1_es == 0 and c1_ec == 0) assert(c1_es and #c1_es >= 0 and c1_ec == 0)
end end
end end
@@ -4219,27 +4229,27 @@ do
do do
local c1_es, c1_ec = c1:entities() local c1_es, c1_ec = c1:entities()
assert(c1 and c1_es and c1_ec) assert(c1 and c1_es and c1_ec)
assert(c1_ec == 4 and #c1_es == 4) assert(c1_ec == 4 and #c1_es >= 4)
assert(c1_es[1] == e1a and c1_es[2] == e1b and c1_es[3] == e12a and c1_es[4] == e12b) assert(c1_es[1] == e1a and c1_es[2] == e1b and c1_es[3] == e12a and c1_es[4] == e12b)
end end
do do
local c12_es, c12_ec = c12:entities() local c12_es, c12_ec = c12:entities()
assert(c12 and c12_es and c12_ec) assert(c12 and c12_es and c12_ec)
assert(c12_ec == 0 and #c12_es == 0) assert(c12_ec == 0 and #c12_es >= 0)
end end
do do
local c13_es, c13_ec = c13:entities() local c13_es, c13_ec = c13:entities()
assert(c13 and c13_es and c13_ec) assert(c13 and c13_es and c13_ec)
assert(c13_ec == 2 and #c13_es == 2) assert(c13_ec == 2 and #c13_es >= 2)
assert(c13_es[1] == e123a and c13_es[2] == e123b) assert(c13_es[1] == e123a and c13_es[2] == e123b)
end end
do do
local c123_es, c123_ec = c123:entities() local c123_es, c123_ec = c123:entities()
assert(c123 and c123_es and c123_ec) assert(c123 and c123_es and c123_ec)
assert(c123_ec == 0 and #c123_es == 0) assert(c123_ec == 0 and #c123_es >= 0)
end end
end end
@@ -4291,7 +4301,7 @@ do
do do
local c2, c2_es, c2_ec = evo.chunk(f2) local c2, c2_es, c2_ec = evo.chunk(f2)
assert(c2 and c2_es and c2_ec) assert(c2 and c2_es and c2_ec)
assert(#c2_es == 2 and c2_ec == 2) assert(#c2_es >= 2 and c2_ec == 2)
assert(c2_es[1] == e2a and c2_es[2] == e2b) assert(c2_es[1] == e2a and c2_es[2] == e2b)
end end
end end
@@ -4324,7 +4334,7 @@ do
do do
local c2, c2_es, c2_ec = evo.chunk(f2) local c2, c2_es, c2_ec = evo.chunk(f2)
assert(c2 and c2_es and c2_ec) assert(c2 and c2_es and c2_ec)
assert(#c2_es == 4 and c2_ec == 4) assert(#c2_es >= 4 and c2_ec == 4)
assert(c2_es[1] == e2a and c2_es[2] == e2b and c2_es[3] == e12a and c2_es[4] == e12b) assert(c2_es[1] == e2a and c2_es[2] == e2b and c2_es[3] == e12a and c2_es[4] == e12b)
end end
end end
@@ -4349,10 +4359,10 @@ do
assert(c1 and c23) assert(c1 and c23)
assert(#c1:fragments() == 1) assert(#c1:fragments() >= 1)
assert(c1:fragments()[1] == f1) assert(c1:fragments()[1] == f1)
assert(#c23:fragments() == 2) assert(#c23:fragments() >= 2)
assert(c23:fragments()[1] == f2) assert(c23:fragments()[1] == f2)
assert(c23:fragments()[2] == f3) assert(c23:fragments()[2] == f3)
end end
@@ -4372,20 +4382,23 @@ do
local iter, state = evo.execute(q1) local iter, state = evo.execute(q1)
local chunk, entity_list = iter(state) local chunk, entity_list, entity_count = iter(state)
assert(entity_list and #entity_list == 1) assert(entity_list and #entity_list >= 1)
assert(entity_count and entity_count == 1)
assert(chunk == evo.chunk(f0, f1) and entity_list[1] == e1) assert(chunk == evo.chunk(f0, f1) and entity_list[1] == e1)
chunk, entity_list = iter(state) chunk, entity_list, entity_count = iter(state)
assert(entity_list and #entity_list == 1) assert(entity_list and #entity_list >= 1)
assert(entity_count and entity_count == 1)
assert(chunk == evo.chunk(f0, f1, f2) and entity_list[1] == e12) assert(chunk == evo.chunk(f0, f1, f2) and entity_list[1] == e12)
chunk, entity_list = iter(state) chunk, entity_list, entity_count = iter(state)
assert(entity_list and #entity_list == 1) assert(entity_list and #entity_list >= 1)
assert(entity_count and entity_count == 1)
assert(chunk == evo.chunk(f0, f1, f2, f3) and entity_list[1] == e123) assert(chunk == evo.chunk(f0, f1, f2, f3) and entity_list[1] == e123)
chunk, entity_list = iter(state) chunk, entity_list, entity_count = iter(state)
assert(not chunk and not entity_list) assert(not chunk and not entity_list and not entity_count)
end end
do do
@@ -4393,16 +4406,18 @@ do
local iter, state = evo.execute(q1) local iter, state = evo.execute(q1)
local chunk, entity_list = iter(state) local chunk, entity_list, entity_count = iter(state)
assert(entity_list and #entity_list == 1) assert(entity_list and #entity_list >= 1)
assert(entity_count and entity_count == 1)
assert(chunk == evo.chunk(f0, f1) and entity_list[1] == e1) assert(chunk == evo.chunk(f0, f1) and entity_list[1] == e1)
chunk, entity_list = iter(state) chunk, entity_list, entity_count = iter(state)
assert(entity_list and #entity_list == 1) assert(entity_list and #entity_list >= 1)
assert(entity_count and entity_count == 1)
assert(chunk == evo.chunk(f0, f1, f2) and entity_list[1] == e12) assert(chunk == evo.chunk(f0, f1, f2) and entity_list[1] == e12)
chunk, entity_list = iter(state) chunk, entity_list, entity_count = iter(state)
assert(not chunk and not entity_list) assert(not chunk and not entity_list and not entity_count)
end end
end end
@@ -4435,7 +4450,7 @@ do
for c, es, ec in evo.execute(qe12) do for c, es, ec in evo.execute(qe12) do
assert(ec > 0) assert(ec > 0)
assert(#es == ec) assert(#es >= ec)
assert(c ~= c1 and c ~= c2 and c ~= c12) assert(c ~= c1 and c ~= c2 and c ~= c12)
matched_chunk_count = matched_chunk_count + 1 matched_chunk_count = matched_chunk_count + 1
matched_entity_count = matched_entity_count + ec matched_entity_count = matched_entity_count + ec
@@ -4453,7 +4468,7 @@ do
for _, es, ec in evo.execute(qe12) do for _, es, ec in evo.execute(qe12) do
assert(ec > 0) assert(ec > 0)
assert(#es == ec) assert(#es >= ec)
matched_chunk_count = matched_chunk_count + 1 matched_chunk_count = matched_chunk_count + 1
matched_entity_count = matched_entity_count + ec matched_entity_count = matched_entity_count + ec
end end
@@ -4468,7 +4483,7 @@ do
local iter, state = evo.execute(qe12) local iter, state = evo.execute(qe12)
local chunk, entity_list, entity_count = iter(state) local chunk, entity_list, entity_count = iter(state)
assert(chunk == c12) assert(chunk == c12)
assert(entity_list and #entity_list == 1) assert(entity_list and #entity_list >= 1)
assert(entity_count and entity_count == 1) assert(entity_count and entity_count == 1)
assert(entity_list[1] == e12) assert(entity_list[1] == e12)
end end
@@ -4495,7 +4510,7 @@ do
local old_c1_es, old_c1_ec = old_c1:entities() local old_c1_es, old_c1_ec = old_c1:entities()
assert(old_c1_es and old_c1_ec) assert(old_c1_es and old_c1_ec)
assert(#old_c1_es == 1 and old_c1_ec == 1) assert(#old_c1_es >= 1 and old_c1_ec == 1)
assert(old_c1_es[1] == e1) assert(old_c1_es[1] == e1)
end end
@@ -4507,7 +4522,7 @@ do
local new_c12_es, new_c12_ec = new_c12:entities() local new_c12_es, new_c12_ec = new_c12:entities()
assert(new_c12_es and new_c12_ec) assert(new_c12_es and new_c12_ec)
assert(#new_c12_es == 1 and new_c12_ec == 1) assert(#new_c12_es >= 1 and new_c12_ec == 1)
assert(new_c12_es[1] == e12) assert(new_c12_es[1] == e12)
end end
@@ -6358,3 +6373,79 @@ do
assert(evo.get(e, f) ~= v2_default) assert(evo.get(e, f) ~= v2_default)
end end
end end
do
local f1, f2 = evo.id(2)
local prefab = evo.builder():prefab():set(f1, 11):set(f2, 22):spawn()
do
local entity = evo.clone(prefab)
assert(evo.has(entity, f1) and evo.get(entity, f1) == 11)
assert(evo.has(entity, f2) and evo.get(entity, f2) == 22)
end
evo.set(f2, evo.UNIQUE)
do
local entity = evo.clone(prefab)
assert(evo.has(entity, f1) and evo.get(entity, f1) == 11)
assert(not evo.has(entity, f2) and evo.get(entity, f2) == nil)
end
evo.remove(f2, evo.UNIQUE)
do
local entity = evo.clone(prefab)
assert(evo.has(entity, f1) and evo.get(entity, f1) == 11)
assert(evo.has(entity, f2) and evo.get(entity, f2) == 22)
end
evo.set(f1, evo.UNIQUE)
evo.set(f2, evo.UNIQUE)
do
local entity = evo.clone(prefab)
assert(evo.empty(entity))
end
evo.remove(f1, evo.UNIQUE)
evo.remove(f2, evo.UNIQUE)
do
local entity = evo.clone(prefab)
assert(evo.has(entity, f1) and evo.get(entity, f1) == 11)
assert(evo.has(entity, f2) and evo.get(entity, f2) == 22)
end
end
do
do
local f = evo.id()
local c = evo.chunk(f)
local b = evo.builder():set(f, 42)
evo.collect_garbage()
local e = b:spawn()
assert(evo.locate(e) ~= c)
assert(evo.locate(e) == evo.chunk(f))
end
do
local f = evo.id()
local c = evo.chunk(f)
local b = evo.builder():set(f, 42)
evo.collect_garbage()
local es = b:multi_spawn(5)
for i = 1, 5 do
assert(evo.locate(es[i]) ~= c)
assert(evo.locate(es[i]) == evo.chunk(f))
end
end
end
do
local ff, ft = evo.id(2)
local b = evo.builder():set(ff, false):set(ft, true)
assert(b:has_all() and not b:has_any())
assert(b:has(ff) and b:has(ft) and b:has_all(ff, ft) and b:has_any(ff, ft))
end

View File

@@ -1,374 +0,0 @@
local basics = require 'develop.basics'
basics.unload 'evolved'
local evo = require 'evolved'
local tiny = require 'develop.3rdparty.tiny'
local N = 1000
print '----------------------------------------'
basics.describe_bench(string.format('Tiny Entity Cycle: %d entities', N),
function(world)
world:update(0.016)
end, function()
local world = tiny.world()
for i = 1, N do
world:addEntity({ a = i })
end
local A = tiny.processingSystem()
A.filter = tiny.requireAll('a')
A.process = function(_, e) world:addEntity({ b = e.a }) end
A.postProcess = function(_) world:refresh() end
local B = tiny.processingSystem()
B.filter = tiny.requireAll('b')
B.process = function(_, e) world:removeEntity(e) end
B.postProcess = function(_) world:refresh() end
world:addSystem(A)
world:addSystem(B)
world:refresh()
return world
end)
basics.describe_bench(string.format('Evolved Entity Cycle (Defer): %d entities', N),
function(a, b, A, B)
evo.defer()
do
for chunk, _, entity_count in evo.execute(A) do
local as = chunk:components(a)
for i = 1, entity_count do
evo.set(evo.id(), b, as[i])
end
end
end
evo.commit()
evo.batch_destroy(B)
end, function()
local a, b = evo.id(2)
for i = 1, N do
evo.builder():set(a, i):spawn()
end
local A = evo.builder():include(a):spawn()
local B = evo.builder():include(b):spawn()
return a, b, A, B
end, function(_, _, A, _)
evo.batch_destroy(A)
end)
basics.describe_bench(string.format('Evolved Entity Cycle (Manual): %d entities', N),
function(a, b, A, B)
local to_create = {}
local to_create_count = 0
for chunk, _, entity_count in evo.execute(A) do
local as = chunk:components(a)
for i = 1, entity_count do
to_create_count = to_create_count + 1
to_create[to_create_count] = as[i]
end
end
for i = 1, to_create_count do
local e = evo.id()
evo.set(e, b, to_create[i])
end
evo.batch_destroy(B)
end, function()
local a, b = evo.id(2)
for i = 1, N do
evo.builder():set(a, i):spawn()
end
local A = evo.builder():include(a):spawn()
local B = evo.builder():include(b):spawn()
return a, b, A, B
end, function(_, _, A, _)
evo.batch_destroy(A)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Tiny Simple Iteration: %d entities', N),
function(world)
world:update(0.016)
end, function()
local world = tiny.world()
for i = 1, N do
world:addEntity({ a = i, b = i })
world:addEntity({ a = i, b = i, c = i })
world:addEntity({ a = i, b = i, c = i, d = i })
world:addEntity({ a = i, b = i, c = i, e = i })
end
local AB = tiny.processingSystem()
AB.filter = tiny.requireAll('a', 'b')
AB.process = function(_, e) e.a, e.b = e.b, e.a end
local CD = tiny.processingSystem()
CD.filter = tiny.requireAll('c', 'd')
CD.process = function(_, e) e.c, e.d = e.d, e.c end
local CE = tiny.processingSystem()
CE.filter = tiny.requireAll('c', 'e')
CE.process = function(_, e) e.c, e.e = e.e, e.c end
world:addSystem(AB)
world:addSystem(CD)
world:addSystem(CE)
world:refresh()
return world
end)
basics.describe_bench(string.format('Evolved Simple Iteration: %d entities', N),
---@param a evolved.entity
---@param b evolved.entity
---@param c evolved.entity
---@param d evolved.entity
---@param e evolved.entity
---@param AB evolved.query
---@param CD evolved.query
---@param CE evolved.query
function(a, b, c, d, e, AB, CD, CE)
for chunk, _, entity_count in evo.execute(AB) do
local as, bs = chunk:components(a, b)
for i = 1, entity_count do
as[i], bs[i] = bs[i], as[i]
end
end
for chunk, _, entity_count in evo.execute(CD) do
local cs, ds = chunk:components(c, d)
for i = 1, entity_count do
cs[i], ds[i] = ds[i], cs[i]
end
end
for chunk, _, entity_count in evo.execute(CE) do
local cs, es = chunk:components(c, e)
for i = 1, entity_count do
cs[i], es[i] = es[i], cs[i]
end
end
end, function()
local a, b, c, d, e = evo.id(5)
for i = 1, N do
evo.builder():set(a, i):set(b, i):spawn()
evo.builder():set(a, i):set(b, i):set(c, i):spawn()
evo.builder():set(a, i):set(b, i):set(c, i):set(d, i):spawn()
evo.builder():set(a, i):set(b, i):set(c, i):set(e, i):spawn()
end
local AB = evo.builder():include(a, b):spawn()
local CD = evo.builder():include(c, d):spawn()
local CE = evo.builder():include(c, e):spawn()
return a, b, c, d, e, AB, CD, CE
end, function(_, _, _, _, _, AB, CD, CE)
evo.batch_destroy(AB)
evo.batch_destroy(CD)
evo.batch_destroy(CE)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Tiny Packed Iteration: %d entities', N),
function(world)
world:update(0.016)
end, function()
local world = tiny.world()
for i = 1, N do
world:addEntity({ a = i, b = i, c = i, d = i, e = i })
end
local A = tiny.processingSystem()
A.filter = tiny.requireAll('a')
A.process = function(_, e) e.a = e.a * 2 end
local B = tiny.processingSystem()
B.filter = tiny.requireAll('b')
B.process = function(_, e) e.b = e.b * 2 end
local C = tiny.processingSystem()
C.filter = tiny.requireAll('c')
C.process = function(_, e) e.c = e.c * 2 end
local D = tiny.processingSystem()
D.filter = tiny.requireAll('d')
D.process = function(_, e) e.d = e.d * 2 end
local E = tiny.processingSystem()
E.filter = tiny.requireAll('e')
E.process = function(_, e) e.e = e.e * 2 end
world:addSystem(A)
world:addSystem(B)
world:addSystem(C)
world:addSystem(D)
world:addSystem(E)
world:refresh()
return world
end)
basics.describe_bench(string.format('Evolved Packed Iteration: %d entities', N),
---@param a evolved.entity
---@param b evolved.entity
---@param c evolved.entity
---@param d evolved.entity
---@param e evolved.entity
---@param A evolved.query
---@param B evolved.query
---@param C evolved.query
---@param D evolved.query
---@param E evolved.query
function(a, b, c, d, e, A, B, C, D, E)
for chunk, _, entity_count in evo.execute(A) do
local as = chunk:components(a)
for i = 1, entity_count do
as[i] = as[i] * 2
end
end
for chunk, _, entity_count in evo.execute(B) do
local bs = chunk:components(b)
for i = 1, entity_count do
bs[i] = bs[i] * 2
end
end
for chunk, _, entity_count in evo.execute(C) do
local cs = chunk:components(c)
for i = 1, entity_count do
cs[i] = cs[i] * 2
end
end
for chunk, _, entity_count in evo.execute(D) do
local ds = chunk:components(d)
for i = 1, entity_count do
ds[i] = ds[i] * 2
end
end
for chunk, _, entity_count in evo.execute(E) do
local es = chunk:components(e)
for i = 1, entity_count do
es[i] = es[i] * 2
end
end
end, function()
local a, b, c, d, e = evo.id(5)
for i = 1, N do
evo.builder():set(a, i):set(b, i):set(c, i):set(d, i):set(e, i):spawn()
end
local A = evo.builder():include(a):spawn()
local B = evo.builder():include(b):spawn()
local C = evo.builder():include(c):spawn()
local D = evo.builder():include(d):spawn()
local E = evo.builder():include(e):spawn()
return a, b, c, d, e, A, B, C, D, E
end, function(_, _, _, _, _, A, _, _, _, _)
evo.batch_destroy(A)
end)
print '----------------------------------------'
basics.describe_bench(string.format('Tiny Fragmented Iteration: %d entities', N),
function(world)
world:update(0.016)
end, function()
local world = tiny.world()
---@type string[]
local chars = {}
for i = 1, 26 do
chars[i] = string.char(string.byte('a') + i - 1)
end
for _, char in ipairs(chars) do
for i = 1, N do
world:addEntity({ [char] = i, data = i })
end
end
local Data = tiny.processingSystem()
Data.filter = tiny.requireAll('data')
Data.process = function(_, e) e.data = e.data * 2 end
local Last = tiny.processingSystem()
Last.filter = tiny.requireAll('z')
Last.process = function(_, e) e.z = e.z * 2 end
world:addSystem(Data)
world:addSystem(Last)
world:refresh()
return world
end)
basics.describe_bench(string.format('Evolved Fragmented Iteration: %d entities', N),
---@param data evolved.entity
---@param last evolved.entity
---@param Data evolved.query
---@param Last evolved.query
function(data, last, Data, Last)
for chunk, _, entity_count in evo.execute(Data) do
local ds = chunk:components(data)
for i = 1, entity_count do
ds[i] = ds[i] * 2
end
end
for chunk, _, entity_count in evo.execute(Last) do
local ls = chunk:components(last)
for i = 1, entity_count do
ls[i] = ls[i] * 2
end
end
end, function()
local data = evo.id()
---@type evolved.fragment[]
local chars = {}
for i = 1, 26 do
chars[i] = evo.id()
end
for _, char in ipairs(chars) do
for i = 1, N do
evo.builder():set(char, i):set(data, i):spawn()
end
end
local Data = evo.builder():include(data):spawn()
local Last = evo.builder():include(chars[#chars]):spawn()
return data, chars[#chars], Data, Last
end, function(_, _, Data, _)
evo.batch_destroy(Data)
end)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,34 @@
rockspec_format = "3.0"
package = "evolved.lua"
version = "1.2.0-0"
source = {
url = "git://github.com/BlackMATov/evolved.lua",
tag = "v1.2.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",
}
}

View File

@@ -0,0 +1,34 @@
rockspec_format = "3.0"
package = "evolved.lua"
version = "1.3.0-0"
source = {
url = "git://github.com/BlackMATov/evolved.lua",
tag = "v1.3.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",
}
}