Merge pull request #1 from BlackMATov/dev

Dev
This commit is contained in:
2025-04-05 02:12:18 +07:00
committed by GitHub
15 changed files with 618 additions and 196 deletions

21
.github/workflows/lua5.1.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: lua5.1
on: [push, pull_request]
jobs:
build:
runs-on: ${{matrix.operating_system}}
strategy:
fail-fast: false
matrix:
lua_version: ["5.1"]
operating_system: ["ubuntu-latest", "macos-latest", "windows-latest"]
name: ${{matrix.operating_system}}-${{matrix.lua_version}}
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
- uses: leafo/gh-actions-lua@v11
with:
luaVersion: ${{matrix.lua_version}}
- run: |
lua ./develop/all.lua

21
.github/workflows/lua5.4.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: lua5.4
on: [push, pull_request]
jobs:
build:
runs-on: ${{matrix.operating_system}}
strategy:
fail-fast: false
matrix:
lua_version: ["5.4"]
operating_system: ["ubuntu-latest", "macos-latest", "windows-latest"]
name: ${{matrix.operating_system}}-${{matrix.lua_version}}
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
- uses: leafo/gh-actions-lua@v11
with:
luaVersion: ${{matrix.lua_version}}
- run: |
lua ./develop/all.lua

21
.github/workflows/luajit.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: luajit
on: [push, pull_request]
jobs:
build:
runs-on: ${{matrix.operating_system}}
strategy:
fail-fast: false
matrix:
lua_version: ["luajit"]
operating_system: ["ubuntu-latest", "macos-latest", "windows-latest"]
name: ${{matrix.operating_system}}-${{matrix.lua_version}}
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
- uses: leafo/gh-actions-lua@v11
with:
luaVersion: ${{matrix.lua_version}}
- run: |
lua ./develop/all.lua

View File

