mirror of
https://github.com/BlackMATov/evolved.lua.git
synced 2025-12-13 11:38:15 +07:00
21
.github/workflows/lua5.1.yml
vendored
Normal file
21
.github/workflows/lua5.1.yml
vendored
Normal 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
21
.github/workflows/lua5.4.yml
vendored
Normal 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
21
.github/workflows/luajit.yml
vendored
Normal 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
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"[json][jsonc][lua][markdown]": {
|
||||
"[json][jsonc][lua][markdown][yaml]": {
|
||||
"editor.formatOnSave": true,
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimFinalNewlines": true,
|
||||
|
||||
12
README.md
12
README.md
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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(): ...
|
||||
|
||||
121
develop/fuzzing/batch_destroy_fuzz.lua
Normal file
121
develop/fuzzing/batch_destroy_fuzz.lua
Normal 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()
|
||||
127
develop/fuzzing/destroy_fuzz.lua
Normal file
127
develop/fuzzing/destroy_fuzz.lua
Normal 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()
|
||||
@@ -1,5 +1,5 @@
|
||||
require 'develop.unload' 'evolved'
|
||||
local basics = require 'develop.basics'
|
||||
basics.unload 'evolved'
|
||||
|
||||
local evo = require 'evolved'
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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'
|
||||
|
||||
424
evolved.lua
424
evolved.lua
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user