73 Commits

Author SHA1 Message Date
BlackMATov
c29092c3e1 update embedded xpcall.lua to v1.0.1 2026-01-04 09:32:08 +07:00
BlackMATov
a0a4a20c35 Happy New Year! 🥳 2026-01-03 15:52:01 +07:00
BlackMATov
2f8b0b0ef3 Merge branch 'feature/process_with' into dev
https://github.com/BlackMATov/evolved.lua/issues/34
2026-01-03 15:48:40 +07:00
BlackMATov
5e0170b4e8 new evolved.process_with function impl 2026-01-03 15:42:59 +07:00
BlackMATov
d42c0cf3db v1.6.0 2025-12-28 06:46:15 +07:00
BlackMATov
723a65ca7f added the new evolved.depth function 2025-12-28 06:36:11 +07:00
BlackMATov
72fc524fe0 little style fixes 2025-12-28 06:02:28 +07:00
BlackMATov
a8d1d84bed add more lua versions to CI 2025-12-25 16:02:27 +07:00
BlackMATov
568cec4012 table.new/create cleanup 2025-12-25 15:55:15 +07:00
BlackMATov
f175a25f1a little style fixes 2025-12-24 15:03:45 +07:00
BlackMATov
856b9c665d update changelog 2025-12-18 01:27:35 +07:00
BlackMATov
8e2a34f2f6 optimize setting of fragments with required fragments 2025-12-18 00:14:10 +07:00
BlackMATov
47dd1bb30a optimize spawning/cloning of entities with required fragments 2025-12-17 07:31:32 +07:00
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
2903b077fe Merge pull request #24 from BlackMATov/dev
Dev
2025-09-26 17:30:35 +07:00
7b6ac89c8a Merge pull request #21 from BlackMATov/dev
Dev
2025-09-12 05:30:07 +07:00
6bf13890ef Merge pull request #14 from BlackMATov/dev
Dev
2025-06-06 21:28:17 +07:00
db191b805f Merge pull request #13 from BlackMATov/dev
Dev
2025-05-23 20:07:43 +07:00
5ab963022c Merge pull request #12 from BlackMATov/dev
Dev
2025-05-21 20:48:59 +07:00
7de95207d6 Merge pull request #11 from BlackMATov/dev
Dev
2025-05-21 17:34:13 +07:00
4d3b909efb Merge pull request #10 from BlackMATov/dev
Dev
2025-05-21 06:20:38 +07:00
52b3cbeb20 Merge pull request #9 from BlackMATov/dev
Dev
2025-05-21 03:38:16 +07:00
fec193f4f0 Merge pull request #8 from BlackMATov/dev
Dev
2025-05-21 02:11:39 +07:00
e672b0291a Merge pull request #7 from BlackMATov/dev
Dev
2025-05-02 07:28:38 +07:00
4624f2e603 Merge pull request #6 from BlackMATov/dev
Dev
2025-04-30 23:47:13 +07:00
c25769f64f Merge pull request #5 from BlackMATov/dev
Dev
2025-04-19 18:40:25 +07:00
d7274765cb Merge pull request #4 from BlackMATov/dev
Dev
2025-04-09 03:04:19 +07:00
ef033e7a0c Merge pull request #3 from BlackMATov/dev
Dev
2025-04-09 00:58:14 +07:00
3638dedca5 Merge pull request #2 from BlackMATov/dev
Dev
2025-04-06 21:27:33 +07:00
d025ea039b Merge pull request #1 from BlackMATov/dev
Dev
2025-04-05 02:12:18 +07:00
BlackMATov
6c0df71f17 Merge branch 'dev' 2025-03-27 15:36:58 +07:00
BlackMATov
730bffc3ad Merge branch 'dev' 2025-03-19 06:52:10 +07:00
BlackMATov
4bbd7ee60a Merge branch 'dev' 2025-03-18 07:08:27 +07:00
BlackMATov
79aecc8db3 Merge branch 'dev' 2025-03-17 00:23:36 +07:00
BlackMATov
b803faea63 Merge branch 'dev' 2025-03-16 07:46:26 +07:00
BlackMATov
722eda0b9b Merge branch 'dev' 2025-03-16 02:06:17 +07:00
BlackMATov
c6def51830 Merge branch 'dev' 2025-03-10 08:14:38 +07:00
BlackMATov
65312f79dd Merge branch 'dev' 2025-03-08 06:07:06 +07:00
BlackMATov
9877e41705 Merge branch 'dev' 2025-03-02 12:09:33 +07:00
BlackMATov
3b8367d5c4 Merge branch 'dev' 2025-02-24 06:06:26 +07:00
BlackMATov
419a6b6c45 Merge branch 'dev' 2025-02-23 03:54:56 +07:00
BlackMATov
368b50770c Merge branch 'dev' 2025-02-22 00:31:27 +07:00
BlackMATov
0d49802235 Merge branch 'dev' 2025-02-08 04:52:56 +07:00
BlackMATov
f096d747f3 Merge branch 'dev' 2025-01-31 22:14:13 +07:00
BlackMATov
4d88063c10 Merge branch 'dev' 2025-01-31 12:51:30 +07:00
BlackMATov
bf135534c0 Merge branch 'dev' 2025-01-25 08:37:55 +07:00
BlackMATov
177ea7f180 Merge branch 'dev' 2025-01-21 10:52:19 +07:00
BlackMATov
b98b5f9c42 Merge branch 'dev' 2025-01-18 01:39:27 +07:00
BlackMATov
c7120e8608 opt: get chunk by fragments without sorting 2025-01-16 06:42:03 +07:00
29 changed files with 3616 additions and 1284 deletions