@@ -1,5 +1,5 @@
{
"[json][jsonc][lua][markdown]": {
"[json][jsonc][lua][markdown][yaml]": {
"editor.formatOnSave": true,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,

View File

@@ -2,13 +2,19 @@
> Evolved ECS (Entity-Component-System) for Lua
[![language][badge.language]][language]
[![lua5.1][badge.lua5.1]][lua5.1]
[![lua5.4][badge.lua5.4]][lua5.4]
[![luajit][badge.luajit]][luajit]
[![license][badge.license]][license]
[badge.language]: https://img.shields.io/badge/language-Lua-orange
[badge.lua5.1]: https://img.shields.io/github/actions/workflow/status/BlackMATov/evolved.lua/.github/workflows/lua5.1.yml?label=Lua%205.1
[badge.lua5.4]: https://img.shields.io/github/actions/workflow/status/BlackMATov/evolved.lua/.github/workflows/lua5.4.yml?label=Lua%205.4
[badge.luajit]: https://img.shields.io/github/actions/workflow/status/BlackMATov/evolved.lua/.github/workflows/luajit.yml?label=LuaJIT
[badge.license]: https://img.shields.io/badge/license-MIT-blue
[language]: https://en.wikipedia.org/wiki/Lua_(programming_language)
[lua5.1]: https://github.com/BlackMATov/evolved.lua/actions?query=workflow%3Alua5.1
[lua5.4]: https://github.com/BlackMATov/evolved.lua/actions?query=workflow%3Alua5.4
[luajit]: https://github.com/BlackMATov/evolved.lua/actions?query=workflow%3Aluajit
[license]: https://en.wikipedia.org/wiki/MIT_License
[evolved]: https://github.com/BlackMATov/evolved.lua

View File

@@ -5,6 +5,7 @@
- can we pass systems and groups to the process function?
- builders should be rewritten :/
- add evolved.spawn_as function
- is/has_all/any for lists?
## After first release

View File

@@ -2,3 +2,8 @@ require 'develop.example'
require 'develop.unbench'
require 'develop.untests'
require 'develop.usbench'
local basics = require 'develop.basics'
basics.describe_fuzz 'develop.fuzzing.destroy_fuzz'
basics.describe_fuzz 'develop.fuzzing.batch_destroy_fuzz'

View File

@@ -12,6 +12,48 @@ local __table_unpack = (function()
return table.unpack or unpack
end)()
---@param pattern string
function basics.unload(pattern)
for name, _ in pairs(package.loaded) do
if name:match(pattern) then
package.loaded[name] = nil
end
end
end
---@param modname string
function basics.describe_fuzz(modname)
print(string.format('| %s ... |', modname))
do
local iters = 0
local start_s = os.clock()
local start_kb = collectgarbage('count')
local success, result = pcall(function()
repeat
iters = iters + 1
basics.unload(modname)
require(modname)
until os.clock() - start_s > 0.5
end)
local finish_s = os.clock()
local finish_kb = collectgarbage('count')
if success then
print(string.format('|-- PASS | us: %.2f | op/s: %.2f | kb/i: %.2f | iters: %d',
(finish_s - start_s) * 1e6 / iters,
iters / (finish_s - start_s),
(finish_kb - start_kb) / iters,
iters))
else
print('|-- FUZZ FAIL: ' .. result)
end
end
end
---@param name string
---@param loop fun(...): ...
---@param init? fun(): ...

View File

@@ -0,0 +1,121 @@
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[]
for i = 1, math.random(1, 10) do
local entity = evo.id()
all_entity_list[i] = entity
end
for _, entity in ipairs(all_entity_list) do
for _ = 0, math.random(0, #all_entity_list) do
local fragment = all_entity_list[math.random(1, #all_entity_list)]
evo.set(entity, fragment)
end
if math.random(1, 5) == 1 then
evo.set(entity, evo.DESTROY_POLICY, evo.DESTROY_POLICY_DESTROY_ENTITY)
end
if math.random(1, 5) == 1 then
evo.set(entity, evo.DESTROY_POLICY, evo.DESTROY_POLICY_REMOVE_FRAGMENT)
end
end
---
---
---
---
---
local should_be_destroyed_entity_set = {} ---@type table<evolved.entity, integer>
local should_be_destroyed_entity_list = {} ---@type evolved.entity[]
local should_be_destroyed_entity_count = 0 ---@type integer
local function collect_destroyed_entities_with(entity)
local entity_destroy_policy = evo.get(entity, evo.DESTROY_POLICY)
or evo.DESTROY_POLICY_REMOVE_FRAGMENT
if entity_destroy_policy == evo.DESTROY_POLICY_DESTROY_ENTITY then
for _, other_entity in ipairs(all_entity_list) do
if evo.has(other_entity, entity) and not should_be_destroyed_entity_set[other_entity] then
should_be_destroyed_entity_count = should_be_destroyed_entity_count + 1
should_be_destroyed_entity_list[should_be_destroyed_entity_count] = other_entity
should_be_destroyed_entity_set[other_entity] = should_be_destroyed_entity_count
end
end
end
end
local destroying_include_list = {} ---@type evolved.entity[]
for i = 1, math.random(1, #all_entity_list) do
local destroying_include = all_entity_list[math.random(1, #all_entity_list)]
destroying_include_list[i] = destroying_include
end
for _, entity in ipairs(all_entity_list) do
if evo.has_all(entity, __table_unpack(destroying_include_list)) then
collect_destroyed_entities_with(entity)
end
end
do
local r = math.random(1, 2)
local q = evo.query():include(__table_unpack(destroying_include_list)):build()
if r == 1 then
evo.batch_destroy(q)
elseif r == 2 then
assert(evo.defer())
evo.batch_destroy(q)
assert(evo.commit())
end
end
---
---
---
---
---
local all_chunk_query = evo.query():build()
for chunk in evo.execute(all_chunk_query) do
assert(not evo.has_any(chunk, __table_unpack(should_be_destroyed_entity_list)))
for _, fragment in ipairs(evo.fragments(chunk)) do
assert(not evo.has_all(fragment, __table_unpack(destroying_include_list)))
end
end
for _, destroyed_entity in ipairs(should_be_destroyed_entity_list) do
assert(not evo.is_alive(destroyed_entity))
end
---
---
---
---
---
evo.destroy(__table_unpack(all_entity_list))
evo.collect_garbage()

View File

@@ -0,0 +1,127 @@
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[]
for i = 1, math.random(1, 10) do
local entity = evo.id()
all_entity_list[i] = entity
end
for _, entity in ipairs(all_entity_list) do
for _ = 0, math.random(0, #all_entity_list) do
local fragment = all_entity_list[math.random(1, #all_entity_list)]
evo.set(entity, fragment)
end
if math.random(1, 5) == 1 then
evo.set(entity, evo.DESTROY_POLICY, evo.DESTROY_POLICY_DESTROY_ENTITY)
end
if math.random(1, 5) == 1 then
evo.set(entity, evo.DESTROY_POLICY, evo.DESTROY_POLICY_REMOVE_FRAGMENT)
end
end
---
---
---
---
---
local should_be_destroyed_entity_set = {} ---@type table<evolved.entity, integer>
local should_be_destroyed_entity_list = {} ---@type evolved.entity[]
local should_be_destroyed_entity_count = 0 ---@type integer
local function collect_destroyed_entities_with(entity)
local entity_destroy_policy = evo.get(entity, evo.DESTROY_POLICY)
or evo.DESTROY_POLICY_REMOVE_FRAGMENT
if entity_destroy_policy == evo.DESTROY_POLICY_DESTROY_ENTITY then
for _, other_entity in ipairs(all_entity_list) do
if evo.has(other_entity, entity) and not should_be_destroyed_entity_set[other_entity] then
should_be_destroyed_entity_count = should_be_destroyed_entity_count + 1
should_be_destroyed_entity_list[should_be_destroyed_entity_count] = other_entity
should_be_destroyed_entity_set[other_entity] = should_be_destroyed_entity_count
end
end
end
end
local destroying_entity_list = {} ---@type evolved.entity[]
for i = 1, math.random(1, #all_entity_list) do
local destroying_entity = all_entity_list[math.random(1, #all_entity_list)]
destroying_entity_list[i] = destroying_entity
collect_destroyed_entities_with(destroying_entity)
end
do
local r = math.random(1, 4)
if r == 1 then
evo.destroy(__table_unpack(destroying_entity_list))
elseif r == 2 then
assert(evo.defer())
evo.destroy(__table_unpack(destroying_entity_list))
assert(evo.commit())
elseif r == 3 then
for _, destroying_entity in ipairs(destroying_entity_list) do
evo.destroy(destroying_entity)
end
elseif r == 4 then
assert(evo.defer())
for _, destroying_entity in ipairs(destroying_entity_list) do
evo.destroy(destroying_entity)
end
assert(evo.commit())
end
end
---
---
---
---
---
local all_chunk_query = evo.query():build()
for chunk in evo.execute(all_chunk_query) do
assert(not evo.has_any(chunk, __table_unpack(destroying_entity_list)))
assert(not evo.has_any(chunk, __table_unpack(should_be_destroyed_entity_list)))
end
for _, destroying_entity in ipairs(destroying_entity_list) do
assert(not evo.is_alive(destroying_entity))
end
for _, destroyed_entity in ipairs(should_be_destroyed_entity_list) do
assert(not evo.is_alive(destroyed_entity))
end
---
---
---
---
---
evo.destroy(__table_unpack(all_entity_list))
evo.collect_garbage()

View File

@@ -1,5 +1,5 @@
require 'develop.unload' 'evolved'
local basics = require 'develop.basics'
basics.unload 'evolved'
local evo = require 'evolved'

View File

@@ -1,8 +0,0 @@
---@param pattern string
return function(pattern)
for name, _ in pairs(package.loaded) do
if name:match(pattern) then
package.loaded[name] = nil
end
end
end

View File

@@ -1,4 +1,5 @@
require 'develop.unload' 'evolved'
local basics = require 'develop.basics'
basics.unload 'evolved'
local evo = require 'evolved'
@@ -6246,7 +6247,7 @@ do
do
local c4_es, c4_ec = evo.entities(c4)
assert(c4_es and #c4_es == 3 and c4_ec == 3)
assert(c4_es[1] == e14 and c4_es[2] == e24 and c4_es[3] == e124)
assert(c4_es[1] == e24 and c4_es[2] == e14 and c4_es[3] == e124)
end
assert(#evo.entities(c14) == 0)

View File

@@ -1,5 +1,5 @@
require 'develop.unload' 'evolved'
local basics = require 'develop.basics'
basics.unload 'evolved'
local evo = require 'evolved'
local tiny = require 'develop.3rdparty.tiny'

View File

@@ -272,6 +272,7 @@ end)()
---@param fmt string
---@param ... any
---@diagnostic disable-next-line: unused-local, unused-function
local function __error_fmt(fmt, ...)
error(string.format('| evolved.lua | %s',
string.format(fmt, ...)))
@@ -279,6 +280,7 @@ end
---@param fmt string
---@param ... any
---@diagnostic disable-next-line: unused-local, unused-function
local function __warning_fmt(fmt, ...)
print(string.format('| evolved.lua | %s',
string.format(fmt, ...)))
@@ -360,13 +362,15 @@ local __table_pool_tag = {
chunk_stack = 2,
each_state = 3,
execute_state = 4,
fragment_set = 5,
fragment_list = 6,
component_list = 7,
group_list = 8,
sorting_stack = 9,
sorting_marks = 10,
__count = 10,
entity_set = 5,
entity_list = 6,
fragment_set = 7,
fragment_list = 8,
component_list = 9,
group_list = 10,
sorting_stack = 11,
sorting_marks = 12,
__count = 12,
}
---@class (exact) evolved.table_pool
@@ -1952,7 +1956,6 @@ end
local __chunk_set
local __chunk_remove
local __chunk_clear
local __chunk_destroy
local __chunk_multi_set
local __chunk_multi_remove
@@ -1966,7 +1969,7 @@ local __chunk_multi_remove
---@param chunk evolved.chunk
local function __purge_chunk(chunk)
if __defer_depth <= 0 then
__error_fmt('purge operations should be deferred')
__error_fmt('this operation should be deferred')
end
if chunk.__child_count > 0 or chunk.__entity_count > 0 then
@@ -2021,30 +2024,192 @@ local function __purge_chunk(chunk)
chunk.__unreachable_or_collected = true
end
---@param fragment evolved.fragment
---@param policy evolved.id
local function __purge_fragment(fragment, policy)
---@param entity_list evolved.entity[]
---@param entity_count integer
local function __destroy_entity_list(entity_list, entity_count)
if __defer_depth <= 0 then
__error_fmt('purge operations should be deferred')
__error_fmt('this operation should be deferred')
end
local minor_chunks = __minor_chunks[fragment]
local minor_chunk_list = minor_chunks and minor_chunks.__item_list --[=[@as evolved.chunk[]]=]
local minor_chunk_count = minor_chunks and minor_chunks.__item_count or 0 --[[@as integer]]
if entity_count == 0 then
return
end
if policy == __DESTROY_POLICY_DESTROY_ENTITY then
for minor_chunk_index = minor_chunk_count, 1, -1 do
local minor_chunk = minor_chunk_list[minor_chunk_index]
_ = __chunk_destroy(minor_chunk)
for i = 1, entity_count do
local entity = entity_list[i]
local entity_index = entity % 0x100000
if __freelist_ids[entity_index] ~= entity then
-- this entity is not alive, nothing to purge
else
local chunk = __entity_chunks[entity_index]
local place = __entity_places[entity_index]
if chunk and chunk.__has_remove_hooks then
local chunk_fragment_list = chunk.__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
local fragment = chunk_fragment_list[chunk_fragment_index]
---@type evolved.remove_hook?
local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE)
if fragment_on_remove then
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
local old_component = component_storage[place]
__defer_call_hook(fragment_on_remove, entity, fragment, old_component)
else
__defer_call_hook(fragment_on_remove, entity, fragment)
end
end
end
end
if chunk then
__detach_entity(chunk, place)
__entity_chunks[entity_index] = nil
__entity_places[entity_index] = nil
__structural_changes = __structural_changes + 1
end
__release_id(entity)
end
elseif policy == __DESTROY_POLICY_REMOVE_FRAGMENT then
for minor_chunk_index = minor_chunk_count, 1, -1 do
local minor_chunk = minor_chunk_list[minor_chunk_index]
_ = __chunk_remove(minor_chunk, fragment)
end
end
---@param fragment_list evolved.fragment[]
---@param fragment_count integer
local function __destroy_fragment_list(fragment_list, fragment_count)
if __defer_depth <= 0 then
__error_fmt('this operation should be deferred')
end
if fragment_count == 0 then
return
end
local processed_fragment_set = __acquire_table(__table_pool_tag.fragment_set)
local processing_fragment_stack = __acquire_table(__table_pool_tag.fragment_list)
local processing_fragment_stack_size = 0
do
__lua_table_move(
fragment_list, 1, fragment_count,
processing_fragment_stack_size + 1, processing_fragment_stack)
processing_fragment_stack_size = processing_fragment_stack_size + fragment_count
end
local releasing_fragment_list = __acquire_table(__table_pool_tag.fragment_list)
local releasing_fragment_count = 0
local destroy_entity_policy_fragment_list = __acquire_table(__table_pool_tag.fragment_list)
local destroy_entity_policy_fragment_count = 0
local remove_fragment_policy_fragment_list = __acquire_table(__table_pool_tag.fragment_list)
local remove_fragment_policy_fragment_count = 0
while processing_fragment_stack_size > 0 do
local processing_fragment = processing_fragment_stack[processing_fragment_stack_size]
processing_fragment_stack[processing_fragment_stack_size] = nil
processing_fragment_stack_size = processing_fragment_stack_size - 1
if processed_fragment_set[processing_fragment] then
-- this fragment has already beed processed
else
processed_fragment_set[processing_fragment] = true
releasing_fragment_count = releasing_fragment_count + 1
releasing_fragment_list[releasing_fragment_count] = processing_fragment
local processing_fragment_destroy_policy = __evolved_get(processing_fragment, __DESTROY_POLICY)
or __DESTROY_POLICY_REMOVE_FRAGMENT
if processing_fragment_destroy_policy == __DESTROY_POLICY_DESTROY_ENTITY then
destroy_entity_policy_fragment_count = destroy_entity_policy_fragment_count + 1
destroy_entity_policy_fragment_list[destroy_entity_policy_fragment_count] = processing_fragment
local minor_chunks = __minor_chunks[processing_fragment]
local minor_chunk_list = minor_chunks and minor_chunks.__item_list --[=[@as evolved.chunk[]]=]
local minor_chunk_count = minor_chunks and minor_chunks.__item_count or 0 --[[@as integer]]
for minor_chunk_index = 1, minor_chunk_count do
local minor_chunk = minor_chunk_list[minor_chunk_index]
local minor_chunk_entity_list = minor_chunk.__entity_list
local minor_chunk_entity_count = minor_chunk.__entity_count
__lua_table_move(
minor_chunk_entity_list, 1, minor_chunk_entity_count,
processing_fragment_stack_size + 1, processing_fragment_stack)
processing_fragment_stack_size = processing_fragment_stack_size + minor_chunk_entity_count
end
elseif processing_fragment_destroy_policy == __DESTROY_POLICY_REMOVE_FRAGMENT then
remove_fragment_policy_fragment_count = remove_fragment_policy_fragment_count + 1
remove_fragment_policy_fragment_list[remove_fragment_policy_fragment_count] = processing_fragment
else
__error_fmt('unknown DESTROY_POLICY policy (%s) on (%s)',
__id_name(processing_fragment_destroy_policy), __id_name(processing_fragment))
end
end
end
__release_table(__table_pool_tag.fragment_set, processed_fragment_set)
__release_table(__table_pool_tag.fragment_list, processing_fragment_stack, true)
if destroy_entity_policy_fragment_count > 0 then
for i = 1, destroy_entity_policy_fragment_count do
local fragment = destroy_entity_policy_fragment_list[i]
local minor_chunks = __minor_chunks[fragment]
local minor_chunk_list = minor_chunks and minor_chunks.__item_list --[=[@as evolved.chunk[]]=]
local minor_chunk_count = minor_chunks and minor_chunks.__item_count or 0 --[[@as integer]]
for minor_chunk_index = 1, minor_chunk_count do
local minor_chunk = minor_chunk_list[minor_chunk_index]
__chunk_clear(minor_chunk)
end
end
__release_table(__table_pool_tag.fragment_list, destroy_entity_policy_fragment_list)
else
__warning_fmt('unknown DESTROY_POLICY policy (%s) on (%s)',
__id_name(policy), __id_name(fragment))
__release_table(__table_pool_tag.fragment_list, destroy_entity_policy_fragment_list, true)
end
if remove_fragment_policy_fragment_count > 0 then
for i = 1, remove_fragment_policy_fragment_count do
local fragment = remove_fragment_policy_fragment_list[i]
local minor_chunks = __minor_chunks[fragment]
local minor_chunk_list = minor_chunks and minor_chunks.__item_list --[=[@as evolved.chunk[]]=]
local minor_chunk_count = minor_chunks and minor_chunks.__item_count or 0 --[[@as integer]]
for minor_chunk_index = 1, minor_chunk_count do
local minor_chunk = minor_chunk_list[minor_chunk_index]
__chunk_remove(minor_chunk, fragment)
end
end
__release_table(__table_pool_tag.fragment_list, remove_fragment_policy_fragment_list)
else
__release_table(__table_pool_tag.fragment_list, remove_fragment_policy_fragment_list, true)
end
if releasing_fragment_count > 0 then
__destroy_entity_list(releasing_fragment_list, releasing_fragment_count)
__release_table(__table_pool_tag.fragment_list, releasing_fragment_list)
else
__release_table(__table_pool_tag.fragment_list, releasing_fragment_list, true)
end
end
@@ -2528,97 +2693,6 @@ __chunk_clear = function(chunk)
__structural_changes = __structural_changes + 1
end
---@param chunk evolved.chunk
__chunk_destroy = function(chunk)
if __defer_depth <= 0 then
__error_fmt('batched chunk operations should be deferred')
end
local chunk_entity_list = chunk.__entity_list
local chunk_entity_count = chunk.__entity_count
if chunk_entity_count == 0 then
return
end
if chunk.__has_remove_hooks then
local chunk_fragment_list = chunk.__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
local fragment = chunk_fragment_list[chunk_fragment_index]
---@type evolved.remove_hook?
local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE)
if fragment_on_remove then
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
for place = 1, chunk_entity_count do
local entity = chunk_entity_list[place]
local old_component = component_storage[place]
__defer_call_hook(fragment_on_remove, entity, fragment, old_component)
end
else
for place = 1, chunk_entity_count do
local entity = chunk_entity_list[place]
__defer_call_hook(fragment_on_remove, entity, fragment)
end
end
end
end
end
do
---@type integer
local purging_count = 0
---@type evolved.fragment[]
local purging_fragments = __acquire_table(__table_pool_tag.fragment_list)
---@type evolved.fragment[]
local purging_policies = __acquire_table(__table_pool_tag.fragment_list)
local entity_chunks = __entity_chunks
local entity_places = __entity_places
for place = 1, chunk_entity_count do
local entity = chunk_entity_list[place]
local entity_index = entity % 0x100000
if __minor_chunks[entity] then
purging_count = purging_count + 1
purging_fragments[purging_count] = entity
purging_policies[purging_count] = __chunk_get_components(chunk, place, __DESTROY_POLICY)
or __DESTROY_POLICY_REMOVE_FRAGMENT
end
entity_chunks[entity_index] = nil
entity_places[entity_index] = nil
__release_id(entity)
end
__detach_all_entities(chunk)
for purging_index = 1, purging_count do
local purging_fragment = purging_fragments[purging_index]
local purging_policy = purging_policies[purging_index]
__purge_fragment(purging_fragment, purging_policy)
end
__release_table(__table_pool_tag.fragment_list, purging_fragments)
__release_table(__table_pool_tag.fragment_list, purging_policies)
end
__structural_changes = __structural_changes + 1
end
---@param old_chunk evolved.chunk
---@param fragments evolved.fragment[]
---@param fragment_count integer
@@ -4874,8 +4948,11 @@ __evolved_destroy = function(...)
__evolved_defer()
do
local entity_chunks = __entity_chunks
local entity_places = __entity_places
local purging_entity_list = __acquire_table(__table_pool_tag.entity_list)
local purging_entity_count = 0
local purging_fragment_list = __acquire_table(__table_pool_tag.fragment_list)
local purging_fragment_count = 0
for argument_index = 1, argument_count do
---@type evolved.entity
@@ -4885,60 +4962,29 @@ __evolved_destroy = function(...)
if __freelist_ids[entity_index] ~= entity then
-- this entity is not alive, nothing to destroy
else
local chunk = entity_chunks[entity_index]
local place = entity_places[entity_index]
if chunk and chunk.__has_remove_hooks then
local chunk_fragment_list = chunk.__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
local fragment = chunk_fragment_list[chunk_fragment_index]
---@type evolved.remove_hook?
local fragment_on_remove = __evolved_get(fragment, __ON_REMOVE)
if fragment_on_remove then
local component_index = chunk_component_indices[fragment]
if component_index then
local component_storage = chunk_component_storages[component_index]
local old_component = component_storage[place]
__defer_call_hook(fragment_on_remove, entity, fragment, old_component)
else
__defer_call_hook(fragment_on_remove, entity, fragment)
end
end
end
end
local purging_fragment ---@type evolved.fragment?
local purging_policy ---@type evolved.id?
if __minor_chunks[entity] then
purging_fragment = entity
purging_policy = chunk and __chunk_get_components(chunk, place, __DESTROY_POLICY)
or __DESTROY_POLICY_REMOVE_FRAGMENT
end
if chunk then
__detach_entity(chunk, place)
entity_chunks[entity_index] = nil
entity_places[entity_index] = nil
__structural_changes = __structural_changes + 1
end
__release_id(entity)
if purging_fragment then
__purge_fragment(purging_fragment, purging_policy)
if not __minor_chunks[entity] then
purging_entity_count = purging_entity_count + 1
purging_entity_list[purging_entity_count] = entity
else
purging_fragment_count = purging_fragment_count + 1
purging_fragment_list[purging_fragment_count] = entity
end
end
end
if purging_entity_count > 0 then
__destroy_entity_list(purging_entity_list, purging_entity_count)
__release_table(__table_pool_tag.entity_list, purging_entity_list)
else
__release_table(__table_pool_tag.entity_list, purging_entity_list, true)
end
if purging_fragment_count > 0 then
__destroy_fragment_list(purging_fragment_list, purging_fragment_count)
__release_table(__table_pool_tag.fragment_list, purging_fragment_list)
else
__release_table(__table_pool_tag.fragment_list, purging_fragment_list, true)
end
end
__evolved_commit()
@@ -5413,9 +5459,11 @@ __evolved_batch_destroy = function(...)
__evolved_defer()
do
---@type evolved.chunk[]
local chunk_list = __acquire_table(__table_pool_tag.chunk_stack)
local chunk_count = 0
local purging_entity_list = __acquire_table(__table_pool_tag.entity_list)
local purging_entity_count = 0
local purging_fragment_list = __acquire_table(__table_pool_tag.fragment_list)
local purging_fragment_count = 0
for argument_index = 1, argument_count do
---@type evolved.query
@@ -5425,19 +5473,35 @@ __evolved_batch_destroy = function(...)
if __freelist_ids[query_index] ~= query then
-- this query is not alive, nothing to destroy
else
for chunk in __evolved_execute(query) do
chunk_count = chunk_count + 1
chunk_list[chunk_count] = chunk
for _, entity_list, entity_count in __evolved_execute(query) do
for i = 1, entity_count do
local entity = entity_list[i]
if not __minor_chunks[entity] then
purging_entity_count = purging_entity_count + 1
purging_entity_list[purging_entity_count] = entity
else
purging_fragment_count = purging_fragment_count + 1
purging_fragment_list[purging_fragment_count] = entity
end
end
end
end
end
for chunk_index = 1, chunk_count do
local chunk = chunk_list[chunk_index]
__chunk_destroy(chunk)
if purging_entity_count > 0 then
__destroy_entity_list(purging_entity_list, purging_entity_count)
__release_table(__table_pool_tag.entity_list, purging_entity_list)
else
__release_table(__table_pool_tag.entity_list, purging_entity_list, true)
end
__release_table(__table_pool_tag.chunk_stack, chunk_list)
if purging_fragment_count > 0 then
__destroy_fragment_list(purging_fragment_list, purging_fragment_count)
__release_table(__table_pool_tag.fragment_list, purging_fragment_list)
else
__release_table(__table_pool_tag.fragment_list, purging_fragment_list, true)
end
end
__evolved_commit()