first and naive version of destroying fragments

This commit is contained in:
BlackMATov
2025-03-02 09:10:43 +07:00
parent e2e8350add
commit b3cf19010c
2 changed files with 535 additions and 23 deletions

View File

@@ -6655,9 +6655,9 @@ end
do
local f1, f2 = evo.id(2)
local c1 = evo.chunk(f1)
local c2 = evo.chunk(f2)
local c12 = evo.chunk(f1, f2)
local c1 = assert(evo.chunk(f1))
local c2 = assert(evo.chunk(f2))
local c12 = assert(evo.chunk(f1, f2))
local e1a = evo.entity():set(f1, 1):build()
local e1b = evo.entity():set(f1, 2):build()
@@ -6694,3 +6694,416 @@ do
assert(c12_es[1] == e1a and c12_es[2] == e1b)
end
end
do
local f1, f2 = evo.id(2)
local c1 = assert(evo.chunk(f1))
assert(evo.set(f2, f1))
assert(evo.destroy(f1))
do
assert(not evo.is_alive(f1))
assert(evo.is_alive(f2))
assert(evo.is_empty(f2))
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 0 and c1_ec == 0)
end
end
do
local f1 = evo.id()
local c1 = assert(evo.chunk(f1))
assert(evo.set(f1, f1))
assert(evo.destroy(f1))
do
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 0 and c1_ec == 0)
end
end
do
local f1, f2 = evo.id(2)
local c1 = assert(evo.chunk(f1))
local c2 = assert(evo.chunk(f2))
local c12 = assert(evo.chunk(f1, f2))
assert(evo.set(f1, evo.ON_DESTROY, evo.REMOVE_FRAGMENT_POLICY))
assert(evo.set(f1, f1))
assert(evo.set(f2, f1))
assert(evo.set(f2, f2))
do
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 0 and c1_ec == 0)
local c2_es, c2_ec = evo.entities(c2)
assert(c2_es and #c2_es == 0 and c2_ec == 0)
local c12_es, c12_ec = evo.entities(c12)
assert(c12_es and #c12_es == 1 and c12_ec == 1)
assert(c12_es[1] == f2)
end
assert(evo.destroy(f1))
do
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 0 and c1_ec == 0)
local c2_es, c2_ec = evo.entities(c2)
assert(c2_es and #c2_es == 1 and c2_ec == 1)
assert(c2_es[1] == f2)
local c12_es, c12_ec = evo.entities(c12)
assert(c12_es and #c12_es == 0 and c12_ec == 0)
end
end
do
local f1, f2 = evo.id(2)
local c1 = assert(evo.chunk(f1))
local c2 = assert(evo.chunk(f2))
local c12 = assert(evo.chunk(f1, f2))
assert(evo.set(f1, evo.ON_DESTROY, evo.DESTROY_ENTITY_POLICY))
assert(evo.set(f1, f1))
assert(evo.set(f2, f1))
assert(evo.set(f2, f2))
do
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 0 and c1_ec == 0)
local c2_es, c2_ec = evo.entities(c2)
assert(c2_es and #c2_es == 0 and c2_ec == 0)
local c12_es, c12_ec = evo.entities(c12)
assert(c12_es and #c12_es == 1 and c12_ec == 1)
assert(c12_es[1] == f2)
end
assert(evo.destroy(f1))
do
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 0 and c1_ec == 0)
local c2_es, c2_ec = evo.entities(c2)
assert(c2_es and #c2_es == 0 and c2_ec == 0)
local c12_es, c12_ec = evo.entities(c12)
assert(c12_es and #c12_es == 0 and c12_ec == 0)
end
end
do
local f1, f2, f3 = evo.id(3)
local c1 = assert(evo.chunk(f1))
local c2 = assert(evo.chunk(f2))
assert(evo.set(f2, f1))
assert(evo.set(f3, f2))
do
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 1 and c1_ec == 1)
assert(c1_es[1] == f2)
local c2_es, c2_ec = evo.entities(c2)
assert(c2_es and #c2_es == 1 and c2_ec == 1)
assert(c2_es[1] == f3)
end
assert(evo.destroy(f1))
do
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 0 and c1_ec == 0)
local c2_es, c2_ec = evo.entities(c2)
assert(c2_es and #c2_es == 1 and c2_ec == 1)
assert(c2_es[1] == f3)
end
end
do
local f1, f2, f3 = evo.id(3)
local c1 = assert(evo.chunk(f1))
local c2 = assert(evo.chunk(f2))
assert(evo.set(f1, evo.ON_DESTROY, evo.REMOVE_FRAGMENT_POLICY))
assert(evo.set(f2, f1))
assert(evo.set(f3, f2))
do
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 1 and c1_ec == 1)
assert(c1_es[1] == f2)
local c2_es, c2_ec = evo.entities(c2)
assert(c2_es and #c2_es == 1 and c2_ec == 1)
assert(c2_es[1] == f3)
end
assert(evo.destroy(f1))
do
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 0 and c1_ec == 0)
local c2_es, c2_ec = evo.entities(c2)
assert(c2_es and #c2_es == 1 and c2_ec == 1)
assert(c2_es[1] == f3)
end
end
do
local f1, f2, f3 = evo.id(3)
local c1 = assert(evo.chunk(f1))
local c2 = assert(evo.chunk(f2))
assert(evo.set(f1, evo.ON_DESTROY, evo.DESTROY_ENTITY_POLICY))
assert(evo.set(f2, f1))
assert(evo.set(f3, f2))
do
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 1 and c1_ec == 1)
assert(c1_es[1] == f2)
local c2_es, c2_ec = evo.entities(c2)
assert(c2_es and #c2_es == 1 and c2_ec == 1)
assert(c2_es[1] == f3)
end
assert(evo.destroy(f1))
do
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 0 and c1_ec == 0)
local c2_es, c2_ec = evo.entities(c2)
assert(c2_es and #c2_es == 0 and c2_ec == 0)
end
end
do
local f1, f2, f3, f4, ft = evo.id(5)
assert(evo.set(f1, ft))
assert(evo.set(f2, ft))
assert(evo.set(f3, ft))
assert(evo.set(f3, evo.ON_DESTROY, evo.DESTROY_ENTITY_POLICY))
local qt = evo.query():include(ft):build()
local c4 = assert(evo.chunk(f4))
local c14 = assert(evo.chunk(f1, f4))
local c24 = assert(evo.chunk(f2, f4))
local c234 = assert(evo.chunk(f2, f3, f4))
local c124 = assert(evo.chunk(f1, f2, f4))
local e14 = evo.entity():set(f1, 1):set(f4, 2):build()
local e24 = evo.entity():set(f2, 3):set(f4, 4):build()
local e234 = evo.entity():set(f2, 5):set(f3, 6):set(f4, 7):build()
local e124 = evo.entity():set(f1, 8):set(f2, 6):set(f4, 9):build()
assert(evo.batch_destroy(qt))
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)
end
assert(#evo.entities(c14) == 0)
assert(#evo.entities(c24) == 0)
assert(#evo.entities(c124) == 0)
assert(#evo.entities(c234) == 0)
assert(evo.is_alive(e14) and not evo.is_empty(e14))
assert(evo.is_alive(e24) and not evo.is_empty(e24))
assert(not evo.is_alive(e234) and evo.is_empty(e234))
assert(evo.is_alive(e124) and not evo.is_empty(e124))
end
do
local f1 = evo.id()
assert(evo.set(f1, evo.ON_DESTROY, evo.DESTROY_ENTITY_POLICY))
assert(evo.set(f1, f1, f1))
local remove_count = 0
assert(evo.set(f1, evo.ON_REMOVE, function(e, f, c)
assert(e == f1)
assert(f == f1)
assert(c == f1)
remove_count = remove_count + 1
end))
local c1 = assert(evo.chunk(f1))
assert(evo.destroy(f1))
do
assert(not evo.is_alive(f1))
assert(remove_count == 1)
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 0 and c1_ec == 0)
end
end
do
local f1 = evo.id()
assert(evo.set(f1, evo.ON_DESTROY, evo.REMOVE_FRAGMENT_POLICY))
assert(evo.set(f1, f1, f1))
local remove_count = 0
assert(evo.set(f1, evo.ON_REMOVE, function(e, f, c)
assert(e == f1)
assert(f == f1)
assert(c == f1)
remove_count = remove_count + 1
end))
local c1 = assert(evo.chunk(f1))
assert(evo.destroy(f1))
do
assert(not evo.is_alive(f1))
assert(remove_count == 1)
local c1_es, c1_ec = evo.entities(c1)
assert(c1_es and #c1_es == 0 and c1_ec == 0)
end
end
do
local f1, f2, f3 = evo.id(3)
assert(evo.set(f1, evo.NAME, 'f1'))
assert(evo.set(f2, evo.NAME, 'f2'))
assert(evo.set(f3, evo.NAME, 'f3'))
local c1 = evo.chunk(f1)
local c12 = evo.chunk(f1, f2)
local c13 = evo.chunk(f1, f3)
local c123 = evo.chunk(f1, f2, f3)
local e1a = evo.entity():set(f1, 1):build()
local e1b = evo.entity():set(f1, 2):build()
local e12a = evo.entity():set(f1, 3):set(f2, 4):build()
local e12b = evo.entity():set(f1, 5):set(f2, 6):build()
local e123a = evo.entity():set(f1, 7):set(f2, 8):set(f3, 9):build()
local e123b = evo.entity():set(f1, 10):set(f2, 11):set(f3, 12):build()
assert(evo.destroy(f2))
do
assert(c1 and c12 and c13 and c123)
end
do
local c1_es, c1_ec = evo.entities(c1)
assert(c1 and c1_es and c1_ec)
assert(c1_ec == 4 and #c1_es == 4)
assert(c1_es[1] == e1a and c1_es[2] == e1b and c1_es[3] == e12a and c1_es[4] == e12b)
end
do
local c12_es, c12_ec = evo.entities(c12)
assert(c12 and c12_es and c12_ec)
assert(c12_ec == 0 and #c12_es == 0)
end
do
local c13_es, c13_ec = evo.entities(c13)
assert(c13 and c13_es and c13_ec)
assert(c13_ec == 2 and #c13_es == 2)
assert(c13_es[1] == e123a and c13_es[2] == e123b)
end
do
local c123_es, c123_ec = evo.entities(c123)
assert(c123 and c123_es and c123_ec)
assert(c123_ec == 0 and #c123_es == 0)
end
end
do
do
local f1, f2 = evo.id(2)
evo.set(f1, f1)
evo.set(f2, f1)
evo.set(f1, evo.ON_DESTROY, evo.DESTROY_ENTITY_POLICY)
assert(evo.destroy(f1))
assert(not evo.is_alive(f1))
assert(not evo.is_alive(f2))
end
do
local f1, f2 = evo.id(2)
evo.set(f1, f1)
evo.set(f2, f1)
evo.set(f1, evo.ON_DESTROY, evo.REMOVE_FRAGMENT_POLICY)
assert(evo.destroy(f1))
assert(not evo.is_alive(f1))
assert(evo.is_alive(f2) and evo.is_empty(f2))
end
end
do
local f1, f2 = evo.id(2)
evo.set(f1, evo.ON_DESTROY, evo.DESTROY_ENTITY_POLICY)
local e12a = evo.entity():set(f1, 1):set(f2, 2):build()
local e12b = evo.entity():set(f1, 3):set(f2, 4):build()
local e_e12a_e12b = evo.entity():set(e12a, 11):set(e12b, 22):build()
local e2a = evo.entity():set(f2, 5):build()
local e2b = evo.entity():set(f2, 6):build()
local e_e2a_e2b = evo.entity():set(e2a, 55):set(e2b, 66):build()
assert(evo.destroy(f1))
do
assert(not evo.is_alive(e12a) and not evo.is_alive(e12b))
assert(evo.is_alive(e_e12a_e12b) and evo.is_empty(e_e12a_e12b))
assert(evo.is_alive(e2a) and evo.is_alive(e2b))
assert(evo.is_alive(e_e2a_e2b) and not evo.is_empty(e_e2a_e2b))
end
do
local c2, c2_es, c2_ec = evo.chunk(f2)
assert(c2 and c2_es and c2_ec)
assert(#c2_es == 2 and c2_ec == 2)
assert(c2_es[1] == e2a and c2_es[2] == e2b)
end
end
do
local f1, f2 = evo.id(2)
evo.set(f1, evo.NAME, "f1")
evo.set(f2, evo.NAME, "f2")
do
local c12 = evo.chunk(f1, f2)
local f3 = evo.id()
evo.set(f3, evo.TAG)
local c123 = evo.chunk(f2, f1, f3)
evo.spawn_at(c123)
assert(c12, c123)
end
evo.set(f1, evo.ON_DESTROY, evo.REMOVE_FRAGMENT_POLICY)
local e12a = evo.entity():set(f1, 1):set(f2, 2):build()
local e12b = evo.entity():set(f1, 3):set(f2, 4):build()
local e_e12a_e12b = evo.entity():set(e12a, 11):set(e12b, 22):build()
local e2a = evo.entity():set(f2, 5):build()
local e2b = evo.entity():set(f2, 6):build()
local e_e2a_e2b = evo.entity():set(e2a, 55):set(e2b, 66):build()
assert(evo.destroy(f1))
do
assert(evo.is_alive(e12a) and evo.is_alive(e12b))
assert(evo.is_alive(e_e12a_e12b) and not evo.is_empty(e_e12a_e12b))
assert(evo.is_alive(e2a) and evo.is_alive(e2b))
assert(evo.is_alive(e_e2a_e2b) and not evo.is_empty(e_e2a_e2b))
end
do
local c2, c2_es, c2_ec = evo.chunk(f2)
assert(c2 and c2_es and c2_ec)
assert(#c2_es == 4 and c2_ec == 4)
assert(c2_es[1] == e2a and c2_es[2] == e2b and c2_es[3] == e12a and c2_es[4] == e12b)
end
end

View File

@@ -128,6 +128,7 @@ local __lua_ipairs = ipairs
local __lua_next = next
local __lua_pairs = pairs
local __lua_pcall = pcall
local __lua_print = print
local __lua_select = select
local __lua_setmetatable = setmetatable
local __lua_string_format = string.format
@@ -1636,6 +1637,73 @@ local __chunk_multi_remove
---
---
---@param fragment evolved.fragment
---@param policy evolved.id
---@return integer purged_count
local function __purge_fragment(fragment, policy)
if __defer_depth <= 0 then
__lua_error('purge operations should be deferred')
end
local minor_chunks = __minor_chunks[fragment]
if not minor_chunks then
return 0
end
local purged_count = 0
if policy == __DESTROY_ENTITY_POLICY then
for minor_chunk_index = #minor_chunks, 1, -1 do
local minor_chunk = minor_chunks[minor_chunk_index]
purged_count = purged_count + __chunk_destroy(minor_chunk)
end
elseif policy == __REMOVE_FRAGMENT_POLICY then
for minor_chunk_index = #minor_chunks, 1, -1 do
local minor_chunk = minor_chunks[minor_chunk_index]
purged_count = purged_count + __chunk_remove(minor_chunk, fragment)
end
else
__lua_print(__lua_string_format('| evolved.lua | unknown ON_DESTROY policy (%s) on (%s)',
__id_name(policy), __id_name(fragment)))
end
return purged_count
end
---@param fragments evolved.fragment[]
---@param policies evolved.id[]
---@param count integer
---@return integer purged_count
local function __purge_fragments(fragments, policies, count)
if __defer_depth <= 0 then
__lua_error('purge operations should be deferred')
end
local purged_count = 0
for index = 1, count do
local fragment, policy = fragments[index], policies[index]
if policy == __DESTROY_ENTITY_POLICY then
purged_count = purged_count + __purge_fragment(fragment, __DESTROY_ENTITY_POLICY)
elseif policy == __REMOVE_FRAGMENT_POLICY then
purged_count = purged_count + __purge_fragment(fragment, __REMOVE_FRAGMENT_POLICY)
else
__lua_print(__lua_string_format('| evolved.lua | unknown ON_DESTROY policy (%s) on (%s)',
__id_name(policy), __id_name(fragment)))
end
end
return purged_count
end
---
---
---
---
---
---@param chunk evolved.chunk
---@param fragment evolved.fragment
---@param ... any component arguments
@@ -2180,18 +2248,38 @@ __chunk_destroy = function(chunk)
end
do
local purging_fragments = __acquire_table(__table_pool_tag.fragment_list)
local purging_policies = __acquire_table(__table_pool_tag.fragment_list)
local purging_count = 0
local entity_chunks = __entity_chunks
local entity_places = __entity_places
for place = 1, chunk_entity_count do
local entity = chunk_entities[place]
local entity_index = entity % 0x100000
if __minor_chunks[entity] then
purging_count = purging_count + 1
purging_policies[purging_count] = __chunk_get_components(chunk, place, __ON_DESTROY)
or __REMOVE_FRAGMENT_POLICY
purging_fragments[purging_count] = entity
end
entity_chunks[entity_index] = nil
entity_places[entity_index] = nil
__release_id(entity)
end
__detach_all_entities(chunk)
if purging_count > 0 then
__purge_fragments(purging_fragments, purging_policies, purging_count)
end
__release_table(__table_pool_tag.fragment_list, purging_fragments)
__release_table(__table_pool_tag.fragment_list, purging_policies)
end
__structural_changes = __structural_changes + chunk_entity_count
@@ -4965,14 +5053,10 @@ __evolved_clear = function(entity)
local chunk = entity_chunks[entity_index]
local place = entity_places[entity_index]
if not chunk then
return true, false
end
__defer()
do
if chunk.__has_remove_hooks then
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
@@ -4998,12 +5082,14 @@ __evolved_clear = function(entity)
end
end
__detach_entity(chunk, place)
if chunk then
__detach_entity(chunk, place)
entity_chunks[entity_index] = nil
entity_places[entity_index] = nil
entity_chunks[entity_index] = nil
entity_places[entity_index] = nil
__structural_changes = __structural_changes + 1
__structural_changes = __structural_changes + 1
end
end
__commit()
@@ -5031,15 +5117,10 @@ __evolved_destroy = function(entity)
local chunk = entity_chunks[entity_index]
local place = entity_places[entity_index]
if not chunk then
__release_id(entity)
return true, false
end
__defer()
do
if chunk.__has_remove_hooks then
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
@@ -5065,13 +5146,31 @@ __evolved_destroy = function(entity)
end
end
__release_id(entity)
__detach_entity(chunk, place)
do
local purging_fragment ---@type evolved.fragment?
local purging_policy ---@type evolved.id?
entity_chunks[entity_index] = nil
entity_places[entity_index] = nil
if __minor_chunks[entity] then
purging_fragment = entity
purging_policy = chunk and __chunk_get_components(chunk, place, __ON_DESTROY)
or __REMOVE_FRAGMENT_POLICY
end
__structural_changes = __structural_changes + 1
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)
end
end
end
__commit()