4 Commits

Author SHA1 Message Date
BlackMATov
b6cc943850 update changelog 2026-03-06 06:03:01 +07:00
BlackMATov
a9fecee874 hold fragments with insert/remove/explicit hooks separately 2026-03-06 05:59:26 +07:00
BlackMATov
39c0b988b5 v1.10.0 2026-02-13 23:18:20 +07:00
BlackMATov
766f7b92be update README 2026-02-13 21:13:51 +07:00
6 changed files with 492 additions and 130 deletions

115
README.md
View File

@@ -45,7 +45,8 @@
- [Batch Operations](#batch-operations) - [Batch Operations](#batch-operations)
- [Systems](#systems) - [Systems](#systems)
- [Processing Payloads](#processing-payloads) - [Processing Payloads](#processing-payloads)
- [Predefined Traits](#predefined-traits) - [Predefined Fragments](#predefined-fragments)
- [Entity Names](#entity-names)
- [Fragment Tags](#fragment-tags) - [Fragment Tags](#fragment-tags)
- [Fragment Hooks](#fragment-hooks) - [Fragment Hooks](#fragment-hooks)
- [Unique Fragments](#unique-fragments) - [Unique Fragments](#unique-fragments)
@@ -53,7 +54,6 @@
- [Internal Fragments](#internal-fragments) - [Internal Fragments](#internal-fragments)
- [Shared Components](#shared-components) - [Shared Components](#shared-components)
- [Fragment Requirements](#fragment-requirements) - [Fragment Requirements](#fragment-requirements)
- [Id Names](#id-names)
- [Destruction Policies](#destruction-policies) - [Destruction Policies](#destruction-policies)
- [Custom Component Storages](#custom-component-storages) - [Custom Component Storages](#custom-component-storages)
- [Garbage Collection](#garbage-collection) - [Garbage Collection](#garbage-collection)
@@ -66,6 +66,7 @@
- [Builder](#builder) - [Builder](#builder)
- [Changelog](#changelog) - [Changelog](#changelog)
- [vX.Y.Z](#vxyz) - [vX.Y.Z](#vxyz)
- [v1.10.0](#v1100)
- [v1.9.0](#v190) - [v1.9.0](#v190)
- [v1.8.0](#v180) - [v1.8.0](#v180)
- [v1.7.0](#v170) - [v1.7.0](#v170)
@@ -491,6 +492,7 @@ When you need to spawn multiple entities with identical fragments, use `multi_sp
---@param component_mapper? evolved.component_mapper ---@param component_mapper? evolved.component_mapper
---@return evolved.entity[] entity_list ---@return evolved.entity[] entity_list
---@return integer entity_count ---@return integer entity_count
---@nodiscard
function evolved.multi_spawn(entity_count, component_table, component_mapper) end function evolved.multi_spawn(entity_count, component_table, component_mapper) end
---@param entity_count integer ---@param entity_count integer
@@ -499,6 +501,7 @@ function evolved.multi_spawn(entity_count, component_table, component_mapper) en
---@param component_mapper? evolved.component_mapper ---@param component_mapper? evolved.component_mapper
---@return evolved.entity[] entity_list ---@return evolved.entity[] entity_list
---@return integer entity_count ---@return integer entity_count
---@nodiscard
function evolved.multi_clone(entity_count, prefab, component_table, component_mapper) end function evolved.multi_clone(entity_count, prefab, component_table, component_mapper) end
``` ```
@@ -529,6 +532,36 @@ end)
Of course, you can use `evolved.multi_clone` in the same way. Builders can also be used for multi-entity spawning and cloning by calling the corresponding methods on the builder object. Of course, you can use `evolved.multi_clone` in the same way. Builders can also be used for multi-entity spawning and cloning by calling the corresponding methods on the builder object.
Also, for all `multi_` functions, the library provides [`_nr`](#evolvedmulti_spawn_nr) and [`_to`](#evolvedmulti_spawn_to) suffix variants that allow you to perform these operations without returning the list of spawned entities or by copying the spawned entities to your own table, which can be more efficient because it avoids the overhead of allocating and returning a new table.
```lua
local evolved = require 'evolved'
local position_x, position_y = evolved.id(2)
do
-- we don't interest in the list of spawned entities,
-- so we use the _nr variant of the multi_spawn function
evolved.multi_spawn_nr(100, {
[position_x] = 0,
[position_y] = 0,
})
end
do
-- store spawned entities in our own table starting at index 1,
-- so we use the _to variant of the multi_spawn function
local entity_list = {}
evolved.multi_spawn_to(entity_list, 1, 100, {
[position_x] = 0,
[position_y] = 0,
})
end
```
### Access Operations ### Access Operations
The library provides all the necessary functions to access entities and their components. I'm not going to cover all the accessor functions here, because they are pretty straightforward and self-explanatory. You can check the [API Reference](#api-reference) for all of them. Here are some of the most important ones: The library provides all the necessary functions to access entities and their components. I'm not going to cover all the accessor functions here, because they are pretty straightforward and self-explanatory. You can check the [API Reference](#api-reference) for all of them. Here are some of the most important ones:
@@ -983,7 +1016,42 @@ evolved.process_with(physics_system, delta_time)
`delta_time` in this example is passed as a processing payload to the system's execution callback. Payloads can be of any type and can be multiple values. Also, payloads are passed to prologue and epilogue callbacks if they are defined. Every subsystem in a group will receive the same payload when the group is processed with [`evolved.process_with`](#evolvedprocess_with). `delta_time` in this example is passed as a processing payload to the system's execution callback. Payloads can be of any type and can be multiple values. Also, payloads are passed to prologue and epilogue callbacks if they are defined. Every subsystem in a group will receive the same payload when the group is processed with [`evolved.process_with`](#evolvedprocess_with).
### Predefined Traits ### Predefined Fragments
#### Entity Names
The library provides a way to assign names to any id using the [`evolved.NAME`](#evolvedname) fragment. This is useful for debugging and development purposes, as it allows you to identify entities or fragments by their names instead of their identifiers. The name of an entity can be retrieved using the [`evolved.name`](#evolvedname-1) function.
```lua
local evolved = require 'evolved'
local player = evolved.builder()
:name('Player')
:build()
assert(evolved.name(player) == 'Player')
```
Names are not unique, so multiple entities can have the same name. Also, the name of an entity can be changed at any time by setting a new name using the [`evolved.NAME`](#evolvedname) fragment as a usual component.
You can find entities by their names using the [`evolved.lookup`](#evolvedlookup) and [`evolved.multi_lookup`](#evolvedmulti_lookup) functions. The [`evolved.lookup`](#evolvedlookup) function returns the first entity with the specified name, while the [`evolved.multi_lookup`](#evolvedmulti_lookup) function returns a list of all entities with the specified name.
```lua
local evolved = require 'evolved'
local player1 = evolved.builder()
:name('Player')
:build()
local player2 = evolved.builder()
:name('Player')
:build()
assert(evolved.lookup('Player') == player1)
local player_list, player_count = evolved.multi_lookup('Player')
assert(player_count == 2 and player_list[1] == player1 and player_list[2] == player2)
```
#### Fragment Tags #### Fragment Tags
@@ -1163,41 +1231,6 @@ local enemy = evolved.builder()
assert(evolved.has_all(enemy, position, velocity)) assert(evolved.has_all(enemy, position, velocity))
``` ```
#### Id Names
The library provides a way to assign names to any id using the [`evolved.NAME`](#evolvedname) fragment. This is useful for debugging and development purposes, as it allows you to identify entities or fragments by their names instead of their identifiers. The name of an entity can be retrieved using the [`evolved.name`](#evolvedname-1) function.
```lua
local evolved = require 'evolved'
local player = evolved.builder()
:name('Player')
:build()
assert(evolved.name(player) == 'Player')
```
Names are not unique, so multiple entities can have the same name. Also, the name of an entity can be changed at any time by setting a new name using the [`evolved.NAME`](#evolvedname) fragment as a usual component.
You can find entities by their names using the [`evolved.lookup`](#evolvedlookup) and [`evolved.multi_lookup`](#evolvedmulti_lookup) functions. The [`evolved.lookup`](#evolvedlookup) function returns the first entity with the specified name, while the [`evolved.multi_lookup`](#evolvedmulti_lookup) function returns a list of all entities with the specified name.
```lua
local evolved = require 'evolved'
local player1 = evolved.builder()
:name('Player')
:build()
local player2 = evolved.builder()
:name('Player')
:build()
assert(evolved.lookup('Player') == player1)
local player_list, player_count = evolved.multi_lookup('Player')
assert(player_count == 2 and player_list[1] == player1 and player_list[2] == player2)
```
#### Destruction Policies #### 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. 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.
@@ -1638,8 +1671,14 @@ builder_mt:destruction_policy :: id -> builder
### vX.Y.Z ### vX.Y.Z
- Slightly improved performance of modifying operations for fragments with [`ON_INSERT`](#evolvedon_insert) and [`ON_REMOVE`](#evolvedon_remove) hooks
- Slightly improved performance of queries with [`EXPLICIT`](#evolvedexplicit) fragments
### v1.10.0
- Added the new [`evolved.lookup`](#evolvedlookup) and [`evolved.multi_lookup`](#evolvedmulti_lookup) functions that allow finding ids by their names - Added the new [`evolved.lookup`](#evolvedlookup) and [`evolved.multi_lookup`](#evolvedmulti_lookup) functions that allow finding ids by their names
- Added a non-shrinking version of the [`evolved.collect_garbage`](#evolvedcollect_garbage) function that only collects garbage without shrinking storages - Added a non-shrinking version of the [`evolved.collect_garbage`](#evolvedcollect_garbage) function that only collects garbage without shrinking storages
- Added [`_nr`](#evolvedmulti_spawn_nr) and [`_to`](#evolvedmulti_spawn_to) variants of the [`evolved.multi_spawn`](#evolvedmulti_spawn) and [`evolved.multi_clone`](#evolvedmulti_clone) functions that provide more efficient ways to spawn or clone entities in some cases
### v1.9.0 ### v1.9.0

View File

@@ -1,4 +1,5 @@
require 'develop.testing.build_tests' require 'develop.testing.build_tests'
require 'develop.testing.cached_hooks_tests'
require 'develop.testing.cancel_tests' require 'develop.testing.cancel_tests'
require 'develop.testing.clone_tests' require 'develop.testing.clone_tests'
require 'develop.testing.depth_tests' require 'develop.testing.depth_tests'

View File

@@ -0,0 +1,203 @@
local evo = require 'evolved'
evo.debug_mode(true)
do
local f1, f2 = evo.id(2)
local insert_hook_calls = 0
if f1 < f2 then
evo.set(f1, evo.ON_INSERT, function()
insert_hook_calls = insert_hook_calls + 1
end)
else
evo.set(f2, evo.ON_INSERT, function()
insert_hook_calls = insert_hook_calls + 1
end)
end
do
insert_hook_calls = 0
local e = evo.spawn { [f1] = 42, [f2] = 'hello' }
assert(insert_hook_calls == 1)
evo.destroy(e)
end
evo.remove(f1, evo.ON_INSERT)
evo.remove(f2, evo.ON_INSERT)
do
insert_hook_calls = 0
local e = evo.spawn { [f1] = 42, [f2] = 'hello' }
assert(insert_hook_calls == 0)
evo.destroy(e)
end
if f1 < f2 then
evo.set(f1, evo.ON_INSERT, function()
insert_hook_calls = insert_hook_calls + 2
end)
else
evo.set(f2, evo.ON_INSERT, function()
insert_hook_calls = insert_hook_calls + 2
end)
end
do
insert_hook_calls = 0
local e = evo.spawn { [f1] = 42, [f2] = 'hello' }
assert(insert_hook_calls == 2)
evo.destroy(e)
end
end
do
local f1, f2 = evo.id(2)
local insert_hook_calls = 0
if f1 > f2 then
evo.set(f1, evo.ON_INSERT, function()
insert_hook_calls = insert_hook_calls + 1
end)
else
evo.set(f2, evo.ON_INSERT, function()
insert_hook_calls = insert_hook_calls + 1
end)
end
do
insert_hook_calls = 0
local e = evo.spawn { [f1] = 42, [f2] = 'hello' }
assert(insert_hook_calls == 1)
evo.destroy(e)
end
evo.remove(f1, evo.ON_INSERT)
evo.remove(f2, evo.ON_INSERT)
do
insert_hook_calls = 0
local e = evo.spawn { [f1] = 42, [f2] = 'hello' }
assert(insert_hook_calls == 0)
evo.destroy(e)
end
if f1 > f2 then
evo.set(f1, evo.ON_INSERT, function()
insert_hook_calls = insert_hook_calls + 2
end)
else
evo.set(f2, evo.ON_INSERT, function()
insert_hook_calls = insert_hook_calls + 2
end)
end
do
insert_hook_calls = 0
local e = evo.spawn { [f1] = 42, [f2] = 'hello' }
assert(insert_hook_calls == 2)
evo.destroy(e)
end
end
do
local f1, f2 = evo.id(2)
local remove_hook_calls = 0
if f1 < f2 then
evo.set(f1, evo.ON_REMOVE, function()
remove_hook_calls = remove_hook_calls + 1
end)
else
evo.set(f2, evo.ON_REMOVE, function()
remove_hook_calls = remove_hook_calls + 1
end)
end
do
remove_hook_calls = 0
local e = evo.spawn { [f1] = 42, [f2] = 'hello' }
evo.destroy(e)
assert(remove_hook_calls == 1)
end
evo.remove(f1, evo.ON_REMOVE)
evo.remove(f2, evo.ON_REMOVE)
do
remove_hook_calls = 0
local e = evo.spawn { [f1] = 42, [f2] = 'hello' }
evo.destroy(e)
assert(remove_hook_calls == 0)
end
if f1 < f2 then
evo.set(f1, evo.ON_REMOVE, function()
remove_hook_calls = remove_hook_calls + 2
end)
else
evo.set(f2, evo.ON_REMOVE, function()
remove_hook_calls = remove_hook_calls + 2
end)
end
do
remove_hook_calls = 0
local e = evo.spawn { [f1] = 42, [f2] = 'hello' }
evo.destroy(e)
assert(remove_hook_calls == 2)
end
end
do
local f1, f2 = evo.id(2)
local remove_hook_calls = 0
if f1 > f2 then
evo.set(f1, evo.ON_REMOVE, function()
remove_hook_calls = remove_hook_calls + 1
end)
else
evo.set(f2, evo.ON_REMOVE, function()
remove_hook_calls = remove_hook_calls + 1
end)
end
do
remove_hook_calls = 0
local e = evo.spawn { [f1] = 42, [f2] = 'hello' }
evo.destroy(e)
assert(remove_hook_calls == 1)
end
evo.remove(f1, evo.ON_REMOVE)
evo.remove(f2, evo.ON_REMOVE)
do
remove_hook_calls = 0
local e = evo.spawn { [f1] = 42, [f2] = 'hello' }
evo.destroy(e)
assert(remove_hook_calls == 0)
end
if f1 > f2 then
evo.set(f1, evo.ON_REMOVE, function()
remove_hook_calls = remove_hook_calls + 2
end)
else
evo.set(f2, evo.ON_REMOVE, function()
remove_hook_calls = remove_hook_calls + 2
end)
end
do
remove_hook_calls = 0
local e = evo.spawn { [f1] = 42, [f2] = 'hello' }
evo.destroy(e)
assert(remove_hook_calls == 2)
end
end

View File

@@ -2928,8 +2928,8 @@ do
last_insert_entity, last_insert_component = 0, 0 last_insert_entity, last_insert_component = 0, 0
local e = evo.spawn({ [f2] = 21, [f1] = true }) local e = evo.spawn({ [f2] = 21, [f1] = true })
assert(set_count == 2 and insert_count == 2) assert(set_count == 2 and insert_count == 2)
assert(last_set_entity == e and last_set_component == 21) assert(last_set_entity == e and (last_set_component == 21 or last_set_component == true))
assert(last_insert_entity == e and last_insert_component == 21) assert(last_insert_entity == e and (last_insert_component == 21 or last_insert_component == true))
end end
do do
@@ -2948,8 +2948,8 @@ do
last_insert_entity, last_insert_component = 0, 0 last_insert_entity, last_insert_component = 0, 0
local e = evo.spawn({ [f3] = 33, [f2] = 22 }) local e = evo.spawn({ [f3] = 33, [f2] = 22 })
assert(set_count == 2 and insert_count == 2) assert(set_count == 2 and insert_count == 2)
assert(last_set_entity == e and last_set_component == nil) assert(last_set_entity == e and (last_set_component == nil or last_set_component == 22))
assert(last_insert_entity == e and last_insert_component == nil) assert(last_insert_entity == e and (last_insert_component == nil or last_insert_component == 22))
end end
end end

View File

@@ -1,7 +1,7 @@
local evolved = { local evolved = {
__HOMEPAGE = 'https://github.com/BlackMATov/evolved.lua', __HOMEPAGE = 'https://github.com/BlackMATov/evolved.lua',
__DESCRIPTION = 'Evolved ECS (Entity-Component-System) for Lua', __DESCRIPTION = 'Evolved ECS (Entity-Component-System) for Lua',
__VERSION = '1.9.0', __VERSION = '1.10.0',
__LICENSE = [[ __LICENSE = [[
MIT License MIT License
@@ -202,6 +202,12 @@ local __structural_changes = 0 ---@type integer
---@field package __has_internal_minors boolean ---@field package __has_internal_minors boolean
---@field package __has_internal_fragments boolean ---@field package __has_internal_fragments boolean
---@field package __has_required_fragments boolean ---@field package __has_required_fragments boolean
---@field package __insert_fragment_list? evolved.fragment[]
---@field package __insert_fragment_count integer
---@field package __remove_fragment_list? evolved.fragment[]
---@field package __remove_fragment_count integer
---@field package __explicit_fragment_list? evolved.fragment[]
---@field package __explicit_fragment_count integer
local __chunk_mt = {} local __chunk_mt = {}
__chunk_mt.__index = __chunk_mt __chunk_mt.__index = __chunk_mt
@@ -819,12 +825,13 @@ end
---@param list V[] ---@param list V[]
---@param size? integer ---@param size? integer
---@return V[] ---@return V[]
---@return integer dup_list_size
---@nodiscard ---@nodiscard
function __list_fns.dup(list, size) function __list_fns.dup(list, size)
local list_size = size or #list local list_size = size or #list
if list_size == 0 then if list_size == 0 then
return {} return {}, 0
end end
local dup_list = __list_fns.new(list_size) local dup_list = __list_fns.new(list_size)
@@ -833,7 +840,7 @@ function __list_fns.dup(list, size)
list, 1, list_size, list, 1, list_size,
1, dup_list) 1, dup_list)
return dup_list return dup_list, list_size
end end
---@generic V ---@generic V
@@ -1408,6 +1415,12 @@ function __new_chunk(chunk_parent, chunk_fragment)
__has_internal_minors = false, __has_internal_minors = false,
__has_internal_fragments = false, __has_internal_fragments = false,
__has_required_fragments = false, __has_required_fragments = false,
__insert_fragment_list = nil,
__insert_fragment_count = 0,
__remove_fragment_list = nil,
__remove_fragment_count = 0,
__explicit_fragment_list = nil,
__explicit_fragment_count = 0,
}, __chunk_mt) }, __chunk_mt)
if not chunk_parent then if not chunk_parent then
@@ -1590,17 +1603,22 @@ function __update_chunk_caches(chunk)
local chunk_fragment_list = chunk.__fragment_list local chunk_fragment_list = chunk.__fragment_list
local chunk_fragment_count = chunk.__fragment_count local chunk_fragment_count = chunk.__fragment_count
local has_setup_hooks = chunk_parent ~= nil and chunk_parent.__has_setup_hooks local has_setup_major = __evolved_has_any(chunk_fragment, __DEFAULT, __DUPLICATE)
or __evolved_has_any(chunk_fragment, __DEFAULT, __DUPLICATE) local has_setup_minors = chunk_parent ~= nil and chunk_parent.__has_setup_hooks
local has_assign_hooks = chunk_parent ~= nil and chunk_parent.__has_assign_hooks local has_assign_major = __evolved_has_any(chunk_fragment, __ON_SET, __ON_ASSIGN)
or __evolved_has_any(chunk_fragment, __ON_SET, __ON_ASSIGN) local has_assign_minors = chunk_parent ~= nil and chunk_parent.__has_assign_hooks
local has_insert_hooks = chunk_parent ~= nil and chunk_parent.__has_insert_hooks local has_insert_major = __evolved_has_any(chunk_fragment, __ON_SET, __ON_INSERT)
or __evolved_has_any(chunk_fragment, __ON_SET, __ON_INSERT) local has_insert_minors = chunk_parent ~= nil and chunk_parent.__has_insert_hooks
local has_remove_hooks = chunk_parent ~= nil and chunk_parent.__has_remove_hooks local has_remove_major = __evolved_has(chunk_fragment, __ON_REMOVE)
or __evolved_has(chunk_fragment, __ON_REMOVE) local has_remove_minors = chunk_parent ~= nil and chunk_parent.__has_remove_hooks
local has_setup_hooks = has_setup_major or has_setup_minors
local has_assign_hooks = has_assign_major or has_assign_minors
local has_insert_hooks = has_insert_major or has_insert_minors
local has_remove_hooks = has_remove_major or has_remove_minors
local has_unique_major = __evolved_has(chunk_fragment, __UNIQUE) local has_unique_major = __evolved_has(chunk_fragment, __UNIQUE)
local has_unique_minors = chunk_parent ~= nil and chunk_parent.__has_unique_fragments local has_unique_minors = chunk_parent ~= nil and chunk_parent.__has_unique_fragments
@@ -1667,6 +1685,75 @@ function __update_chunk_caches(chunk)
else else
chunk.__without_unique_fragments = chunk chunk.__without_unique_fragments = chunk
end end
if has_insert_hooks then
local parent_insert_fragment_list = chunk_parent and chunk_parent.__insert_fragment_list
local parent_insert_fragment_count = chunk_parent and chunk_parent.__insert_fragment_count or 0
if has_insert_major then
local insert_fragment_list, insert_fragment_count = parent_insert_fragment_list
and __list_fns.dup(parent_insert_fragment_list, parent_insert_fragment_count)
or __list_fns.new(1), 0
insert_fragment_count = parent_insert_fragment_count + 1
insert_fragment_list[insert_fragment_count] = chunk_fragment
chunk.__insert_fragment_list = insert_fragment_list
chunk.__insert_fragment_count = insert_fragment_count
else
chunk.__insert_fragment_list = parent_insert_fragment_list
chunk.__insert_fragment_count = parent_insert_fragment_count
end
else
chunk.__insert_fragment_list = nil
chunk.__insert_fragment_count = 0
end
if has_remove_hooks then
local parent_remove_fragment_list = chunk_parent and chunk_parent.__remove_fragment_list
local parent_remove_fragment_count = chunk_parent and chunk_parent.__remove_fragment_count or 0
if has_remove_major then
local remove_fragment_list, remove_fragment_count = parent_remove_fragment_list
and __list_fns.dup(parent_remove_fragment_list, parent_remove_fragment_count)
or __list_fns.new(1), 0
remove_fragment_count = parent_remove_fragment_count + 1
remove_fragment_list[remove_fragment_count] = chunk_fragment
chunk.__remove_fragment_list = remove_fragment_list
chunk.__remove_fragment_count = remove_fragment_count
else
chunk.__remove_fragment_list = parent_remove_fragment_list
chunk.__remove_fragment_count = parent_remove_fragment_count
end
else
chunk.__remove_fragment_list = nil
chunk.__remove_fragment_count = 0
end
if has_explicit_fragments then
local parent_explicit_fragment_list = chunk_parent and chunk_parent.__explicit_fragment_list
local parent_explicit_fragment_count = chunk_parent and chunk_parent.__explicit_fragment_count or 0
if has_explicit_major then
local explicit_fragment_list, explicit_fragment_count = parent_explicit_fragment_list
and __list_fns.dup(parent_explicit_fragment_list, parent_explicit_fragment_count)
or __list_fns.new(1), 0
explicit_fragment_count = parent_explicit_fragment_count + 1
explicit_fragment_list[explicit_fragment_count] = chunk_fragment
chunk.__explicit_fragment_list = explicit_fragment_list
chunk.__explicit_fragment_count = explicit_fragment_count
else
chunk.__explicit_fragment_list = parent_explicit_fragment_list
chunk.__explicit_fragment_count = parent_explicit_fragment_count
end
else
chunk.__explicit_fragment_list = nil
chunk.__explicit_fragment_count = 0
end
end end
---@param chunk evolved.chunk ---@param chunk evolved.chunk
@@ -2063,17 +2150,15 @@ function __query_minor_matches(chunk, query)
end end
end end
if chunk.__has_explicit_fragments then local chunk_explicit_fragment_list = chunk.__explicit_fragment_list
local chunk_fragment_list = chunk.__fragment_list
local chunk_fragment_count = chunk.__fragment_count
for chunk_fragment_index = 1, chunk_fragment_count do if chunk_explicit_fragment_list then
local chunk_fragment = chunk_fragment_list[chunk_fragment_index] for chunk_explicit_fragment_index = 1, chunk.__explicit_fragment_count do
local fragment = chunk_explicit_fragment_list[chunk_explicit_fragment_index]
local is_chunk_fragment_matched = local is_chunk_fragment_matched =
(not __evolved_has(chunk_fragment, __EXPLICIT)) or (query_variant_count > 0 and query_variant_set[fragment]) or
(query_variant_count > 0 and query_variant_set[chunk_fragment]) or (query_include_count > 0 and query_include_set[fragment])
(query_include_count > 0 and query_include_set[chunk_fragment])
if not is_chunk_fragment_matched then if not is_chunk_fragment_matched then
return false return false
@@ -2639,12 +2724,11 @@ function __spawn_entity(chunk, entity, component_table, component_mapper)
component_mapper(chunk, place, place) component_mapper(chunk, place, place)
end end
if chunk.__has_insert_hooks then local chunk_insert_fragment_list = chunk.__insert_fragment_list
local chunk_fragment_list = chunk.__fragment_list
local chunk_fragment_count = chunk.__fragment_count
for chunk_fragment_index = 1, chunk_fragment_count do if chunk_insert_fragment_list then
local fragment = chunk_fragment_list[chunk_fragment_index] for chunk_insert_fragment_index = 1, chunk.__insert_fragment_count do
local fragment = chunk_insert_fragment_list[chunk_insert_fragment_index]
---@type evolved.set_hook?, evolved.insert_hook? ---@type evolved.set_hook?, evolved.insert_hook?
local fragment_on_set, fragment_on_insert = local fragment_on_set, fragment_on_insert =
@@ -2778,12 +2862,11 @@ function __multi_spawn_entity(chunk, entity_list, entity_first, entity_count, co
component_mapper(chunk, b_place, e_place) component_mapper(chunk, b_place, e_place)
end end
if chunk.__has_insert_hooks then local chunk_insert_fragment_list = chunk.__insert_fragment_list
local chunk_fragment_list = chunk.__fragment_list
local chunk_fragment_count = chunk.__fragment_count
for chunk_fragment_index = 1, chunk_fragment_count do if chunk_insert_fragment_list then
local fragment = chunk_fragment_list[chunk_fragment_index] for chunk_insert_fragment_index = 1, chunk.__insert_fragment_count do
local fragment = chunk_insert_fragment_list[chunk_insert_fragment_index]
---@type evolved.set_hook?, evolved.insert_hook? ---@type evolved.set_hook?, evolved.insert_hook?
local fragment_on_set, fragment_on_insert = local fragment_on_set, fragment_on_insert =
@@ -2939,12 +3022,11 @@ function __clone_entity(prefab, entity, component_table, component_mapper)
component_mapper(chunk, place, place) component_mapper(chunk, place, place)
end end
if chunk.__has_insert_hooks then local chunk_insert_fragment_list = chunk.__insert_fragment_list
local chunk_fragment_list = chunk.__fragment_list
local chunk_fragment_count = chunk.__fragment_count
for chunk_fragment_index = 1, chunk_fragment_count do if chunk_insert_fragment_list then
local fragment = chunk_fragment_list[chunk_fragment_index] for chunk_insert_fragment_index = 1, chunk.__insert_fragment_count do
local fragment = chunk_insert_fragment_list[chunk_insert_fragment_index]
---@type evolved.set_hook?, evolved.insert_hook? ---@type evolved.set_hook?, evolved.insert_hook?
local fragment_on_set, fragment_on_insert = local fragment_on_set, fragment_on_insert =
@@ -3107,12 +3189,11 @@ function __multi_clone_entity(prefab, entity_list, entity_first, entity_count, c
component_mapper(chunk, b_place, e_place) component_mapper(chunk, b_place, e_place)
end end
if chunk.__has_insert_hooks then local chunk_insert_fragment_list = chunk.__insert_fragment_list
local chunk_fragment_list = chunk.__fragment_list
local chunk_fragment_count = chunk.__fragment_count
for chunk_fragment_index = 1, chunk_fragment_count do if chunk_insert_fragment_list then
local fragment = chunk_fragment_list[chunk_fragment_index] for chunk_insert_fragment_index = 1, chunk.__insert_fragment_count do
local fragment = chunk_insert_fragment_list[chunk_insert_fragment_index]
---@type evolved.set_hook?, evolved.insert_hook? ---@type evolved.set_hook?, evolved.insert_hook?
local fragment_on_set, fragment_on_insert = local fragment_on_set, fragment_on_insert =
@@ -3377,27 +3458,29 @@ function __clear_entity_one(entity)
local chunk = entity_chunks[entity_primary] local chunk = entity_chunks[entity_primary]
local place = entity_places[entity_primary] local place = entity_places[entity_primary]
if chunk and chunk.__has_remove_hooks then if chunk then
local chunk_fragment_list = chunk.__fragment_list local chunk_remove_fragment_list = chunk.__remove_fragment_list
local chunk_fragment_count = chunk.__fragment_count
local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages
for chunk_fragment_index = 1, chunk_fragment_count do if chunk_remove_fragment_list then
local fragment = chunk_fragment_list[chunk_fragment_index] local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages
---@type evolved.remove_hook? for chunk_remove_fragment_index = 1, chunk.__remove_fragment_count do
local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE) local fragment = chunk_remove_fragment_list[chunk_remove_fragment_index]
if fragment_on_remove then ---@type evolved.remove_hook?
local component_index = chunk_component_indices[fragment] local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE)
if component_index then if fragment_on_remove then
local component_storage = chunk_component_storages[component_index] local component_index = chunk_component_indices[fragment]
local old_component = component_storage[place]
fragment_on_remove(entity, fragment, old_component) if component_index then
else local component_storage = chunk_component_storages[component_index]
fragment_on_remove(entity, fragment) local old_component = component_storage[place]
fragment_on_remove(entity, fragment, old_component)
else
fragment_on_remove(entity, fragment)
end
end end
end end
end end
@@ -3444,27 +3527,29 @@ function __destroy_entity_one(entity)
local chunk = entity_chunks[entity_primary] local chunk = entity_chunks[entity_primary]
local place = entity_places[entity_primary] local place = entity_places[entity_primary]
if chunk and chunk.__has_remove_hooks then if chunk then
local chunk_fragment_list = chunk.__fragment_list local chunk_remove_fragment_list = chunk.__remove_fragment_list
local chunk_fragment_count = chunk.__fragment_count
local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages
for chunk_fragment_index = 1, chunk_fragment_count do if chunk_remove_fragment_list then
local fragment = chunk_fragment_list[chunk_fragment_index] local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages
---@type evolved.remove_hook? for chunk_remove_fragment_index = 1, chunk.__remove_fragment_count do
local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE) local fragment = chunk_remove_fragment_list[chunk_remove_fragment_index]
if fragment_on_remove then ---@type evolved.remove_hook?
local component_index = chunk_component_indices[fragment] local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE)
if component_index then if fragment_on_remove then
local component_storage = chunk_component_storages[component_index] local component_index = chunk_component_indices[fragment]
local old_component = component_storage[place]
fragment_on_remove(entity, fragment, old_component) if component_index then
else local component_storage = chunk_component_storages[component_index]
fragment_on_remove(entity, fragment) local old_component = component_storage[place]
fragment_on_remove(entity, fragment, old_component)
else
fragment_on_remove(entity, fragment)
end
end end
end end
end end
@@ -4060,8 +4145,6 @@ function __chunk_remove(old_chunk, ...)
local old_entity_list = old_chunk.__entity_list local old_entity_list = old_chunk.__entity_list
local old_entity_count = old_chunk.__entity_count local old_entity_count = old_chunk.__entity_count
local old_fragment_list = old_chunk.__fragment_list
local old_fragment_count = old_chunk.__fragment_count
local old_component_indices = old_chunk.__component_indices local old_component_indices = old_chunk.__component_indices
local old_component_storages = old_chunk.__component_storages local old_component_storages = old_chunk.__component_storages
@@ -4075,12 +4158,14 @@ function __chunk_remove(old_chunk, ...)
return return
end end
if old_chunk.__has_remove_hooks then local old_remove_fragment_list = old_chunk.__remove_fragment_list
if old_remove_fragment_list then
local new_fragment_set = new_chunk and new_chunk.__fragment_set local new_fragment_set = new_chunk and new_chunk.__fragment_set
or __safe_tbls.__EMPTY_FRAGMENT_SET or __safe_tbls.__EMPTY_FRAGMENT_SET
for old_fragment_index = 1, old_fragment_count do for old_remove_fragment_index = 1, old_chunk.__remove_fragment_count do
local fragment = old_fragment_list[old_fragment_index] local fragment = old_remove_fragment_list[old_remove_fragment_index]
if not new_fragment_set[fragment] then if not new_fragment_set[fragment] then
---@type evolved.remove_hook? ---@type evolved.remove_hook?
@@ -4209,14 +4294,14 @@ function __chunk_clear(chunk)
return return
end end
if chunk.__has_remove_hooks then local chunk_remove_fragment_list = chunk.__remove_fragment_list
local chunk_fragment_list = chunk.__fragment_list
local chunk_fragment_count = chunk.__fragment_count if chunk_remove_fragment_list then
local chunk_component_indices = chunk.__component_indices local chunk_component_indices = chunk.__component_indices
local chunk_component_storages = chunk.__component_storages local chunk_component_storages = chunk.__component_storages
for chunk_fragment_index = 1, chunk_fragment_count do for chunk_remove_fragment_index = 1, chunk.__remove_fragment_count do
local fragment = chunk_fragment_list[chunk_fragment_index] local fragment = chunk_remove_fragment_list[chunk_remove_fragment_index]
---@type evolved.remove_hook? ---@type evolved.remove_hook?
local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE) local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE)
@@ -5610,17 +5695,17 @@ function __evolved_remove(entity, ...)
__evolved_defer() __evolved_defer()
if old_chunk and old_chunk ~= new_chunk then if old_chunk and old_chunk ~= new_chunk then
local old_fragment_list = old_chunk.__fragment_list
local old_fragment_count = old_chunk.__fragment_count
local old_component_indices = old_chunk.__component_indices local old_component_indices = old_chunk.__component_indices
local old_component_storages = old_chunk.__component_storages local old_component_storages = old_chunk.__component_storages
if old_chunk.__has_remove_hooks then local old_remove_fragment_list = old_chunk.__remove_fragment_list
if old_remove_fragment_list then
local new_fragment_set = new_chunk and new_chunk.__fragment_set local new_fragment_set = new_chunk and new_chunk.__fragment_set
or __safe_tbls.__EMPTY_FRAGMENT_SET or __safe_tbls.__EMPTY_FRAGMENT_SET
for old_fragment_index = 1, old_fragment_count do for old_remove_fragment_index = 1, old_chunk.__remove_fragment_count do
local fragment = old_fragment_list[old_fragment_index] local fragment = old_remove_fragment_list[old_remove_fragment_index]
if not new_fragment_set[fragment] then if not new_fragment_set[fragment] then
---@type evolved.remove_hook? ---@type evolved.remove_hook?

View File

@@ -0,0 +1,34 @@
rockspec_format = "3.0"
package = "evolved.lua"
version = "1.10.0-0"
source = {
url = "git://github.com/BlackMATov/evolved.lua",
tag = "v1.10.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",
}
}