mirror of
https://github.com/BlackMATov/evolved.lua.git
synced 2025-12-15 04:15:28 +07:00
update precached chunk flags on the fly
This commit is contained in:
@@ -3,9 +3,7 @@
|
|||||||
## Backlog
|
## Backlog
|
||||||
|
|
||||||
- optimize batch operations for cases with moving entities to empty chunks
|
- optimize batch operations for cases with moving entities to empty chunks
|
||||||
- should we clear chunk's components by on_insert tag callback?
|
|
||||||
- try to keep entity_chunks/places tables as arrays
|
- try to keep entity_chunks/places tables as arrays
|
||||||
- update chunk precached hook flags after adding/removing hooks
|
|
||||||
|
|
||||||
## After first release
|
## After first release
|
||||||
|
|
||||||
|
|||||||
@@ -6237,3 +6237,165 @@ do
|
|||||||
assert(assign_count == 8 and insert_count == 8 and remove_count == 8)
|
assert(assign_count == 8 and insert_count == 8 and remove_count == 8)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local f1, f2, f3, f4, f5 = evo.id(5)
|
||||||
|
|
||||||
|
local assign_count = 0
|
||||||
|
|
||||||
|
evo.set(f4, evo.ON_ASSIGN, function()
|
||||||
|
assign_count = assign_count + 1
|
||||||
|
end)
|
||||||
|
|
||||||
|
local e1 = evo.id()
|
||||||
|
assert(evo.insert(e1, f1, 41))
|
||||||
|
|
||||||
|
local e12 = evo.id()
|
||||||
|
assert(evo.insert(e12, f1, 41))
|
||||||
|
assert(evo.insert(e12, f2, 42))
|
||||||
|
|
||||||
|
local e35 = evo.id()
|
||||||
|
assert(evo.insert(e35, f3, 43))
|
||||||
|
assert(evo.insert(e35, f5, 45))
|
||||||
|
|
||||||
|
local e34 = evo.id()
|
||||||
|
assert(evo.insert(e34, f3, 43))
|
||||||
|
assert(evo.insert(e34, f4, 44))
|
||||||
|
|
||||||
|
evo.set(f1, evo.ON_ASSIGN, function()
|
||||||
|
assign_count = assign_count + 1
|
||||||
|
end)
|
||||||
|
|
||||||
|
evo.set(f3, evo.ON_ASSIGN, function()
|
||||||
|
assign_count = assign_count + 1
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert(assign_count == 0)
|
||||||
|
|
||||||
|
assert(evo.assign(e1, f1, 41))
|
||||||
|
assert(assign_count == 1)
|
||||||
|
|
||||||
|
assert(evo.assign(e12, f1, 42))
|
||||||
|
assert(assign_count == 2)
|
||||||
|
|
||||||
|
assert(evo.assign(e34, f3, 43))
|
||||||
|
assert(assign_count == 3)
|
||||||
|
|
||||||
|
assert(evo.assign(e35, f3, 43))
|
||||||
|
assert(assign_count == 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local f1, f2, f3 = evo.id(3)
|
||||||
|
local set_count = 0
|
||||||
|
|
||||||
|
evo.set(f1, evo.ON_SET, function() set_count = set_count + 1 end)
|
||||||
|
evo.set(f2, evo.ON_SET, function() set_count = set_count + 1 end)
|
||||||
|
evo.set(f3, evo.ON_SET, function() set_count = set_count + 1 end)
|
||||||
|
|
||||||
|
local e13 = evo.id()
|
||||||
|
assert(evo.set(e13, f1, 41) and evo.set(e13, f3, 43))
|
||||||
|
assert(set_count == 2)
|
||||||
|
|
||||||
|
local e123 = evo.id()
|
||||||
|
assert(evo.set(e123, f1, 41) and evo.set(e123, f2, 42) and evo.set(e123, f3, 43))
|
||||||
|
assert(set_count == 5)
|
||||||
|
|
||||||
|
assert(evo.assign(e123, f1, 41) and evo.assign(e123, f2, 42) and evo.assign(e123, f3, 43))
|
||||||
|
assert(set_count == 8)
|
||||||
|
|
||||||
|
do
|
||||||
|
set_count = 0
|
||||||
|
|
||||||
|
assert(evo.remove(f1, evo.ON_SET))
|
||||||
|
|
||||||
|
evo.set(e13, f1, 41)
|
||||||
|
assert(set_count == 0)
|
||||||
|
evo.set(e13, f3, 43)
|
||||||
|
assert(set_count == 1)
|
||||||
|
|
||||||
|
evo.set(e123, f1, 41)
|
||||||
|
assert(set_count == 1)
|
||||||
|
evo.set(e123, f2, 42)
|
||||||
|
assert(set_count == 2)
|
||||||
|
evo.set(e123, f3, 43)
|
||||||
|
assert(set_count == 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
set_count = 0
|
||||||
|
|
||||||
|
assert(evo.remove(f2, evo.ON_SET))
|
||||||
|
|
||||||
|
evo.set(e13, f1, 41)
|
||||||
|
assert(set_count == 0)
|
||||||
|
evo.set(e13, f3, 43)
|
||||||
|
assert(set_count == 1)
|
||||||
|
|
||||||
|
evo.set(e123, f1, 41)
|
||||||
|
assert(set_count == 1)
|
||||||
|
evo.set(e123, f2, 42)
|
||||||
|
assert(set_count == 1)
|
||||||
|
evo.set(e123, f3, 43)
|
||||||
|
assert(set_count == 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local f1, f2 = evo.id(2)
|
||||||
|
|
||||||
|
local e1 = evo.id()
|
||||||
|
assert(evo.insert(e1, f1, 41))
|
||||||
|
assert(evo.insert(e1, f2, 42))
|
||||||
|
|
||||||
|
evo.set(f1, evo.DEFAULT, 51)
|
||||||
|
evo.set(f2, evo.CONSTRUCT, function() return 52 end)
|
||||||
|
|
||||||
|
assert(evo.assign(e1, f1))
|
||||||
|
assert(evo.assign(e1, f2))
|
||||||
|
|
||||||
|
assert(evo.get(e1, f1) == 51)
|
||||||
|
assert(evo.get(e1, f2) == 52)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local f1, f2 = evo.id(2)
|
||||||
|
|
||||||
|
local e1 = evo.id()
|
||||||
|
assert(evo.insert(e1, f1, 41))
|
||||||
|
|
||||||
|
local e2 = evo.id()
|
||||||
|
assert(evo.insert(e2, f1, 41))
|
||||||
|
assert(evo.insert(e2, f2, 42))
|
||||||
|
|
||||||
|
assert(evo.get(e1, f1) == 41)
|
||||||
|
assert(evo.get(e2, f1) == 41)
|
||||||
|
assert(evo.get(e2, f2) == 42)
|
||||||
|
|
||||||
|
assert(evo.insert(f1, evo.TAG))
|
||||||
|
assert(evo.get(e1, f1) == nil)
|
||||||
|
assert(evo.get(e2, f1) == nil)
|
||||||
|
assert(evo.get(e2, f2) == 42)
|
||||||
|
|
||||||
|
assert(evo.remove(f1, evo.TAG))
|
||||||
|
assert(evo.get(e1, f1) == true)
|
||||||
|
assert(evo.get(e2, f1) == true)
|
||||||
|
assert(evo.get(e2, f2) == 42)
|
||||||
|
|
||||||
|
assert(evo.insert(f2, evo.TAG))
|
||||||
|
assert(evo.get(e1, f1) == true)
|
||||||
|
assert(evo.get(e2, f1) == true)
|
||||||
|
assert(evo.get(e2, f2) == nil)
|
||||||
|
|
||||||
|
assert(evo.insert(f2, evo.DEFAULT, 42))
|
||||||
|
assert(evo.remove(f2, evo.TAG))
|
||||||
|
assert(evo.get(e1, f1) == true)
|
||||||
|
assert(evo.get(e2, f1) == true)
|
||||||
|
assert(evo.get(e2, f2) == 42)
|
||||||
|
|
||||||
|
assert(evo.set(f1, evo.DEFAULT, 81))
|
||||||
|
assert(evo.set(f2, evo.DEFAULT, 82))
|
||||||
|
assert(evo.get(e1, f1) == true)
|
||||||
|
assert(evo.get(e2, f1) == true)
|
||||||
|
assert(evo.get(e2, f2) == 42)
|
||||||
|
end
|
||||||
|
|||||||
195
evolved.lua
195
evolved.lua
@@ -458,6 +458,47 @@ local function __component_construct(fragment, ...)
|
|||||||
return component == nil and true or component
|
return component == nil and true or component
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param fragment evolved.fragment
|
||||||
|
---@param trace fun(chunk: evolved.chunk, ...: any): boolean
|
||||||
|
---@param ... any additional trace arguments
|
||||||
|
local function __trace_fragment_chunks(fragment, trace, ...)
|
||||||
|
local major_chunks = __major_chunks[fragment]
|
||||||
|
|
||||||
|
if not major_chunks then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
---@type evolved.chunk[]
|
||||||
|
local chunk_stack = __acquire_table(__TABLE_POOL_TAG__CHUNK_STACK)
|
||||||
|
local chunk_stack_size = 0
|
||||||
|
|
||||||
|
for i = 1, #major_chunks do
|
||||||
|
local major_chunk = major_chunks[i]
|
||||||
|
chunk_stack_size = chunk_stack_size + 1
|
||||||
|
chunk_stack[chunk_stack_size] = major_chunk
|
||||||
|
end
|
||||||
|
|
||||||
|
while chunk_stack_size > 0 do
|
||||||
|
local chunk = chunk_stack[chunk_stack_size]
|
||||||
|
|
||||||
|
chunk_stack[chunk_stack_size] = nil
|
||||||
|
chunk_stack_size = chunk_stack_size - 1
|
||||||
|
|
||||||
|
if trace(chunk, ...) then
|
||||||
|
local chunk_children = chunk.__children
|
||||||
|
local chunk_child_count = chunk.__child_count
|
||||||
|
|
||||||
|
for i = 1, chunk_child_count do
|
||||||
|
local chunk_child = chunk_children[i]
|
||||||
|
chunk_stack_size = chunk_stack_size + 1
|
||||||
|
chunk_stack[chunk_stack_size] = chunk_child
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
__release_table(__TABLE_POOL_TAG__CHUNK_STACK, chunk_stack, true)
|
||||||
|
end
|
||||||
|
|
||||||
---@param entity evolved.entity
|
---@param entity evolved.entity
|
||||||
---@param fragment evolved.fragment
|
---@param fragment evolved.fragment
|
||||||
---@param new_component evolved.component
|
---@param new_component evolved.component
|
||||||
@@ -5273,10 +5314,138 @@ end
|
|||||||
---
|
---
|
||||||
---
|
---
|
||||||
|
|
||||||
evolved.set(evolved.TAG, evolved.TAG)
|
---@param chunk evolved.chunk
|
||||||
|
---@return boolean
|
||||||
|
local function __update_chunk_caches_trace(chunk)
|
||||||
|
local chunk_parent, chunk_fragment = chunk.__parent, chunk.__fragment
|
||||||
|
|
||||||
|
local has_defaults_or_constructs = (chunk_parent and chunk_parent.__has_defaults_or_constructs)
|
||||||
|
or evolved.has_any(chunk_fragment, evolved.DEFAULT, evolved.CONSTRUCT)
|
||||||
|
|
||||||
|
local has_set_or_assign_hooks = (chunk_parent and chunk_parent.__has_set_or_assign_hooks)
|
||||||
|
or evolved.has_any(chunk_fragment, evolved.ON_SET, evolved.ON_ASSIGN)
|
||||||
|
|
||||||
|
local has_set_or_insert_hooks = (chunk_parent and chunk_parent.__has_set_or_insert_hooks)
|
||||||
|
or evolved.has_any(chunk_fragment, evolved.ON_SET, evolved.ON_INSERT)
|
||||||
|
|
||||||
|
local has_remove_hooks = (chunk_parent and chunk_parent.__has_remove_hooks)
|
||||||
|
or evolved.has(chunk_fragment, evolved.ON_REMOVE)
|
||||||
|
|
||||||
|
chunk.__has_defaults_or_constructs = has_defaults_or_constructs
|
||||||
|
chunk.__has_set_or_assign_hooks = has_set_or_assign_hooks
|
||||||
|
chunk.__has_set_or_insert_hooks = has_set_or_insert_hooks
|
||||||
|
chunk.__has_remove_hooks = has_remove_hooks
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param fragment evolved.fragment
|
||||||
|
local function __update_fragment_hooks(fragment)
|
||||||
|
__trace_fragment_chunks(fragment, __update_chunk_caches_trace, fragment)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert(evolved.insert(evolved.ON_SET, evolved.ON_INSERT, __update_fragment_hooks))
|
||||||
|
assert(evolved.insert(evolved.ON_ASSIGN, evolved.ON_INSERT, __update_fragment_hooks))
|
||||||
|
assert(evolved.insert(evolved.ON_INSERT, evolved.ON_INSERT, __update_fragment_hooks))
|
||||||
|
assert(evolved.insert(evolved.ON_REMOVE, evolved.ON_INSERT, __update_fragment_hooks))
|
||||||
|
|
||||||
|
assert(evolved.insert(evolved.ON_SET, evolved.ON_REMOVE, __update_fragment_hooks))
|
||||||
|
assert(evolved.insert(evolved.ON_ASSIGN, evolved.ON_REMOVE, __update_fragment_hooks))
|
||||||
|
assert(evolved.insert(evolved.ON_INSERT, evolved.ON_REMOVE, __update_fragment_hooks))
|
||||||
|
assert(evolved.insert(evolved.ON_REMOVE, evolved.ON_REMOVE, __update_fragment_hooks))
|
||||||
|
|
||||||
|
---
|
||||||
|
---
|
||||||
|
---
|
||||||
|
---
|
||||||
|
---
|
||||||
|
|
||||||
|
---@param chunk evolved.chunk
|
||||||
|
---@param fragment evolved.fragment
|
||||||
|
---@return boolean
|
||||||
|
local function __update_chunk_tags_trace(chunk, fragment)
|
||||||
|
local component_count = chunk.__component_count
|
||||||
|
local component_indices = chunk.__component_indices
|
||||||
|
local component_storages = chunk.__component_storages
|
||||||
|
local component_fragments = chunk.__component_fragments
|
||||||
|
|
||||||
|
local component_index = component_indices[fragment]
|
||||||
|
|
||||||
|
if component_index and evolved.has(fragment, evolved.TAG) then
|
||||||
|
if component_index ~= component_count then
|
||||||
|
local last_component_storage = component_storages[component_count]
|
||||||
|
local last_component_fragment = component_fragments[component_count]
|
||||||
|
component_indices[last_component_fragment] = component_index
|
||||||
|
component_storages[component_index] = last_component_storage
|
||||||
|
component_fragments[component_index] = last_component_fragment
|
||||||
|
end
|
||||||
|
|
||||||
|
component_indices[fragment] = nil
|
||||||
|
component_storages[component_count] = nil
|
||||||
|
component_fragments[component_count] = nil
|
||||||
|
|
||||||
|
component_count = component_count - 1
|
||||||
|
chunk.__component_count = component_count
|
||||||
|
end
|
||||||
|
|
||||||
|
if not component_index and not evolved.has(fragment, evolved.TAG) then
|
||||||
|
component_count = component_count + 1
|
||||||
|
chunk.__component_count = component_count
|
||||||
|
|
||||||
|
local storage = {}
|
||||||
|
local storage_index = component_count
|
||||||
|
|
||||||
|
component_indices[fragment] = storage_index
|
||||||
|
component_storages[storage_index] = storage
|
||||||
|
component_fragments[storage_index] = fragment
|
||||||
|
|
||||||
|
local new_component = evolved.get(fragment, evolved.DEFAULT)
|
||||||
|
|
||||||
|
if new_component == nil then
|
||||||
|
new_component = true
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, chunk.__entity_count do
|
||||||
|
storage[i] = new_component
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function __update_fragment_tags(fragment)
|
||||||
|
__trace_fragment_chunks(fragment, __update_chunk_tags_trace, fragment)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param fragment evolved.fragment
|
||||||
|
local function __update_fragment_defaults(fragment)
|
||||||
|
__trace_fragment_chunks(fragment, __update_chunk_caches_trace, fragment)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param fragment evolved.fragment
|
||||||
|
local function __update_fragment_constructs(fragment)
|
||||||
|
__trace_fragment_chunks(fragment, __update_chunk_caches_trace, fragment)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert(evolved.insert(evolved.TAG, evolved.ON_INSERT, __update_fragment_tags))
|
||||||
|
assert(evolved.insert(evolved.TAG, evolved.ON_REMOVE, __update_fragment_tags))
|
||||||
|
|
||||||
|
assert(evolved.insert(evolved.DEFAULT, evolved.ON_INSERT, __update_fragment_defaults))
|
||||||
|
assert(evolved.insert(evolved.DEFAULT, evolved.ON_REMOVE, __update_fragment_defaults))
|
||||||
|
|
||||||
|
assert(evolved.insert(evolved.CONSTRUCT, evolved.ON_INSERT, __update_fragment_constructs))
|
||||||
|
assert(evolved.insert(evolved.CONSTRUCT, evolved.ON_REMOVE, __update_fragment_constructs))
|
||||||
|
|
||||||
|
---
|
||||||
|
---
|
||||||
|
---
|
||||||
|
---
|
||||||
|
---
|
||||||
|
|
||||||
|
assert(evolved.insert(evolved.TAG, evolved.TAG))
|
||||||
|
|
||||||
---@param ... evolved.fragment
|
---@param ... evolved.fragment
|
||||||
evolved.set(evolved.INCLUDES, evolved.CONSTRUCT, function(...)
|
assert(evolved.insert(evolved.INCLUDES, evolved.CONSTRUCT, function(...)
|
||||||
local fragment_count = select('#', ...)
|
local fragment_count = select('#', ...)
|
||||||
|
|
||||||
if fragment_count == 0 then
|
if fragment_count == 0 then
|
||||||
@@ -5291,11 +5460,11 @@ evolved.set(evolved.INCLUDES, evolved.CONSTRUCT, function(...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
return include_list
|
return include_list
|
||||||
end)
|
end))
|
||||||
|
|
||||||
---@param query evolved.query
|
---@param query evolved.query
|
||||||
---@param include_list evolved.fragment[]
|
---@param include_list evolved.fragment[]
|
||||||
evolved.set(evolved.INCLUDES, evolved.ON_SET, function(query, _, include_list)
|
assert(evolved.insert(evolved.INCLUDES, evolved.ON_SET, function(query, _, include_list)
|
||||||
local include_list_size = #include_list
|
local include_list_size = #include_list
|
||||||
|
|
||||||
---@type table<evolved.fragment, boolean>
|
---@type table<evolved.fragment, boolean>
|
||||||
@@ -5318,14 +5487,14 @@ evolved.set(evolved.INCLUDES, evolved.ON_SET, function(query, _, include_list)
|
|||||||
|
|
||||||
evolved.set(query, __INCLUDE_SET, include_set)
|
evolved.set(query, __INCLUDE_SET, include_set)
|
||||||
evolved.set(query, __SORTED_INCLUDE_LIST, sorted_include_list)
|
evolved.set(query, __SORTED_INCLUDE_LIST, sorted_include_list)
|
||||||
end)
|
end))
|
||||||
|
|
||||||
evolved.set(evolved.INCLUDES, evolved.ON_REMOVE, function(query)
|
assert(evolved.insert(evolved.INCLUDES, evolved.ON_REMOVE, function(query)
|
||||||
evolved.remove(query, __INCLUDE_SET, __SORTED_INCLUDE_LIST)
|
evolved.remove(query, __INCLUDE_SET, __SORTED_INCLUDE_LIST)
|
||||||
end)
|
end))
|
||||||
|
|
||||||
---@param ... evolved.fragment
|
---@param ... evolved.fragment
|
||||||
evolved.set(evolved.EXCLUDES, evolved.CONSTRUCT, function(...)
|
assert(evolved.insert(evolved.EXCLUDES, evolved.CONSTRUCT, function(...)
|
||||||
local fragment_count = select('#', ...)
|
local fragment_count = select('#', ...)
|
||||||
|
|
||||||
if fragment_count == 0 then
|
if fragment_count == 0 then
|
||||||
@@ -5340,11 +5509,11 @@ evolved.set(evolved.EXCLUDES, evolved.CONSTRUCT, function(...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
return exclude_list
|
return exclude_list
|
||||||
end)
|
end))
|
||||||
|
|
||||||
---@param query evolved.query
|
---@param query evolved.query
|
||||||
---@param exclude_list evolved.fragment[]
|
---@param exclude_list evolved.fragment[]
|
||||||
evolved.set(evolved.EXCLUDES, evolved.ON_SET, function(query, _, exclude_list)
|
assert(evolved.insert(evolved.EXCLUDES, evolved.ON_SET, function(query, _, exclude_list)
|
||||||
local exclude_list_size = #exclude_list
|
local exclude_list_size = #exclude_list
|
||||||
|
|
||||||
---@type table<evolved.fragment, boolean>
|
---@type table<evolved.fragment, boolean>
|
||||||
@@ -5367,11 +5536,11 @@ evolved.set(evolved.EXCLUDES, evolved.ON_SET, function(query, _, exclude_list)
|
|||||||
|
|
||||||
evolved.set(query, __EXCLUDE_SET, exclude_set)
|
evolved.set(query, __EXCLUDE_SET, exclude_set)
|
||||||
evolved.set(query, __SORTED_EXCLUDE_LIST, sorted_exclude_list)
|
evolved.set(query, __SORTED_EXCLUDE_LIST, sorted_exclude_list)
|
||||||
end)
|
end))
|
||||||
|
|
||||||
evolved.set(evolved.EXCLUDES, evolved.ON_REMOVE, function(query)
|
assert(evolved.insert(evolved.EXCLUDES, evolved.ON_REMOVE, function(query)
|
||||||
evolved.remove(query, __EXCLUDE_SET, __SORTED_EXCLUDE_LIST)
|
evolved.remove(query, __EXCLUDE_SET, __SORTED_EXCLUDE_LIST)
|
||||||
end)
|
end))
|
||||||
|
|
||||||
---
|
---
|
||||||
---
|
---
|
||||||
|
|||||||
Reference in New Issue
Block a user