172 Commits
v1.0.0 ... dev

Author SHA1 Message Date
BlackMATov
5895c6ee8f v1.5.0 2025-11-24 13:45:55 +07:00
BlackMATov
1c02ba5468 little love2d example 2025-11-24 13:35:34 +07:00
BlackMATov
760b477564 update changelog 2025-11-21 06:31:42 +07:00
BlackMATov
fc910881bd cache defaults/duplicates per chunk, use it for spawn/clone ops 2025-11-21 05:37:14 +07:00
BlackMATov
71a7c84a67 add spawn/clone with defaults bmarks 2025-11-20 16:19:13 +07:00
BlackMATov
582a09a6db additional spawn/clone tests 2025-11-20 05:00:52 +07:00
BlackMATov
de73881f63 improve performance of the clone operations 2025-11-19 08:51:26 +07:00
BlackMATov
55e444ca63 improve performance of the spawn operations 2025-11-19 02:23:48 +07:00
BlackMATov
e499c701ef add defer clone bmarks 2025-11-12 23:44:34 +07:00
BlackMATov
789f167bf4 add defer spawn bmarks 2025-11-12 16:47:38 +07:00
BlackMATov
00367ce07e Merge branch 'feature/teal' into dev 2025-11-08 01:34:29 +07:00
BlackMATov
07902eb184 teal definitions cleanup 2025-11-07 23:26:45 +07:00
ecdbfe660f Merge pull request #30 from p0sel0k/main 2025-11-07 16:03:22 +07:00
p0sel0k
cfd68767cf fix: set and batch_set component argument should be optional 2025-11-04 21:57:00 +03:00
p0sel0k
f1ba9ab909 fix: replace number type with integer; EachState\ExecuteState records 2025-11-04 18:56:02 +03:00
BlackMATov
77ff3e77db readme: internal fragments
https://github.com/BlackMATov/evolved.lua/issues/28
2025-11-04 21:00:22 +07:00
p0sel0k
825eba5328 fix: remove teal types for internal usage 2025-11-04 10:06:01 +03:00
p0sel0k
67002503ed fix: removed IComponent and added generics for functions and hooks that take Component as a single argument 2025-11-03 11:57:18 +03:00
p0sel0k
1bb0089e9f fix: functions arguments naming 2025-11-02 21:21:25 +03:00
p0sel0k
dc642f5294 fix: fixes after review 2025-11-02 21:12:26 +03:00
p0sel0k
a81a8646e9 fix: wrong file name 2025-10-29 19:29:56 +03:00
p0sel0k
aa6d2c1c48 feat: add Teal language definitions 2025-10-29 19:24:07 +03:00
BlackMATov
5fe48de890 little speed up of exclude-only queries 2025-10-29 22:57:58 +07:00
0d7adcb5fd Merge pull request #27 from BlackMATov/dev
Dev
2025-10-20 16:16:39 +07:00
BlackMATov
f48f1bb290 v1.4.0 2025-10-20 16:11:03 +07:00
BlackMATov
6f1a85165f more tests 2025-10-16 06:22:30 +07:00
BlackMATov
bd87e593e9 root directory cleanup 2025-10-14 17:50:51 +07:00
BlackMATov
0eac310fd5 style fixes 2025-10-12 23:35:28 +07:00
BlackMATov
22cedd26bb remove some of the specialized defer functions in favor of the universal defer_call_hook 2025-10-12 07:04:44 +07:00
BlackMATov
d298be4188 ON_REMOVE hooks are now invoked before the fragment is actually removed from the entity
issue: https://github.com/BlackMATov/evolved.lua/issues/26
2025-10-12 06:46:43 +07:00
BlackMATov
24933e6a04 little internal hooks refactoring 2025-10-08 16:18:49 +07:00
BlackMATov
6841bb42fe style fixes 2025-10-07 22:56:29 +07:00
BlackMATov
dc912eb6da the universal builder:build/multi_build methods 2025-10-06 19:05:16 +07:00
BlackMATov
8d3c4633fb little coverage upping 2025-10-06 16:53:53 +07:00
BlackMATov
8704fb0c39 update changelog 2025-10-06 04:46:14 +07:00
BlackMATov
86c9ef7cf2 caching exclude-only queries was a mistake 2025-10-06 04:38:06 +07:00
BlackMATov
bd5f9bb61f cache exclude-only queries too 2025-10-06 02:53:38 +07:00
BlackMATov
cfa5dc7a9f lazy query chunks updating 2025-10-06 01:46:54 +07:00
BlackMATov
243adc1a93 fix query cache reset 2025-10-05 09:13:59 +07:00
BlackMATov
cf19fba9e4 cache query major chunks: first impl 2025-10-05 08:59:07 +07:00
BlackMATov
784b9c6a15 delele some unnecessary checks 2025-09-29 15:20:37 +07:00
2903b077fe Merge pull request #24 from BlackMATov/dev
Dev
2025-09-26 17:30:35 +07:00
BlackMATov
d3b14a6741 v1.3.0 2025-09-26 17:27:49 +07:00
BlackMATov
fdf5a03a02 improve performance of builders that are used for spawning multiple times 2025-09-26 17:21:50 +07:00
BlackMATov
9221da6ea7 slightly improve required fragments perf 2025-09-24 18:16:01 +07:00
BlackMATov
0aa57f6b5b benchmarks refactoring 2 2025-09-24 00:51:25 +07:00
BlackMATov
7e38e43d7c benchmarks refactoring 2025-09-23 17:37:29 +07:00
BlackMATov
b1b627b677 improve perf of cloning prefabs with many unique fragments 2025-09-23 07:53:11 +07:00
BlackMATov
281866cf6e set/assign hooks are not invoked for tags on override operations anymore 2025-09-23 07:24:26 +07:00
BlackMATov
4ad7fec26d update readme 2025-09-23 05:05:30 +07:00
BlackMATov
f15118be05 the new evolved.locate public function
ref: #23
2025-09-23 04:58:10 +07:00
BlackMATov
964ea45f48 use xpcall to process systems 2025-09-22 21:27:57 +07:00
BlackMATov
b2c08e1127 cancel deferring ops in systems on error 2025-09-22 05:51:21 +07:00
BlackMATov
2250bd64ce the new evolved.cancel public function 2025-09-22 02:34:37 +07:00
BlackMATov
e564be46fb collect garbage from old bytecode 2025-09-22 01:56:08 +07:00
BlackMATov
521ad94278 the internal garbage collector now collects more garbage 2025-09-20 03:11:12 +07:00
BlackMATov
7f6909e48c remove some unused code about pinned chunks 2025-09-20 01:53:29 +07:00
BlackMATov
ec745f6ad7 Merge branch 'feature/schemes' into dev 2025-09-19 19:51:02 +07:00
BlackMATov
b3eec59f8b update readme 2025-09-19 19:50:50 +07:00
BlackMATov
1635dd66b1 remove schemes temporary 2025-09-19 18:58:18 +07:00
BlackMATov
b420085ed5 proof of concept ffi component storages
fast batch ops storage swapping was temporary removed
2025-09-19 07:04:19 +07:00
BlackMATov
6d5f810d45 experimental scheme creation 2025-09-15 17:56:44 +07:00
BlackMATov
5447f50090 dummy SCHEME class and readme 2025-09-12 05:58:41 +07:00
BlackMATov
e6d79dc600 Merge branch 'dev' into feature/schemes 2025-09-12 05:45:33 +07:00
7b6ac89c8a Merge pull request #21 from BlackMATov/dev
Dev
2025-09-12 05:30:07 +07:00
BlackMATov
91b3910eda v1.2.0 2025-09-12 05:27:17 +07:00
BlackMATov
7f5ac62a79 Merge branch 'feature/multi_spawn' into dev 2025-09-12 05:13:55 +07:00
BlackMATov
327a6bcbce final tweaks of the multi_spawn/clone functions 2025-09-12 05:11:29 +07:00
BlackMATov
5184b39f4e proof of concept multi_clone/spawn optimizations 2025-09-12 01:52:33 +07:00
BlackMATov
de7d1a6674 dirty proof of concept multi_spawn impl (without any optimization) 2025-09-11 06:57:13 +07:00
BlackMATov
632232b9b1 dummy multi spawn api 2025-09-11 01:27:54 +07:00
BlackMATov
fbc61a8895 style fixes 2025-09-10 16:27:50 +07:00
BlackMATov
e3ed2d89a6 style fixes 2025-09-09 14:46:54 +07:00
BlackMATov
bb7f469288 inline internal ids unpacking 2025-09-09 05:02:27 +07:00
BlackMATov
8417cecbbe little test fixes 2025-09-08 17:42:31 +07:00
BlackMATov
eb31ed247b little test fixes 2025-09-08 17:41:18 +07:00
BlackMATov
9400401161 dummy SCHEME fragment trait 2025-09-03 15:07:32 +07:00
BlackMATov
59fb4d8ea4 update readme 2025-09-01 16:09:35 +07:00
BlackMATov
001e6f2956 Merge branch 'feature/pairs' into dev 2025-09-01 15:49:46 +07:00
BlackMATov
fb6d13ca74 temp remove pairs to merge other changes to dev 2025-09-01 15:34:03 +07:00
BlackMATov
8f61a14db6 update pairs todos 2025-09-01 15:09:29 +07:00
BlackMATov
0c016f1b67 return xxx_set debug mode 2025-09-01 01:59:00 +07:00
BlackMATov
26bf586140 primary/secondary functon set doesn't work with pairs as entity now 2025-09-01 01:53:29 +07:00
BlackMATov
46f1516a55 style fixes 2025-09-01 01:10:17 +07:00
BlackMATov
4cd8393546 public api works only with non-pair ids in has/get functions 2025-09-01 00:33:10 +07:00
BlackMATov
22302cee75 primary/secondary iterators for pair entities 2025-08-29 18:19:19 +07:00
BlackMATov
d4a7c7b77c more pair checks 2025-08-29 05:56:23 +07:00
BlackMATov
12beee6eec debug mode for pack/unpack and pair/unpair 2025-08-26 05:42:04 +07:00
BlackMATov
71a7d382c1 more type annots 2025-08-26 04:13:50 +07:00
BlackMATov
f2a8ee5b83 little style fixes 2025-08-24 16:14:26 +07:00
BlackMATov
81bf1d91e9 Revert "temp remove pairs to merge other changes to dev" 2025-08-20 23:27:08 +07:00
BlackMATov
6b4c6f2a9a update changelog 2025-08-20 23:17:12 +07:00
BlackMATov
7eb4bfd62d Merge branch 'feature/temp_remove_pairs' into dev 2025-08-20 23:11:55 +07:00
BlackMATov
1b49f4fcd0 temp remove pairs to merge other changes to dev 2025-08-20 23:04:11 +07:00
BlackMATov
77bc6c298e remove 'options' param from evolved.pack 2025-08-20 22:23:25 +07:00
BlackMATov
008df17ee6 fix readme formatting 2025-08-20 05:41:06 +07:00
BlackMATov
ba3018213e builder wildcard has/remove first impl 2025-08-20 05:16:18 +07:00
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
6bf13890ef Merge pull request #14 from BlackMATov/dev
Dev
2025-06-06 21:28:17 +07:00
BlackMATov
9a5ea20778 v1.1.0 2025-06-06 21:25:08 +07:00
BlackMATov
0112d0747a Merge branch 'feature/requires_fragment' into dev 2025-06-06 21:21:59 +07:00
BlackMATov
c222a49257 fix the cloning with requires behavior for removed required fragments 2025-06-06 21:20:38 +07:00
BlackMATov
fbd9f9f970 additional requries-fragment tests 2025-06-06 18:32:56 +07:00
BlackMATov
d8c9481f13 Merge branch 'dev' into feature/requires_fragment 2025-06-05 14:46:47 +07:00
BlackMATov
47fcc9cc13 additional requries-fragment test 2025-06-05 14:46:16 +07:00
BlackMATov
cb98a4e461 update README 2025-05-31 07:14:03 +07:00
BlackMATov
a559c73c35 update README to reflect the new REQUIRES trait feature 2025-05-30 03:41:42 +07:00
BlackMATov
ba5ee22f5d little improvements REQUIRES fragments 2025-05-30 01:26:56 +07:00
BlackMATov
50afb722d1 proof of concept REQUIRES fragment impl 2025-05-29 17:08:40 +07:00
BlackMATov
8eccd461fd add pack/unpack fuzz test 2025-05-28 23:34:14 +07:00
BlackMATov
c323131d1e add pack/unpack fuzz test 2025-05-28 23:33:57 +07:00
BlackMATov
8038031b51 has_required_fragments chunk flag 2025-05-28 22:44:18 +07:00
BlackMATov
1399820d71 new REQUIRES dummy fragment 2025-05-28 15:06:44 +07:00
BlackMATov
3a64bac8e2 systems can be queries themselves 2025-05-26 17:37:40 +07:00
BlackMATov
5ae0e77f20 update GUIDES 2025-05-25 22:30:45 +07:00
BlackMATov
e78c4e8d6b update README 2025-05-24 18:39:17 +07:00
db191b805f Merge pull request #13 from BlackMATov/dev
Dev
2025-05-23 20:07:43 +07:00
BlackMATov
9c6e53e610 update README 2025-05-23 19:57:54 +07:00
45 changed files with 9407 additions and 3461 deletions

