mirror of
https://github.com/BlackMATov/evolved.lua.git
synced 2025-12-13 19:48:00 +07:00
Compare commits
2 Commits
dev
...
feature/pa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffb0e37b7a | ||
|
|
a63b0d4400 |
143
README.md
143
README.md
@@ -53,7 +53,8 @@
|
||||
- [Cheat Sheet](#cheat-sheet)
|
||||
- [Aliases](#aliases)
|
||||
- [Predefs](#predefs)
|
||||
- [Functions](#functions)
|
||||
- [Core Functions](#core-functions)
|
||||
- [Relation Functions](#relation-functions)
|
||||
- [Classes](#classes)
|
||||
- [Chunk](#chunk)
|
||||
- [Builder](#builder)
|
||||
@@ -156,6 +157,7 @@ function evolved.pack(index, version) end
|
||||
---@param id evolved.id
|
||||
---@return integer primary
|
||||
---@return integer secondary
|
||||
---@return integer options
|
||||
---@nodiscard
|
||||
function evolved.unpack(id) end
|
||||
```
|
||||
@@ -1024,6 +1026,7 @@ assert(not evolved.alive(entity))
|
||||
|
||||
```
|
||||
id :: implementation-specific
|
||||
pair :: id
|
||||
|
||||
entity :: id
|
||||
fragment :: id
|
||||
@@ -1047,14 +1050,20 @@ remove_hook :: {entity, fragment, component}
|
||||
|
||||
each_state :: implementation-specific
|
||||
execute_state :: implementation-specific
|
||||
primaries_state :: implementation-specific
|
||||
secondaries_state :: implementation-specific
|
||||
|
||||
each_iterator :: {each_state? -> fragment?, component?}
|
||||
execute_iterator :: {execute_state? -> chunk?, entity[]?, integer?}
|
||||
primaries_iterator :: {primaries_state? -> fragment?, component?}
|
||||
secondaries_iterator :: {secondaries_state? -> fragment?, component?}
|
||||
```
|
||||
|
||||
### Predefs
|
||||
|
||||
```
|
||||
ANY :: fragment
|
||||
|
||||
TAG :: fragment
|
||||
NAME :: fragment
|
||||
|
||||
@@ -1090,7 +1099,7 @@ DESTRUCTION_POLICY_DESTROY_ENTITY :: id
|
||||
DESTRUCTION_POLICY_REMOVE_FRAGMENT :: id
|
||||
```
|
||||
|
||||
### Functions
|
||||
### Core Functions
|
||||
|
||||
```
|
||||
id :: integer? -> id...
|
||||
@@ -1138,6 +1147,25 @@ debug_mode :: boolean -> ()
|
||||
collect_garbage :: ()
|
||||
```
|
||||
|
||||
### Relation Functions
|
||||
|
||||
```
|
||||
pair :: id, id -> pair
|
||||
unpair :: pair -> id, id
|
||||
|
||||
is_pair :: id -> boolean
|
||||
is_wildcard :: id -> boolean
|
||||
|
||||
primary :: entity, fragment, integer? -> fragment?, component?
|
||||
secondary :: entity, fragment, integer? -> fragment?, component?
|
||||
|
||||
primaries :: entity, fragment -> {primaries_state? -> fragment?, component?}, primaries_state?
|
||||
secondaries :: entity, fragment -> {secondaries_state? -> fragment?, component?}, secondaries_state?
|
||||
|
||||
primary_count :: entity, fragment -> integer
|
||||
secondary_count :: entity, fragment -> integer
|
||||
```
|
||||
|
||||
### Classes
|
||||
|
||||
#### Chunk
|
||||
@@ -1232,6 +1260,8 @@ builder_mt:destruction_policy :: id -> builder
|
||||
|
||||
## Predefs
|
||||
|
||||
### `evolved.ANY`
|
||||
|
||||
### `evolved.TAG`
|
||||
|
||||
### `evolved.NAME`
|
||||
@@ -1280,7 +1310,7 @@ builder_mt:destruction_policy :: id -> builder
|
||||
|
||||
### `evolved.DESTRUCTION_POLICY_REMOVE_FRAGMENT`
|
||||
|
||||
## Functions
|
||||
## Core Functions
|
||||
|
||||
### `evolved.id`
|
||||
|
||||
@@ -1316,6 +1346,7 @@ function evolved.pack(index, version) end
|
||||
---@param id evolved.id
|
||||
---@return integer primary
|
||||
---@return integer secondary
|
||||
---@return integer options
|
||||
---@nodiscard
|
||||
function evolved.unpack(id) end
|
||||
```
|
||||
@@ -1547,6 +1578,112 @@ function evolved.debug_mode(yesno) end
|
||||
function evolved.collect_garbage() end
|
||||
```
|
||||
|
||||
## Relation Functions
|
||||
|
||||
### `evolved.pair`
|
||||
|
||||
```lua
|
||||
---@param primary evolved.id
|
||||
---@param secondary evolved.id
|
||||
---@return evolved.pair pair
|
||||
---@nodiscard
|
||||
function evolved.pair(primary, secondary) end
|
||||
```
|
||||
|
||||
### `evolved.unpair`
|
||||
|
||||
```lua
|
||||
---@param pair evolved.pair
|
||||
---@return evolved.id primary
|
||||
---@return evolved.id secondary
|
||||
---@nodiscard
|
||||
function evolved.unpair(pair) end
|
||||
```
|
||||
|
||||
### `evolved.is_pair`
|
||||
|
||||
```lua
|
||||
---@param id evolved.id
|
||||
---@return boolean
|
||||
---@nodiscard
|
||||
function evolved.is_pair(id) end
|
||||
```
|
||||
|
||||
### `evolved.is_wildcard`
|
||||
|
||||
```lua
|
||||
---@param id evolved.id
|
||||
---@return boolean
|
||||
---@nodiscard
|
||||
function evolved.is_wildcard(id) end
|
||||
```
|
||||
|
||||
### `evolved.primary`
|
||||
|
||||
```lua
|
||||
---@param entity evolved.entity
|
||||
---@param secondary evolved.fragment
|
||||
---@param index? integer
|
||||
---@return evolved.fragment? primary
|
||||
---@return evolved.component? component
|
||||
---@nodiscard
|
||||
function evolved.primary(entity, secondary, index) end
|
||||
```
|
||||
|
||||
### `evolved.secondary`
|
||||
|
||||
```lua
|
||||
---@param entity evolved.entity
|
||||
---@param primary evolved.fragment
|
||||
---@param index? integer
|
||||
---@return evolved.fragment? secondary
|
||||
---@return evolved.component? component
|
||||
---@nodiscard
|
||||
function evolved.secondary(entity, primary, index) end
|
||||
```
|
||||
|
||||
### `evolved.primaries`
|
||||
|
||||
```lua
|
||||
---@param entity evolved.entity
|
||||
---@param secondary evolved.fragment
|
||||
---@return evolved.primaries_iterator iterator
|
||||
---@return evolved.primaries_state? iterator_state
|
||||
---@nodiscard
|
||||
function evolved.primaries(entity, secondary) end
|
||||
```
|
||||
|
||||
### `evolved.secondaries`
|
||||
|
||||
```lua
|
||||
---@param entity evolved.entity
|
||||
---@param primary evolved.fragment
|
||||
---@return evolved.secondaries_iterator iterator
|
||||
---@return evolved.secondaries_state? iterator_state
|
||||
---@nodiscard
|
||||
function evolved.secondaries(entity, primary) end
|
||||
```
|
||||
|
||||
### `evolved.primary_count`
|
||||
|
||||
```lua
|
||||
---@param entity evolved.entity
|
||||
---@param secondary evolved.fragment
|
||||
---@return integer
|
||||
---@nodiscard
|
||||
function evolved.primary_count(entity, secondary) end
|
||||
```
|
||||
|
||||
### `evolved.secondary_count`
|
||||
|
||||
```lua
|
||||
---@param entity evolved.entity
|
||||
---@param primary evolved.fragment
|
||||
---@return integer
|
||||
---@nodiscard
|
||||
function evolved.secondary_count(entity, primary) end
|
||||
```
|
||||
|
||||
## Classes
|
||||
|
||||
### Chunk
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
- add INDEX fragment trait
|
||||
- use compact prefix-tree for chunks
|
||||
- optional ffi component storages
|
||||
- add EXCLUSIVE fragment trait
|
||||
|
||||
## Thoughts
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
require 'develop.samples.relations'
|
||||
require 'develop.samples.systems'
|
||||
|
||||
require 'develop.testing.name_tests'
|
||||
require 'develop.testing.pairs_tests'
|
||||
require 'develop.testing.requires_fragment_tests'
|
||||
require 'develop.testing.system_as_query_tests'
|
||||
|
||||
@@ -23,3 +25,5 @@ print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.requires_fuzz'
|
||||
print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.unique_fuzz'
|
||||
print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.wildcard_fuzz'
|
||||
|
||||
@@ -13,8 +13,9 @@ for _ = 1, 1000 do
|
||||
local initial_secondary = math.random(1, 2 ^ 20 - 1)
|
||||
|
||||
local packed_id = evo.pack(initial_primary, initial_secondary)
|
||||
local unpacked_primary, unpacked_secondary = evo.unpack(packed_id)
|
||||
local unpacked_primary, unpacked_secondary, unpacked_options = evo.unpack(packed_id)
|
||||
|
||||
assert(initial_primary == unpacked_primary)
|
||||
assert(initial_secondary == unpacked_secondary)
|
||||
assert(0 == unpacked_options)
|
||||
end
|
||||
|
||||
275
develop/fuzzing/wildcard_fuzz.lua
Normal file
275
develop/fuzzing/wildcard_fuzz.lua
Normal file
@@ -0,0 +1,275 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
evo.debug_mode(true)
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
local __table_unpack = (function()
|
||||
---@diagnostic disable-next-line: deprecated
|
||||
return table.unpack or unpack
|
||||
end)()
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
local all_entity_list = {} ---@type evolved.entity[]
|
||||
local all_fragment_list = {} ---@type evolved.fragment[]
|
||||
|
||||
for i = 1, math.random(1, 5) do
|
||||
local fragment_builder = evo.builder()
|
||||
|
||||
if math.random(1, 3) == 1 then
|
||||
fragment_builder:explicit()
|
||||
end
|
||||
|
||||
if math.random(1, 3) == 1 then
|
||||
if math.random(1, 2) == 1 then
|
||||
fragment_builder:destruction_policy(evo.DESTRUCTION_POLICY_DESTROY_ENTITY)
|
||||
else
|
||||
fragment_builder:destruction_policy(evo.DESTRUCTION_POLICY_REMOVE_FRAGMENT)
|
||||
end
|
||||
end
|
||||
|
||||
all_fragment_list[i] = fragment_builder:spawn()
|
||||
end
|
||||
|
||||
for i = 1, math.random(50, 100) do
|
||||
local entity_builder = evo.builder()
|
||||
|
||||
for _ = 0, math.random(0, #all_fragment_list) do
|
||||
if math.random(1, 2) == 1 then
|
||||
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
entity_builder:set(fragment)
|
||||
else
|
||||
local primary = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
local secondary = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
entity_builder:set(evo.pair(primary, secondary))
|
||||
end
|
||||
end
|
||||
|
||||
all_entity_list[i] = entity_builder:spawn()
|
||||
end
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
for _ = 1, math.random(1, 100) do
|
||||
local query_builder = evo.builder()
|
||||
|
||||
local query_include_set = {} ---@type table<evolved.fragment, integer>
|
||||
local query_include_list = {} ---@type evolved.entity[]
|
||||
local query_include_count = 0 ---@type integer
|
||||
|
||||
local query_exclude_set = {} ---@type table<evolved.fragment, integer>
|
||||
local query_exclude_list = {} ---@type evolved.entity[]
|
||||
local query_exclude_count = 0 ---@type integer
|
||||
|
||||
for _ = 1, math.random(0, 2) do
|
||||
if math.random(1, 2) == 1 then
|
||||
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
|
||||
query_builder:include(fragment)
|
||||
|
||||
if not query_include_set[fragment] then
|
||||
query_include_count = query_include_count + 1
|
||||
query_include_set[fragment] = query_include_count
|
||||
query_include_list[query_include_count] = fragment
|
||||
end
|
||||
else
|
||||
local primary = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
local secondary = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
|
||||
if math.random(1, 3) == 1 then
|
||||
primary = evo.ANY
|
||||
end
|
||||
|
||||
if math.random(1, 3) == 1 then
|
||||
secondary = evo.ANY
|
||||
end
|
||||
|
||||
local pair = evo.pair(primary, secondary)
|
||||
|
||||
query_builder:include(pair)
|
||||
|
||||
if not query_include_set[pair] then
|
||||
query_include_count = query_include_count + 1
|
||||
query_include_set[pair] = query_include_count
|
||||
query_include_list[query_include_count] = pair
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _ = 1, math.random(0, 2) do
|
||||
if math.random(1, 2) == 1 then
|
||||
local fragment = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
|
||||
query_builder:exclude(fragment)
|
||||
|
||||
if not query_exclude_set[fragment] then
|
||||
query_exclude_count = query_exclude_count + 1
|
||||
query_exclude_set[fragment] = query_exclude_count
|
||||
query_exclude_list[query_exclude_count] = fragment
|
||||
end
|
||||
else
|
||||
local primary = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
local secondary = all_fragment_list[math.random(1, #all_fragment_list)]
|
||||
|
||||
if math.random(1, 3) == 1 then
|
||||
primary = evo.ANY
|
||||
end
|
||||
|
||||
if math.random(1, 3) == 1 then
|
||||
secondary = evo.ANY
|
||||
end
|
||||
|
||||
local pair = evo.pair(primary, secondary)
|
||||
|
||||
query_builder:exclude(pair)
|
||||
|
||||
if not query_exclude_set[pair] then
|
||||
query_exclude_count = query_exclude_count + 1
|
||||
query_exclude_set[pair] = query_exclude_count
|
||||
query_exclude_list[query_exclude_count] = pair
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local query_entity_set = {} ---@type table<evolved.entity, integer>
|
||||
local query_entity_count = 0 ---@type integer
|
||||
|
||||
do
|
||||
local query = query_builder:spawn()
|
||||
|
||||
for chunk, entity_list, entity_count in evo.execute(query) do
|
||||
if not chunk:has(evo.INTERNAL) then
|
||||
for i = 1, entity_count do
|
||||
local entity = entity_list[i]
|
||||
assert(not query_entity_set[entity])
|
||||
query_entity_count = query_entity_count + 1
|
||||
query_entity_set[entity] = query_entity_count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if query_entity_set[query] then
|
||||
query_entity_set[query] = nil
|
||||
query_entity_count = query_entity_count - 1
|
||||
end
|
||||
|
||||
evo.destroy(query)
|
||||
end
|
||||
|
||||
do
|
||||
local expected_entity_count = 0
|
||||
|
||||
for _, entity in ipairs(all_entity_list) do
|
||||
local is_entity_expected =
|
||||
not evo.empty(entity) and
|
||||
evo.has_all(entity, __table_unpack(query_include_list)) and
|
||||
not evo.has_any(entity, __table_unpack(query_exclude_list))
|
||||
|
||||
for fragment in evo.each(entity) do
|
||||
local is_fragment_explicit = false
|
||||
|
||||
if not is_fragment_explicit and evo.is_pair(fragment) then
|
||||
is_fragment_explicit = evo.has(evo.unpair(fragment), evo.EXPLICIT)
|
||||
end
|
||||
|
||||
if not is_fragment_explicit and not evo.is_pair(fragment) then
|
||||
is_fragment_explicit = evo.has(fragment, evo.EXPLICIT)
|
||||
end
|
||||
|
||||
if is_fragment_explicit then
|
||||
local is_fragment_included = false
|
||||
|
||||
if not is_fragment_included then
|
||||
is_fragment_included = query_include_set[fragment] ~= nil
|
||||
end
|
||||
|
||||
if not is_fragment_included and evo.is_pair(fragment) then
|
||||
local fragment_primary = evo.unpair(fragment)
|
||||
is_fragment_included = query_include_set[evo.pair(fragment_primary, evo.ANY)] ~= nil
|
||||
end
|
||||
|
||||
if not is_fragment_included and not evo.is_pair(fragment) then
|
||||
is_fragment_included = query_include_set[evo.pair(fragment, evo.ANY)] ~= nil
|
||||
end
|
||||
|
||||
if not is_fragment_included then
|
||||
is_entity_expected = false
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if is_entity_expected then
|
||||
assert(query_entity_set[entity])
|
||||
expected_entity_count = expected_entity_count + 1
|
||||
else
|
||||
assert(not query_entity_set[entity])
|
||||
end
|
||||
end
|
||||
|
||||
for _, entity in ipairs(all_fragment_list) do
|
||||
local is_entity_expected =
|
||||
not evo.empty(entity) and
|
||||
evo.has_all(entity, __table_unpack(query_include_list)) and
|
||||
not evo.has_any(entity, __table_unpack(query_exclude_list))
|
||||
|
||||
for fragment in evo.each(entity) do
|
||||
if evo.has(fragment, evo.EXPLICIT) then
|
||||
is_entity_expected = is_entity_expected and
|
||||
(query_include_set[fragment] ~= nil) or
|
||||
(evo.is_pair(fragment) and query_include_set[evo.pair(fragment, evo.ANY)] ~= nil)
|
||||
end
|
||||
end
|
||||
|
||||
if is_entity_expected then
|
||||
assert(query_entity_set[entity])
|
||||
expected_entity_count = expected_entity_count + 1
|
||||
else
|
||||
assert(not query_entity_set[entity])
|
||||
end
|
||||
end
|
||||
|
||||
assert(query_entity_count == expected_entity_count)
|
||||
end
|
||||
end
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
---
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.destroy(__table_unpack(all_entity_list))
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
evo.destroy(__table_unpack(all_fragment_list))
|
||||
else
|
||||
evo.destroy(__table_unpack(all_fragment_list))
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
evo.destroy(__table_unpack(all_entity_list))
|
||||
end
|
||||
|
||||
if math.random(1, 2) == 1 then
|
||||
evo.collect_garbage()
|
||||
end
|
||||
79
develop/samples/relations.lua
Normal file
79
develop/samples/relations.lua
Normal file
@@ -0,0 +1,79 @@
|
||||
---@diagnostic disable: unused-local
|
||||
|
||||
local evo = require 'evolved'
|
||||
|
||||
evo.debug_mode(true)
|
||||
|
||||
local fragments = {
|
||||
planet = evo.builder()
|
||||
:name('planet')
|
||||
:tag()
|
||||
:spawn(),
|
||||
spaceship = evo.builder()
|
||||
:name('spaceship')
|
||||
:tag()
|
||||
:spawn(),
|
||||
}
|
||||
|
||||
local relations = {
|
||||
docked_to = evo.builder()
|
||||
:name('docked_to')
|
||||
:tag()
|
||||
:spawn(),
|
||||
}
|
||||
|
||||
local planets = {
|
||||
mars = evo.builder()
|
||||
:name('Mars')
|
||||
:set(fragments.planet)
|
||||
:spawn(),
|
||||
venus = evo.builder()
|
||||
:name('Venus')
|
||||
:set(fragments.planet)
|
||||
:spawn(),
|
||||
}
|
||||
|
||||
local spaceships = {
|
||||
falcon = evo.builder()
|
||||
:name('Millennium Falcon')
|
||||
:set(fragments.spaceship)
|
||||
:set(evo.pair(relations.docked_to, planets.mars))
|
||||
:spawn(),
|
||||
enterprise = evo.builder()
|
||||
:name('USS Enterprise')
|
||||
:set(fragments.spaceship)
|
||||
:set(evo.pair(relations.docked_to, planets.venus))
|
||||
:spawn(),
|
||||
}
|
||||
|
||||
local queries = {
|
||||
all_docked_spaceships = evo.builder()
|
||||
:include(fragments.spaceship)
|
||||
:include(evo.pair(relations.docked_to, evo.ANY))
|
||||
:spawn(),
|
||||
docked_spaceships_to_mars = evo.builder()
|
||||
:include(fragments.spaceship)
|
||||
:include(evo.pair(relations.docked_to, planets.mars))
|
||||
:spawn(),
|
||||
|
||||
}
|
||||
|
||||
print '-= | All Docked Spaceships | =-'
|
||||
|
||||
for chunk, entity_list, entity_count in evo.execute(queries.all_docked_spaceships) do
|
||||
for i = 1, entity_count do
|
||||
local entity = entity_list[i]
|
||||
local planet = evo.secondary(entity, relations.docked_to)
|
||||
print(string.format('%s is docked to %s', evo.name(entity), evo.name(planet)))
|
||||
end
|
||||
end
|
||||
|
||||
print '-= | Docked Spaceships to Mars | =-'
|
||||
|
||||
for chunk, entity_list, entity_count in evo.execute(queries.docked_spaceships_to_mars) do
|
||||
for i = 1, entity_count do
|
||||
local entity = entity_list[i]
|
||||
local planet = evo.secondary(entity, relations.docked_to)
|
||||
print(string.format('%s is docked to %s', evo.name(entity), evo.name(planet)))
|
||||
end
|
||||
end
|
||||
@@ -3,8 +3,8 @@ 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))
|
||||
local index, version, options = evo.unpack(id)
|
||||
assert(evo.name(id) == string.format('$%d#%d:%d:%d', id, index, version, options))
|
||||
|
||||
evo.set(id, evo.NAME, 'hello')
|
||||
assert(evo.name(id) == 'hello')
|
||||
@@ -13,7 +13,7 @@ do
|
||||
assert(evo.name(id) == 'world')
|
||||
|
||||
evo.destroy(id)
|
||||
assert(evo.name(id) == string.format('$%d#%d:%d', id, index, version))
|
||||
assert(evo.name(id) == string.format('$%d#%d:%d:%d', id, index, version, options))
|
||||
end
|
||||
|
||||
do
|
||||
|
||||
1921
develop/testing/pairs_tests.lua
Normal file
1921
develop/testing/pairs_tests.lua
Normal file
File diff suppressed because it is too large
Load Diff
1964
evolved.lua
1964
evolved.lua
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user