mirror of
https://github.com/BlackMATov/evolved.lua.git
synced 2025-12-16 14:11:16 +07:00
the brand new destroying entity/fragment process
This commit is contained in:
@@ -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