5
.luacov Normal file
View File

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

View File

@@ -28,6 +28,9 @@
"ignoreDir": [
".vscode",
"develop/3rdparty"
],
"library": [
"${3rd}/love2d/library"
]
}
}

11
.vscode/launch.json vendored
View File

@@ -27,6 +27,17 @@
"lua": "luajit",
"file": "${workspaceFolder}/develop/all.lua"
}
},
{
"name": "Launch Evolved Example (LÖVE)",
"type": "lua-local",
"request": "launch",
"program": {
"command": "love"
},
"args": [
"${workspaceFolder}/example"
]
}
]
}

View File

@@ -1,8 +1,14 @@
{
"[json][jsonc][lua][markdown][yaml]": {
"[json][jsonc][lua][markdown][teal][yaml]": {
"editor.formatOnSave": true,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true
},
"markdown.extension.toc.levels": "2..6",
"markdown.extension.toc.omittedFromToc": {
"README.md": [
"# API Reference"
]
}
}

842
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +0,0 @@
# Roadmap
## Backlog
## After first release
- cached queries
- observers and events
- add INDEX fragment trait
- add REQUIRES fragment trait
- use compact prefix-tree for chunks
- optional ffi component storages

22
develop/GUIDES.md Normal file
View File

@@ -0,0 +1,22 @@
# Guidelines
## Checklists
### New Version Releasing
1. Ensure all tests pass on CI.
2. Update the version number in `evolved.lua`.
3. Update the **Changelog** section in `README.md`.
4. Create a new rockspec file in `rockspecs`.
5. Commit the changes with a message like `vX.Y.Z`.
6. Push and merge the changes to the `main` branch.
7. Create the release on GitHub.
8. Upload the new package to LuaRocks.
### Adding a New Top-Level Function
1. Insert the new function into the `evolved` table in `evolved.lua`.
2. Create tests for the function in `develop/testing/function_name_tests.lua`.
3. Add the new test to `develop/all.lua`.
4. Document the function in the **Cheat Sheet** and **API Reference** sections of `README.md`.
5. Provide a description in the **Overview** section of `README.md`.
6. Describe the update in the **Changelog** section of `README.md`.

18
develop/ROADMAP.md Normal file
View File

@@ -0,0 +1,18 @@
# Roadmap
## Backlog
- 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.
- We should have a way to not copy components on deferred spawn/clone.
## Known Issues
- Required fragments are slower than they should be
- Errors in hooks are cannot be handled properly right now

View File

@@ -1,15 +1,34 @@
require 'develop.example'
require 'develop.unbench'
require 'develop.untests'
require 'develop.usbench'
require 'develop.testing.build_tests'
require 'develop.testing.cancel_tests'
require 'develop.testing.clone_tests'
require 'develop.testing.locate_tests'
require 'develop.testing.main_tests'
require 'develop.testing.multi_spawn_tests'
require 'develop.testing.name_tests'
require 'develop.testing.requires_fragment_tests'
require 'develop.testing.spawn_tests'
require 'develop.testing.system_as_query_tests'
require 'develop.benchmarks.clone_bmarks'
require 'develop.benchmarks.common_bmarks'
require 'develop.benchmarks.migration_bmarks'
require 'develop.benchmarks.process_bmarks'
require 'develop.benchmarks.spawn_bmarks'
require 'develop.benchmarks.table_bmarks'
local basics = require 'develop.basics'
print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.destroy_fuzz'
print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.execute_fuzz'
print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.batch_destroy_fuzz'
print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.explicit_fuzz'
print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.pack_unpack_fuzz'
print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.requires_fuzz'
print '----------------------------------------'
basics.describe_fuzz 'develop.fuzzing.unique_fuzz'

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,532 @@
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 D1, D2, D3, D4, D5 = evo.id(5)
evo.set(D1, evo.DEFAULT, true)
evo.set(D2, evo.DEFAULT, true)
evo.set(D3, evo.DEFAULT, true)
evo.set(D4, evo.DEFAULT, true)
evo.set(D5, evo.DEFAULT, true)
evo.set(D1, evo.DUPLICATE, function(v) return not v end)
evo.set(D2, evo.DUPLICATE, function(v) return not v end)
evo.set(D3, evo.DUPLICATE, function(v) return not v end)
evo.set(D4, evo.DUPLICATE, function(v) return not v end)
evo.set(D5, evo.DUPLICATE, function(v) return not v end)
local QF1 = evo.builder():include(F1):spawn()
local QD1 = evo.builder():include(D1):spawn()
local RF1 = evo.builder():require(F1):spawn()
local RF123 = evo.builder():require(F1, F2, F3):spawn()
local RF12345 = evo.builder():require(F1, F2, F3, F4, F5):spawn()
local RD1 = evo.builder():require(D1):spawn()
local RD123 = evo.builder():require(D1, D2, D3):spawn()
local RD12345 = evo.builder():require(D1, D2, D3, D4, D5):spawn()
print '----------------------------------------'
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone | %d entities with 1 component', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [F1] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Defer Clone | %d entities with 1 component', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [F1] = true }
evo.defer()
for _ = 1, N do
clone(prefab)
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone With Defaults | %d entities with 1 component', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [D1] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone | %d entities with 3 components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Defer Clone | %d entities with 3 components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true }
evo.defer()
for _ = 1, N do
clone(prefab)
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone With Defaults | %d entities with 3 components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [D1] = true, [D2] = true, [D3] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone | %d entities with 5 components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Defer 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 }
evo.defer()
for _ = 1, N do
clone(prefab)
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone With Defaults | %d entities with 5 components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [D1] = true, [D2] = true, [D3] = true, [D4] = true, [D5] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(QD1)
end)
print '----------------------------------------'
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone | %d entities with 1 required component', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [RF1] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Defer Clone | %d entities with 1 required component', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [RF1] = true }
evo.defer()
for _ = 1, N do
clone(prefab)
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone With Defaults | %d entities with 1 required component', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [RD1] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone | %d entities with 3 required components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [RF123] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Defer Clone | %d entities with 3 required components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [RF123] = true }
evo.defer()
for _ = 1, N do
clone(prefab)
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone With Defaults | %d entities with 3 required components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [RD123] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone | %d entities with 5 required components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [RF12345] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Defer Clone | %d entities with 5 required components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [RF12345] = true }
evo.defer()
for _ = 1, N do
clone(prefab)
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone With Defaults | %d entities with 5 required components', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [RD12345] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(QD1)
end)
print '----------------------------------------'
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone | %d entities with 1 component', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [F1] = true }
multi_clone(N, prefab)
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Defer Clone | %d entities with 1 component', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [F1] = true }
evo.defer()
multi_clone(N, prefab)
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone With Defaults | %d entities with 1 component', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [D1] = true }
multi_clone(N, prefab)
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone | %d entities with 3 components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true }
multi_clone(N, prefab)
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Defer Clone | %d entities with 3 components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true }
evo.defer()
multi_clone(N, prefab)
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone With Defaults | %d entities with 3 components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [D1] = true, [D2] = true, [D3] = true }
multi_clone(N, prefab)
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone | %d entities with 5 components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
multi_clone(N, prefab)
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Defer 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 }
evo.defer()
multi_clone(N, prefab)
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone With Defaults | %d entities with 5 components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [D1] = true, [D2] = true, [D3] = true, [D4] = true, [D5] = true }
multi_clone(N, prefab)
evo.batch_destroy(QD1)
end)
print '----------------------------------------'
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone | %d entities with 1 required component', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [RF1] = true }
multi_clone(N, prefab)
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Defer Clone | %d entities with 1 required component', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [RF1] = true }
evo.defer()
multi_clone(N, prefab)
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone With Defaults | %d entities with 1 required component', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [RD1] = true }
multi_clone(N, prefab)
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone | %d entities with 3 required components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [RF123] = true }
multi_clone(N, prefab)
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Defer Clone | %d entities with 3 required components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [RF123] = true }
evo.defer()
multi_clone(N, prefab)
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone With Defaults | %d entities with 3 required components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [RD123] = true }
multi_clone(N, prefab)
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone | %d entities with 5 required components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [RF12345] = true }
multi_clone(N, prefab)
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Defer Clone | %d entities with 5 required components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [RF12345] = true }
evo.defer()
multi_clone(N, prefab)
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone With Defaults | %d entities with 5 required components', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [RD12345] = true }
multi_clone(N, prefab)
evo.batch_destroy(QD1)
end)

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,764 @@
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 D1, D2, D3, D4, D5 = evo.id(5)
evo.set(D1, evo.DEFAULT, true)
evo.set(D2, evo.DEFAULT, true)
evo.set(D3, evo.DEFAULT, true)
evo.set(D4, evo.DEFAULT, true)
evo.set(D5, evo.DEFAULT, true)
evo.set(D1, evo.DUPLICATE, function(v) return not v end)
evo.set(D2, evo.DUPLICATE, function(v) return not v end)
evo.set(D3, evo.DUPLICATE, function(v) return not v end)
evo.set(D4, evo.DUPLICATE, function(v) return not v end)
evo.set(D5, evo.DUPLICATE, function(v) return not v end)
local QF1 = evo.builder():include(F1):spawn()
local QD1 = evo.builder():include(D1):spawn()
local RF1 = evo.builder():require(F1):spawn()
local RF123 = evo.builder():require(F1, F2, F3):spawn()
local RF12345 = evo.builder():require(F1, F2, F3, F4, F5):spawn()
local RD1 = evo.builder():require(D1):spawn()
local RD123 = evo.builder():require(D1, D2, D3):spawn()
local RD12345 = evo.builder():require(D1, D2, D3, D4, D5):spawn()
print '----------------------------------------'
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn | %d entities with 1 component', N),
function()
local spawn = evo.spawn
local components = { [F1] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Defer Spawn | %d entities with 1 component', N),
function()
local spawn = evo.spawn
local components = { [F1] = true }
evo.defer()
for _ = 1, N do
spawn(components)
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn With Defaults | %d entities with 1 component', N),
function()
local spawn = evo.spawn
local components = { [D1] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn | %d entities with 3 components', N),
function()
local spawn = evo.spawn
local components = { [F1] = true, [F2] = true, [F3] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Defer Spawn | %d entities with 3 components', N),
function()
local spawn = evo.spawn
local components = { [F1] = true, [F2] = true, [F3] = true }
evo.defer()
for _ = 1, N do
spawn(components)
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn With Defaults | %d entities with 3 components', N),
function()
local spawn = evo.spawn
local components = { [D1] = true, [D2] = true, [D3] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn | %d entities with 5 components', N),
function()
local spawn = evo.spawn
local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Defer Spawn | %d entities with 5 components', N),
function()
local spawn = evo.spawn
local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
evo.defer()
for _ = 1, N do
spawn(components)
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn With Defaults | %d entities with 5 components', N),
function()
local spawn = evo.spawn
local components = { [D1] = true, [D2] = true, [D3] = true, [D4] = true, [D5] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(QD1)
end)
print '----------------------------------------'
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn | %d entities with 1 required component', N),
function()
local spawn = evo.spawn
local components = { [RF1] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Defer Spawn | %d entities with 1 required component', N),
function()
local spawn = evo.spawn
local components = { [RF1] = true }
evo.defer()
for _ = 1, N do
spawn(components)
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn With Defaults | %d entities with 1 required component', N),
function()
local spawn = evo.spawn
local components = { [RD1] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn | %d entities with 3 required components', N),
function()
local spawn = evo.spawn
local components = { [RF123] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Defer Spawn | %d entities with 3 required components', N),
function()
local spawn = evo.spawn
local components = { [RF123] = true }
evo.defer()
for _ = 1, N do
spawn(components)
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn With Defaults | %d entities with 3 required components', N),
function()
local spawn = evo.spawn
local components = { [RD123] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn | %d entities with 5 required components', N),
function()
local spawn = evo.spawn
local components = { [RF12345] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Defer Spawn | %d entities with 5 required components', N),
function()
local spawn = evo.spawn
local components = { [RF12345] = true }
evo.defer()
for _ = 1, N do
spawn(components)
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn With Defaults | %d entities with 5 required components', N),
function()
local spawn = evo.spawn
local components = { [RD12345] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(QD1)
end)
print '----------------------------------------'
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn | %d entities with 1 component', N),
function()
local builder = evo.builder():set(F1)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Defer Spawn | %d entities with 1 component', N),
function()
local builder = evo.builder():set(F1)
evo.defer()
for _ = 1, N do
builder:spawn()
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn With Defaults | %d entities with 1 component', N),
function()
local builder = evo.builder():set(D1)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn | %d entities with 3 components', N),
function()
local builder = evo.builder():set(F1):set(F2):set(F3)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Defer Spawn | %d entities with 3 components', N),
function()
local builder = evo.builder():set(F1):set(F2):set(F3)
evo.defer()
for _ = 1, N do
builder:spawn()
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn With Defaults | %d entities with 3 components', N),
function()
local builder = evo.builder():set(D1):set(D2):set(D3)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn | %d entities with 5 components', N),
function()
local builder = evo.builder():set(F1):set(F2):set(F3):set(F4):set(F5)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Defer Spawn | %d entities with 5 components', N),
function()
local builder = evo.builder():set(F1):set(F2):set(F3):set(F4):set(F5)
evo.defer()
for _ = 1, N do
builder:spawn()
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn With Defaults | %d entities with 5 components', N),
function()
local builder = evo.builder():set(D1):set(D2):set(D3):set(D4):set(D5)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(QD1)
end)
print '----------------------------------------'
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn | %d entities with 1 required component', N),
function()
local builder = evo.builder():set(RF1)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Defer Spawn | %d entities with 1 required component', N),
function()
local builder = evo.builder():set(RF1)
evo.defer()
for _ = 1, N do
builder:spawn()
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn With Defaults | %d entities with 1 required component', N),
function()
local builder = evo.builder():set(RD1)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn | %d entities with 3 required components', N),
function()
local builder = evo.builder():set(RF123)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Defer Spawn | %d entities with 3 required components', N),
function()
local builder = evo.builder():set(RF123)
evo.defer()
for _ = 1, N do
builder:spawn()
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn With Defaults | %d entities with 3 required components', N),
function()
local builder = evo.builder():set(RD123)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn | %d entities with 5 required components', N),
function()
local builder = evo.builder():set(RF12345)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Defer Spawn | %d entities with 5 required components', N),
function()
local builder = evo.builder():set(RF12345)
evo.defer()
for _ = 1, N do
builder:spawn()
end
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn With Defaults | %d entities with 5 required components', N),
function()
local builder = evo.builder():set(RD12345)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(QD1)
end)
print '----------------------------------------'
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn | %d entities with 1 component', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [F1] = true }
multi_spawn(N, components)
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Defer Spawn | %d entities with 1 component', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [F1] = true }
evo.defer()
multi_spawn(N, components)
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn With Defaults | %d entities with 1 component', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [D1] = true }
multi_spawn(N, components)
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn | %d entities with 3 components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [F1] = true, [F2] = true, [F3] = true }
multi_spawn(N, components)
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Defer Spawn | %d entities with 3 components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [F1] = true, [F2] = true, [F3] = true }
evo.defer()
multi_spawn(N, components)
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn With Defaults | %d entities with 3 components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [D1] = true, [D2] = true, [D3] = true }
multi_spawn(N, components)
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn | %d entities with 5 components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
multi_spawn(N, components)
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Defer 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 }
evo.defer()
multi_spawn(N, components)
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn With Defaults | %d entities with 5 components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [D1] = true, [D2] = true, [D3] = true, [D4] = true, [D5] = true }
multi_spawn(N, components)
evo.batch_destroy(QD1)
end)
print '----------------------------------------'
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn | %d entities with 1 required component', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [F1] = true }
multi_spawn(N, components)
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Defer Spawn | %d entities with 1 required component', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [F1] = true }
evo.defer()
multi_spawn(N, components)
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn With Defaults | %d entities with 1 required component', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [D1] = true }
multi_spawn(N, components)
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn | %d entities with 3 required components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [RF123] = true }
multi_spawn(N, components)
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Defer Spawn | %d entities with 3 required components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [RF123] = true }
evo.defer()
multi_spawn(N, components)
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn With Defaults | %d entities with 3 required components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [RD123] = true }
multi_spawn(N, components)
evo.batch_destroy(QD1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn | %d entities with 5 required components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [RF12345] = true }
multi_spawn(N, components)
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Defer Spawn | %d entities with 5 required components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [RF12345] = true }
evo.defer()
multi_spawn(N, components)
evo.commit()
evo.batch_destroy(QF1)
end)
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn With Defaults | %d entities with 5 required components', N),
function()
local multi_spawn = evo.multi_spawn
local components = { [RD12345] = true }
multi_spawn(N, components)
evo.batch_destroy(QD1)
end)

