additional oop-like api

This commit is contained in:
BlackMATov
2024-11-23 11:46:14 +07:00
parent 390bbd4f3b
commit e6de3def34
7 changed files with 187 additions and 106 deletions

View File

@@ -1,8 +1,6 @@
# evolved.lua
## API Reference
### Module `idpools`
## Module `idpools`
```
idpools.idpool -> (idpool)
@@ -13,7 +11,17 @@ idpools.release -> idpool -> id -> ()
idpools.is_alive -> idpool -> id -> (boolean)
```
### Module `registry`
### Instance `idpool`
```
idpool.pack -> integer -> integer -> (id)
idpool.unpack -> id -> (integer, integer)
idpool:acquire -> (id)
idpool:release -> id -> ()
idpool:is_alive -> id -> (boolean)
```
## Module `registry`
```
registry.entity -> (entity)
@@ -30,11 +38,39 @@ registry.remove -> entity -> entity -> ()
registry.query -> entity -> entity... -> (query)
registry.execute -> query -> (() -> (chunk?))
registry.chunk -> entity -> entity... -> (chunk)
registry.chunk_entities -> chunk -> entity -> (entity[])
registry.chunk_components -> chunk -> entity -> (any[])
registry.entities -> chunk -> entity -> (entity[])
registry.components -> chunk -> entity -> (any[])
```
### Module `singles`
### Instance `entity`
```
enity:is_alive -> (boolean)
enity:destroy -> ()
enity:get -> entity -> (any)
enity:get_or -> entity -> any -> (any)
enity:has -> entity -> (boolean)
enity:has_all -> entity -> entity... -> (boolean)
enity:has_any -> entity -> entity... -> (boolean)
enity:assign -> entity -> any -> ()
enity:insert -> entity -> any -> ()
enity:remove -> entity -> ()
```
### Instance `query`
```
query:execute -> (() -> (chunk?))
```
### Instance `chunk`
```
chunk:entities -> entity -> (entity[])
chunk:components -> entity -> (any[])
```
## Module `singles`
```
singles.single -> any -> (entity)
@@ -43,7 +79,7 @@ singles.has -> entity -> (boolean)
singles.assign -> entity -> any -> ()
```
### Module `vectors`
## Module `vectors`
```
vectors.vector2 -> number -> number -> (vector2)

View File

@@ -2,7 +2,8 @@
## Backlog
- [ ] add oop-like api for entities and queries
- [x] add additional oop-like api
- [ ] add fluent interface for oop-like api
- [ ] cache matched chunks in queries
- [ ] cache transitions between chunks
- [ ] chunk's children should be sorted by id and stored in an array instead of a table

View File

@@ -17,19 +17,17 @@ local queries = {
do
local entity = evo.registry.entity()
local position = evo.vectors.vector2(512, 50)
local velocity = evo.vectors.vector2(math.random(-20, 20), 20)
evo.registry.insert(entity, fragments.position, position)
evo.registry.insert(entity, fragments.velocity, velocity)
entity:insert(fragments.position, evo.vectors.vector2(512, 50))
entity:insert(fragments.velocity, evo.vectors.vector2(math.random(-20, 20), 20))
end
do
local dt = evo.singles.get(singles.delta_time)
for chunk in evo.registry.execute(queries.bodies) do
local es = evo.registry.chunk_entities(chunk)
local ps = evo.registry.chunk_components(chunk, fragments.position)
local vs = evo.registry.chunk_components(chunk, fragments.velocity)
for chunk in queries.bodies:execute() do
local es = chunk:entities()
local ps = chunk:components(fragments.position)
local vs = chunk:components(fragments.velocity)
for i = 1, #es do
ps[i] = ps[i] + vs[i] * dt

View File

@@ -10,19 +10,19 @@ end
do
local p = evo.idpools.idpool()
local i1_1 = evo.idpools.acquire(p)
local i1_1 = p:acquire()
assert(i1_1 == 0x100001)
local i2_1 = evo.idpools.acquire(p)
local i2_1 = p:acquire()
assert(i2_1 == 0x100002)
do
local i, v = evo.idpools.unpack(i1_1)
local i, v = p.unpack(i1_1)
assert(i == 1 and v == 1)
end
do
local i, v = evo.idpools.unpack(i2_1)
local i, v = p.unpack(i2_1)
assert(i == 2 and v == 1)
end
end
@@ -30,39 +30,39 @@ end
do
local p = evo.idpools.idpool()
local i1_1 = evo.idpools.acquire(p)
local i2_1 = evo.idpools.acquire(p)
assert(evo.idpools.is_alive(p, i1_1))
assert(evo.idpools.is_alive(p, i2_1))
local i1_1 = p:acquire()
local i2_1 = p:acquire()
assert(p:is_alive(i1_1))
assert(p:is_alive(i2_1))
evo.idpools.release(p, i1_1)
assert(not evo.idpools.is_alive(p, i1_1))
assert(evo.idpools.is_alive(p, i2_1))
p:release(i1_1)
assert(not p:is_alive(i1_1))
assert(p:is_alive(i2_1))
evo.idpools.release(p, i2_1)
assert(not evo.idpools.is_alive(p, i1_1))
assert(not evo.idpools.is_alive(p, i2_1))
p:release(i2_1)
assert(not p:is_alive(i1_1))
assert(not p:is_alive(i2_1))
local i2_2 = evo.idpools.acquire(p)
local i2_2 = p:acquire()
assert(i2_2 == 0x200002)
local i1_2 = evo.idpools.acquire(p)
local i1_2 = p:acquire()
assert(i1_2 == 0x200001)
assert(not evo.idpools.is_alive(p, i1_1))
assert(not evo.idpools.is_alive(p, i2_1))
assert(evo.idpools.is_alive(p, i1_2))
assert(evo.idpools.is_alive(p, i2_2))
assert(not p:is_alive(i1_1))
assert(not p:is_alive(i2_1))
assert(p:is_alive(i1_2))
assert(p:is_alive(i2_2))
end
do
local p = evo.idpools.idpool()
for _ = 1, 0xFFFFF - 1 do
_ = evo.idpools.acquire(p)
_ = p:acquire()
end
assert(evo.idpools.acquire(p) == 0x1FFFFF)
assert(p:acquire() == 0x1FFFFF)
if not os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") then
assert(not pcall(evo.idpools.acquire, p))
@@ -73,16 +73,16 @@ do
local p = evo.idpools.idpool()
for _ = 1, 0x7FF - 1 do
evo.idpools.release(p, evo.idpools.acquire(p))
p:release(p:acquire())
end
local i1_7FF = evo.idpools.acquire(p)
local i1_7FF = p:acquire()
assert(i1_7FF == 0x7FF00001)
evo.idpools.release(p, i1_7FF)
p:release(i1_7FF)
local i1_1 = evo.idpools.acquire(p)
local i1_1 = p:acquire()
assert(i1_1 == 0x100001)
evo.idpools.release(p, i1_1)
p:release(i1_1)
end
for _ = 1, 100 do

View File

@@ -7,21 +7,21 @@ do
local e = evo.registry.entity()
assert(e.__chunk == nil)
evo.registry.insert(e, f1)
assert(evo.registry.has(e, f1))
assert(not evo.registry.has(e, f2))
e:insert(f1)
assert(e:has(f1))
assert(not e:has(f2))
evo.registry.insert(e, f2)
assert(evo.registry.has(e, f1))
assert(evo.registry.has(e, f2))
e:insert(f2)
assert(e:has(f1))
assert(e:has(f2))
evo.registry.remove(e, f1)
assert(not evo.registry.has(e, f1))
assert(evo.registry.has(e, f2))
e:remove(f1)
assert(not e:has(f1))
assert(e:has(f2))
evo.registry.remove(e, f2)
assert(not evo.registry.has(e, f1))
assert(not evo.registry.has(e, f2))
e:remove(f2)
assert(not e:has(f1))
assert(not e:has(f2))
end
do
@@ -29,28 +29,28 @@ do
local e = evo.registry.entity()
if not os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") then
assert(not pcall(evo.registry.get, e, f))
assert(not pcall(evo.registry.assign, e, f, 42))
assert(not pcall(e.get, e, f))
assert(not pcall(e.assign, e, f, 42))
end
assert(evo.registry.get_or(e, f) == nil)
assert(evo.registry.get_or(e, f, 42) == 42)
assert(e:get_or(f) == nil)
assert(e:get_or(f, 42) == 42)
evo.registry.insert(e, f, 84)
e:insert(f, 84)
assert(evo.registry.get(e, f) == 84)
assert(evo.registry.get_or(e, f) == 84)
assert(evo.registry.get_or(e, f, 42) == 84)
assert(e:get(f) == 84)
assert(e:get_or(f) == 84)
assert(e:get_or(f, 42) == 84)
if not os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") then
assert(not pcall(evo.registry.insert, e, f, 42))
assert(not pcall(e.insert, e, f, 42))
end
evo.registry.assign(e, f)
assert(evo.registry.get(e, f) == true)
e:assign(f)
assert(e:get(f) == true)
evo.registry.assign(e, f, 21)
assert(evo.registry.get(e, f) == 21)
e:assign(f, 21)
assert(e:get(f) == 21)
end
do
@@ -58,7 +58,7 @@ do
local e = evo.registry.entity()
evo.registry.insert(e, f1, f1.__guid)
e:insert(f1, f1.__guid)
assert(e.__chunk == evo.registry.chunk(f1))
do
@@ -67,7 +67,7 @@ do
assert(#chunk_f1.__components[f1] == 1)
end
evo.registry.insert(e, f2, f2.__guid)
e:insert(f2, f2.__guid)
assert(e.__chunk == evo.registry.chunk(f1, f2))
do
@@ -81,7 +81,7 @@ do
assert(#chunk_f1_f2.__components[f2] == 1)
end
evo.registry.remove(e, f1)
e:remove(f1)
assert(e.__chunk == evo.registry.chunk(f2))
do
@@ -134,40 +134,40 @@ for _ = 1, 100 do
shuffle_array(insert_fragments)
for _, f in ipairs(insert_fragments) do
evo.registry.insert(e1, f, f.__guid)
e1:insert(f, f.__guid)
end
shuffle_array(insert_fragments)
for _, f in ipairs(insert_fragments) do
evo.registry.insert(e2, f, f.__guid)
e2:insert(f, f.__guid)
end
assert(e1.__chunk == e2.__chunk)
assert(evo.registry.has_all(e1, evo.compat.unpack(insert_fragments)))
assert(evo.registry.has_all(e2, evo.compat.unpack(insert_fragments)))
assert(e1:has_all(evo.compat.unpack(insert_fragments)))
assert(e2:has_all(evo.compat.unpack(insert_fragments)))
shuffle_array(remove_fragments)
for _, f in ipairs(remove_fragments) do
if evo.registry.has(e1, f) then
evo.registry.remove(e1, f)
if e1:has(f) then
e1:remove(f)
end
end
shuffle_array(remove_fragments)
for _, f in ipairs(remove_fragments) do
if evo.registry.has(e2, f) then
evo.registry.remove(e2, f)
if e2:has(f) then
e2:remove(f)
end
end
assert(e1.__chunk == e2.__chunk)
assert(not evo.registry.has_any(e1, evo.compat.unpack(remove_fragments)))
assert(not evo.registry.has_any(e2, evo.compat.unpack(remove_fragments)))
assert(not e1:has_any(evo.compat.unpack(remove_fragments)))
assert(not e2:has_any(evo.compat.unpack(remove_fragments)))
if e1.__chunk ~= nil then
for f, _ in pairs(e1.__chunk.__components) do
assert(evo.registry.get(e1, f) == f.__guid)
assert(evo.registry.get(e2, f) == f.__guid)
assert(e1:get(f) == f.__guid)
assert(e2:get(f) == f.__guid)
end
end
end
@@ -177,34 +177,34 @@ do
local f1, f2, f3 = evo.registry.entity(), evo.registry.entity(), evo.registry.entity()
local e1 = evo.registry.entity()
evo.registry.insert(e1, f1)
e1:insert(f1)
local e2 = evo.registry.entity()
evo.registry.insert(e2, f1)
evo.registry.insert(e2, f2)
e2:insert(f1)
e2:insert(f2)
local e3 = evo.registry.entity()
evo.registry.insert(e3, f1)
evo.registry.insert(e3, f2)
evo.registry.insert(e3, f3)
e3:insert(f1)
e3:insert(f2)
e3:insert(f3)
do
local e = evo.registry.entity()
evo.registry.insert(e, f1)
evo.registry.remove(e, f1)
e:insert(f1)
e:remove(f1)
evo.registry.insert(e, f1)
evo.registry.insert(e, f2)
evo.registry.remove(e, f1)
evo.registry.remove(e, f2)
e:insert(f1)
e:insert(f2)
e:remove(f1)
e:remove(f2)
evo.registry.insert(e, f1)
evo.registry.insert(e, f2)
evo.registry.insert(e, f3)
evo.registry.remove(e, f1)
evo.registry.remove(e, f2)
evo.registry.remove(e, f3)
e:insert(f1)
e:insert(f2)
e:insert(f3)
e:remove(f1)
e:remove(f2)
e:remove(f3)
end
local q1 = evo.registry.query(f1)
@@ -216,8 +216,8 @@ do
---@nodiscard
local function collect_query_entities(query)
local entities = {} ---@type evolved.entity[]
for chunk in evo.registry.execute(query) do
for _, e in ipairs(chunk.__entities) do
for chunk in query:execute() do
for _, e in ipairs(chunk:entities()) do
table.insert(entities, e)
end
end

View File

@@ -1,6 +1,12 @@
---@class evolved.idpools
local idpools = {}
---
---
---
---
---
---@alias evolved.id integer
---@class evolved.idpool
@@ -9,6 +15,12 @@ local idpools = {}
local evolved_idpool_mt = {}
evolved_idpool_mt.__index = evolved_idpool_mt
---
---
---
---
---
---@return evolved.idpool
function idpools.idpool()
---@type evolved.idpool
@@ -91,4 +103,22 @@ function idpools.is_alive(idpool, id)
return idpool.__freelist_ids[index] == id
end
---
---
---
---
---
evolved_idpool_mt.pack = idpools.pack
evolved_idpool_mt.unpack = idpools.unpack
evolved_idpool_mt.acquire = idpools.acquire
evolved_idpool_mt.release = idpools.release
evolved_idpool_mt.is_alive = idpools.is_alive
---
---
---
---
---
return idpools

View File

@@ -495,7 +495,7 @@ end
---@param chunk evolved.chunk
---@return evolved.entity[]
---@nodiscard
function registry.chunk_entities(chunk)
function registry.entities(chunk)
return chunk.__entities
end
@@ -503,7 +503,7 @@ end
---@param fragment evolved.entity
---@return any[]
---@nodiscard
function registry.chunk_components(chunk, fragment)
function registry.components(chunk, fragment)
local components = chunk.__components[fragment]
if components == nil then
@@ -525,6 +525,17 @@ function evolved_entity_mt:__tostring()
return string.format('[%d;%d]', index, version)
end
evolved_entity_mt.is_alive = registry.is_alive
evolved_entity_mt.destroy = registry.destroy
evolved_entity_mt.get = registry.get
evolved_entity_mt.get_or = registry.get_or
evolved_entity_mt.has = registry.has
evolved_entity_mt.has_all = registry.has_all
evolved_entity_mt.has_any = registry.has_any
evolved_entity_mt.assign = registry.assign
evolved_entity_mt.insert = registry.insert
evolved_entity_mt.remove = registry.remove
function evolved_query_mt:__tostring()
local fragment_ids = ''
@@ -535,6 +546,8 @@ function evolved_query_mt:__tostring()
return string.format('(%s)', fragment_ids)
end
evolved_query_mt.execute = registry.execute
function evolved_chunk_mt:__tostring()
local fragment_ids = ''
@@ -546,6 +559,9 @@ function evolved_chunk_mt:__tostring()
return string.format('{%s}', fragment_ids)
end
evolved_chunk_mt.entities = registry.entities
evolved_chunk_mt.components = registry.components
---
---
---