Fix actors being GC'd during initialization (closes #9)

This commit is contained in:
~keith 2022-02-22 19:02:52 +00:00
parent 98d8b35a4f
commit 38447b2c7e
Signed by: keith
GPG Key ID: 5BEBEEAB2C73D520
5 changed files with 57 additions and 46 deletions

View File

@ -36,7 +36,7 @@
:initform nil) :initform nil)
(children :documentation "The actors this actor is a parent of." (children :documentation "The actors this actor is a parent of."
:reader children :reader children
:type (proper-list pointer) :type (proper-list (or actor id-ref))
:initform nil) :initform nil)
(components :documentation "The components attached to this actor." (components :documentation "The components attached to this actor."
:reader components :reader components
@ -89,13 +89,11 @@
(and (o! this active-p) (not (o! this :slot blocked-p)))) (and (o! this active-p) (not (o! this :slot blocked-p))))
(defmethod apply-to-tree ((this actor) fun) (defmethod apply-to-tree ((this actor) fun)
"Apply fun to this actor and all its children recursively."
(funcall fun this) (funcall fun this)
(loop for child-ptr in (o! this children) (loop for child in (o! this children)
when (typep child-ptr 'weak-pointer) when (typep child 'actor)
do (let ((child (weak-pointer-value child-ptr))) do (o! child (apply-to-tree fun))))
(unless child
(error "nil value dereferencing child-ptr in ~S" this))
(o! child (apply-to-tree fun)))))
(defmethod print-object ((this actor) stream) (defmethod print-object ((this actor) stream)
(print-unreadable-object (this stream :type t :identity t) (print-unreadable-object (this stream :type t :identity t)
@ -111,7 +109,7 @@
"Add a component to this object." "Add a component to this object."
(let ((component-class (class-of component))) (let ((component-class (class-of component)))
(when (o! this (get-component component-class)) (when (o! this (get-component component-class))
(error "~S already has a component of class ~S" this component-class)) (error "~S already has a component of class ~S" this component-class))
(push component (o! this :slot components)) (push component (o! this :slot components))
(o! component (attach this))) (o! component (attach this)))
component) component)
@ -119,8 +117,12 @@
(defmethod add-child ((this actor) child) (defmethod add-child ((this actor) child)
"Add a child to this object." "Add a child to this object."
(when (o! child parent) (when (o! child parent)
(error "~S is already a child of ~S" child (o! child parent))) (error "~S is already a child of ~S" child (o! child parent)))
(push (make-weak-pointer child) (o! this :slot children)) (unless (find-if (lambda (x) (etypecase x
(actor (eq x child))
(id-ref (eq (id-ref-actor x) (o! child id)))))
(o! this :slot children))
(push child (o! this :slot children)))
(setf (o! child :slot parent) (make-weak-pointer this)) (setf (o! child :slot parent) (make-weak-pointer this))
(o! child (parent-changed)) (o! child (parent-changed))
child) child)
@ -129,7 +131,11 @@
"Remove a child from this object." "Remove a child from this object."
(unless (eq (o! child parent) this) (unless (eq (o! child parent) this)
(error "~S is not a child of ~S" child this)) (error "~S is not a child of ~S" child this))
(setf (o! this :slot children) (delete child (o! this :slot children) :key #'deref-sus-pointer :count 1)) (setf (o! this :slot children)
(delete-if (lambda (x) (etypecase x
(actor (eq x child))
(id-ref (eq (id-ref-actor x) (o! child id)))))
(o! this :slot children) :count 1))
(setf (o! child :slot parent) nil) (setf (o! child :slot parent) nil)
(o! child (parent-changed)) (o! child (parent-changed))
child) child)
@ -164,8 +170,7 @@
(setf (o! this :slot active-p) nil)) (setf (o! this :slot active-p) nil))
(loop for component in (o! this components) (loop for component in (o! this components)
do (o! component (deactivate :origin (or origin this)))) do (o! component (deactivate :origin (or origin this))))
(loop for child-ptr in (o! this children) (loop for child in (o! this children)
for child = (weak-pointer-value child-ptr)
do (o! child (deactivate :origin (or origin this))))) do (o! child (deactivate :origin (or origin this)))))
(defmethod activate ((this actor) &key origin) (defmethod activate ((this actor) &key origin)
@ -174,8 +179,7 @@
(unless origin (unless origin
(setf (o! this :slot active-p) t)) (setf (o! this :slot active-p) t))
(when (o! this tree-active-p) (when (o! this tree-active-p)
(loop for child-ptr in (o! this children) (loop for child in (o! this children)
for child = (weak-pointer-value child-ptr)
when (o! child active-p) when (o! child active-p)
do (o! child (activate :origin (or origin this)))) do (o! child (activate :origin (or origin this))))
(loop for component in (o! this components) (loop for component in (o! this components)
@ -185,7 +189,6 @@
(defmethod resume ((this actor)) (defmethod resume ((this actor))
"Initialize or restore this actor's state." "Initialize or restore this actor's state."
(format t "=> actor resume: ~S~%" this)
;; Restore self ;; Restore self
(when (typep (o! this :slot scene) 'id-ref) (when (typep (o! this :slot scene) 'id-ref)
;; relink to scene ;; relink to scene
@ -199,29 +202,26 @@
(o! parent (add-child this)))) (o! parent (add-child this))))
(loop for entry on (o! this :slot children) (loop for entry on (o! this :slot children)
when (typep (car entry) 'id-ref) when (typep (car entry) 'id-ref)
do (rplaca entry (pointerize (car entry)))) do (rplaca entry (dereferize (car entry))))
;; Restore components ;; Restore components
(loop for component in (o! this components) (loop for component in (o! this components)
do (o! component (resume))) do (o! component (resume)))
;; Restore children ;; Restore children
(loop for child-ptr in (o! this children) (loop for child in (o! this children)
for child = (weak-pointer-value child-ptr)
do (o! child (resume)))) do (o! child (resume))))
(defmethod suspend ((this actor)) (defmethod suspend ((this actor))
"Prepare this actor for serialization." "Prepare this actor for serialization."
;; Suspend children ;; Suspend children
(loop for child-ptr in (o! this children) (loop for child in (o! this children)
for child = (weak-pointer-value child-ptr)
do (o! child (suspend))) do (o! child (suspend)))
;; Suspend components ;; Suspend components
(loop for component in (o! this components) (loop for component in (o! this components)
do (o! component (suspend))) do (o! component (suspend)))
;; Suspend self ;; Suspend self
(loop for child-cell on (o! this :slot children) (loop for child-cell on (o! this :slot children)
when (typep (car child-cell) 'weak-pointer) when (typep (car child-cell) 'actor)
do (rplaca child-cell (referize (car child-cell)))) do (rplaca child-cell (referize (car child-cell))))
(format t "suspend -- children: ~S~%" (o! this :slot children))
(referize-setf (o! this :slot scene)) (referize-setf (o! this :slot scene))
(referize-setf (o! this :slot parent))) (referize-setf (o! this :slot parent)))
@ -242,9 +242,10 @@
; Remove from parent ; Remove from parent
(when (o! this parent) (when (o! this parent)
(o! this parent (remove-child this))) (o! this parent (remove-child this)))
(loop for child-ptr in (o! this children) (loop for child in (o! this children)
for child = (deref-sus-pointer child-ptr) do (typecase child
do (o! child (destroy))) (id-ref (o! (dereferize child) (destroy)))
(t (o! child (destroy)))))
(when (o! this scene) (when (o! this scene)
(o! this scene (remove-actor this)))) (o! this scene (remove-actor this))))
(setf (o! this :slot destroyed-p) t)) (setf (o! this :slot destroyed-p) t))