View File

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

View File

@@ -1,129 +0,0 @@
---@diagnostic disable: unused-local
local evo = require 'evolved'
evo.debug_mode(true)
---@class evolved.vector2
---@field x number
---@field y number
---@param x number
---@param y number
---@return evolved.vector2
---@nodiscard
local function vector2(x, y)
---@type evolved.vector2
return { x = x, y = y }
end
local consts = {
delta_time = 0.016,
physics_gravity = vector2(0, 9.81),
}
local groups = {
awake = evo.spawn(),
physics = evo.spawn(),
graphics = evo.spawn(),
shutdown = evo.spawn(),
}
local fragments = {
force = evo.spawn(),
position = evo.spawn(),
velocity = evo.spawn(),
}
local queries = {
physics_bodies = evo.builder()
:include(fragments.force, fragments.position, fragments.velocity)
:spawn(),
}
local awake_system = evo.builder()
:group(groups.awake)
:prologue(function()
print '-= | Awake | =-'
evo.builder()
:set(fragments.force, vector2(0, 0))
:set(fragments.position, vector2(0, 0))
:set(fragments.velocity, vector2(0, 0))
:spawn()
end):spawn()
local integrate_forces_system = evo.builder()
:group(groups.physics)
:query(queries.physics_bodies)
:execute(function(chunk, entities, entity_count)
local delta_time, physics_gravity =
consts.delta_time, consts.physics_gravity
---@type evolved.vector2[], evolved.vector2[]
local forces, velocities = chunk:components(
fragments.force, fragments.velocity)
for i = 1, entity_count do
local force, velocity = forces[i], velocities[i]
velocity.x = velocity.x + (physics_gravity.x + force.x) * delta_time
velocity.y = velocity.y + (physics_gravity.y + force.y) * delta_time
end
end):spawn()
local integrate_velocities_system = evo.builder()
:group(groups.physics)
:query(queries.physics_bodies)
:execute(function(chunk, entities, entity_count)
local delta_time =
consts.delta_time
---@type evolved.vector2[], evolved.vector2[], evolved.vector2[]
local forces, positions, velocities = chunk:components(
fragments.force, fragments.position, fragments.velocity)
for i = 1, entity_count do
local force, position, velocity = forces[i], positions[i], velocities[i]
position.x = position.x + velocity.x * delta_time
position.y = position.y + velocity.y * delta_time
force.x = 0
force.y = 0
end
end):spawn()
local graphics_system = evo.builder()
:group(groups.graphics)
:query(queries.physics_bodies)
:execute(function(chunk, entities, entity_count)
---@type evolved.vector2[]
local positions = chunk:components(
fragments.position)
for i = 1, entity_count do
local entity, position = entities[i], positions[i]
print(string.format(
'|-> {entity %d} at {%.4f, %.4f}',
entity, position.x, position.y))
end
end):spawn()
local shutdown_system = evo.builder()
:group(groups.shutdown)
:epilogue(function()
print '-= | Shutdown | =-'
evo.batch_destroy(queries.physics_bodies)
end):spawn()
do
evo.process(groups.awake)
for _ = 1, 10 do
evo.process(groups.physics)
evo.process(groups.graphics)
end
evo.process(groups.shutdown)
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

