mirror of
https://github.com/BlackMATov/evolved.lua.git
synced 2026-03-22 04:44:06 +07:00
Merge branch 'feature/realloc' into dev
This commit is contained in:
174
README.md
174
README.md
@@ -53,6 +53,7 @@
|
||||
- [Shared Components](#shared-components)
|
||||
- [Fragment Requirements](#fragment-requirements)
|
||||
- [Destruction Policies](#destruction-policies)
|
||||
- [Custom Component Storages](#custom-component-storages)
|
||||
- [Cheat Sheet](#cheat-sheet)
|
||||
- [Aliases](#aliases)
|
||||
- [Predefs](#predefs)
|
||||
@@ -61,6 +62,7 @@
|
||||
- [Chunk](#chunk)
|
||||
- [Builder](#builder)
|
||||
- [Changelog](#changelog)
|
||||
- [vX.Y.Z](#vxyz)
|
||||
- [v1.7.0](#v170)
|
||||
- [v1.6.0](#v160)
|
||||
- [v1.5.0](#v150)
|
||||
@@ -1153,6 +1155,145 @@ evolved.destroy(world)
|
||||
assert(not evolved.alive(entity))
|
||||
```
|
||||
|
||||
#### Custom Component Storages
|
||||
|
||||
In some cases, you might want custom storages for fragment components. For example, you might want to store components in a specialized way for performance reasons. The library provides two fragment traits for this purpose: [`evolved.REALLOC`](#evolvedrealloc) and [`evolved.COMPMOVE`](#evolvedcompmove).
|
||||
|
||||
The [`evolved.REALLOC`](#evolvedrealloc) trait expects a function that is called when the fragment storage needs to be reallocated. The [`evolved.COMPMOVE`](#evolvedcompmove) trait expects a function that is called when components need to be moved from one storage to another.
|
||||
|
||||
A canonical example of using custom storages is implementing a fragment that stores components in an FFI-backed storage for better processing performance in LuaJIT. This is an advanced topic and requires a good understanding of LuaJIT FFI and memory management. So I won't cover it here in detail, but here is a simple example to give you an idea of how it works. More information can be found on the [LuaJIT](https://luajit.org/ext_ffi.html) website.
|
||||
|
||||
```lua
|
||||
local ffi = require 'ffi'
|
||||
local evolved = require 'evolved'
|
||||
|
||||
--
|
||||
--
|
||||
-- Define FFI double storage realloc and compmove functions
|
||||
--
|
||||
--
|
||||
|
||||
local FFI_DOUBLE_TYPEOF = ffi.typeof('double')
|
||||
local FFI_DOUBLE_SIZEOF = ffi.sizeof(FFI_DOUBLE_TYPEOF)
|
||||
local FFI_DOUBLE_STORAGE_TYPEOF = ffi.typeof('double[?]')
|
||||
|
||||
---@param src ffi.cdata*?
|
||||
---@param src_size integer
|
||||
---@param dst_size integer
|
||||
---@return ffi.cdata*?
|
||||
local function FFI_DOUBLE_STORAGE_REALLOC(src, src_size, dst_size)
|
||||
if dst_size == 0 then
|
||||
-- freeing the src storage, just let the GC handle it
|
||||
return
|
||||
end
|
||||
|
||||
-- to support 1-based indexing, allocate one extra element
|
||||
local dst = ffi.new(FFI_DOUBLE_STORAGE_TYPEOF, dst_size + 1)
|
||||
|
||||
if src and src_size > 0 then
|
||||
-- handle both expanding and shrinking
|
||||
local min_size = math.min(src_size, dst_size)
|
||||
ffi.copy(dst + 1, src + 1, min_size * FFI_DOUBLE_SIZEOF)
|
||||
end
|
||||
|
||||
return dst
|
||||
end
|
||||
|
||||
---@param src ffi.cdata*
|
||||
---@param f integer
|
||||
---@param e integer
|
||||
---@param t integer
|
||||
---@param dst ffi.cdata*
|
||||
local function FFI_DOUBLE_STORAGE_COMPMOVE(src, f, e, t, dst)
|
||||
ffi.copy(dst + t, src + f, (e - f + 1) * FFI_DOUBLE_SIZEOF)
|
||||
end
|
||||
|
||||
--
|
||||
--
|
||||
-- Define fragments with our custom FFI storages
|
||||
--
|
||||
--
|
||||
|
||||
local POSITION_X = evolved.builder()
|
||||
:default(0)
|
||||
:realloc(FFI_DOUBLE_STORAGE_REALLOC)
|
||||
:compmove(FFI_DOUBLE_STORAGE_COMPMOVE)
|
||||
:build()
|
||||
|
||||
local POSITION_Y = evolved.builder()
|
||||
:default(0)
|
||||
:realloc(FFI_DOUBLE_STORAGE_REALLOC)
|
||||
:compmove(FFI_DOUBLE_STORAGE_COMPMOVE)
|
||||
:build()
|
||||
|
||||
local VELOCITY_X = evolved.builder()
|
||||
:default(0)
|
||||
:realloc(FFI_DOUBLE_STORAGE_REALLOC)
|
||||
:compmove(FFI_DOUBLE_STORAGE_COMPMOVE)
|
||||
:build()
|
||||
|
||||
local VELOCITY_Y = evolved.builder()
|
||||
:default(0)
|
||||
:realloc(FFI_DOUBLE_STORAGE_REALLOC)
|
||||
:compmove(FFI_DOUBLE_STORAGE_COMPMOVE)
|
||||
:build()
|
||||
|
||||
--
|
||||
--
|
||||
-- Define a movement system that uses these components
|
||||
--
|
||||
--
|
||||
|
||||
local MOVEMENT_SYSTEM = evolved.builder()
|
||||
:include(POSITION_X, POSITION_Y)
|
||||
:include(VELOCITY_X, VELOCITY_Y)
|
||||
:execute(function(chunk, entity_list, entity_count, delta_time)
|
||||
local position_xs, position_ys = chunk:components(POSITION_X, POSITION_Y)
|
||||
local velocity_xs, velocity_ys = chunk:components(VELOCITY_X, VELOCITY_Y)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local px, py = position_xs[i], position_ys[i]
|
||||
local vx, vy = velocity_xs[i], velocity_ys[i]
|
||||
|
||||
px = px + vx * delta_time
|
||||
py = py + vy * delta_time
|
||||
|
||||
position_xs[i], position_ys[i] = px, py
|
||||
end
|
||||
end):build()
|
||||
|
||||
--
|
||||
--
|
||||
-- Spawn some entities with these components
|
||||
--
|
||||
--
|
||||
|
||||
do
|
||||
local entity_list, entity_count = evolved.builder()
|
||||
:set(POSITION_X)
|
||||
:set(POSITION_Y)
|
||||
:set(VELOCITY_X)
|
||||
:set(VELOCITY_Y)
|
||||
:multi_build(10000)
|
||||
|
||||
for i = 1, entity_count do
|
||||
local entity = entity_list[i]
|
||||
evolved.set(entity, POSITION_X, math.random(0, 640))
|
||||
evolved.set(entity, POSITION_Y, math.random(0, 480))
|
||||
evolved.set(entity, VELOCITY_X, math.random(-100, 100))
|
||||
evolved.set(entity, VELOCITY_Y, math.random(-100, 100))
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
--
|
||||
-- Process the movement system with a delta time payload
|
||||
--
|
||||
--
|
||||
|
||||
evolved.process_with(MOVEMENT_SYSTEM, 0.016)
|
||||
```
|
||||
|
||||
## Cheat Sheet
|
||||
|
||||
### Aliases
|
||||
@@ -1171,6 +1312,9 @@ storage :: component[]
|
||||
default :: component
|
||||
duplicate :: {component -> component}
|
||||
|
||||
realloc :: {storage?, integer, integer -> storage?}
|
||||
compmove :: {storage, integer, integer, integer, storage}
|
||||
|
||||
execute :: {chunk, entity[], integer, any...}
|
||||
prologue :: {any...}
|
||||
epilogue :: {any...}
|
||||
@@ -1200,6 +1344,9 @@ INTERNAL :: fragment
|
||||
DEFAULT :: fragment
|
||||
DUPLICATE :: fragment
|
||||
|
||||
REALLOC :: fragment
|
||||
COMPMOVE :: fragment
|
||||
|
||||
PREFAB :: fragment
|
||||
DISABLED :: fragment
|
||||
|
||||
@@ -1335,6 +1482,9 @@ builder_mt:internal :: builder
|
||||
builder_mt:default :: component -> builder
|
||||
builder_mt:duplicate :: {component -> component} -> builder
|
||||
|
||||
builder_mt:realloc :: {storage?, integer, integer -> storage?} -> builder
|
||||
builder_mt:compmove :: {storage, integer, integer, integer, storage} -> builder
|
||||
|
||||
builder_mt:prefab :: builder
|
||||
builder_mt:disabled :: builder
|
||||
|
||||
@@ -1361,6 +1511,10 @@ builder_mt:destruction_policy :: id -> builder
|
||||
|
||||
## Changelog
|
||||
|
||||
### vX.Y.Z
|
||||
|
||||
- Added the new [`evolved.REALLOC`](#evolvedrealloc) and [`evolved.COMPMOVE`](#evolvedcompmove) fragment traits that allow customizing component storages
|
||||
|
||||
### v1.7.0
|
||||
|
||||
- Added the new [`evolved.VARIANTS`](#evolvedvariants) query fragment that allows specifying any of multiple fragments in queries
|
||||
@@ -1430,6 +1584,10 @@ builder_mt:destruction_policy :: id -> builder
|
||||
|
||||
### `evolved.DUPLICATE`
|
||||
|
||||
### `evolved.REALLOC`
|
||||
|
||||
### `evolved.COMPMOVE`
|
||||
|
||||
### `evolved.PREFAB`
|
||||
|
||||
### `evolved.DISABLED`
|
||||
@@ -2047,6 +2205,22 @@ function evolved.builder_mt:default(default) end
|
||||
function evolved.builder_mt:duplicate(duplicate) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:realloc`
|
||||
|
||||
```lua
|
||||
---@param realloc evolved.realloc
|
||||
---@return evolved.builder builder
|
||||
function evolved.builder_mt:realloc(realloc) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:compmove`
|
||||
|
||||
```lua
|
||||
---@param compmove evolved.compmove
|
||||
---@return evolved.builder builder
|
||||
function evolved.builder_mt:compmove(compmove) end
|
||||
```
|
||||
|
||||
#### `evolved.builder_mt:prefab`
|
||||
|
||||
```lua
|
||||
|
||||
@@ -10,7 +10,12 @@
|
||||
## Thoughts
|
||||
|
||||
- We should have a way to not copy components on deferred spawn/clone
|
||||
- Not all assoc_list_remove operations need to keep order, we can have an unordered variant also
|
||||
- We still have several places where we use __lua_next without deterministic order, we should fix that
|
||||
- Having a light version of the gargabe collector can be useful for some use-cases
|
||||
- We can shrink the table pool tables on garbage collection if they are too large
|
||||
- Should we sort chunk children by fragment id?
|
||||
|
||||
## Known Issues
|
||||
|
||||
- Errors in hooks are cannot be handled properly right now
|
||||
- Errors in hooks or rellocs/compmoves are cannot be handled properly right now
|
||||
|
||||
@@ -8,6 +8,7 @@ require 'develop.testing.main_tests'
|
||||
require 'develop.testing.multi_spawn_tests'
|
||||
require 'develop.testing.name_tests'
|
||||
require 'develop.testing.process_with_tests'
|
||||
require 'develop.testing.realloc_tests'
|
||||
require 'develop.testing.requires_fragment_tests'
|
||||
require 'develop.testing.spawn_tests'
|
||||
require 'develop.testing.system_as_query_tests'
|
||||
@@ -35,3 +36,5 @@ print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.requires_fuzz'
|
||||
print '----------------------------------------'
|
||||
basics.describe_fuzz 'develop.fuzzing.unique_fuzz'
|
||||
|
||||
print 'All tests passed.'
|
||||
|
||||
588
develop/testing/realloc_tests.lua
Normal file
588
develop/testing/realloc_tests.lua
Normal file
@@ -0,0 +1,588 @@
|
||||
local evo = require 'evolved'
|
||||
|
||||
---@type ffilib?
|
||||
local ffi = (function()
|
||||
local ffi_loader = package and package.preload and package.preload['ffi']
|
||||
local ffi = ffi_loader and ffi_loader()
|
||||
return ffi
|
||||
end)()
|
||||
|
||||
if not ffi then
|
||||
return
|
||||
end
|
||||
|
||||
local FLOAT_TYPEOF = ffi.typeof('float')
|
||||
local FLOAT_SIZEOF = ffi.sizeof(FLOAT_TYPEOF)
|
||||
local FLOAT_STORAGE_TYPEOF = ffi.typeof('$[?]', FLOAT_TYPEOF)
|
||||
|
||||
local DOUBLE_TYPEOF = ffi.typeof('double')
|
||||
local DOUBLE_SIZEOF = ffi.sizeof(DOUBLE_TYPEOF)
|
||||
local DOUBLE_STORAGE_TYPEOF = ffi.typeof('$[?]', DOUBLE_TYPEOF)
|
||||
|
||||
local STORAGE_SIZES = {}
|
||||
|
||||
---@type evolved.realloc
|
||||
local function float_realloc(src, src_size, dst_size)
|
||||
if dst_size == 0 then
|
||||
assert(src and src_size > 0)
|
||||
local expected_src_size = STORAGE_SIZES[src]
|
||||
assert(expected_src_size == src_size)
|
||||
STORAGE_SIZES[src] = nil
|
||||
return
|
||||
else
|
||||
if src then
|
||||
assert(src_size > 0)
|
||||
local expected_src_size = STORAGE_SIZES[src]
|
||||
assert(expected_src_size == src_size)
|
||||
else
|
||||
assert(src_size == 0)
|
||||
end
|
||||
|
||||
local dst = ffi.new(FLOAT_STORAGE_TYPEOF, dst_size + 1)
|
||||
STORAGE_SIZES[dst] = dst_size
|
||||
|
||||
if src then
|
||||
ffi.copy(dst + 1, src + 1, math.min(src_size, dst_size) * FLOAT_SIZEOF)
|
||||
end
|
||||
|
||||
return dst
|
||||
end
|
||||
end
|
||||
|
||||
---@type evolved.realloc
|
||||
local function double_realloc(src, src_size, dst_size)
|
||||
if dst_size == 0 then
|
||||
assert(src and src_size > 0)
|
||||
local expected_src_size = STORAGE_SIZES[src]
|
||||
assert(expected_src_size == src_size)
|
||||
STORAGE_SIZES[src] = nil
|
||||
return
|
||||
else
|
||||
if src then
|
||||
assert(src_size > 0)
|
||||
local expected_src_size = STORAGE_SIZES[src]
|
||||
assert(expected_src_size == src_size)
|
||||
else
|
||||
assert(src_size == 0)
|
||||
end
|
||||
|
||||
local dst = ffi.new(DOUBLE_STORAGE_TYPEOF, dst_size + 1)
|
||||
STORAGE_SIZES[dst] = dst_size
|
||||
|
||||
if src then
|
||||
ffi.copy(dst + 1, src + 1, math.min(src_size, dst_size) * DOUBLE_SIZEOF)
|
||||
end
|
||||
|
||||
return dst
|
||||
end
|
||||
end
|
||||
|
||||
---@type evolved.compmove
|
||||
local function double_compmove(src, f, e, t, dst)
|
||||
ffi.copy(dst + t, src + f, (e - f + 1) * DOUBLE_SIZEOF)
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():realloc(double_realloc):build()
|
||||
|
||||
local e1 = evo.builder():set(f1, 21):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 21)
|
||||
|
||||
local e2 = evo.builder():set(f1, 42):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 21)
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 42)
|
||||
|
||||
local e3 = evo.builder():set(f1, 84):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 21)
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 42)
|
||||
assert(evo.has(e3, f1) and evo.get(e3, f1) == 84)
|
||||
|
||||
evo.destroy(e1)
|
||||
assert(not evo.has(e1, f1))
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 42)
|
||||
assert(evo.has(e3, f1) and evo.get(e3, f1) == 84)
|
||||
|
||||
evo.destroy(e3)
|
||||
assert(not evo.has(e1, f1))
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 42)
|
||||
assert(not evo.has(e3, f1))
|
||||
|
||||
evo.destroy(e2)
|
||||
assert(not evo.has(e1, f1))
|
||||
assert(not evo.has(e2, f1))
|
||||
assert(not evo.has(e3, f1))
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():realloc(double_realloc):build()
|
||||
local q1 = evo.builder():include(f1):build()
|
||||
|
||||
do
|
||||
local es, ec = {}, 10
|
||||
for i = 1, ec do es[i] = evo.spawn({ [f1] = i }) end
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == i) end
|
||||
end
|
||||
|
||||
do
|
||||
local p = evo.builder():set(f1, 42):build()
|
||||
local es, ec = {}, 10
|
||||
for i = 1, ec do es[i] = evo.clone(p) end
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42) end
|
||||
end
|
||||
|
||||
do
|
||||
local es1, ec1 = evo.multi_spawn(10, { [f1] = 42 })
|
||||
for i = 1, ec1 do assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 42) end
|
||||
|
||||
local es2, ec2 = evo.multi_spawn(20, { [f1] = 84 })
|
||||
for i = 1, ec1 do assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 42) end
|
||||
for i = 1, ec2 do assert(evo.has(es2[i], f1) and evo.get(es2[i], f1) == 84) end
|
||||
end
|
||||
|
||||
do
|
||||
local p = evo.builder():set(f1, 21):build()
|
||||
|
||||
local es1, ec1 = evo.multi_clone(10, p)
|
||||
for i = 1, ec1 do assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 21) end
|
||||
|
||||
local es2, ec2 = evo.multi_clone(20, p)
|
||||
for i = 1, ec1 do assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 21) end
|
||||
for i = 1, ec2 do assert(evo.has(es2[i], f1) and evo.get(es2[i], f1) == 21) end
|
||||
end
|
||||
|
||||
evo.batch_destroy(q1)
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():realloc(double_realloc):build()
|
||||
local f2 = evo.builder():realloc(double_realloc):build()
|
||||
|
||||
local q1 = evo.builder():include(f1):build()
|
||||
local q2 = evo.builder():include(f2):build()
|
||||
|
||||
do
|
||||
local e = evo.builder():set(f1, 21):set(f2, 42):build()
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 21)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 42)
|
||||
|
||||
evo.remove(e, f1)
|
||||
|
||||
assert(not evo.has(e, f1))
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 42)
|
||||
end
|
||||
|
||||
do
|
||||
local e = evo.builder():set(f1, 21):set(f2, 42):build()
|
||||
assert(evo.has(e, f1) and evo.get(e, f1) == 21)
|
||||
assert(evo.has(e, f2) and evo.get(e, f2) == 42)
|
||||
|
||||
evo.clear(e)
|
||||
|
||||
assert(not evo.has(e, f1))
|
||||
assert(not evo.has(e, f2))
|
||||
end
|
||||
|
||||
do
|
||||
local es, ec = evo.multi_spawn(10, { [f1] = 21, [f2] = 42 })
|
||||
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 21)
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 42)
|
||||
end
|
||||
|
||||
evo.batch_remove(q1, f1)
|
||||
|
||||
local e12 = evo.builder():set(f1, 1):set(f2, 2):build()
|
||||
assert(evo.has(e12, f1) and evo.get(e12, f1) == 1)
|
||||
assert(evo.has(e12, f2) and evo.get(e12, f2) == 2)
|
||||
|
||||
for i = 1, ec do
|
||||
assert(not evo.has(es[i], f1))
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 42)
|
||||
end
|
||||
|
||||
evo.batch_set(q2, f1, 84)
|
||||
|
||||
assert(evo.has(e12, f1) and evo.get(e12, f1) == 84)
|
||||
assert(evo.has(e12, f2) and evo.get(e12, f2) == 2)
|
||||
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 84)
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 42)
|
||||
end
|
||||
|
||||
evo.batch_set(q2, f1, 21)
|
||||
|
||||
assert(evo.has(e12, f1) and evo.get(e12, f1) == 21)
|
||||
assert(evo.has(e12, f2) and evo.get(e12, f2) == 2)
|
||||
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 21)
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 42)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():realloc(double_realloc):compmove(double_compmove):build()
|
||||
local f2 = evo.builder():realloc(double_realloc):compmove(double_compmove):build()
|
||||
|
||||
local q1 = evo.builder():include(f1):build()
|
||||
local q2 = evo.builder():include(f2):build()
|
||||
|
||||
do
|
||||
local es1, ec1 = evo.multi_spawn(10, { [f1] = 1, [f2] = 2 })
|
||||
|
||||
for i = 1, ec1 do
|
||||
assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 1)
|
||||
assert(evo.has(es1[i], f2) and evo.get(es1[i], f2) == 2)
|
||||
end
|
||||
|
||||
local es2, ec2 = evo.multi_spawn(20, { [f1] = 3, [f2] = 4 })
|
||||
|
||||
for i = 1, ec1 do
|
||||
assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 1)
|
||||
assert(evo.has(es1[i], f2) and evo.get(es1[i], f2) == 2)
|
||||
end
|
||||
|
||||
for i = 1, ec2 do
|
||||
assert(evo.has(es2[i], f1) and evo.get(es2[i], f1) == 3)
|
||||
assert(evo.has(es2[i], f2) and evo.get(es2[i], f2) == 4)
|
||||
end
|
||||
|
||||
local e2 = evo.builder():set(f2, 42):build()
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == 42)
|
||||
|
||||
evo.batch_remove(q1, f1)
|
||||
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == 42)
|
||||
|
||||
for i = 1, ec1 do
|
||||
assert(not evo.has(es1[i], f1))
|
||||
assert(evo.has(es1[i], f2) and evo.get(es1[i], f2) == 2)
|
||||
end
|
||||
|
||||
for i = 1, ec2 do
|
||||
assert(not evo.has(es2[i], f1))
|
||||
assert(evo.has(es2[i], f2) and evo.get(es2[i], f2) == 4)
|
||||
end
|
||||
|
||||
local e12 = evo.builder():set(f1, 21):set(f2, 42):build()
|
||||
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == 42)
|
||||
assert(evo.has(e12, f1) and evo.get(e12, f1) == 21)
|
||||
assert(evo.has(e12, f2) and evo.get(e12, f2) == 42)
|
||||
|
||||
evo.batch_set(q2, f1, 84)
|
||||
|
||||
assert(evo.has(e2, f2) and evo.get(e2, f2) == 42)
|
||||
assert(evo.has(e12, f1) and evo.get(e12, f1) == 84)
|
||||
assert(evo.has(e12, f2) and evo.get(e12, f2) == 42)
|
||||
|
||||
for i = 1, ec1 do
|
||||
assert(evo.has(es1[i], f1) and evo.get(es1[i], f1) == 84)
|
||||
assert(evo.has(es1[i], f2) and evo.get(es1[i], f2) == 2)
|
||||
end
|
||||
|
||||
for i = 1, ec2 do
|
||||
assert(evo.has(es2[i], f1) and evo.get(es2[i], f1) == 84)
|
||||
assert(evo.has(es2[i], f2) and evo.get(es2[i], f2) == 4)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():default(42):build()
|
||||
|
||||
local es, ec = evo.multi_spawn(10, { [f1] = 21 })
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 21) end
|
||||
|
||||
evo.set(f1, evo.TAG)
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == nil) end
|
||||
|
||||
evo.remove(f1, evo.TAG)
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42) end
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():realloc(float_realloc):build()
|
||||
|
||||
local e1 = evo.builder():set(f1, 3):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 3)
|
||||
|
||||
evo.set(f1, evo.REALLOC, double_realloc)
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 3)
|
||||
|
||||
evo.remove(f1, evo.REALLOC)
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 3)
|
||||
|
||||
evo.set(f1, evo.REALLOC, double_realloc)
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 3)
|
||||
end
|
||||
|
||||
do
|
||||
local f1 = evo.builder():realloc(double_realloc):build()
|
||||
|
||||
local es, ec = evo.multi_spawn(20, { [f1] = 42 })
|
||||
|
||||
for i = 1, ec / 2 do
|
||||
evo.destroy(es[ec - i + 1])
|
||||
end
|
||||
|
||||
evo.collect_garbage()
|
||||
|
||||
for i = 1, ec / 2 do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
evo.collect_garbage()
|
||||
|
||||
local f1 = evo.builder():name('f1'):realloc(double_realloc):compmove(double_compmove):build()
|
||||
local f2 = evo.builder():name('f2'):realloc(double_realloc):compmove(double_compmove):build()
|
||||
|
||||
local q1 = evo.builder():include(f1):build()
|
||||
local q2 = evo.builder():include(f2):build()
|
||||
|
||||
do
|
||||
local es, ec = evo.multi_spawn(40, { [f2] = 2 })
|
||||
for i = 1, ec do
|
||||
assert(not evo.has(es[i], f1))
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2)
|
||||
end
|
||||
evo.batch_destroy(q2)
|
||||
end
|
||||
|
||||
do
|
||||
local es, ec = evo.multi_spawn(50, { [f1] = 1, [f2] = 2 })
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 1)
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2)
|
||||
end
|
||||
|
||||
evo.batch_remove(q1, f1)
|
||||
for i = 1, ec do
|
||||
assert(not evo.has(es[i], f1))
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2)
|
||||
end
|
||||
|
||||
evo.batch_destroy(q1, q2)
|
||||
end
|
||||
|
||||
do
|
||||
evo.spawn({ [f1] = 1 })
|
||||
evo.spawn({ [f2] = 2 })
|
||||
evo.spawn({ [f1] = 1, [f2] = 2 })
|
||||
end
|
||||
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
do
|
||||
evo.collect_garbage()
|
||||
|
||||
local f1 = evo.builder():name('f1'):realloc(double_realloc):compmove(double_compmove):build()
|
||||
local f2 = evo.builder():name('f2'):realloc(double_realloc):compmove(double_compmove):build()
|
||||
|
||||
local q1 = evo.builder():include(f1):build()
|
||||
local q2 = evo.builder():include(f2):build()
|
||||
|
||||
do
|
||||
local es, ec = evo.multi_spawn(40, { [f1] = 1, [f2] = 2 })
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 1)
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2)
|
||||
end
|
||||
evo.batch_destroy(q2)
|
||||
end
|
||||
|
||||
do
|
||||
local es, ec = evo.multi_spawn(50, { [f1] = 1 })
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 1)
|
||||
assert(not evo.has(es[i], f2))
|
||||
end
|
||||
|
||||
evo.batch_set(q1, f2, 2)
|
||||
for i = 1, ec do
|
||||
assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 1)
|
||||
assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2)
|
||||
end
|
||||
|
||||
evo.batch_destroy(q1, q2)
|
||||
end
|
||||
|
||||
do
|
||||
evo.spawn({ [f1] = 1 })
|
||||
evo.spawn({ [f2] = 2 })
|
||||
evo.spawn({ [f1] = 1, [f2] = 2 })
|
||||
end
|
||||
|
||||
evo.collect_garbage()
|
||||
end
|
||||
|
||||
do
|
||||
evo.collect_garbage()
|
||||
|
||||
local alloc_call_count = 0
|
||||
local free_call_count = 0
|
||||
local resize_call_count = 0
|
||||
|
||||
local function ctor_realloc()
|
||||
---@type evolved.realloc
|
||||
return function(src, src_size, dst_size)
|
||||
if dst_size == 0 then
|
||||
assert(src and src_size > 0)
|
||||
free_call_count = free_call_count + 1
|
||||
return
|
||||
else
|
||||
if src then
|
||||
assert(src_size > 0)
|
||||
resize_call_count = resize_call_count + 1
|
||||
else
|
||||
assert(src_size == 0)
|
||||
alloc_call_count = alloc_call_count + 1
|
||||
end
|
||||
|
||||
local dst = {}
|
||||
|
||||
if src then
|
||||
for i = 1, math.min(src_size, dst_size) do
|
||||
dst[i] = src[i]
|
||||
end
|
||||
end
|
||||
|
||||
return dst
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local realloc1 = ctor_realloc()
|
||||
local realloc2 = ctor_realloc()
|
||||
|
||||
local f1 = evo.builder():default(44):realloc(realloc1):build()
|
||||
|
||||
alloc_call_count, free_call_count, resize_call_count = 0, 0, 0
|
||||
|
||||
do
|
||||
local e1 = evo.builder():set(f1, 21):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 21)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0)
|
||||
|
||||
local e2 = evo.builder():set(f1, 42):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 21)
|
||||
assert(evo.has(e2, f1) and evo.get(e2, f1) == 42)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0)
|
||||
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.destroy(e1)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.destroy(e2)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
end
|
||||
|
||||
alloc_call_count, free_call_count, resize_call_count = 0, 0, 0
|
||||
|
||||
do
|
||||
local es, ec = evo.multi_spawn(10, { [f1] = 84 })
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
for i = 1, ec / 2 do evo.destroy(es[i]) end
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 1)
|
||||
|
||||
evo.set(f1, evo.REALLOC, realloc2)
|
||||
assert(alloc_call_count == 2 and free_call_count == 1 and resize_call_count == 1)
|
||||
|
||||
for i = 1, ec do evo.destroy(es[i]) end
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 2 and free_call_count == 2 and resize_call_count == 1)
|
||||
end
|
||||
|
||||
alloc_call_count, free_call_count, resize_call_count = 0, 0, 0
|
||||
|
||||
do
|
||||
local e1 = evo.builder():set(f1, 24):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 24)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.set(f1, evo.TAG)
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == nil)
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
local es, ec = evo.multi_spawn(20, { [f1] = 48 })
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == nil) end
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
evo.remove(f1, evo.TAG)
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 44)
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 44) end
|
||||
assert(alloc_call_count == 2 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
evo.destroy(e1)
|
||||
for i = 1, ec do evo.destroy(es[i]) end
|
||||
assert(alloc_call_count == 2 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 2 and free_call_count == 2 and resize_call_count == 0)
|
||||
end
|
||||
|
||||
alloc_call_count, free_call_count, resize_call_count = 0, 0, 0
|
||||
|
||||
do
|
||||
local e1 = evo.builder():set(f1, 100):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 100)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.set(f1, evo.TAG)
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == nil)
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
local es, ec = evo.multi_spawn(20, { [f1] = 48 })
|
||||
for i = 1, ec do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == nil) end
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
evo.destroy(e1)
|
||||
for i = 1, ec do evo.destroy(es[i]) end
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
|
||||
evo.collect_garbage()
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
local realloc = ctor_realloc()
|
||||
|
||||
local f1 = evo.builder():realloc(realloc):build()
|
||||
|
||||
alloc_call_count, free_call_count, resize_call_count = 0, 0, 0
|
||||
|
||||
do
|
||||
local e1 = evo.builder():set(f1, 42):build()
|
||||
assert(evo.has(e1, f1) and evo.get(e1, f1) == 42)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.destroy(e1)
|
||||
assert(not evo.has(e1, f1) and evo.get(e1, f1) == nil)
|
||||
assert(alloc_call_count == 1 and free_call_count == 0 and resize_call_count == 0)
|
||||
|
||||
evo.set(f1, evo.TAG)
|
||||
assert(alloc_call_count == 1 and free_call_count == 1 and resize_call_count == 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -64,6 +64,9 @@
|
||||
default: function<Component>(self: Builder, default: Component): Builder
|
||||
duplicate: function<Component>(self: Builder, duplicate: function(Component): Component): Builder
|
||||
|
||||
realloc: function<Component>(self: Builder, realloc: function({ Component } | nil, integer, integer): { Component } | nil): Builder
|
||||
compmove: function<Component>(self: Builder, compmove: function({ Component }, integer, integer, integer, { Component })): Builder
|
||||
|
||||
prefab: function(self: Builder): Builder
|
||||
disabled: function(self: Builder): Builder
|
||||
|
||||
@@ -98,6 +101,9 @@
|
||||
DEFAULT: Fragment
|
||||
DUPLICATE: Fragment
|
||||
|
||||
REALLOC: Fragment
|
||||
COMPMOVE: Fragment
|
||||
|
||||
PREFAB: Fragment
|
||||
DISABLED: Fragment
|
||||
|
||||
|
||||
609
evolved.lua
609
evolved.lua
@@ -40,6 +40,9 @@ local evolved = {
|
||||
---@alias evolved.default evolved.component
|
||||
---@alias evolved.duplicate fun(component: evolved.component): evolved.component
|
||||
|
||||
---@alias evolved.realloc fun(src?: evolved.storage, src_size: integer, dst_size: integer): evolved.storage?
|
||||
---@alias evolved.compmove fun(src: evolved.storage, f: integer, e: integer, t: integer, dst: evolved.storage)
|
||||
|
||||
---@alias evolved.execute fun(
|
||||
--- chunk: evolved.chunk,
|
||||
--- entity_list: evolved.entity[],
|
||||
@@ -158,6 +161,7 @@ local __structural_changes = 0 ---@type integer
|
||||
---@field package __child_count integer
|
||||
---@field package __entity_list evolved.entity[]
|
||||
---@field package __entity_count integer
|
||||
---@field package __entity_capacity integer
|
||||
---@field package __fragment evolved.fragment
|
||||
---@field package __fragment_set table<evolved.fragment, integer>
|
||||
---@field package __fragment_list evolved.fragment[]
|
||||
@@ -168,6 +172,8 @@ local __structural_changes = 0 ---@type integer
|
||||
---@field package __component_fragments evolved.fragment[]
|
||||
---@field package __component_defaults evolved.default[]
|
||||
---@field package __component_duplicates evolved.duplicate[]
|
||||
---@field package __component_reallocs evolved.realloc[]
|
||||
---@field package __component_compmoves evolved.compmove[]
|
||||
---@field package __with_fragment_edges table<evolved.fragment, evolved.chunk>
|
||||
---@field package __without_fragment_edges table<evolved.fragment, evolved.chunk>
|
||||
---@field package __with_required_fragments? evolved.chunk
|
||||
@@ -971,6 +977,9 @@ local __INTERNAL = __acquire_id()
|
||||
local __DEFAULT = __acquire_id()
|
||||
local __DUPLICATE = __acquire_id()
|
||||
|
||||
local __REALLOC = __acquire_id()
|
||||
local __COMPMOVE = __acquire_id()
|
||||
|
||||
local __PREFAB = __acquire_id()
|
||||
local __DISABLED = __acquire_id()
|
||||
|
||||
@@ -1100,6 +1109,9 @@ local __id_name
|
||||
|
||||
local __new_chunk
|
||||
|
||||
local __default_realloc
|
||||
local __default_compmove
|
||||
|
||||
local __update_chunk_caches
|
||||
local __update_chunk_queries
|
||||
local __update_chunk_storages
|
||||
@@ -1144,6 +1156,8 @@ local __clone_entity
|
||||
local __multi_clone_entity
|
||||
|
||||
local __purge_chunk
|
||||
local __expand_chunk
|
||||
local __shrink_chunk
|
||||
local __clear_chunk_list
|
||||
local __destroy_entity_list
|
||||
local __destroy_fragment_list
|
||||
@@ -1170,8 +1184,6 @@ local __defer_multi_clone_entity
|
||||
---@return string
|
||||
---@nodiscard
|
||||
function __id_name(id)
|
||||
local id_primary, id_secondary = __evolved_unpack(id)
|
||||
|
||||
---@type string?
|
||||
local id_name = __evolved_get(id, __NAME)
|
||||
|
||||
@@ -1179,6 +1191,7 @@ function __id_name(id)
|
||||
return id_name
|
||||
end
|
||||
|
||||
local id_primary, id_secondary = __evolved_unpack(id)
|
||||
return __lua_string_format('$%d#%d:%d', id, id_primary, id_secondary)
|
||||
end
|
||||
|
||||
@@ -1221,6 +1234,7 @@ function __new_chunk(chunk_parent, chunk_fragment)
|
||||
__child_count = 0,
|
||||
__entity_list = {},
|
||||
__entity_count = 0,
|
||||
__entity_capacity = 0,
|
||||
__fragment = chunk_fragment,
|
||||
__fragment_set = chunk_fragment_set,
|
||||
__fragment_list = chunk_fragment_list,
|
||||
@@ -1231,6 +1245,8 @@ function __new_chunk(chunk_parent, chunk_fragment)
|
||||
__component_fragments = {},
|
||||
__component_defaults = {},
|
||||
__component_duplicates = {},
|
||||
__component_reallocs = {},
|
||||
__component_compmoves = {},
|
||||
__with_fragment_edges = {},
|
||||
__without_fragment_edges = {},
|
||||
__with_required_fragments = nil,
|
||||
@@ -1304,6 +1320,37 @@ function __new_chunk(chunk_parent, chunk_fragment)
|
||||
return chunk
|
||||
end
|
||||
|
||||
---@param src? evolved.storage
|
||||
---@param src_size integer
|
||||
---@param dst_size integer
|
||||
---@return evolved.storage?
|
||||
function __default_realloc(src, src_size, dst_size)
|
||||
if dst_size == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
if src and dst_size >= src_size then
|
||||
return src
|
||||
end
|
||||
|
||||
local dst = __lua_table_new(dst_size)
|
||||
|
||||
if src then
|
||||
__lua_table_move(src, 1, dst_size, 1, dst)
|
||||
end
|
||||
|
||||
return dst
|
||||
end
|
||||
|
||||
---@param src evolved.storage
|
||||
---@param f integer
|
||||
---@param e integer
|
||||
---@param t integer
|
||||
---@param dst evolved.storage
|
||||
function __default_compmove(src, f, e, t, dst)
|
||||
__lua_table_move(src, f, e, t, dst)
|
||||
end
|
||||
|
||||
---@param chunk evolved.chunk
|
||||
function __update_chunk_caches(chunk)
|
||||
local chunk_parent = chunk.__parent
|
||||
@@ -1415,6 +1462,7 @@ end
|
||||
---@param chunk evolved.chunk
|
||||
function __update_chunk_storages(chunk)
|
||||
local entity_count = chunk.__entity_count
|
||||
local entity_capacity = chunk.__entity_capacity
|
||||
|
||||
local fragment_list = chunk.__fragment_list
|
||||
local fragment_count = chunk.__fragment_count
|
||||
@@ -1425,29 +1473,49 @@ function __update_chunk_storages(chunk)
|
||||
local component_fragments = chunk.__component_fragments
|
||||
local component_defaults = chunk.__component_defaults
|
||||
local component_duplicates = chunk.__component_duplicates
|
||||
local component_reallocs = chunk.__component_reallocs
|
||||
local component_compmoves = chunk.__component_compmoves
|
||||
|
||||
for fragment_index = 1, fragment_count do
|
||||
local fragment = fragment_list[fragment_index]
|
||||
local component_index = component_indices[fragment]
|
||||
|
||||
---@type evolved.default?, evolved.duplicate?
|
||||
local fragment_default, fragment_duplicate =
|
||||
__evolved_get(fragment, __DEFAULT, __DUPLICATE)
|
||||
local component_index = component_indices[fragment]
|
||||
local component_realloc = component_index and component_reallocs[component_index]
|
||||
|
||||
---@type evolved.default?, evolved.duplicate?, evolved.realloc?, evolved.compmove?
|
||||
local fragment_default, fragment_duplicate, fragment_realloc, fragment_compmove =
|
||||
__evolved_get(fragment, __DEFAULT, __DUPLICATE, __REALLOC, __COMPMOVE)
|
||||
|
||||
local is_fragment_tag = __evolved_has(fragment, __TAG)
|
||||
|
||||
if component_index and is_fragment_tag then
|
||||
if entity_capacity > 0 then
|
||||
local component_storage = component_storages[component_index]
|
||||
|
||||
if component_realloc then
|
||||
component_realloc(component_storage, entity_capacity, 0)
|
||||
else
|
||||
__default_realloc(component_storage, entity_capacity, 0)
|
||||
end
|
||||
|
||||
component_storages[component_index] = nil
|
||||
end
|
||||
|
||||
if component_index ~= component_count then
|
||||
local last_component_storage = component_storages[component_count]
|
||||
local last_component_fragment = component_fragments[component_count]
|
||||
local last_component_default = component_defaults[component_count]
|
||||
local last_component_duplicate = component_duplicates[component_count]
|
||||
local last_component_realloc = component_reallocs[component_count]
|
||||
local last_component_compmove = component_compmoves[component_count]
|
||||
|
||||
component_indices[last_component_fragment] = component_index
|
||||
component_storages[component_index] = last_component_storage
|
||||
component_fragments[component_index] = last_component_fragment
|
||||
component_defaults[component_index] = last_component_default
|
||||
component_duplicates[component_index] = last_component_duplicate
|
||||
component_reallocs[component_index] = last_component_realloc
|
||||
component_compmoves[component_index] = last_component_compmove
|
||||
end
|
||||
|
||||
component_indices[fragment] = nil
|
||||
@@ -1455,6 +1523,8 @@ function __update_chunk_storages(chunk)
|
||||
component_fragments[component_count] = nil
|
||||
component_defaults[component_count] = nil
|
||||
component_duplicates[component_count] = nil
|
||||
component_reallocs[component_count] = nil
|
||||
component_compmoves[component_count] = nil
|
||||
|
||||
component_count = component_count - 1
|
||||
chunk.__component_count = component_count
|
||||
@@ -1462,32 +1532,93 @@ function __update_chunk_storages(chunk)
|
||||
component_count = component_count + 1
|
||||
chunk.__component_count = component_count
|
||||
|
||||
local component_storage = __lua_table_new(entity_count)
|
||||
local component_storage_index = component_count
|
||||
component_index = component_count
|
||||
|
||||
component_indices[fragment] = component_storage_index
|
||||
component_storages[component_storage_index] = component_storage
|
||||
component_fragments[component_storage_index] = fragment
|
||||
component_defaults[component_storage_index] = fragment_default
|
||||
component_duplicates[component_storage_index] = fragment_duplicate
|
||||
|
||||
if fragment_duplicate then
|
||||
for place = 1, entity_count do
|
||||
local new_component = fragment_default
|
||||
if new_component ~= nil then new_component = fragment_duplicate(new_component) end
|
||||
if new_component == nil then new_component = true end
|
||||
component_storage[place] = new_component
|
||||
end
|
||||
else
|
||||
local new_component = fragment_default
|
||||
if new_component == nil then new_component = true end
|
||||
for place = 1, entity_count do
|
||||
component_storage[place] = new_component
|
||||
end
|
||||
end
|
||||
elseif component_index then
|
||||
component_indices[fragment] = component_index
|
||||
component_storages[component_index] = nil
|
||||
component_fragments[component_index] = fragment
|
||||
component_defaults[component_index] = fragment_default
|
||||
component_duplicates[component_index] = fragment_duplicate
|
||||
component_reallocs[component_index] = fragment_realloc
|
||||
component_compmoves[component_index] = fragment_compmove
|
||||
|
||||
if entity_capacity > 0 then
|
||||
local new_component_storage ---@type evolved.storage?
|
||||
|
||||
if fragment_realloc then
|
||||
new_component_storage = fragment_realloc(nil, 0, entity_capacity)
|
||||
else
|
||||
new_component_storage = __default_realloc(nil, 0, entity_capacity)
|
||||
end
|
||||
|
||||
if not new_component_storage then
|
||||
__error_fmt('component storage allocation failed: chunk (%s), fragment (%s)',
|
||||
__lua_tostring(chunk), __id_name(fragment))
|
||||
end
|
||||
|
||||
if fragment_duplicate then
|
||||
for place = 1, entity_count do
|
||||
local new_component = fragment_default
|
||||
if new_component ~= nil then new_component = fragment_duplicate(new_component) end
|
||||
if new_component == nil then new_component = true end
|
||||
new_component_storage[place] = new_component
|
||||
end
|
||||
else
|
||||
local new_component = fragment_default
|
||||
if new_component == nil then new_component = true end
|
||||
for place = 1, entity_count do
|
||||
new_component_storage[place] = new_component
|
||||
end
|
||||
end
|
||||
|
||||
component_storages[component_index] = new_component_storage
|
||||
end
|
||||
elseif component_index then
|
||||
if fragment_realloc ~= component_realloc and entity_capacity > 0 then
|
||||
local new_component_storage ---@type evolved.storage?
|
||||
local old_component_storage = component_storages[component_index]
|
||||
|
||||
if fragment_realloc then
|
||||
new_component_storage = fragment_realloc(nil, 0, entity_capacity)
|
||||
else
|
||||
new_component_storage = __default_realloc(nil, 0, entity_capacity)
|
||||
end
|
||||
|
||||
if not new_component_storage then
|
||||
__error_fmt('component storage allocation failed: chunk (%s), fragment (%s)',
|
||||
__lua_tostring(chunk), __id_name(fragment))
|
||||
end
|
||||
|
||||
if fragment_duplicate then
|
||||
for place = 1, entity_count do
|
||||
local new_component = old_component_storage[place]
|
||||
if new_component == nil then new_component = fragment_default end
|
||||
if new_component ~= nil then new_component = fragment_duplicate(new_component) end
|
||||
if new_component == nil then new_component = true end
|
||||
new_component_storage[place] = new_component
|
||||
end
|
||||
else
|
||||
for place = 1, entity_count do
|
||||
local new_component = old_component_storage[place]
|
||||
if new_component == nil then new_component = fragment_default end
|
||||
if new_component == nil then new_component = true end
|
||||
new_component_storage[place] = new_component
|
||||
end
|
||||
end
|
||||
|
||||
if component_realloc then
|
||||
component_realloc(old_component_storage, entity_capacity, 0)
|
||||
else
|
||||
__default_realloc(old_component_storage, entity_capacity, 0)
|
||||
end
|
||||
|
||||
component_storages[component_index] = new_component_storage
|
||||
end
|
||||
|
||||
component_defaults[component_index] = fragment_default
|
||||
component_duplicates[component_index] = fragment_duplicate
|
||||
component_reallocs[component_index] = fragment_realloc
|
||||
component_compmoves[component_index] = fragment_compmove
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2159,27 +2290,16 @@ function __detach_entity(chunk, place)
|
||||
local component_count = chunk.__component_count
|
||||
local component_storages = chunk.__component_storages
|
||||
|
||||
if place == entity_count then
|
||||
entity_list[entity_count] = nil
|
||||
|
||||
for component_index = 1, component_count do
|
||||
local component_storage = component_storages[component_index]
|
||||
component_storage[entity_count] = nil
|
||||
end
|
||||
else
|
||||
if place ~= entity_count then
|
||||
local last_entity = entity_list[entity_count]
|
||||
local last_entity_primary = last_entity % 2 ^ 20
|
||||
entity_list[place] = last_entity
|
||||
|
||||
local last_entity_primary = last_entity % 2 ^ 20
|
||||
__entity_places[last_entity_primary] = place
|
||||
|
||||
entity_list[place] = last_entity
|
||||
entity_list[entity_count] = nil
|
||||
|
||||
for component_index = 1, component_count do
|
||||
local component_storage = component_storages[component_index]
|
||||
local last_entity_component = component_storage[entity_count]
|
||||
component_storage[place] = last_entity_component
|
||||
component_storage[entity_count] = nil
|
||||
component_storage[place] = component_storage[entity_count]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2188,18 +2308,6 @@ end
|
||||
|
||||
---@param chunk evolved.chunk
|
||||
function __detach_all_entities(chunk)
|
||||
local entity_list = chunk.__entity_list
|
||||
|
||||
local component_count = chunk.__component_count
|
||||
local component_storages = chunk.__component_storages
|
||||
|
||||
__lua_table_clear(entity_list)
|
||||
|
||||
for component_index = 1, component_count do
|
||||
local component_storage = component_storages[component_index]
|
||||
__lua_table_clear(component_storage)
|
||||
end
|
||||
|
||||
chunk.__entity_count = 0
|
||||
end
|
||||
|
||||
@@ -2230,9 +2338,6 @@ function __spawn_entity(chunk, entity, components)
|
||||
return
|
||||
end
|
||||
|
||||
local chunk_entity_list = chunk.__entity_list
|
||||
local chunk_entity_count = chunk.__entity_count
|
||||
|
||||
local chunk_component_count = chunk.__component_count
|
||||
local chunk_component_indices = chunk.__component_indices
|
||||
local chunk_component_storages = chunk.__component_storages
|
||||
@@ -2240,7 +2345,13 @@ function __spawn_entity(chunk, entity, components)
|
||||
local chunk_component_defaults = chunk.__component_defaults
|
||||
local chunk_component_duplicates = chunk.__component_duplicates
|
||||
|
||||
local place = chunk_entity_count + 1
|
||||
local place = chunk.__entity_count + 1
|
||||
|
||||
if place > chunk.__entity_capacity then
|
||||
__expand_chunk(chunk, place)
|
||||
end
|
||||
|
||||
local chunk_entity_list = chunk.__entity_list
|
||||
|
||||
do
|
||||
chunk.__entity_count = place
|
||||
@@ -2349,9 +2460,6 @@ function __multi_spawn_entity(chunk, entity_list, entity_count, components)
|
||||
return
|
||||
end
|
||||
|
||||
local chunk_entity_list = chunk.__entity_list
|
||||
local chunk_entity_count = chunk.__entity_count
|
||||
|
||||
local chunk_component_count = chunk.__component_count
|
||||
local chunk_component_indices = chunk.__component_indices
|
||||
local chunk_component_storages = chunk.__component_storages
|
||||
@@ -2359,8 +2467,14 @@ function __multi_spawn_entity(chunk, entity_list, entity_count, components)
|
||||
local chunk_component_defaults = chunk.__component_defaults
|
||||
local chunk_component_duplicates = chunk.__component_duplicates
|
||||
|
||||
local b_place = chunk_entity_count + 1
|
||||
local e_place = chunk_entity_count + entity_count
|
||||
local b_place = chunk.__entity_count + 1
|
||||
local e_place = b_place + entity_count - 1
|
||||
|
||||
if e_place > chunk.__entity_capacity then
|
||||
__expand_chunk(chunk, e_place)
|
||||
end
|
||||
|
||||
local chunk_entity_list = chunk.__entity_list
|
||||
|
||||
do
|
||||
chunk.__entity_count = e_place
|
||||
@@ -2500,9 +2614,6 @@ function __clone_entity(prefab, entity, components)
|
||||
return
|
||||
end
|
||||
|
||||
local chunk_entity_list = chunk.__entity_list
|
||||
local chunk_entity_count = chunk.__entity_count
|
||||
|
||||
local chunk_component_count = chunk.__component_count
|
||||
local chunk_component_indices = chunk.__component_indices
|
||||
local chunk_component_storages = chunk.__component_storages
|
||||
@@ -2513,7 +2624,13 @@ function __clone_entity(prefab, entity, components)
|
||||
local prefab_component_indices = prefab_chunk.__component_indices
|
||||
local prefab_component_storages = prefab_chunk.__component_storages
|
||||
|
||||
local place = chunk_entity_count + 1
|
||||
local place = chunk.__entity_count + 1
|
||||
|
||||
if place > chunk.__entity_capacity then
|
||||
__expand_chunk(chunk, place)
|
||||
end
|
||||
|
||||
local chunk_entity_list = chunk.__entity_list
|
||||
|
||||
do
|
||||
chunk.__entity_count = place
|
||||
@@ -2646,9 +2763,6 @@ function __multi_clone_entity(prefab, entity_list, entity_count, components)
|
||||
return
|
||||
end
|
||||
|
||||
local chunk_entity_list = chunk.__entity_list
|
||||
local chunk_entity_count = chunk.__entity_count
|
||||
|
||||
local chunk_component_count = chunk.__component_count
|
||||
local chunk_component_indices = chunk.__component_indices
|
||||
local chunk_component_storages = chunk.__component_storages
|
||||
@@ -2659,8 +2773,14 @@ function __multi_clone_entity(prefab, entity_list, entity_count, components)
|
||||
local prefab_component_indices = prefab_chunk.__component_indices
|
||||
local prefab_component_storages = prefab_chunk.__component_storages
|
||||
|
||||
local b_place = chunk_entity_count + 1
|
||||
local e_place = chunk_entity_count + entity_count
|
||||
local b_place = chunk.__entity_count + 1
|
||||
local e_place = b_place + entity_count - 1
|
||||
|
||||
if e_place > chunk.__entity_capacity then
|
||||
__expand_chunk(chunk, e_place)
|
||||
end
|
||||
|
||||
local chunk_entity_list = chunk.__entity_list
|
||||
|
||||
do
|
||||
chunk.__entity_count = e_place
|
||||
@@ -2779,6 +2899,10 @@ function __purge_chunk(chunk)
|
||||
__error_fmt('chunk should be empty before purging')
|
||||
end
|
||||
|
||||
if chunk.__entity_capacity > 0 then
|
||||
__shrink_chunk(chunk, 0)
|
||||
end
|
||||
|
||||
local chunk_parent = chunk.__parent
|
||||
local chunk_fragment = chunk.__fragment
|
||||
|
||||
@@ -2833,6 +2957,143 @@ function __purge_chunk(chunk)
|
||||
chunk.__unreachable_or_collected = true
|
||||
end
|
||||
|
||||
---@param chunk evolved.chunk
|
||||
---@param min_capacity integer
|
||||
function __expand_chunk(chunk, min_capacity)
|
||||
if __defer_depth <= 0 then
|
||||
__error_fmt('this operation should be deferred')
|
||||
end
|
||||
|
||||
local entity_count = chunk.__entity_count
|
||||
|
||||
if min_capacity < entity_count then
|
||||
min_capacity = entity_count
|
||||
end
|
||||
|
||||
local old_capacity = chunk.__entity_capacity
|
||||
if old_capacity >= min_capacity then
|
||||
-- no need to expand, the chunk is already large enough
|
||||
return
|
||||
end
|
||||
|
||||
local new_capacity = old_capacity * 2
|
||||
|
||||
if new_capacity < min_capacity then
|
||||
new_capacity = min_capacity
|
||||
end
|
||||
|
||||
if new_capacity < 4 then
|
||||
new_capacity = 4
|
||||
end
|
||||
|
||||
do
|
||||
local component_count = chunk.__component_count
|
||||
local component_storages = chunk.__component_storages
|
||||
local component_reallocs = chunk.__component_reallocs
|
||||
|
||||
for component_index = 1, component_count do
|
||||
local component_realloc = component_reallocs[component_index]
|
||||
|
||||
local new_component_storage ---@type evolved.storage?
|
||||
local old_component_storage = component_storages[component_index]
|
||||
|
||||
if component_realloc then
|
||||
new_component_storage = component_realloc(
|
||||
old_component_storage, old_capacity, new_capacity)
|
||||
else
|
||||
new_component_storage = __default_realloc(
|
||||
old_component_storage, old_capacity, new_capacity)
|
||||
end
|
||||
|
||||
if min_capacity > 0 and not new_component_storage then
|
||||
__error_fmt(
|
||||
'component storage reallocation failed: chunk (%s), fragment (%s)',
|
||||
__lua_tostring(chunk), __id_name(chunk.__component_fragments[component_index]))
|
||||
elseif min_capacity == 0 and new_component_storage then
|
||||
__warning_fmt(
|
||||
'component storage reallocation for zero capacity should return nil: chunk (%s), fragment (%s)',
|
||||
__lua_tostring(chunk), __id_name(chunk.__component_fragments[component_index]))
|
||||
new_component_storage = nil
|
||||
end
|
||||
|
||||
component_storages[component_index] = new_component_storage
|
||||
end
|
||||
end
|
||||
|
||||
chunk.__entity_capacity = new_capacity
|
||||
end
|
||||
|
||||
---@param chunk evolved.chunk
|
||||
---@param min_capacity integer
|
||||
function __shrink_chunk(chunk, min_capacity)
|
||||
if __defer_depth <= 0 then
|
||||
__error_fmt('this operation should be deferred')
|
||||
end
|
||||
|
||||
local entity_count = chunk.__entity_count
|
||||
|
||||
if min_capacity < entity_count then
|
||||
min_capacity = entity_count
|
||||
end
|
||||
|
||||
if min_capacity > 0 and min_capacity < 4 then
|
||||
min_capacity = 4
|
||||
end
|
||||
|
||||
local old_capacity = chunk.__entity_capacity
|
||||
if old_capacity <= min_capacity then
|
||||
-- no need to shrink, the chunk is already small enough
|
||||
return
|
||||
end
|
||||
|
||||
do
|
||||
local old_entity_list = chunk.__entity_list
|
||||
local new_entity_list = __lua_table_new(min_capacity)
|
||||
|
||||
__lua_table_move(
|
||||
old_entity_list, 1, entity_count,
|
||||
1, new_entity_list)
|
||||
|
||||
chunk.__entity_list = new_entity_list
|
||||
end
|
||||
|
||||
do
|
||||
local component_count = chunk.__component_count
|
||||
local component_storages = chunk.__component_storages
|
||||
local component_reallocs = chunk.__component_reallocs
|
||||
|
||||
for component_index = 1, component_count do
|
||||
local component_realloc = component_reallocs[component_index]
|
||||
|
||||
local new_component_storage ---@type evolved.storage?
|
||||
local old_component_storage = component_storages[component_index]
|
||||
|
||||
if component_realloc then
|
||||
new_component_storage = component_realloc(
|
||||
old_component_storage, old_capacity, min_capacity)
|
||||
else
|
||||
new_component_storage = __default_realloc(
|
||||
old_component_storage, old_capacity, min_capacity)
|
||||
end
|
||||
|
||||
if min_capacity > 0 and not new_component_storage then
|
||||
__error_fmt(
|
||||
'component storage reallocation failed: chunk (%s), fragment (%s)',
|
||||
__lua_tostring(chunk), __id_name(chunk.__component_fragments[component_index]))
|
||||
elseif min_capacity == 0 and new_component_storage then
|
||||
__warning_fmt(
|
||||
'component storage reallocation for zero capacity should return nil: chunk (%s), fragment (%s)',
|
||||
__lua_tostring(chunk), __id_name(chunk.__component_fragments[component_index]))
|
||||
new_component_storage = nil
|
||||
end
|
||||
|
||||
component_storages[component_index] = new_component_storage
|
||||
end
|
||||
end
|
||||
|
||||
chunk.__entity_capacity = min_capacity
|
||||
end
|
||||
|
||||
---@param chunk_list evolved.chunk[]
|
||||
---@param chunk_count integer
|
||||
function __clear_chunk_list(chunk_list, chunk_count)
|
||||
@@ -3152,11 +3413,10 @@ function __chunk_set(old_chunk, fragment, component)
|
||||
end
|
||||
end
|
||||
|
||||
local new_entity_list = new_chunk.__entity_list
|
||||
local new_entity_count = new_chunk.__entity_count
|
||||
|
||||
local new_component_indices = new_chunk.__component_indices
|
||||
local new_component_storages = new_chunk.__component_storages
|
||||
local new_component_reallocs = new_chunk.__component_reallocs
|
||||
local new_component_compmoves = new_chunk.__component_compmoves
|
||||
|
||||
local new_chunk_has_setup_hooks = new_chunk.__has_setup_hooks
|
||||
local new_chunk_has_insert_hooks = new_chunk.__has_insert_hooks
|
||||
@@ -3169,40 +3429,53 @@ function __chunk_set(old_chunk, fragment, component)
|
||||
__evolved_get(fragment, __DEFAULT, __DUPLICATE, __ON_SET, __ON_INSERT)
|
||||
end
|
||||
|
||||
local sum_entity_count = old_entity_count + new_entity_count
|
||||
local sum_entity_count = old_entity_count + new_chunk.__entity_count
|
||||
|
||||
if new_entity_count == 0 then
|
||||
old_chunk.__entity_list, new_chunk.__entity_list =
|
||||
new_entity_list, old_entity_list
|
||||
if sum_entity_count > new_chunk.__entity_capacity then
|
||||
__expand_chunk(new_chunk, sum_entity_count)
|
||||
end
|
||||
|
||||
old_entity_list, new_entity_list =
|
||||
new_entity_list, old_entity_list
|
||||
local new_entity_list = new_chunk.__entity_list
|
||||
local new_entity_count = new_chunk.__entity_count
|
||||
|
||||
for old_ci = 1, old_component_count do
|
||||
local old_f = old_component_fragments[old_ci]
|
||||
local new_ci = new_component_indices[old_f]
|
||||
|
||||
old_component_storages[old_ci], new_component_storages[new_ci] =
|
||||
new_component_storages[new_ci], old_component_storages[old_ci]
|
||||
end
|
||||
|
||||
new_chunk.__entity_count = sum_entity_count
|
||||
else
|
||||
do
|
||||
for old_ci = 1, old_component_count do
|
||||
local old_f = old_component_fragments[old_ci]
|
||||
local old_cs = old_component_storages[old_ci]
|
||||
|
||||
local new_ci = new_component_indices[old_f]
|
||||
local new_cs = new_component_storages[new_ci]
|
||||
local new_cr = new_component_reallocs[new_ci]
|
||||
local new_cm = new_component_compmoves[new_ci]
|
||||
|
||||
__lua_table_move(
|
||||
old_cs, 1, old_entity_count,
|
||||
new_entity_count + 1, new_cs)
|
||||
if new_cm then
|
||||
new_cm(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs)
|
||||
elseif new_cr then
|
||||
for old_place = 1, old_entity_count do
|
||||
local new_place = new_entity_count + old_place
|
||||
new_cs[new_place] = old_cs[old_place]
|
||||
end
|
||||
else
|
||||
if new_entity_count > 0 then
|
||||
__default_compmove(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs)
|
||||
else
|
||||
old_component_storages[old_ci], new_component_storages[new_ci] =
|
||||
new_component_storages[new_ci], old_component_storages[old_ci]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
__lua_table_move(
|
||||
old_entity_list, 1, old_entity_count,
|
||||
new_entity_count + 1, new_entity_list)
|
||||
if new_entity_count > 0 then
|
||||
__lua_table_move(
|
||||
old_entity_list, 1, old_entity_count,
|
||||
new_entity_count + 1, new_entity_list)
|
||||
else
|
||||
old_chunk.__entity_list, new_chunk.__entity_list =
|
||||
new_entity_list, old_entity_list
|
||||
|
||||
old_entity_list, new_entity_list =
|
||||
new_entity_list, old_entity_list
|
||||
end
|
||||
|
||||
new_chunk.__entity_count = sum_entity_count
|
||||
end
|
||||
@@ -3475,47 +3748,59 @@ function __chunk_remove(old_chunk, ...)
|
||||
end
|
||||
|
||||
if new_chunk then
|
||||
local new_entity_list = new_chunk.__entity_list
|
||||
local new_entity_count = new_chunk.__entity_count
|
||||
|
||||
local new_component_count = new_chunk.__component_count
|
||||
local new_component_storages = new_chunk.__component_storages
|
||||
local new_component_fragments = new_chunk.__component_fragments
|
||||
local new_component_reallocs = new_chunk.__component_reallocs
|
||||
local new_component_compmoves = new_chunk.__component_compmoves
|
||||
|
||||
local sum_entity_count = old_entity_count + new_entity_count
|
||||
local sum_entity_count = old_entity_count + new_chunk.__entity_count
|
||||
|
||||
if new_entity_count == 0 then
|
||||
old_chunk.__entity_list, new_chunk.__entity_list =
|
||||
new_entity_list, old_entity_list
|
||||
if sum_entity_count > new_chunk.__entity_capacity then
|
||||
__expand_chunk(new_chunk, sum_entity_count)
|
||||
end
|
||||
|
||||
old_entity_list, new_entity_list =
|
||||
new_entity_list, old_entity_list
|
||||
local new_entity_list = new_chunk.__entity_list
|
||||
local new_entity_count = new_chunk.__entity_count
|
||||
|
||||
for new_ci = 1, new_component_count do
|
||||
local new_f = new_component_fragments[new_ci]
|
||||
local old_ci = old_component_indices[new_f]
|
||||
|
||||
old_component_storages[old_ci], new_component_storages[new_ci] =
|
||||
new_component_storages[new_ci], old_component_storages[old_ci]
|
||||
end
|
||||
|
||||
new_chunk.__entity_count = sum_entity_count
|
||||
else
|
||||
do
|
||||
for new_ci = 1, new_component_count do
|
||||
local new_f = new_component_fragments[new_ci]
|
||||
local new_cs = new_component_storages[new_ci]
|
||||
local new_cr = new_component_reallocs[new_ci]
|
||||
local new_cm = new_component_compmoves[new_ci]
|
||||
|
||||
local old_ci = old_component_indices[new_f]
|
||||
local old_cs = old_component_storages[old_ci]
|
||||
|
||||
__lua_table_move(
|
||||
old_cs, 1, old_entity_count,
|
||||
new_entity_count + 1, new_cs)
|
||||
if new_cm then
|
||||
new_cm(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs)
|
||||
elseif new_cr then
|
||||
for old_place = 1, old_entity_count do
|
||||
local new_place = new_entity_count + old_place
|
||||
new_cs[new_place] = old_cs[old_place]
|
||||
end
|
||||
else
|
||||
if new_entity_count > 0 then
|
||||
__default_compmove(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs)
|
||||
else
|
||||
old_component_storages[old_ci], new_component_storages[new_ci] =
|
||||
new_component_storages[new_ci], old_component_storages[old_ci]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
__lua_table_move(
|
||||
old_entity_list, 1, old_entity_count,
|
||||
new_entity_count + 1, new_entity_list)
|
||||
if new_entity_count > 0 then
|
||||
__lua_table_move(
|
||||
old_entity_list, 1, old_entity_count,
|
||||
new_entity_count + 1, new_entity_list)
|
||||
else
|
||||
old_chunk.__entity_list, new_chunk.__entity_list =
|
||||
new_entity_list, old_entity_list
|
||||
|
||||
old_entity_list, new_entity_list =
|
||||
new_entity_list, old_entity_list
|
||||
end
|
||||
|
||||
new_chunk.__entity_count = sum_entity_count
|
||||
end
|
||||
@@ -3633,7 +3918,7 @@ local __defer_op = {
|
||||
}
|
||||
|
||||
---@type table<evolved.defer_op, fun(bytes: any[], index: integer): integer>
|
||||
local __defer_ops = __list_new(__defer_op.__count)
|
||||
local __defer_ops = __lua_table_new(__defer_op.__count)
|
||||
|
||||
---@param hook fun(...)
|
||||
---@param ... any hook arguments
|
||||
@@ -4243,7 +4528,7 @@ function __evolved_multi_spawn(entity_count, components)
|
||||
end
|
||||
end
|
||||
|
||||
local entity_list = __list_new(entity_count)
|
||||
local entity_list = __lua_table_new(entity_count)
|
||||
|
||||
for entity_index = 1, entity_count do
|
||||
entity_list[entity_index] = __acquire_id()
|
||||
@@ -4323,7 +4608,7 @@ function __evolved_multi_clone(entity_count, prefab, components)
|
||||
end
|
||||
end
|
||||
|
||||
local entity_list = __list_new(entity_count)
|
||||
local entity_list = __lua_table_new(entity_count)
|
||||
|
||||
for entity_index = 1, entity_count do
|
||||
entity_list[entity_index] = __acquire_id()
|
||||
@@ -4649,9 +4934,6 @@ function __evolved_set(entity, fragment, component)
|
||||
end
|
||||
end
|
||||
|
||||
local new_entity_list = new_chunk.__entity_list
|
||||
local new_entity_count = new_chunk.__entity_count
|
||||
|
||||
local new_component_indices = new_chunk.__component_indices
|
||||
local new_component_storages = new_chunk.__component_storages
|
||||
|
||||
@@ -4666,10 +4948,16 @@ function __evolved_set(entity, fragment, component)
|
||||
__evolved_get(fragment, __DEFAULT, __DUPLICATE, __ON_SET, __ON_INSERT)
|
||||
end
|
||||
|
||||
local new_place = new_entity_count + 1
|
||||
new_chunk.__entity_count = new_place
|
||||
local new_place = new_chunk.__entity_count + 1
|
||||
|
||||
if new_place > new_chunk.__entity_capacity then
|
||||
__expand_chunk(new_chunk, new_place)
|
||||
end
|
||||
|
||||
local new_entity_list = new_chunk.__entity_list
|
||||
|
||||
new_entity_list[new_place] = entity
|
||||
new_chunk.__entity_count = new_place
|
||||
|
||||
if old_chunk then
|
||||
local old_component_count = old_chunk.__component_count
|
||||
@@ -4855,17 +5143,20 @@ function __evolved_remove(entity, ...)
|
||||
end
|
||||
|
||||
if new_chunk then
|
||||
local new_entity_list = new_chunk.__entity_list
|
||||
local new_entity_count = new_chunk.__entity_count
|
||||
|
||||
local new_component_count = new_chunk.__component_count
|
||||
local new_component_storages = new_chunk.__component_storages
|
||||
local new_component_fragments = new_chunk.__component_fragments
|
||||
|
||||
local new_place = new_entity_count + 1
|
||||
new_chunk.__entity_count = new_place
|
||||
local new_place = new_chunk.__entity_count + 1
|
||||
|
||||
if new_place > new_chunk.__entity_capacity then
|
||||
__expand_chunk(new_chunk, new_place)
|
||||
end
|
||||
|
||||
local new_entity_list = new_chunk.__entity_list
|
||||
|
||||
new_entity_list[new_place] = entity
|
||||
new_chunk.__entity_count = new_place
|
||||
|
||||
for new_ci = 1, new_component_count do
|
||||
local new_f = new_component_fragments[new_ci]
|
||||
@@ -5463,12 +5754,21 @@ function __evolved_collect_garbage()
|
||||
for postorder_chunk_index = postorder_chunk_stack_size, 1, -1 do
|
||||
local postorder_chunk = postorder_chunk_stack[postorder_chunk_index]
|
||||
|
||||
local postorder_chunk_child_count = postorder_chunk.__child_count
|
||||
local postorder_chunk_entity_count = postorder_chunk.__entity_count
|
||||
local postorder_chunk_entity_capacity = postorder_chunk.__entity_capacity
|
||||
|
||||
local should_be_purged =
|
||||
postorder_chunk.__child_count == 0 and
|
||||
postorder_chunk.__entity_count == 0
|
||||
postorder_chunk_child_count == 0 and
|
||||
postorder_chunk_entity_count == 0
|
||||
|
||||
local should_be_shrunk =
|
||||
postorder_chunk_entity_count < postorder_chunk_entity_capacity
|
||||
|
||||
if should_be_purged then
|
||||
__purge_chunk(postorder_chunk)
|
||||
elseif should_be_shrunk then
|
||||
__shrink_chunk(postorder_chunk, 0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5771,7 +6071,7 @@ function __builder_mt:multi_spawn(entity_count)
|
||||
end
|
||||
end
|
||||
|
||||
local entity_list = __list_new(entity_count)
|
||||
local entity_list = __lua_table_new(entity_count)
|
||||
|
||||
for entity_index = 1, entity_count do
|
||||
entity_list[entity_index] = __acquire_id()
|
||||
@@ -5849,7 +6149,7 @@ function __builder_mt:multi_clone(entity_count, prefab)
|
||||
end
|
||||
end
|
||||
|
||||
local entity_list = __list_new(entity_count)
|
||||
local entity_list = __lua_table_new(entity_count)
|
||||
|
||||
for entity_index = 1, entity_count do
|
||||
entity_list[entity_index] = __acquire_id()
|
||||
@@ -6051,6 +6351,18 @@ function __builder_mt:duplicate(duplicate)
|
||||
return self:set(__DUPLICATE, duplicate)
|
||||
end
|
||||
|
||||
---@param realloc evolved.realloc
|
||||
---@return evolved.builder builder
|
||||
function __builder_mt:realloc(realloc)
|
||||
return self:set(__REALLOC, realloc)
|
||||
end
|
||||
|
||||
---@param compmove evolved.compmove
|
||||
---@return evolved.builder builder
|
||||
function __builder_mt:compmove(compmove)
|
||||
return self:set(__COMPMOVE, compmove)
|
||||
end
|
||||
|
||||
---@return evolved.builder builder
|
||||
function __builder_mt:prefab()
|
||||
return self:set(__PREFAB)
|
||||
@@ -6263,6 +6575,12 @@ __evolved_set(__DEFAULT, __ON_REMOVE, __update_major_chunks)
|
||||
__evolved_set(__DUPLICATE, __ON_INSERT, __update_major_chunks)
|
||||
__evolved_set(__DUPLICATE, __ON_REMOVE, __update_major_chunks)
|
||||
|
||||
__evolved_set(__REALLOC, __ON_SET, __update_major_chunks)
|
||||
__evolved_set(__REALLOC, __ON_REMOVE, __update_major_chunks)
|
||||
|
||||
__evolved_set(__COMPMOVE, __ON_SET, __update_major_chunks)
|
||||
__evolved_set(__COMPMOVE, __ON_REMOVE, __update_major_chunks)
|
||||
|
||||
---
|
||||
---
|
||||
---
|
||||
@@ -6279,6 +6597,9 @@ __evolved_set(__INTERNAL, __NAME, 'INTERNAL')
|
||||
__evolved_set(__DEFAULT, __NAME, 'DEFAULT')
|
||||
__evolved_set(__DUPLICATE, __NAME, 'DUPLICATE')
|
||||
|
||||
__evolved_set(__REALLOC, __NAME, 'REALLOC')
|
||||
__evolved_set(__COMPMOVE, __NAME, 'COMPMOVE')
|
||||
|
||||
__evolved_set(__PREFAB, __NAME, 'PREFAB')
|
||||
__evolved_set(__DISABLED, __NAME, 'DISABLED')
|
||||
|
||||
@@ -6320,6 +6641,9 @@ __evolved_set(__INTERNAL, __INTERNAL)
|
||||
__evolved_set(__DEFAULT, __INTERNAL)
|
||||
__evolved_set(__DUPLICATE, __INTERNAL)
|
||||
|
||||
__evolved_set(__REALLOC, __INTERNAL)
|
||||
__evolved_set(__COMPMOVE, __INTERNAL)
|
||||
|
||||
__evolved_set(__PREFAB, __INTERNAL)
|
||||
__evolved_set(__DISABLED, __INTERNAL)
|
||||
|
||||
@@ -6683,6 +7007,9 @@ evolved.INTERNAL = __INTERNAL
|
||||
evolved.DEFAULT = __DEFAULT
|
||||
evolved.DUPLICATE = __DUPLICATE
|
||||
|
||||
evolved.REALLOC = __REALLOC
|
||||
evolved.COMPMOVE = __COMPMOVE
|
||||
|
||||
evolved.PREFAB = __PREFAB
|
||||
evolved.DISABLED = __DISABLED
|
||||
|
||||
|
||||
Reference in New Issue
Block a user