86 Commits

Author SHA1 Message Date
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
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
BlackMATov
66aec17052 little naming fixes 2025-08-20 02:15:12 +07:00
BlackMATov
91edfa9da9 move example to samples/systems 2025-08-19 05:59:41 +07:00
BlackMATov
9b796b2a8d reduce pair function calls 2025-08-19 04:14:23 +07:00
BlackMATov
dcc5190466 evolved.is_pair/is_wildcard functions 2025-08-19 02:50:12 +07:00
BlackMATov
9e74ddf9c3 mark INTERNAL trait as unique and explicit 2025-08-18 19:45:46 +07:00
BlackMATov
26de93405e find smallest minor chunks for wildcard execute 2025-08-18 19:43:30 +07:00
BlackMATov
be64359177 update roadmap 2025-08-18 05:26:49 +07:00
BlackMATov
3b411cce25 manual param validation, remove some cases 2025-08-18 03:52:53 +07:00
BlackMATov
4a2088e833 wildcard queries and wildcard fuzz test 2025-08-17 21:53:22 +07:00
BlackMATov
e9084f818b alive/empty/has/get function work only with primary fragment in pairs now 2025-08-17 21:45:15 +07:00
BlackMATov
0e6f23d30b rnd gc for fuzz tests 2025-08-15 23:48:05 +07:00
BlackMATov
3f7ab3cf4d additional major/minor chunks for all chunks with pairs 2025-08-15 23:47:09 +07:00
BlackMATov
bd337cefe1 store pair indices in chunk instead full fragments 2025-08-12 06:16:17 +07:00
BlackMATov
2ed3be7a4a unload evolved before fuzz/bench 2025-08-09 02:36:07 +07:00
BlackMATov
a8fda4a22a add min fuzz/bench iters and time 2025-08-07 04:06:42 +07:00
BlackMATov
3e4b0d02c1 store pair majors/minors in main chunk storages 2025-08-05 05:47:14 +07:00
BlackMATov
676aae4402 update chunk flags for pair major chunks 2025-08-03 03:56:51 +07:00
BlackMATov
35c6592418 required fragments work with pairs by primary fragment 2025-08-01 06:46:43 +07:00
BlackMATov
dbca453bbb alive/empty/has/get function work with a primary fragment of pairs 2025-08-01 06:00:29 +07:00
BlackMATov
025a9d4d8c more pair checks 2025-07-30 02:11:08 +07:00
BlackMATov
b6e4bfe608 remove wildcard-set 2025-07-21 22:09:51 +07:00
BlackMATov
90e7bb25ef mark all internal fragments 2025-07-12 00:40:26 +07:00
BlackMATov
d6b16df401 chunk purging with pairs 2025-07-11 22:36:56 +07:00
BlackMATov
d86c85d522 clear pair chunks when pair fragments are destroyed 2025-07-11 18:44:01 +07:00
BlackMATov
f7e4dfb30c remove wildcard get tests 2025-07-08 06:19:18 +07:00
BlackMATov
f4671e5a64 wildcard set 2025-07-08 06:05:14 +07:00
BlackMATov
6603399ee6 evolved.each function documentation 2025-07-07 14:17:11 +07:00
BlackMATov
d91b087c76 style fixes 2025-07-07 13:53:54 +07:00
BlackMATov
041777eb23 update readme 2025-07-07 12:46:17 +07:00
BlackMATov
b8e0345e02 primary/secondary pair iterators 2025-07-07 05:33:45 +07:00
BlackMATov
aa3717d290 update roadmap 2025-07-05 20:04:23 +07:00
BlackMATov
83e09183a2 alive/empty/has for new ids/pairs 2025-07-05 20:04:15 +07:00
BlackMATov
837302c533 chunk_has_all/any for new ids/pairs 2025-07-05 01:43:39 +07:00
BlackMATov
27b134e6c0 new pair flags in chunks, with/without_xxx functions for new ids and pairs 2025-07-04 23:43:46 +07:00
BlackMATov
1c89e3853c new way to pack identifiers and pairs 2025-07-02 00:35:33 +07:00
BlackMATov
5eb8902d5a new evolved.name function 2025-06-30 23:21:46 +07:00
BlackMATov
b5d8ced4c8 universal pack/unpack functions with optional flags 2025-06-20 20:06:42 +07:00
BlackMATov
d24ec1ac8e make the without_fragment function set slightly faster 2025-06-19 08:30:14 +07:00
BlackMATov
8d7435064d additional debug checks for pair/unpair 2025-06-18 22:08:29 +07:00
BlackMATov
3291ad7479 simplify alive function set for now 2025-06-18 21:56:47 +07:00
BlackMATov
71cfdff3b7 proof of concept chunk_without for pair wildcards 2025-06-18 03:09:51 +07:00
BlackMATov
04b36f901b skip paired fragments while gathering required fragments 2025-06-18 01:50:29 +07:00
BlackMATov
063acc778b more effective has function set for pair wildcards 2025-06-18 01:27:45 +07:00
BlackMATov
78ad8bd53e new assoc list helper functions 2025-06-17 23:34:27 +07:00
BlackMATov
14055fbadf set/remove/clear/destroy for pairs 2025-06-16 21:56:22 +07:00
BlackMATov
697a041832 has/get function set for pairs 2025-06-16 21:36:20 +07:00
BlackMATov
9a2a62ec89 empty function set for pairs 2025-06-16 21:31:41 +07:00
BlackMATov
4f33796b97 has function set for pairs 2025-06-16 21:15:52 +07:00
BlackMATov
1e9005e468 alive function set for pairs 2025-06-15 07:19:21 +07:00
BlackMATov
c7402cbb05 simplify validation functions 2025-06-15 07:17:39 +07:00
BlackMATov
5375c0bdea dummy ANY predefined fragment 2025-06-15 07:11:39 +07:00
BlackMATov
44d2572530 basic pairs construction 2025-06-15 07:09:36 +07:00
BlackMATov
56a5fb8265 disable gc for fuzz tests 2025-06-09 19:50:49 +07:00
BlackMATov
21aae4ae86 update ROADMAP 2025-06-09 18:57:07 +07:00
BlackMATov
be22c2c85b update README 2025-06-09 07:37:32 +07:00
19 changed files with 2830 additions and 1230 deletions