@@ -0,0 +1,267 @@
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_fragment_list = {} ---@type evolved.fragment[]
for i = 1, math.random(1, 10) do
local fragment = evo.id()
all_fragment_list[i] = fragment
end
---@param query evolved.query
local function generate_query(query)
local include_set = {}
local include_list = {}
local include_count = 0
for _ = 1, math.random(0, #all_fragment_list) do
local include = all_fragment_list[math.random(1, #all_fragment_list)]
if not include_set[include] then
include_count = include_count + 1
include_set[include] = include_count
include_list[include_count] = include
end
end
local exclude_set = {}
local exclude_list = {}
local exclude_count = 0
for _ = 1, math.random(0, #all_fragment_list) do
local exclude = all_fragment_list[math.random(1, #all_fragment_list)]
if not exclude_set[exclude] then
exclude_count = exclude_count + 1
exclude_set[exclude] = exclude_count
exclude_list[exclude_count] = exclude
end
end
if include_count > 0 then
evo.set(query, evo.INCLUDES, include_list)
end
if exclude_count > 0 then
evo.set(query, evo.EXCLUDES, exclude_list)
end
end
---@param query_count integer
---@return evolved.query[] query_list
---@return integer query_count
---@nodiscard
local function generate_queries(query_count)
local query_list = {} ---@type evolved.query[]
for i = 1, query_count do
local query = evo.id()
query_list[i] = query
generate_query(query)
end
return query_list, query_count
end
---@param entity evolved.entity
local function generate_entity(entity)
for _ = 0, math.random(0, #all_fragment_list) do
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
evo.set(entity, fragment)
end
end
---@param entity_count integer
---@return evolved.entity[] entity_list
---@return integer entity_count
local function generate_entities(entity_count)
local entity_list = {} ---@type evolved.entity[]
for i = 1, entity_count do
local entity = evo.id()
entity_list[i] = entity
generate_entity(entity)
end
return entity_list, entity_count
end
local pre_query_list, pre_query_count = generate_queries(math.random(1, 10))
local pre_entity_list, pre_entity_count = generate_entities(math.random(1, 10))
for _ = 1, math.random(1, 5) do
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
evo.set(fragment, evo.EXPLICIT)
end
for _ = 1, math.random(1, 5) do
local query = pre_query_list[math.random(1, pre_query_count)]
if math.random(1, 2) == 1 then
generate_query(query)
else
if math.random(1, 2) == 1 then
evo.remove(query, evo.INCLUDES)
else
evo.remove(query, evo.EXCLUDES)
end
end
end
local post_query_list, post_query_count = generate_queries(math.random(1, 10))
local post_entity_list, post_entity_count = generate_entities(math.random(1, 10))
---
---
---
---
---
local all_query_list = {}
local all_query_count = 0
local all_entity_list = {}
local all_entity_count = 0
for i = 1, pre_query_count do
all_query_count = all_query_count + 1
all_query_list[all_query_count] = pre_query_list[i]
end
for i = 1, post_query_count do
all_query_count = all_query_count + 1
all_query_list[all_query_count] = post_query_list[i]
end
for i = 1, pre_entity_count do
all_entity_count = all_entity_count + 1
all_entity_list[all_entity_count] = pre_entity_list[i]
end
for i = 1, post_entity_count do
all_entity_count = all_entity_count + 1
all_entity_list[all_entity_count] = post_entity_list[i]
end
---
---
---
---
---
local function execute_query(query)
local query_chunk_set = {}
local query_entity_set = {}
local query_include_list = evo.get(query, evo.INCLUDES) or {}
local query_exclude_list = evo.get(query, evo.EXCLUDES) or {}
local query_include_set = {}
for _, include in ipairs(query_include_list) do
query_include_set[include] = true
end
for chunk, entity_list, entity_count in evo.execute(query) do
assert(not query_chunk_set[chunk])
query_chunk_set[chunk] = true
for i = 1, entity_count do
local entity = entity_list[i]
assert(not query_entity_set[entity])
query_entity_set[entity] = true
end
assert(chunk:has_all(__table_unpack(query_include_list)))
assert(not chunk:has_any(__table_unpack(query_exclude_list)))
end
for i = 1, all_entity_count do
local entity = all_entity_list[i]
local is_entity_matched =
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) and not query_include_set[fragment] then
is_entity_matched = false
end
end
if is_entity_matched then
assert(query_entity_set[entity])
else
assert(not query_entity_set[entity])
end
end
end
for i = 1, all_query_count do
execute_query(all_query_list[i])
end
---
---
---
---
---
for _ = 1, math.random(1, 5) do
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
evo.set(fragment, evo.EXPLICIT)
end
for _ = 1, math.random(1, 5) do
local query = pre_query_list[math.random(1, pre_query_count)]
if math.random(1, 2) == 1 then
generate_query(query)
else
if math.random(1, 2) == 1 then
evo.remove(query, evo.INCLUDES)
else
evo.remove(query, evo.EXCLUDES)
end
end
end
for i = 1, all_query_count do
execute_query(all_query_list[i])
end
---
---
---
---
---
if math.random(1, 2) == 1 then
evo.collect_garbage()
end
evo.destroy(__table_unpack(all_query_list))
evo.destroy(__table_unpack(all_entity_list))
evo.destroy(__table_unpack(all_fragment_list))
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

@@ -0,0 +1,20 @@
local evo = require 'evolved'
evo.debug_mode(true)
---
---
---
---
---
for _ = 1, 1000 do
local initial_primary = math.random(1, 2 ^ 20 - 1)
local initial_secondary = math.random(1, 2 ^ 20 - 1)
local packed_id = evo.pack(initial_primary, initial_secondary)
local unpacked_primary, unpacked_secondary = evo.unpack(packed_id)
assert(initial_primary == unpacked_primary)
assert(initial_secondary == unpacked_secondary)
end

View File

@@ -0,0 +1,131 @@
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_fragment_list = {} ---@type evolved.fragment[]
for i = 1, math.random(1, 10) do
local fragment = evo.builder()
:default(42)
:spawn()
all_fragment_list[i] = fragment
end
for _, fragment in ipairs(all_fragment_list) do
if math.random(1, 2) == 1 then
for _ = 0, math.random(0, #all_fragment_list) do
local require_list = evo.get(fragment, evo.REQUIRES) or {}
require_list[#require_list + 1] = all_fragment_list[math.random(1, #all_fragment_list)]
evo.set(fragment, evo.REQUIRES, require_list)
end
end
end
local all_entity_list = {} ---@type evolved.entity[]
for i = 1, math.random(1, 10) do
local entity = evo.id()
all_entity_list[i] = entity
for _ = 0, math.random(0, #all_fragment_list) do
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
if math.random(1, 2) == 1 then
evo.set(entity, fragment, 42)
else
local query = evo.builder()
:include(all_fragment_list[math.random(1, #all_fragment_list)])
:spawn()
evo.batch_set(query, fragment, 42)
evo.destroy(query)
end
end
end
for _ = 1, math.random(1, #all_entity_list) do
local components = {}
for _ = 1, math.random(1, #all_fragment_list) do
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
components[fragment] = 42
end
all_entity_list[#all_entity_list + 1] = evo.spawn(components)
end
for _ = 1, math.random(1, #all_entity_list) do
local prefab = all_entity_list[math.random(1, #all_entity_list)]
all_entity_list[#all_entity_list + 1] = evo.clone(prefab)
end
---
---
---
---
---
local function collect_required_fragments_for(fragment, req_fragment_set, req_fragment_list)
local fragment_requires = evo.get(fragment, evo.REQUIRES) or {}
for _, required_fragment in ipairs(fragment_requires) do
if not req_fragment_set[required_fragment] then
req_fragment_set[required_fragment] = true
req_fragment_list[#req_fragment_list + 1] = required_fragment
collect_required_fragments_for(required_fragment, req_fragment_set, req_fragment_list)
end
end
end
for _, entity in ipairs(all_entity_list) do
for fragment in evo.each(entity) do
local req_fragment_list = {}
collect_required_fragments_for(fragment, {}, req_fragment_list)
for _, required_fragment in ipairs(req_fragment_list) do
assert(evo.has(entity, required_fragment))
local required_component = evo.get(entity, required_fragment)
assert(required_component == 42)
end
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

@@ -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,41 @@
local evo = require 'evolved'
do
local f1, f2 = evo.id(2)
do
local e = evo.builder():set(f1, 42):set(f2, 'hello'):build()
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == 'hello')
end
do
local p = evo.builder():set(f1, 42):build()
local e = evo.builder():set(f2, 'hello'):build(p)
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == 'hello')
end
do
local entity_list, entity_count = evo.builder():set(f1, 42):set(f2, 'hello'):multi_build(5)
assert(entity_count == 5)
for i = 1, entity_count do
local e = entity_list[i]
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == 'hello')
end
end
do
local p = evo.builder():set(f1, 42):build()
local entity_list, entity_count = evo.builder():set(f2, 'hello'):multi_build(5, p)
assert(entity_count == 5)
for i = 1, entity_count do
local e = entity_list[i]
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == 'hello')
end
end
end

View File

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

View File

@@ -0,0 +1,397 @@
local evo = require 'evolved'
do
do
local p = evo.spawn()
local e = evo.clone(p)
assert(evo.alive(e) and evo.empty(e))
end
do
local p = evo.spawn()
local e = evo.clone(p, {})
assert(evo.alive(e) and evo.empty(e))
end
do
local f1, f2 = evo.id(2)
evo.set(f1, evo.REQUIRES, { f2 })
evo.set(f2, evo.DEFAULT, 42)
local p = evo.spawn()
local e = evo.clone(p, { [f1] = 'hello' })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2))
assert(evo.has(e, f1) and evo.get(e, f1) == 'hello')
assert(evo.has(e, f2) and evo.get(e, f2) == 42)
end
end
do
local f1, f2, f3, f4 = evo.id(4)
evo.set(f1, evo.TAG)
evo.set(f1, evo.REQUIRES, { f2, f3 })
evo.set(f4, evo.UNIQUE)
do
local p = evo.spawn { [f4] = 'unique' }
local e = evo.clone(p)
assert(evo.alive(e) and evo.empty(e))
end
do
local p = evo.spawn { [f4] = 'unique' }
local e = evo.clone(p, {})
assert(evo.alive(e) and evo.empty(e))
end
do
local p = evo.spawn { [f4] = 'unique' }
local e = evo.clone(p, { [f4] = 'another' })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f4))
assert(evo.has(e, f4) and evo.get(e, f4) == 'another')
end
do
local p = evo.spawn { [f2] = 100, [f4] = 'unique' }
local e = evo.clone(p, { [f4] = 'another' })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f2, f4))
assert(evo.has(e, f2) and evo.get(e, f2) == 100)
assert(evo.has(e, f4) and evo.get(e, f4) == 'another')
end
do
local p = evo.spawn { [f2] = 100, [f4] = 'unique' }
local e = evo.clone(p, { [f1] = 'hello', [f3] = 10 })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3))
assert(evo.has(e, f1) and evo.get(e, f1) == nil)
assert(evo.has(e, f2) and evo.get(e, f2) == 100)
assert(evo.has(e, f3) and evo.get(e, f3) == 10)
end
end
do
do
local f1, f2, f3, f4 = evo.id(4)
evo.set(f4, evo.TAG)
do
local p = evo.spawn { [f2] = 21, [f3] = 'hello', [f4] = true }
local e = evo.clone(p, { [f1] = 'world', [f2] = 10 })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3, f4))
assert(evo.has(e, f1) and evo.get(e, f1) == 'world')
assert(evo.has(e, f2) and evo.get(e, f2) == 10)
assert(evo.has(e, f3) and evo.get(e, f3) == 'hello')
assert(evo.has(e, f4) and evo.get(e, f4) == nil)
end
end
do
local f1, f2, f3, f4 = evo.id(4)
evo.set(f2, evo.DEFAULT, 42)
evo.set(f3, evo.DUPLICATE, function() return nil end)
evo.set(f4, evo.TAG)
do
local p = evo.spawn { [f2] = 21, [f3] = 'hello', [f4] = true }
local e = evo.clone(p, { [f1] = 'world', [f2] = 10 })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3, f4))
assert(evo.has(e, f1) and evo.get(e, f1) == 'world')
assert(evo.has(e, f2) and evo.get(e, f2) == 10)
assert(evo.has(e, f3) and evo.get(e, f3) == true)
assert(evo.has(e, f4) and evo.get(e, f4) == nil)
end
end
end
do
local f1, f2, f3, f4 = evo.id(4)
evo.set(f1, evo.TAG)
evo.set(f1, evo.REQUIRES, { f2, f3 })
evo.set(f2, evo.DEFAULT, 42)
evo.set(f2, evo.DUPLICATE, function(v) return v * 2 end)
evo.set(f3, evo.DUPLICATE, function() return nil end)
evo.set(f4, evo.UNIQUE)
do
local p = evo.spawn { [f4] = 'unique' }
local e = evo.clone(p)
assert(evo.alive(e) and evo.empty(e))
end
do
local p = evo.spawn { [f4] = 'unique' }
local e = evo.clone(p, {})
assert(evo.alive(e) and evo.empty(e))
end
do
local p = evo.spawn { [f4] = 'unique' }
local e = evo.clone(p, { [f4] = 'another' })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f4))
assert(evo.has(e, f4) and evo.get(e, f4) == 'another')
end
do
local p = evo.spawn { [f2] = 100, [f4] = 'unique' }
local e = evo.clone(p, { [f4] = 'another' })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f2, f4))
assert(evo.has(e, f2) and evo.get(e, f2) == 200 * 2)
assert(evo.has(e, f4) and evo.get(e, f4) == 'another')
end
do
local p = evo.spawn { [f2] = 100, [f4] = 'unique' }
local e = evo.clone(p, { [f1] = 'hello', [f2] = 10 })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3))
assert(evo.has(e, f1) and evo.get(e, f1) == nil)
assert(evo.has(e, f2) and evo.get(e, f2) == 10 * 2)
assert(evo.has(e, f3) and evo.get(e, f3) == true)
end
local f1_set_count, f1_inserted_count = 0, 0
local f2_set_sum, f3_inserted_count = 0, 0
evo.set(f1, evo.ON_SET, function(e, f, c)
assert(evo.get(e, f) == c)
f1_set_count = f1_set_count + 1
end)
evo.set(f1, evo.ON_INSERT, function(e, f, c)
assert(evo.get(e, f) == c)
f1_inserted_count = f1_inserted_count + 1
end)
evo.set(f2, evo.ON_SET, function(e, f, c)
assert(evo.get(e, f) == c)
f2_set_sum = f2_set_sum + c
end)
evo.set(f3, evo.ON_INSERT, function(e, f, c)
assert(evo.get(e, f) == c)
f3_inserted_count = f3_inserted_count + 1
end)
do
f1_set_count, f1_inserted_count = 0, 0
f2_set_sum, f3_inserted_count = 0, 0
local p = evo.spawn { [f2] = 100, [f4] = 'unique' }
local e = evo.clone(p, { [f1] = 'hello', [f2] = 10 })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3))
assert(evo.has(e, f1) and evo.get(e, f1) == nil)
assert(evo.has(e, f2) and evo.get(e, f2) == 10 * 2)
assert(evo.has(e, f3) and evo.get(e, f3) == true)
assert(f1_set_count == 1)
assert(f1_inserted_count == 1)
assert(f2_set_sum == 100 * 2 + 10 * 2)
assert(f3_inserted_count == 1)
end
end
do
local f1, f2, f3, f4 = evo.id(4)
evo.set(f1, evo.TAG)
evo.set(f1, evo.REQUIRES, { f2, f3 })
evo.set(f4, evo.UNIQUE)
do
local p = evo.spawn { [f4] = 'unique' }
local es, ec = evo.multi_clone(1, p)
assert(#es == 1 and ec == 1)
for i = 1, ec do
assert(evo.alive(es[i]) and evo.empty(es[i]))
end
end
do
local p = evo.spawn { [f4] = 'unique' }
local es, ec = evo.multi_clone(2, p, {})
assert(#es == 2 and ec == 2)
for i = 1, ec do
assert(evo.alive(es[i]) and evo.empty(es[i]))
end
end
do
local p = evo.spawn { [f4] = 'unique' }
local es, ec = evo.multi_clone(3, p, { [f4] = 'another' })
assert(#es == 3 and ec == 3)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f4))
assert(evo.has(es[i], f4) and evo.get(es[i], f4) == 'another')
end
end
do
local p = evo.spawn { [f2] = 100, [f4] = 'unique' }
local es, ec = evo.multi_clone(4, p, { [f4] = 'another' })
assert(#es == 4 and ec == 4)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f2, f4))
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 100)
assert(evo.has(es[i], f4) and evo.get(es[i], f4) == 'another')
end
end
do
local p = evo.spawn { [f2] = 100, [f4] = 'unique' }
local es, ec = evo.multi_clone(5, p, { [f1] = 'hello', [f3] = 10 })
assert(#es == 5 and ec == 5)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == nil)
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 100)
assert(evo.has(es[i], f3) and evo.get(es[i], f3) == 10)
end
end
end
do
do
local f1, f2, f3, f4 = evo.id(4)
evo.set(f4, evo.TAG)
do
local p = evo.spawn { [f2] = 21, [f3] = 'hello', [f4] = true }
local es, ec = evo.multi_clone(2, p, { [f1] = 'world', [f2] = 10 })
assert(#es == 2 and ec == 2)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3, f4))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 'world')
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 10)
assert(evo.has(es[i], f3) and evo.get(es[i], f3) == 'hello')
assert(evo.has(es[i], f4) and evo.get(es[i], f4) == nil)
end
end
end
do
local f1, f2, f3, f4 = evo.id(4)
evo.set(f2, evo.DEFAULT, 42)
evo.set(f3, evo.DUPLICATE, function() return nil end)
evo.set(f4, evo.TAG)
do
local p = evo.spawn { [f2] = 21, [f3] = 'hello', [f4] = true }
local es, ec = evo.multi_clone(2, p, { [f1] = 'world', [f2] = 10 })
assert(#es == 2 and ec == 2)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3, f4))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 'world')
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 10)
assert(evo.has(es[i], f3) and evo.get(es[i], f3) == true)
assert(evo.has(es[i], f4) and evo.get(es[i], f4) == nil)
end
end
end
end
do
local f1, f2, f3, f4 = evo.id(4)
evo.set(f1, evo.TAG)
evo.set(f1, evo.REQUIRES, { f2, f3 })
evo.set(f2, evo.DEFAULT, 42)
evo.set(f2, evo.DUPLICATE, function(v) return v * 2 end)
evo.set(f3, evo.DUPLICATE, function() return nil end)
evo.set(f4, evo.UNIQUE)
do
local p = evo.spawn { [f4] = 'unique' }
local es, ec = evo.multi_clone(3, p)
assert(#es == 3 and ec == 3)
for i = 1, ec do
assert(evo.alive(es[i]) and evo.empty(es[i]))
end
end
do
local p = evo.spawn { [f4] = 'unique' }
local es, ec = evo.multi_clone(3, p, {})
assert(#es == 3 and ec == 3)
for i = 1, ec do
assert(evo.alive(es[i]) and evo.empty(es[i]))
end
end
do
local p = evo.spawn { [f4] = 'unique' }
local es, ec = evo.multi_clone(2, p, { [f4] = 'another' })
assert(#es == 2 and ec == 2)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f4))
assert(evo.has(es[i], f4) and evo.get(es[i], f4) == 'another')
end
end
do
local p = evo.spawn { [f2] = 100, [f4] = 'unique' }
local es, ec = evo.multi_clone(4, p, { [f4] = 'another' })
assert(#es == 4 and ec == 4)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f2, f4))
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 200 * 2)
assert(evo.has(es[i], f4) and evo.get(es[i], f4) == 'another')
end
end
do
local p = evo.spawn { [f2] = 100, [f4] = 'unique' }
local es, ec = evo.multi_clone(5, p, { [f1] = 'hello', [f2] = 10 })
assert(#es == 5 and ec == 5)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == nil)
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 10 * 2)
assert(evo.has(es[i], f3) and evo.get(es[i], f3) == true)
end
end
local f1_set_count, f1_inserted_count = 0, 0
local f2_set_sum, f3_inserted_count = 0, 0
evo.set(f1, evo.ON_SET, function(e, f, c)
assert(evo.get(e, f) == c)
f1_set_count = f1_set_count + 1
end)
evo.set(f1, evo.ON_INSERT, function(e, f, c)
assert(evo.get(e, f) == c)
f1_inserted_count = f1_inserted_count + 1
end)
evo.set(f2, evo.ON_SET, function(e, f, c)
assert(evo.get(e, f) == c)
f2_set_sum = f2_set_sum + c
end)
evo.set(f3, evo.ON_INSERT, function(e, f, c)
assert(evo.get(e, f) == c)
f3_inserted_count = f3_inserted_count + 1
end)
do
f1_set_count, f1_inserted_count = 0, 0
f2_set_sum, f3_inserted_count = 0, 0
local p = evo.spawn { [f2] = 100, [f4] = 'unique' }
local es, ec = evo.multi_clone(1, p, { [f1] = 'hello', [f2] = 10 })
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == nil)
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 10 * 2)
assert(evo.has(es[i], f3) and evo.get(es[i], f3) == true)
assert(f1_set_count == 1)
assert(f1_inserted_count == 1)
assert(f2_set_sum == 100 * 2 + 10 * 2)
assert(f3_inserted_count == 1)
end
end
end

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,607 @@
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
do
local f1, f2, f3 = evo.id(3)
evo.set(f1, evo.REQUIRES, { f2, f3 })
evo.set(f3, evo.TAG)
do
local entity_list, entity_count = evo.multi_spawn(2, { [f1] = 42 })
assert(entity_list and #entity_list == 2)
assert(entity_count == 2)
for i = 1, entity_count do
local e = entity_list[i]
assert(e and not evo.empty(e))
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == true)
assert(evo.has(e, f3) and evo.get(e, f3) == nil)
end
end
do
local entity_prefab = evo.builder():set(f1, 42):spawn()
local clone_list, clone_count = evo.multi_clone(2, entity_prefab)
assert(clone_list and #clone_list == 2)
assert(clone_count == 2)
for i = 1, clone_count do
local e = clone_list[i]
assert(e and not evo.empty(e))
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == true)
assert(evo.has(e, f3) and evo.get(e, f3) == nil)
end
end
do
local entity_prefab = evo.builder():set(f1, 42):spawn()
evo.remove(entity_prefab, f2, f3)
local clone_list, clone_count = evo.multi_clone(2, entity_prefab, { [f1] = 21 })
assert(clone_list and #clone_list == 2)
assert(clone_count == 2)
for i = 1, clone_count do
local e = clone_list[i]
assert(e and not evo.empty(e))
assert(evo.has(e, f1) and evo.get(e, f1) == 21)
assert(evo.has(e, f2) and evo.get(e, f2) == true)
assert(evo.has(e, f3) and evo.get(e, f3) == nil)
end
end
evo.set(f2, evo.DEFAULT, false)
do
local entity_list, entity_count = evo.multi_spawn(2, { [f1] = 42 })
assert(entity_list and #entity_list == 2)
assert(entity_count == 2)
for i = 1, entity_count do
local e = entity_list[i]
assert(e and not evo.empty(e))
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == false)
assert(evo.has(e, f3) and evo.get(e, f3) == nil)
end
end
do
local entity_prefab = evo.builder():set(f1, 42):spawn()
local clone_list, clone_count = evo.multi_clone(2, entity_prefab)
assert(clone_list and #clone_list == 2)
assert(clone_count == 2)
for i = 1, clone_count do
local e = clone_list[i]
assert(e and not evo.empty(e))
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == false)
assert(evo.has(e, f3) and evo.get(e, f3) == nil)
end
end
do
local entity_prefab = evo.builder():set(f1, 42):spawn()
evo.remove(entity_prefab, f2, f3)
local clone_list, clone_count = evo.multi_clone(2, entity_prefab, { [f1] = 21 })
assert(clone_list and #clone_list == 2)
assert(clone_count == 2)
for i = 1, clone_count do
local e = clone_list[i]
assert(e and not evo.empty(e))
assert(evo.has(e, f1) and evo.get(e, f1) == 21)
assert(evo.has(e, f2) and evo.get(e, f2) == false)
assert(evo.has(e, f3) and evo.get(e, f3) == nil)
end
end
local v_set_sum = 0
local v_insert_sum = 0
local f3_set_times = 0
local f3_insert_times = 0
evo.set(f1, evo.ON_SET, function(e, f, v)
assert(f == f1)
v_set_sum = v_set_sum + v
assert(evo.get(e, f) == v)
end)
evo.set(f1, evo.ON_INSERT, function(e, f, v)
assert(f == f1)
v_insert_sum = v_insert_sum + v
assert(evo.get(e, f) == v)
end)
evo.set(f3, evo.ON_SET, function(e, f, v)
assert(f == f3)
f3_set_times = f3_set_times + 1
assert(v == nil)
assert(evo.has(e, f))
end)
evo.set(f3, evo.ON_INSERT, function(e, f, v)
assert(f == f3)
f3_insert_times = f3_insert_times + 1
assert(v == nil)
assert(evo.has(e, f))
end)
do
local entity_list, entity_count = evo.multi_spawn(2, { [f1] = 42 })
assert(entity_list and #entity_list == 2)
assert(entity_count == 2)
for i = 1, entity_count do
local e = entity_list[i]
assert(e and not evo.empty(e))
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == false)
end
end
do
local entity_prefab = evo.builder():set(f1, 42):spawn()
local clone_list, clone_count = evo.multi_clone(2, entity_prefab)
assert(clone_list and #clone_list == 2)
assert(clone_count == 2)
for i = 1, clone_count do
local e = clone_list[i]
assert(e and not evo.empty(e))
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == false)
end
end
do
local entity_prefab = evo.builder():set(f1, 42):spawn()
evo.remove(entity_prefab, f2, f3)
local clone_list, clone_count = evo.multi_clone(2, entity_prefab, { [f1] = 21 })
assert(clone_list and #clone_list == 2)
assert(clone_count == 2)
for i = 1, clone_count do
local e = clone_list[i]
assert(e and not evo.empty(e))
assert(evo.has(e, f1) and evo.get(e, f1) == 21)
assert(evo.has(e, f2) and evo.get(e, f2) == false)
end
end
assert(v_set_sum == 42 * 6 + 21 * 2)
assert(v_insert_sum == 42 * 6 + 21 * 2)
assert(f3_set_times == 8)
assert(f3_insert_times == 8)
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 f1, f2, f3, f4 = evo.id(4)
evo.set(f1, evo.REQUIRES, { f2, f3, f4 })
local f1_default = v2(1, 2)
local f2_default = v2(3, 4)
local f3_default = v2(10, 11)
local f4_default = v2(12, 13)
evo.set(f1, evo.DEFAULT, f1_default)
evo.set(f2, evo.DEFAULT, f2_default)
evo.set(f3, evo.DEFAULT, f3_default)
evo.set(f4, evo.DEFAULT, f4_default)
evo.set(f1, evo.DUPLICATE, v2_clone)
evo.set(f2, evo.DUPLICATE, v2_clone)
evo.set(f3, evo.DUPLICATE, v2_clone)
do
local entity_list, entity_count = evo.multi_spawn(2, { [f1] = v2(5, 6), [f2] = v2(7, 8) })
assert(entity_list and #entity_list == 2)
assert(entity_count == 2)
for i = 1, entity_count do
local e = entity_list[i]
assert(e and not evo.empty(e))
assert(evo.has(e, f1) and evo.get(e, f1) ~= f1_default)
assert(evo.get(e, f1).x == 5 and evo.get(e, f1).y == 6)
assert(evo.has(e, f2) and evo.get(e, f2) ~= f2_default)
assert(evo.get(e, f2).x == 7 and evo.get(e, f2).y == 8)
assert(evo.has(e, f3) and evo.get(e, f3) ~= f3_default)
assert(evo.get(e, f3).x == 10 and evo.get(e, f3).y == 11)
assert(evo.has(e, f4) and evo.get(e, f4) == f4_default)
end
end
do
local entity_prefab = evo.builder():set(f1, v2(5, 6)):set(f2, v2(7, 8)):spawn()
local clone_list, clone_count = evo.multi_clone(2, entity_prefab, { [f2] = f2_default })
assert(clone_list and #clone_list == 2)
assert(clone_count == 2)
for i = 1, clone_count do
local e = clone_list[i]
assert(e and not evo.empty(e))
assert(evo.has(e, f1) and evo.get(e, f1) ~= f1_default and evo.get(e, f1) ~= evo.get(entity_prefab, f1))
assert(evo.get(e, f1).x == 5 and evo.get(e, f1).y == 6)
assert(evo.has(e, f2) and evo.get(e, f2) ~= f2_default and evo.get(e, f2) ~= evo.get(entity_prefab, f2))
assert(evo.get(e, f2).x == 3 and evo.get(e, f2).y == 4)
assert(evo.has(e, f3) and evo.get(e, f3) ~= f3_default)
assert(evo.get(e, f3).x == 10 and evo.get(e, f3).y == 11)
assert(evo.has(e, f4) and evo.get(e, f4) == f4_default)
end
end
do
local entity_prefab = evo.builder():set(f1, v2(5, 6)):set(f2, v2(7, 8)):spawn()
evo.remove(entity_prefab, f2, f3, f4)
local clone_list, clone_count = evo.multi_clone(2, entity_prefab, { [f2] = f2_default })
assert(clone_list and #clone_list == 2)
assert(clone_count == 2)
for i = 1, clone_count do
local e = clone_list[i]
assert(e and not evo.empty(e))
assert(evo.has(e, f1) and evo.get(e, f1) ~= f1_default and evo.get(e, f1) ~= evo.get(entity_prefab, f1))
assert(evo.get(e, f1).x == 5 and evo.get(e, f1).y == 6)
assert(evo.has(e, f2) and evo.get(e, f2) ~= f2_default and evo.get(e, f2) ~= evo.get(entity_prefab, f2))
assert(evo.get(e, f2).x == 3 and evo.get(e, f2).y == 4)
assert(evo.has(e, f3) and evo.get(e, f3) ~= f3_default)
assert(evo.get(e, f3).x == 10 and evo.get(e, f3).y == 11)
assert(evo.has(e, f4) and evo.get(e, f4) == f4_default)
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

@@ -0,0 +1,245 @@
local evo = require 'evolved'
do
local f1, f2 = evo.id(2)
evo.set(f1, evo.REQUIRES)
evo.set(f2, evo.REQUIRES, evo.get(f1, evo.REQUIRES))
local f1_rs = evo.get(f1, evo.REQUIRES)
local f2_rs = evo.get(f2, evo.REQUIRES)
assert(f1_rs and f2_rs and #f1_rs == 0 and #f2_rs == 0 and f1_rs ~= f2_rs)
end
do
local f1, f2 = evo.id(2)
local f3 = evo.builder():require(f1):require(f2):spawn()
local f3_rs = evo.get(f3, evo.REQUIRES)
assert(f3_rs and #f3_rs == 2 and f3_rs[1] == f1 and f3_rs[2] == f2)
end
do
local f1, f2 = evo.id(2)
local f3 = evo.builder():require(f1, f2):spawn()
local f3_rs = evo.get(f3, evo.REQUIRES)
assert(f3_rs and #f3_rs == 2 and f3_rs[1] == f1 and f3_rs[2] == f2)
end
do
local f1, f2, f3 = evo.id(3)
evo.set(f1, evo.REQUIRES, { f2 })
evo.set(f3, evo.REQUIRES, { f1, f2 })
do
local e = evo.id()
evo.set(e, f1)
assert(evo.has(e, f2))
assert(evo.get(e, f2) == true)
end
do
local e = evo.builder():set(f1):spawn()
assert(evo.has(e, f2))
assert(evo.get(e, f2) == true)
end
do
local e = evo.spawn { [f1] = true }
assert(evo.has(e, f2))
assert(evo.get(e, f2) == true)
evo.remove(e, f2)
assert(not evo.has(e, f2))
local e2 = evo.clone(e)
assert(evo.has(e2, f2))
assert(evo.get(e2, f2) == true)
local e3 = evo.clone(e, { [f3] = true })
assert(evo.has(e3, f2))
assert(evo.get(e3, f2) == true)
end
do
local f0 = evo.id()
local q0 = evo.builder():include(f0):spawn()
local e1 = evo.builder():set(f0):spawn()
local e2 = evo.builder():set(f0):spawn()
local e3 = evo.builder():set(f0):set(f2, false):spawn()
evo.batch_set(q0, f1)
assert(evo.has(e1, f2) and evo.get(e1, f2) == true)
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
assert(evo.has(e3, f2) and evo.get(e3, f2) == false)
end
end
do
local f1, f2, f3 = evo.id(3)
evo.set(f1, evo.REQUIRES, { f2 })
evo.set(f2, evo.DEFAULT, 42)
evo.set(f3, evo.REQUIRES, { f1, f2 })
do
local e = evo.id()
evo.set(e, f1)
assert(evo.has(e, f2))
assert(evo.get(e, f2) == 42)
end
do
local e = evo.builder():set(f1):spawn()
assert(evo.has(e, f2))
assert(evo.get(e, f2) == 42)
end
do
local e = evo.spawn { [f1] = true, }
assert(evo.has(e, f2))
assert(evo.get(e, f2) == 42)
evo.remove(e, f2)
assert(not evo.has(e, f2))
local e2 = evo.clone(e)
assert(evo.has(e2, f2))
assert(evo.get(e2, f2) == 42)
local e3 = evo.clone(e, { [f3] = true })
assert(evo.has(e3, f2))
assert(evo.get(e3, f2) == 42)
end
do
local f0 = evo.id()
local q0 = evo.builder():include(f0):spawn()
local e1 = evo.builder():set(f0):spawn()
local e2 = evo.builder():set(f0):spawn()
local e3 = evo.builder():set(f0):set(f2, 21):spawn()
evo.batch_set(q0, f1)
assert(evo.has(e1, f2) and evo.get(e1, f2) == 42)
assert(evo.has(e2, f2) and evo.get(e2, f2) == 42)
assert(evo.has(e3, f2) and evo.get(e3, f2) == 21)
end
end
do
local f1, f2, f3 = evo.id(3)
evo.set(f1, evo.REQUIRES, { f2 })
evo.set(f2, evo.REQUIRES, { f3 })
evo.set(f3, evo.DEFAULT, 42)
evo.set(f3, evo.REQUIRES, { f1, f2 })
do
local e = evo.id()
evo.set(e, f1)
assert(evo.has(e, f2))
assert(evo.get(e, f2) == true)
assert(evo.has(e, f3))
assert(evo.get(e, f3) == 42)
end
do
local e = evo.builder():set(f1):spawn()
assert(evo.has(e, f2))
assert(evo.get(e, f2) == true)
assert(evo.has(e, f3))
assert(evo.get(e, f3) == 42)
end
do
local e = evo.spawn { [f1] = true }
assert(evo.has(e, f2))
assert(evo.get(e, f2) == true)
assert(evo.has(e, f3))
assert(evo.get(e, f3) == 42)
evo.remove(e, f2, f3)
assert(not evo.has(e, f2))
assert(not evo.has(e, f3))
local e2 = evo.clone(e, { [f1] = 21 })
assert(evo.has(e2, f1) and evo.get(e2, f1) == 21)
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
assert(evo.has(e2, f3) and evo.get(e2, f3) == 42)
local e3 = evo.clone(e, { [f3] = 21 })
assert(evo.has(e3, f1) and evo.get(e3, f1) == true)
assert(evo.has(e3, f2) and evo.get(e3, f2) == true)
assert(evo.has(e3, f3) and evo.get(e3, f3) == 21)
end
end
do
local f1, f2, f3 = evo.id(3)
evo.set(f1, evo.REQUIRES, { f2 })
evo.set(f2, evo.REQUIRES, { f3 })
evo.set(f3, evo.REQUIRES, { f1, f2, f3 })
do
local e = evo.id()
evo.set(e, f1, 42)
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == true)
assert(evo.has(e, f3) and evo.get(e, f3) == true)
end
do
local e = evo.builder():set(f1, 42):spawn()
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == true)
assert(evo.has(e, f3) and evo.get(e, f3) == true)
end
do
local e = evo.spawn { [f1] = 42 }
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == true)
assert(evo.has(e, f3) and evo.get(e, f3) == true)
evo.remove(e, f2, f3)
assert(not evo.has(e, f2))
assert(not evo.has(e, f3))
local e2 = evo.clone(e, { [f1] = 21 })
assert(evo.has(e2, f1) and evo.get(e2, f1) == 21)
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
assert(evo.has(e2, f3) and evo.get(e2, f3) == true)
local e3 = evo.clone(e, { [f3] = 21 })
assert(evo.has(e3, f1) and evo.get(e3, f1) == 42)
assert(evo.has(e3, f2) and evo.get(e3, f2) == true)
assert(evo.has(e3, f3) and evo.get(e3, f3) == 21)
end
end
do
local f1, f2, f3, f4 = evo.id(4)
do
evo.set(f1, evo.REQUIRES, { f2 })
do
local e = evo.id()
evo.set(e, f1)
assert(evo.has(e, f2) and evo.get(e, f2) == true)
end
evo.set(f1, evo.REQUIRES, { f2, f3 })
do
local e = evo.id()
evo.set(e, f1)
assert(evo.has(e, f2) and evo.get(e, f2) == true)
assert(evo.has(e, f3) and evo.get(e, f3) == true)
end
evo.set(f3, evo.REQUIRES, { f4 })
do
local e = evo.id()
evo.set(e, f1)
assert(evo.has(e, f2) and evo.get(e, f2) == true)
assert(evo.has(e, f3) and evo.get(e, f3) == true)
assert(evo.has(e, f4) and evo.get(e, f4) == true)
end
end
end

View File

@@ -0,0 +1,329 @@
local evo = require 'evolved'
do
do
local e = evo.spawn()
assert(evo.alive(e) and evo.empty(e))
end
do
local e = evo.spawn({})
assert(evo.alive(e) and evo.empty(e))
end
end
do
local f1, f2, f3 = evo.id(3)
evo.set(f2, evo.REQUIRES, { f1, f3 })
do
local e = evo.spawn({ [f1] = 42 })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1))
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
end
do
local e = evo.spawn({ [f1] = 42, [f2] = 'hello' })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3))
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == 'hello')
assert(evo.has(e, f3) and evo.get(e, f3) == true)
end
end
do
local f1, f2, f3 = evo.id(3)
evo.set(f2, evo.REQUIRES, { f1, f3 })
evo.set(f3, evo.DEFAULT, 21)
evo.set(f3, evo.REQUIRES, { f2 })
do
local e = evo.spawn({ [f1] = 42 })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1))
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
end
do
local e = evo.spawn({ [f1] = 42, [f2] = 'hello' })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3))
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == 'hello')
assert(evo.has(e, f3) and evo.get(e, f3) == 21)
end
end
do
local f1, f2, f3, f4 = evo.id(4)
evo.set(f2, evo.DUPLICATE, function() return nil end)
evo.set(f2, evo.REQUIRES, { f1, f3, f4 })
evo.set(f3, evo.DEFAULT, 21)
evo.set(f3, evo.DUPLICATE, function(v) return v * 3 end)
evo.set(f3, evo.REQUIRES, { f2 })
do
local e = evo.spawn({ [f1] = 42 })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1))
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
end
do
local e = evo.spawn({ [f1] = 42, [f2] = true })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3, f4))
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
assert(evo.has(e, f2) and evo.get(e, f2) == true)
assert(evo.has(e, f3) and evo.get(e, f3) == 21 * 3)
assert(evo.has(e, f4) and evo.get(e, f4) == true)
end
end
do
local f1, f2, f3 = evo.id(3)
evo.set(f2, evo.REQUIRES, { f3 })
evo.set(f3, evo.TAG)
local f2_set_sum, f2_inserted_sum = 0, 0
local f3_set_count, f3_inserted_count = 0, 0
evo.set(f2, evo.ON_SET, function(e, f, c)
assert(c == 42)
assert(evo.get(e, f) == c)
assert(f == f2)
f2_set_sum = f2_set_sum + c
end)
evo.set(f2, evo.ON_INSERT, function(e, f, c)
assert(c == 42)
assert(evo.get(e, f) == c)
assert(f == f2)
f2_inserted_sum = f2_inserted_sum + c
end)
evo.set(f3, evo.ON_SET, function(e, f, c)
assert(c == nil)
assert(evo.get(e, f) == c)
assert(f == f3)
f3_set_count = f3_set_count + 1
end)
evo.set(f3, evo.ON_INSERT, function(e, f, c)
assert(c == nil)
assert(evo.get(e, f) == c)
assert(f == f3)
f3_inserted_count = f3_inserted_count + 1
end)
do
f3_set_count, f3_inserted_count = 0, 0
local e = evo.spawn({ [f1] = 'hello', [f2] = 42 })
assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3))
assert(f2_set_sum == 42 and f2_inserted_sum == 42)
assert(f3_set_count == 1 and f3_inserted_count == 1)
end
end
do
do
local es, ec = evo.multi_spawn(2)
assert(#es == 2 and ec == 2)
for i = 1, ec do
assert(evo.alive(es[i]) and evo.empty(es[i]))
end
end
do
local es, ec = evo.multi_spawn(2, {})
assert(#es == 2 and ec == 2)
for i = 1, ec do
assert(evo.alive(es[i]) and evo.empty(es[i]))
end
end
end
do
local f1, f2 = evo.id(2)
do
local es, ec = evo.multi_spawn(3, { [f1] = 42 })
assert(#es == 3 and ec == 3)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42)
end
end
do
local es, ec = evo.multi_spawn(3, { [f1] = 42, [f2] = 'hello' })
assert(#es == 3 and ec == 3)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42)
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'hello')
end
end
end
do
local f1, f2 = evo.id(2)
evo.set(f1, evo.REQUIRES, { f2 })
do
local es, ec = evo.multi_spawn(3, { [f1] = 42 })
assert(#es == 3 and ec == 3)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42)
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == true)
end
end
end
do
local f1, f2 = evo.id(2)
evo.set(f1, evo.REQUIRES, { f2 })
do
local es, ec = evo.multi_spawn(1, { [f1] = 42 })
assert(#es == 1 and ec == 1)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42)
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == true)
end
end
end
do
local f1, f2, f3 = evo.id(3)
evo.set(f1, evo.REQUIRES, { f2, f3 })
evo.set(f2, evo.DEFAULT, 'hello')
do
local es, ec = evo.multi_spawn(4, { [f1] = 42 })
assert(#es == 4 and ec == 4)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42)
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'hello')
assert(evo.has(es[i], f3) and evo.get(es[i], f3) == true)
end
end
do
local es, ec = evo.multi_spawn(4, { [f1] = 42, [f2] = 'world' })
assert(#es == 4 and ec == 4)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42)
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'world')
assert(evo.has(es[i], f3) and evo.get(es[i], f3) == true)
end
end
do
local es, ec = evo.multi_spawn(4, { [f1] = 42, [f2] = 'world', [f3] = false })
assert(#es == 4 and ec == 4)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42)
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'world')
assert(evo.has(es[i], f3) and evo.get(es[i], f3) == false)
end
end
end
do
local f1, f2 = evo.id(2)
evo.set(f1, evo.REQUIRES, { f2 })
evo.set(f1, evo.DUPLICATE, function() return nil end)
evo.set(f2, evo.DEFAULT, 'hello')
evo.set(f2, evo.DUPLICATE, function(v) return v .. '!' end)
do
local es, ec = evo.multi_spawn(4, { [f1] = 42 })
assert(#es == 4 and ec == 4)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == true)
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'hello!')
end
end
do
local es, ec = evo.multi_spawn(4, { [f1] = 42, [f2] = 'world' })
assert(#es == 4 and ec == 4)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2))
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == true)
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'world!')
end
end
do
local es, ec = evo.multi_spawn(4, { [f2] = 'hello world' })
assert(#es == 4 and ec == 4)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f2))
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'hello world!')
end
end
end
do
local f1, f2, f3 = evo.id(3)
evo.set(f2, evo.REQUIRES, { f3 })
evo.set(f3, evo.TAG)
local f2_set_sum, f2_inserted_sum = 0, 0
local f3_set_count, f3_inserted_count = 0, 0
evo.set(f2, evo.ON_SET, function(e, f, c)
assert(c == 42)
assert(evo.get(e, f) == c)
assert(f == f2)
f2_set_sum = f2_set_sum + c
end)
evo.set(f2, evo.ON_INSERT, function(e, f, c)
assert(c == 42)
assert(evo.get(e, f) == c)
assert(f == f2)
f2_inserted_sum = f2_inserted_sum + c
end)
evo.set(f3, evo.ON_SET, function(e, f, c)
assert(c == nil)
assert(evo.get(e, f) == c)
assert(f == f3)
f3_set_count = f3_set_count + 1
end)
evo.set(f3, evo.ON_INSERT, function(e, f, c)
assert(c == nil)
assert(evo.get(e, f) == c)
assert(f == f3)
f3_inserted_count = f3_inserted_count + 1
end)
do
local es, ec = evo.multi_spawn(3, { [f1] = 'hello', [f2] = 42 })
assert(#es == 3 and ec == 3)
for i = 1, ec do
assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3))
assert(f2_set_sum == 42 * 3 and f2_inserted_sum == 42 * 3)
assert(f3_set_count == 3 and f3_inserted_count == 3)
end
end
end

View File

@@ -0,0 +1,128 @@
local evo = require 'evolved'
do
local f1, f2, f3 = evo.id(3)
local q1e3 = evo.builder():include(f1):exclude(f3):spawn()
local q2e3 = evo.builder():include(f2):exclude(f3):spawn()
local e1 = evo.builder():set(f1, 1):spawn()
local e12 = evo.builder():set(f1, 11):set(f2, 12):spawn()
local e2 = evo.builder():set(f2, 2):spawn()
local e23 = evo.builder():set(f2, 23):set(f3, 3):spawn()
local c1 = evo.chunk(f1)
local c12 = evo.chunk(f1, f2)
local c2 = evo.chunk(f2)
do
local _, entity_list, entity_count = evo.chunk(f2, f3)
assert(entity_count == 1 and entity_list[1] == e23)
end
do
local entity_sum = 0
local s = evo.builder()
:query(q1e3)
:execute(function(chunk, entity_list, entity_count)
for i = 1, entity_count do
entity_sum = entity_sum + entity_list[i]
end
if chunk == c1 then
assert(entity_count == 1)
assert(entity_list[1] == e1)
elseif chunk == c12 then
assert(entity_count == 1)
assert(entity_list[1] == e12)
else
assert(false, "Unexpected chunk: " .. tostring(chunk))
end
end):spawn()
evo.process(s)
assert(entity_sum == e1 + e12)
end
do
local entity_sum = 0
local s = evo.builder()
:query(q2e3)
:execute(function(chunk, entity_list, entity_count)
for i = 1, entity_count do
entity_sum = entity_sum + entity_list[i]
end
if chunk == c12 then
assert(entity_count == 1)
assert(entity_list[1] == e12)
elseif chunk == c2 then
assert(entity_count == 1)
assert(entity_list[1] == e2)
else
assert(false, "Unexpected chunk: " .. tostring(chunk))
end
end):spawn()
evo.process(s)
assert(entity_sum == e12 + e2)
end
do
local entity_sum = 0
local s = evo.builder()
:include(f1)
:exclude(f3)
:execute(function(chunk, entity_list, entity_count)
for i = 1, entity_count do
entity_sum = entity_sum + entity_list[i]
end
if chunk == c1 then
assert(entity_count == 1)
assert(entity_list[1] == e1)
elseif chunk == c12 then
assert(entity_count == 1)
assert(entity_list[1] == e12)
else
assert(false, "Unexpected chunk: " .. tostring(chunk))
end
end):spawn()
evo.process(s)
assert(entity_sum == e1 + e12)
end
do
local entity_sum = 0
local s = evo.builder()
:include(f2)
:exclude(f3)
:execute(function(chunk, entity_list, entity_count)
for i = 1, entity_count do
entity_sum = entity_sum + entity_list[i]
end
if chunk == c12 then
assert(entity_count == 1)
assert(entity_list[1] == e12)
elseif chunk == c2 then
assert(entity_count == 1)
assert(entity_list[1] == e2)
else
assert(false, "Unexpected chunk: " .. tostring(chunk))
end
end):spawn()
evo.process(s)
assert(entity_sum == e12 + e2)
end
end

View File

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

View File

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

181
evolved.d.tl Normal file
View File

@@ -0,0 +1,181 @@
local record Evolved
interface Id end
type Entity = Id
type Fragment = Id
type Query = Id
type System = Id
interface EachState end
interface ExecuteState end
type EachIterator = function(state?: EachState): Fragment, any
type ExecuteIterator = function(state?: ExecuteState): Chunk, { Entity }, integer
interface Chunk
alive: function(self: Chunk): boolean
empty: function(self: Chunk): boolean
has: function(self: Chunk, fragment: Fragment): boolean
has_all: function(self: Chunk, ...: Fragment): boolean
has_any: function(self: Chunk, ...: Fragment): boolean
entities: function(self: Chunk): { Entity }, integer
fragments: function(self: Chunk): { Fragment }, integer
components: function(self: Chunk)
components: function<C1>(self: Chunk, f1: Fragment): { C1 }
components: function<C1, C2>(self: Chunk, f1: Fragment, f2: Fragment): { C1 }, { C2 }
components: function<C1, C2, C3>(self: Chunk, f1: Fragment, f2: Fragment, f3: Fragment): { C1 }, { C2 }, { C3 }
components: function<C1, C2, C3, C4>(self: Chunk, f1: Fragment, f2: Fragment, f3: Fragment, f4: Fragment): { C1 }, { C2 }, { C3 }, { C4 }
end
interface Builder
build: function(self: Builder, prefab?: Entity): Entity
multi_build: function(self: Builder, entity_count: integer, prefab?: Entity): { Entity }, integer
spawn: function(self: Builder): Entity
multi_spawn: function(self: Builder, entity_count: integer): { Entity }, integer
clone: function(self: Builder, prefab: Entity): Entity
multi_clone: function(self: Builder, entity_count: integer, prefab: Entity): { Entity }, integer
has: function(self: Builder, fragment: Fragment): boolean
has_all: function(self: Builder, ...: Fragment): boolean
has_any: function(self: Builder, ...: Fragment): boolean
get: function(self: Builder)
get: function<C1>(self: Builder, f1: Fragment): C1 | nil
get: function<C1, C2>(self: Builder, f1: Fragment, f2: Fragment): C1 | nil, C2 | nil
get: function<C1, C2, C3>(self: Builder, f1: Fragment, f2: Fragment, f3: Fragment): C1 | nil, C2 | nil, C3 | nil
get: function<C1, C2, C3, C4>(self: Builder, f1: Fragment, f2: Fragment, f3: Fragment, f4: Fragment): C1 | nil, C2 | nil, C3 | nil, C4 | nil
set: function<Component>(self: Builder, fragment: Fragment, component?: Component): Builder
remove: function(self: Builder, ...: Fragment): Builder
clear: function(self: Builder): Builder
tag: function(self: Builder): Builder
name: function(self: Builder, name: string): Builder
unique: function(self: Builder): Builder
explicit: function(self: Builder): Builder
internal: function(self: Builder): Builder
default: function<Component>(self: Builder, default: Component): Builder
duplicate: function<Component>(self: Builder, duplicate: function(Component): Component): Builder
prefab: function(self: Builder): Builder
disabled: function(self: Builder): Builder
include: function(self: Builder, ...: Fragment): Builder
exclude: function(self: Builder, ...: Fragment): Builder
require: function(self: Builder, ...: Fragment): Builder
on_set: function<Component>(self: Builder, on_set: function(Entity, Fragment, ? Component, ? Component)): Builder
on_assign: function<Component>(self: Builder, on_assign: function(Entity, Fragment, ? Component, ? Component)): Builder
on_insert: function<Component>(self: Builder, on_insert: function(Entity, Fragment, ? Component)): Builder
on_remove: function<Component>(self: Builder, on_remove: function(Entity, Fragment, ? Component)): Builder
group: function(self: Builder, group: System): Builder
query: function(self: Builder, query: Query): Builder
execute: function(self: Builder, execute: function(Chunk, {Entity}, integer)): Builder
prologue: function(self: Builder, prologue: function()): Builder
epilogue: function(self: Builder, epilogue: function()): Builder
destruction_policy: function(self: Builder, destruction_policy: Id): Builder
end
TAG: Fragment
NAME: Fragment
UNIQUE: Fragment
EXPLICIT: Fragment
INTERNAL: Fragment
DEFAULT: Fragment
DUPLICATE: Fragment
PREFAB: Fragment
DISABLED: Fragment
INCLUDES: Fragment
EXCLUDES: Fragment
REQUIRES: Fragment
ON_SET: Fragment
ON_ASSIGN: Fragment
ON_INSERT: Fragment
ON_REMOVE: Fragment
GROUP: Fragment
QUERY: Fragment
EXECUTE: Fragment
PROLOGUE: Fragment
EPILOGUE: Fragment
DESTRUCTION_POLICY: Fragment
DESTRUCTION_POLICY_DESTROY_ENTITY: Id
DESTRUCTION_POLICY_REMOVE_FRAGMENT: Id
id: function(count?: integer): Id...
name: function(...: Id): string...
pack: function(primary: integer, secondary: integer): Id
unpack: function(id: Id): integer, integer
defer: function(): boolean
commit: function(): boolean
cancel: function(): boolean
spawn: function(components?: { Fragment: any }): Entity
multi_spawn: function(entity_count: integer, components?: { Fragment: any }): { Entity }, integer
clone: function(prefab: Entity, components?: { Fragment: any }): Entity
multi_clone: function(entity_count: integer, prefab: Entity, components?: { Fragment: any }): { Entity }, integer
alive: function(entity: Entity): boolean
alive_all: function(...: Entity): boolean
alive_any: function(...: Entity): boolean
empty: function(entity: Entity): boolean
empty_all: function(...: Entity): boolean
empty_any: function(...: Entity): boolean
has: function(entity: Entity, fragment: Fragment): boolean
has_all: function(entity: Entity, ...: Fragment): boolean
has_any: function(entity: Entity, ...: Fragment): boolean
get: function(entity: Entity)
get: function<C1>(entity: Entity, f1: Fragment): C1 | nil
get: function<C1, C2>(entity: Entity, f1: Fragment, f2: Fragment): C1 | nil, C2 | nil
get: function<C1, C2, C3>(entity: Entity, f1: Fragment, f2: Fragment, f3: Fragment): C1 | nil, C2 | nil, C3 | nil
get: function<C1, C2, C3, C4>(entity: Entity, f1: Fragment, f2: Fragment, f3: Fragment, f4: Fragment): C1 | nil, C2 | nil, C3 | nil, C4 | nil
set: function<Component>(entity: Entity, fragment: Fragment, component?: Component)
remove: function(entity: Entity, ...: Fragment)
clear: function(...: Entity)
destroy: function(...: Entity)
batch_set: function<Component>(query: Query, fragment: Fragment, component?: Component)
batch_remove: function(query: Query, ...: Fragment)
batch_clear: function(...: Query)
batch_destroy: function(...: Query)
each: function(entity: Entity): EachIterator, EachState | nil
execute: function(query: Query): ExecuteIterator, ExecuteState | nil
locate: function(entity: Entity): Chunk | nil, integer
process: function(...: System)
debug_mode: function(yesno: boolean)
collect_garbage: function()
chunk: function(fragment: Fragment, ...: Fragment): Chunk, { Entity }, integer
builder: function(): Builder
end
return Evolved

File diff suppressed because it is too large Load Diff

10
example/conf.lua Normal file
View File

@@ -0,0 +1,10 @@
if os.getenv('LOCAL_LUA_DEBUGGER_VSCODE') == '1' then
require('lldebugger').start()
end
---@type love.conf
function love.conf(t)
t.window.title = 'Evolved Example'
t.window.width = 640
t.window.height = 480
end

173
example/main.lua Normal file
View File

@@ -0,0 +1,173 @@
local evolved = require 'evolved'
local STAGES = {
ON_SETUP = evolved.builder()
:name('STAGES.ON_SETUP')
:build(),
ON_UPDATE = evolved.builder()
:name('STAGES.ON_UPDATE')
:build(),
ON_RENDER = evolved.builder()
:name('STAGES.ON_RENDER')
:build(),
}
local UNIFORMS = {
DELTA_TIME = 1.0 / 60.0,
}
local FRAGMENTS = {
POSITION_X = evolved.builder()
:name('FRAGMENTS.POSITION_X')
:default(0)
:build(),
POSITION_Y = evolved.builder()
:name('FRAGMENTS.POSITION_Y')
:default(0)
:build(),
VELOCITY_X = evolved.builder()
:name('FRAGMENTS.VELOCITY_X')
:default(0)
:build(),
VELOCITY_Y = evolved.builder()
:name('FRAGMENTS.VELOCITY_Y')
:default(0)
:build(),
}
local PREFABS = {
CIRCLE = evolved.builder()
:name('PREFABS.CIRCLE')
:prefab()
:set(FRAGMENTS.POSITION_X)
:set(FRAGMENTS.POSITION_Y)
:set(FRAGMENTS.VELOCITY_X)
:set(FRAGMENTS.VELOCITY_Y)
:build(),
}
---
---
---
---
---
evolved.builder()
:name('SYSTEMS.STARTUP')
:group(STAGES.ON_SETUP)
:prologue(function()
local screen_width, screen_height = love.graphics.getDimensions()
local circle_list, circle_count = evolved.multi_clone(100, PREFABS.CIRCLE)
for i = 1, circle_count do
local circle = circle_list[i]
local px = math.random() * screen_width
local py = math.random() * screen_height
local vx = math.random(-100, 100)
local vy = math.random(-100, 100)
evolved.set(circle, FRAGMENTS.POSITION_X, px)
evolved.set(circle, FRAGMENTS.POSITION_Y, py)
evolved.set(circle, FRAGMENTS.VELOCITY_X, vx)
evolved.set(circle, FRAGMENTS.VELOCITY_Y, vy)
end
end):build()
evolved.builder()
:name('SYSTEMS.MOVEMENT')
:group(STAGES.ON_UPDATE)
:include(FRAGMENTS.POSITION_X, FRAGMENTS.POSITION_Y)
:include(FRAGMENTS.VELOCITY_X, FRAGMENTS.VELOCITY_Y)
:execute(function(chunk, _, entity_count)
local delta_time = UNIFORMS.DELTA_TIME
local screen_width, screen_height = love.graphics.getDimensions()
---@type number[], number[]
local position_xs, position_ys = chunk:components(
FRAGMENTS.POSITION_X, FRAGMENTS.POSITION_Y)
---@type number[], number[]
local velocity_xs, velocity_ys = chunk:components(
FRAGMENTS.VELOCITY_X, FRAGMENTS.VELOCITY_Y)
for i = 1, entity_count do
local px, py = position_xs[i], position_ys[i]
local vx, vy = velocity_xs[i], velocity_ys[i]
px = px + vx * delta_time
py = py + vy * delta_time
if px < 0 and vx < 0 then
vx = -vx
elseif px > screen_width and vx > 0 then
vx = -vx
end
if py < 0 and vy < 0 then
vy = -vy
elseif py > screen_height and vy > 0 then
vy = -vy
end
position_xs[i], position_ys[i] = px, py
velocity_xs[i], velocity_ys[i] = vx, vy
end
end):build()
evolved.builder()
:name('SYSTEMS.RENDERING')
:group(STAGES.ON_RENDER)
:include(FRAGMENTS.POSITION_X, FRAGMENTS.POSITION_Y)
:execute(function(chunk, _, entity_count)
---@type number[], number[]
local position_xs, position_ys = chunk:components(
FRAGMENTS.POSITION_X, FRAGMENTS.POSITION_Y)
for i = 1, entity_count do
local x, y = position_xs[i], position_ys[i]
love.graphics.circle('fill', x, y, 10)
end
end):build()
evolved.builder()
:name('SYSTEMS.DEBUGGING')
:group(STAGES.ON_RENDER)
:epilogue(function()
local fps = love.timer.getFPS()
local mem = collectgarbage('count')
love.graphics.print(string.format('FPS: %d', fps), 10, 10)
love.graphics.print(string.format('MEM: %d KB', mem), 10, 30)
end):build()
---
---
---
---
---
---@type love.load
function love.load()
evolved.process(STAGES.ON_SETUP)
end
---@type love.update
function love.update(dt)
UNIFORMS.DELTA_TIME = dt
evolved.process(STAGES.ON_UPDATE)
end
---@type love.draw
function love.draw()
evolved.process(STAGES.ON_RENDER)
end
---@type love.keypressed
function love.keypressed(key)
if key == 'escape' then
love.event.quit()
end
end

View File

@@ -0,0 +1,34 @@
rockspec_format = "3.0"
package = "evolved.lua"
version = "1.1.0-0"
source = {
url = "git://github.com/BlackMATov/evolved.lua",
tag = "v1.1.0",
}
description = {
homepage = "https://github.com/BlackMATov/evolved.lua",
summary = "Evolved ECS (Entity-Component-System) for Lua",
detailed = [[
`evolved.lua` is a fast and flexible ECS (Entity-Component-System) library for Lua.
It is designed to be simple and easy to use, while providing all the features needed to create complex systems with blazing performance.
]],
license = "MIT",
labels = {
"ecs",
"entity",
"entities",
"component",
"components",
"entity-component",
"entity-component-system",
},
}
dependencies = {
"lua >= 5.1",
}
build = {
type = "builtin",
modules = {
evolved = "evolved.lua",
}
}

View File

@@ -0,0 +1,34 @@
rockspec_format = "3.0"
package = "evolved.lua"
version = "1.2.0-0"
source = {
url = "git://github.com/BlackMATov/evolved.lua",
tag = "v1.2.0",
}
description = {
homepage = "https://github.com/BlackMATov/evolved.lua",
summary = "Evolved ECS (Entity-Component-System) for Lua",
detailed = [[
`evolved.lua` is a fast and flexible ECS (Entity-Component-System) library for Lua.
It is designed to be simple and easy to use, while providing all the features needed to create complex systems with blazing performance.
]],
license = "MIT",
labels = {
"ecs",
"entity",
"entities",
"component",
"components",
"entity-component",
"entity-component-system",
},
}
dependencies = {
"lua >= 5.1",
}
build = {
type = "builtin",
modules = {
evolved = "evolved.lua",
}
}

View File

@@ -0,0 +1,34 @@
rockspec_format = "3.0"
package = "evolved.lua"
version = "1.3.0-0"
source = {
url = "git://github.com/BlackMATov/evolved.lua",
tag = "v1.3.0",
}
description = {
homepage = "https://github.com/BlackMATov/evolved.lua",
summary = "Evolved ECS (Entity-Component-System) for Lua",
detailed = [[
`evolved.lua` is a fast and flexible ECS (Entity-Component-System) library for Lua.
It is designed to be simple and easy to use, while providing all the features needed to create complex systems with blazing performance.
]],
license = "MIT",
labels = {
"ecs",
"entity",
"entities",
"component",
"components",
"entity-component",
"entity-component-system",
},
}
dependencies = {
"lua >= 5.1",
}
build = {
type = "builtin",
modules = {
evolved = "evolved.lua",
}
}

View File

@@ -0,0 +1,34 @@
rockspec_format = "3.0"
package = "evolved.lua"
version = "1.4.0-0"
source = {
url = "git://github.com/BlackMATov/evolved.lua",
tag = "v1.4.0",
}
description = {
homepage = "https://github.com/BlackMATov/evolved.lua",
summary = "Evolved ECS (Entity-Component-System) for Lua",
detailed = [[
`evolved.lua` is a fast and flexible ECS (Entity-Component-System) library for Lua.
It is designed to be simple and easy to use, while providing all the features needed to create complex systems with blazing performance.
]],
license = "MIT",
labels = {
"ecs",
"entity",
"entities",
"component",
"components",
"entity-component",
"entity-component-system",
},
}
dependencies = {
"lua >= 5.1",
}
build = {
type = "builtin",
modules = {
evolved = "evolved.lua",
}
}

View File

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