View File

@@ -14,7 +14,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
- uses: leafo/gh-actions-lua@v11
- uses: leafo/gh-actions-lua@v12
with:
luaVersion: ${{matrix.lua_version}}
- run: |

21
.github/workflows/lua5.2.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: lua5.2
on: [push, pull_request]
jobs:
build:
runs-on: ${{matrix.operating_system}}
strategy:
fail-fast: false
matrix:
lua_version: ["5.2"]
operating_system: ["ubuntu-latest", "macos-latest", "windows-latest"]
name: ${{matrix.operating_system}}-${{matrix.lua_version}}
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
- uses: leafo/gh-actions-lua@v12
with:
luaVersion: ${{matrix.lua_version}}
- run: |
lua ./develop/all.lua

21
.github/workflows/lua5.3.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: lua5.3
on: [push, pull_request]
jobs:
build:
runs-on: ${{matrix.operating_system}}
strategy:
fail-fast: false
matrix:
lua_version: ["5.3"]
operating_system: ["ubuntu-latest", "macos-latest", "windows-latest"]
name: ${{matrix.operating_system}}-${{matrix.lua_version}}
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
- uses: leafo/gh-actions-lua@v12
with:
luaVersion: ${{matrix.lua_version}}
- run: |
lua ./develop/all.lua

View File

@@ -14,7 +14,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
- uses: leafo/gh-actions-lua@v11
- uses: leafo/gh-actions-lua@v12
with:
luaVersion: ${{matrix.lua_version}}
- run: |

View File

@@ -14,7 +14,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
- uses: leafo/gh-actions-lua@v11
- uses: leafo/gh-actions-lua@v12
with:
luaVersion: ${{matrix.lua_version}}
- run: |

View File

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

38
.vscode/launch.json vendored
View File

