mirror of
https://github.com/BlackMATov/evolved.lua.git
synced 2025-12-13 11:38:15 +07:00
Compare commits
106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b6ac89c8a | |||
|
|
91b3910eda | ||
|
|
7f5ac62a79 | ||
|
|
327a6bcbce | ||
|
|
5184b39f4e | ||
|
|
de7d1a6674 | ||
|
|
632232b9b1 | ||
|
|
fbc61a8895 | ||
|
|
e3ed2d89a6 | ||
|
|
bb7f469288 | ||
|
|
8417cecbbe | ||
|
|
59fb4d8ea4 | ||
|
|
001e6f2956 | ||
|
|
fb6d13ca74 | ||
|
|
8f61a14db6 | ||
|
|
0c016f1b67 | ||
|
|
26bf586140 | ||
|
|
46f1516a55 | ||
|
|
4cd8393546 | ||
|
|
22302cee75 | ||
|
|
d4a7c7b77c | ||
|
|
12beee6eec | ||
|
|
71a7d382c1 | ||
|
|
f2a8ee5b83 | ||
|
|
81bf1d91e9 | ||
|
|
6b4c6f2a9a | ||
|
|
7eb4bfd62d | ||
|
|
1b49f4fcd0 | ||
|
|
77bc6c298e | ||
|
|
008df17ee6 | ||
|
|
ba3018213e | ||
|
|
66aec17052 | ||
|
|
91edfa9da9 | ||
|
|
9b796b2a8d | ||
|
|
dcc5190466 | ||
|
|
9e74ddf9c3 | ||
|
|
26de93405e | ||
|
|
be64359177 | ||
|
|
3b411cce25 | ||
|
|
4a2088e833 | ||
|
|
e9084f818b | ||
|
|
0e6f23d30b | ||
|
|
3f7ab3cf4d | ||
|
|
bd337cefe1 | ||
|
|
2ed3be7a4a | ||
|
|
a8fda4a22a | ||
|
|
3e4b0d02c1 | ||
|
|
676aae4402 | ||
|
|
35c6592418 | ||
|
|
dbca453bbb | ||
|
|
025a9d4d8c | ||
|
|
b6e4bfe608 | ||
|
|
90e7bb25ef | ||
|
|
d6b16df401 | ||
|
|
d86c85d522 | ||
|
|
f7e4dfb30c | ||
|
|
f4671e5a64 | ||
|
|
6603399ee6 | ||
|
|
d91b087c76 | ||
|
|
041777eb23 | ||
|
|
b8e0345e02 | ||
|
|
aa3717d290 | ||
|
|
83e09183a2 | ||
|
|
837302c533 | ||
|
|
27b134e6c0 | ||
|
|
1c89e3853c | ||
|
|
5eb8902d5a | ||
|
|
b5d8ced4c8 | ||
|
|
d24ec1ac8e | ||
|
|
8d7435064d | ||
|
|
3291ad7479 | ||
|
|
71cfdff3b7 | ||
|
|
04b36f901b | ||
|
|
063acc778b | ||
|
|
78ad8bd53e | ||
|
|
14055fbadf | ||
|
|
697a041832 | ||
|
|
9a2a62ec89 | ||
|
|
4f33796b97 | ||
|
|
1e9005e468 | ||
|
|
c7402cbb05 | ||
|
|
5375c0bdea | ||
|
|
44d2572530 | ||
|
|
56a5fb8265 | ||
|
|
21aae4ae86 | ||
|
|
be22c2c85b | ||
| 6bf13890ef | |||
|
|
9a5ea20778 | ||
|
|
0112d0747a | ||
|
|
c222a49257 | ||
|
|
fbd9f9f970 | ||
|
|
d8c9481f13 | ||
|
|
47fcc9cc13 | ||
|
|
cb98a4e461 | ||
|
|
a559c73c35 | ||
|
|
ba5ee22f5d | ||
|
|
50afb722d1 | ||
|
|
8eccd461fd | ||
|
|
c323131d1e | ||
|
|
8038031b51 | ||
|
|
1399820d71 | ||
|
|
3a64bac8e2 | ||
|
|
5ae0e77f20 | ||
|
|
e78c4e8d6b | ||
| db191b805f | |||
|
|
9c6e53e610 |
5
.luacov
Normal file
5
.luacov
Normal file
@@ -0,0 +1,5 @@
|
||||
modules = {
|
||||
['evolved'] = 'evolved.lua'
|
||||
}
|
||||
reporter = 'html'
|
||||
reportfile = 'luacov.report.html'
|
||||
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@@ -4,5 +4,12 @@
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimFinalNewlines": true,
|
||||
"files.trimTrailingWhitespace": true
|
||||
},
|
||||
"markdown.extension.toc.levels": "2..6",
|
||||
"markdown.extension.toc.omittedFromToc": {
|
||||
"README.md": [
|
||||
"# Changelog",
|
||||
"# API Reference"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
22
GUIDES.md
Normal file
22
GUIDES.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Guidelines
|
||||
|
||||
## Checklists
|
||||
|
||||
### New Version Releasing
|
||||
|
||||
1. Ensure all tests pass on CI.
|
||||
2. Update the version number in `evolved.lua`.
|
||||
3. Update the **Changelog** section in `README.md`.
|
||||
4. Create a new rockspec file in `rockspecs`.
|
||||
5. Commit the changes with a message like `vX.Y.Z`.
|
||||
6. Push and merge the changes to the `main` branch.
|
||||
7. Create the release on GitHub.
|
||||
8. Upload the new package to LuaRocks.
|
||||
|
||||
### Adding a New Top-Level Function
|
||||
1. Insert the new function into the `evolved` table in `evolved.lua`.
|
||||
2. Create tests for the function in `develop/testing/function_name_tests.lua`.
|
||||
3. Add the new test to `develop/all.lua`.
|
||||
4. Document the function in the **Cheat Sheet** and **API Reference** sections of `README.md`.
|
||||
5. Provide a description in the **Overview** section of `README.md`.
|
||||
6. Describe the update in the **Changelog** section of `README.md`.
|
||||
629
README.md
629
README.md
@@ -1,4 +1,4 @@
|
||||
# evolved.lua (work in progress)
|
||||
# evolved.lua
|
||||
|
||||
> Evolved ECS (Entity-Component-System) for Lua
|
||||
|
||||
@@ -19,6 +19,46 @@
|
||||
|
||||
[evolved]: https://github.com/BlackMATov/evolved.lua
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Performance](#performance)
|
||||
- [Simplicity](#simplicity)
|
||||
- [Flexibility](#flexibility)
|
||||
- [Installation](#installation)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Overview](#overview)
|
||||
- [Identifiers](#identifiers)
|
||||
- [Entities, Fragments, and Components](#entities-fragments-and-components)
|
||||
- [Traits](#traits)
|
||||
- [Singletons](#singletons)
|
||||
- [Chunks](#chunks)
|
||||
- [Structural Changes](#structural-changes)
|
||||
- [Spawning Entities](#spawning-entities)
|
||||
- [Entity Builders](#entity-builders)
|
||||
- [Access Operations](#access-operations)
|
||||
- [Iterating Over Fragments](#iterating-over-fragments)
|
||||
- [Modifying Operations](#modifying-operations)
|
||||
- [Debug Mode](#debug-mode)
|
||||
- [Queries](#queries)
|
||||
- [Deferred Operations](#deferred-operations)
|
||||
- [Batch Operations](#batch-operations)
|
||||
- [Systems](#systems)
|
||||
- [Predefined Traits](#predefined-traits)
|
||||
- [Fragment Tags](#fragment-tags)
|
||||
- [Fragment Hooks](#fragment-hooks)
|
||||
- [Unique Fragments](#unique-fragments)
|
||||
- [Explicit Fragments](#explicit-fragments)
|
||||
- [Shared Components](#shared-components)
|
||||
- [Fragment Requirements](#fragment-requirements)
|
||||
- [Destruction Policies](#destruction-policies)
|
||||
- [Cheat Sheet](#cheat-sheet)
|
||||
- [Aliases](#aliases)
|
||||
- [Predefs](#predefs)
|
||||
- [Functions](#functions)
|
||||
- [Classes](#classes)
|
||||
- [Chunk](#chunk)
|
||||
- [Builder](#builder)
|
||||
- [License](#license)
|
||||
|
||||
## Introduction
|
||||
|
||||
`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. Before we start exploring the library, let's take a look at the main advantages of using `evolved.lua`:
|
||||
@@ -41,211 +81,21 @@ And yes, the library has some unusual concepts at its core, but once you get the
|
||||
|
||||
On the other hand, `evolved.lua` tries to be minimalistic and does not provide features that can be implemented outside the library. I'm trying to find a balance between minimalism and the number of possibilities, which forces me to make flexible decisions in the library's design. I hope you will find this balance acceptable.
|
||||
|
||||
## Requirements
|
||||
|
||||
- [lua](https://www.lua.org/) **>= 5.1**
|
||||
- [luajit](https://luajit.org/) **>= 2.0**
|
||||
|
||||
## Installation
|
||||
|
||||
You can install `evolved.lua` using [luarocks](https://luarocks.org/) with the following command:
|
||||
`evolved.lua` is a single-file pure Lua library and does not require any external dependencies. It is designed to work with [Lua 5.1](https://www.lua.org/) and later, [LuaJIT](https://luajit.org/), and [Luau](https://luau.org/) (Roblox).
|
||||
|
||||
All you need to start using the library is the [evolved.lua](./evolved.lua) source file. You can download it from the [releases](https://github.com/BlackMATov/evolved.lua/releases) page or clone the [repository](https://github.com/BlackMATov/evolved.lua) and copy the file to your project.
|
||||
|
||||
If you are using [LuaRocks](https://luarocks.org/), you can install the library using the following command:
|
||||
|
||||
```bash
|
||||
luarocks install evolved.lua
|
||||
```
|
||||
|
||||
Or just clone the [repository](https://github.com/BlackMATov/evolved.lua) and copy the [evolved.lua](evolved.lua) file to your project.
|
||||
|
||||
## Quick Start
|
||||
|
||||
To start using `evolved.lua`, read the [Overview](#overview) section first. It will give you a basic understanding of how the library works and how to use it. After that, check the full-featured [Example](develop/example.lua), which demonstrates complex usage of the library. Finally, refer to the [Cheat Sheet](#cheat-sheet) for a quick reference of all the functions and classes provided by the library.
|
||||
|
||||
Enjoy! :suspect:
|
||||
|
||||
## Cheat Sheet
|
||||
|
||||
### Aliases
|
||||
|
||||
```
|
||||
id :: implementation-specific
|
||||
|
||||
entity :: id
|
||||
fragment :: id
|
||||
query :: id
|
||||
system :: id
|
||||
|
||||
component :: any
|
||||
storage :: component[]
|
||||
|
||||
default :: component
|
||||
duplicate :: {component -> component}
|
||||
|
||||
execute :: {chunk, entity[], integer}
|
||||
prologue :: {}
|
||||
epilogue :: {}
|
||||
|
||||
set_hook :: {entity, fragment, component, component?}
|
||||
assign_hook :: {entity, fragment, component, component}
|
||||
insert_hook :: {entity, fragment, component}
|
||||
remove_hook :: {entity, fragment, component}
|
||||
|
||||
each_state :: implementation-specific
|
||||
execute_state :: implementation-specific
|
||||
|
||||
each_iterator :: {each_state? -> fragment?, component?}
|
||||
execute_iterator :: {execute_state? -> chunk?, entity[]?, integer?}
|
||||
```
|
||||
|
||||
### Predefs
|
||||
|
||||
```
|
||||
TAG :: fragment
|
||||
NAME :: fragment
|
||||
|
||||
UNIQUE :: fragment
|
||||
EXPLICIT :: fragment
|
||||
|
||||
DEFAULT :: fragment
|
||||
DUPLICATE :: fragment
|
||||
|
||||
PREFAB :: fragment
|
||||
DISABLED :: fragment
|
||||
|
||||
INCLUDES :: fragment
|
||||
EXCLUDES :: 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
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
```
|
||||
id :: integer? -> id...
|
||||
|
||||
pack :: integer, integer -> id
|
||||
unpack :: id -> integer, integer
|
||||
|
||||
defer :: boolean
|
||||
commit :: boolean
|
||||
|
||||
spawn :: <fragment, component>? -> entity
|
||||
clone :: entity -> <fragment, component>? -> entity
|
||||
|
||||
alive :: entity -> boolean
|
||||
alive_all :: entity... -> boolean
|
||||
alive_any :: entity... -> boolean
|
||||
|
||||
empty :: entity -> boolean
|
||||
empty_all :: entity... -> boolean
|
||||
empty_any :: entity... -> boolean
|
||||
|
||||
has :: entity, fragment -> boolean
|
||||
has_all :: entity, fragment... -> boolean
|
||||
has_any :: entity, fragment... -> boolean
|
||||
|
||||
get :: entity, fragment... -> component...
|
||||
|
||||
set :: entity, fragment, component -> ()
|
||||
remove :: entity, fragment... -> ()
|
||||
clear :: entity... -> ()
|
||||
destroy :: entity... -> ()
|
||||
|
||||
batch_set :: query, fragment, component -> ()
|
||||
batch_remove :: query, fragment... -> ()
|
||||
batch_clear :: query... -> ()
|
||||
batch_destroy :: query... -> ()
|
||||
|
||||
each :: entity -> {each_state? -> fragment?, component?}, each_state?
|
||||
execute :: query -> {execute_state? -> chunk?, entity[]?, integer?}, execute_state?
|
||||
|
||||
process :: system... -> ()
|
||||
|
||||
debug_mode :: boolean -> ()
|
||||
collect_garbage :: ()
|
||||
```
|
||||
|
||||
### Classes
|
||||
|
||||
#### Chunk
|
||||
|
||||
```
|
||||
chunk :: fragment, fragment... -> chunk, entity[], integer
|
||||
|
||||
chunk_mt:alive :: boolean
|
||||
chunk_mt:empty :: boolean
|
||||
|
||||
chunk_mt:has :: fragment -> boolean
|
||||
chunk_mt:has_all :: fragment... -> boolean
|
||||
chunk_mt:has_any :: fragment... -> boolean
|
||||
|
||||
chunk_mt:entities :: entity[], integer
|
||||
chunk_mt:fragments :: fragment[], integer
|
||||
chunk_mt:components :: fragment... -> storage...
|
||||
```
|
||||
|
||||
#### Builder
|
||||
|
||||
```
|
||||
builder :: builder
|
||||
|
||||
builder_mt:spawn :: entity
|
||||
builder_mt:clone :: entity -> entity
|
||||
|
||||
builder_mt:has :: fragment -> boolean
|
||||
builder_mt:has_all :: fragment... -> boolean
|
||||
builder_mt:has_any :: fragment... -> boolean
|
||||
|
||||
builder_mt:get :: fragment... -> component...
|
||||
|
||||
builder_mt:set :: fragment, component -> builder
|
||||
builder_mt:remove :: fragment... -> builder
|
||||
builder_mt:clear :: builder
|
||||
|
||||
builder_mt:tag :: builder
|
||||
builder_mt:name :: string -> builder
|
||||
|
||||
builder_mt:unique :: builder
|
||||
builder_mt:explicit :: builder
|
||||
|
||||
builder_mt:default :: component -> builder
|
||||
builder_mt:duplicate :: {component -> component} -> builder
|
||||
|
||||
builder_mt:prefab :: builder
|
||||
builder_mt:disabled :: builder
|
||||
|
||||
builder_mt:include :: fragment... -> builder
|
||||
builder_mt:exclude :: fragment... -> builder
|
||||
|
||||
builder_mt:on_set :: {entity, fragment, component, component?} -> builder
|
||||
builder_mt:on_assign :: {entity, fragment, component, component} -> builder
|
||||
builder_mt:on_insert :: {entity, fragment, component} -> builder
|
||||
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:prologue :: {} -> builder
|
||||
builder_mt:epilogue :: {} -> builder
|
||||
|
||||
builder_mt:destruction_policy :: id -> builder
|
||||
```
|
||||
To get started with `evolved.lua`, read the [Overview](#overview) section to understand the basic concepts and how to use the library. After that, check the [Samples](develop/samples), which demonstrate complex usage of the library. Finally, refer to the [Cheat Sheet](#cheat-sheet) for a quick reference of all the functions and classes provided by the library.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -300,11 +150,13 @@ Sometimes (for debugging purposes, for example), it is necessary to extract the
|
||||
---@param index integer
|
||||
---@param version integer
|
||||
---@return evolved.id id
|
||||
---@nodiscard
|
||||
function evolved.pack(index, version) end
|
||||
|
||||
---@param id evolved.id
|
||||
---@return integer index
|
||||
---@return integer version
|
||||
---@return integer primary
|
||||
---@return integer secondary
|
||||
---@nodiscard
|
||||
function evolved.unpack(id) end
|
||||
```
|
||||
|
||||
@@ -556,7 +408,7 @@ evolved.set(enemy1, stamina, 42)
|
||||
|
||||
#### Entity Builders
|
||||
|
||||
Another way to avoid structural changes when spawning entities is to use the [`evolved.builder`](#evolvedbuilder) fluid interface. The [`evolved.builder`](#evolvedbuilder) function returns a builder object that allows you to spawn entities with a specific set of fragments and components without the necessity of setting them one by one with structural changes for each change.
|
||||
Another way to avoid structural changes when spawning entities is to use the [`evolved.builder`](#evolvedbuilder) fluent interface. The [`evolved.builder`](#evolvedbuilder) function returns a builder object that allows you to spawn entities with a specific set of fragments and components without the necessity of setting them one by one with structural changes for each change.
|
||||
|
||||
```lua
|
||||
local evolved = require 'evolved'
|
||||
@@ -598,6 +450,35 @@ The [`evolved.alive`](#evolvedalive) function checks whether an entity is alive.
|
||||
|
||||
All of these functions can be safely called on non-alive entities and non-alive fragments. Also, they do not cause any structural changes, because they do not modify anything.
|
||||
|
||||
### Iterating Over Fragments
|
||||
|
||||
Sometimes, you may need to iterate over all fragments attached to an entity. You can use the [`evolved.each`](#evolvedeach) function for this purpose.
|
||||
|
||||
```lua
|
||||
local evolved = require 'evolved'
|
||||
|
||||
local health = evolved.builder()
|
||||
:name('health')
|
||||
:spawn()
|
||||
|
||||
local stamina = evolved.builder()
|
||||
:name('stamina')
|
||||
:spawn()
|
||||
|
||||
local player = evolved.builder()
|
||||
:set(health, 100)
|
||||
:set(stamina, 50)
|
||||
:spawn()
|
||||
|
||||
for fragment, component in evolved.each(player) do
|
||||
print(string.format('Fragment (%s) has value %d',
|
||||
evolved.name(fragment), component))
|
||||
end
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> [Structural changes](#structural-changes) are not allowed during iteration. If you want to spawn new entities or insert/remove fragments while iterating, defer these operations until the iteration is complete. See the [Deferred Operations](#deferred-operations) section for more details.
|
||||
|
||||
### Modifying Operations
|
||||
|
||||
The library provides a classic set of functions for modifying entities. These functions are used to insert, override, and remove fragments from entities.
|
||||
@@ -823,6 +704,28 @@ 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.
|
||||
|
||||
```lua
|
||||
local evolved = require 'evolved'
|
||||
|
||||
local health = evolved.id()
|
||||
|
||||
local system = evolved.builder()
|
||||
:include(health)
|
||||
:execute(function(chunk, entity_list, entity_count)
|
||||
local health_components = chunk:components(health)
|
||||
|
||||
for i = 1, entity_count do
|
||||
health_components[i] = math.max(
|
||||
health_components[i] - 1,
|
||||
0)
|
||||
end
|
||||
end):spawn()
|
||||
|
||||
evolved.process(system)
|
||||
```
|
||||
|
||||
To group systems together, you can use the [`evolved.GROUP`](#evolvedgroup) fragment. Systems with a specified group will be processed when you call the [`evolved.process`](#evolvedprocess) function with this group. For example, you can group all physics systems together and process them in one [`evolved.process`](#evolvedprocess) call.
|
||||
|
||||
```lua
|
||||
@@ -895,7 +798,7 @@ 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.
|
||||
|
||||
### Advanced Topics
|
||||
### Predefined Traits
|
||||
|
||||
#### Fragment Tags
|
||||
|
||||
@@ -1039,6 +942,35 @@ local enemy2 = evolved.builder()
|
||||
assert(evolved.get(enemy1, position) ~= evolved.get(enemy2, position))
|
||||
```
|
||||
|
||||
#### Fragment Requirements
|
||||
|
||||
Sometimes you want to add additional fragments to an entity when it receives a specific fragment. For example, you might want to add `position` and `velocity` fragments when an entity is given a `physical` fragment. This can be done using the [`evolved.REQUIRES`](#evolvedrequires) fragment trait. This trait expects a list of fragments that will be added to the entity when the fragment is inserted.
|
||||
|
||||
```lua
|
||||
local evolved = require 'evolved'
|
||||
|
||||
local position = evolved.builder()
|
||||
:default(vector2(0, 0))
|
||||
:duplicate(vector2_duplicate)
|
||||
:spawn()
|
||||
|
||||
local velocity = evolved.builder()
|
||||
:default(vector2(0, 0))
|
||||
:duplicate(vector2_duplicate)
|
||||
:spawn()
|
||||
|
||||
local physical = evolved.builder()
|
||||
:tag()
|
||||
:require(position, velocity)
|
||||
:spawn()
|
||||
|
||||
local enemy = evolved.builder()
|
||||
:set(physical)
|
||||
:spawn()
|
||||
|
||||
assert(evolved.has_all(enemy, position, velocity))
|
||||
```
|
||||
|
||||
#### Destruction Policies
|
||||
|
||||
Typically, fragments remain alive for the entire lifetime of the program. However, in some cases, you might want to destroy fragments when they are no longer needed. For example, you can use some runtime entities as fragments for other entities. In this case, you might want to destroy such fragments even while they are still attached to other entities. Since entities cannot have destroyed fragments, a destruction policy must be applied to resolve this. By default, the library will remove the destroyed fragment from all entities that have it.
|
||||
@@ -1086,6 +1018,223 @@ evolved.destroy(world)
|
||||
assert(not evolved.alive(entity))
|
||||
```
|
||||
|
||||
## Cheat Sheet
|
||||
|
||||
### Aliases
|
||||
|
||||
```
|
||||
id :: implementation-specific
|
||||
|
||||
entity :: id
|
||||
fragment :: id
|
||||
query :: id
|
||||
system :: id
|
||||
|
||||
component :: any
|
||||
storage :: component[]
|
||||
|
||||
default :: component
|
||||
duplicate :: {component -> component}
|
||||
|
||||
execute :: {chunk, entity[], integer}
|
||||
prologue :: {}
|
||||
epilogue :: {}
|
||||
|
||||
set_hook :: {entity, fragment, component, component?}
|
||||
assign_hook :: {entity, fragment, component, component}
|
||||
insert_hook :: {entity, fragment, component}
|
||||
remove_hook :: {entity, fragment, component}
|
||||
|
||||
each_state :: implementation-specific
|
||||
execute_state :: implementation-specific
|
||||
|
||||
each_iterator :: {each_state? -> fragment?, component?}
|
||||
execute_iterator :: {execute_state? -> chunk?, entity[]?, integer?}
|
||||
```
|
||||
|
||||
### Predefs
|
||||
|
||||
```
|
||||
TAG :: fragment
|
||||
NAME :: fragment
|
||||
|
||||
UNIQUE :: fragment
|
||||
EXPLICIT :: fragment
|
||||
INTERNAL :: fragment
|
||||
|
||||
DEFAULT :: fragment
|
||||
DUPLICATE :: fragment
|
||||
|
||||
PREFAB :: fragment
|
||||
DISABLED :: fragment
|
||||
|
||||
INCLUDES :: fragment
|
||||
EXCLUDES :: fragment
|
||||
REQUIRES :: fragment
|
||||
|
||||
ON_SET :: fragment
|
||||
ON_ASSIGN :: fragment
|
||||
ON_INSERT :: fragment
|
||||
ON_REMOVE :: fragment
|
||||
|
||||
GROUP :: fragment
|
||||
|
||||
QUERY :: fragment
|
||||
EXECUTE :: fragment
|
||||
|
||||
PROLOGUE :: fragment
|
||||
EPILOGUE :: fragment
|
||||
|
||||
DESTRUCTION_POLICY :: fragment
|
||||
DESTRUCTION_POLICY_DESTROY_ENTITY :: id
|
||||
DESTRUCTION_POLICY_REMOVE_FRAGMENT :: id
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
```
|
||||
id :: integer? -> id...
|
||||
name :: id... -> string...
|
||||
|
||||
pack :: integer, integer -> id
|
||||
unpack :: id -> integer, integer
|
||||
|
||||
defer :: boolean
|
||||
commit :: boolean
|
||||
|
||||
spawn :: <fragment, component>? -> entity
|
||||
multi_spawn :: integer, <fragment, component>? -> entity[]
|
||||
|
||||
clone :: entity, <fragment, component>? -> entity
|
||||
multi_clone :: integer, entity, <fragment, component>? -> entity[]
|
||||
|
||||
alive :: entity -> boolean
|
||||
alive_all :: entity... -> boolean
|
||||
alive_any :: entity... -> boolean
|
||||
|
||||
empty :: entity -> boolean
|
||||
empty_all :: entity... -> boolean
|
||||
empty_any :: entity... -> boolean
|
||||
|
||||
has :: entity, fragment -> boolean
|
||||
has_all :: entity, fragment... -> boolean
|
||||
has_any :: entity, fragment... -> boolean
|
||||
|
||||
get :: entity, fragment... -> component...
|
||||
|
||||
set :: entity, fragment, component -> ()
|
||||
remove :: entity, fragment... -> ()
|
||||
clear :: entity... -> ()
|
||||
destroy :: entity... -> ()
|
||||
|
||||
batch_set :: query, fragment, component -> ()
|
||||
batch_remove :: query, fragment... -> ()
|
||||
batch_clear :: query... -> ()
|
||||
batch_destroy :: query... -> ()
|
||||
|
||||
each :: entity -> {each_state? -> fragment?, component?}, each_state?
|
||||
execute :: query -> {execute_state? -> chunk?, entity[]?, integer?}, execute_state?
|
||||
|
||||
process :: system... -> ()
|
||||
|
||||
debug_mode :: boolean -> ()
|
||||
collect_garbage :: ()
|
||||
```
|
||||
|
||||
### Classes
|
||||
|
||||
#### Chunk
|
||||
|
||||
```
|
||||
chunk :: fragment, fragment... -> chunk, entity[], integer
|
||||
|
||||
chunk_mt:alive :: boolean
|
||||
chunk_mt:empty :: boolean
|
||||
|
||||
chunk_mt:has :: fragment -> boolean
|
||||
chunk_mt:has_all :: fragment... -> boolean
|
||||
chunk_mt:has_any :: fragment... -> boolean
|
||||
|
||||
chunk_mt:entities :: entity[], integer
|
||||
chunk_mt:fragments :: fragment[], integer
|
||||
chunk_mt:components :: fragment... -> storage...
|
||||
```
|
||||
|
||||
#### Builder
|
||||
|
||||
```
|
||||
builder :: builder
|
||||
|
||||
builder_mt:spawn :: entity
|
||||
builder_mt:multi_spawn :: integer -> entity[]
|
||||
|
||||
builder_mt:clone :: entity -> entity
|
||||
builder_mt:multi_clone :: integer, entity -> entity[]
|
||||
|
||||
builder_mt:has :: fragment -> boolean
|
||||
builder_mt:has_all :: fragment... -> boolean
|
||||
builder_mt:has_any :: fragment... -> boolean
|
||||
|
||||
builder_mt:get :: fragment... -> component...
|
||||
|
||||
builder_mt:set :: fragment, component -> builder
|
||||
builder_mt:remove :: fragment... -> builder
|
||||
builder_mt:clear :: builder
|
||||
|
||||
builder_mt:tag :: builder
|
||||
builder_mt:name :: string -> builder
|
||||
|
||||
builder_mt:unique :: builder
|
||||
builder_mt:explicit :: builder
|
||||
builder_mt:internal :: builder
|
||||
|
||||
builder_mt:default :: component -> builder
|
||||
builder_mt:duplicate :: {component -> component} -> builder
|
||||
|
||||
builder_mt:prefab :: builder
|
||||
builder_mt:disabled :: builder
|
||||
|
||||
builder_mt:include :: fragment... -> builder
|
||||
builder_mt:exclude :: fragment... -> builder
|
||||
builder_mt:require :: fragment... -> builder
|
||||
|
||||
builder_mt:on_set :: {entity, fragment, component, component?} -> builder
|
||||
builder_mt:on_assign :: {entity, fragment, component, component} -> builder
|
||||
builder_mt:on_insert :: {entity, fragment, component} -> builder
|
||||
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:prologue :: {} -> builder
|
||||
builder_mt:epilogue :: {} -> builder
|
||||
|
||||
builder_mt:destruction_policy :: id -> builder
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
`evolved.lua` is licensed under the [MIT License][license]. For more details, see the [LICENSE.md](./LICENSE.md) file in the repository.
|
||||
|
||||
# Changelog
|
||||
|
||||
## v1.2.0
|
||||
|
||||
- Added the new [`evolved.name`](#evolvedname-1) function
|
||||
- Added the new [`evolved.multi_spawn`](#evolvedmulti_spawn) and [`evolved.multi_clone`](#evolvedmulti_clone) functions
|
||||
- Added the new [`evolved.INTERNAL`](#evolvedinternal) fragment trait
|
||||
|
||||
## v1.1.0
|
||||
|
||||
- [`Systems`](#systems) can be queries themselves now
|
||||
- Added the new [`evolved.REQUIRES`](#evolvedrequires) fragment trait
|
||||
|
||||
## v1.0.0
|
||||
|
||||
- Initial release
|
||||
|
||||
# API Reference
|
||||
|
||||
## Predefs
|
||||
@@ -1098,6 +1247,8 @@ assert(not evolved.alive(entity))
|
||||
|
||||
### `evolved.EXPLICIT`
|
||||
|
||||
### `evolved.INTERNAL`
|
||||
|
||||
### `evolved.DEFAULT`
|
||||
|
||||
### `evolved.DUPLICATE`
|
||||
@@ -1110,6 +1261,8 @@ assert(not evolved.alive(entity))
|
||||
|
||||
### `evolved.EXCLUDES`
|
||||
|
||||
### `evolved.REQUIRES`
|
||||
|
||||
### `evolved.ON_SET`
|
||||
|
||||
### `evolved.ON_ASSIGN`
|
||||
@@ -1145,6 +1298,15 @@ assert(not evolved.alive(entity))
|
||||
function evolved.id(count) end
|
||||
```
|
||||
|
||||
### `evolved.name`
|
||||
|
||||
```lua
|
||||
---@param ... evolved.id ids
|
||||
---@return string... names
|
||||
---@nodiscard
|
||||
function evolved.name(...) end
|
||||
```
|
||||
|
||||
### `evolved.pack`
|
||||
|
||||
```lua
|
||||
@@ -1159,8 +1321,8 @@ function evolved.pack(index, version) end
|
||||
|
||||
```lua
|
||||
---@param id evolved.id
|
||||
---@return integer index
|
||||
---@return integer version
|
||||
---@return integer primary
|
||||
---@return integer secondary
|
||||
---@nodiscard
|
||||
function evolved.unpack(id) end
|
||||
```
|
||||
@@ -1183,19 +1345,38 @@ function evolved.commit() end
|
||||
|
||||
```lua
|
||||
---@param components? table<evolved.fragment, evolved.component>
|
||||
---@return evolved.entity
|
||||
---@return evolved.entity entity
|
||||
function evolved.spawn(components) end
|
||||
```
|
||||
|
||||
### `evolved.multi_spawn`
|
||||
|
||||
```lua
|
||||
---@param entity_count integer
|
||||
---@param components? table<evolved.fragment, evolved.component>
|
||||
---@return evolved.entity[] entity_list
|
||||
function evolved.multi_spawn(entity_count, components) end
|
||||
```
|
||||
|
||||
### `evolved.clone`
|
||||
|
||||
```lua
|
||||
---@param prefab evolved.entity
|
||||
---@param components? table<evolved.fragment, evolved.component>
|
||||
---@return evolved.entity
|
||||
---@return evolved.entity entity
|
||||
function evolved.clone(prefab, components) end
|
||||
```
|
||||
|
||||
### `evolved.multi_clone`
|
||||
|
||||
```lua
|
||||
---@param entity_count integer
|
||||
---@param prefab evolved.entity
|
||||
---@param components? table<evolved.fragment, evolved.component>
|
||||
---@return evolved.entity[] entity_list
|
||||
function evolved.multi_clone(entity_count, prefab, components) end
|
||||
```
|
||||
|
||||
### `evolved.alive`
|
||||
|
||||
```lua
|
||||
@@ -1491,18 +1672,35 @@ function evolved.builder() end
|
||||
#### `evolved.builder_mt:spawn`
|
||||
|
||||
```lua
|
||||
---@return evolved.entity
|
||||
---@return evolved.entity entity
|
||||
function evolved.builder_mt:spawn() end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:multi_spawn`
|
||||
|
||||
```lua
|
||||
---@param entity_count integer
|
||||
---@return evolved.entity[] entity_list
|
||||
function evolved.builder_mt:multi_spawn(entity_count) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:clone`
|
||||
|
||||
```lua
|
||||
---@param prefab evolved.entity
|
||||
---@return evolved.entity
|
||||
---@return evolved.entity entity
|
||||
function evolved.builder_mt:clone(prefab) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:multi_clone`
|
||||
|
||||
```lua
|
||||
---@param entity_count integer
|
||||
---@param prefab evolved.entity
|
||||
---@return evolved.entity[] entity_list
|
||||
function evolved.builder_mt:multi_clone(entity_count, prefab) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:has`
|
||||
|
||||
```lua
|
||||
@@ -1592,6 +1790,13 @@ function evolved.builder_mt:unique() end
|
||||
function evolved.builder_mt:explicit() end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:internal`
|
||||
|
||||
```lua
|
||||
---@return evolved.builder builder
|
||||
function evolved.builder_mt:internal() end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:default`
|
||||
|
||||
```lua
|
||||
@@ -1638,6 +1843,14 @@ function evolved.builder_mt:include(...) end
|
||||
function evolved.builder_mt:exclude(...) end
|
||||
```
|
||||
|
||||
### `evolved.builder_mt:require`
|
||||
|
||||
```lua
|
||||
---@param ... evolved.fragment fragments
|
||||
---@return evolved.builder builder
|
||||
function evolved.builder_mt:require(...) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:on_set`
|
||||
|
||||
```lua
|
||||
@@ -1717,5 +1930,3 @@ function evolved.builder_mt:epilogue(epilogue) end
|
||||
---@return evolved.builder builder
|
||||
function evolved.builder_mt:destruction_policy(destruction_policy) end
|
||||
```
|
||||
|
||||
## [License (MIT)](./LICENSE.md)
|
||||
|
||||
14
ROADMAP.md
14
ROADMAP.md
@@ -2,11 +2,17 @@
|
||||
|
||||
## Backlog
|
||||
|
||||
## After first release
|
||||
|
||||
- cached queries
|
||||
- Improve the performance of required fragments by caching first-level required chunks.
|
||||
- Improve the performance of builders that are used multiple times by caching hint chunks.
|
||||
- Queries can cache major chunks to avoid finding them every time.
|
||||
- Add a function to shrink storages to free unused memory.
|
||||
- observers and events
|
||||
- add INDEX fragment trait
|
||||
- add REQUIRES fragment trait
|
||||
- use compact prefix-tree for chunks
|
||||
- optional ffi component storages
|
||||
|
||||
## Thoughts
|
||||
|
||||
- We can return deferred status from modifying operations and spawn/clone methods.
|
||||
- Should we make one builder:build method instead of :spawn and :clone?
|
||||
- Should we cache the result of without_unique_fragments to clone faster?
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
require 'develop.example'
|
||||
require 'develop.unbench'
|
||||
require 'develop.samples.systems'
|
||||
|
||||
require 'develop.testing.multi_spawn_tests'
|
||||
require 'develop.testing.name_tests'
|
||||
require 'develop.testing.requires_fragment_tests'
|
||||
require 'develop.testing.system_as_query_tests'
|
||||
|
||||
require 'develop.benchmarks.multi_clone_bmarks'
|
||||
require 'develop.benchmarks.multi_spawn_bmarks'
|
||||
|
||||
require 'develop.untests'
|
||||
|
||||
require 'develop.unbench'
|
||||
require 'develop.usbench'
|
||||
|
||||
local basics = require 'develop.basics'
|
||||
@@ -12,4 +22,8 @@ basics.describe_fuzz 'develop.fuzzing.batch_destroy_fuzz'
|
||||
print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.explicit_fuzz'
|
||||
print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.pack_unpack_fuzz'
|
||||
print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.requires_fuzz'
|
||||
print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.unique_fuzz'
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
local basics = {}
|
||||
|
||||
local MIN_FUZZ_SECS = 0.5
|
||||
local MIN_BENCH_SECS = 0.1
|
||||
local MIN_WARMUP_SECS = 0.1
|
||||
|
||||
local MIN_FUZZ_ITERS = 100
|
||||
local MIN_BENCH_ITERS = 100
|
||||
local MIN_WARMUP_ITERS = 100
|
||||
|
||||
local __table_pack = (function()
|
||||
---@diagnostic disable-next-line: deprecated
|
||||
return table.pack or function(...)
|
||||
@@ -23,8 +31,13 @@ end
|
||||
|
||||
---@param modname string
|
||||
function basics.describe_fuzz(modname)
|
||||
basics.unload('evolved')
|
||||
|
||||
print(string.format('| %s ... |', modname))
|
||||
|
||||
collectgarbage('collect')
|
||||
collectgarbage('stop')
|
||||
|
||||
do
|
||||
local iters = 0
|
||||
|
||||
@@ -36,7 +49,7 @@ function basics.describe_fuzz(modname)
|
||||
iters = iters + 1
|
||||
basics.unload(modname)
|
||||
require(modname)
|
||||
until os.clock() - start_s > 0.5
|
||||
until iters >= MIN_FUZZ_ITERS and os.clock() - start_s >= MIN_FUZZ_SECS
|
||||
end)
|
||||
|
||||
local finish_s = os.clock()
|
||||
@@ -52,6 +65,9 @@ function basics.describe_fuzz(modname)
|
||||
print('|-- FUZZ FAIL: ' .. result)
|
||||
end
|
||||
end
|
||||
|
||||
collectgarbage('restart')
|
||||
collectgarbage('collect')
|
||||
end
|
||||
|
||||
---@param name string
|
||||
@@ -59,17 +75,22 @@ end
|
||||
---@param init? fun(): ...
|
||||
---@param fini? fun(...): ...
|
||||
function basics.describe_bench(name, loop, init, fini)
|
||||
basics.unload('evolved')
|
||||
|
||||
print(string.format('| %s ... |', name))
|
||||
|
||||
local state = init and __table_pack(init()) or {}
|
||||
|
||||
do
|
||||
local iters = 0
|
||||
|
||||
local warmup_s = os.clock()
|
||||
|
||||
local success, result = pcall(function()
|
||||
repeat
|
||||
iters = iters + 1
|
||||
loop(__table_unpack(state))
|
||||
until os.clock() - warmup_s > 0.1
|
||||
until iters >= MIN_WARMUP_ITERS and os.clock() - warmup_s > MIN_WARMUP_SECS
|
||||
end)
|
||||
|
||||
if not success then
|
||||
@@ -91,7 +112,7 @@ function basics.describe_bench(name, loop, init, fini)
|
||||
repeat
|
||||
iters = iters + 1
|
||||
loop(__table_unpack(state))
|
||||
until os.clock() - start_s > 0.1
|
||||
until iters >= MIN_BENCH_ITERS and os.clock() - start_s > MIN_BENCH_SECS
|
||||
end)
|
||||
|
||||
local finish_s = os.clock()
|
||||
|
||||
59
develop/benchmarks/multi_clone_bmarks.lua
Normal file
59
develop/benchmarks/multi_clone_bmarks.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
local evo = require 'evolved'
|
||||
local basics = require 'develop.basics'
|
||||
|
||||
evo.debug_mode(false)
|
||||
|
||||
local N = 1000
|
||||
|
||||
local F1, F2, F3, F4, F5 = evo.id(5)
|
||||
local Q1 = evo.builder():include(F1):spawn()
|
||||
|
||||
print '----------------------------------------'
|
||||
|
||||
basics.describe_bench(string.format('Multi Clone Benchmarks: Simple Clone | %d entities with 1 component', N),
|
||||
function()
|
||||
local clone = evo.clone
|
||||
|
||||
local prefab = evo.spawn { [F1] = true }
|
||||
|
||||
for _ = 1, N do
|
||||
clone(prefab)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('Multi Clone Benchmarks: Simple Clone | %d entities with 5 components', N),
|
||||
function()
|
||||
local clone = evo.clone
|
||||
|
||||
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
|
||||
|
||||
for _ = 1, N do
|
||||
clone(prefab)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('Multi Clone Benchmarks: Multi Clone | %d entities with 1 component', N),
|
||||
function()
|
||||
local multi_clone = evo.multi_clone
|
||||
|
||||
local prefab = evo.spawn { [F1] = true }
|
||||
|
||||
multi_clone(N, prefab)
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('Multi Clone Benchmarks: Multi Clone | %d entities with 5 components', N),
|
||||
function()
|
||||
local multi_clone = evo.multi_clone
|
||||
|
||||
local prefab = evo.spawn { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
|
||||
|
||||
multi_clone(N, prefab)
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end)
|
||||
59
develop/benchmarks/multi_spawn_bmarks.lua
Normal file
59
develop/benchmarks/multi_spawn_bmarks.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
local evo = require 'evolved'
|
||||
local basics = require 'develop.basics'
|
||||
|
||||
evo.debug_mode(false)
|
||||
|
||||
local N = 1000
|
||||
|
||||
local F1, F2, F3, F4, F5 = evo.id(5)
|
||||
local Q1 = evo.builder():include(F1):spawn()
|
||||
|
||||
print '----------------------------------------'
|
||||
|
||||
basics.describe_bench(string.format('Multi Spawn Benchmarks: Simple Spawn | %d entities with 1 component', N),
|
||||
function()
|
||||
local spawn = evo.spawn
|
||||
|
||||
local components = { [F1] = true }
|
||||
|
||||
for _ = 1, N do
|
||||
spawn(components)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('Multi Spawn Benchmarks: Simple Spawn | %d entities with 5 components', N),
|
||||
function()
|
||||
local spawn = evo.spawn
|
||||
|
||||
local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
|
||||
|
||||
for _ = 1, N do
|
||||
spawn(components)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('Multi Spawn Benchmarks: Multi Spawn | %d entities with 1 component', N),
|
||||
function()
|
||||
local multi_spawn = evo.multi_spawn
|
||||
|
||||
local components = { [F1] = true }
|
||||
|
||||
multi_spawn(N, components)
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('Multi Spawn Benchmarks: Multi Spawn | %d entities with 5 components', N),
|
||||
function()
|
||||
local multi_spawn = evo.multi_spawn
|
||||
|
||||
local components = { [F1] = true, [F2] = true, [F3] = true, [F4] = true, [F5] = true }
|
||||
|
||||
multi_spawn(N, components)
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end)
|
||||
@@ -117,5 +117,12 @@ end
|
||||
---
|
||||
---
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
evo.destroy(__table_unpack(all_entity_list))
|
||||
evo.collect_garbage()
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
@@ -123,5 +123,12 @@ end
|
||||
---
|
||||
---
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
evo.destroy(__table_unpack(all_entity_list))
|
||||
evo.collect_garbage()
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
@@ -77,5 +77,12 @@ end
|
||||
---
|
||||
---
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
evo.destroy(__table_unpack(all_entity_list))
|
||||
evo.collect_garbage()
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
20
develop/fuzzing/pack_unpack_fuzz.lua
Normal file
20
develop/fuzzing/pack_unpack_fuzz.lua
Normal file
@@ -0,0 +1,20 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
evo.debug_mode(true)
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
for _ = 1, 1000 do
|
||||
local initial_primary = math.random(1, 2 ^ 20 - 1)
|
||||
local initial_secondary = math.random(1, 2 ^ 20 - 1)
|
||||
|
||||
local packed_id = evo.pack(initial_primary, initial_secondary)
|
||||
local unpacked_primary, unpacked_secondary = evo.unpack(packed_id)
|
||||
|
||||
assert(initial_primary == unpacked_primary)
|
||||
assert(initial_secondary == unpacked_secondary)
|
||||
end
|
||||
131
develop/fuzzing/requires_fuzz.lua
Normal file
131
develop/fuzzing/requires_fuzz.lua
Normal file
@@ -0,0 +1,131 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
evo.debug_mode(true)
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
local __table_unpack = (function()
|
||||
---@diagnostic disable-next-line: deprecated
|
||||
return table.unpack or unpack
|
||||
end)()
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
local all_fragment_list = {} ---@type evolved.fragment[]
|
||||
|
||||
for i = 1, math.random(1, 10) do
|
||||
local fragment = evo.builder()
|
||||
:default(42)
|
||||
:spawn()
|
||||
all_fragment_list[i] = fragment
|
||||
end
|
||||
|
||||
for _, fragment in ipairs(all_fragment_list) do
|
||||
if math.random(1, 2) == 1 then
|
||||
for _ = 0, math.random(0, #all_fragment_list) do
|
||||
local require_list = evo.get(fragment, evo.REQUIRES) or {}
|
||||
require_list[#require_list + 1] = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
evo.set(fragment, evo.REQUIRES, require_list)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local all_entity_list = {} ---@type evolved.entity[]
|
||||
|
||||
for i = 1, math.random(1, 10) do
|
||||
local entity = evo.id()
|
||||
all_entity_list[i] = entity
|
||||
|
||||
for _ = 0, math.random(0, #all_fragment_list) do
|
||||
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.set(entity, fragment, 42)
|
||||
else
|
||||
local query = evo.builder()
|
||||
:include(all_fragment_list[math.random(1, #all_fragment_list)])
|
||||
:spawn()
|
||||
evo.batch_set(query, fragment, 42)
|
||||
evo.destroy(query)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _ = 1, math.random(1, #all_entity_list) do
|
||||
local components = {}
|
||||
for _ = 1, math.random(1, #all_fragment_list) do
|
||||
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
components[fragment] = 42
|
||||
end
|
||||
all_entity_list[#all_entity_list + 1] = evo.spawn(components)
|
||||
end
|
||||
|
||||
for _ = 1, math.random(1, #all_entity_list) do
|
||||
local prefab = all_entity_list[math.random(1, #all_entity_list)]
|
||||
all_entity_list[#all_entity_list + 1] = evo.clone(prefab)
|
||||
end
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
local function collect_required_fragments_for(fragment, req_fragment_set, req_fragment_list)
|
||||
local fragment_requires = evo.get(fragment, evo.REQUIRES) or {}
|
||||
for _, required_fragment in ipairs(fragment_requires) do
|
||||
if not req_fragment_set[required_fragment] then
|
||||
req_fragment_set[required_fragment] = true
|
||||
req_fragment_list[#req_fragment_list + 1] = required_fragment
|
||||
collect_required_fragments_for(required_fragment, req_fragment_set, req_fragment_list)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, entity in ipairs(all_entity_list) do
|
||||
for fragment in evo.each(entity) do
|
||||
local req_fragment_list = {}
|
||||
collect_required_fragments_for(fragment, {}, req_fragment_list)
|
||||
for _, required_fragment in ipairs(req_fragment_list) do
|
||||
assert(evo.has(entity, required_fragment))
|
||||
local required_component = evo.get(entity, required_fragment)
|
||||
assert(required_component == 42)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.destroy(__table_unpack(all_entity_list))
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
evo.destroy(__table_unpack(all_fragment_list))
|
||||
else
|
||||
evo.destroy(__table_unpack(all_fragment_list))
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
evo.destroy(__table_unpack(all_entity_list))
|
||||
end
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
@@ -63,5 +63,12 @@ end
|
||||
---
|
||||
---
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
evo.destroy(__table_unpack(all_entity_list))
|
||||
evo.collect_garbage()
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
308
develop/testing/multi_spawn_tests.lua
Normal file
308
develop/testing/multi_spawn_tests.lua
Normal file
@@ -0,0 +1,308 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
do
|
||||
local entity_list
|
||||
|
||||
do
|
||||
entity_list = evo.multi_spawn(0)
|
||||
assert(entity_list and #entity_list == 0)
|
||||
|
||||
entity_list = evo.multi_spawn(0, {})
|
||||
assert(entity_list and #entity_list == 0)
|
||||
end
|
||||
|
||||
do
|
||||
entity_list = evo.multi_spawn(-1)
|
||||
assert(entity_list and #entity_list == 0)
|
||||
|
||||
entity_list = evo.multi_spawn(-1, {})
|
||||
assert(entity_list and #entity_list == 0)
|
||||
end
|
||||
|
||||
do
|
||||
entity_list = evo.builder():multi_spawn(0)
|
||||
assert(entity_list and #entity_list == 0)
|
||||
end
|
||||
|
||||
do
|
||||
entity_list = evo.builder():multi_spawn(-1)
|
||||
assert(entity_list and #entity_list == 0)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local entity_list
|
||||
|
||||
do
|
||||
entity_list = evo.multi_spawn(1)
|
||||
assert(entity_list and #entity_list == 1)
|
||||
assert(entity_list[1] and evo.empty(entity_list[1]))
|
||||
assert(not entity_list[2])
|
||||
|
||||
entity_list = evo.multi_spawn(1, {})
|
||||
assert(entity_list and #entity_list == 1)
|
||||
assert(entity_list[1] and evo.empty(entity_list[1]))
|
||||
assert(not entity_list[2])
|
||||
end
|
||||
|
||||
do
|
||||
entity_list = evo.multi_spawn(2)
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_list[1] and evo.empty(entity_list[1]))
|
||||
assert(entity_list[2] and evo.empty(entity_list[2]))
|
||||
assert(not entity_list[3])
|
||||
|
||||
entity_list = evo.multi_spawn(2, {})
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_list[1] and evo.empty(entity_list[1]))
|
||||
assert(entity_list[2] and evo.empty(entity_list[2]))
|
||||
assert(not entity_list[3])
|
||||
end
|
||||
|
||||
do
|
||||
entity_list = evo.builder():multi_spawn(1)
|
||||
assert(entity_list and #entity_list == 1)
|
||||
assert(entity_list[1] and evo.empty(entity_list[1]))
|
||||
assert(not entity_list[2])
|
||||
end
|
||||
|
||||
do
|
||||
entity_list = evo.builder():multi_spawn(2)
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_list[1] and evo.empty(entity_list[1]))
|
||||
assert(entity_list[2] and evo.empty(entity_list[2]))
|
||||
assert(not entity_list[3])
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local entity_list
|
||||
|
||||
local prefab = evo.id()
|
||||
|
||||
do
|
||||
entity_list = evo.multi_clone(0, prefab)
|
||||
assert(entity_list and #entity_list == 0)
|
||||
|
||||
entity_list = evo.multi_clone(0, prefab, {})
|
||||
assert(entity_list and #entity_list == 0)
|
||||
end
|
||||
|
||||
do
|
||||
entity_list = evo.multi_clone(-1, prefab)
|
||||
assert(entity_list and #entity_list == 0)
|
||||
|
||||
entity_list = evo.multi_clone(-1, prefab, {})
|
||||
assert(entity_list and #entity_list == 0)
|
||||
end
|
||||
|
||||
do
|
||||
entity_list = evo.builder():multi_clone(0, prefab)
|
||||
assert(entity_list and #entity_list == 0)
|
||||
end
|
||||
|
||||
do
|
||||
entity_list = evo.builder():multi_clone(-1, prefab)
|
||||
assert(entity_list and #entity_list == 0)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local entity_list
|
||||
|
||||
local prefab = evo.id()
|
||||
|
||||
do
|
||||
entity_list = evo.multi_clone(1, prefab)
|
||||
assert(entity_list and #entity_list == 1)
|
||||
assert(entity_list[1] and evo.empty(entity_list[1]))
|
||||
assert(not entity_list[2])
|
||||
|
||||
entity_list = evo.multi_clone(1, prefab, {})
|
||||
assert(entity_list and #entity_list == 1)
|
||||
assert(entity_list[1] and evo.empty(entity_list[1]))
|
||||
assert(not entity_list[2])
|
||||
end
|
||||
|
||||
do
|
||||
entity_list = evo.multi_clone(2, prefab)
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_list[1] and evo.empty(entity_list[1]))
|
||||
assert(entity_list[2] and evo.empty(entity_list[2]))
|
||||
assert(not entity_list[3])
|
||||
|
||||
entity_list = evo.multi_clone(2, prefab, {})
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_list[1] and evo.empty(entity_list[1]))
|
||||
assert(entity_list[2] and evo.empty(entity_list[2]))
|
||||
assert(not entity_list[3])
|
||||
end
|
||||
|
||||
do
|
||||
entity_list = evo.builder():multi_clone(1, prefab)
|
||||
assert(entity_list and #entity_list == 1)
|
||||
assert(entity_list[1] and evo.empty(entity_list[1]))
|
||||
assert(not entity_list[2])
|
||||
end
|
||||
|
||||
do
|
||||
entity_list = evo.builder():multi_clone(2, prefab)
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_list[1] and evo.empty(entity_list[1]))
|
||||
assert(entity_list[2] and evo.empty(entity_list[2]))
|
||||
assert(not entity_list[3])
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
|
||||
do
|
||||
local entity_list
|
||||
|
||||
entity_list = evo.multi_spawn(2, { [f1] = true, [f2] = 123 })
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_list[1] and evo.get(entity_list[1], f1) == true and evo.get(entity_list[1], f2) == 123)
|
||||
assert(entity_list[2] and evo.get(entity_list[2], f1) == true and evo.get(entity_list[2], f2) == 123)
|
||||
|
||||
entity_list = evo.multi_spawn(2, { [f1] = false, [f2] = 456 })
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_list[1] and evo.get(entity_list[1], f1) == false and evo.get(entity_list[1], f2) == 456)
|
||||
assert(entity_list[2] and evo.get(entity_list[2], f1) == false and evo.get(entity_list[2], f2) == 456)
|
||||
end
|
||||
|
||||
do
|
||||
local prefab = evo.builder():set(f1, true):set(f2, 123):spawn()
|
||||
|
||||
local entity_list
|
||||
|
||||
entity_list = evo.multi_clone(2, prefab)
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_list[1] and evo.get(entity_list[1], f1) == true and evo.get(entity_list[1], f2) == 123)
|
||||
assert(entity_list[2] and evo.get(entity_list[2], f1) == true and evo.get(entity_list[2], f2) == 123)
|
||||
|
||||
entity_list = evo.multi_clone(2, prefab, {})
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_list[1] and evo.get(entity_list[1], f1) == true and evo.get(entity_list[1], f2) == 123)
|
||||
assert(entity_list[2] and evo.get(entity_list[2], f1) == true and evo.get(entity_list[2], f2) == 123)
|
||||
|
||||
entity_list = evo.multi_clone(2, prefab, { [f1] = false, [f2] = 456 })
|
||||
assert(entity_list and #entity_list == 2)
|
||||
assert(entity_list[1] and evo.get(entity_list[1], f1) == false and evo.get(entity_list[1], f2) == 456)
|
||||
assert(entity_list[2] and evo.get(entity_list[2], f1) == false and evo.get(entity_list[2], f2) == 456)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3 = evo.id(3)
|
||||
|
||||
do
|
||||
local entity_list1, entity_list2
|
||||
|
||||
evo.defer()
|
||||
do
|
||||
entity_list1 = evo.multi_spawn(2, { [f1] = 42, [f2] = "hello", [f3] = false })
|
||||
assert(entity_list1 and #entity_list1 == 2)
|
||||
assert(entity_list1[1] and evo.empty(entity_list1[1]))
|
||||
assert(entity_list1[2] and evo.empty(entity_list1[2]))
|
||||
assert(not entity_list1[3])
|
||||
|
||||
entity_list2 = evo.multi_spawn(3, { [f2] = "world", [f3] = true })
|
||||
assert(entity_list2 and #entity_list2 == 3)
|
||||
assert(entity_list2[1] and evo.empty(entity_list2[1]))
|
||||
assert(entity_list2[2] and evo.empty(entity_list2[2]))
|
||||
assert(entity_list2[3] and evo.empty(entity_list2[3]))
|
||||
end
|
||||
evo.commit()
|
||||
do
|
||||
assert(entity_list1 and #entity_list1 == 2)
|
||||
assert(entity_list1[1] and not evo.empty(entity_list1[1]))
|
||||
assert(entity_list1[2] and not evo.empty(entity_list1[2]))
|
||||
assert(not entity_list1[3])
|
||||
assert(
|
||||
evo.get(entity_list1[1], f1) == 42 and
|
||||
evo.get(entity_list1[1], f2) == "hello" and
|
||||
evo.get(entity_list1[1], f3) == false)
|
||||
assert(
|
||||
evo.get(entity_list1[2], f1) == 42 and
|
||||
evo.get(entity_list1[2], f2) == "hello" and
|
||||
evo.get(entity_list1[2], f3) == false)
|
||||
|
||||
assert(entity_list2 and #entity_list2 == 3)
|
||||
assert(entity_list2[1] and not evo.empty(entity_list2[1]))
|
||||
assert(entity_list2[2] and not evo.empty(entity_list2[2]))
|
||||
assert(entity_list2[3] and not evo.empty(entity_list2[3]))
|
||||
assert(not entity_list2[4])
|
||||
assert(
|
||||
evo.get(entity_list2[1], f1) == nil and
|
||||
evo.get(entity_list2[1], f2) == "world" and
|
||||
evo.get(entity_list2[1], f3) == true)
|
||||
assert(
|
||||
evo.get(entity_list2[2], f1) == nil and
|
||||
evo.get(entity_list2[2], f2) == "world" and
|
||||
evo.get(entity_list2[2], f3) == true)
|
||||
assert(
|
||||
evo.get(entity_list2[3], f1) == nil and
|
||||
evo.get(entity_list2[3], f2) == "world" and
|
||||
evo.get(entity_list2[3], f3) == true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3 = evo.id(3)
|
||||
|
||||
do
|
||||
local prefab = evo.builder():set(f1, false):set(f2, 123):spawn()
|
||||
|
||||
local entity_list1, entity_list2
|
||||
|
||||
evo.defer()
|
||||
do
|
||||
entity_list1 = evo.multi_clone(2, prefab)
|
||||
assert(entity_list1 and #entity_list1 == 2)
|
||||
assert(entity_list1[1] and evo.empty(entity_list1[1]))
|
||||
assert(entity_list1[2] and evo.empty(entity_list1[2]))
|
||||
assert(not entity_list1[3])
|
||||
|
||||
entity_list2 = evo.multi_clone(3, prefab, { [f2] = 456, [f3] = "world" })
|
||||
assert(entity_list2 and #entity_list2 == 3)
|
||||
assert(entity_list2[1] and evo.empty(entity_list2[1]))
|
||||
assert(entity_list2[2] and evo.empty(entity_list2[2]))
|
||||
assert(entity_list2[3] and evo.empty(entity_list2[3]))
|
||||
end
|
||||
evo.commit()
|
||||
do
|
||||
assert(entity_list1 and #entity_list1 == 2)
|
||||
assert(entity_list1[1] and not evo.empty(entity_list1[1]))
|
||||
assert(entity_list1[2] and not evo.empty(entity_list1[2]))
|
||||
assert(not entity_list1[3])
|
||||
assert(
|
||||
evo.get(entity_list1[1], f1) == false and
|
||||
evo.get(entity_list1[1], f2) == 123 and
|
||||
evo.get(entity_list1[1], f3) == nil)
|
||||
assert(
|
||||
evo.get(entity_list1[2], f1) == false and
|
||||
evo.get(entity_list1[2], f2) == 123 and
|
||||
evo.get(entity_list1[2], f3) == nil)
|
||||
|
||||
assert(entity_list2 and #entity_list2 == 3)
|
||||
assert(entity_list2[1] and not evo.empty(entity_list2[1]))
|
||||
assert(entity_list2[2] and not evo.empty(entity_list2[2]))
|
||||
assert(entity_list2[3] and not evo.empty(entity_list2[3]))
|
||||
assert(not entity_list2[4])
|
||||
assert(
|
||||
evo.get(entity_list2[1], f1) == false and
|
||||
evo.get(entity_list2[1], f2) == 456 and
|
||||
evo.get(entity_list2[1], f3) == "world")
|
||||
assert(
|
||||
evo.get(entity_list2[2], f1) == false and
|
||||
evo.get(entity_list2[2], f2) == 456 and
|
||||
evo.get(entity_list2[2], f3) == "world")
|
||||
assert(
|
||||
evo.get(entity_list2[3], f1) == false and
|
||||
evo.get(entity_list2[3], f2) == 456 and
|
||||
evo.get(entity_list2[3], f3) == "world")
|
||||
end
|
||||
end
|
||||
end
|
||||
43
develop/testing/name_tests.lua
Normal file
43
develop/testing/name_tests.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
do
|
||||
local id = evo.id()
|
||||
|
||||
local index, version = evo.unpack(id)
|
||||
assert(evo.name(id) == string.format('$%d#%d:%d', id, index, version))
|
||||
|
||||
evo.set(id, evo.NAME, 'hello')
|
||||
assert(evo.name(id) == 'hello')
|
||||
|
||||
evo.set(id, evo.NAME, 'world')
|
||||
assert(evo.name(id) == 'world')
|
||||
|
||||
evo.destroy(id)
|
||||
assert(evo.name(id) == string.format('$%d#%d:%d', id, index, version))
|
||||
end
|
||||
|
||||
do
|
||||
local id1, id2, id3, id4, id5 = evo.id(5)
|
||||
|
||||
evo.set(id1, evo.NAME, 'id1')
|
||||
evo.set(id2, evo.NAME, 'id2')
|
||||
evo.set(id3, evo.NAME, 'id3')
|
||||
evo.set(id4, evo.NAME, 'id4')
|
||||
evo.set(id5, evo.NAME, 'id5')
|
||||
|
||||
do
|
||||
local id1_n, id3_n, id5_n = evo.name(id1, id3, id5)
|
||||
assert(id1_n == 'id1')
|
||||
assert(id3_n == 'id3')
|
||||
assert(id5_n == 'id5')
|
||||
end
|
||||
|
||||
do
|
||||
local id1_n, id2_n, id3_n, id4_n, id5_n = evo.name(id1, id2, id3, id4, id5)
|
||||
assert(id1_n == 'id1')
|
||||
assert(id2_n == 'id2')
|
||||
assert(id3_n == 'id3')
|
||||
assert(id4_n == 'id4')
|
||||
assert(id5_n == 'id5')
|
||||
end
|
||||
end
|
||||
245
develop/testing/requires_fragment_tests.lua
Normal file
245
develop/testing/requires_fragment_tests.lua
Normal file
@@ -0,0 +1,245 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
evo.set(f1, evo.REQUIRES)
|
||||
evo.set(f2, evo.REQUIRES, evo.get(f1, evo.REQUIRES))
|
||||
local f1_rs = evo.get(f1, evo.REQUIRES)
|
||||
local f2_rs = evo.get(f2, evo.REQUIRES)
|
||||
assert(f1_rs and f2_rs and #f1_rs == 0 and #f2_rs == 0 and f1_rs ~= f2_rs)
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
local f3 = evo.builder():require(f1):require(f2):spawn()
|
||||
local f3_rs = evo.get(f3, evo.REQUIRES)
|
||||
assert(f3_rs and #f3_rs == 2 and f3_rs[1] == f1 and f3_rs[2] == f2)
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2 = evo.id(2)
|
||||
local f3 = evo.builder():require(f1, f2):spawn()
|
||||
local f3_rs = evo.get(f3, evo.REQUIRES)
|
||||
assert(f3_rs and #f3_rs == 2 and f3_rs[1] == f1 and f3_rs[2] == f2)
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3 = evo.id(3)
|
||||
evo.set(f1, evo.REQUIRES, { f2 })
|
||||
evo.set(f3, evo.REQUIRES, { f1, f2 })
|
||||
|
||||
do
|
||||
local e = evo.id()
|
||||
evo.set(e, f1)
|
||||
assert(evo.has(e, f2))
|
||||
assert(evo.get(e, f2) == true)
|
||||
end
|
||||
|
||||
do
|
||||
local e = evo.builder():set(f1):spawn()
|
||||
assert(evo.has(e, f2))
|
||||
assert(evo.get(e, f2) == true)
|
||||
end
|
||||
|
||||
do
|
||||
local e = evo.spawn { [f1] = true }
|
||||
assert(evo.has(e, f2))
|
||||
assert(evo.get(e, f2) == true)
|
||||
|
||||
evo.remove(e, f2)
|
||||
assert(not evo.has(e, f2))
|
||||
|
||||
local e2 = evo.clone(e)
|
||||
assert(evo.has(e2, f2))
|
||||
assert(evo.get(e2, f2) == true)
|
||||
|
||||
local e3 = evo.clone(e, { [f3] = true })
|
||||
assert(evo.has(e3, f2))
|
||||
assert(evo.get(e3, f2) == true)
|
||||
end
|
||||
|
||||
do
|
||||
local f0 = evo.id()
|
||||
local q0 = evo.builder():include(f0):spawn()
|
||||
|
||||
local e1 = evo.builder():set(f0):spawn()
|
||||
local e2 = evo.builder():set(f0):spawn()
|
||||
local e3 = evo.builder():set(f0):set(f2, false):spawn()
|
||||
|
||||
evo.batch_set(q0, f1)
|
||||
|
||||
assert(evo.has(e1, f2) and evo.get(e1, f2) == true)
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
|
||||
assert(evo.has(e3, f2) and evo.get(e3, f2) == false)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3 = evo.id(3)
|
||||
evo.set(f1, evo.REQUIRES, { f2 })
|
||||
evo.set(f2, evo.DEFAULT, 42)
|
||||
evo.set(f3, evo.REQUIRES, { f1, f2 })
|
||||
|
||||
do
|
||||
local e = evo.id()
|
||||
evo.set(e, f1)
|
||||
assert(evo.has(e, f2))
|
||||
assert(evo.get(e, f2) == 42)
|
||||
end
|
||||
|
||||
do
|
||||
local e = evo.builder():set(f1):spawn()
|
||||
assert(evo.has(e, f2))
|
||||
assert(evo.get(e, f2) == 42)
|
||||
end
|
||||
|
||||
do
|
||||
local e = evo.spawn { [f1] = true, }
|
||||
assert(evo.has(e, f2))
|
||||
assert(evo.get(e, f2) == 42)
|
||||
|
||||
evo.remove(e, f2)
|
||||
assert(not evo.has(e, f2))
|
||||
|
||||
local e2 = evo.clone(e)
|
||||
assert(evo.has(e2, f2))
|
||||
assert(evo.get(e2, f2) == 42)
|
||||
|
||||
local e3 = evo.clone(e, { [f3] = true })
|
||||
assert(evo.has(e3, f2))
|
||||
assert(evo.get(e3, f2) == 42)
|
||||
end
|
||||
|
||||
do
|
||||
local f0 = evo.id()
|
||||
local q0 = evo.builder():include(f0):spawn()
|
||||
|
||||
local e1 = evo.builder():set(f0):spawn()
|
||||
local e2 = evo.builder():set(f0):spawn()
|
||||
local e3 = evo.builder():set(f0):set(f2, 21):spawn()
|
||||
|
||||
evo.batch_set(q0, f1)
|
||||
|
||||
assert(evo.has(e1, f2) and evo.get(e1, f2) == 42)
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == 42)
|
||||
assert(evo.has(e3, f2) and evo.get(e3, f2) == 21)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3 = evo.id(3)
|
||||
evo.set(f1, evo.REQUIRES, { f2 })
|
||||
evo.set(f2, evo.REQUIRES, { f3 })
|
||||
evo.set(f3, evo.DEFAULT, 42)
|
||||
evo.set(f3, evo.REQUIRES, { f1, f2 })
|
||||
|
||||
do
|
||||
local e = evo.id()
|
||||
evo.set(e, f1)
|
||||
assert(evo.has(e, f2))
|
||||
assert(evo.get(e, f2) == true)
|
||||
assert(evo.has(e, f3))
|
||||
assert(evo.get(e, f3) == 42)
|
||||
end
|
||||
|
||||
do
|
||||
local e = evo.builder():set(f1):spawn()
|
||||
assert(evo.has(e, f2))
|
||||
assert(evo.get(e, f2) == true)
|
||||
assert(evo.has(e, f3))
|
||||
assert(evo.get(e, f3) == 42)
|
||||
end
|
||||
|
||||
do
|
||||
local e = evo.spawn { [f1] = true }
|
||||
assert(evo.has(e, f2))
|
||||
assert(evo.get(e, f2) == true)
|
||||
assert(evo.has(e, f3))
|
||||
assert(evo.get(e, f3) == 42)
|
||||
|
||||
evo.remove(e, f2, f3)
|
||||
assert(not evo.has(e, f2))
|
||||
assert(not evo.has(e, f3))
|
||||
|
||||
local e2 = evo.clone(e, { [f1] = 21 })
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 21)
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
|
||||
assert(evo.has(e2, f3) and evo.get(e2, f3) == 42)
|
||||
|
||||
local e3 = evo.clone(e, { [f3] = 21 })
|
||||
assert(evo.has(e3, f1) and evo.get(e3, f1) == true)
|
||||
assert(evo.has(e3, f2) and evo.get(e3, f2) == true)
|
||||
assert(evo.has(e3, f3) and evo.get(e3, f3) == 21)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3 = evo.id(3)
|
||||
evo.set(f1, evo.REQUIRES, { f2 })
|
||||
evo.set(f2, evo.REQUIRES, { f3 })
|
||||
evo.set(f3, evo.REQUIRES, { f1, f2, f3 })
|
||||
|
||||
do
|
||||
local e = evo.id()
|
||||
evo.set(e, f1, 42)
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == true)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) == true)
|
||||
end
|
||||
|
||||
do
|
||||
local e = evo.builder():set(f1, 42):spawn()
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == true)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) == true)
|
||||
end
|
||||
|
||||
do
|
||||
local e = evo.spawn { [f1] = 42 }
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 42)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == true)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) == true)
|
||||
|
||||
evo.remove(e, f2, f3)
|
||||
assert(not evo.has(e, f2))
|
||||
assert(not evo.has(e, f3))
|
||||
|
||||
local e2 = evo.clone(e, { [f1] = 21 })
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 21)
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == true)
|
||||
assert(evo.has(e2, f3) and evo.get(e2, f3) == true)
|
||||
|
||||
local e3 = evo.clone(e, { [f3] = 21 })
|
||||
assert(evo.has(e3, f1) and evo.get(e3, f1) == 42)
|
||||
assert(evo.has(e3, f2) and evo.get(e3, f2) == true)
|
||||
assert(evo.has(e3, f3) and evo.get(e3, f3) == 21)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1, f2, f3, f4 = evo.id(4)
|
||||
|
||||
do
|
||||
evo.set(f1, evo.REQUIRES, { f2 })
|
||||
do
|
||||
local e = evo.id()
|
||||
evo.set(e, f1)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == true)
|
||||
end
|
||||
evo.set(f1, evo.REQUIRES, { f2, f3 })
|
||||
do
|
||||
local e = evo.id()
|
||||
evo.set(e, f1)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == true)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) == true)
|
||||
end
|
||||
evo.set(f3, evo.REQUIRES, { f4 })
|
||||
do
|
||||
local e = evo.id()
|
||||
evo.set(e, f1)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == true)
|
||||
assert(evo.has(e, f3) and evo.get(e, f3) == true)
|
||||
assert(evo.has(e, f4) and evo.get(e, f4) == true)
|
||||
end
|
||||
end
|
||||
end
|
||||
128
develop/testing/system_as_query_tests.lua
Normal file
128
develop/testing/system_as_query_tests.lua
Normal file
@@ -0,0 +1,128 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
do
|
||||
local f1, f2, f3 = evo.id(3)
|
||||
|
||||
local q1e3 = evo.builder():include(f1):exclude(f3):spawn()
|
||||
local q2e3 = evo.builder():include(f2):exclude(f3):spawn()
|
||||
|
||||
local e1 = evo.builder():set(f1, 1):spawn()
|
||||
local e12 = evo.builder():set(f1, 11):set(f2, 12):spawn()
|
||||
local e2 = evo.builder():set(f2, 2):spawn()
|
||||
local e23 = evo.builder():set(f2, 23):set(f3, 3):spawn()
|
||||
|
||||
local c1 = evo.chunk(f1)
|
||||
local c12 = evo.chunk(f1, f2)
|
||||
local c2 = evo.chunk(f2)
|
||||
|
||||
do
|
||||
local _, entity_list, entity_count = evo.chunk(f2, f3)
|
||||
assert(entity_count == 1 and entity_list[1] == e23)
|
||||
end
|
||||
|
||||
do
|
||||
local entity_sum = 0
|
||||
|
||||
local s = evo.builder()
|
||||
:query(q1e3)
|
||||
:execute(function(chunk, entity_list, entity_count)
|
||||
for i = 1, entity_count do
|
||||
entity_sum = entity_sum + entity_list[i]
|
||||
end
|
||||
|
||||
if chunk == c1 then
|
||||
assert(entity_count == 1)
|
||||
assert(entity_list[1] == e1)
|
||||
elseif chunk == c12 then
|
||||
assert(entity_count == 1)
|
||||
assert(entity_list[1] == e12)
|
||||
else
|
||||
assert(false, "Unexpected chunk: " .. tostring(chunk))
|
||||
end
|
||||
end):spawn()
|
||||
|
||||
evo.process(s)
|
||||
|
||||
assert(entity_sum == e1 + e12)
|
||||
end
|
||||
|
||||
do
|
||||
local entity_sum = 0
|
||||
|
||||
local s = evo.builder()
|
||||
:query(q2e3)
|
||||
:execute(function(chunk, entity_list, entity_count)
|
||||
for i = 1, entity_count do
|
||||
entity_sum = entity_sum + entity_list[i]
|
||||
end
|
||||
|
||||
if chunk == c12 then
|
||||
assert(entity_count == 1)
|
||||
assert(entity_list[1] == e12)
|
||||
elseif chunk == c2 then
|
||||
assert(entity_count == 1)
|
||||
assert(entity_list[1] == e2)
|
||||
else
|
||||
assert(false, "Unexpected chunk: " .. tostring(chunk))
|
||||
end
|
||||
end):spawn()
|
||||
|
||||
evo.process(s)
|
||||
|
||||
assert(entity_sum == e12 + e2)
|
||||
end
|
||||
|
||||
do
|
||||
local entity_sum = 0
|
||||
|
||||
local s = evo.builder()
|
||||
:include(f1)
|
||||
:exclude(f3)
|
||||
:execute(function(chunk, entity_list, entity_count)
|
||||
for i = 1, entity_count do
|
||||
entity_sum = entity_sum + entity_list[i]
|
||||
end
|
||||
|
||||
if chunk == c1 then
|
||||
assert(entity_count == 1)
|
||||
assert(entity_list[1] == e1)
|
||||
elseif chunk == c12 then
|
||||
assert(entity_count == 1)
|
||||
assert(entity_list[1] == e12)
|
||||
else
|
||||
assert(false, "Unexpected chunk: " .. tostring(chunk))
|
||||
end
|
||||
end):spawn()
|
||||
|
||||
evo.process(s)
|
||||
|
||||
assert(entity_sum == e1 + e12)
|
||||
end
|
||||
|
||||
do
|
||||
local entity_sum = 0
|
||||
|
||||
local s = evo.builder()
|
||||
:include(f2)
|
||||
:exclude(f3)
|
||||
:execute(function(chunk, entity_list, entity_count)
|
||||
for i = 1, entity_count do
|
||||
entity_sum = entity_sum + entity_list[i]
|
||||
end
|
||||
|
||||
if chunk == c12 then
|
||||
assert(entity_count == 1)
|
||||
assert(entity_list[1] == e12)
|
||||
elseif chunk == c2 then
|
||||
assert(entity_count == 1)
|
||||
assert(entity_list[1] == e2)
|
||||
else
|
||||
assert(false, "Unexpected chunk: " .. tostring(chunk))
|
||||
end
|
||||
end):spawn()
|
||||
|
||||
evo.process(s)
|
||||
|
||||
assert(entity_sum == e12 + e2)
|
||||
end
|
||||
end
|
||||
@@ -7,6 +7,11 @@ local N = 1000
|
||||
local B = evo.builder()
|
||||
local F1, F2, F3, F4, F5 = evo.id(5)
|
||||
local Q1 = evo.builder():include(F1):spawn()
|
||||
local R1 = evo.builder():require(F1):spawn()
|
||||
local R2 = evo.builder():require(F1, F2):spawn()
|
||||
local R3 = evo.builder():require(F1, F2, F3):spawn()
|
||||
local R4 = evo.builder():require(F1, F2, F3, F4):spawn()
|
||||
local R5 = evo.builder():require(F1, F2, F3, F4, F5):spawn()
|
||||
|
||||
print '----------------------------------------'
|
||||
|
||||
@@ -610,7 +615,6 @@ basics.describe_bench(string.format('create and destroy %d entities with 5 compo
|
||||
|
||||
print '----------------------------------------'
|
||||
|
||||
|
||||
basics.describe_bench(string.format('create and destroy %d entities with 1 components / clone', N),
|
||||
---@param entities evolved.id[]
|
||||
function(entities)
|
||||
@@ -690,3 +694,167 @@ basics.describe_bench(string.format('create and destroy %d entities with 5 compo
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
print '----------------------------------------'
|
||||
|
||||
basics.describe_bench(string.format('create and destroy %d entities with 1 requires / spawn', N),
|
||||
---@param entities evolved.id[]
|
||||
function(entities)
|
||||
local spawn = evo.spawn
|
||||
|
||||
local components = { [R1] = true }
|
||||
|
||||
for i = 1, N do
|
||||
entities[i] = spawn(components)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('create and destroy %d entities with 2 requires / spawn', N),
|
||||
---@param entities evolved.id[]
|
||||
function(entities)
|
||||
local spawn = evo.spawn
|
||||
|
||||
local components = { [R2] = true }
|
||||
|
||||
for i = 1, N do
|
||||
entities[i] = spawn(components)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('create and destroy %d entities with 3 requires / spawn', N),
|
||||
---@param entities evolved.id[]
|
||||
function(entities)
|
||||
local spawn = evo.spawn
|
||||
|
||||
local components = { [R3] = true }
|
||||
|
||||
for i = 1, N do
|
||||
entities[i] = spawn(components)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('create and destroy %d entities with 4 requires / spawn', N),
|
||||
---@param entities evolved.id[]
|
||||
function(entities)
|
||||
local spawn = evo.spawn
|
||||
|
||||
local components = { [R4] = true }
|
||||
|
||||
for i = 1, N do
|
||||
entities[i] = spawn(components)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('create and destroy %d entities with 5 requires / spawn', N),
|
||||
---@param entities evolved.id[]
|
||||
function(entities)
|
||||
local spawn = evo.spawn
|
||||
|
||||
local components = { [R5] = true }
|
||||
|
||||
for i = 1, N do
|
||||
entities[i] = spawn(components)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
print '----------------------------------------'
|
||||
|
||||
basics.describe_bench(string.format('create and destroy %d entities with 1 requires / clone', N),
|
||||
---@param entities evolved.id[]
|
||||
function(entities)
|
||||
local clone = evo.clone
|
||||
|
||||
local prefab = evo.spawn({ [R1] = true })
|
||||
|
||||
for i = 1, N do
|
||||
entities[i] = clone(prefab)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('create and destroy %d entities with 2 requires / clone', N),
|
||||
---@param entities evolved.id[]
|
||||
function(entities)
|
||||
local clone = evo.clone
|
||||
|
||||
local prefab = evo.spawn({ [R2] = true })
|
||||
|
||||
for i = 1, N do
|
||||
entities[i] = clone(prefab)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('create and destroy %d entities with 3 requires / clone', N),
|
||||
---@param entities evolved.id[]
|
||||
function(entities)
|
||||
local clone = evo.clone
|
||||
|
||||
local prefab = evo.spawn({ [R3] = true })
|
||||
|
||||
for i = 1, N do
|
||||
entities[i] = clone(prefab)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('create and destroy %d entities with 4 requires / clone', N),
|
||||
---@param entities evolved.id[]
|
||||
function(entities)
|
||||
local clone = evo.clone
|
||||
|
||||
local prefab = evo.spawn({ [R4] = true })
|
||||
|
||||
for i = 1, N do
|
||||
entities[i] = clone(prefab)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
basics.describe_bench(string.format('create and destroy %d entities with 5 requires / clone', N),
|
||||
---@param entities evolved.id[]
|
||||
function(entities)
|
||||
local clone = evo.clone
|
||||
|
||||
local prefab = evo.spawn({ [R5] = true })
|
||||
|
||||
for i = 1, N do
|
||||
entities[i] = clone(prefab)
|
||||
end
|
||||
|
||||
evo.batch_destroy(Q1)
|
||||
end, function()
|
||||
return {}
|
||||
end)
|
||||
|
||||
@@ -598,29 +598,31 @@ do
|
||||
evo.set(e2b, f2, 45)
|
||||
|
||||
do
|
||||
local chunk, entities = evo.chunk(f1)
|
||||
assert(entities and entities[1] == e1)
|
||||
local chunk, entity_list, entity_count = evo.chunk(f1)
|
||||
assert(entity_list and entity_list[1] == e1)
|
||||
assert(entity_count and entity_count == 1)
|
||||
assert(chunk and chunk:components(f1)[1] == 41)
|
||||
end
|
||||
|
||||
do
|
||||
local chunk, entities = evo.chunk(f1, f2)
|
||||
local chunk, entity_list, entity_count = evo.chunk(f1, f2)
|
||||
assert(chunk == evo.chunk(f1, f2))
|
||||
assert(chunk == evo.chunk(f1, f1, f2))
|
||||
assert(chunk == evo.chunk(f1, f1, f2, f2))
|
||||
assert(chunk == evo.chunk(f1, f2, f2, f1))
|
||||
assert(chunk == evo.chunk(f2, f1))
|
||||
assert(chunk == evo.chunk(f2, f1, f2, f1))
|
||||
assert(entities and entities[1] == e2 and entities[2] == e2b)
|
||||
assert(entity_list and entity_list[1] == e2 and entity_list[2] == e2b)
|
||||
assert(entity_count and entity_count == 2)
|
||||
assert(chunk and chunk:components(f1)[1] == 42 and chunk:components(f2)[1] == 43)
|
||||
assert(chunk and chunk:components(f1)[2] == 44 and chunk:components(f2)[2] == 45)
|
||||
end
|
||||
|
||||
do
|
||||
local chunk123, entities123 = evo.chunk(f1, f2, f3)
|
||||
local chunk321, entities321 = evo.chunk(f3, f2, f1)
|
||||
assert(chunk123 and #entities123 == 0)
|
||||
assert(chunk321 and #entities321 == 0)
|
||||
local chunk123, entities123, entity123_count = evo.chunk(f1, f2, f3)
|
||||
local chunk321, entities321, entity321_count = evo.chunk(f3, f2, f1)
|
||||
assert(chunk123 and #entities123 >= 0 and entity123_count == 0)
|
||||
assert(chunk321 and #entities321 >= 0 and entity321_count == 0)
|
||||
assert(chunk123 == chunk321 and entities123 == entities321)
|
||||
end
|
||||
end
|
||||
@@ -1864,13 +1866,13 @@ do
|
||||
assert(evo.get(e3, f1) == nil and evo.get(e3, f2) == nil and evo.get(e3, f3) == 43)
|
||||
|
||||
do
|
||||
local chunk, chunk_entities = evo.chunk(f1, f2, f3)
|
||||
assert(chunk and chunk_entities)
|
||||
local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f1, f2, f3)
|
||||
assert(chunk and chunk_entity_list and chunk_entity_count == 2)
|
||||
|
||||
assert(chunk_entities[1] == e3 and chunk_entities[2] == e1)
|
||||
assert(chunk_entity_list[1] == e3 and chunk_entity_list[2] == e1)
|
||||
|
||||
assert(#chunk:components(f1) == 0)
|
||||
assert(#chunk:components(f2) == 0)
|
||||
assert(#chunk:components(f1) >= 0)
|
||||
assert(#chunk:components(f2) >= 0)
|
||||
assert(chunk:components(f3)[1] == 43 and chunk:components(f3)[2] == 50)
|
||||
end
|
||||
end
|
||||
@@ -1906,22 +1908,22 @@ do
|
||||
assert(not evo.has(e3, f1) and evo.has(e3, f2) and evo.has(e3, f3))
|
||||
|
||||
do
|
||||
local chunk, chunk_entities = evo.chunk(f2)
|
||||
assert(chunk and chunk_entities)
|
||||
local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f2)
|
||||
assert(chunk and chunk_entity_list and chunk_entity_count == 1)
|
||||
|
||||
assert(chunk_entities[1] == e1)
|
||||
assert(#chunk:components(f1) == 0)
|
||||
assert(#chunk:components(f2) == 0)
|
||||
assert(#chunk:components(f3) == 0)
|
||||
assert(chunk_entity_list[1] == e1)
|
||||
assert(#chunk:components(f1) >= 0)
|
||||
assert(#chunk:components(f2) >= 0)
|
||||
assert(#chunk:components(f3) >= 0)
|
||||
end
|
||||
|
||||
do
|
||||
local chunk, chunk_entities = evo.chunk(f2, f3)
|
||||
assert(chunk and chunk_entities)
|
||||
local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f2, f3)
|
||||
assert(chunk and chunk_entity_list and chunk_entity_count == 1)
|
||||
|
||||
assert(chunk_entities[1] == e3)
|
||||
assert(#chunk:components(f1) == 0)
|
||||
assert(#chunk:components(f2) == 0)
|
||||
assert(chunk_entity_list[1] == e3)
|
||||
assert(#chunk:components(f1) >= 0)
|
||||
assert(#chunk:components(f2) >= 0)
|
||||
assert(chunk:components(f3)[1] == 43)
|
||||
end
|
||||
end
|
||||
@@ -1961,13 +1963,13 @@ do
|
||||
assert(not evo.has(e3, f1) and not evo.has(e3, f2) and not evo.has(e3, f3))
|
||||
|
||||
do
|
||||
local chunk, chunk_entities = evo.chunk(f1, f2, f3)
|
||||
assert(chunk and chunk_entities)
|
||||
local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f1, f2, f3)
|
||||
assert(chunk and chunk_entity_list and chunk_entity_count == 0)
|
||||
|
||||
assert(next(chunk_entities) == nil)
|
||||
assert(#chunk:components(f1) == 0)
|
||||
assert(#chunk:components(f2) == 0)
|
||||
assert(#chunk:components(f3) == 0)
|
||||
assert(#chunk_entity_list >= 0)
|
||||
assert(#chunk:components(f1) >= 0)
|
||||
assert(#chunk:components(f2) >= 0)
|
||||
assert(#chunk:components(f3) >= 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2006,13 +2008,13 @@ do
|
||||
assert(not evo.has(e3, f1) and not evo.has(e3, f2) and not evo.has(e3, f3))
|
||||
|
||||
do
|
||||
local chunk, chunk_entities = evo.chunk(f1, f2, f3)
|
||||
assert(chunk and chunk_entities)
|
||||
local chunk, chunk_entity_list, chunk_entity_count = evo.chunk(f1, f2, f3)
|
||||
assert(chunk and chunk_entity_list and chunk_entity_count == 0)
|
||||
|
||||
assert(next(chunk_entities) == nil)
|
||||
assert(#chunk:components(f1) == 0)
|
||||
assert(#chunk:components(f2) == 0)
|
||||
assert(#chunk:components(f3) == 0)
|
||||
assert(#chunk_entity_list >= 0)
|
||||
assert(#chunk:components(f1) >= 0)
|
||||
assert(#chunk:components(f2) >= 0)
|
||||
assert(#chunk:components(f3) >= 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2197,13 +2199,15 @@ do
|
||||
do
|
||||
local iter, state = evo.execute(q)
|
||||
|
||||
local chunk, entities = iter(state)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(chunk == evo.chunk(f2))
|
||||
assert(entities and entities[1] == e2)
|
||||
assert(entity_list and entity_list[1] == e2)
|
||||
assert(entity_count == 1)
|
||||
|
||||
chunk, entities = iter(state)
|
||||
chunk, entity_list, entity_count = iter(state)
|
||||
assert(not chunk)
|
||||
assert(not entities)
|
||||
assert(not entity_list)
|
||||
assert(not entity_count)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2224,9 +2228,9 @@ do
|
||||
do
|
||||
local entity_sum = 0
|
||||
|
||||
for _, entities in evo.execute(q) do
|
||||
assert(#entities > 0)
|
||||
for _, e in ipairs(entities) do
|
||||
for _, entity_list, entity_count in evo.execute(q) do
|
||||
assert(entity_count > 0)
|
||||
for _, e in ipairs(entity_list) do
|
||||
entity_sum = entity_sum + e
|
||||
end
|
||||
end
|
||||
@@ -2253,30 +2257,35 @@ do
|
||||
|
||||
do
|
||||
local iter, state = evo.execute(q)
|
||||
local chunk, entities = iter(state)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(chunk == evo.chunk(f1))
|
||||
assert(entities and entities[1] == e1)
|
||||
assert(entity_list and entity_list[1] == e1)
|
||||
assert(entity_count == 1)
|
||||
|
||||
chunk, entities = iter(state)
|
||||
chunk, entity_list, entity_count = iter(state)
|
||||
assert(not chunk)
|
||||
assert(not entities)
|
||||
assert(not entity_list)
|
||||
assert(not entity_count)
|
||||
end
|
||||
|
||||
evo.set(q, evo.EXCLUDES)
|
||||
|
||||
do
|
||||
local iter, state = evo.execute(q)
|
||||
local chunk, entities = iter(state)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(chunk == evo.chunk(f1))
|
||||
assert(entities and entities[1] == e1)
|
||||
assert(entity_list and entity_list[1] == e1)
|
||||
assert(entity_count == 1)
|
||||
|
||||
chunk, entities = iter(state)
|
||||
chunk, entity_list, entity_count = iter(state)
|
||||
assert(chunk == evo.chunk(f1, f2))
|
||||
assert(entities and entities[1] == e2)
|
||||
assert(entity_list and entity_list[1] == e2)
|
||||
assert(entity_count == 1)
|
||||
|
||||
chunk, entities = iter(state)
|
||||
chunk, entity_list, entity_count = iter(state)
|
||||
assert(not chunk)
|
||||
assert(not entities)
|
||||
assert(not entity_list)
|
||||
assert(not entity_count)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2310,9 +2319,10 @@ do
|
||||
|
||||
do
|
||||
local iter, state = evo.execute(q)
|
||||
local chunk, entities = iter(state)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(chunk == evo.chunk(f1))
|
||||
assert(entities and entities[1] == e1)
|
||||
assert(entity_list and entity_list[1] == e1)
|
||||
assert(entity_count == 1)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2448,7 +2458,7 @@ do
|
||||
local function collect_entities(q)
|
||||
local entities = {}
|
||||
for _, es, es_count in evo.execute(q) do
|
||||
assert(#es == es_count)
|
||||
assert(#es >= es_count)
|
||||
for _, e in ipairs(es) do
|
||||
entities[#entities + 1] = e
|
||||
end
|
||||
@@ -2462,7 +2472,7 @@ do
|
||||
|
||||
do
|
||||
local entities = collect_entities(q1)
|
||||
assert(#entities == 3)
|
||||
assert(#entities >= 3)
|
||||
assert(entities[1] == e1)
|
||||
assert(entities[2] == e2)
|
||||
assert(entities[3] == e3)
|
||||
@@ -2470,14 +2480,14 @@ do
|
||||
|
||||
do
|
||||
local entities = collect_entities(q2)
|
||||
assert(#entities == 2)
|
||||
assert(#entities >= 2)
|
||||
assert(entities[1] == e2)
|
||||
assert(entities[2] == e3)
|
||||
end
|
||||
|
||||
do
|
||||
local entities = collect_entities(q3)
|
||||
assert(#entities == 1)
|
||||
assert(#entities >= 1)
|
||||
assert(entities[1] == e2)
|
||||
end
|
||||
end
|
||||
@@ -3246,36 +3256,36 @@ do
|
||||
local e = evo.spawn({ [f1] = 1, [f2] = 2, [f3] = 3, [f4] = 4, [f5] = 5 })
|
||||
|
||||
local c, es = evo.chunk(f1, f2, f3, f4, f5)
|
||||
assert(c and es and #es == 1 and es[1] == e)
|
||||
assert(c and es and #es >= 1 and es[1] == e)
|
||||
|
||||
do
|
||||
local c1, c2 = c:components(f1, f2)
|
||||
assert(c1 and #c1 == 1 and c1[1] == 1)
|
||||
assert(c2 and #c2 == 1 and c2[1] == 2)
|
||||
assert(c1 and #c1 >= 1 and c1[1] == 1)
|
||||
assert(c2 and #c2 >= 1 and c2[1] == 2)
|
||||
end
|
||||
|
||||
do
|
||||
local c1, c2, c3 = c:components(f1, f2, f3)
|
||||
assert(c1 and #c1 == 1 and c1[1] == 1)
|
||||
assert(c2 and #c2 == 1 and c2[1] == 2)
|
||||
assert(c3 and #c3 == 1 and c3[1] == 3)
|
||||
assert(c1 and #c1 >= 1 and c1[1] == 1)
|
||||
assert(c2 and #c2 >= 1 and c2[1] == 2)
|
||||
assert(c3 and #c3 >= 1 and c3[1] == 3)
|
||||
end
|
||||
|
||||
do
|
||||
local c1, c2, c3, c4 = c:components(f1, f2, f3, f4)
|
||||
assert(c1 and #c1 == 1 and c1[1] == 1)
|
||||
assert(c2 and #c2 == 1 and c2[1] == 2)
|
||||
assert(c3 and #c3 == 1 and c3[1] == 3)
|
||||
assert(c4 and #c4 == 1 and c4[1] == 4)
|
||||
assert(c1 and #c1 >= 1 and c1[1] == 1)
|
||||
assert(c2 and #c2 >= 1 and c2[1] == 2)
|
||||
assert(c3 and #c3 >= 1 and c3[1] == 3)
|
||||
assert(c4 and #c4 >= 1 and c4[1] == 4)
|
||||
end
|
||||
|
||||
do
|
||||
local c1, c2, c3, c4, c5 = c:components(f1, f2, f3, f4, f5)
|
||||
assert(c1 and #c1 == 1 and c1[1] == 1)
|
||||
assert(c2 and #c2 == 1 and c2[1] == 2)
|
||||
assert(c3 and #c3 == 1 and c3[1] == 3)
|
||||
assert(c4 and #c4 == 1 and c4[1] == 4)
|
||||
assert(c5 and #c5 == 1 and c5[1] == 5)
|
||||
assert(c1 and #c1 >= 1 and c1[1] == 1)
|
||||
assert(c2 and #c2 >= 1 and c2[1] == 2)
|
||||
assert(c3 and #c3 >= 1 and c3[1] == 3)
|
||||
assert(c4 and #c4 >= 1 and c4[1] == 4)
|
||||
assert(c5 and #c5 >= 1 and c5[1] == 5)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3722,7 +3732,7 @@ do
|
||||
|
||||
do
|
||||
local c1, c1_es = evo.chunk(f1)
|
||||
assert(c1 and c1_es and #c1_es == 2)
|
||||
assert(c1 and c1_es and #c1_es >= 2)
|
||||
assert(c1_es[1] == e1a and c1_es[2] == e1b)
|
||||
assert(c1:components(f1)[1] == 1 and c1:components(f1)[2] == 11)
|
||||
end
|
||||
@@ -3731,10 +3741,10 @@ do
|
||||
|
||||
do
|
||||
local c1, c1_es = evo.chunk(f1)
|
||||
assert(c1 and c1_es and #c1_es == 0)
|
||||
assert(c1 and c1_es and #c1_es >= 0)
|
||||
|
||||
local c12, c12_es = evo.chunk(f1, f2)
|
||||
assert(c12 and c12_es and #c12_es == 2)
|
||||
assert(c12 and c12_es and #c12_es >= 2)
|
||||
assert(c12_es[1] == e1a and c12_es[2] == e1b)
|
||||
assert(c12:components(f1)[1] == 1 and c12:components(f1)[2] == 11)
|
||||
assert(c12:components(f2)[1] == 2 and c12:components(f2)[2] == 2)
|
||||
@@ -3745,7 +3755,7 @@ do
|
||||
|
||||
do
|
||||
local c1, c1_es = evo.chunk(f1)
|
||||
assert(c1 and c1_es and #c1_es == 2)
|
||||
assert(c1 and c1_es and #c1_es >= 2)
|
||||
assert(c1_es[1] == e1c and c1_es[2] == e1d)
|
||||
assert(c1:components(f1)[1] == 111 and c1:components(f1)[2] == 1111)
|
||||
end
|
||||
@@ -3755,10 +3765,10 @@ do
|
||||
|
||||
do
|
||||
local c1, c1_es = evo.chunk(f1)
|
||||
assert(c1 and c1_es and #c1_es == 0)
|
||||
assert(c1 and c1_es and #c1_es >= 0)
|
||||
|
||||
local c12, c12_es = evo.chunk(f1, f2)
|
||||
assert(c12 and c12_es and #c12_es == 4)
|
||||
assert(c12 and c12_es and #c12_es >= 4)
|
||||
assert(c12_es[1] == e1a and c12_es[2] == e1b)
|
||||
assert(c12_es[3] == e1c and c12_es[4] == e1d)
|
||||
assert(c12:components(f1)[1] == 1 and c12:components(f1)[2] == 11)
|
||||
@@ -3778,7 +3788,7 @@ do
|
||||
|
||||
do
|
||||
local c123, c123_es = evo.chunk(f1, f2, f3)
|
||||
assert(c123 and c123_es and #c123_es == 2)
|
||||
assert(c123 and c123_es and #c123_es >= 2)
|
||||
assert(c123_es[1] == e123a and c123_es[2] == e123b)
|
||||
assert(c123:components(f1)[1] == 1 and c123:components(f1)[2] == 11)
|
||||
assert(c123:components(f2)[1] == 2 and c123:components(f2)[2] == 22)
|
||||
@@ -3789,7 +3799,7 @@ do
|
||||
|
||||
do
|
||||
local c13, c13_es = evo.chunk(f3, f1)
|
||||
assert(c13 and c13_es and #c13_es == 2)
|
||||
assert(c13 and c13_es and #c13_es >= 2)
|
||||
assert(c13_es[1] == e123a and c13_es[2] == e123b)
|
||||
assert(c13:components(f1)[1] == 1 and c13:components(f1)[2] == 11)
|
||||
assert(c13:components(f2)[1] == nil and c13:components(f2)[2] == nil)
|
||||
@@ -3801,7 +3811,7 @@ do
|
||||
|
||||
do
|
||||
local c3, c3_es = evo.chunk(f3)
|
||||
assert(c3 and c3_es and #c3_es == 2)
|
||||
assert(c3 and c3_es and #c3_es >= 2)
|
||||
assert(c3_es[1] == e3a and c3_es[2] == e3b)
|
||||
assert(c3:components(f3)[1] == 3 and c3:components(f3)[2] == 33)
|
||||
end
|
||||
@@ -3810,7 +3820,7 @@ do
|
||||
|
||||
do
|
||||
local c3, c3_es = evo.chunk(f3)
|
||||
assert(c3 and c3_es and #c3_es == 4)
|
||||
assert(c3 and c3_es and #c3_es >= 4)
|
||||
assert(c3_es[1] == e3a and c3_es[2] == e3b)
|
||||
assert(c3_es[3] == e123a and c3_es[4] == e123b)
|
||||
assert(c3:components(f1)[1] == nil and c3:components(f1)[2] == nil)
|
||||
@@ -3833,13 +3843,13 @@ do
|
||||
do
|
||||
local c1, c1_es, c1_ec = evo.chunk(f1)
|
||||
assert(c1 and c1_es and c1_ec)
|
||||
assert(c1_ec == 2 and #c1_es == 2 and c1_es[1] == e1a and c1_es[2] == e1b)
|
||||
assert(c1_ec == 2 and #c1_es >= 2 and c1_es[1] == e1a and c1_es[2] == e1b)
|
||||
end
|
||||
|
||||
do
|
||||
local c12, c12_es, c12_ec = evo.chunk(f1, f2)
|
||||
assert(c12 and c12_es and c12_ec)
|
||||
assert(c12_ec == 1 and #c12_es == 1 and c12_es[1] == e12)
|
||||
assert(c12_ec == 1 and #c12_es >= 1 and c12_es[1] == e12)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3897,14 +3907,14 @@ do
|
||||
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 2 and c1_ec == 2)
|
||||
assert(c1_es and #c1_es >= 2 and c1_ec == 2)
|
||||
assert(c1_es[1] == e1a and c1_es[2] == e1b)
|
||||
|
||||
local c2_es, c2_ec = c2:entities()
|
||||
assert(c2_es and #c2_es == 0 and c2_ec == 0)
|
||||
assert(c2_es and #c2_es >= 0 and c2_ec == 0)
|
||||
|
||||
local c12_es, c12_ec = c12:entities()
|
||||
assert(c12_es and #c12_es == 2 and c12_ec == 2)
|
||||
assert(c12_es and #c12_es >= 2 and c12_ec == 2)
|
||||
assert(c12_es[1] == e12a and c12_es[2] == e12b)
|
||||
end
|
||||
|
||||
@@ -3915,14 +3925,14 @@ do
|
||||
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 0 and c1_ec == 0)
|
||||
assert(c1_es and #c1_es >= 0 and c1_ec == 0)
|
||||
|
||||
local c2_es, c2_ec = c2:entities()
|
||||
assert(c2_es and #c2_es == 2 and c2_ec == 2)
|
||||
assert(c2_es and #c2_es >= 2 and c2_ec == 2)
|
||||
assert(c2_es[1] == e12a and c2_es[2] == e12b)
|
||||
|
||||
local c12_es, c12_ec = c12:entities()
|
||||
assert(c12_es and #c12_es == 2 and c12_ec == 2)
|
||||
assert(c12_es and #c12_es >= 2 and c12_ec == 2)
|
||||
assert(c12_es[1] == e1a and c12_es[2] == e1b)
|
||||
end
|
||||
end
|
||||
@@ -3938,7 +3948,7 @@ do
|
||||
assert(evo.empty(f2))
|
||||
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 0 and c1_ec == 0)
|
||||
assert(c1_es and #c1_es >= 0 and c1_ec == 0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3949,7 +3959,7 @@ do
|
||||
evo.destroy(f1)
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 0 and c1_ec == 0)
|
||||
assert(c1_es and #c1_es >= 0 and c1_ec == 0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3964,26 +3974,26 @@ do
|
||||
evo.set(f2, f2)
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 0 and c1_ec == 0)
|
||||
assert(c1_es and #c1_es >= 0 and c1_ec == 0)
|
||||
|
||||
local c2_es, c2_ec = c2:entities()
|
||||
assert(c2_es and #c2_es == 0 and c2_ec == 0)
|
||||
assert(c2_es and #c2_es >= 0 and c2_ec == 0)
|
||||
|
||||
local c12_es, c12_ec = c12:entities()
|
||||
assert(c12_es and #c12_es == 1 and c12_ec == 1)
|
||||
assert(c12_es and #c12_es >= 1 and c12_ec == 1)
|
||||
assert(c12_es[1] == f2)
|
||||
end
|
||||
evo.destroy(f1)
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 0 and c1_ec == 0)
|
||||
assert(c1_es and #c1_es >= 0 and c1_ec == 0)
|
||||
|
||||
local c2_es, c2_ec = c2:entities()
|
||||
assert(c2_es and #c2_es == 1 and c2_ec == 1)
|
||||
assert(c2_es and #c2_es >= 1 and c2_ec == 1)
|
||||
assert(c2_es[1] == f2)
|
||||
|
||||
local c12_es, c12_ec = c12:entities()
|
||||
assert(c12_es and #c12_es == 0 and c12_ec == 0)
|
||||
assert(c12_es and #c12_es >= 0 and c12_ec == 0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3998,25 +4008,25 @@ do
|
||||
evo.set(f2, f2)
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 0 and c1_ec == 0)
|
||||
assert(c1_es and #c1_es >= 0 and c1_ec == 0)
|
||||
|
||||
local c2_es, c2_ec = c2:entities()
|
||||
assert(c2_es and #c2_es == 0 and c2_ec == 0)
|
||||
assert(c2_es and #c2_es >= 0 and c2_ec == 0)
|
||||
|
||||
local c12_es, c12_ec = c12:entities()
|
||||
assert(c12_es and #c12_es == 1 and c12_ec == 1)
|
||||
assert(c12_es and #c12_es >= 1 and c12_ec == 1)
|
||||
assert(c12_es[1] == f2)
|
||||
end
|
||||
evo.destroy(f1)
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 0 and c1_ec == 0)
|
||||
assert(c1_es and #c1_es >= 0 and c1_ec == 0)
|
||||
|
||||
local c2_es, c2_ec = c2:entities()
|
||||
assert(c2_es and #c2_es == 0 and c2_ec == 0)
|
||||
assert(c2_es and #c2_es >= 0 and c2_ec == 0)
|
||||
|
||||
local c12_es, c12_ec = c12:entities()
|
||||
assert(c12_es and #c12_es == 0 and c12_ec == 0)
|
||||
assert(c12_es and #c12_es >= 0 and c12_ec == 0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4028,20 +4038,20 @@ do
|
||||
evo.set(f3, f2)
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 1 and c1_ec == 1)
|
||||
assert(c1_es and #c1_es >= 1 and c1_ec == 1)
|
||||
assert(c1_es[1] == f2)
|
||||
|
||||
local c2_es, c2_ec = c2:entities()
|
||||
assert(c2_es and #c2_es == 1 and c2_ec == 1)
|
||||
assert(c2_es and #c2_es >= 1 and c2_ec == 1)
|
||||
assert(c2_es[1] == f3)
|
||||
end
|
||||
evo.destroy(f1)
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 0 and c1_ec == 0)
|
||||
assert(c1_es and #c1_es >= 0 and c1_ec == 0)
|
||||
|
||||
local c2_es, c2_ec = c2:entities()
|
||||
assert(c2_es and #c2_es == 1 and c2_ec == 1)
|
||||
assert(c2_es and #c2_es >= 1 and c2_ec == 1)
|
||||
assert(c2_es[1] == f3)
|
||||
end
|
||||
end
|
||||
@@ -4055,20 +4065,20 @@ do
|
||||
evo.set(f3, f2)
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 1 and c1_ec == 1)
|
||||
assert(c1_es and #c1_es >= 1 and c1_ec == 1)
|
||||
assert(c1_es[1] == f2)
|
||||
|
||||
local c2_es, c2_ec = c2:entities()
|
||||
assert(c2_es and #c2_es == 1 and c2_ec == 1)
|
||||
assert(c2_es and #c2_es >= 1 and c2_ec == 1)
|
||||
assert(c2_es[1] == f3)
|
||||
end
|
||||
evo.destroy(f1)
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 0 and c1_ec == 0)
|
||||
assert(c1_es and #c1_es >= 0 and c1_ec == 0)
|
||||
|
||||
local c2_es, c2_ec = c2:entities()
|
||||
assert(c2_es and #c2_es == 1 and c2_ec == 1)
|
||||
assert(c2_es and #c2_es >= 1 and c2_ec == 1)
|
||||
assert(c2_es[1] == f3)
|
||||
end
|
||||
end
|
||||
@@ -4082,20 +4092,20 @@ do
|
||||
evo.set(f3, f2)
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 1 and c1_ec == 1)
|
||||
assert(c1_es and #c1_es >= 1 and c1_ec == 1)
|
||||
assert(c1_es[1] == f2)
|
||||
|
||||
local c2_es, c2_ec = c2:entities()
|
||||
assert(c2_es and #c2_es == 1 and c2_ec == 1)
|
||||
assert(c2_es and #c2_es >= 1 and c2_ec == 1)
|
||||
assert(c2_es[1] == f3)
|
||||
end
|
||||
evo.destroy(f1)
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 0 and c1_ec == 0)
|
||||
assert(c1_es and #c1_es >= 0 and c1_ec == 0)
|
||||
|
||||
local c2_es, c2_ec = c2:entities()
|
||||
assert(c2_es and #c2_es == 0 and c2_ec == 0)
|
||||
assert(c2_es and #c2_es >= 0 and c2_ec == 0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4122,14 +4132,14 @@ do
|
||||
|
||||
do
|
||||
local c4_es, c4_ec = c4:entities()
|
||||
assert(c4_es and #c4_es == 3 and c4_ec == 3)
|
||||
assert(c4_es and #c4_es >= 3 and c4_ec == 3)
|
||||
assert(c4_es[1] == e24 and c4_es[2] == e14 and c4_es[3] == e124)
|
||||
end
|
||||
|
||||
assert(#c14:entities() == 0)
|
||||
assert(#c24:entities() == 0)
|
||||
assert(#c124:entities() == 0)
|
||||
assert(#c234:entities() == 0)
|
||||
assert(#c14:entities() >= 0)
|
||||
assert(#c24:entities() >= 0)
|
||||
assert(#c124:entities() >= 0)
|
||||
assert(#c234:entities() >= 0)
|
||||
|
||||
assert(evo.alive(e14) and not evo.empty(e14))
|
||||
assert(evo.alive(e24) and not evo.empty(e24))
|
||||
@@ -4159,7 +4169,7 @@ do
|
||||
assert(remove_count == 1)
|
||||
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 0 and c1_ec == 0)
|
||||
assert(c1_es and #c1_es >= 0 and c1_ec == 0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4185,7 +4195,7 @@ do
|
||||
assert(remove_count == 1)
|
||||
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1_es and #c1_es == 0 and c1_ec == 0)
|
||||
assert(c1_es and #c1_es >= 0 and c1_ec == 0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4219,27 +4229,27 @@ do
|
||||
do
|
||||
local c1_es, c1_ec = c1:entities()
|
||||
assert(c1 and c1_es and c1_ec)
|
||||
assert(c1_ec == 4 and #c1_es == 4)
|
||||
assert(c1_ec == 4 and #c1_es >= 4)
|
||||
assert(c1_es[1] == e1a and c1_es[2] == e1b and c1_es[3] == e12a and c1_es[4] == e12b)
|
||||
end
|
||||
|
||||
do
|
||||
local c12_es, c12_ec = c12:entities()
|
||||
assert(c12 and c12_es and c12_ec)
|
||||
assert(c12_ec == 0 and #c12_es == 0)
|
||||
assert(c12_ec == 0 and #c12_es >= 0)
|
||||
end
|
||||
|
||||
do
|
||||
local c13_es, c13_ec = c13:entities()
|
||||
assert(c13 and c13_es and c13_ec)
|
||||
assert(c13_ec == 2 and #c13_es == 2)
|
||||
assert(c13_ec == 2 and #c13_es >= 2)
|
||||
assert(c13_es[1] == e123a and c13_es[2] == e123b)
|
||||
end
|
||||
|
||||
do
|
||||
local c123_es, c123_ec = c123:entities()
|
||||
assert(c123 and c123_es and c123_ec)
|
||||
assert(c123_ec == 0 and #c123_es == 0)
|
||||
assert(c123_ec == 0 and #c123_es >= 0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4291,7 +4301,7 @@ do
|
||||
do
|
||||
local c2, c2_es, c2_ec = evo.chunk(f2)
|
||||
assert(c2 and c2_es and c2_ec)
|
||||
assert(#c2_es == 2 and c2_ec == 2)
|
||||
assert(#c2_es >= 2 and c2_ec == 2)
|
||||
assert(c2_es[1] == e2a and c2_es[2] == e2b)
|
||||
end
|
||||
end
|
||||
@@ -4324,7 +4334,7 @@ do
|
||||
do
|
||||
local c2, c2_es, c2_ec = evo.chunk(f2)
|
||||
assert(c2 and c2_es and c2_ec)
|
||||
assert(#c2_es == 4 and c2_ec == 4)
|
||||
assert(#c2_es >= 4 and c2_ec == 4)
|
||||
assert(c2_es[1] == e2a and c2_es[2] == e2b and c2_es[3] == e12a and c2_es[4] == e12b)
|
||||
end
|
||||
end
|
||||
@@ -4349,10 +4359,10 @@ do
|
||||
|
||||
assert(c1 and c23)
|
||||
|
||||
assert(#c1:fragments() == 1)
|
||||
assert(#c1:fragments() >= 1)
|
||||
assert(c1:fragments()[1] == f1)
|
||||
|
||||
assert(#c23:fragments() == 2)
|
||||
assert(#c23:fragments() >= 2)
|
||||
assert(c23:fragments()[1] == f2)
|
||||
assert(c23:fragments()[2] == f3)
|
||||
end
|
||||
@@ -4372,20 +4382,23 @@ do
|
||||
|
||||
local iter, state = evo.execute(q1)
|
||||
|
||||
local chunk, entity_list = iter(state)
|
||||
assert(entity_list and #entity_list == 1)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(entity_list and #entity_list >= 1)
|
||||
assert(entity_count and entity_count == 1)
|
||||
assert(chunk == evo.chunk(f0, f1) and entity_list[1] == e1)
|
||||
|
||||
chunk, entity_list = iter(state)
|
||||
assert(entity_list and #entity_list == 1)
|
||||
chunk, entity_list, entity_count = iter(state)
|
||||
assert(entity_list and #entity_list >= 1)
|
||||
assert(entity_count and entity_count == 1)
|
||||
assert(chunk == evo.chunk(f0, f1, f2) and entity_list[1] == e12)
|
||||
|
||||
chunk, entity_list = iter(state)
|
||||
assert(entity_list and #entity_list == 1)
|
||||
chunk, entity_list, entity_count = iter(state)
|
||||
assert(entity_list and #entity_list >= 1)
|
||||
assert(entity_count and entity_count == 1)
|
||||
assert(chunk == evo.chunk(f0, f1, f2, f3) and entity_list[1] == e123)
|
||||
|
||||
chunk, entity_list = iter(state)
|
||||
assert(not chunk and not entity_list)
|
||||
chunk, entity_list, entity_count = iter(state)
|
||||
assert(not chunk and not entity_list and not entity_count)
|
||||
end
|
||||
|
||||
do
|
||||
@@ -4393,16 +4406,18 @@ do
|
||||
|
||||
local iter, state = evo.execute(q1)
|
||||
|
||||
local chunk, entity_list = iter(state)
|
||||
assert(entity_list and #entity_list == 1)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(entity_list and #entity_list >= 1)
|
||||
assert(entity_count and entity_count == 1)
|
||||
assert(chunk == evo.chunk(f0, f1) and entity_list[1] == e1)
|
||||
|
||||
chunk, entity_list = iter(state)
|
||||
assert(entity_list and #entity_list == 1)
|
||||
chunk, entity_list, entity_count = iter(state)
|
||||
assert(entity_list and #entity_list >= 1)
|
||||
assert(entity_count and entity_count == 1)
|
||||
assert(chunk == evo.chunk(f0, f1, f2) and entity_list[1] == e12)
|
||||
|
||||
chunk, entity_list = iter(state)
|
||||
assert(not chunk and not entity_list)
|
||||
chunk, entity_list, entity_count = iter(state)
|
||||
assert(not chunk and not entity_list and not entity_count)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4435,7 +4450,7 @@ do
|
||||
|
||||
for c, es, ec in evo.execute(qe12) do
|
||||
assert(ec > 0)
|
||||
assert(#es == ec)
|
||||
assert(#es >= ec)
|
||||
assert(c ~= c1 and c ~= c2 and c ~= c12)
|
||||
matched_chunk_count = matched_chunk_count + 1
|
||||
matched_entity_count = matched_entity_count + ec
|
||||
@@ -4453,7 +4468,7 @@ do
|
||||
|
||||
for _, es, ec in evo.execute(qe12) do
|
||||
assert(ec > 0)
|
||||
assert(#es == ec)
|
||||
assert(#es >= ec)
|
||||
matched_chunk_count = matched_chunk_count + 1
|
||||
matched_entity_count = matched_entity_count + ec
|
||||
end
|
||||
@@ -4468,7 +4483,7 @@ do
|
||||
local iter, state = evo.execute(qe12)
|
||||
local chunk, entity_list, entity_count = iter(state)
|
||||
assert(chunk == c12)
|
||||
assert(entity_list and #entity_list == 1)
|
||||
assert(entity_list and #entity_list >= 1)
|
||||
assert(entity_count and entity_count == 1)
|
||||
assert(entity_list[1] == e12)
|
||||
end
|
||||
@@ -4495,7 +4510,7 @@ do
|
||||
|
||||
local old_c1_es, old_c1_ec = old_c1:entities()
|
||||
assert(old_c1_es and old_c1_ec)
|
||||
assert(#old_c1_es == 1 and old_c1_ec == 1)
|
||||
assert(#old_c1_es >= 1 and old_c1_ec == 1)
|
||||
assert(old_c1_es[1] == e1)
|
||||
end
|
||||
|
||||
@@ -4507,7 +4522,7 @@ do
|
||||
|
||||
local new_c12_es, new_c12_ec = new_c12:entities()
|
||||
assert(new_c12_es and new_c12_ec)
|
||||
assert(#new_c12_es == 1 and new_c12_ec == 1)
|
||||
assert(#new_c12_es >= 1 and new_c12_ec == 1)
|
||||
assert(new_c12_es[1] == e12)
|
||||
end
|
||||
|
||||
@@ -6325,3 +6340,36 @@ do
|
||||
assert(not chunk and not entity_list and not entity_count)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local function v2(x, y) return { x = x or 0, y = y or 0 } end
|
||||
local function v2_clone(v) return { x = v.x, y = v.y } end
|
||||
|
||||
local v2_default = v2(1, 2)
|
||||
|
||||
do
|
||||
local f = evo.builder():default(v2_default):spawn()
|
||||
|
||||
local b = evo.builder()
|
||||
|
||||
b:set(f)
|
||||
evo.remove(f, evo.DEFAULT)
|
||||
|
||||
local e = b:spawn()
|
||||
assert(evo.has(e, f) and evo.get(e, f).x == 1 and evo.get(e, f).y == 2)
|
||||
assert(evo.get(e, f) == v2_default)
|
||||
end
|
||||
|
||||
do
|
||||
local f = evo.builder():default(v2_default):duplicate(v2_clone):spawn()
|
||||
|
||||
local b = evo.builder()
|
||||
|
||||
b:set(f)
|
||||
evo.remove(f, evo.DEFAULT, evo.DUPLICATE)
|
||||
|
||||
local e = b:spawn()
|
||||
assert(evo.has(e, f) and evo.get(e, f).x == 1 and evo.get(e, f).y == 2)
|
||||
assert(evo.get(e, f) ~= v2_default)
|
||||
end
|
||||
end
|
||||
|
||||
3391
evolved.lua
3391
evolved.lua
File diff suppressed because it is too large
Load Diff
34
rockspecs/evolved.lua-1.1.0-0.rockspec
Normal file
34
rockspecs/evolved.lua-1.1.0-0.rockspec
Normal file
@@ -0,0 +1,34 @@
|
||||
rockspec_format = "3.0"
|
||||
package = "evolved.lua"
|
||||
version = "1.1.0-0"
|
||||
source = {
|
||||
url = "git://github.com/BlackMATov/evolved.lua",
|
||||
tag = "v1.1.0",
|
||||
}
|
||||
description = {
|
||||
homepage = "https://github.com/BlackMATov/evolved.lua",
|
||||
summary = "Evolved ECS (Entity-Component-System) for Lua",
|
||||
detailed = [[
|
||||
`evolved.lua` is a fast and flexible ECS (Entity-Component-System) library for Lua.
|
||||
It is designed to be simple and easy to use, while providing all the features needed to create complex systems with blazing performance.
|
||||
]],
|
||||
license = "MIT",
|
||||
labels = {
|
||||
"ecs",
|
||||
"entity",
|
||||
"entities",
|
||||
"component",
|
||||
"components",
|
||||
"entity-component",
|
||||
"entity-component-system",
|
||||
},
|
||||
}
|
||||
dependencies = {
|
||||
"lua >= 5.1",
|
||||
}
|
||||
build = {
|
||||
type = "builtin",
|
||||
modules = {
|
||||
evolved = "evolved.lua",
|
||||
}
|
||||
}
|
||||
34
rockspecs/evolved.lua-1.2.0-0.rockspec
Normal file
34
rockspecs/evolved.lua-1.2.0-0.rockspec
Normal file
@@ -0,0 +1,34 @@
|
||||
rockspec_format = "3.0"
|
||||
package = "evolved.lua"
|
||||
version = "1.2.0-0"
|
||||
source = {
|
||||
url = "git://github.com/BlackMATov/evolved.lua",
|
||||
tag = "v1.2.0",
|
||||
}
|
||||
description = {
|
||||
homepage = "https://github.com/BlackMATov/evolved.lua",
|
||||
summary = "Evolved ECS (Entity-Component-System) for Lua",
|
||||
detailed = [[
|
||||
`evolved.lua` is a fast and flexible ECS (Entity-Component-System) library for Lua.
|
||||
It is designed to be simple and easy to use, while providing all the features needed to create complex systems with blazing performance.
|
||||
]],
|
||||
license = "MIT",
|
||||
labels = {
|
||||
"ecs",
|
||||
"entity",
|
||||
"entities",
|
||||
"component",
|
||||
"components",
|
||||
"entity-component",
|
||||
"entity-component-system",
|
||||
},
|
||||
}
|
||||
dependencies = {
|
||||
"lua >= 5.1",
|
||||
}
|
||||
build = {
|
||||
type = "builtin",
|
||||
modules = {
|
||||
evolved = "evolved.lua",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user