mirror of
https://github.com/BlackMATov/evolved.lua.git
synced 2026-03-22 04:44:06 +07:00
Compare commits
92 Commits
v1.3.0
...
f6b8844a82
| Author | SHA1 | Date | |
|---|---|---|---|
| f6b8844a82 | |||
|
|
7ce5ee924c | ||
|
|
539a62c8a8 | ||
|
|
63a7ab5c79 | ||
|
|
9a9fb1ddb9 | ||
|
|
7b44740803 | ||
|
|
b0d035c0d4 | ||
|
|
8d88d55267 | ||
|
|
b774abf63c | ||
|
|
4a018f4c40 | ||
|
|
39c20f13dd | ||
|
|
ce864b7433 | ||
|
|
04c9e4aaeb | ||
| e48bdf0511 | |||
|
|
e9824a4776 | ||
|
|
c3760c40bf | ||
|
|
a2a4fc56e3 | ||
|
|
21d5091d14 | ||
|
|
18ee0d9a12 | ||
|
|
12c86ca679 | ||
|
|
a0f252f47c | ||
|
|
b17118544d | ||
|
|
b9cdbe961b | ||
|
|
4f78c8245c | ||
|
|
a7e5652ad4 | ||
|
|
c52f708184 | ||
|
|
e75ddef396 | ||
|
|
c9bfb26748 | ||
|
|
3a3abbd2fd | ||
| a945401e9b | |||
|
|
d9c9b4cf85 | ||
|
|
20c94a0b72 | ||
|
|
e396c320ee | ||
|
|
52c898f912 | ||
|
|
a5319351c1 | ||
|
|
c9f4a74518 | ||
|
|
c29092c3e1 | ||
|
|
a0a4a20c35 | ||
|
|
2f8b0b0ef3 | ||
|
|
5e0170b4e8 | ||
| a1423ea9ee | |||
|
|
d42c0cf3db | ||
|
|
723a65ca7f | ||
|
|
72fc524fe0 | ||
|
|
a8d1d84bed | ||
|
|
568cec4012 | ||
|
|
f175a25f1a | ||
|
|
856b9c665d | ||
|
|
8e2a34f2f6 | ||
|
|
47dd1bb30a | ||
| 12a720bd9e | |||
|
|
5895c6ee8f | ||
|
|
1c02ba5468 | ||
|
|
760b477564 | ||
|
|
fc910881bd | ||
|
|
71a7c84a67 | ||
|
|
582a09a6db | ||
|
|
de73881f63 | ||
|
|
55e444ca63 | ||
|
|
e499c701ef | ||
|
|
789f167bf4 | ||
|
|
00367ce07e | ||
|
|
07902eb184 | ||
| ecdbfe660f | |||
|
|
cfd68767cf | ||
|
|
f1ba9ab909 | ||
|
|
77ff3e77db | ||
|
|
825eba5328 | ||
|
|
67002503ed | ||
|
|
1bb0089e9f | ||
|
|
dc642f5294 | ||
|
|
a81a8646e9 | ||
|
|
aa6d2c1c48 | ||
|
|
5fe48de890 | ||
| 0d7adcb5fd | |||
|
|
f48f1bb290 | ||
|
|
6f1a85165f | ||
|
|
bd87e593e9 | ||
|
|
0eac310fd5 | ||
|
|
22cedd26bb | ||
|
|
d298be4188 | ||
|
|
24933e6a04 | ||
|
|
6841bb42fe | ||
|
|
dc912eb6da | ||
|
|
8d3c4633fb | ||
|
|
8704fb0c39 | ||
|
|
86c9ef7cf2 | ||
|
|
bd5f9bb61f | ||
|
|
cfa5dc7a9f | ||
|
|
243adc1a93 | ||
|
|
cf19fba9e4 | ||
|
|
784b9c6a15 |
2
.github/workflows/lua5.1.yml
vendored
2
.github/workflows/lua5.1.yml
vendored
@@ -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
21
.github/workflows/lua5.2.yml
vendored
Normal 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
21
.github/workflows/lua5.3.yml
vendored
Normal 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
|
||||
2
.github/workflows/lua5.4.yml
vendored
2
.github/workflows/lua5.4.yml
vendored
@@ -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: |
|
||||
|
||||
2
.github/workflows/luajit.yml
vendored
2
.github/workflows/luajit.yml
vendored
@@ -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: |
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
"ignoreDir": [
|
||||
".vscode",
|
||||
"develop/3rdparty"
|
||||
],
|
||||
"library": [
|
||||
"${3rd}/love2d/library"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
38
.vscode/launch.json
vendored
38
.vscode/launch.json
vendored
@@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"[json][jsonc][lua][markdown][yaml]": {
|
||||
"[json][jsonc][lua][markdown][teal][yaml]": {
|
||||
"editor.formatOnSave": true,
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimFinalNewlines": true,
|
||||
|
||||
@@ -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
|
||||
|
||||
534
README.md
534
README.md
@@ -35,6 +35,7 @@
|
||||
- [Structural Changes](#structural-changes)
|
||||
- [Spawning Entities](#spawning-entities)
|
||||
- [Entity Builders](#entity-builders)
|
||||
- [Multi-Entity Spawning](#multi-entity-spawning)
|
||||
- [Access Operations](#access-operations)
|
||||
- [Iterating Over Fragments](#iterating-over-fragments)
|
||||
- [Modifying Operations](#modifying-operations)
|
||||
@@ -43,14 +44,17 @@
|
||||
- [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)
|
||||
- [Custom Component Storages](#custom-component-storages)
|
||||
- [Cheat Sheet](#cheat-sheet)
|
||||
- [Aliases](#aliases)
|
||||
- [Predefs](#predefs)
|
||||
@@ -59,6 +63,12 @@
|
||||
- [Chunk](#chunk)
|
||||
- [Builder](#builder)
|
||||
- [Changelog](#changelog)
|
||||
- [v1.9.0](#v190)
|
||||
- [v1.8.0](#v180)
|
||||
- [v1.7.0](#v170)
|
||||
- [v1.6.0](#v160)
|
||||
- [v1.5.0](#v150)
|
||||
- [v1.4.0](#v140)
|
||||
- [v1.3.0](#v130)
|
||||
- [v1.2.0](#v120)
|
||||
- [v1.1.0](#v110)
|
||||
@@ -101,7 +111,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
|
||||
|
||||
@@ -153,11 +163,11 @@ function evolved.alive_any(...) end
|
||||
Sometimes (for debugging purposes, for example), it is necessary to extract the index and version from an identifier or to pack them back into an identifier. The [`evolved.pack`](#evolvedpack) and [`evolved.unpack`](#evolvedunpack) functions can be used for this purpose.
|
||||
|
||||
```lua
|
||||
---@param index integer
|
||||
---@param version integer
|
||||
---@param primary integer
|
||||
---@param secondary integer
|
||||
---@return evolved.id id
|
||||
---@nodiscard
|
||||
function evolved.pack(index, version) end
|
||||
function evolved.pack(primary, secondary) end
|
||||
|
||||
---@param id evolved.id
|
||||
---@return integer primary
|
||||
@@ -412,17 +422,19 @@ You should try to avoid structural changes, especially in performance-critical c
|
||||
#### Spawning Entities
|
||||
|
||||
```lua
|
||||
---@param components? table<evolved.fragment, evolved.component>
|
||||
---@param component_table? table<evolved.fragment, evolved.component>
|
||||
---@param component_mapper? fun(chunk: evolved.chunk, place: integer)
|
||||
---@return evolved.entity
|
||||
function evolved.spawn(components) end
|
||||
function evolved.spawn(component_table, component_mapper) end
|
||||
|
||||
---@param prefab evolved.entity
|
||||
---@param components? table<evolved.fragment, evolved.component>
|
||||
---@param component_table? table<evolved.fragment, evolved.component>
|
||||
---@param component_mapper? fun(chunk: evolved.chunk, place: integer)
|
||||
---@return evolved.entity
|
||||
function evolved.clone(prefab, components) end
|
||||
function evolved.clone(prefab, component_table, component_mapper) end
|
||||
```
|
||||
|
||||
The [`evolved.spawn`](#evolvedspawn) function allows you to spawn an entity with all the necessary fragments. It takes a table of components as an argument, where the keys are fragments and the values are components. By the way, you don't need to create this `components` table every time; consider using a predefined table for maximum performance.
|
||||
The [`evolved.spawn`](#evolvedspawn) function allows you to spawn an entity with all the necessary fragments. It takes a table of components as an argument, where the keys are fragments and the values are components. By the way, you don't need to create this `component_table` every time; consider using a predefined table for maximum performance.
|
||||
|
||||
You can also use the [`evolved.clone`](#evolvedclone) function to clone an existing entity. This is useful for creating entities with the same fragments as an existing entity but with different components.
|
||||
|
||||
@@ -461,11 +473,59 @@ local health, stamina = evolved.id(2)
|
||||
local enemy = evolved.builder()
|
||||
:set(health, 100)
|
||||
:set(stamina, 50)
|
||||
:spawn()
|
||||
:build()
|
||||
```
|
||||
|
||||
Builders can be reused, so you can create a builder with a specific set of fragments and components and then use it to spawn multiple entities with the same fragments and components.
|
||||
|
||||
#### Multi-Entity Spawning
|
||||
|
||||
When you need to spawn multiple entities with identical fragments, use `multi_spawn` and `multi_clone` to optimize performance and reduce overhead.
|
||||
|
||||
```lua
|
||||
---@param entity_count integer
|
||||
---@param component_table? evolved.component_table
|
||||
---@param component_mapper? evolved.component_mapper
|
||||
---@return evolved.entity[] entity_list
|
||||
---@return integer entity_count
|
||||
function evolved.multi_spawn(entity_count, component_table, component_mapper) end
|
||||
|
||||
---@param entity_count integer
|
||||
---@param prefab evolved.entity
|
||||
---@param component_table? evolved.component_table
|
||||
---@param component_mapper? evolved.component_mapper
|
||||
---@return evolved.entity[] entity_list
|
||||
---@return integer entity_count
|
||||
function evolved.multi_clone(entity_count, prefab, component_table, component_mapper) end
|
||||
```
|
||||
|
||||
These functions behave like their single-entity counterparts, but they allow you to spawn or clone multiple entities in one call. This approach minimizes the overhead of repeated function calls and structural changes, improving performance when handling large numbers of entities.
|
||||
|
||||
Typically, when spawning multiple entities, they share the same set of fragments, but their components can differ. You can achieve this by providing a `component_mapper` function, which receives the chunk and the range of places for the newly spawned entities. This avoids many `evolved.set` calls after spawning, which can be costly when creating many entities.
|
||||
|
||||
Here is a small example of using `evolved.multi_spawn` with a `component_mapper`:
|
||||
|
||||
```lua
|
||||
local evolved = require 'evolved'
|
||||
|
||||
local position_x, position_y = evolved.id(2)
|
||||
|
||||
evolved.multi_spawn(1000, {
|
||||
[position_x] = 0,
|
||||
[position_y] = 0,
|
||||
}, function(chunk, b_place, e_place)
|
||||
local x_components = chunk:components(position_x)
|
||||
local y_components = chunk:components(position_y)
|
||||
|
||||
for i = b_place, e_place do
|
||||
x_components[i] = math.random(-100, 100)
|
||||
y_components[i] = math.random(-100, 100)
|
||||
end
|
||||
end)
|
||||
```
|
||||
|
||||
Of course, you can use `evolved.multi_clone` in the same way. Builders can also be used for multi-entity spawning and cloning by calling the corresponding methods on the builder object.
|
||||
|
||||
### Access Operations
|
||||
|
||||
The library provides all the necessary functions to access entities and their components. I'm not going to cover all the accessor functions here, because they are pretty straightforward and self-explanatory. You can check the [API Reference](#api-reference) for all of them. Here are some of the most important ones:
|
||||
@@ -502,16 +562,16 @@ local evolved = require 'evolved'
|
||||
|
||||
local health = evolved.builder()
|
||||
:name('health')
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local stamina = evolved.builder()
|
||||
:name('stamina')
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local player = evolved.builder()
|
||||
:set(health, 100)
|
||||
:set(stamina, 50)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
for fragment, component in evolved.each(player) do
|
||||
print(string.format('Fragment (%s) has value %d',
|
||||
@@ -582,16 +642,22 @@ evolved.set(entity, fragment, 42)
|
||||
|
||||
One of the most important features of any ECS library is the ability to process entities by filters or queries. `evolved.lua` provides a simple and efficient way to do this.
|
||||
|
||||
First, you need to create a query that describes which entities you want to process. You can specify fragments you want to include, and fragments you want to exclude. Queries are just identifiers with a special predefined fragments: [`evolved.INCLUDES`](#evolvedincludes) and [`evolved.EXCLUDES`](#evolvedexcludes). These fragments expect a list of fragments as their components.
|
||||
First, you need to create a query that describes which entities you want to process. You can specify fragments you want to include, and fragments you want to exclude. Queries are just identifiers with a special predefined fragments: [`evolved.INCLUDES`](#evolvedincludes), [`evolved.EXCLUDES`](#evolvedexcludes), and [`evolved.VARIANTS`](#evolvedvariants). These fragments expect a list of fragments as their components.
|
||||
|
||||
- [`evolved.INCLUDES`](#evolvedincludes) is used to specify fragments that must be present in the entity;
|
||||
- [`evolved.EXCLUDES`](#evolvedexcludes) is used to specify fragments that must not be present in the entity;
|
||||
- [`evolved.VARIANTS`](#evolvedvariants) is used to specify fragments where at least one must be present in the entity.
|
||||
|
||||
```lua
|
||||
local evolved = require 'evolved'
|
||||
|
||||
local health, poisoned, resistant = evolved.id(3)
|
||||
local alive, undead = evolved.id(2)
|
||||
|
||||
local query = evolved.id()
|
||||
evolved.set(query, evolved.INCLUDES, { health, poisoned })
|
||||
evolved.set(query, evolved.EXCLUDES, { resistant })
|
||||
evolved.set(query, evolved.VARIANTS, { alive, undead })
|
||||
```
|
||||
|
||||
The builder interface can be used to create queries too. It is more convenient to use, because the builder has special methods for including and excluding fragments. Here is a simple example of this:
|
||||
@@ -600,10 +666,11 @@ The builder interface can be used to create queries too. It is more convenient t
|
||||
local query = evolved.builder()
|
||||
:include(health, poisoned)
|
||||
:exclude(resistant)
|
||||
:spawn()
|
||||
:variant(alive, undead)
|
||||
:build()
|
||||
```
|
||||
|
||||
We don't have to set both [`evolved.INCLUDES`](#evolvedincludes) and [`evolved.EXCLUDES`](#evolvedexcludes) fragments, we can even do it without filters at all, then the query will match all chunks in the world.
|
||||
We don't have to set all of [`evolved.INCLUDES`](#evolvedincludes), [`evolved.EXCLUDES`](#evolvedexcludes), and [`evolved.VARIANTS`](#evolvedvariants) fragments, we can even do it without filters at all, then the query will match all chunks in the world.
|
||||
|
||||
After the query is created, we are ready to process our filtered by this query entities. You can do this by using the [`evolved.execute`](#evolvedexecute) function. This function takes a query as an argument and returns an iterator that can be used to iterate over all matching with the query chunks.
|
||||
|
||||
@@ -640,6 +707,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
|
||||
|
||||
@@ -647,7 +718,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'
|
||||
@@ -657,7 +728,7 @@ local health, poisoned = evolved.id(2)
|
||||
local player = evolved.builder()
|
||||
:set(health, 100)
|
||||
:set(poisoned, true)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
-- start a deferred scope
|
||||
evolved.defer()
|
||||
@@ -685,7 +756,7 @@ local health, poisoned = evolved.id(2)
|
||||
local player = evolved.builder()
|
||||
:set(health, 100)
|
||||
:set(poisoned, true)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
-- start a deferred scope
|
||||
evolved.defer()
|
||||
@@ -733,7 +804,7 @@ local destroying_mark = evolved.id()
|
||||
|
||||
local destroying_mark_query = evolved.builder()
|
||||
:include(destroying_mark)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
-- destroy all entities with the destroying_mark fragment
|
||||
evolved.batch_destroy(destroying_mark_query)
|
||||
@@ -755,7 +826,7 @@ local health, max_health = evolved.id(2)
|
||||
|
||||
local query = evolved.builder()
|
||||
:include(health, max_health)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local system = evolved.builder()
|
||||
:query(query)
|
||||
@@ -768,7 +839,7 @@ local system = evolved.builder()
|
||||
health_components[i] + 1,
|
||||
max_health_components[i])
|
||||
end
|
||||
end):spawn()
|
||||
end):build()
|
||||
```
|
||||
|
||||
The [`evolved.process`](#evolvedprocess) function is used to process systems. It takes systems as arguments and executes them in the order they were passed.
|
||||
@@ -778,7 +849,7 @@ The [`evolved.process`](#evolvedprocess) function is used to process systems. It
|
||||
function evolved.process(...) end
|
||||
```
|
||||
|
||||
If you don't specify a query for the system, the system itself will be treated as a query. This means the system can contain `evolved.INCLUDES` and `evolved.EXCLUDES` fragments, and it will be processed according to them. This is useful for creating systems with unique queries that don't need to be reused in other systems.
|
||||
If you don't specify a query for the system, the system itself will be treated as a query. This means the system can contain `evolved.INCLUDES`, `evolved.EXCLUDES`, and `evolved.VARIANTS` fragments, and it will be processed according to them. This is useful for creating systems with unique queries that don't need to be reused in other systems.
|
||||
|
||||
```lua
|
||||
local evolved = require 'evolved'
|
||||
@@ -795,7 +866,7 @@ local system = evolved.builder()
|
||||
health_components[i] - 1,
|
||||
0)
|
||||
end
|
||||
end):spawn()
|
||||
end):build()
|
||||
|
||||
evolved.process(system)
|
||||
```
|
||||
@@ -814,7 +885,7 @@ local velocity_x, velocity_y = evolved.id(2)
|
||||
local physical_body_query = evolved.builder()
|
||||
:include(position_x, position_y)
|
||||
:include(velocity_x, velocity_y)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local physics_group = evolved.id()
|
||||
|
||||
@@ -829,7 +900,7 @@ evolved.builder()
|
||||
vx[i] = vx[i] + gravity_x
|
||||
vy[i] = vy[i] + gravity_y
|
||||
end
|
||||
end):spawn()
|
||||
end):build()
|
||||
|
||||
evolved.builder()
|
||||
:group(physics_group)
|
||||
@@ -845,7 +916,7 @@ evolved.builder()
|
||||
px[i] = px[i] + vx[i]
|
||||
py[i] = py[i] + vy[i]
|
||||
end
|
||||
end):spawn()
|
||||
end):build()
|
||||
|
||||
evolved.process(physics_group)
|
||||
```
|
||||
@@ -862,7 +933,7 @@ local system = evolved.builder()
|
||||
:epilogue(function()
|
||||
print('Epilogue')
|
||||
end)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
evolved.process(system)
|
||||
```
|
||||
@@ -872,6 +943,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
|
||||
@@ -904,7 +1012,7 @@ local evolved = require 'evolved'
|
||||
local health = evolved.builder()
|
||||
:on_set(function(entity, fragment, component)
|
||||
print('health set to ' .. component)
|
||||
end):spawn()
|
||||
end):build()
|
||||
|
||||
local player = evolved.id()
|
||||
evolved.set(player, health, 100) -- prints "health set to 100"
|
||||
@@ -929,7 +1037,7 @@ local enemy_prefab = evolved.builder()
|
||||
:prefab()
|
||||
:set(health, 100)
|
||||
:set(stamina, 50)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local enemy_clone = evolved.clone(enemy_prefab)
|
||||
|
||||
@@ -951,18 +1059,22 @@ local evolved = require 'evolved'
|
||||
|
||||
local enemy_tag = evolved.builder()
|
||||
:tag()
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local only_enabled_enemies = evolved.builder()
|
||||
:include(enemy_tag)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local all_enemies_including_disabled = evolved.builder()
|
||||
:include(enemy_tag)
|
||||
:include(evolved.DISABLED)
|
||||
:spawn()
|
||||
: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.
|
||||
@@ -976,11 +1088,11 @@ local position = evolved.id()
|
||||
|
||||
local enemy1 = evolved.builder()
|
||||
:set(position, initial_position)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local enemy2 = evolved.builder()
|
||||
:set(position, initial_position)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
-- the enemy1 and enemy2 share the same table,
|
||||
-- and that's definitely not what we want in this case
|
||||
@@ -1005,15 +1117,15 @@ end
|
||||
local position = evolved.builder()
|
||||
:default(vector2(0, 0))
|
||||
:duplicate(vector2_duplicate)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local enemy1 = evolved.builder()
|
||||
:set(position)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local enemy2 = evolved.builder()
|
||||
:set(position)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
-- the enemy1 and enemy2 have different tables now
|
||||
assert(evolved.get(enemy1, position) ~= evolved.get(enemy2, position))
|
||||
@@ -1029,21 +1141,21 @@ local evolved = require 'evolved'
|
||||
local position = evolved.builder()
|
||||
:default(vector2(0, 0))
|
||||
:duplicate(vector2_duplicate)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local velocity = evolved.builder()
|
||||
:default(vector2(0, 0))
|
||||
:duplicate(vector2_duplicate)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local physical = evolved.builder()
|
||||
:tag()
|
||||
:require(position, velocity)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local enemy = evolved.builder()
|
||||
:set(physical)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
assert(evolved.has_all(enemy, position, velocity))
|
||||
```
|
||||
@@ -1057,11 +1169,11 @@ local evolved = require 'evolved'
|
||||
|
||||
local world = evolved.builder()
|
||||
:tag()
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local entity = evolved.builder()
|
||||
:set(world)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
-- destroy the world fragment that is attached to the entity
|
||||
evolved.destroy(world)
|
||||
@@ -1082,11 +1194,11 @@ local evolved = require 'evolved'
|
||||
local world = evolved.builder()
|
||||
:tag()
|
||||
:destruction_policy(evolved.DESTRUCTION_POLICY_DESTROY_ENTITY)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
local entity = evolved.builder()
|
||||
:set(world)
|
||||
:spawn()
|
||||
:build()
|
||||
|
||||
-- destroy the world fragment that is attached to the entity
|
||||
evolved.destroy(world)
|
||||
@@ -1095,6 +1207,145 @@ evolved.destroy(world)
|
||||
assert(not evolved.alive(entity))
|
||||
```
|
||||
|
||||
#### Custom Component Storages
|
||||
|
||||
In some cases, you might want custom storages for fragment components. For example, you might want to store components in a specialized way for performance reasons. The library provides two fragment traits for this purpose: [`evolved.REALLOC`](#evolvedrealloc) and [`evolved.COMPMOVE`](#evolvedcompmove).
|
||||
|
||||
The [`evolved.REALLOC`](#evolvedrealloc) trait expects a function that is called when the fragment storage needs to be reallocated. The [`evolved.COMPMOVE`](#evolvedcompmove) trait expects a function that is called when components need to be moved from one storage to another.
|
||||
|
||||
A canonical example of using custom storages is implementing a fragment that stores components in an FFI-backed storage for better processing performance in LuaJIT. This is an advanced topic and requires a good understanding of LuaJIT FFI and memory management. So I won't cover it here in detail, but here is a simple example to give you an idea of how it works. More information can be found on the [LuaJIT](https://luajit.org/ext_ffi.html) website.
|
||||
|
||||
```lua
|
||||
local ffi = require 'ffi'
|
||||
local evolved = require 'evolved'
|
||||
|
||||
--
|
||||
--
|
||||
-- Define FFI double storage realloc and compmove functions
|
||||
--
|
||||
--
|
||||
|
||||
local FFI_DOUBLE_TYPEOF = ffi.typeof('double')
|
||||
local FFI_DOUBLE_SIZEOF = ffi.sizeof(FFI_DOUBLE_TYPEOF)
|
||||
local FFI_DOUBLE_STORAGE_TYPEOF = ffi.typeof('double[?]')
|
||||
|
||||
---@param src ffi.cdata*?
|
||||
---@param src_size integer
|
||||
---@param dst_size integer
|
||||
---@return ffi.cdata*?
|
||||
local function FFI_DOUBLE_STORAGE_REALLOC(src, src_size, dst_size)
|
||||
if dst_size == 0 then
|
||||
-- freeing the src storage, just let the GC handle it
|
||||
return
|
||||
end
|
||||
|
||||
-- to support 1-based indexing, allocate one extra element
|
||||
local dst = ffi.new(FFI_DOUBLE_STORAGE_TYPEOF, dst_size + 1)
|
||||
|
||||
if src and src_size > 0 then
|
||||
-- handle both expanding and shrinking
|
||||
local min_size = math.min(src_size, dst_size)
|
||||
ffi.copy(dst + 1, src + 1, min_size * FFI_DOUBLE_SIZEOF)
|
||||
end
|
||||
|
||||
return dst
|
||||
end
|
||||
|
||||
---@param src ffi.cdata*
|
||||
---@param f integer
|
||||
---@param e integer
|
||||
---@param t integer
|
||||
---@param dst ffi.cdata*
|
||||
local function FFI_DOUBLE_STORAGE_COMPMOVE(src, f, e, t, dst)
|
||||
ffi.copy(dst + t, src + f, (e - f + 1) * FFI_DOUBLE_SIZEOF)
|
||||
end
|
||||
|
||||
--
|
||||
--
|
||||
-- Define fragments with our custom FFI storages
|
||||
--
|
||||
--
|
||||
|
||||
local POSITION_X = evolved.builder()
|
||||
:default(0)
|
||||
:realloc(FFI_DOUBLE_STORAGE_REALLOC)
|
||||
:compmove(FFI_DOUBLE_STORAGE_COMPMOVE)
|
||||
:build()
|
||||
|
||||
local POSITION_Y = evolved.builder()
|
||||
:default(0)
|
||||
:realloc(FFI_DOUBLE_STORAGE_REALLOC)
|
||||
:compmove(FFI_DOUBLE_STORAGE_COMPMOVE)
|
||||
:build()
|
||||
|
||||
local VELOCITY_X = evolved.builder()
|
||||
:default(0)
|
||||
:realloc(FFI_DOUBLE_STORAGE_REALLOC)
|
||||
:compmove(FFI_DOUBLE_STORAGE_COMPMOVE)
|
||||
:build()
|
||||
|
||||
local VELOCITY_Y = evolved.builder()
|
||||
:default(0)
|
||||
:realloc(FFI_DOUBLE_STORAGE_REALLOC)
|
||||
:compmove(FFI_DOUBLE_STORAGE_COMPMOVE)
|
||||
:build()
|
||||
|
||||
--
|
||||
--
|
||||
-- Define a movement system that uses these components
|
||||
--
|
||||
--
|
||||
|
||||
local MOVEMENT_SYSTEM = evolved.builder()
|
||||
:include(POSITION_X, POSITION_Y)
|
||||
:include(VELOCITY_X, VELOCITY_Y)
|
||||
:execute(function(chunk, entity_list, entity_count, delta_time)
|
||||
local position_xs, position_ys = chunk:components(POSITION_X, POSITION_Y)
|
||||
local velocity_xs, velocity_ys = chunk:components(VELOCITY_X, 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
|
||||
|
||||
position_xs[i], position_ys[i] = px, py
|
||||
end
|
||||
end):build()
|
||||
|
||||
--
|
||||
--
|
||||
-- Spawn some entities with these components
|
||||
--
|
||||
--
|
||||
|
||||
evolved.builder()
|
||||
:set(POSITION_X)
|
||||
:set(POSITION_Y)
|
||||
:set(VELOCITY_X)
|
||||
:set(VELOCITY_Y)
|
||||
:multi_spawn(10000, function(chunk, b_place, e_place)
|
||||
local position_xs, position_ys = chunk:components(POSITION_X, POSITION_Y)
|
||||
local velocity_xs, velocity_ys = chunk:components(VELOCITY_X, VELOCITY_Y)
|
||||
|
||||
for place = b_place, e_place do
|
||||
position_xs[place] = math.random(0, 640)
|
||||
position_ys[place] = math.random(0, 480)
|
||||
velocity_xs[place] = math.random(-100, 100)
|
||||
velocity_ys[place] = math.random(-100, 100)
|
||||
end
|
||||
end)
|
||||
|
||||
--
|
||||
--
|
||||
-- Process the movement system with a delta time payload
|
||||
--
|
||||
--
|
||||
|
||||
evolved.process_with(MOVEMENT_SYSTEM, 0.016)
|
||||
```
|
||||
|
||||
## Cheat Sheet
|
||||
|
||||
### Aliases
|
||||
@@ -1110,12 +1361,18 @@ system :: id
|
||||
component :: any
|
||||
storage :: component[]
|
||||
|
||||
component_table :: <fragment, component>
|
||||
component_mapper :: {chunk, integer, integer}
|
||||
|
||||
default :: component
|
||||
duplicate :: {component -> component}
|
||||
|
||||
execute :: {chunk, entity[], integer}
|
||||
prologue :: {}
|
||||
epilogue :: {}
|
||||
realloc :: {storage?, integer, integer -> storage?}
|
||||
compmove :: {storage, integer, integer, integer, storage}
|
||||
|
||||
execute :: {chunk, entity[], integer, any...}
|
||||
prologue :: {any...}
|
||||
epilogue :: {any...}
|
||||
|
||||
set_hook :: {entity, fragment, component, component}
|
||||
assign_hook :: {entity, fragment, component, component}
|
||||
@@ -1142,11 +1399,15 @@ INTERNAL :: fragment
|
||||
DEFAULT :: fragment
|
||||
DUPLICATE :: fragment
|
||||
|
||||
REALLOC :: fragment
|
||||
COMPMOVE :: fragment
|
||||
|
||||
PREFAB :: fragment
|
||||
DISABLED :: fragment
|
||||
|
||||
INCLUDES :: fragment
|
||||
EXCLUDES :: fragment
|
||||
VARIANTS :: fragment
|
||||
REQUIRES :: fragment
|
||||
|
||||
ON_SET :: fragment
|
||||
@@ -1177,14 +1438,15 @@ pack :: integer, integer -> id
|
||||
unpack :: id -> integer, integer
|
||||
|
||||
defer :: boolean
|
||||
depth :: integer
|
||||
commit :: boolean
|
||||
cancel :: boolean
|
||||
|
||||
spawn :: <fragment, component>? -> entity
|
||||
multi_spawn :: integer, <fragment, component>? -> entity[]
|
||||
spawn :: component_table?, component_mapper? -> entity
|
||||
multi_spawn :: integer, component_table?, component_mapper? -> entity[], integer
|
||||
|
||||
clone :: entity, <fragment, component>? -> entity
|
||||
multi_clone :: integer, entity, <fragment, component>? -> entity[]
|
||||
clone :: entity, component_table?, component_mapper? -> entity
|
||||
multi_clone :: integer, entity, component_table?, component_mapper? -> entity[], integer
|
||||
|
||||
alive :: entity -> boolean
|
||||
alive_all :: entity... -> boolean
|
||||
@@ -1198,7 +1460,7 @@ has :: entity, fragment -> boolean
|
||||
has_all :: entity, fragment... -> boolean
|
||||
has_any :: entity, fragment... -> boolean
|
||||
|
||||
get :: entity, fragment... -> component...
|
||||
get :: entity, fragment... -> component...
|
||||
|
||||
set :: entity, fragment, component -> ()
|
||||
remove :: entity, fragment... -> ()
|
||||
@@ -1216,6 +1478,7 @@ execute :: query -> {execute_state? -> chunk?, entity[]?, integer?}, execute_sta
|
||||
locate :: entity -> chunk?, integer
|
||||
|
||||
process :: system... -> ()
|
||||
process_with :: system, ... -> ()
|
||||
|
||||
debug_mode :: boolean -> ()
|
||||
collect_garbage :: ()
|
||||
@@ -1245,11 +1508,14 @@ chunk_mt:components :: fragment... -> storage...
|
||||
```
|
||||
builder :: builder
|
||||
|
||||
builder_mt:spawn :: entity
|
||||
builder_mt:multi_spawn :: integer -> entity[]
|
||||
builder_mt:build :: entity?, component_mapper? -> entity
|
||||
builder_mt:multi_build :: integer, entity?, component_mapper? -> entity[], integer
|
||||
|
||||
builder_mt:clone :: entity -> entity
|
||||
builder_mt:multi_clone :: integer, entity -> entity[]
|
||||
builder_mt:spawn :: component_mapper? -> entity
|
||||
builder_mt:multi_spawn :: integer, component_mapper? -> entity[], integer
|
||||
|
||||
builder_mt:clone :: entity, component_mapper? -> entity
|
||||
builder_mt:multi_clone :: integer, entity, component_mapper? -> entity[], integer
|
||||
|
||||
builder_mt:has :: fragment -> boolean
|
||||
builder_mt:has_all :: fragment... -> boolean
|
||||
@@ -1271,11 +1537,15 @@ builder_mt:internal :: builder
|
||||
builder_mt:default :: component -> builder
|
||||
builder_mt:duplicate :: {component -> component} -> builder
|
||||
|
||||
builder_mt:realloc :: {storage?, integer, integer -> storage?} -> builder
|
||||
builder_mt:compmove :: {storage, integer, integer, integer, storage} -> builder
|
||||
|
||||
builder_mt:prefab :: builder
|
||||
builder_mt:disabled :: builder
|
||||
|
||||
builder_mt:include :: fragment... -> builder
|
||||
builder_mt:exclude :: fragment... -> builder
|
||||
builder_mt:variant :: fragment... -> builder
|
||||
builder_mt:require :: fragment... -> builder
|
||||
|
||||
builder_mt:on_set :: {entity, fragment, component, component} -> builder
|
||||
@@ -1286,16 +1556,48 @@ 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
|
||||
|
||||
### v1.9.0
|
||||
|
||||
- Performance improvements of the [`evolved.destroy`](#evolveddestroy) and [`evolved.batch_destroy`](#evolvedbatch_destroy) functions
|
||||
- Ensured deterministic chunk ordering to improve processing consistency across runs
|
||||
|
||||
### v1.8.0
|
||||
|
||||
- Added the new [`evolved.REALLOC`](#evolvedrealloc) and [`evolved.COMPMOVE`](#evolvedcompmove) fragment traits that allow customizing component storages
|
||||
- Added `component_mapper` argument to the spawning and cloning functions that allows filling components in chunks during the operation
|
||||
|
||||
### v1.7.0
|
||||
|
||||
- Added the new [`evolved.VARIANTS`](#evolvedvariants) query fragment that allows specifying any of multiple fragments in queries
|
||||
- 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
|
||||
- [`evolved.ON_REMOVE`](#evolvedon_remove) hooks are now invoked before the fragment is actually removed from the entity
|
||||
|
||||
### v1.3.0
|
||||
|
||||
- Added the new [`evolved.cancel`](#evolvedcancel) function
|
||||
@@ -1343,6 +1645,10 @@ builder_mt:destruction_policy :: id -> builder
|
||||
|
||||
### `evolved.DUPLICATE`
|
||||
|
||||
### `evolved.REALLOC`
|
||||
|
||||
### `evolved.COMPMOVE`
|
||||
|
||||
### `evolved.PREFAB`
|
||||
|
||||
### `evolved.DISABLED`
|
||||
@@ -1351,6 +1657,8 @@ builder_mt:destruction_policy :: id -> builder
|
||||
|
||||
### `evolved.EXCLUDES`
|
||||
|
||||
### `evolved.VARIANTS`
|
||||
|
||||
### `evolved.REQUIRES`
|
||||
|
||||
### `evolved.ON_SET`
|
||||
@@ -1400,11 +1708,11 @@ function evolved.name(...) end
|
||||
### `evolved.pack`
|
||||
|
||||
```lua
|
||||
---@param index integer
|
||||
---@param version integer
|
||||
---@param primary integer
|
||||
---@param secondary integer
|
||||
---@return evolved.id id
|
||||
---@nodiscard
|
||||
function evolved.pack(index, version) end
|
||||
function evolved.pack(primary, secondary) end
|
||||
```
|
||||
|
||||
### `evolved.unpack`
|
||||
@@ -1424,6 +1732,14 @@ function evolved.unpack(id) end
|
||||
function evolved.defer() end
|
||||
```
|
||||
|
||||
### `evolved.depth`
|
||||
|
||||
```lua
|
||||
---@return integer depth
|
||||
---@nodiscard
|
||||
function evolved.depth() end
|
||||
```
|
||||
|
||||
### `evolved.commit`
|
||||
|
||||
```lua
|
||||
@@ -1441,27 +1757,31 @@ function evolved.cancel() end
|
||||
### `evolved.spawn`
|
||||
|
||||
```lua
|
||||
---@param components? table<evolved.fragment, evolved.component>
|
||||
---@param component_table? evolved.component_table
|
||||
---@param component_mapper? evolved.component_mapper
|
||||
---@return evolved.entity entity
|
||||
function evolved.spawn(components) end
|
||||
function evolved.spawn(component_table, component_mapper) end
|
||||
```
|
||||
|
||||
### `evolved.multi_spawn`
|
||||
|
||||
```lua
|
||||
---@param entity_count integer
|
||||
---@param components? table<evolved.fragment, evolved.component>
|
||||
---@param component_table? evolved.component_table
|
||||
---@param component_mapper? evolved.component_mapper
|
||||
---@return evolved.entity[] entity_list
|
||||
function evolved.multi_spawn(entity_count, components) end
|
||||
---@return integer entity_count
|
||||
function evolved.multi_spawn(entity_count, component_table, component_mapper) end
|
||||
```
|
||||
|
||||
### `evolved.clone`
|
||||
|
||||
```lua
|
||||
---@param prefab evolved.entity
|
||||
---@param components? table<evolved.fragment, evolved.component>
|
||||
---@param component_table? evolved.component_table
|
||||
---@param component_mapper? evolved.component_mapper
|
||||
---@return evolved.entity entity
|
||||
function evolved.clone(prefab, components) end
|
||||
function evolved.clone(prefab, component_table, component_mapper) end
|
||||
```
|
||||
|
||||
### `evolved.multi_clone`
|
||||
@@ -1469,9 +1789,11 @@ function evolved.clone(prefab, components) end
|
||||
```lua
|
||||
---@param entity_count integer
|
||||
---@param prefab evolved.entity
|
||||
---@param components? table<evolved.fragment, evolved.component>
|
||||
---@param component_table? evolved.component_table
|
||||
---@param component_mapper? evolved.component_mapper
|
||||
---@return evolved.entity[] entity_list
|
||||
function evolved.multi_clone(entity_count, prefab, components) end
|
||||
---@return integer entity_count
|
||||
function evolved.multi_clone(entity_count, prefab, component_table, component_mapper) end
|
||||
```
|
||||
|
||||
### `evolved.alive`
|
||||
@@ -1667,6 +1989,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
|
||||
@@ -1776,27 +2106,51 @@ function evolved.chunk_mt:components(...) end
|
||||
function evolved.builder() end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:build`
|
||||
|
||||
```lua
|
||||
---@param prefab? evolved.entity
|
||||
---@param component_mapper? evolved.component_mapper
|
||||
---@return evolved.entity entity
|
||||
function evolved.builder_mt:build(prefab, component_mapper) end
|
||||
```
|
||||
|
||||
### `evolved.builder_mt:multi_build`
|
||||
|
||||
```lua
|
||||
---@param entity_count integer
|
||||
---@param prefab? evolved.entity
|
||||
---@param component_mapper? evolved.component_mapper
|
||||
---@return evolved.entity[] entity_list
|
||||
---@return integer entity_count
|
||||
function evolved.builder_mt:multi_build(entity_count, prefab, component_mapper) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:spawn`
|
||||
|
||||
```lua
|
||||
---@param component_mapper? evolved.component_mapper
|
||||
---@return evolved.entity entity
|
||||
function evolved.builder_mt:spawn() end
|
||||
function evolved.builder_mt:spawn(component_mapper) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:multi_spawn`
|
||||
|
||||
```lua
|
||||
---@param entity_count integer
|
||||
---@param component_mapper? evolved.component_mapper
|
||||
---@return evolved.entity[] entity_list
|
||||
function evolved.builder_mt:multi_spawn(entity_count) end
|
||||
---@return integer entity_count
|
||||
function evolved.builder_mt:multi_spawn(entity_count, component_mapper) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:clone`
|
||||
|
||||
```lua
|
||||
---@param prefab evolved.entity
|
||||
---@param component_mapper? evolved.component_mapper
|
||||
---@return evolved.entity entity
|
||||
function evolved.builder_mt:clone(prefab) end
|
||||
function evolved.builder_mt:clone(prefab, component_mapper) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:multi_clone`
|
||||
@@ -1804,8 +2158,10 @@ function evolved.builder_mt:clone(prefab) end
|
||||
```lua
|
||||
---@param entity_count integer
|
||||
---@param prefab evolved.entity
|
||||
---@param component_mapper? evolved.component_mapper
|
||||
---@return evolved.entity[] entity_list
|
||||
function evolved.builder_mt:multi_clone(entity_count, prefab) end
|
||||
---@return integer entity_count
|
||||
function evolved.builder_mt:multi_clone(entity_count, prefab, component_mapper) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:has`
|
||||
@@ -1907,7 +2263,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
|
||||
```
|
||||
@@ -1920,6 +2276,22 @@ function evolved.builder_mt:default(default) end
|
||||
function evolved.builder_mt:duplicate(duplicate) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:realloc`
|
||||
|
||||
```lua
|
||||
---@param realloc evolved.realloc
|
||||
---@return evolved.builder builder
|
||||
function evolved.builder_mt:realloc(realloc) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:compmove`
|
||||
|
||||
```lua
|
||||
---@param compmove evolved.compmove
|
||||
---@return evolved.builder builder
|
||||
function evolved.builder_mt:compmove(compmove) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:prefab`
|
||||
|
||||
```lua
|
||||
@@ -1950,6 +2322,14 @@ function evolved.builder_mt:include(...) end
|
||||
function evolved.builder_mt:exclude(...) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:variant`
|
||||
|
||||
```lua
|
||||
---@param ... evolved.fragment fragments
|
||||
---@return evolved.builder builder
|
||||
function evolved.builder_mt:variant(...) end
|
||||
```
|
||||
|
||||
### `evolved.builder_mt:require`
|
||||
|
||||
```lua
|
||||
|
||||
18
ROADMAP.md
18
ROADMAP.md
@@ -1,18 +0,0 @@
|
||||
# Roadmap
|
||||
|
||||
## Backlog
|
||||
|
||||
- Queries can cache major chunks to avoid finding them every time.
|
||||
- observers and events
|
||||
- add INDEX fragment trait
|
||||
- use compact prefix-tree for chunks
|
||||
- optional ffi component storages
|
||||
|
||||
## Thoughts
|
||||
|
||||
- We can return deferred status from modifying operations and spawn/clone methods.
|
||||
- Should we make one builder:build method instead of :spawn and :clone?
|
||||
|
||||
## Known Issues
|
||||
|
||||
- Required fragments are slower than they should be
|
||||
@@ -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`.
|
||||
17
develop/ROADMAP.md
Normal file
17
develop/ROADMAP.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Roadmap
|
||||
|
||||
## Backlog
|
||||
|
||||
- observers and events
|
||||
- add INDEX fragment trait
|
||||
- use compact prefix-tree for chunks
|
||||
|
||||
## Thoughts
|
||||
|
||||
- We should have a way to not copy components on deferred spawn/clone
|
||||
- Having a light version of the gargabe collector can be useful for some use-cases
|
||||
- Basic default component value as true looks awful, should we use something else?
|
||||
|
||||
## Known Issues
|
||||
|
||||
- Errors in hooks or rellocs/compmoves/mappers are cannot be handled properly right now
|
||||
@@ -1,26 +1,34 @@
|
||||
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.mappers_tests'
|
||||
require 'develop.testing.multi_spawn_tests'
|
||||
require 'develop.testing.name_tests'
|
||||
require 'develop.testing.process_with_tests'
|
||||
require 'develop.testing.realloc_tests'
|
||||
require 'develop.testing.requires_fragment_tests'
|
||||
require 'develop.testing.spawn_tests'
|
||||
require 'develop.testing.system_as_query_tests'
|
||||
|
||||
require 'develop.benchmarks.clone_bmarks'
|
||||
require 'develop.benchmarks.common_bmarks'
|
||||
require 'develop.benchmarks.destroy_bmarks'
|
||||
require 'develop.benchmarks.migration_bmarks'
|
||||
require 'develop.benchmarks.process_bmarks'
|
||||
require 'develop.benchmarks.spawn_bmarks'
|
||||
require 'develop.benchmarks.table_bmarks'
|
||||
|
||||
require 'develop.untests'
|
||||
|
||||
local basics = require 'develop.basics'
|
||||
|
||||
print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.destroy_fuzz'
|
||||
print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.execute_fuzz'
|
||||
print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.batch_destroy_fuzz'
|
||||
print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.explicit_fuzz'
|
||||
@@ -30,3 +38,5 @@ print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.requires_fuzz'
|
||||
print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.unique_fuzz'
|
||||
|
||||
print 'All tests passed.'
|
||||
|
||||
@@ -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)
|
||||
|
||||
56
develop/benchmarks/destroy_bmarks.lua
Normal file
56
develop/benchmarks/destroy_bmarks.lua
Normal file
@@ -0,0 +1,56 @@
|
||||
local evo = require 'evolved'
|
||||
local basics = require 'develop.basics'
|
||||
|
||||
evo.debug_mode(false)
|
||||
|
||||
local N = 1000
|
||||
|
||||
print '----------------------------------------'
|
||||
|
||||
basics.describe_bench(string.format('Destroy Benchmarks: Acquire and Release %d ids', N),
|
||||
function(tables)
|
||||
local id = evo.id
|
||||
local destroy = evo.destroy
|
||||
|
||||
for i = 1, N do
|
||||
tables[i] = id()
|
||||
end
|
||||
|
||||
for i = 1, N do
|
||||
destroy(tables[i])
|
||||
end
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('Destroy Benchmarks: Acquire and Release %d double ids', N),
|
||||
function(tables)
|
||||
local id = evo.id
|
||||
local destroy = evo.destroy
|
||||
|
||||
for i = 1, N, 2 do
|
||||
tables[i], tables[i + 1] = id(2)
|
||||
end
|
||||
|
||||
for i = 1, N, 2 do
|
||||
destroy(tables[i], tables[i + 1])
|
||||
end
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('Destroy Benchmarks: Acquire and Release %d triple ids', N),
|
||||
function(tables)
|
||||
local id = evo.id
|
||||
local destroy = evo.destroy
|
||||
|
||||
for i = 1, N, 3 do
|
||||
tables[i], tables[i + 1], tables[i + 2] = id(3)
|
||||
end
|
||||
|
||||
for i = 1, N, 3 do
|
||||
destroy(tables[i], tables[i + 1], tables[i + 2])
|
||||
end
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
@@ -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)
|
||||
|
||||
308
develop/fuzzing/execute_fuzz.lua
Normal file
308
develop/fuzzing/execute_fuzz.lua
Normal file
@@ -0,0 +1,308 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
evo.debug_mode(true)
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
local __table_unpack = (function()
|
||||
---@diagnostic disable-next-line: deprecated
|
||||
return table.unpack or unpack
|
||||
end)()
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
local all_fragment_list = {} ---@type evolved.fragment[]
|
||||
|
||||
for i = 1, math.random(1, 10) do
|
||||
local fragment = evo.id()
|
||||
all_fragment_list[i] = fragment
|
||||
end
|
||||
|
||||
---@param query evolved.query
|
||||
local function generate_query(query)
|
||||
local include_set = {}
|
||||
local include_list = {}
|
||||
local include_count = 0
|
||||
|
||||
for _ = 1, math.random(0, #all_fragment_list) do
|
||||
local include = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
|
||||
if not include_set[include] then
|
||||
include_count = include_count + 1
|
||||
include_set[include] = include_count
|
||||
include_list[include_count] = include
|
||||
end
|
||||
end
|
||||
|
||||
local exclude_set = {}
|
||||
local exclude_list = {}
|
||||
local exclude_count = 0
|
||||
|
||||
for _ = 1, math.random(0, #all_fragment_list) do
|
||||
local exclude = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
|
||||
if not exclude_set[exclude] then
|
||||
exclude_count = exclude_count + 1
|
||||
exclude_set[exclude] = exclude_count
|
||||
exclude_list[exclude_count] = exclude
|
||||
end
|
||||
end
|
||||
|
||||
local variant_set = {}
|
||||
local variant_list = {}
|
||||
local variant_count = 0
|
||||
|
||||
for _ = 1, math.random(0, #all_fragment_list) do
|
||||
local variant = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
|
||||
if not variant_set[variant] then
|
||||
variant_count = variant_count + 1
|
||||
variant_set[variant] = variant_count
|
||||
variant_list[variant_count] = variant
|
||||
end
|
||||
end
|
||||
|
||||
if include_count > 0 then
|
||||
evo.set(query, evo.INCLUDES, include_list)
|
||||
end
|
||||
|
||||
if exclude_count > 0 then
|
||||
evo.set(query, evo.EXCLUDES, exclude_list)
|
||||
end
|
||||
|
||||
if variant_count > 0 then
|
||||
evo.set(query, evo.VARIANTS, variant_list)
|
||||
end
|
||||
end
|
||||
|
||||
---@param query_count integer
|
||||
---@return evolved.query[] query_list
|
||||
---@return integer query_count
|
||||
---@nodiscard
|
||||
local function generate_queries(query_count)
|
||||
local query_list = {} ---@type evolved.query[]
|
||||
|
||||
for i = 1, query_count do
|
||||
local query = evo.id()
|
||||
query_list[i] = query
|
||||
generate_query(query)
|
||||
end
|
||||
|
||||
return query_list, query_count
|
||||
end
|
||||
|
||||
---@param entity evolved.entity
|
||||
local function generate_entity(entity)
|
||||
for _ = 0, math.random(0, #all_fragment_list) do
|
||||
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
evo.set(entity, fragment)
|
||||
end
|
||||
end
|
||||
|
||||
---@param entity_count integer
|
||||
---@return evolved.entity[] entity_list
|
||||
---@return integer entity_count
|
||||
local function generate_entities(entity_count)
|
||||
local entity_list = {} ---@type evolved.entity[]
|
||||
|
||||
for i = 1, entity_count do
|
||||
local entity = evo.id()
|
||||
entity_list[i] = entity
|
||||
generate_entity(entity)
|
||||
end
|
||||
|
||||
return entity_list, entity_count
|
||||
end
|
||||
|
||||
local pre_query_list, pre_query_count = generate_queries(math.random(1, 10))
|
||||
local pre_entity_list, pre_entity_count = generate_entities(math.random(1, 10))
|
||||
|
||||
for _ = 1, math.random(1, 5) do
|
||||
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
|
||||
evo.set(fragment, evo.EXPLICIT)
|
||||
end
|
||||
|
||||
for _ = 1, math.random(1, 5) do
|
||||
local query = pre_query_list[math.random(1, pre_query_count)]
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
generate_query(query)
|
||||
else
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.remove(query, evo.INCLUDES)
|
||||
else
|
||||
evo.remove(query, evo.EXCLUDES)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local post_query_list, post_query_count = generate_queries(math.random(1, 10))
|
||||
local post_entity_list, post_entity_count = generate_entities(math.random(1, 10))
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
local all_query_list = {}
|
||||
local all_query_count = 0
|
||||
local all_entity_list = {}
|
||||
local all_entity_count = 0
|
||||
|
||||
for i = 1, pre_query_count do
|
||||
all_query_count = all_query_count + 1
|
||||
all_query_list[all_query_count] = pre_query_list[i]
|
||||
end
|
||||
|
||||
for i = 1, post_query_count do
|
||||
all_query_count = all_query_count + 1
|
||||
all_query_list[all_query_count] = post_query_list[i]
|
||||
end
|
||||
|
||||
for i = 1, pre_entity_count do
|
||||
all_entity_count = all_entity_count + 1
|
||||
all_entity_list[all_entity_count] = pre_entity_list[i]
|
||||
end
|
||||
|
||||
for i = 1, post_entity_count do
|
||||
all_entity_count = all_entity_count + 1
|
||||
all_entity_list[all_entity_count] = post_entity_list[i]
|
||||
end
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
local function execute_query(query)
|
||||
local query_chunk_set = {}
|
||||
local query_entity_set = {}
|
||||
|
||||
local query_include_list = evo.get(query, evo.INCLUDES) or {}
|
||||
local query_exclude_list = evo.get(query, evo.EXCLUDES) or {}
|
||||
local query_variant_list = evo.get(query, evo.VARIANTS) or {}
|
||||
|
||||
local query_include_count = #query_include_list
|
||||
local query_exclude_count = #query_exclude_list
|
||||
local query_variant_count = #query_variant_list
|
||||
|
||||
local query_include_set = {}
|
||||
for _, include in ipairs(query_include_list) do
|
||||
query_include_set[include] = true
|
||||
end
|
||||
|
||||
local query_variant_set = {}
|
||||
for _, variant in ipairs(query_variant_list) do
|
||||
query_variant_set[variant] = true
|
||||
end
|
||||
|
||||
for chunk, entity_list, entity_count in evo.execute(query) do
|
||||
assert(not query_chunk_set[chunk])
|
||||
query_chunk_set[chunk] = true
|
||||
|
||||
for i = 1, entity_count do
|
||||
local entity = entity_list[i]
|
||||
assert(not query_entity_set[entity])
|
||||
query_entity_set[entity] = true
|
||||
end
|
||||
|
||||
if query_include_count > 0 then
|
||||
assert(chunk:has_all(__table_unpack(query_include_list)))
|
||||
end
|
||||
|
||||
if query_exclude_count > 0 then
|
||||
assert(not chunk:has_any(__table_unpack(query_exclude_list)))
|
||||
end
|
||||
|
||||
if query_variant_count > 0 then
|
||||
assert(chunk:has_any(__table_unpack(query_variant_list)))
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, all_entity_count do
|
||||
local entity = all_entity_list[i]
|
||||
|
||||
local is_entity_matched =
|
||||
(query_variant_count == 0 or evo.has_any(entity, __table_unpack(query_variant_list))) and
|
||||
(query_include_count == 0 or evo.has_all(entity, __table_unpack(query_include_list))) and
|
||||
(query_exclude_count == 0 or not evo.has_any(entity, __table_unpack(query_exclude_list)))
|
||||
|
||||
for fragment in evo.each(entity) do
|
||||
if evo.has(fragment, evo.EXPLICIT) and not query_variant_set[fragment] and not query_include_set[fragment] then
|
||||
is_entity_matched = false
|
||||
end
|
||||
end
|
||||
|
||||
if is_entity_matched then
|
||||
assert(query_entity_set[entity])
|
||||
else
|
||||
assert(not query_entity_set[entity])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, all_query_count do
|
||||
execute_query(all_query_list[i])
|
||||
end
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
for _ = 1, math.random(1, 5) do
|
||||
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
|
||||
evo.set(fragment, evo.EXPLICIT)
|
||||
end
|
||||
|
||||
for _ = 1, math.random(1, 5) do
|
||||
local query = pre_query_list[math.random(1, pre_query_count)]
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
generate_query(query)
|
||||
else
|
||||
local r = math.random(1, 3)
|
||||
if r == 1 then
|
||||
evo.remove(query, evo.INCLUDES)
|
||||
elseif r == 2 then
|
||||
evo.remove(query, evo.EXCLUDES)
|
||||
else
|
||||
evo.remove(query, evo.VARIANTS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, all_query_count do
|
||||
execute_query(all_query_list[i])
|
||||
end
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
evo.destroy(__table_unpack(all_query_list))
|
||||
evo.destroy(__table_unpack(all_entity_list))
|
||||
evo.destroy(__table_unpack(all_fragment_list))
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
@@ -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
|
||||
41
develop/testing/build_tests.lua
Normal file
41
develop/testing/build_tests.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
|
||||
do
|
||||
local e = evo.builder():set(f1, 42):set(f2, 'hello'):build()
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 'hello')
|
||||
end
|
||||
|
||||
do
|
||||
local p = evo.builder():set(f1, 42):build()
|
||||
local e = evo.builder():set(f2, 'hello'):build(p)
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 'hello')
|
||||
end
|
||||
|
||||
do
|
||||
local entity_list, entity_count = evo.builder():set(f1, 42):set(f2, 'hello'):multi_build(5)
|
||||
assert(entity_count == 5)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local e = entity_list[i]
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 'hello')
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local p = evo.builder():set(f1, 42):build()
|
||||
local entity_list, entity_count = evo.builder():set(f2, 'hello'):multi_build(5, p)
|
||||
assert(entity_count == 5)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local e = entity_list[i]
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 'hello')
|
||||
end
|
||||
end
|
||||
end
|
||||
397
develop/testing/clone_tests.lua
Normal file
397
develop/testing/clone_tests.lua
Normal 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
|
||||
65
develop/testing/depth_tests.lua
Normal file
65
develop/testing/depth_tests.lua
Normal 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
|
||||
104
develop/testing/destroy_tests.lua
Normal file
104
develop/testing/destroy_tests.lua
Normal 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
|
||||
@@ -2302,27 +2302,66 @@ do
|
||||
evo.set(e2, f2, 44)
|
||||
|
||||
do
|
||||
local iter, state = evo.execute(q)
|
||||
local chunk = iter(state)
|
||||
assert(chunk and chunk ~= evo.chunk(f1))
|
||||
local e1_count = 0
|
||||
local e2_count = 0
|
||||
|
||||
for _, entity_list, entity_count in evo.execute(q) do
|
||||
for i = 1, entity_count do
|
||||
if entity_list[i] == e1 then
|
||||
e1_count = e1_count + 1
|
||||
elseif entity_list[i] == e2 then
|
||||
e2_count = e2_count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert(e1_count == 1)
|
||||
assert(e2_count == 1)
|
||||
end
|
||||
|
||||
evo.set(q, evo.EXCLUDES, { f2 })
|
||||
|
||||
do
|
||||
local iter, state = evo.execute(q)
|
||||
local chunk = iter(state)
|
||||
assert(chunk and chunk ~= evo.chunk(f1))
|
||||
local e1_count = 0
|
||||
local e2_count = 0
|
||||
|
||||
for chunk, entity_list, entity_count in evo.execute(q) do
|
||||
assert(not chunk:has(f2))
|
||||
|
||||
for i = 1, entity_count do
|
||||
if entity_list[i] == e1 then
|
||||
e1_count = e1_count + 1
|
||||
elseif entity_list[i] == e2 then
|
||||
e2_count = e2_count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert(e1_count == 1)
|
||||
assert(e2_count == 0)
|
||||
end
|
||||
|
||||
evo.set(q, evo.INCLUDES, { f1 })
|
||||
|
||||
do
|
||||
local iter, state = evo.execute(q)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(chunk == evo.chunk(f1))
|
||||
assert(entity_list and entity_list[1] == e1)
|
||||
assert(entity_count == 1)
|
||||
local e1_count = 0
|
||||
local e2_count = 0
|
||||
|
||||
for chunk, entity_list, entity_count in evo.execute(q) do
|
||||
assert(chunk:has(f1))
|
||||
assert(not chunk:has(f2))
|
||||
|
||||
for i = 1, entity_count do
|
||||
if entity_list[i] == e1 then
|
||||
e1_count = e1_count + 1
|
||||
elseif entity_list[i] == e2 then
|
||||
e2_count = e2_count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert(e1_count == 1)
|
||||
assert(e2_count == 0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2530,7 +2569,7 @@ do
|
||||
end)
|
||||
:on_remove(function(e, f, c)
|
||||
f2_remove_count = f2_remove_count + 1
|
||||
assert(evo.get(e, f) == nil)
|
||||
assert(evo.get(e, f) == c)
|
||||
assert(evo.alive(f))
|
||||
assert(c == 82)
|
||||
end)
|
||||
@@ -3321,7 +3360,7 @@ do
|
||||
remove_count = remove_count + 1
|
||||
assert(f == f1)
|
||||
assert(c == 51)
|
||||
assert(evo.get(e, f1) == nil)
|
||||
assert(evo.get(e, f1) == c)
|
||||
|
||||
do
|
||||
evo.remove(e, f2)
|
||||
@@ -3348,7 +3387,7 @@ do
|
||||
remove_count = remove_count + 1
|
||||
assert(f == f2)
|
||||
assert(c == 51)
|
||||
assert(evo.get(e, f2) == nil)
|
||||
assert(evo.get(e, f2) == c)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -3518,8 +3557,7 @@ do
|
||||
assert(e == e1 or e == e2)
|
||||
assert(f == f1)
|
||||
assert(c == 51)
|
||||
assert(evo.get(e1, f1) == nil)
|
||||
assert(evo.get(e2, f1) == nil)
|
||||
assert(evo.get(e, f) == c)
|
||||
end)
|
||||
|
||||
do
|
||||
@@ -6449,3 +6487,650 @@ do
|
||||
assert(b:has_all() and not b:has_any())
|
||||
assert(b:has(ff) and b:has(ft) and b:has_all(ff, ft) and b:has_any(ff, ft))
|
||||
end
|
||||
|
||||
do
|
||||
do
|
||||
local f = evo.id()
|
||||
local q = evo.builder():include(f):spawn()
|
||||
local e = evo.builder():set(f, 42):spawn()
|
||||
|
||||
local iter, state = evo.execute(q)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(chunk and entity_list and entity_count)
|
||||
assert(chunk == evo.chunk(f) and entity_count == 1 and entity_list[1] == e)
|
||||
end
|
||||
|
||||
do
|
||||
local f = evo.id()
|
||||
local e = evo.builder():set(f, 42):spawn()
|
||||
local q = evo.builder():include(f):spawn()
|
||||
|
||||
local iter, state = evo.execute(q)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(chunk and entity_list and entity_count)
|
||||
assert(chunk == evo.chunk(f) and entity_count == 1 and entity_list[1] == e)
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
local q = evo.builder():exclude(f2):spawn()
|
||||
local e = evo.builder():set(f1, 42):spawn()
|
||||
|
||||
local e_count = 0
|
||||
|
||||
for chunk, entity_list, entity_count in evo.execute(q) do
|
||||
for i = 1, entity_count do
|
||||
if entity_list[i] == e then
|
||||
e_count = e_count + 1
|
||||
assert(chunk == evo.chunk(f1))
|
||||
assert(chunk:components(f1)[1] == 42)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert(e_count == 1)
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3 = evo.id(3)
|
||||
local q = evo.builder():exclude(f2):spawn()
|
||||
local e1 = evo.builder():set(f1, 42):spawn()
|
||||
local e2 = evo.builder():set(f1, 42):set(f3, 21):spawn()
|
||||
|
||||
local e1_count, e2_count = 0, 0
|
||||
|
||||
for chunk, entity_list, entity_count in evo.execute(q) do
|
||||
for i = 1, entity_count do
|
||||
if entity_list[i] == e1 then
|
||||
e1_count = e1_count + 1
|
||||
assert(chunk == evo.chunk(f1))
|
||||
assert(chunk:components(f1)[1] == 42)
|
||||
end
|
||||
|
||||
if entity_list[i] == e2 then
|
||||
e2_count = e2_count + 1
|
||||
assert(chunk == evo.chunk(f1, f3))
|
||||
assert(chunk:components(f1)[1] == 42)
|
||||
assert(chunk:components(f3)[1] == 21)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert(e1_count == 1)
|
||||
assert(e2_count == 1)
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
local e = evo.builder():set(f1, 42):spawn()
|
||||
local q = evo.builder():exclude(f2):spawn()
|
||||
|
||||
local e_count = 0
|
||||
|
||||
for chunk, entity_list, entity_count in evo.execute(q) do
|
||||
for i = 1, entity_count do
|
||||
if entity_list[i] == e then
|
||||
e_count = e_count + 1
|
||||
assert(chunk == evo.chunk(f1))
|
||||
assert(chunk:components(f1)[1] == 42)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert(e_count == 1)
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3 = evo.id(3)
|
||||
local e1 = evo.builder():set(f1, 42):spawn()
|
||||
local e2 = evo.builder():set(f1, 42):set(f3, 21):spawn()
|
||||
local q = evo.builder():exclude(f2):spawn()
|
||||
|
||||
local e1_count, e2_count = 0, 0
|
||||
|
||||
for chunk, entity_list, entity_count in evo.execute(q) do
|
||||
for i = 1, entity_count do
|
||||
if entity_list[i] == e1 then
|
||||
e1_count = e1_count + 1
|
||||
assert(chunk == evo.chunk(f1))
|
||||
assert(chunk:components(f1)[1] == 42)
|
||||
end
|
||||
|
||||
if entity_list[i] == e2 then
|
||||
e2_count = e2_count + 1
|
||||
assert(chunk == evo.chunk(f1, f3))
|
||||
assert(chunk:components(f1)[1] == 42)
|
||||
assert(chunk:components(f3)[1] == 21)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert(e1_count == 1)
|
||||
assert(e2_count == 1)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
local q1 = evo.builder():include(f1):spawn()
|
||||
local q2 = evo.builder():include(f2):spawn()
|
||||
local e12 = evo.builder():set(f1, 42):set(f2, 21):spawn()
|
||||
|
||||
do
|
||||
local iter, state = evo.execute(q1)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(chunk and entity_list and entity_count)
|
||||
assert(chunk == evo.chunk(f1, f2) and entity_count == 1 and entity_list[1] == e12)
|
||||
end
|
||||
|
||||
do
|
||||
local iter, state = evo.execute(q2)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(chunk and entity_list and entity_count)
|
||||
assert(chunk == evo.chunk(f1, f2) and entity_count == 1 and entity_list[1] == e12)
|
||||
end
|
||||
|
||||
evo.set(f1, evo.EXPLICIT)
|
||||
|
||||
do
|
||||
local iter, state = evo.execute(q1)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(chunk and entity_list and entity_count)
|
||||
assert(chunk == evo.chunk(f1, f2) and entity_count == 1 and entity_list[1] == e12)
|
||||
end
|
||||
|
||||
do
|
||||
local iter, state = evo.execute(q2)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(not chunk and not entity_list and not entity_count)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local function v2(x, y) return { x = x or 0, y = y or 0 } end
|
||||
local function v2_clone(v) return { x = v.x, y = v.y } end
|
||||
|
||||
local f1, f2 = evo.id(2)
|
||||
|
||||
local f1_default = v2(1, 2)
|
||||
local f2_default = v2(3, 4)
|
||||
|
||||
evo.set(f1, evo.DEFAULT, f1_default)
|
||||
evo.set(f2, evo.DEFAULT, f2_default)
|
||||
|
||||
evo.set(f1, evo.DUPLICATE, v2_clone)
|
||||
evo.set(f2, evo.DUPLICATE, v2_clone)
|
||||
|
||||
local e1 = evo.builder():set(f1, v2(10, 11)):spawn()
|
||||
local e2 = evo.builder():set(f1, v2(12, 13)):set(f2, v2(14, 15)):spawn()
|
||||
|
||||
do
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1).x == 10 and evo.get(e1, f1).y == 11)
|
||||
assert(evo.get(e1, f1) ~= f1_default)
|
||||
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1).x == 12 and evo.get(e2, f1).y == 13)
|
||||
assert(evo.get(e2, f1) ~= f1_default)
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2).x == 14 and evo.get(e2, f2).y == 15)
|
||||
assert(evo.get(e2, f2) ~= f2_default)
|
||||
end
|
||||
|
||||
evo.set(f1, evo.TAG)
|
||||
|
||||
do
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == nil)
|
||||
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == nil)
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2).x == 14 and evo.get(e2, f2).y == 15)
|
||||
assert(evo.get(e2, f2) ~= f2_default)
|
||||
end
|
||||
|
||||
evo.remove(f1, evo.TAG)
|
||||
|
||||
do
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1).x == 1 and evo.get(e1, f1).y == 2)
|
||||
assert(evo.get(e1, f1) ~= f1_default)
|
||||
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1).x == 1 and evo.get(e2, f1).y == 2)
|
||||
assert(evo.get(e2, f1) ~= f1_default)
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2).x == 14 and evo.get(e2, f2).y == 15)
|
||||
assert(evo.get(e2, f2) ~= f2_default)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3 = evo.id(3)
|
||||
|
||||
evo.set(f1, evo.REQUIRES, { f2, f3 })
|
||||
evo.set(f2, evo.DEFAULT, false)
|
||||
evo.set(f3, evo.TAG)
|
||||
|
||||
local v_set_sum = 0
|
||||
local v_insert_sum = 0
|
||||
|
||||
local f3_set_times = 0
|
||||
local f3_insert_times = 0
|
||||
|
||||
evo.set(f1, evo.ON_SET, function(e, f, v)
|
||||
assert(f == f1)
|
||||
v_set_sum = v_set_sum + v
|
||||
assert(evo.get(e, f) == v)
|
||||
end)
|
||||
|
||||
evo.set(f1, evo.ON_INSERT, function(e, f, v)
|
||||
assert(f == f1)
|
||||
v_insert_sum = v_insert_sum + v
|
||||
assert(evo.get(e, f) == v)
|
||||
end)
|
||||
|
||||
evo.set(f3, evo.ON_SET, function(e, f, v)
|
||||
assert(f == f3)
|
||||
f3_set_times = f3_set_times + 1
|
||||
assert(v == nil)
|
||||
assert(evo.has(e, f))
|
||||
end)
|
||||
|
||||
evo.set(f3, evo.ON_INSERT, function(e, f, v)
|
||||
assert(f == f3)
|
||||
f3_insert_times = f3_insert_times + 1
|
||||
assert(v == nil)
|
||||
assert(evo.has(e, f))
|
||||
end)
|
||||
|
||||
do
|
||||
local e = evo.spawn({ [f1] = 42 })
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == false)
|
||||
end
|
||||
|
||||
do
|
||||
local entity_prefab = evo.builder():set(f1, 42):spawn()
|
||||
|
||||
local e = evo.clone(entity_prefab)
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == false)
|
||||
end
|
||||
|
||||
do
|
||||
local entity_prefab = evo.builder():set(f1, 42):spawn()
|
||||
evo.remove(entity_prefab, f2, f3)
|
||||
|
||||
local e = evo.clone(entity_prefab, { [f1] = 21 })
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 21)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == false)
|
||||
end
|
||||
|
||||
assert(v_set_sum == 42 * 4 + 21 * 1)
|
||||
assert(v_insert_sum == 42 * 4 + 21 * 1)
|
||||
|
||||
assert(f3_set_times == 5)
|
||||
assert(f3_insert_times == 5)
|
||||
end
|
||||
|
||||
do
|
||||
local function v2(x, y) return { x = x or 0, y = y or 0 } end
|
||||
local function v2_clone(v) return { x = v.x, y = v.y } end
|
||||
|
||||
local f1, f2, f3, f4, f5, f6, f7 = evo.id(7)
|
||||
evo.set(f1, evo.REQUIRES, { f2, f3, f4 })
|
||||
evo.set(f5, evo.REQUIRES, { f6, f7 })
|
||||
|
||||
local f1_default = v2(1, 2)
|
||||
local f2_default = v2(3, 4)
|
||||
local f3_default = v2(10, 11)
|
||||
local f4_default = v2(12, 13)
|
||||
local f6_default = v2(14, 15)
|
||||
local f7_default = v2(16, 17)
|
||||
|
||||
evo.set(f1, evo.DEFAULT, f1_default)
|
||||
evo.set(f2, evo.DEFAULT, f2_default)
|
||||
evo.set(f3, evo.DEFAULT, f3_default)
|
||||
evo.set(f4, evo.DEFAULT, f4_default)
|
||||
evo.set(f6, evo.DEFAULT, f6_default)
|
||||
evo.set(f7, evo.DEFAULT, f7_default)
|
||||
|
||||
evo.set(f1, evo.DUPLICATE, v2_clone)
|
||||
evo.set(f2, evo.DUPLICATE, v2_clone)
|
||||
evo.set(f3, evo.DUPLICATE, v2_clone)
|
||||
evo.set(f5, evo.DUPLICATE, v2_clone)
|
||||
evo.set(f6, evo.DUPLICATE, v2_clone)
|
||||
|
||||
do
|
||||
local entity_list, entity_count = evo.multi_spawn(2, { [f1] = v2(5, 6), [f2] = v2(7, 8) })
|
||||
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_count == 2)
|
||||
|
||||
local q_f1 = evo.builder():include(f1):spawn()
|
||||
|
||||
local f2_v = v2(20, 21)
|
||||
evo.batch_set(q_f1, f2, f2_v)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local e = entity_list[i]
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1).x == 5 and evo.get(e, f1).y == 6)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2).x == 20 and evo.get(e, f2).y == 21)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3).x == 10 and evo.get(e, f3).y == 11)
|
||||
assert(evo.has(e, f4) and evo.get(e, f4).x == 12 and evo.get(e, f4).y == 13)
|
||||
|
||||
assert(evo.get(e, f1) ~= f1_default)
|
||||
assert(evo.get(e, f2) ~= f2_v and evo.get(e, f2) ~= f2_default)
|
||||
assert(evo.get(e, f3) ~= f3_default)
|
||||
assert(evo.get(e, f4) == f4_default)
|
||||
end
|
||||
|
||||
local f5_v = v2(30, 31)
|
||||
evo.batch_set(q_f1, f5, f5_v)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local e = entity_list[i]
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1).x == 5 and evo.get(e, f1).y == 6)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2).x == 20 and evo.get(e, f2).y == 21)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3).x == 10 and evo.get(e, f3).y == 11)
|
||||
assert(evo.has(e, f4) and evo.get(e, f4).x == 12 and evo.get(e, f4).y == 13)
|
||||
assert(evo.has(e, f5) and evo.get(e, f5).x == 30 and evo.get(e, f5).y == 31)
|
||||
assert(evo.has(e, f6) and evo.get(e, f6).x == 14 and evo.get(e, f6).y == 15)
|
||||
assert(evo.has(e, f7) and evo.get(e, f7).x == 16 and evo.get(e, f7).y == 17)
|
||||
|
||||
assert(evo.get(e, f1) ~= f1_default)
|
||||
assert(evo.get(e, f2) ~= f2_v and evo.get(e, f2) ~= f2_default)
|
||||
assert(evo.get(e, f3) ~= f3_default)
|
||||
assert(evo.get(e, f4) == f4_default)
|
||||
assert(evo.get(e, f5) ~= f5_v)
|
||||
assert(evo.get(e, f6) ~= f6_default)
|
||||
assert(evo.get(e, f7) == f7_default)
|
||||
end
|
||||
|
||||
f5_v = v2(32, 33)
|
||||
evo.batch_set(q_f1, f5, f5_v)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local e = entity_list[i]
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1).x == 5 and evo.get(e, f1).y == 6)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2).x == 20 and evo.get(e, f2).y == 21)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3).x == 10 and evo.get(e, f3).y == 11)
|
||||
assert(evo.has(e, f4) and evo.get(e, f4).x == 12 and evo.get(e, f4).y == 13)
|
||||
assert(evo.has(e, f5) and evo.get(e, f5).x == 32 and evo.get(e, f5).y == 33)
|
||||
assert(evo.has(e, f6) and evo.get(e, f6).x == 14 and evo.get(e, f6).y == 15)
|
||||
assert(evo.has(e, f7) and evo.get(e, f7).x == 16 and evo.get(e, f7).y == 17)
|
||||
|
||||
assert(evo.get(e, f1) ~= f1_default)
|
||||
assert(evo.get(e, f2) ~= f2_v and evo.get(e, f2) ~= f2_default)
|
||||
assert(evo.get(e, f3) ~= f3_default)
|
||||
assert(evo.get(e, f4) == f4_default)
|
||||
assert(evo.get(e, f5) ~= f5_v)
|
||||
assert(evo.get(e, f6) ~= f6_default)
|
||||
assert(evo.get(e, f7) == f7_default)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local function v2(x, y) return { x = x or 0, y = y or 0 } end
|
||||
local function v2_clone(v) return { x = v.x, y = v.y } end
|
||||
|
||||
local f1, f2, f3, f4, f5, f6, f7 = evo.id(7)
|
||||
evo.set(f1, evo.REQUIRES, { f2, f3, f4 })
|
||||
evo.set(f5, evo.REQUIRES, { f6, f7 })
|
||||
|
||||
local f1_default = v2(1, 2)
|
||||
local f2_default = v2(3, 4)
|
||||
local f3_default = v2(10, 11)
|
||||
local f4_default = v2(12, 13)
|
||||
local f6_default = v2(14, 15)
|
||||
local f7_default = v2(16, 17)
|
||||
|
||||
evo.set(f1, evo.DEFAULT, f1_default)
|
||||
evo.set(f2, evo.DEFAULT, f2_default)
|
||||
evo.set(f3, evo.DEFAULT, f3_default)
|
||||
evo.set(f4, evo.DEFAULT, f4_default)
|
||||
evo.set(f6, evo.DEFAULT, f6_default)
|
||||
evo.set(f7, evo.DEFAULT, f7_default)
|
||||
|
||||
evo.set(f1, evo.DUPLICATE, v2_clone)
|
||||
evo.set(f2, evo.DUPLICATE, v2_clone)
|
||||
evo.set(f3, evo.DUPLICATE, v2_clone)
|
||||
evo.set(f5, evo.DUPLICATE, v2_clone)
|
||||
evo.set(f6, evo.DUPLICATE, v2_clone)
|
||||
|
||||
local f5_set_sum = 0
|
||||
local f5_insert_sum = 0
|
||||
local f6_set_sum = 0
|
||||
local f6_insert_sum = 0
|
||||
local f7_set_sum = 0
|
||||
local f7_insert_sum = 0
|
||||
|
||||
evo.set(f5, evo.ON_SET, function(e, f, v)
|
||||
assert(evo.get(e, f) == v)
|
||||
assert(f == f5)
|
||||
f5_set_sum = f5_set_sum + v.x + v.y
|
||||
end)
|
||||
|
||||
evo.set(f5, evo.ON_INSERT, function(e, f, v)
|
||||
assert(evo.get(e, f) == v)
|
||||
assert(f == f5)
|
||||
f5_insert_sum = f5_insert_sum + v.x + v.y
|
||||
end)
|
||||
|
||||
evo.set(f6, evo.ON_SET, function(e, f, v)
|
||||
assert(evo.get(e, f) == v)
|
||||
assert(f == f6)
|
||||
f6_set_sum = f6_set_sum + v.x + v.y
|
||||
end)
|
||||
|
||||
evo.set(f6, evo.ON_INSERT, function(e, f, v)
|
||||
assert(evo.get(e, f) == v)
|
||||
assert(f == f6)
|
||||
f6_insert_sum = f6_insert_sum + v.x + v.y
|
||||
end)
|
||||
|
||||
evo.set(f7, evo.ON_SET, function(e, f, v)
|
||||
assert(evo.get(e, f) == v)
|
||||
assert(f == f7)
|
||||
f7_set_sum = f7_set_sum + v.x + v.y
|
||||
end)
|
||||
|
||||
evo.set(f7, evo.ON_INSERT, function(e, f, v)
|
||||
assert(evo.get(e, f) == v)
|
||||
assert(f == f7)
|
||||
f7_insert_sum = f7_insert_sum + v.x + v.y
|
||||
end)
|
||||
|
||||
do
|
||||
local entity_list, entity_count = evo.multi_spawn(2, { [f1] = v2(5, 6), [f2] = v2(7, 8) })
|
||||
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_count == 2)
|
||||
|
||||
local q_f1 = evo.builder():include(f1):spawn()
|
||||
|
||||
local f2_v = v2(20, 21)
|
||||
evo.batch_set(q_f1, f2, f2_v)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local e = entity_list[i]
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1).x == 5 and evo.get(e, f1).y == 6)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2).x == 20 and evo.get(e, f2).y == 21)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3).x == 10 and evo.get(e, f3).y == 11)
|
||||
assert(evo.has(e, f4) and evo.get(e, f4).x == 12 and evo.get(e, f4).y == 13)
|
||||
|
||||
assert(evo.get(e, f1) ~= f1_default)
|
||||
assert(evo.get(e, f2) ~= f2_v and evo.get(e, f2) ~= f2_default)
|
||||
assert(evo.get(e, f3) ~= f3_default)
|
||||
assert(evo.get(e, f4) == f4_default)
|
||||
end
|
||||
|
||||
assert(f5_set_sum == 0)
|
||||
assert(f5_insert_sum == 0)
|
||||
assert(f6_set_sum == 0)
|
||||
assert(f6_insert_sum == 0)
|
||||
assert(f7_set_sum == 0)
|
||||
assert(f7_insert_sum == 0)
|
||||
|
||||
local f5_v = v2(30, 31)
|
||||
evo.batch_set(q_f1, f5, f5_v)
|
||||
|
||||
assert(f5_set_sum == (30 + 31) * entity_count)
|
||||
assert(f5_insert_sum == (30 + 31) * entity_count)
|
||||
assert(f6_set_sum == (14 + 15) * entity_count)
|
||||
assert(f6_insert_sum == (14 + 15) * entity_count)
|
||||
assert(f7_set_sum == (16 + 17) * entity_count)
|
||||
assert(f7_insert_sum == (16 + 17) * entity_count)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local e = entity_list[i]
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1).x == 5 and evo.get(e, f1).y == 6)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2).x == 20 and evo.get(e, f2).y == 21)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3).x == 10 and evo.get(e, f3).y == 11)
|
||||
assert(evo.has(e, f4) and evo.get(e, f4).x == 12 and evo.get(e, f4).y == 13)
|
||||
assert(evo.has(e, f5) and evo.get(e, f5).x == 30 and evo.get(e, f5).y == 31)
|
||||
assert(evo.has(e, f6) and evo.get(e, f6).x == 14 and evo.get(e, f6).y == 15)
|
||||
assert(evo.has(e, f7) and evo.get(e, f7).x == 16 and evo.get(e, f7).y == 17)
|
||||
|
||||
assert(evo.get(e, f1) ~= f1_default)
|
||||
assert(evo.get(e, f2) ~= f2_v and evo.get(e, f2) ~= f2_default)
|
||||
assert(evo.get(e, f3) ~= f3_default)
|
||||
assert(evo.get(e, f4) == f4_default)
|
||||
assert(evo.get(e, f5) ~= f5_v)
|
||||
assert(evo.get(e, f6) ~= f6_default)
|
||||
assert(evo.get(e, f7) == f7_default)
|
||||
end
|
||||
|
||||
f5_set_sum = 0
|
||||
f5_insert_sum = 0
|
||||
f6_set_sum = 0
|
||||
f6_insert_sum = 0
|
||||
f7_set_sum = 0
|
||||
f7_insert_sum = 0
|
||||
|
||||
f5_v = v2(32, 33)
|
||||
evo.batch_set(q_f1, f5, f5_v)
|
||||
|
||||
assert(f5_set_sum == (32 + 33) * entity_count)
|
||||
assert(f5_insert_sum == 0)
|
||||
assert(f6_set_sum == 0)
|
||||
assert(f6_insert_sum == 0)
|
||||
assert(f7_set_sum == 0)
|
||||
assert(f7_insert_sum == 0)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local e = entity_list[i]
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1).x == 5 and evo.get(e, f1).y == 6)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2).x == 20 and evo.get(e, f2).y == 21)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3).x == 10 and evo.get(e, f3).y == 11)
|
||||
assert(evo.has(e, f4) and evo.get(e, f4).x == 12 and evo.get(e, f4).y == 13)
|
||||
assert(evo.has(e, f5) and evo.get(e, f5).x == 32 and evo.get(e, f5).y == 33)
|
||||
assert(evo.has(e, f6) and evo.get(e, f6).x == 14 and evo.get(e, f6).y == 15)
|
||||
assert(evo.has(e, f7) and evo.get(e, f7).x == 16 and evo.get(e, f7).y == 17)
|
||||
|
||||
assert(evo.get(e, f1) ~= f1_default)
|
||||
assert(evo.get(e, f2) ~= f2_v and evo.get(e, f2) ~= f2_default)
|
||||
assert(evo.get(e, f3) ~= f3_default)
|
||||
assert(evo.get(e, f4) == f4_default)
|
||||
assert(evo.get(e, f5) ~= f5_v)
|
||||
assert(evo.get(e, f6) ~= f6_default)
|
||||
assert(evo.get(e, f7) == f7_default)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local s1, s2 = evo.id(2)
|
||||
|
||||
local process_order = ''
|
||||
|
||||
evo.set(s1, evo.PROLOGUE, function()
|
||||
process_order = process_order .. '1'
|
||||
end)
|
||||
|
||||
evo.set(s2, evo.PROLOGUE, function()
|
||||
process_order = process_order .. '2'
|
||||
end)
|
||||
|
||||
do
|
||||
process_order = ''
|
||||
evo.set(s2, evo.GROUP, s1)
|
||||
evo.process(s1)
|
||||
assert(process_order == '12')
|
||||
end
|
||||
|
||||
do
|
||||
process_order = ''
|
||||
evo.remove(s2, evo.GROUP)
|
||||
evo.process(s1)
|
||||
assert(process_order == '1')
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local s1, s2, s3 = evo.id(3)
|
||||
|
||||
local process_order = ''
|
||||
|
||||
evo.set(s1, evo.PROLOGUE, function()
|
||||
process_order = process_order .. '1'
|
||||
end)
|
||||
|
||||
evo.set(s2, evo.PROLOGUE, function()
|
||||
process_order = process_order .. '2'
|
||||
end)
|
||||
|
||||
evo.set(s3, evo.PROLOGUE, function()
|
||||
process_order = process_order .. '3'
|
||||
end)
|
||||
|
||||
do
|
||||
process_order = ''
|
||||
evo.set(s2, evo.GROUP, s1)
|
||||
evo.process(s1)
|
||||
assert(process_order == '12')
|
||||
end
|
||||
|
||||
do
|
||||
process_order = ''
|
||||
evo.set(s2, evo.GROUP, s3)
|
||||
evo.process(s1)
|
||||
assert(process_order == '1')
|
||||
evo.process(s3)
|
||||
assert(process_order == '132')
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
evo.set(f1, evo.NAME, 'f1')
|
||||
evo.set(f2, evo.NAME, 'f2')
|
||||
|
||||
do
|
||||
local c1 = evo.chunk(f1)
|
||||
assert(tostring(c1) == '<f1>')
|
||||
|
||||
local c2 = evo.chunk(f2)
|
||||
assert(tostring(c2) == '<f2>')
|
||||
|
||||
local c12 = evo.chunk(f1, f2)
|
||||
assert(tostring(c12) == '<f1, f2>')
|
||||
|
||||
local c21 = evo.chunk(f2, f1)
|
||||
assert(tostring(c21) == '<f1, f2>')
|
||||
end
|
||||
|
||||
do
|
||||
local b = evo.builder():set(f1)
|
||||
assert(tostring(b) == '<f1>')
|
||||
|
||||
b:set(f1, 1):set(f2, 2)
|
||||
assert(tostring(b) == '<f1, f2>')
|
||||
end
|
||||
end
|
||||
242
develop/testing/mappers_tests.lua
Normal file
242
develop/testing/mappers_tests.lua
Normal file
@@ -0,0 +1,242 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
|
||||
local e1 = evo.spawn({ [f1] = 1, [f2] = 2 }, function(c, p)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
f1s[p] = f1s[p] * 2
|
||||
f2s[p] = f2s[p] * 3
|
||||
end)
|
||||
|
||||
local e2 = evo.spawn({ [f1] = 1, [f2] = 2 }, function(c, p)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
f1s[p] = f1s[p] + 10
|
||||
f2s[p] = f2s[p] + 20
|
||||
end)
|
||||
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 2)
|
||||
assert(evo.has(e1, f2) and evo.get(e1, f2) == 6)
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 11)
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == 22)
|
||||
|
||||
local e11 = evo.clone(e1, nil, function(c, p)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
f1s[p] = f1s[p] * 3
|
||||
f2s[p] = f2s[p] * 4
|
||||
end)
|
||||
|
||||
local e22 = evo.clone(e2, nil, function(c, p)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
f1s[p] = f1s[p] + 30
|
||||
f2s[p] = f2s[p] + 40
|
||||
end)
|
||||
|
||||
assert(evo.has(e11, f1) and evo.get(e11, f1) == 6)
|
||||
assert(evo.has(e11, f2) and evo.get(e11, f2) == 24)
|
||||
assert(evo.has(e22, f1) and evo.get(e22, f1) == 41)
|
||||
assert(evo.has(e22, f2) and evo.get(e22, f2) == 62)
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
|
||||
evo.defer()
|
||||
|
||||
local e1 = evo.spawn({ [f1] = 1, [f2] = 2 }, function(c, p)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
f1s[p] = f1s[p] * 2
|
||||
f2s[p] = f2s[p] * 3
|
||||
end)
|
||||
|
||||
local e2 = evo.spawn({ [f1] = 1, [f2] = 2 }, function(c, p)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
f1s[p] = f1s[p] + 10
|
||||
f2s[p] = f2s[p] + 20
|
||||
end)
|
||||
|
||||
assert(not evo.has(e1, f1) and evo.get(e1, f1) == nil)
|
||||
assert(not evo.has(e1, f2) and evo.get(e1, f2) == nil)
|
||||
assert(not evo.has(e2, f1) and evo.get(e2, f1) == nil)
|
||||
assert(not evo.has(e2, f2) and evo.get(e2, f2) == nil)
|
||||
|
||||
evo.commit()
|
||||
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 2)
|
||||
assert(evo.has(e1, f2) and evo.get(e1, f2) == 6)
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 11)
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == 22)
|
||||
|
||||
evo.defer()
|
||||
|
||||
local e11 = evo.clone(e1, nil, function(c, p)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
f1s[p] = f1s[p] * 3
|
||||
f2s[p] = f2s[p] * 4
|
||||
end)
|
||||
|
||||
local e22 = evo.clone(e2, nil, function(c, p)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
f1s[p] = f1s[p] + 30
|
||||
f2s[p] = f2s[p] + 40
|
||||
end)
|
||||
|
||||
assert(not evo.has(e11, f1) and evo.get(e11, f1) == nil)
|
||||
assert(not evo.has(e11, f2) and evo.get(e11, f2) == nil)
|
||||
assert(not evo.has(e22, f1) and evo.get(e22, f1) == nil)
|
||||
assert(not evo.has(e22, f2) and evo.get(e22, f2) == nil)
|
||||
|
||||
evo.commit()
|
||||
|
||||
assert(evo.has(e11, f1) and evo.get(e11, f1) == 6)
|
||||
assert(evo.has(e11, f2) and evo.get(e11, f2) == 24)
|
||||
assert(evo.has(e22, f1) and evo.get(e22, f1) == 41)
|
||||
assert(evo.has(e22, f2) and evo.get(e22, f2) == 62)
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
|
||||
local es, ec = evo.multi_spawn(10, { [f1] = 1, [f2] = 2 }, function(c, b, e)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
for p = b, e do
|
||||
f1s[p] = f1s[p] * 2
|
||||
f2s[p] = f2s[p] * 3
|
||||
end
|
||||
end)
|
||||
|
||||
for i = 1, ec do
|
||||
local e = es[i]
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 2)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 6)
|
||||
end
|
||||
|
||||
local es2, ec2 = evo.multi_clone(10, es[1], nil, function(c, b, e)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
for p = b, e do
|
||||
f1s[p] = f1s[p] + 10
|
||||
f2s[p] = f2s[p] + 20
|
||||
end
|
||||
end)
|
||||
|
||||
for i = 1, ec2 do
|
||||
local e = es2[i]
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 12)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 26)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
|
||||
evo.defer()
|
||||
|
||||
local es, ec = evo.multi_spawn(10, { [f1] = 1, [f2] = 2 }, function(c, b, e)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
for p = b, e do
|
||||
f1s[p] = f1s[p] * 2
|
||||
f2s[p] = f2s[p] * 3
|
||||
end
|
||||
end)
|
||||
|
||||
for i = 1, ec do
|
||||
local e = es[i]
|
||||
assert(not evo.has(e, f1) and evo.get(e, f1) == nil)
|
||||
assert(not evo.has(e, f2) and evo.get(e, f2) == nil)
|
||||
end
|
||||
|
||||
evo.commit()
|
||||
|
||||
for i = 1, ec do
|
||||
local e = es[i]
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 2)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 6)
|
||||
end
|
||||
|
||||
evo.defer()
|
||||
|
||||
local es2, ec2 = evo.multi_clone(10, es[1], nil, function(c, b, e)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
for p = b, e do
|
||||
f1s[p] = f1s[p] + 10
|
||||
f2s[p] = f2s[p] + 20
|
||||
end
|
||||
end)
|
||||
|
||||
for i = 1, ec2 do
|
||||
local e = es2[i]
|
||||
assert(not evo.has(e, f1) and evo.get(e, f1) == nil)
|
||||
assert(not evo.has(e, f2) and evo.get(e, f2) == nil)
|
||||
end
|
||||
|
||||
evo.commit()
|
||||
|
||||
for i = 1, ec2 do
|
||||
local e = es2[i]
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 12)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 26)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
|
||||
local e1 = evo.builder():set(f1, 1):set(f2, 2):build(nil, function(c, p)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
f1s[p] = f1s[p] * 2
|
||||
f2s[p] = f2s[p] * 3
|
||||
end)
|
||||
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 2)
|
||||
assert(evo.has(e1, f2) and evo.get(e1, f2) == 6)
|
||||
|
||||
local e2 = evo.builder():build(e1, function(c, p)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
f1s[p] = f1s[p] + 10
|
||||
f2s[p] = f2s[p] + 20
|
||||
end)
|
||||
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 12)
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == 26)
|
||||
|
||||
local e3 = evo.builder():set(f2, 3):build(e1, function(c, p)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
f1s[p] = f1s[p] + 10
|
||||
f2s[p] = f2s[p] + 20
|
||||
end)
|
||||
|
||||
assert(evo.has(e3, f1) and evo.get(e3, f1) == 12)
|
||||
assert(evo.has(e3, f2) and evo.get(e3, f2) == 23)
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
|
||||
local es, ec = evo.builder():set(f1, 1):set(f2, 2):multi_build(10, nil, function(c, b, e)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
for p = b, e do
|
||||
f1s[p] = f1s[p] * 2
|
||||
f2s[p] = f2s[p] * 3
|
||||
end
|
||||
end)
|
||||
|
||||
for i = 1, ec do
|
||||
local e = es[i]
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 2)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 6)
|
||||
end
|
||||
|
||||
local es2, ec2 = evo.builder():multi_build(10, es[1], function(c, b, e)
|
||||
local f1s, f2s = c:components(f1, f2)
|
||||
for p = b, e do
|
||||
f1s[p] = f1s[p] + 10
|
||||
f2s[p] = f2s[p] + 20
|
||||
end
|
||||
end)
|
||||
|
||||
for i = 1, ec2 do
|
||||
local e = es2[i]
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 12)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 26)
|
||||
end
|
||||
end
|
||||
@@ -306,3 +306,302 @@ do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3 = evo.id(3)
|
||||
|
||||
evo.set(f1, evo.REQUIRES, { f2, f3 })
|
||||
evo.set(f3, evo.TAG)
|
||||
|
||||
do
|
||||
local entity_list, entity_count = evo.multi_spawn(2, { [f1] = 42 })
|
||||
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_count == 2)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local e = entity_list[i]
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == true)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) == nil)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local entity_prefab = evo.builder():set(f1, 42):spawn()
|
||||
|
||||
local clone_list, clone_count = evo.multi_clone(2, entity_prefab)
|
||||
|
||||
assert(clone_list and #clone_list == 2)
|
||||
assert(clone_count == 2)
|
||||
|
||||
for i = 1, clone_count do
|
||||
local e = clone_list[i]
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == true)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) == nil)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local entity_prefab = evo.builder():set(f1, 42):spawn()
|
||||
evo.remove(entity_prefab, f2, f3)
|
||||
|
||||
local clone_list, clone_count = evo.multi_clone(2, entity_prefab, { [f1] = 21 })
|
||||
|
||||
assert(clone_list and #clone_list == 2)
|
||||
assert(clone_count == 2)
|
||||
|
||||
for i = 1, clone_count do
|
||||
local e = clone_list[i]
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 21)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == true)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) == nil)
|
||||
end
|
||||
end
|
||||
|
||||
evo.set(f2, evo.DEFAULT, false)
|
||||
|
||||
do
|
||||
local entity_list, entity_count = evo.multi_spawn(2, { [f1] = 42 })
|
||||
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_count == 2)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local e = entity_list[i]
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == false)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) == nil)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local entity_prefab = evo.builder():set(f1, 42):spawn()
|
||||
|
||||
local clone_list, clone_count = evo.multi_clone(2, entity_prefab)
|
||||
|
||||
assert(clone_list and #clone_list == 2)
|
||||
assert(clone_count == 2)
|
||||
|
||||
for i = 1, clone_count do
|
||||
local e = clone_list[i]
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == false)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) == nil)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local entity_prefab = evo.builder():set(f1, 42):spawn()
|
||||
evo.remove(entity_prefab, f2, f3)
|
||||
|
||||
local clone_list, clone_count = evo.multi_clone(2, entity_prefab, { [f1] = 21 })
|
||||
|
||||
assert(clone_list and #clone_list == 2)
|
||||
assert(clone_count == 2)
|
||||
|
||||
for i = 1, clone_count do
|
||||
local e = clone_list[i]
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 21)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == false)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) == nil)
|
||||
end
|
||||
end
|
||||
|
||||
local v_set_sum = 0
|
||||
local v_insert_sum = 0
|
||||
|
||||
local f3_set_times = 0
|
||||
local f3_insert_times = 0
|
||||
|
||||
evo.set(f1, evo.ON_SET, function(e, f, v)
|
||||
assert(f == f1)
|
||||
v_set_sum = v_set_sum + v
|
||||
assert(evo.get(e, f) == v)
|
||||
end)
|
||||
|
||||
evo.set(f1, evo.ON_INSERT, function(e, f, v)
|
||||
assert(f == f1)
|
||||
v_insert_sum = v_insert_sum + v
|
||||
assert(evo.get(e, f) == v)
|
||||
end)
|
||||
|
||||
evo.set(f3, evo.ON_SET, function(e, f, v)
|
||||
assert(f == f3)
|
||||
f3_set_times = f3_set_times + 1
|
||||
assert(v == nil)
|
||||
assert(evo.has(e, f))
|
||||
end)
|
||||
|
||||
evo.set(f3, evo.ON_INSERT, function(e, f, v)
|
||||
assert(f == f3)
|
||||
f3_insert_times = f3_insert_times + 1
|
||||
assert(v == nil)
|
||||
assert(evo.has(e, f))
|
||||
end)
|
||||
|
||||
do
|
||||
local entity_list, entity_count = evo.multi_spawn(2, { [f1] = 42 })
|
||||
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_count == 2)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local e = entity_list[i]
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == false)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local entity_prefab = evo.builder():set(f1, 42):spawn()
|
||||
|
||||
local clone_list, clone_count = evo.multi_clone(2, entity_prefab)
|
||||
|
||||
assert(clone_list and #clone_list == 2)
|
||||
assert(clone_count == 2)
|
||||
|
||||
for i = 1, clone_count do
|
||||
local e = clone_list[i]
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == false)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local entity_prefab = evo.builder():set(f1, 42):spawn()
|
||||
evo.remove(entity_prefab, f2, f3)
|
||||
|
||||
local clone_list, clone_count = evo.multi_clone(2, entity_prefab, { [f1] = 21 })
|
||||
|
||||
assert(clone_list and #clone_list == 2)
|
||||
assert(clone_count == 2)
|
||||
|
||||
for i = 1, clone_count do
|
||||
local e = clone_list[i]
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 21)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == false)
|
||||
end
|
||||
end
|
||||
|
||||
assert(v_set_sum == 42 * 6 + 21 * 2)
|
||||
assert(v_insert_sum == 42 * 6 + 21 * 2)
|
||||
|
||||
assert(f3_set_times == 8)
|
||||
assert(f3_insert_times == 8)
|
||||
end
|
||||
|
||||
do
|
||||
local function v2(x, y) return { x = x or 0, y = y or 0 } end
|
||||
local function v2_clone(v) return { x = v.x, y = v.y } end
|
||||
|
||||
local f1, f2, f3, f4 = evo.id(4)
|
||||
evo.set(f1, evo.REQUIRES, { f2, f3, f4 })
|
||||
|
||||
local f1_default = v2(1, 2)
|
||||
local f2_default = v2(3, 4)
|
||||
local f3_default = v2(10, 11)
|
||||
local f4_default = v2(12, 13)
|
||||
|
||||
evo.set(f1, evo.DEFAULT, f1_default)
|
||||
evo.set(f2, evo.DEFAULT, f2_default)
|
||||
evo.set(f3, evo.DEFAULT, f3_default)
|
||||
evo.set(f4, evo.DEFAULT, f4_default)
|
||||
|
||||
evo.set(f1, evo.DUPLICATE, v2_clone)
|
||||
evo.set(f2, evo.DUPLICATE, v2_clone)
|
||||
evo.set(f3, evo.DUPLICATE, v2_clone)
|
||||
|
||||
do
|
||||
local entity_list, entity_count = evo.multi_spawn(2, { [f1] = v2(5, 6), [f2] = v2(7, 8) })
|
||||
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_count == 2)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local e = entity_list[i]
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) ~= f1_default)
|
||||
assert(evo.get(e, f1).x == 5 and evo.get(e, f1).y == 6)
|
||||
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) ~= f2_default)
|
||||
assert(evo.get(e, f2).x == 7 and evo.get(e, f2).y == 8)
|
||||
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) ~= f3_default)
|
||||
assert(evo.get(e, f3).x == 10 and evo.get(e, f3).y == 11)
|
||||
|
||||
assert(evo.has(e, f4) and evo.get(e, f4) == f4_default)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local entity_prefab = evo.builder():set(f1, v2(5, 6)):set(f2, v2(7, 8)):spawn()
|
||||
|
||||
local clone_list, clone_count = evo.multi_clone(2, entity_prefab, { [f2] = f2_default })
|
||||
|
||||
assert(clone_list and #clone_list == 2)
|
||||
assert(clone_count == 2)
|
||||
|
||||
for i = 1, clone_count do
|
||||
local e = clone_list[i]
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) ~= f1_default and evo.get(e, f1) ~= evo.get(entity_prefab, f1))
|
||||
assert(evo.get(e, f1).x == 5 and evo.get(e, f1).y == 6)
|
||||
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) ~= f2_default and evo.get(e, f2) ~= evo.get(entity_prefab, f2))
|
||||
assert(evo.get(e, f2).x == 3 and evo.get(e, f2).y == 4)
|
||||
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) ~= f3_default)
|
||||
assert(evo.get(e, f3).x == 10 and evo.get(e, f3).y == 11)
|
||||
|
||||
assert(evo.has(e, f4) and evo.get(e, f4) == f4_default)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local entity_prefab = evo.builder():set(f1, v2(5, 6)):set(f2, v2(7, 8)):spawn()
|
||||
evo.remove(entity_prefab, f2, f3, f4)
|
||||
|
||||
local clone_list, clone_count = evo.multi_clone(2, entity_prefab, { [f2] = f2_default })
|
||||
|
||||
assert(clone_list and #clone_list == 2)
|
||||
assert(clone_count == 2)
|
||||
|
||||
for i = 1, clone_count do
|
||||
local e = clone_list[i]
|
||||
assert(e and not evo.empty(e))
|
||||
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) ~= f1_default and evo.get(e, f1) ~= evo.get(entity_prefab, f1))
|
||||
assert(evo.get(e, f1).x == 5 and evo.get(e, f1).y == 6)
|
||||
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) ~= f2_default and evo.get(e, f2) ~= evo.get(entity_prefab, f2))
|
||||
assert(evo.get(e, f2).x == 3 and evo.get(e, f2).y == 4)
|
||||
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) ~= f3_default)
|
||||
assert(evo.get(e, f3).x == 10 and evo.get(e, f3).y == 11)
|
||||
|
||||
assert(evo.has(e, f4) and evo.get(e, f4) == f4_default)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
107
develop/testing/process_with_tests.lua
Normal file
107
develop/testing/process_with_tests.lua
Normal 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
|
||||
588
develop/testing/realloc_tests.lua
Normal file
588
develop/testing/realloc_tests.lua
Normal file
@@ -0,0 +1,588 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
---@type ffilib?
|
||||
local ffi = (function()
|
||||
local ffi_loader = package and package.preload and package.preload['ffi']
|
||||
local ffi = ffi_loader and ffi_loader()
|
||||
return ffi
|
||||
end)()
|
||||
|
||||
if not ffi then
|
||||
return
|
||||
end
|
||||
|
||||
local FLOAT_TYPEOF = ffi.typeof('float')
|
||||
local FLOAT_SIZEOF = ffi.sizeof(FLOAT_TYPEOF)
|
||||
local FLOAT_STORAGE_TYPEOF = ffi.typeof('$[?]', FLOAT_TYPEOF)
|
||||
|
||||
local DOUBLE_TYPEOF = ffi.typeof('double')
|
||||
local DOUBLE_SIZEOF = ffi.sizeof(DOUBLE_TYPEOF)
|
||||
local DOUBLE_STORAGE_TYPEOF = ffi.typeof('$[?]', DOUBLE_TYPEOF)
|
||||
|
||||
local STORAGE_SIZES = {}
|
||||
|
||||
---@type evolved.realloc
|
||||
local function float_realloc(src, src_size, dst_size)
|
||||
if dst_size == 0 then
|
||||
assert(src and src_size > 0)
|
||||
local expected_src_size = STORAGE_SIZES[src]
|
||||
assert(expected_src_size == src_size)
|
||||
STORAGE_SIZES[src] = nil
|
||||
return
|
||||
else
|
||||
if src then
|
||||
assert(src_size > 0)
|
||||
local expected_src_size = STORAGE_SIZES[src]
|
||||
assert(expected_src_size == src_size)
|
||||
else
|
||||
assert(src_size == 0)
|
||||
end
|
||||
|
||||
local dst = ffi.new(FLOAT_STORAGE_TYPEOF, dst_size + 1)
|
||||
STORAGE_SIZES[dst] = dst_size
|
||||
|
||||
if src then
|
||||
ffi.copy(dst + 1, src + 1, math.min(src_size, dst_size) * FLOAT_SIZEOF)
|
||||
end
|
||||
|
||||
return dst
|
||||
end
|
||||
end
|
||||
|
||||
---@type evolved.realloc
|
||||
local function double_realloc(src, src_size, dst_size)
|
||||
if dst_size == 0 then
|
||||
assert(src and src_size > 0)
|
||||
local expected_src_size = STORAGE_SIZES[src]
|
||||
assert(expected_src_size == src_size)
|
||||
STORAGE_SIZES[src] = nil
|
||||
return
|
||||
else
|
||||
if src then
|
||||
assert(src_size > 0)
|
||||
local expected_src_size = STORAGE_SIZES[src]
|
||||
assert(expected_src_size == src_size)
|
||||
else
|
||||
assert(src_size == 0)
|
||||
end
|
||||
|
||||
local dst = ffi.new(DOUBLE_STORAGE_TYPEOF, dst_size + 1)
|
||||
STORAGE_SIZES[dst] = dst_size
|
||||
|
||||
if src then
|
||||
ffi.copy(dst + 1, src + 1, math.min(src_size, dst_size) * DOUBLE_SIZEOF)
|
||||
end
|
||||
|
||||
return dst
|
||||
end
|
||||
end
|
||||
|
||||
---@type evolved.compmove
|
||||
local function double_compmove(src, f, e, t, dst)
|
||||
ffi.copy(dst + t, src + f, (e - f + 1) * DOUBLE_SIZEOF)
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():realloc(double_realloc):build()
|
||||
|
||||
local e1 = evo.builder():set(f1, 21):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 21)
|
||||
|
||||
local e2 = evo.builder():set(f1, 42):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 21)
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 42)
|
||||
|
||||
local e3 = evo.builder():set(f1, 84):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 21)
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 42)
|
||||
assert(evo.has(e3, f1) and evo.get(e3, f1) == 84)
|
||||
|
||||
evo.destroy(e1)
|
||||
assert(not evo.has(e1, f1))
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 42)
|
||||
assert(evo.has(e3, f1) and evo.get(e3, f1) == 84)
|
||||
|
||||
evo.destroy(e3)
|
||||
assert(not evo.has(e1, f1))
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 42)
|
||||
assert(not evo.has(e3, f1))
|
||||
|
||||
evo.destroy(e2)
|
||||
assert(not evo.has(e1, f1))
|
||||
assert(not evo.has(e2, f1))
|
||||
assert(not evo.has(e3, f1))
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():realloc(double_realloc):build()
|
||||
local q1 = evo.builder():include(f1):build()
|
||||
|
||||
do
|
||||
local es, ec = {}, 10
|
||||
for i = 1, ec do es[i] = evo.spawn({ [f1] = i }) end
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == i) end
|
||||
end
|
||||
|
||||
do
|
||||
local p = evo.builder():set(f1, 42):build()
|
||||
local es, ec = {}, 10
|
||||
for i = 1, ec do es[i] = evo.clone(p) end
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42) end
|
||||
end
|
||||
|
||||
do
|
||||
local es1, ec1 = evo.multi_spawn(10, { [f1] = 42 })
|
||||
for i = 1, ec1 do assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 42) end
|
||||
|
||||
local es2, ec2 = evo.multi_spawn(20, { [f1] = 84 })
|
||||
for i = 1, ec1 do assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 42) end
|
||||
for i = 1, ec2 do assert(evo.has(es2[i], f1) and evo.get(es2[i], f1) == 84) end
|
||||
end
|
||||
|
||||
do
|
||||
local p = evo.builder():set(f1, 21):build()
|
||||
|
||||
local es1, ec1 = evo.multi_clone(10, p)
|
||||
for i = 1, ec1 do assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 21) end
|
||||
|
||||
local es2, ec2 = evo.multi_clone(20, p)
|
||||
for i = 1, ec1 do assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 21) end
|
||||
for i = 1, ec2 do assert(evo.has(es2[i], f1) and evo.get(es2[i], f1) == 21) end
|
||||
end
|
||||
|
||||
evo.batch_destroy(q1)
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():realloc(double_realloc):build()
|
||||
local f2 = evo.builder():realloc(double_realloc):build()
|
||||
|
||||
local q1 = evo.builder():include(f1):build()
|
||||
local q2 = evo.builder():include(f2):build()
|
||||
|
||||
do
|
||||
local e = evo.builder():set(f1, 21):set(f2, 42):build()
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 21)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 42)
|
||||
|
||||
evo.remove(e, f1)
|
||||
|
||||
assert(not evo.has(e, f1))
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 42)
|
||||
end
|
||||
|
||||
do
|
||||
local e = evo.builder():set(f1, 21):set(f2, 42):build()
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 21)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 42)
|
||||
|
||||
evo.clear(e)
|
||||
|
||||
assert(not evo.has(e, f1))
|
||||
assert(not evo.has(e, f2))
|
||||
end
|
||||
|
||||
do
|
||||
local es, ec = evo.multi_spawn(10, { [f1] = 21, [f2] = 42 })
|
||||
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 21)
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 42)
|
||||
end
|
||||
|
||||
evo.batch_remove(q1, f1)
|
||||
|
||||
local e12 = evo.builder():set(f1, 1):set(f2, 2):build()
|
||||
assert(evo.has(e12, f1) and evo.get(e12, f1) == 1)
|
||||
assert(evo.has(e12, f2) and evo.get(e12, f2) == 2)
|
||||
|
||||
for i = 1, ec do
|
||||
assert(not evo.has(es[i], f1))
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 42)
|
||||
end
|
||||
|
||||
evo.batch_set(q2, f1, 84)
|
||||
|
||||
assert(evo.has(e12, f1) and evo.get(e12, f1) == 84)
|
||||
assert(evo.has(e12, f2) and evo.get(e12, f2) == 2)
|
||||
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 84)
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 42)
|
||||
end
|
||||
|
||||
evo.batch_set(q2, f1, 21)
|
||||
|
||||
assert(evo.has(e12, f1) and evo.get(e12, f1) == 21)
|
||||
assert(evo.has(e12, f2) and evo.get(e12, f2) == 2)
|
||||
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 21)
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 42)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():realloc(double_realloc):compmove(double_compmove):build()
|
||||
local f2 = evo.builder():realloc(double_realloc):compmove(double_compmove):build()
|
||||
|
||||
local q1 = evo.builder():include(f1):build()
|
||||
local q2 = evo.builder():include(f2):build()
|
||||
|
||||
do
|
||||
local es1, ec1 = evo.multi_spawn(10, { [f1] = 1, [f2] = 2 })
|
||||
|
||||
for i = 1, ec1 do
|
||||
assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 1)
|
||||
assert(evo.has(es1[i], f2) and evo.get(es1[i], f2) == 2)
|
||||
end
|
||||
|
||||
local es2, ec2 = evo.multi_spawn(20, { [f1] = 3, [f2] = 4 })
|
||||
|
||||
for i = 1, ec1 do
|
||||
assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 1)
|
||||
assert(evo.has(es1[i], f2) and evo.get(es1[i], f2) == 2)
|
||||
end
|
||||
|
||||
for i = 1, ec2 do
|
||||
assert(evo.has(es2[i], f1) and evo.get(es2[i], f1) == 3)
|
||||
assert(evo.has(es2[i], f2) and evo.get(es2[i], f2) == 4)
|
||||
end
|
||||
|
||||
local e2 = evo.builder():set(f2, 42):build()
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == 42)
|
||||
|
||||
evo.batch_remove(q1, f1)
|
||||
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == 42)
|
||||
|
||||
for i = 1, ec1 do
|
||||
assert(not evo.has(es1[i], f1))
|
||||
assert(evo.has(es1[i], f2) and evo.get(es1[i], f2) == 2)
|
||||
end
|
||||
|
||||
for i = 1, ec2 do
|
||||
assert(not evo.has(es2[i], f1))
|
||||
assert(evo.has(es2[i], f2) and evo.get(es2[i], f2) == 4)
|
||||
end
|
||||
|
||||
local e12 = evo.builder():set(f1, 21):set(f2, 42):build()
|
||||
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == 42)
|
||||
assert(evo.has(e12, f1) and evo.get(e12, f1) == 21)
|
||||
assert(evo.has(e12, f2) and evo.get(e12, f2) == 42)
|
||||
|
||||
evo.batch_set(q2, f1, 84)
|
||||
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == 42)
|
||||
assert(evo.has(e12, f1) and evo.get(e12, f1) == 84)
|
||||
assert(evo.has(e12, f2) and evo.get(e12, f2) == 42)
|
||||
|
||||
for i = 1, ec1 do
|
||||
assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 84)
|
||||
assert(evo.has(es1[i], f2) and evo.get(es1[i], f2) == 2)
|
||||
end
|
||||
|
||||
for i = 1, ec2 do
|
||||
assert(evo.has(es2[i], f1) and evo.get(es2[i], f1) == 84)
|
||||
assert(evo.has(es2[i], f2) and evo.get(es2[i], f2) == 4)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():default(42):build()
|
||||
|
||||
local es, ec = evo.multi_spawn(10, { [f1] = 21 })
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 21) end
|
||||
|
||||
evo.set(f1, evo.TAG)
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == nil) end
|
||||
|
||||
evo.remove(f1, evo.TAG)
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42) end
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():realloc(float_realloc):build()
|
||||
|
||||
local e1 = evo.builder():set(f1, 3):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 3)
|
||||
|
||||
evo.set(f1, evo.REALLOC, double_realloc)
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 3)
|
||||
|
||||
evo.remove(f1, evo.REALLOC)
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 3)
|
||||
|
||||
evo.set(f1, evo.REALLOC, double_realloc)
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 3)
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():realloc(double_realloc):build()
|
||||
|
||||
local es, ec = evo.multi_spawn(20, { [f1] = 42 })
|
||||
|
||||
for i = 1, ec / 2 do
|
||||
evo.destroy(es[ec - i + 1])
|
||||
end
|
||||
|
||||
evo.collect_garbage()
|
||||
|
||||
for i = 1, ec / 2 do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
evo.collect_garbage()
|
||||
|
||||
local f1 = evo.builder():name('f1'):realloc(double_realloc):compmove(double_compmove):build()
|
||||
local f2 = evo.builder():name('f2'):realloc(double_realloc):compmove(double_compmove):build()
|
||||
|
||||
local q1 = evo.builder():include(f1):build()
|
||||
local q2 = evo.builder():include(f2):build()
|
||||
|
||||
do
|
||||
local es, ec = evo.multi_spawn(40, { [f2] = 2 })
|
||||
for i = 1, ec do
|
||||
assert(not evo.has(es[i], f1))
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2)
|
||||
end
|
||||
evo.batch_destroy(q2)
|
||||
end
|
||||
|
||||
do
|
||||
local es, ec = evo.multi_spawn(50, { [f1] = 1, [f2] = 2 })
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 1)
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2)
|
||||
end
|
||||
|
||||
evo.batch_remove(q1, f1)
|
||||
for i = 1, ec do
|
||||
assert(not evo.has(es[i], f1))
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2)
|
||||
end
|
||||
|
||||
evo.batch_destroy(q1, q2)
|
||||
end
|
||||
|
||||
do
|
||||
evo.spawn({ [f1] = 1 })
|
||||
evo.spawn({ [f2] = 2 })
|
||||
evo.spawn({ [f1] = 1, [f2] = 2 })
|
||||
end
|
||||
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
do
|
||||
evo.collect_garbage()
|
||||
|
||||
local f1 = evo.builder():name('f1'):realloc(double_realloc):compmove(double_compmove):build()
|
||||
local f2 = evo.builder():name('f2'):realloc(double_realloc):compmove(double_compmove):build()
|
||||
|
||||
local q1 = evo.builder():include(f1):build()
|
||||
local q2 = evo.builder():include(f2):build()
|
||||
|
||||
do
|
||||
local es, ec = evo.multi_spawn(40, { [f1] = 1, [f2] = 2 })
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 1)
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2)
|
||||
end
|
||||
evo.batch_destroy(q2)
|
||||
end
|
||||
|
||||
do
|
||||
local es, ec = evo.multi_spawn(50, { [f1] = 1 })
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 1)
|
||||
assert(not evo.has(es[i], f2))
|
||||
end
|
||||
|
||||
evo.batch_set(q1, f2, 2)
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 1)
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2)
|
||||
end
|
||||
|
||||
evo.batch_destroy(q1, q2)
|
||||
end
|
||||
|
||||
do
|
||||
evo.spawn({ [f1] = 1 })
|
||||
evo.spawn({ [f2] = 2 })
|
||||
evo.spawn({ [f1] = 1, [f2] = 2 })
|
||||
end
|
||||
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
do
|
||||
evo.collect_garbage()
|
||||
|
||||
local alloc_call_count = 0
|
||||
local free_call_count = 0
|
||||
local resize_call_count = 0
|
||||
|
||||
local function ctor_realloc()
|
||||
---@type evolved.realloc
|
||||
return function(src, src_size, dst_size)
|
||||
if dst_size == 0 then
|
||||
assert(src and src_size > 0)
|
||||
free_call_count = free_call_count + 1
|
||||
return
|
||||
else
|
||||
if src then
|
||||
assert(src_size > 0)
|
||||
resize_call_count = resize_call_count + 1
|
||||
else
|
||||
assert(src_size == 0)
|
||||
alloc_call_count = alloc_call_count + 1
|
||||
end
|
||||
|
||||
local dst = {}
|
||||
|
||||
if src then
|
||||
for i = 1, math.min(src_size, dst_size) do
|
||||
dst[i] = src[i]
|
||||
end
|
||||
end
|
||||
|
||||
return dst
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local realloc1 = ctor_realloc()
|
||||
local realloc2 = ctor_realloc()
|
||||
|
||||
local f1 = evo.builder():default(44):realloc(realloc1):build()
|
||||
|
||||
alloc_call_count, free_call_count, resize_call_count = 0, 0, 0
|
||||
|
||||
do
|
||||
local e1 = evo.builder():set(f1, 21):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 21)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0)
|
||||
|
||||
local e2 = evo.builder():set(f1, 42):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 21)
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 42)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0)
|
||||
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.destroy(e1)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.destroy(e2)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
end
|
||||
|
||||
alloc_call_count, free_call_count, resize_call_count = 0, 0, 0
|
||||
|
||||
do
|
||||
local es, ec = evo.multi_spawn(10, { [f1] = 84 })
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
for i = 1, ec / 2 do evo.destroy(es[i]) end
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 1)
|
||||
|
||||
evo.set(f1, evo.REALLOC, realloc2)
|
||||
assert(alloc_call_count == 2 and free_call_count == 1 and resize_call_count == 1)
|
||||
|
||||
for i = 1, ec do evo.destroy(es[i]) end
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 2 and free_call_count == 2 and resize_call_count == 1)
|
||||
end
|
||||
|
||||
alloc_call_count, free_call_count, resize_call_count = 0, 0, 0
|
||||
|
||||
do
|
||||
local e1 = evo.builder():set(f1, 24):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 24)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.set(f1, evo.TAG)
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == nil)
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
local es, ec = evo.multi_spawn(20, { [f1] = 48 })
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == nil) end
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
evo.remove(f1, evo.TAG)
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 44)
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 44) end
|
||||
assert(alloc_call_count == 2 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
evo.destroy(e1)
|
||||
for i = 1, ec do evo.destroy(es[i]) end
|
||||
assert(alloc_call_count == 2 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 2 and free_call_count == 2 and resize_call_count == 0)
|
||||
end
|
||||
|
||||
alloc_call_count, free_call_count, resize_call_count = 0, 0, 0
|
||||
|
||||
do
|
||||
local e1 = evo.builder():set(f1, 100):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 100)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.set(f1, evo.TAG)
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == nil)
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
local es, ec = evo.multi_spawn(20, { [f1] = 48 })
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == nil) end
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
evo.destroy(e1)
|
||||
for i = 1, ec do evo.destroy(es[i]) end
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
local realloc = ctor_realloc()
|
||||
|
||||
local f1 = evo.builder():realloc(realloc):build()
|
||||
|
||||
alloc_call_count, free_call_count, resize_call_count = 0, 0, 0
|
||||
|
||||
do
|
||||
local e1 = evo.builder():set(f1, 42):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 42)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.destroy(e1)
|
||||
assert(not evo.has(e1, f1) and evo.get(e1, f1) == nil)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.set(f1, evo.TAG)
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -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
|
||||
|
||||
329
develop/testing/spawn_tests.lua
Normal file
329
develop/testing/spawn_tests.lua
Normal 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
|
||||
221
evolved.d.tl
Normal file
221
evolved.d.tl
Normal file
@@ -0,0 +1,221 @@
|
||||
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,
|
||||
component_mapper?: function(Chunk, integer)): Entity
|
||||
|
||||
multi_build: function(self: Builder,
|
||||
entity_count: integer,
|
||||
prefab?: Entity,
|
||||
component_mapper?: function(Chunk, integer, integer)): { Entity }, integer
|
||||
|
||||
spawn: function(self: Builder,
|
||||
component_mapper?: function(Chunk, integer)): Entity
|
||||
|
||||
multi_spawn: function(self: Builder,
|
||||
entity_count: integer,
|
||||
component_mapper?: function(Chunk, integer, integer)): { Entity }, integer
|
||||
|
||||
clone: function(self: Builder,
|
||||
prefab: Entity,
|
||||
component_mapper?: function(Chunk, integer)): Entity
|
||||
|
||||
multi_clone: function(self: Builder,
|
||||
entity_count: integer,
|
||||
prefab: Entity,
|
||||
component_mapper?: function(Chunk, integer, integer)): { 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
|
||||
|
||||
realloc: function<Component>(self: Builder, realloc: function({ Component } | nil, integer, integer): { Component } | nil): Builder
|
||||
compmove: function<Component>(self: Builder, compmove: function({ Component }, integer, integer, integer, { Component })): Builder
|
||||
|
||||
prefab: function(self: Builder): Builder
|
||||
disabled: function(self: Builder): Builder
|
||||
|
||||
include: function(self: Builder, ...: Fragment): Builder
|
||||
exclude: function(self: Builder, ...: Fragment): Builder
|
||||
variant: 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
|
||||
|
||||
REALLOC: Fragment
|
||||
COMPMOVE: Fragment
|
||||
|
||||
PREFAB: Fragment
|
||||
DISABLED: Fragment
|
||||
|
||||
INCLUDES: Fragment
|
||||
EXCLUDES: Fragment
|
||||
VARIANTS: 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(
|
||||
component_table?: { Fragment: any },
|
||||
component_mapper?: function(Chunk, integer)): Entity
|
||||
|
||||
multi_spawn: function(
|
||||
entity_count: integer,
|
||||
component_table?: { Fragment: any },
|
||||
component_mapper?: function(Chunk, integer, integer)): { Entity }, integer
|
||||
|
||||
clone: function(
|
||||
prefab: Entity,
|
||||
component_table?: { Fragment: any },
|
||||
component_mapper?: function(Chunk, integer)): Entity
|
||||
|
||||
multi_clone: function(
|
||||
entity_count: integer,
|
||||
prefab: Entity,
|
||||
component_table?: { Fragment: any },
|
||||
component_mapper?: function(Chunk, integer, integer)): { 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
|
||||
5172
evolved.lua
5172
evolved.lua
File diff suppressed because it is too large
Load Diff
10
example/conf.lua
Normal file
10
example/conf.lua
Normal 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
|
||||
170
example/main.lua
Normal file
170
example/main.lua
Normal file
@@ -0,0 +1,170 @@
|
||||
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()
|
||||
evolved.multi_clone(500, PREFABS.CIRCLE, nil, function(chunk, b_place, e_place)
|
||||
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 = b_place, e_place do
|
||||
local px = math.random() * screen_width
|
||||
local py = math.random() * screen_height
|
||||
|
||||
local vx = math.random(-100, 100)
|
||||
local vy = math.random(-100, 100)
|
||||
|
||||
position_xs[i], position_ys[i] = px, py
|
||||
velocity_xs[i], velocity_ys[i] = vx, vy
|
||||
end
|
||||
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, 5)
|
||||
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
|
||||
34
rockspecs/evolved.lua-1.4.0-0.rockspec
Normal file
34
rockspecs/evolved.lua-1.4.0-0.rockspec
Normal 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",
|
||||
}
|
||||
}
|
||||
34
rockspecs/evolved.lua-1.5.0-0.rockspec
Normal file
34
rockspecs/evolved.lua-1.5.0-0.rockspec
Normal 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",
|
||||
}
|
||||
}
|
||||
34
rockspecs/evolved.lua-1.6.0-0.rockspec
Normal file
34
rockspecs/evolved.lua-1.6.0-0.rockspec
Normal 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",
|
||||
}
|
||||
}
|
||||
34
rockspecs/evolved.lua-1.7.0-0.rockspec
Normal file
34
rockspecs/evolved.lua-1.7.0-0.rockspec
Normal file
@@ -0,0 +1,34 @@
|
||||
rockspec_format = "3.0"
|
||||
package = "evolved.lua"
|
||||
version = "1.7.0-0"
|
||||
source = {
|
||||
url = "git://github.com/BlackMATov/evolved.lua",
|
||||
tag = "v1.7.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",
|
||||
}
|
||||
}
|
||||
34
rockspecs/evolved.lua-1.8.0-0.rockspec
Normal file
34
rockspecs/evolved.lua-1.8.0-0.rockspec
Normal file
@@ -0,0 +1,34 @@
|
||||
rockspec_format = "3.0"
|
||||
package = "evolved.lua"
|
||||
version = "1.8.0-0"
|
||||
source = {
|
||||
url = "git://github.com/BlackMATov/evolved.lua",
|
||||
tag = "v1.8.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",
|
||||
}
|
||||
}
|
||||
34
rockspecs/evolved.lua-1.9.0-0.rockspec
Normal file
34
rockspecs/evolved.lua-1.9.0-0.rockspec
Normal file
@@ -0,0 +1,34 @@
|
||||
rockspec_format = "3.0"
|
||||
package = "evolved.lua"
|
||||
version = "1.9.0-0"
|
||||
source = {
|
||||
url = "git://github.com/BlackMATov/evolved.lua",
|
||||
tag = "v1.9.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",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user