@@ -10,6 +10,24 @@
"file": "${workspaceFolder}/develop/all.lua"
}
},
{
"name": "Launch Evolved All (lua5.2)",
"type": "lua-local",
"request": "launch",
"program": {
"lua": "lua5.2",
"file": "${workspaceFolder}/develop/all.lua"
}
},
{
"name": "Launch Evolved All (lua5.3)",
"type": "lua-local",
"request": "launch",
"program": {
"lua": "lua5.3",
"file": "${workspaceFolder}/develop/all.lua"
}
},
{
"name": "Launch Evolved All (lua5.4)",
"type": "lua-local",
@@ -19,6 +37,15 @@
"file": "${workspaceFolder}/develop/all.lua"
}
},
{
"name": "Launch Evolved All (lua5.5)",
"type": "lua-local",
"request": "launch",
"program": {
"lua": "lua5.5",
"file": "${workspaceFolder}/develop/all.lua"
}
},
{
"name": "Launch Evolved All (luajit)",
"type": "lua-local",
@@ -27,6 +54,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,5 +1,5 @@
{
"[json][jsonc][lua][markdown][yaml]": {
"[json][jsonc][lua][markdown][teal][yaml]": {
"editor.formatOnSave": true,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (C) 2024-2025, by Matvey Cherevko (blackmatov@gmail.com)
Copyright (C) 2024-2026, by Matvey Cherevko (blackmatov@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

105
README.md
View File

@@ -43,11 +43,13 @@
- [Deferred Operations](#deferred-operations)
- [Batch Operations](#batch-operations)
- [Systems](#systems)
- [Processing Payloads](#processing-payloads)
- [Predefined Traits](#predefined-traits)
- [Fragment Tags](#fragment-tags)
- [Fragment Hooks](#fragment-hooks)
- [Unique Fragments](#unique-fragments)
- [Explicit Fragments](#explicit-fragments)
- [Internal Fragments](#internal-fragments)
- [Shared Components](#shared-components)
- [Fragment Requirements](#fragment-requirements)
- [Destruction Policies](#destruction-policies)
@@ -59,7 +61,10 @@
- [Chunk](#chunk)
- [Builder](#builder)
- [Changelog](#changelog)
- [vX.X.X](#vxxx)
- [vX.Y.Z](#vxyz)
- [v1.6.0](#v160)
- [v1.5.0](#v150)
- [v1.4.0](#v140)
- [v1.3.0](#v130)
- [v1.2.0](#v120)
- [v1.1.0](#v110)
@@ -102,7 +107,7 @@ luarocks install evolved.lua
## Quick Start
To get started with `evolved.lua`, read the [Overview](#overview) section to understand the basic concepts and how to use the library. After that, check the [Samples](develop/samples), which demonstrate complex usage of the library. Finally, refer to the [Cheat Sheet](#cheat-sheet) for a quick reference of all the functions and classes provided by the library.
To get started with `evolved.lua`, read the [Overview](#overview) section to understand the basic concepts and how to use the library. After that, check the [Example](example), which demonstrate complex usage of the library. Finally, refer to the [Cheat Sheet](#cheat-sheet) for a quick reference of all the functions and classes provided by the library.
## Overview
@@ -641,6 +646,10 @@ Now we know that structural changes are not allowed during iteration, but what i
---@return boolean started
function evolved.defer() end
---@return integer depth
---@nodiscard
function evolved.depth() end
---@return boolean committed
function evolved.commit() end
@@ -648,7 +657,7 @@ function evolved.commit() end
function evolved.cancel() end
```
The [`evolved.defer`](#evolveddefer) function starts a deferred scope. This means that all changes made inside the scope will be queued and applied after leaving the scope. The [`evolved.commit`](#evolvedcommit) function closes the last deferred scope and applies all queued changes. These functions can be nested, so you can start a new deferred scope inside an existing one. The [`evolved.commit`](#evolvedcommit) function will apply all queued changes only when the last deferred scope is closed.
The [`evolved.defer`](#evolveddefer) function starts a deferred scope. This means that all changes made inside the scope will be queued and applied after leaving the scope. The [`evolved.commit`](#evolvedcommit) function closes the last deferred scope and applies all queued changes. These functions can be nested, so you can start a new deferred scope inside an existing one. The [`evolved.commit`](#evolvedcommit) function will apply all queued changes only when the last deferred scope is closed. The [`evolved.depth`](#evolveddepth) function returns the current depth of deferred scopes. If there are no deferred scopes, it returns `0`.
```lua
local evolved = require 'evolved'
@@ -873,6 +882,43 @@ The prologue and epilogue fragments do not require an explicit query. They will
> [!NOTE]
> And one more thing about systems. Execution callbacks are called in the [deferred scope](#deferred-operations), which means that all modifying operations inside the callback will be queued and applied after the system has processed all chunks. But prologue and epilogue callbacks are not called in the deferred scope, so all modifying operations inside them will be applied immediately. This is done to avoid confusion and to make it clear that prologue and epilogue callbacks are not part of the chunk processing.
#### Processing Payloads
Additionally, systems can have a payload that will be passed to the execution, prologue, and epilogue callbacks. This is useful for passing additional data to the system without using global variables or closures.
```lua
---@param system evolved.system
---@param ... any processing payload
function evolved.process_with(system, ...) end
```
The [`evolved.process_with`](#evolvedprocess_with) function is similar to the [`evolved.process`](#evolvedprocess) function, but it takes a processing payload as additional arguments. These arguments will be passed to the system's callbacks.
```lua
local evolved = require 'evolved'
local position_x, position_y = evolved.id(2)
local velocity_x, velocity_y = evolved.id(2)
local physics_system = evolved.builder()
:include(position_x, position_y)
:include(velocity_x, velocity_y)
:execute(function(chunk, entity_list, entity_count, delta_time)
local px, py = chunk:components(position_x, position_y)
local vx, vy = chunk:components(velocity_x, velocity_y)
for i = 1, entity_count do
px[i] = px[i] + vx[i] * delta_time
py[i] = py[i] + vy[i] * delta_time
end
end):build()
local delta_time = 0.016
evolved.process_with(physics_system, delta_time)
```
`delta_time` in this example is passed as a processing payload to the system's execution callback. Payloads can be of any type and can be multiple values. Also, payloads are passed to prologue and epilogue callbacks if they are defined. Every subsystem in a group will receive the same payload when the group is processed with [`evolved.process_with`](#evolvedprocess_with).
### Predefined Traits
#### Fragment Tags
@@ -964,6 +1010,10 @@ local all_enemies_including_disabled = evolved.builder()
:build()
```
#### Internal Fragments
All predefined fragments provided by the library are marked as internal with the [`evolved.INTERNAL`](#evolvedinternal) trait. Because [`evolved.INTERNAL`](#evolvedinternal) is itself marked as [`evolved.EXPLICIT`](#evolvedexplicit), these fragments are hidden from queries by default. This prevents accidental use of internal fragments in user code and helps distinguish them from user-defined fragments.
#### Shared Components
Often, we want to store components as tables, and by default, these tables will be shared between entities. This means that if you modify the table in one entity, it will be modified in all entities that share this table. Sometimes this is what we want. For example, when we want to share a configuration or some resource between entities. But in other cases, we want each entity to have its own copy of the table. For example, if we want to store the position of an entity as a table, we don't want to share this table with other entities. Yes, we can copy the table manually, but the library provides a little bit of syntactic sugar for this.
@@ -1114,9 +1164,9 @@ storage :: component[]
default :: component
duplicate :: {component -> component}
execute :: {chunk, entity[], integer}
prologue :: {}
epilogue :: {}
execute :: {chunk, entity[], integer, any...}
prologue :: {any...}
epilogue :: {any...}
set_hook :: {entity, fragment, component, component}
assign_hook :: {entity, fragment, component, component}
@@ -1178,6 +1228,7 @@ pack :: integer, integer -> id
unpack :: id -> integer, integer
defer :: boolean
depth :: integer
commit :: boolean
cancel :: boolean
@@ -1217,6 +1268,7 @@ execute :: query -> {execute_state? -> chunk?, entity[]?, integer?}, execute_sta
locate :: entity -> chunk?, integer
process :: system... -> ()
process_with :: system, ... -> ()
debug_mode :: boolean -> ()
collect_garbage :: ()
@@ -1290,17 +1342,32 @@ builder_mt:on_remove :: {entity, fragment} -> builder
builder_mt:group :: system -> builder
builder_mt:query :: query -> builder
builder_mt:execute :: {chunk, entity[], integer} -> builder
builder_mt:execute :: {chunk, entity[], integer, any...} -> builder
builder_mt:prologue :: {} -> builder
builder_mt:epilogue :: {} -> builder
builder_mt:prologue :: {any...} -> builder
builder_mt:epilogue :: {any...} -> builder
builder_mt:destruction_policy :: id -> builder
```
## Changelog
### vX.X.X
### vX.Y.Z
- Added the new [`evolved.process_with`](#evolvedprocess_with) function that allows passing payloads to processing systems
### v1.6.0
- Significant performance improvements of the [`evolved.REQUIRES`](#evolvedrequires) fragment trait
- Added the new [`evolved.depth`](#evolveddepth) function that returns the current depth of deferred scopes
### v1.5.0
- Added a little [LÖVE](https://love2d.org) example
- The spawn and clone operations with defaults have been significantly optimized
- Added basic [Teal](https://github.com/teal-language) type definitions, thanks to [@p0sel0k](https://github.com/p0sel0k)
### v1.4.0
- Improved query execution performance by caching some internal calculations
- Added the universal [`builder.build`](#evolvedbuilder_mtbuild) and [`builder.multi_build`](#evolvedbuilder_mtmulti_build) methods that can be used to spawn or clone entities depending on the method arguments
@@ -1434,6 +1501,14 @@ function evolved.unpack(id) end
function evolved.defer() end
```
### `evolved.depth`
```lua
---@return integer depth
---@nodiscard
function evolved.depth() end
```
### `evolved.commit`
```lua
@@ -1679,6 +1754,14 @@ function evolved.locate(entity) end
function evolved.process(...) end
```
### `evolved.process_with`
```lua
---@param system evolved.system
---@param ... any processing payload
function evolved.process_with(system, ...) end
```
### `evolved.debug_mode`
```lua
@@ -1939,7 +2022,7 @@ function evolved.builder_mt:internal() end
#### `evolved.builder_mt:default`
```lua
---@param default evolved.component
---@param default evolved.default
---@return evolved.builder builder
function evolved.builder_mt:default(default) end
```

View File

@@ -17,6 +17,7 @@
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`.
4. Update the Teal type definitions in `evolved.d.tl`.
5. Document the function in the **Cheat Sheet** and **API Reference** sections of `README.md`.
6. Provide a description in the **Overview** section of `README.md`.
7. Describe the update in the **Changelog** section of `README.md`.

View File

@@ -9,10 +9,8 @@
## 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.
- 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,12 +1,15 @@
require 'develop.samples.systems'
require 'develop.testing.build_tests'
require 'develop.testing.cancel_tests'
require 'develop.testing.clone_tests'
require 'develop.testing.depth_tests'
require 'develop.testing.destroy_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.process_with_tests'
require 'develop.testing.requires_fragment_tests'
require 'develop.testing.spawn_tests'
require 'develop.testing.system_as_query_tests'
require 'develop.benchmarks.clone_bmarks'

View File

@@ -6,16 +6,35 @@ 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)
local Q1 = evo.builder():include(F1):spawn()
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)
local R1 = evo.builder():require(F1):spawn()
local R3 = evo.builder():require(F1, F2, F3):spawn()
local R5 = evo.builder():require(F1, F2, F3, F4, F5):spawn()
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),
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone | %d entities with 1 component', N),
function()
local clone = evo.clone
@@ -25,10 +44,41 @@ basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entitie
clone(prefab)
end
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entities with 3 components', N),
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
@@ -38,10 +88,41 @@ basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entitie
clone(prefab)
end
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entities with 5 components', N),
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
@@ -51,53 +132,180 @@ basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entitie
clone(prefab)
end
evo.batch_destroy(Q1)
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),
basics.describe_bench(
string.format('Clone Benchmarks: Simple Clone | %d entities with 1 required component', N),
function()
local clone = evo.clone
local prefab = evo.spawn { [R1] = true }
local prefab = evo.spawn { [RF1] = true }
evo.remove(prefab, F1)
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entities with 3 required components', N),
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 { [R3] = true }
local prefab = evo.spawn { [RF1] = true }
evo.defer()
for _ = 1, N do
clone(prefab)
end
evo.commit()
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Simple Clone | %d entities with 5 required components', N),
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 { [R5] = true }
local prefab = evo.spawn { [RD1] = true }
for _ = 1, N do
clone(prefab)
end
evo.batch_destroy(Q1)
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 }
evo.remove(prefab, F1, F2, F3)
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 }
evo.remove(prefab, F1, F2, F3, F4, F5)
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),
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone | %d entities with 1 component', N),
function()
local multi_clone = evo.multi_clone
@@ -105,10 +313,37 @@ basics.describe_bench(string.format('Clone Benchmarks: Multi Clone | %d entities
multi_clone(N, prefab)
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Multi Clone | %d entities with 3 components', N),
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
@@ -116,10 +351,37 @@ basics.describe_bench(string.format('Clone Benchmarks: Multi Clone | %d entities
multi_clone(N, prefab)
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Multi Clone | %d entities with 5 components', N),
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
@@ -127,40 +389,147 @@ basics.describe_bench(string.format('Clone Benchmarks: Multi Clone | %d entities
multi_clone(N, prefab)
evo.batch_destroy(Q1)
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),
basics.describe_bench(
string.format('Clone Benchmarks: Multi Clone | %d entities with 1 required component', N),
function()
local multi_clone = evo.multi_clone
local prefab = evo.spawn { [R1] = true }
local prefab = evo.spawn { [RF1] = true }
multi_clone(N, prefab)
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Multi Clone | %d entities with 3 required components', N),
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 { [R3] = true }
local prefab = evo.spawn { [RF1] = true }
evo.defer()
multi_clone(N, prefab)
evo.commit()
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Clone Benchmarks: Multi Clone | %d entities with 5 required components', N),
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 { [R5] = true }
local prefab = evo.spawn { [RD1] = true }
multi_clone(N, prefab)
evo.batch_destroy(Q1)
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

@@ -6,16 +6,35 @@ 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)
local Q1 = evo.builder():include(F1):spawn()
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)
local R1 = evo.builder():require(F1):spawn()
local R3 = evo.builder():require(F1, F2, F3):spawn()
local R5 = evo.builder():require(F1, F2, F3, F4, F5):spawn()
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),
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn | %d entities with 1 component', N),
function()
local spawn = evo.spawn
@@ -25,10 +44,41 @@ basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entitie
spawn(components)
end
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entities with 3 components', N),
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
@@ -38,10 +88,41 @@ basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entitie
spawn(components)
end
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entities with 5 components', N),
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
@@ -51,53 +132,177 @@ basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entitie
spawn(components)
end
evo.batch_destroy(Q1)
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),
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Spawn | %d entities with 1 required component', N),
function()
local spawn = evo.spawn
local components = { [R1] = true }
local components = { [RF1] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entities with 3 required components', N),
basics.describe_bench(
string.format('Spawn Benchmarks: Simple Defer Spawn | %d entities with 1 required component', N),
function()
local spawn = evo.spawn
local components = { [R3] = true }
local components = { [RF1] = true }
evo.defer()
for _ = 1, N do
spawn(components)
end
evo.commit()
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Simple Spawn | %d entities with 5 required components', N),
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 = { [R5] = true }
local components = { [RD1] = true }
for _ = 1, N do
spawn(components)
end
evo.batch_destroy(Q1)
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),
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn | %d entities with 1 component', N),
function()
local builder = evo.builder():set(F1)
@@ -105,10 +310,37 @@ basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entiti
builder:spawn()
end
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entities with 3 components', N),
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)
@@ -116,10 +348,37 @@ basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entiti
builder:spawn()
end
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entities with 5 components', N),
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)
@@ -127,47 +386,155 @@ basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entiti
builder:spawn()
end
evo.batch_destroy(Q1)
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),
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn | %d entities with 1 required component', N),
function()
local builder = evo.builder():set(R1)
local builder = evo.builder():set(RF1)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entities with 3 required components', N),
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Defer Spawn | %d entities with 1 required component', N),
function()
local builder = evo.builder():set(R3)
local builder = evo.builder():set(RF1)
evo.defer()
for _ = 1, N do
builder:spawn()
end
evo.commit()
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Builder Spawn | %d entities with 5 required components', N),
basics.describe_bench(
string.format('Spawn Benchmarks: Builder Spawn With Defaults | %d entities with 1 required component', N),
function()
local builder = evo.builder():set(R5)
local builder = evo.builder():set(RD1)
for _ = 1, N do
builder:spawn()
end
evo.batch_destroy(Q1)
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),
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn | %d entities with 1 component', N),
function()
local multi_spawn = evo.multi_spawn
@@ -175,10 +542,37 @@ basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities
multi_spawn(N, components)
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities with 3 components', N),
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
@@ -186,10 +580,37 @@ basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities
multi_spawn(N, components)
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities with 5 components', N),
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
@@ -197,12 +618,39 @@ basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities
multi_spawn(N, components)
evo.batch_destroy(Q1)
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),
basics.describe_bench(
string.format('Spawn Benchmarks: Multi Spawn | %d entities with 1 required component', N),
function()
local multi_spawn = evo.multi_spawn
@@ -210,27 +658,107 @@ basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities
multi_spawn(N, components)
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities with 3 required components', N),
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 = { [R3] = true }
local components = { [F1] = true }
evo.defer()
multi_spawn(N, components)
evo.commit()
evo.batch_destroy(Q1)
evo.batch_destroy(QF1)
end)
basics.describe_bench(string.format('Spawn Benchmarks: Multi Spawn | %d entities with 5 required components', N),
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 = { [R5] = true }
local components = { [D1] = true }
multi_spawn(N, components)
evo.batch_destroy(Q1)
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

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

@@ -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,65 @@
local evo = require 'evolved'
do
assert(evo.depth() == 0)
assert(evo.defer())
assert(evo.depth() == 1)
assert(not evo.defer())
assert(evo.depth() == 2)
assert(not evo.cancel())
assert(evo.depth() == 1)
assert(evo.cancel())
assert(evo.depth() == 0)
end
do
assert(evo.depth() == 0)
assert(evo.defer())
assert(evo.depth() == 1)
assert(not evo.defer())
assert(evo.depth() == 2)
assert(not evo.commit())
assert(evo.depth() == 1)
assert(evo.commit())
assert(evo.depth() == 0)
end
do
assert(evo.depth() == 0)
assert(evo.defer())
assert(evo.depth() == 1)
assert(not evo.defer())
assert(evo.depth() == 2)
assert(not evo.cancel())
assert(evo.depth() == 1)
assert(evo.commit())
assert(evo.depth() == 0)
end
do
assert(evo.depth() == 0)
assert(evo.defer())
assert(evo.depth() == 1)
assert(not evo.defer())
assert(evo.depth() == 2)
assert(not evo.commit())
assert(evo.depth() == 1)
assert(evo.cancel())
assert(evo.depth() == 0)
end

View File

@@ -0,0 +1,104 @@
local evo = require 'evolved'
do
local e = evo.id()
assert(evo.alive(e))
evo.destroy(e)
assert(not evo.alive(e))
evo.destroy(e)
assert(not evo.alive(e))
end
do
local e1, e2 = evo.id(2)
assert(evo.alive_all(e1, e2))
evo.destroy(e1, e2)
assert(not evo.alive_any(e1, e2))
evo.destroy(e1, e2)
assert(not evo.alive_any(e1, e2))
end
do
do
local e, f1, f2, f3 = evo.id(4)
evo.set(e, f1, 42)
evo.set(e, f2, 21)
evo.set(e, f3, 84)
evo.destroy(f1, f2)
assert(evo.alive(e) and not evo.has_any(e, f1, f2) and evo.has(e, f3))
end
do
local e, f1, f2, f3 = evo.id(4)
evo.set(f1, evo.DESTRUCTION_POLICY, evo.DESTRUCTION_POLICY_REMOVE_FRAGMENT)
evo.set(e, f1, 42)
evo.set(e, f2, 21)
evo.set(e, f3, 84)
evo.destroy(f1, f2)
assert(evo.alive(e) and not evo.has_any(e, f1, f2) and evo.has(e, f3))
end
do
local e, f1, f2, f3 = evo.id(4)
evo.set(f2, evo.DESTRUCTION_POLICY, evo.DESTRUCTION_POLICY_REMOVE_FRAGMENT)
evo.set(e, f1, 42)
evo.set(e, f2, 21)
evo.set(e, f3, 84)
evo.destroy(f1, f2)
assert(evo.alive(e) and not evo.has_any(e, f1, f2) and evo.has(e, f3))
end
do
local e, f1, f2, f3 = evo.id(4)
evo.set(f1, evo.DESTRUCTION_POLICY, evo.DESTRUCTION_POLICY_REMOVE_FRAGMENT)
evo.set(f2, evo.DESTRUCTION_POLICY, evo.DESTRUCTION_POLICY_REMOVE_FRAGMENT)
evo.set(e, f1, 42)
evo.set(e, f2, 21)
evo.set(e, f3, 84)
evo.destroy(f1, f2)
assert(evo.alive(e) and not evo.has_any(e, f1, f2) and evo.has(e, f3))
end
do
local e, f1, f2, f3 = evo.id(4)
evo.set(f1, evo.DESTRUCTION_POLICY, evo.DESTRUCTION_POLICY_DESTROY_ENTITY)
evo.set(e, f1, 42)
evo.set(e, f2, 21)
evo.set(e, f3, 84)
evo.destroy(f1, f2)
assert(not evo.alive(e))
end
do
local e, f1, f2, f3 = evo.id(4)
evo.set(f2, evo.DESTRUCTION_POLICY, evo.DESTRUCTION_POLICY_DESTROY_ENTITY)
evo.set(e, f1, 42)
evo.set(e, f2, 21)
evo.set(e, f3, 84)
evo.destroy(f1, f2)
assert(not evo.alive(e))
end
do
local e, f1, f2, f3 = evo.id(4)
evo.set(f1, evo.DESTRUCTION_POLICY, evo.DESTRUCTION_POLICY_DESTROY_ENTITY)
evo.set(f2, evo.DESTRUCTION_POLICY, evo.DESTRUCTION_POLICY_DESTROY_ENTITY)
evo.set(e, f1, 42)
evo.set(e, f2, 21)
evo.set(e, f3, 84)
evo.destroy(f1, f2)
assert(not evo.alive(e))
end
end

View File

@@ -0,0 +1,107 @@
local evo = require 'evolved'
do
local f = evo.id()
local e = evo.builder():set(f, 42):spawn()
local s = evo.builder()
:include(f)
:prologue(function(payload1, payload2, payload3)
assert(payload1 == 11 and payload2 == 22 and payload3 == 33)
end)
:execute(function(chunk, entity_list, entity_count, payload1, payload2, payload3)
assert(payload1 == 11 and payload2 == 22 and payload3 == 33)
assert(chunk == evo.chunk(f) and entity_count == 1 and entity_list[1] == e)
end)
:epilogue(function(payload1, payload2, payload3)
assert(payload1 == 11 and payload2 == 22 and payload3 == 33)
end)
:spawn()
evo.process_with(s, 11, 22, 33)
end
do
local f = evo.id()
local e = evo.builder():set(f, 42):spawn()
local s = evo.builder()
:include(f)
:prologue(function(payload1, payload2, payload3)
assert(payload1 == nil and payload2 == 42 and payload3 == nil)
end)
:execute(function(chunk, entity_list, entity_count, payload1, payload2, payload3)
assert(payload1 == nil and payload2 == 42 and payload3 == nil)
assert(chunk == evo.chunk(f) and entity_count == 1 and entity_list[1] == e)
end)
:epilogue(function(payload1, payload2, payload3)
assert(payload1 == nil and payload2 == 42 and payload3 == nil)
end)
:spawn()
evo.process_with(s, nil, 42)
end
do
local f = evo.id()
local e = evo.builder():set(f, 42):spawn()
local s = evo.builder()
:include(f)
:prologue(function(payload1, payload2, payload3)
assert(payload1 == nil and payload2 == nil and payload3 == nil)
end)
:execute(function(chunk, entity_list, entity_count, payload1, payload2, payload3)
assert(payload1 == nil and payload2 == nil and payload3 == nil)
assert(chunk == evo.chunk(f) and entity_count == 1 and entity_list[1] == e)
end)
:epilogue(function(payload1, payload2, payload3)
assert(payload1 == nil and payload2 == nil and payload3 == nil)
end)
:spawn()
evo.process_with(s)
end
do
local f = evo.id()
local e = evo.builder():set(f, 42):spawn()
local prologue_sum, execute_sum, epilogue_sum = 0, 0, 0
local function sum(...)
local s = 0
for i = 1, select('#', ...) do
s = s + select(i, ...)
end
return s
end
local function iota(n)
if n == 0 then return end
return n, iota(n - 1)
end
local s = evo.builder()
:include(f)
:prologue(function(...)
prologue_sum = prologue_sum + sum(...)
end)
:execute(function(chunk, entity_list, entity_count, ...)
execute_sum = execute_sum + sum(...)
assert(chunk == evo.chunk(f) and entity_count == 1 and entity_list[1] == e)
end)
:epilogue(function(...)
epilogue_sum = epilogue_sum + sum(...)
end)
:spawn()
for n = 0, 50 do
prologue_sum, execute_sum, epilogue_sum = 0, 0, 0
evo.process_with(s, iota(n))
local expect_sum = (n * (n + 1)) / 2
assert(prologue_sum == expect_sum)
assert(execute_sum == expect_sum)
assert(epilogue_sum == expect_sum)
end
end

View File

@@ -243,3 +243,143 @@ do
end
end
end
do
local f1, f2, f3, f4 = evo.id(4)
evo.set(f1, evo.REQUIRES, { f2 })
evo.set(f2, evo.REQUIRES, { f3 })
evo.set(f3, evo.REQUIRES, { f4 })
do
local e1 = evo.builder():set(f1):spawn()
assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
assert(evo.has(e1, f2) and evo.get(e1, f2) == true)
assert(evo.has(e1, f3) and evo.get(e1, f3) == true)
assert(evo.has(e1, f4) and evo.get(e1, f4) == true)
local e2 = evo.builder():set(f2):spawn()
assert(not evo.has(e2, f1) and evo.get(e2, f1) == nil)
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
assert(evo.has(e2, f3) and evo.get(e2, f3) == true)
assert(evo.has(e2, f4) and evo.get(e2, f4) == true)
local e3 = evo.builder():set(f3):spawn()
assert(not evo.has(e3, f1) and evo.get(e3, f1) == nil)
assert(not evo.has(e3, f2) and evo.get(e3, f2) == nil)
assert(evo.has(e3, f3) and evo.get(e3, f3) == true)
assert(evo.has(e3, f4) and evo.get(e3, f4) == true)
end
do
local e1 = evo.id()
evo.set(e1, f1)
assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
assert(evo.has(e1, f2) and evo.get(e1, f2) == true)
assert(evo.has(e1, f3) and evo.get(e1, f3) == true)
assert(evo.has(e1, f4) and evo.get(e1, f4) == true)
local e2 = evo.id()
evo.set(e2, f2)
assert(not evo.has(e2, f1) and evo.get(e2, f1) == nil)
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
assert(evo.has(e2, f3) and evo.get(e2, f3) == true)
assert(evo.has(e2, f4) and evo.get(e2, f4) == true)
local e3 = evo.id()
evo.set(e3, f3)
assert(not evo.has(e3, f1) and evo.get(e3, f1) == nil)
assert(not evo.has(e3, f2) and evo.get(e3, f2) == nil)
assert(evo.has(e3, f3) and evo.get(e3, f3) == true)
assert(evo.has(e3, f4) and evo.get(e3, f4) == true)
end
evo.remove(f2, evo.REQUIRES)
do
local e1 = evo.builder():set(f1):spawn()
assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
assert(evo.has(e1, f2) and evo.get(e1, f2) == true)
assert(not evo.has(e1, f3) and evo.get(e1, f3) == nil)
assert(not evo.has(e1, f4) and evo.get(e1, f4) == nil)
local e2 = evo.builder():set(f2):spawn()
assert(not evo.has(e2, f1) and evo.get(e2, f1) == nil)
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
assert(not evo.has(e2, f3) and evo.get(e2, f3) == nil)
assert(not evo.has(e2, f4) and evo.get(e2, f4) == nil)
local e3 = evo.builder():set(f3):spawn()
assert(not evo.has(e3, f1) and evo.get(e3, f1) == nil)
assert(not evo.has(e3, f2) and evo.get(e3, f2) == nil)
assert(evo.has(e3, f3) and evo.get(e3, f3) == true)
assert(evo.has(e3, f4) and evo.get(e3, f4) == true)
end
do
local e1 = evo.id()
evo.set(e1, f1)
assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
assert(evo.has(e1, f2) and evo.get(e1, f2) == true)
assert(not evo.has(e1, f3) and evo.get(e1, f3) == nil)
assert(not evo.has(e1, f4) and evo.get(e1, f4) == nil)
local e2 = evo.id()
evo.set(e2, f2)
assert(not evo.has(e2, f1) and evo.get(e2, f1) == nil)
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
assert(not evo.has(e2, f3) and evo.get(e2, f3) == nil)
assert(not evo.has(e2, f4) and evo.get(e2, f4) == nil)
local e3 = evo.id()
evo.set(e3, f3)
assert(not evo.has(e3, f1) and evo.get(e3, f1) == nil)
assert(not evo.has(e3, f2) and evo.get(e3, f2) == nil)
assert(evo.has(e3, f3) and evo.get(e3, f3) == true)
assert(evo.has(e3, f4) and evo.get(e3, f4) == true)
end
evo.set(f2, evo.REQUIRES, { f4 })
do
local e1 = evo.builder():set(f1):spawn()
assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
assert(evo.has(e1, f2) and evo.get(e1, f2) == true)
assert(not evo.has(e1, f3) and evo.get(e1, f3) == nil)
assert(evo.has(e1, f4) and evo.get(e1, f4) == true)
local e2 = evo.builder():set(f2):spawn()
assert(not evo.has(e2, f1) and evo.get(e2, f1) == nil)
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
assert(not evo.has(e2, f3) and evo.get(e2, f3) == nil)
assert(evo.has(e2, f4) and evo.get(e2, f4) == true)
local e3 = evo.builder():set(f3):spawn()
assert(not evo.has(e3, f1) and evo.get(e3, f1) == nil)
assert(not evo.has(e3, f2) and evo.get(e3, f2) == nil)
assert(evo.has(e3, f3) and evo.get(e3, f3) == true)
assert(evo.has(e3, f4) and evo.get(e3, f4) == true)
end
do
local e1 = evo.id()
evo.set(e1, f1)
assert(evo.has(e1, f1) and evo.get(e1, f1) == true)
assert(evo.has(e1, f2) and evo.get(e1, f2) == true)
assert(not evo.has(e1, f3) and evo.get(e1, f3) == nil)
assert(evo.has(e1, f4) and evo.get(e1, f4) == true)
local e2 = evo.id()
evo.set(e2, f2)
assert(not evo.has(e2, f1) and evo.get(e2, f1) == nil)
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
assert(not evo.has(e2, f3) and evo.get(e2, f3) == nil)
assert(evo.has(e2, f4) and evo.get(e2, f4) == true)
local e3 = evo.id()
evo.set(e3, f3)
assert(not evo.has(e3, f1) and evo.get(e3, f1) == nil)
assert(not evo.has(e3, f2) and evo.get(e3, f2) == nil)
assert(evo.has(e3, f3) and evo.get(e3, f3) == true)
assert(evo.has(e3, f4) and evo.get(e3, f4) == true)
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

183
evolved.d.tl Normal file
View File

@@ -0,0 +1,183 @@
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, ...: any)): Builder
prologue: function(self: Builder, prologue: function(...: any)): Builder
epilogue: function(self: Builder, epilogue: function(...: any)): 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
depth: function(): integer
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)
process_with: function(system: System, ...: any)
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

167
example/main.lua Normal file
View File

@@ -0,0 +1,167 @@
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 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, 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)
evolved.process_with(STAGES.ON_UPDATE, dt)
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.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",
}
}

View File

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