42 Commits

Author SHA1 Message Date
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
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
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
17 changed files with 2413 additions and 4113 deletions

5
.luacov Normal file
View File

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

192
README.md
View File

@@ -95,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
@@ -147,17 +147,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.
```lua
---@param primary integer
---@param secondary integer
---@param options? integer
---@param index integer
---@param version integer
---@return evolved.id id
---@nodiscard
function evolved.pack(primary, secondary, options) end
function evolved.pack(index, version) end
---@param id evolved.id
---@return integer primary
---@return integer secondary
---@return integer options
---@nodiscard
function evolved.unpack(id) end
```
@@ -1049,20 +1047,14 @@ remove_hook :: {entity, fragment, component}
each_state :: implementation-specific
execute_state :: implementation-specific
primaries_state :: implementation-specific
secondaries_state :: implementation-specific
each_iterator :: {each_state? -> fragment?, component?}
execute_iterator :: {execute_state? -> chunk?, entity[]?, integer?}
primaries_iterator :: {primaries_state? -> fragment?, component?}
secondaries_iterator :: {secondaries_state? -> fragment?, component?}
```
### Predefs
```
ANY :: fragment
TAG :: fragment
NAME :: fragment
@@ -1104,17 +1096,17 @@ DESTRUCTION_POLICY_REMOVE_FRAGMENT :: id
id :: integer? -> id...
name :: id... -> string...
pack :: integer, integer, integer? -> id
unpack :: id -> integer, integer, integer
pair :: id, id -> id
unpair :: id -> id, id
pack :: integer, integer -> id
unpack :: id -> integer, integer
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
@@ -1143,15 +1135,6 @@ batch_destroy :: query... -> ()
each :: entity -> {each_state? -> fragment?, component?}, each_state?
execute :: query -> {execute_state? -> chunk?, entity[]?, integer?}, execute_state?
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
process :: system... -> ()
debug_mode :: boolean -> ()
@@ -1183,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
@@ -1234,6 +1220,16 @@ builder_mt:destruction_policy :: id -> builder
# Changelog
## vX.X.X
- Nothing yet, stay tuned!
## 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
@@ -1247,8 +1243,6 @@ builder_mt:destruction_policy :: id -> builder
## Predefs
### `evolved.ANY`
### `evolved.TAG`
### `evolved.NAME`
@@ -1320,12 +1314,11 @@ function evolved.name(...) end
### `evolved.pack`
```lua
---@param primary integer
---@param secondary integer
---@param options? integer
---@param index integer
---@param version integer
---@return evolved.id id
---@nodiscard
function evolved.pack(primary, secondary, options) end
function evolved.pack(index, version) end
```
### `evolved.unpack`
@@ -1334,31 +1327,10 @@ function evolved.pack(primary, secondary, options) end
---@param id evolved.id
---@return integer primary
---@return integer secondary
---@return integer options
---@nodiscard
function evolved.unpack(id) end
```
### `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.defer`
```lua
@@ -1377,19 +1349,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
@@ -1586,74 +1577,6 @@ function evolved.debug_mode(yesno) end
function evolved.collect_garbage() end
```
## Relations
### `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
### Chunk
@@ -1753,18 +1676,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

View File

@@ -5,12 +5,14 @@
- 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.
- Should we make one builder:build method instead of :spawn and :clone?
- Add multi-spawn to the builder to spawn multiple entities at once.
- Add a function to shrink storages to free unused memory.
- Should we cache the result of without_unique_fragments to clone faster?
- observers and events
- add INDEX fragment trait
- use compact prefix-tree for chunks
- optional ffi component storages
- add EXCLUSIVE fragment trait
## 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,13 +1,16 @@
require 'develop.example'
require 'develop.untests'
require 'develop.samples.relations'
require 'develop.samples.systems'
require 'develop.testing.multi_spawn_tests'
require 'develop.testing.name_tests'
require 'develop.testing.pairs_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.benchmarks.process_bmarks'
require 'develop.untests'
require 'develop.unbench'
require 'develop.usbench'
@@ -25,5 +28,3 @@ print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.requires_fuzz'
print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.unique_fuzz'
print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.wildcard_fuzz'

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

@@ -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

@@ -13,35 +13,8 @@ for _ = 1, 1000 do
local initial_secondary = math.random(1, 2 ^ 20 - 1)
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_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

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,64 +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():explicit():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,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
local id = evo.id()
local index, version, options = evo.unpack(id)
assert(evo.name(id) == string.format('$%d#%d:%d:%d', id, index, version, options))
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')
@@ -13,7 +13,7 @@ do
assert(evo.name(id) == 'world')
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
do

File diff suppressed because it is too large Load Diff

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

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",
}
}