Aego Playground

Hot reload

Saving a script while the game runs (aego run, Play in the editor) swaps the code without restarting. The workspace builds a new generation from the saved files. At the start of the next frame (script.swap, PhaseFrameBegin, the VM stack is empty), every module of that generation is loaded into the same VM. Every live instance is then moved into the new layout, and the dynamic schema is replaced in the same transaction. If anything fails, nothing changes and the previous generation keeps running. A save that does not compile never produces a generation.

Instances keep their identity: InstanceID, node, heap strings and slices survive. Fields are matched by name (or @former), never by slot:

Change Result
same type value kept
new field its default
removed field dropped
incompatible type (float → string) default + warning, counted as reset
enum by member name; a removed member resets the field
struct field by field, recursively
[]T element by element; incompatible element type resets the slice
NodeRef, AssetRef, ComponentRef, ScriptRef kept
Coroutine kept as a value; see below for whether it is still running
Connection kept; rebound or invalidated, see below

After the swap, for every script whose package (or a dependency's interface) changed:

  1. its coroutines are cancelled: a coroutine's suspended state belongs to the old code; a Coroutine field keeps the old, no longer running handle;
  2. signal connections are rebound by signal name, parameter types and handler name; a connection whose signal or handler is gone, or whose signature changed, is removed and its Connection reports Connected() == false;
  3. func Reloaded() runs. Use it to restart coroutines:
func Reloaded() {
	if flash > 0 {
		blink = start Blink(6)
	}
}

Ready does not run again. Instances that faulted in a changed script resume running. Instances of a removed script stop. Coroutines and connections of unchanged scripts are untouched. The Console prints one line per reload: Hot reload N → N+1: X migrated, Y reset, Z coroutines canceled, W handlers disconnected, … ms; the same numbers appear in the Profiler's Scripts section. Changes in native/ are never swapped in-process: the supervisor rebuilds and restarts.