2.4 KiB
2.4 KiB
ADR 0004: Editor Gameplay Hot Reload
Status
Accepted
Context
Iterating on FPS controller feel (sim movement, player input, camera presentation) required restarting the entire editor after every Rust change. Full restarts are slow (GPU init, egui layout, scene reload) and break flow.
Competing approaches:
- Full editor restart — simple; too slow for gameplay iteration.
- Subprocess game binary — preserves editor shell; breaks in-process viewport render-to-texture (cross-process GPU sharing).
- In-process dylib hot reload — keeps one world and PIE model; swaps gameplay function bodies via
hot-lib-reloader.
Decision
Add dev-only in-process hot reload for the full GamePlugin surface:
| Layer | Crate | Hot reload? |
|---|---|---|
| Components, resources, TypeIds | protocol, shared, settings, sim |
Static (never swapped) |
| Gameplay system bodies | game_hot (cdylib + rlib) |
Yes |
| Plugin registration shell | game, editor |
Static |
| Editor UI | editor |
Static |
Implementation:
crates/game_hotholds#[unsafe(no_mangle)]systems (sim, player, world, rendering bootstrap).gameregisters systems once; withhot-reloadfeature,hot_modulewraps dylib functions.editorHotReloadPlugin(enabled viadevfeature) pollsLibReloadObserver, watches the dylib withnotify, shows status in the bottom bar, and supports Ctrl+Shift+R manual refresh.on_hot_reloadre-applies idempotent bootstrap (camera FX tags, ambient light); spawns guard against duplicate player/world entities.
Release builds omit hot-reload; shipped game binary links game_hot statically.
Consequences
- Gameplay iteration no longer requires editor restart for logic-only changes.
- Component layout or schedule graph changes still require a full restart (documented in README).
- Linux uses a single
target/directory; Windows may need separate bin/dylib target dirs to avoid DLL locking (follow-up). devfeature on editor implieshot-reload(not optional in daily dev workflow).