the new evolved.locate public function

ref: #23
This commit is contained in:
BlackMATov
2025-09-23 04:58:10 +07:00
parent 964ea45f48
commit f15118be05
4 changed files with 125 additions and 1 deletions

View File

@@ -31,6 +31,7 @@
- [Traits](#traits)
- [Singletons](#singletons)
- [Chunks](#chunks)
- [Entity Location](#entity-location)
- [Structural Changes](#structural-changes)
- [Spawning Entities](#spawning-entities)
- [Entity Builders](#entity-builders)
@@ -365,6 +366,43 @@ end
-- Entity: 1048603, Health: 75, Stamina: 40
```
### Entity Location
Sometimes it is useful to know which chunk a specific entity is in and its position within that chunk. The [`evolved.locate`](#evolvedlocate) function provides this information.
```lua
---@param entity evolved.entity
---@return evolved.chunk? chunk
---@return integer place
function evolved.locate(entity) end
```
This function takes an entity and returns the chunk that contains it and the entitys position (index) within that chunk. If the entity is not alive or is empty, the function returns `nil` for the chunk and `0` for the place.
This is low-level functionality that you will rarely need. However, it can be useful in specific cases. For example, when you need to modify an entitys component directly to avoid unnecessary [Deferred Operations](#deferred-operations) or [Fragment Hooks](#fragment-hooks), instead of using a higher-level function like [`evolved.set`](#evolvedset).
```lua
local evolved = require 'evolved'
local health, stamina = evolved.id(2)
local player = evolved.id()
evolved.set(player, health, 100)
evolved.set(player, stamina, 50)
local player_chunk, player_place = evolved.locate(player)
local health_components = player_chunk:components(health)
local stamina_components = player_chunk:components(stamina)
health_components[player_place] = 75
stamina_components[player_place] = 42
```
> [!WARNING]
> Do not use [`evolved.locate`](#evolvedlocate) to manipulate components directly unless you fully understand what you are doing. Because it is low-level functionality, incorrect use can lead to inconsistencies, as it bypasses the librarys safety checks and hook mechanisms. Use it only when you are certain it is safe and necessary.
### Structural Changes
Every time we insert or remove a fragment from an entity, the entity will be migrated to a new chunk. This is done automatically by the library, of course. However, you should be aware of this because it can affect performance, especially if you have many fragments on the entity. This is called a `structural change`.
@@ -1172,6 +1210,8 @@ batch_destroy :: query... -> ()
each :: entity -> {each_state? -> fragment?, component?}, each_state?
execute :: query -> {execute_state? -> chunk?, entity[]?, integer?}, execute_state?
locate :: entity -> chunk?, integer
process :: system... -> ()
debug_mode :: boolean -> ()
@@ -1255,8 +1295,9 @@ builder_mt:destruction_policy :: id -> builder
### vX.X.X
- The internal garbage collector now collects more garbage
- Added the new [`evolved.cancel`](#evolvedcancel) function
- Added the new [`evolved.locate`](#evolvedlocate) function
- The internal garbage collector now collects more garbage
- Improved system processing debugging experience with stack traces on errors
### v1.2.0
@@ -1603,6 +1644,16 @@ function evolved.each(entity) end
function evolved.execute(query) end
```
### `evolved.locate`
```lua
---@param entity evolved.entity
---@return evolved.chunk? chunk
---@return integer place
---@nodiscard
function evolved.locate(entity) end
```
### `evolved.process`
```lua

View File

@@ -1,6 +1,7 @@
require 'develop.samples.systems'
require 'develop.testing.cancel_tests'
require 'develop.testing.locate_tests'
require 'develop.testing.multi_spawn_tests'
require 'develop.testing.name_tests'
require 'develop.testing.requires_fragment_tests'

View File

@@ -0,0 +1,48 @@
local evo = require 'evolved'
do
local e1, e2, f1, f2 = evo.id(4)
do
local chunk, place = evo.locate(e1)
assert(chunk == nil and place == 0)
end
evo.set(e1, f1, 42)
do
local chunk, place = evo.locate(e1)
assert(chunk and chunk == evo.chunk(f1) and place == 1)
assert(chunk:components(f1)[place] == 42)
chunk, place = evo.locate(e2)
assert(chunk == nil and place == 0)
end
evo.set(e1, f2, 'hello')
do
local chunk, place = evo.locate(e1)
assert(chunk and chunk == evo.chunk(f1, f2) and place == 1)
assert(chunk:components(f1)[place] == 42)
assert(chunk:components(f2)[place] == 'hello')
chunk, place = evo.locate(e2)
assert(chunk == nil and place == 0)
end
evo.set(e2, f1, 84)
evo.set(e2, f2, 'world')
do
local chunk, place = evo.locate(e1)
assert(chunk and chunk == evo.chunk(f1, f2) and place == 1)
assert(chunk:components(f1)[place] == 42)
assert(chunk:components(f2)[place] == 'hello')
chunk, place = evo.locate(e2)
assert(chunk and chunk == evo.chunk(f1, f2) and place == 2)
assert(chunk:components(f1)[place] == 84)
assert(chunk:components(f2)[place] == 'world')
end
end

View File

@@ -842,6 +842,8 @@ local __evolved_batch_destroy
local __evolved_each
local __evolved_execute
local __evolved_locate
local __evolved_process
local __evolved_debug_mode
@@ -5883,6 +5885,26 @@ function __evolved_execute(query)
end
end
---@param entity evolved.entity
---@return evolved.chunk? chunk
---@return integer place
---@nodiscard
function __evolved_locate(entity)
local entity_primary = entity % 2 ^ 20
if __freelist_ids[entity_primary] ~= entity then
return nil, 0
end
local entity_chunk = __entity_chunks[entity_primary]
if not entity_chunk then
return nil, 0
end
return entity_chunk, __entity_places[entity_primary]
end
---@param ... evolved.system systems
function __evolved_process(...)
local argument_count = __lua_select('#', ...)
@@ -6989,6 +7011,8 @@ evolved.batch_destroy = __evolved_batch_destroy
evolved.each = __evolved_each
evolved.execute = __evolved_execute
evolved.locate = __evolved_locate
evolved.process = __evolved_process
evolved.debug_mode = __evolved_debug_mode