5
.luacov Normal file
View File

@@ -0,0 +1,5 @@
modules = {
['evolved'] = 'evolved.lua'
}
reporter = 'html'
reportfile = 'luacov.report.html'

123
README.md
View File

@@ -35,6 +35,7 @@
- [Spawning Entities](#spawning-entities)
- [Entity Builders](#entity-builders)
- [Access Operations](#access-operations)
- [Iterating Over Fragments](#iterating-over-fragments)
- [Modifying Operations](#modifying-operations)
- [Debug Mode](#debug-mode)
- [Queries](#queries)
@@ -94,7 +95,7 @@ luarocks install evolved.lua
## Quick Start
To get started with `evolved.lua`, read the [Overview](#overview) section to understand the basic concepts and how to use the library. After that, check the [Example](develop/example.lua), which demonstrates complex usage of the library. Finally, refer to the [Cheat Sheet](#cheat-sheet) for a quick reference of all the functions and classes provided by the library.
To get started with `evolved.lua`, read the [Overview](#overview) section to understand the basic concepts and how to use the library. After that, check the [Samples](develop/samples), which demonstrate complex usage of the library. Finally, refer to the [Cheat Sheet](#cheat-sheet) for a quick reference of all the functions and classes provided by the library.
## Overview
@@ -149,11 +150,13 @@ Sometimes (for debugging purposes, for example), it is necessary to extract the
---@param index integer
---@param version integer
---@return evolved.id id
---@nodiscard
function evolved.pack(index, version) end
---@param id evolved.id
---@return integer index
---@return integer version
---@return integer primary
---@return integer secondary
---@nodiscard
function evolved.unpack(id) end
```
@@ -405,7 +408,7 @@ evolved.set(enemy1, stamina, 42)
#### Entity Builders
Another way to avoid structural changes when spawning entities is to use the [`evolved.builder`](#evolvedbuilder) fluid interface. The [`evolved.builder`](#evolvedbuilder) function returns a builder object that allows you to spawn entities with a specific set of fragments and components without the necessity of setting them one by one with structural changes for each change.
Another way to avoid structural changes when spawning entities is to use the [`evolved.builder`](#evolvedbuilder) fluent interface. The [`evolved.builder`](#evolvedbuilder) function returns a builder object that allows you to spawn entities with a specific set of fragments and components without the necessity of setting them one by one with structural changes for each change.
```lua
local evolved = require 'evolved'
@@ -447,6 +450,35 @@ The [`evolved.alive`](#evolvedalive) function checks whether an entity is alive.
All of these functions can be safely called on non-alive entities and non-alive fragments. Also, they do not cause any structural changes, because they do not modify anything.
### Iterating Over Fragments
Sometimes, you may need to iterate over all fragments attached to an entity. You can use the [`evolved.each`](#evolvedeach) function for this purpose.
```lua
local evolved = require 'evolved'
local health = evolved.builder()
:name('health')
:spawn()
local stamina = evolved.builder()
:name('stamina')
:spawn()
local player = evolved.builder()
:set(health, 100)
:set(stamina, 50)
:spawn()
for fragment, component in evolved.each(player) do
print(string.format('Fragment (%s) has value %d',
evolved.name(fragment), component))
end
```
> [!NOTE]
> [Structural changes](#structural-changes) are not allowed during iteration. If you want to spawn new entities or insert/remove fragments while iterating, defer these operations until the iteration is complete. See the [Deferred Operations](#deferred-operations) section for more details.
### Modifying Operations
The library provides a classic set of functions for modifying entities. These functions are used to insert, override, and remove fragments from entities.
@@ -1028,6 +1060,7 @@ NAME :: fragment
UNIQUE :: fragment
EXPLICIT :: fragment
INTERNAL :: fragment
DEFAULT :: fragment
DUPLICATE :: fragment
@@ -1061,6 +1094,7 @@ DESTRUCTION_POLICY_REMOVE_FRAGMENT :: id
```
id :: integer? -> id...
name :: id... -> string...
pack :: integer, integer -> id
unpack :: id -> integer, integer
@@ -1069,7 +1103,10 @@ defer :: boolean
commit :: boolean
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_all :: entity... -> boolean
@@ -1129,7 +1166,10 @@ chunk_mt:components :: fragment... -> storage...
builder :: builder
builder_mt:spawn :: entity
builder_mt:multi_spawn :: integer -> entity[]
builder_mt:clone :: entity -> entity
builder_mt:multi_clone :: integer, entity -> entity[]
builder_mt:has :: fragment -> boolean
builder_mt:has_all :: fragment... -> boolean
@@ -1146,6 +1186,7 @@ builder_mt:name :: string -> builder
builder_mt:unique :: builder
builder_mt:explicit :: builder
builder_mt:internal :: builder
builder_mt:default :: component -> builder
builder_mt:duplicate :: {component -> component} -> builder
@@ -1179,6 +1220,12 @@ builder_mt:destruction_policy :: id -> builder
# Changelog
## 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
@@ -1200,6 +1247,8 @@ builder_mt:destruction_policy :: id -> builder
### `evolved.EXPLICIT`
### `evolved.INTERNAL`
### `evolved.DEFAULT`
### `evolved.DUPLICATE`
@@ -1249,6 +1298,15 @@ builder_mt:destruction_policy :: id -> builder
function evolved.id(count) end
```
### `evolved.name`
```lua
---@param ... evolved.id ids
---@return string... names
---@nodiscard
function evolved.name(...) end
```
### `evolved.pack`
```lua
@@ -1263,8 +1321,8 @@ function evolved.pack(index, version) end
```lua
---@param id evolved.id
---@return integer index
---@return integer version
---@return integer primary
---@return integer secondary
---@nodiscard
function evolved.unpack(id) end
```
@@ -1287,19 +1345,38 @@ function evolved.commit() end
```lua
---@param components? table<evolved.fragment, evolved.component>
---@return evolved.entity
---@return evolved.entity entity
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`
```lua
---@param prefab evolved.entity
---@param components? table<evolved.fragment, evolved.component>
---@return evolved.entity
---@return evolved.entity entity
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`
```lua
@@ -1595,18 +1672,35 @@ function evolved.builder() end
#### `evolved.builder_mt:spawn`
```lua
---@return evolved.entity
---@return evolved.entity entity
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`
```lua
---@param prefab evolved.entity
---@return evolved.entity
---@return evolved.entity entity
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`
```lua
@@ -1696,6 +1790,13 @@ function evolved.builder_mt:unique() end
function evolved.builder_mt:explicit() end
```
#### `evolved.builder_mt:internal`
```lua
---@return evolved.builder builder
function evolved.builder_mt:internal() end
```
#### `evolved.builder_mt:default`
```lua

View File

@@ -2,10 +2,17 @@
## Backlog
## After first release
- cached queries
- 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.
- Add a function to shrink storages to free unused memory.
- observers and events
- add INDEX fragment trait
- use compact prefix-tree for chunks
- optional ffi component storages
## Thoughts
- 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 cache the result of without_unique_fragments to clone faster?

View File

@@ -1,9 +1,15 @@
require 'develop.example'
require 'develop.untests'
require 'develop.samples.systems'
require 'develop.testing.multi_spawn_tests'
require 'develop.testing.name_tests'
require 'develop.testing.requires_fragment_tests'
require 'develop.testing.system_as_query_tests'
require 'develop.benchmarks.multi_clone_bmarks'
require 'develop.benchmarks.multi_spawn_bmarks'
require 'develop.untests'
require 'develop.unbench'
require 'develop.usbench'

View File

@@ -1,5 +1,13 @@
local basics = {}
local MIN_FUZZ_SECS = 0.5
local MIN_BENCH_SECS = 0.1
local MIN_WARMUP_SECS = 0.1
local MIN_FUZZ_ITERS = 100
local MIN_BENCH_ITERS = 100
local MIN_WARMUP_ITERS = 100
local __table_pack = (function()
---@diagnostic disable-next-line: deprecated
return table.pack or function(...)
@@ -23,8 +31,13 @@ end
---@param modname string
function basics.describe_fuzz(modname)
basics.unload('evolved')
print(string.format('| %s ... |', modname))
collectgarbage('collect')
collectgarbage('stop')
do
local iters = 0
@@ -36,7 +49,7 @@ function basics.describe_fuzz(modname)
iters = iters + 1
basics.unload(modname)
require(modname)
until os.clock() - start_s > 0.5
until iters >= MIN_FUZZ_ITERS and os.clock() - start_s >= MIN_FUZZ_SECS
end)
local finish_s = os.clock()
@@ -52,6 +65,9 @@ function basics.describe_fuzz(modname)
print('|-- FUZZ FAIL: ' .. result)
end
end
collectgarbage('restart')
collectgarbage('collect')
end
---@param name string
@@ -59,17 +75,22 @@ end
---@param init? fun(): ...
---@param fini? fun(...): ...
function basics.describe_bench(name, loop, init, fini)
basics.unload('evolved')
print(string.format('| %s ... |', name))
local state = init and __table_pack(init()) or {}
do
local iters = 0
local warmup_s = os.clock()
local success, result = pcall(function()
repeat
iters = iters + 1
loop(__table_unpack(state))
until os.clock() - warmup_s > 0.1
until iters >= MIN_WARMUP_ITERS and os.clock() - warmup_s > MIN_WARMUP_SECS
end)
if not success then
@@ -91,7 +112,7 @@ function basics.describe_bench(name, loop, init, fini)
repeat
iters = iters + 1
loop(__table_unpack(state))
until os.clock() - start_s > 0.1
until iters >= MIN_BENCH_ITERS and os.clock() - start_s > MIN_BENCH_SECS
end)
local finish_s = os.clock()

View File

@@ -0,0 +1,59 @@
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('Multi 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('Multi 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)
basics.describe_bench(string.format('Multi 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('Multi 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)

View File

@@ -0,0 +1,59 @@
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('Multi 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('Multi 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)
basics.describe_bench(string.format('Multi 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('Multi 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)

View File

@@ -117,5 +117,12 @@ end
---
---
if math.random(1, 2) == 1 then
evo.collect_garbage()
end
evo.destroy(__table_unpack(all_entity_list))
evo.collect_garbage()
if math.random(1, 2) == 1 then
evo.collect_garbage()
end

View File

@@ -123,5 +123,12 @@ end
---
---
if math.random(1, 2) == 1 then
evo.collect_garbage()
end
evo.destroy(__table_unpack(all_entity_list))
evo.collect_garbage()
if math.random(1, 2) == 1 then
evo.collect_garbage()
end

View File

@@ -77,5 +77,12 @@ end
---
---
if math.random(1, 2) == 1 then
evo.collect_garbage()
end
evo.destroy(__table_unpack(all_entity_list))
evo.collect_garbage()
if math.random(1, 2) == 1 then
evo.collect_garbage()
end

View File

@@ -9,12 +9,12 @@ evo.debug_mode(true)
---
for _ = 1, 1000 do
local initial_index = math.random(1, 0xFFFFF)
local initial_version = math.random(1, 0xFFFFF)
local initial_primary = math.random(1, 2 ^ 20 - 1)
local initial_secondary = math.random(1, 2 ^ 20 - 1)
local packed_id = evo.pack(initial_index, initial_version)
local unpacked_index, unpacked_version = evo.unpack(packed_id)
local packed_id = evo.pack(initial_primary, initial_secondary)
local unpacked_primary, unpacked_secondary = evo.unpack(packed_id)
assert(initial_index == unpacked_index)
assert(initial_version == unpacked_version)
assert(initial_primary == unpacked_primary)
assert(initial_secondary == unpacked_secondary)
end

View File

@@ -108,6 +108,24 @@ end
---
---
evo.destroy(__table_unpack(all_entity_list))
evo.destroy(__table_unpack(all_fragment_list))
evo.collect_garbage()
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

@@ -63,5 +63,12 @@ end
---
---
if math.random(1, 2) == 1 then
evo.collect_garbage()
end
evo.destroy(__table_unpack(all_entity_list))
evo.collect_garbage()
if math.random(1, 2) == 1 then
evo.collect_garbage()
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

@@ -0,0 +1,43 @@
local evo = require 'evolved'
do
local id = evo.id()
local index, version = evo.unpack(id)
assert(evo.name(id) == string.format('$%d#%d:%d', id, index, version))
evo.set(id, evo.NAME, 'hello')
assert(evo.name(id) == 'hello')
evo.set(id, evo.NAME, 'world')
assert(evo.name(id) == 'world')
evo.destroy(id)
assert(evo.name(id) == string.format('$%d#%d:%d', id, index, version))
end
do
local id1, id2, id3, id4, id5 = evo.id(5)
evo.set(id1, evo.NAME, 'id1')
evo.set(id2, evo.NAME, 'id2')
evo.set(id3, evo.NAME, 'id3')
evo.set(id4, evo.NAME, 'id4')
evo.set(id5, evo.NAME, 'id5')
do
local id1_n, id3_n, id5_n = evo.name(id1, id3, id5)
assert(id1_n == 'id1')
assert(id3_n == 'id3')
assert(id5_n == 'id5')
end
do
local id1_n, id2_n, id3_n, id4_n, id5_n = evo.name(id1, id2, id3, id4, id5)
assert(id1_n == 'id1')
assert(id2_n == 'id2')
assert(id3_n == 'id3')
assert(id4_n == 'id4')
assert(id5_n == 'id5')
end
end

View File

@@ -598,29 +598,31 @@ do
evo.set(e2b, f2, 45)
do
local chunk, entities = evo.chunk(f1)
assert(entities and entities[1] == e1)
local chunk, entity_list, entity_count = evo.chunk(f1)
assert(entity_list and entity_list[1] == e1)
assert(entity_count and entity_count == 1)
assert(chunk and chunk:components(f1)[1] == 41)
end
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, f1, f2))
assert(chunk == evo.chunk(f1, f1, f2, f2))
assert(chunk == evo.chunk(f1, f2, f2, f1))
assert(chunk == evo.chunk(f2, f1))
assert(chunk == evo.chunk(f2, f1, f2, f1))
assert(entities and entities[1] == e2 and entities[2] == e2b)
assert(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)[2] == 44 and chunk:components(f2)[2] == 45)
end
do
local chunk123, entities123 = evo.chunk(f1, f2, f3)
local chunk321, entities321 = evo.chunk(f3, f2, f1)
assert(chunk123 and #entities123 == 0)
assert(chunk321 and #entities321 == 0)
local chunk123, entities123, entity123_count = evo.chunk(f1, f2, f3)
local chunk321, entities321, entity321_count = evo.chunk(f3, f2, f1)
assert(chunk123 and #entities123 >= 0 and entity123_count == 0)
assert(chunk321 and #entities321 >= 0 and entity321_count == 0)
assert(chunk123 == chunk321 and entities123 == entities321)
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)
do
local chunk, chunk_entities = evo.chunk(f1, f2, f3)
assert(chunk and chunk_entities)
local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f1, f2, f3)
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(f2) == 0)
assert(#chunk:components(f1) >= 0)
assert(#chunk:components(f2) >= 0)
assert(chunk:components(f3)[1] == 43 and chunk:components(f3)[2] == 50)
end
end
@@ -1906,22 +1908,22 @@ do
assert(not evo.has(e3, f1) and evo.has(e3, f2) and evo.has(e3, f3))
do
local chunk, chunk_entities = evo.chunk(f2)
assert(chunk and chunk_entities)
local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f2)
assert(chunk and chunk_entity_list and chunk_entity_count == 1)
assert(chunk_entities[1] == e1)
assert(#chunk:components(f1) == 0)
assert(#chunk:components(f2) == 0)
assert(#chunk:components(f3) == 0)
assert(chunk_entity_list[1] == e1)
assert(#chunk:components(f1) >= 0)
assert(#chunk:components(f2) >= 0)
assert(#chunk:components(f3) >= 0)
end
do
local chunk, chunk_entities = evo.chunk(f2, f3)
assert(chunk and chunk_entities)
local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f2, f3)
assert(chunk and chunk_entity_list and chunk_entity_count == 1)
assert(chunk_entities[1] == e3)
assert(#chunk:components(f1) == 0)
assert(#chunk:components(f2) == 0)
assert(chunk_entity_list[1] == e3)
assert(#chunk:components(f1) >= 0)
assert(#chunk:components(f2) >= 0)
assert(chunk:components(f3)[1] == 43)
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))
do
local chunk, chunk_entities = evo.chunk(f1, f2, f3)
assert(chunk and chunk_entities)
local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f1, f2, f3)
assert(chunk and chunk_entity_list and chunk_entity_count == 0)
assert(next(chunk_entities) == nil)
assert(#chunk:components(f1) == 0)
assert(#chunk:components(f2) == 0)
assert(#chunk:components(f3) == 0)
assert(#chunk_entity_list >= 0)
assert(#chunk:components(f1) >= 0)
assert(#chunk:components(f2) >= 0)
assert(#chunk:components(f3) >= 0)
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))
do
local chunk, chunk_entities = evo.chunk(f1, f2, f3)
assert(chunk and chunk_entities)
local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f1, f2, f3)
assert(chunk and chunk_entity_list and chunk_entity_count == 0)
assert(next(chunk_entities) == nil)
assert(#chunk:components(f1) == 0)
assert(#chunk:components(f2) == 0)
assert(#chunk:components(f3) == 0)
assert(#chunk_entity_list >= 0)
assert(#chunk:components(f1) >= 0)
assert(#chunk:components(f2) >= 0)
assert(#chunk:components(f3) >= 0)
end
end
end
@@ -2197,13 +2199,15 @@ do
do
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(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 entities)
assert(not entity_list)
assert(not entity_count)
end
end
@@ -2224,9 +2228,9 @@ do
do
local entity_sum = 0
for _, entities in evo.execute(q) do
assert(#entities > 0)
for _, e in ipairs(entities) do
for _, entity_list, entity_count in evo.execute(q) do
assert(entity_count > 0)
for _, e in ipairs(entity_list) do
entity_sum = entity_sum + e
end
end
@@ -2253,30 +2257,35 @@ do
do
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(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 entities)
assert(not entity_list)
assert(not entity_count)
end
evo.set(q, evo.EXCLUDES)
do
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(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(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 entities)
assert(not entity_list)
assert(not entity_count)
end
end
@@ -2310,9 +2319,10 @@ do
do
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(entities and entities[1] == e1)
assert(entity_list and entity_list[1] == e1)
assert(entity_count == 1)
end
end
@@ -2448,7 +2458,7 @@ do
local function collect_entities(q)
local entities = {}
for _, es, es_count in evo.execute(q) do
assert(#es == es_count)
assert(#es >= es_count)
for _, e in ipairs(es) do
entities[#entities + 1] = e
end
@@ -2462,7 +2472,7 @@ do
do
local entities = collect_entities(q1)
assert(#entities == 3)
assert(#entities >= 3)
assert(entities[1] == e1)
assert(entities[2] == e2)
assert(entities[3] == e3)
@@ -2470,14 +2480,14 @@ do
do
local entities = collect_entities(q2)
assert(#entities == 2)
assert(#entities >= 2)
assert(entities[1] == e2)
assert(entities[2] == e3)
end
do
local entities = collect_entities(q3)
assert(#entities == 1)
assert(#entities >= 1)
assert(entities[1] == e2)
end
end
@@ -3246,36 +3256,36 @@ do
local e = evo.spawn({ [f1] = 1, [f2] = 2, [f3] = 3, [f4] = 4, [f5] = 5 })
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
local c1, c2 = c:components(f1, f2)
assert(c1 and #c1 == 1 and c1[1] == 1)
assert(c2 and #c2 == 1 and c2[1] == 2)
assert(c1 and #c1 >= 1 and c1[1] == 1)
assert(c2 and #c2 >= 1 and c2[1] == 2)
end
do
local c1, c2, c3 = c:components(f1, f2, f3)
assert(c1 and #c1 == 1 and c1[1] == 1)
assert(c2 and #c2 == 1 and c2[1] == 2)
assert(c3 and #c3 == 1 and c3[1] == 3)
assert(c1 and #c1 >= 1 and c1[1] == 1)
assert(c2 and #c2 >= 1 and c2[1] == 2)
assert(c3 and #c3 >= 1 and c3[1] == 3)
end
do
local c1, c2, c3, c4 = c:components(f1, f2, f3, f4)
assert(c1 and #c1 == 1 and c1[1] == 1)
assert(c2 and #c2 == 1 and c2[1] == 2)
assert(c3 and #c3 == 1 and c3[1] == 3)
assert(c4 and #c4 == 1 and c4[1] == 4)
assert(c1 and #c1 >= 1 and c1[1] == 1)
assert(c2 and #c2 >= 1 and c2[1] == 2)
assert(c3 and #c3 >= 1 and c3[1] == 3)
assert(c4 and #c4 >= 1 and c4[1] == 4)
end
do
local c1, c2, c3, c4, c5 = c:components(f1, f2, f3, f4, f5)
assert(c1 and #c1 == 1 and c1[1] == 1)
assert(c2 and #c2 == 1 and c2[1] == 2)
assert(c3 and #c3 == 1 and c3[1] == 3)
assert(c4 and #c4 == 1 and c4[1] == 4)
assert(c5 and #c5 == 1 and c5[1] == 5)
assert(c1 and #c1 >= 1 and c1[1] == 1)
assert(c2 and #c2 >= 1 and c2[1] == 2)
assert(c3 and #c3 >= 1 and c3[1] == 3)
assert(c4 and #c4 >= 1 and c4[1] == 4)
assert(c5 and #c5 >= 1 and c5[1] == 5)
end
end
@@ -3722,7 +3732,7 @@ do
do
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:components(f1)[1] == 1 and c1:components(f1)[2] == 11)
end
@@ -3731,10 +3741,10 @@ do
do
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)
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:components(f1)[1] == 1 and c12:components(f1)[2] == 11)
assert(c12:components(f2)[1] == 2 and c12:components(f2)[2] == 2)
@@ -3745,7 +3755,7 @@ do
do
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:components(f1)[1] == 111 and c1:components(f1)[2] == 1111)
end
@@ -3755,10 +3765,10 @@ do
do
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)
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[3] == e1c and c12_es[4] == e1d)
assert(c12:components(f1)[1] == 1 and c12:components(f1)[2] == 11)
@@ -3778,7 +3788,7 @@ do
do
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:components(f1)[1] == 1 and c123:components(f1)[2] == 11)
assert(c123:components(f2)[1] == 2 and c123:components(f2)[2] == 22)
@@ -3789,7 +3799,7 @@ do
do
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:components(f1)[1] == 1 and c13:components(f1)[2] == 11)
assert(c13:components(f2)[1] == nil and c13:components(f2)[2] == nil)
@@ -3801,7 +3811,7 @@ do
do
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:components(f3)[1] == 3 and c3:components(f3)[2] == 33)
end
@@ -3810,7 +3820,7 @@ do
do
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[3] == e123a and c3_es[4] == e123b)
assert(c3:components(f1)[1] == nil and c3:components(f1)[2] == nil)
@@ -3833,13 +3843,13 @@ do
do
local c1, c1_es, c1_ec = evo.chunk(f1)
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
do
local c12, c12_es, c12_ec = evo.chunk(f1, f2)
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
@@ -3897,14 +3907,14 @@ do
do
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)
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()
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)
end
@@ -3915,14 +3925,14 @@ do
do
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()
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)
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)
end
end
@@ -3938,7 +3948,7 @@ do
assert(evo.empty(f2))
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
@@ -3949,7 +3959,7 @@ do
evo.destroy(f1)
do
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
@@ -3964,26 +3974,26 @@ do
evo.set(f2, f2)
do
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()
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()
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)
end
evo.destroy(f1)
do
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()
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)
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
@@ -3998,25 +4008,25 @@ do
evo.set(f2, f2)
do
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()
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()
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)
end
evo.destroy(f1)
do
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()
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()
assert(c12_es and #c12_es == 0 and c12_ec == 0)
assert(c12_es and #c12_es >= 0 and c12_ec == 0)
end
end
@@ -4028,20 +4038,20 @@ do
evo.set(f3, f2)
do
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)
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)
end
evo.destroy(f1)
do
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()
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)
end
end
@@ -4055,20 +4065,20 @@ do
evo.set(f3, f2)
do
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)
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)
end
evo.destroy(f1)
do
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()
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)
end
end
@@ -4082,20 +4092,20 @@ do
evo.set(f3, f2)
do
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)
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)
end
evo.destroy(f1)
do
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()
assert(c2_es and #c2_es == 0 and c2_ec == 0)
assert(c2_es and #c2_es >= 0 and c2_ec == 0)
end
end
@@ -4122,14 +4132,14 @@ do
do
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)
end
assert(#c14:entities() == 0)
assert(#c24:entities() == 0)
assert(#c124:entities() == 0)
assert(#c234:entities() == 0)
assert(#c14:entities() >= 0)
assert(#c24:entities() >= 0)
assert(#c124:entities() >= 0)
assert(#c234:entities() >= 0)
assert(evo.alive(e14) and not evo.empty(e14))
assert(evo.alive(e24) and not evo.empty(e24))
@@ -4159,7 +4169,7 @@ do
assert(remove_count == 1)
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
@@ -4185,7 +4195,7 @@ do
assert(remove_count == 1)
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
@@ -4219,27 +4229,27 @@ do
do
local c1_es, c1_ec = c1:entities()
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)
end
do
local c12_es, c12_ec = c12:entities()
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
do
local c13_es, c13_ec = c13:entities()
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)
end
do
local c123_es, c123_ec = c123:entities()
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
@@ -4291,7 +4301,7 @@ do
do
local c2, c2_es, c2_ec = evo.chunk(f2)
assert(c2 and c2_es and c2_ec)
assert(#c2_es == 2 and c2_ec == 2)
assert(#c2_es >= 2 and c2_ec == 2)
assert(c2_es[1] == e2a and c2_es[2] == e2b)
end
end
@@ -4324,7 +4334,7 @@ do
do
local c2, c2_es, c2_ec = evo.chunk(f2)
assert(c2 and c2_es and c2_ec)
assert(#c2_es == 4 and c2_ec == 4)
assert(#c2_es >= 4 and c2_ec == 4)
assert(c2_es[1] == e2a and c2_es[2] == e2b and c2_es[3] == e12a and c2_es[4] == e12b)
end
end
@@ -4349,10 +4359,10 @@ do
assert(c1 and c23)
assert(#c1:fragments() == 1)
assert(#c1:fragments() >= 1)
assert(c1:fragments()[1] == f1)
assert(#c23:fragments() == 2)
assert(#c23:fragments() >= 2)
assert(c23:fragments()[1] == f2)
assert(c23:fragments()[2] == f3)
end
@@ -4372,20 +4382,23 @@ do
local iter, state = evo.execute(q1)
local chunk, entity_list = iter(state)
assert(entity_list and #entity_list == 1)
local chunk, entity_list, entity_count = iter(state)
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)
chunk, entity_list = iter(state)
assert(entity_list and #entity_list == 1)
chunk, entity_list, entity_count = iter(state)
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)
chunk, entity_list = iter(state)
assert(entity_list and #entity_list == 1)
chunk, entity_list, entity_count = iter(state)
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)
chunk, entity_list = iter(state)
assert(not chunk and not entity_list)
chunk, entity_list, entity_count = iter(state)
assert(not chunk and not entity_list and not entity_count)
end
do
@@ -4393,16 +4406,18 @@ do
local iter, state = evo.execute(q1)
local chunk, entity_list = iter(state)
assert(entity_list and #entity_list == 1)
local chunk, entity_list, entity_count = iter(state)
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)
chunk, entity_list = iter(state)
assert(entity_list and #entity_list == 1)
chunk, entity_list, entity_count = iter(state)
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)
chunk, entity_list = iter(state)
assert(not chunk and not entity_list)
chunk, entity_list, entity_count = iter(state)
assert(not chunk and not entity_list and not entity_count)
end
end
@@ -4435,7 +4450,7 @@ do
for c, es, ec in evo.execute(qe12) do
assert(ec > 0)
assert(#es == ec)
assert(#es >= ec)
assert(c ~= c1 and c ~= c2 and c ~= c12)
matched_chunk_count = matched_chunk_count + 1
matched_entity_count = matched_entity_count + ec
@@ -4453,7 +4468,7 @@ do
for _, es, ec in evo.execute(qe12) do
assert(ec > 0)
assert(#es == ec)
assert(#es >= ec)
matched_chunk_count = matched_chunk_count + 1
matched_entity_count = matched_entity_count + ec
end
@@ -4468,7 +4483,7 @@ do
local iter, state = evo.execute(qe12)
local chunk, entity_list, entity_count = iter(state)
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_list[1] == e12)
end
@@ -4495,7 +4510,7 @@ do
local old_c1_es, old_c1_ec = old_c1:entities()
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)
end
@@ -4507,7 +4522,7 @@ do
local new_c12_es, new_c12_ec = new_c12:entities()
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)
end
@@ -6325,3 +6340,36 @@ do
assert(not chunk and not entity_list and not entity_count)
end
end
do
local function v2(x, y) return { x = x or 0, y = y or 0 } end
local function v2_clone(v) return { x = v.x, y = v.y } end
local v2_default = v2(1, 2)
do
local f = evo.builder():default(v2_default):spawn()
local b = evo.builder()
b:set(f)
evo.remove(f, evo.DEFAULT)
local e = b:spawn()
assert(evo.has(e, f) and evo.get(e, f).x == 1 and evo.get(e, f).y == 2)
assert(evo.get(e, f) == v2_default)
end
do
local f = evo.builder():default(v2_default):duplicate(v2_clone):spawn()
local b = evo.builder()
b:set(f)
evo.remove(f, evo.DEFAULT, evo.DUPLICATE)
local e = b:spawn()
assert(evo.has(e, f) and evo.get(e, f).x == 1 and evo.get(e, f).y == 2)
assert(evo.get(e, f) ~= v2_default)
end
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",
}
}