View File

@ -67,14 +67,14 @@
(defun make-id () (defun make-id ()
"Return a unique ID." "Return a unique ID."
(setq *id-counter* (+ *id-counter* 1))) (setf *id-counter* (+ *id-counter* 1)))
(defun fixed-id (id) (defun fixed-id (id)
"Ensure the given ID won't be returned by make-id." "Ensure the given ID won't be returned by make-id."
(declare (type fixnum id)) (declare (type fixnum id))
(when (>= id *id-counter*) (when (>= id *id-counter*)
(setq *id-counter* (+ id 1))) (setf *id-counter* (+ id 1)))
id) id)
(defvar *world-scenes* () (defvar *world-scenes* ()

View File

@ -13,7 +13,7 @@
deref-pointer points-to ensure-live deref-pointer points-to ensure-live
vxy1 vxy-trunc vxy1 vxy-trunc
make-id fixed-id make-id fixed-id
*running-scenes* *world-scenes*
add-scene remove-scene get-scene update-all-scenes add-scene remove-scene get-scene update-all-scenes
initialize-actors-in initialize-actors-in
*view-width* *view-height* *view-ppu* *pixel-scale* *view-width* *view-height* *view-ppu* *pixel-scale*
@ -24,7 +24,7 @@
id-ref make-id-ref id-ref make-id-ref
pointer pointer
deref-sus-pointer deref-sus-pointer
referize pointerize referize dereferize pointerize
referize-setf pointerize-setf referize-setf pointerize-setf
make-generic-load-form make-generic-load-form
generate-load-forms generate-load-forms
@ -43,6 +43,7 @@
; methods ; methods
get-component add-component get-component add-component
add-child remove-child add-child remove-child
apply-to-tree
has-tag add-tag remove-tag has-tag add-tag remove-tag
parent-changed parent-changed
deactivate activate deactivate activate

View File

@ -65,7 +65,7 @@
(defmethod destroy ((this scene)) (defmethod destroy ((this scene))
"Mark this scene for unloading." "Mark this scene for unloading."
(unless (o! this destroyed-p) (unless (o! this destroyed-p)
; We're dead, clean up actors ;; We're dead, clean up actors
(loop for actor in (o! this actors) (loop for actor in (o! this actors)
do (o! actor (destroy))) do (o! actor (destroy)))
(remove-scene this)) (remove-scene this))
@ -76,8 +76,7 @@
;; Restore actors ;; Restore actors
(loop for actor in (o! this actors) (loop for actor in (o! this actors)
unless (o! actor :slot parent) unless (o! actor :slot parent)
do (format t "===> scene resume: ~S~%" actor) do (o! actor (resume))))
(o! actor (resume))))
(defmethod suspend ((this scene)) (defmethod suspend ((this scene))
"Prepare this scene for serialization." "Prepare this scene for serialization."

View File

@ -19,10 +19,11 @@
(null nil))) (null nil)))
(defun referize (ptr) (defun referize (ptr)
"Convert weak-pointer ptr into an id-ref." "Convert ptr into an id-ref."
(declare (type weak-pointer ptr))
(let ((target (weak-pointer-value ptr))) (let ((target (etypecase ptr
(weak-pointer (weak-pointer-value ptr))
((or scene actor component) ptr))))
(etypecase target (etypecase target
(scene (scene
(make-id-ref :scene (o! target id))) (make-id-ref :scene (o! target id)))
@ -41,22 +42,28 @@
:component (class-name (class-of target)))) :component (class-name (class-of target))))
))) )))
(defun pointerize (ref) (defun dereferize (ref)
"Convert id-ref ref into a weak-pointer." "Return the object specified by id-ref ref."
(declare (type id-ref ref)) (declare (type id-ref ref))
(let ((scene (get-scene (id-ref-scene ref))) actor component) (let ((scene (get-scene (id-ref-scene ref))) actor component)
(unless scene (unless scene
(error "can't pointerize ~S (scene not found)" ref)) (error "can't dereferize ~S (scene not found)" ref))
(if (id-ref-actor ref) (if (id-ref-actor ref)
(if (setf actor (o! scene (get-actor (id-ref-actor ref)))) (if (setf actor (o! scene (get-actor (id-ref-actor ref))))
(if (id-ref-component ref) (if (id-ref-component ref)
(if (setf component (o! actor (get-component (find-class (id-ref-component ref))))) (if (setf component (o! actor (get-component (find-class (id-ref-component ref)))))
(make-weak-pointer component) component
(error "can't pointerize ~S (component not found)" ref)) (error "can't dereferize ~S (component not found)" ref))
(make-weak-pointer actor)) actor)
(error "can't pointerize ~S (actor not found)" ref)) (error "can't dereferize ~S (actor not found)" ref))
(make-weak-pointer scene)))) scene)))
(defun pointerize (ref)
"Convert id-ref ref into a weak-pointer."
(declare (type id-ref ref))
(make-weak-pointer (dereferize ref)))
(defmacro referize-setf (place) (defmacro referize-setf (place)
`(when (typep ,place 'weak-pointer) `(when (typep ,place 'weak-pointer)
@ -224,8 +231,8 @@
(declare (type actor actor)) (declare (type actor actor))
(cons actor (cons actor
(loop for child-ptr in (o! actor children) (loop for child in (o! actor children)
nconc (collect-descendents (weak-pointer-value child-ptr))))) nconc (collect-descendents child))))
(defun dump-actors (actors &key (destroy-after t) (prune t) (nice-syms nil)) (defun dump-actors (actors &key (destroy-after t) (prune t) (nice-syms nil))
"Suspend and serialize actors." "Suspend and serialize actors."
@ -253,6 +260,9 @@
(let ((scene (eval scene-form))) (let ((scene (eval scene-form)))
(add-scene scene) (add-scene scene)
(o! scene (resume)) (o! scene (resume))
(loop for actor in (o! scene actors)
when (and (not (o! actor parent)) (o! actor active-p))
do (o! actor (activate)))
scene)) scene))
(defun load-resume-actors (actor-forms) (defun load-resume-actors (actor-forms)