1
0
Fork 0
mirror of https://github.com/Reuh/ubiquitousse.git synced 2025-10-27 09:09:30 +00:00

ecs: simplify linked list implementation

This commit is contained in:
Étienne Fildadut 2022-10-11 14:52:56 +09:00
parent fe2bac6ebd
commit 99a19b11c5

View file

@ -98,6 +98,9 @@ local sprite = {
} }
]]-- ]]--
--- Special value used as the first element of each system's linked list of entities.
let head = {}
--- Recursively remove subsystems from a system. --- Recursively remove subsystems from a system.
let recDestroySystems = (system) let recDestroySystems = (system)
for i=#system.systems, 1, -1 do for i=#system.systems, 1, -1 do
@ -383,10 +386,11 @@ let system_mt = {
--- Private fields --- --- Private fields ---
--- First element of the linked list of entities: { entity, next_element }. --- First element of the linked list of entities: { entity, next_element }.
-- The default entity `head` is always added as a first element to simplify algorithms; remember to skip it.
-- @local -- @local
_first = nil, _first = nil,
--- Associative map of entities in the system and their previous linked list element (or `true` if first element). --- Hash map of entities in the system and their previous linked list element. Does not contain a key for the `head` entity.
-- This make the list effectively a doubly linked list, but with easy access to the previous element using this map (and therefore O(1) deletion). -- This make the list effectively a doubly linked list, but with fast access to the previous element using this map (and therefore O(1) deletion).
-- @local -- @local
_previous = nil, _previous = nil,
--- Amount of time waited since last update (if interval is set). --- Amount of time waited since last update (if interval is set).
@ -419,30 +423,20 @@ let system_mt = {
copy({ [@component] = @default }, e) copy({ [@component] = @default }, e)
end end
-- add to linked list -- add to linked list
if @_first == nil then let entity = @_first
@_first = { e, nil } while entity[2] ~= nil do -- no need to process first entity as it is the special `head` entity
@_previous[e] = true if @compare(e, entity[2][1]) then
elseif @compare(e, @_first[1]) then let nxt = entity[2]
let nxt = @_first entity[2] = { e, nxt }
@_first = { e, nxt }
@_previous[e] = true
@_previous[nxt[1]] = @_first
else
let entity = @_first
while entity[2] ~= nil do
if @compare(e, entity[2][1]) then
let nxt = entity[2]
entity[2] = { e, nxt }
@_previous[e] = entity
@_previous[nxt[1]] = entity[2]
break
end
entity = entity[2]
end
if entity[2] == nil then
entity[2] = { e, nil }
@_previous[e] = entity @_previous[e] = entity
@_previous[nxt[1]] = entity[2]
break
end end
entity = entity[2]
end
if entity[2] == nil then
entity[2] = { e, nil }
@_previous[e] = entity
end end
-- notify addition -- notify addition
@entityCount += 1 @entityCount += 1
@ -483,16 +477,9 @@ let system_mt = {
if @_previous[e] then -- recheck in case it was removed already from a subsystem onRemove callback if @_previous[e] then -- recheck in case it was removed already from a subsystem onRemove callback
-- remove from linked list -- remove from linked list
let prev = @_previous[e] let prev = @_previous[e]
if prev == true then prev[2] = prev[2][2]
@_first = @_first[2] if prev[2] then
if @_first then @_previous[prev[2][1]] = prev
@_previous[@_first[1]] = true
end
else
prev[2] = prev[2][2]
if prev[2] then
@_previous[prev[2][1]] = prev
end
end end
-- notify removal -- notify removal
@_previous[e] = nil @_previous[e] = nil
@ -545,43 +532,33 @@ let system_mt = {
-- @tparam Entity... ... other entities to reorder -- @tparam Entity... ... other entities to reorder
-- @treturn Entity,... `e,...` the function arguments -- @treturn Entity,... `e,...` the function arguments
reorder = :(e, ...) reorder = :(e, ...)
if e ~= nil then if e ~= nil and @_previous[e] then
if @_previous[e] then let prev = @_previous[e] -- { prev, { e, next } }
let prev = @_previous[e] -- { prev, { e, next } } let next = prev[2][2]
let next = prev == true and @_first[2] or prev[2][2] -- remove e from linked list
-- remove e from linked list prev[2] = next
if prev == true then if next then
@_first = @_first[2] @_previous[next[1]] = prev
else end
prev[2] = next -- find position so that prev < e <= next
end while prev[1] ~= head and @compare(e, prev[1]) do -- ensure prev < e
if next then next = prev
@_previous[next[1]] = prev prev = @_previous[prev[1]]
end end
-- find position so that prev < e <= next while next ~= nil and not @compare(e, next[1]) do -- ensure e <= next
while prev ~= true and @compare(e, prev[1]) do -- ensure prev < e prev = next
next = prev next = next[2]
prev = @_previous[prev[1]] end
end -- reinsert e in linked list
while next ~= nil and not @compare(e, next[1]) do -- ensure e <= next let new = { e, next }
prev = next @_previous[e] = prev
next = next[2] if next then
end @_previous[next[1]] = new
-- reinsert e in linked list end
let new = { e, next } prev[2] = new
@_previous[e] = prev -- Reorder in subsystems
if next then for _, s in ipairs(@systems) do
@_previous[next[1]] = new s:reorder(e)
end
if prev == true then
@_first = new
else
prev[2] = new
end
-- Reorder in subsystems
for _, s in ipairs(@systems) do
s:reorder(e)
end
end end
end end
if ... then if ... then
@ -607,7 +584,7 @@ let system_mt = {
--- Returns an iterator that iterate through the entties in this system, in order. --- Returns an iterator that iterate through the entties in this system, in order.
-- @treturn iterator iterator over the entities in this system -- @treturn iterator iterator over the entities in this system
iter = :() iter = :()
return nextEntity, { @_first } return nextEntity, { @_first[2] }
end, end,
--- Get the `i`th entity in the system. --- Get the `i`th entity in the system.
-- This is a simple wrapper around `iter`; it _will_ iterate over all the entities in the system in order until we reach the desired one. -- This is a simple wrapper around `iter`; it _will_ iterate over all the entities in the system in order until we reach the desired one.
@ -759,6 +736,7 @@ let recInstanciateSystems = (world, systems)
world = world, world = world,
w = world, w = world,
s = world.s, s = world.s,
_first = { head },
_previous = {}, _previous = {},
}, { }, {
__index = :(k) __index = :(k)
@ -813,6 +791,7 @@ ecs = {
let world = setmetatable({ let world = setmetatable({
filter = ecs.all(), filter = ecs.all(),
s = {}, s = {},
_first = { head },
_previous = {} _previous = {}
}, { __index = system_mt }) }, { __index = system_mt })
world.world = world world.world = world