; SPDX-FileCopyrightText: 2023 Jummit
;
; SPDX-License-Identifier: GPL-3.0-or-later
;; An ECS world with systems and entities.
;; Provides a way to delete entities by their index while iterating.
(fn new-world [systems entities]
(local world entities)
(var to-remove {})
(var err nil)
(var err-timer nil)
(var shown {})
(fn world.remove [entity]
"Marks the entity to be deleted after at the end of the world.run call."
(tset to-remove entity true))
(fn world.replace [entities]
"Replaces all entities with the given ones."
(table.move entities 1 (length entities) 1 world)
(tset world (+ (length world) 1) nil))
(fn clear-removed []
(let [remove-order (icollect [id _ (pairs to-remove)] id)]
(table.sort remove-order (fn [a b] (< b a)))
(each [_ i (ipairs remove-order)]
(table.remove world i))
(set to-remove {})))
(fn world.run []
"Run all systems once."
(each [_ system (ipairs systems)]
(case (xpcall (fn [] (system world)) debug.traceback)
(false msg)
(when (not (. shown msg))
(tset shown msg true)
(_G.trace msg)
(set err msg)
(set err-timer 300))))
(when err
(set err-timer (- err-timer 1))
(_G.rect 0 0 300 8 15)
(_G.print (string.match err "[^\n]+") 1 1 2 false 1 true)
(when (< err-timer 0)
(set err nil)))
(clear-removed))
world)
{: new-world}