Game/Frame Lifecycle
In contrast to event driven scripting like Roblox, games on All Out use a frame lifecycle model that allows you to run code when the game starts, each frame, and at the end of a session.
Last updated
In contrast to event driven scripting like Roblox, games on All Out use a frame lifecycle model that allows you to run code when the game starts, each frame, and at the end of a session.
All Out games run on a simple lifecycle: some callbacks happen once at startup, and some happen every frame.
You’ll implement these callbacks either:
Globally (top-level ao_* procs in main.csl), or
On components (methods like ao_update inside Player or your own Component subclasses)
If you’re looking for the “template” main.csl, see Getting Started with CSL.
These are top-level procs in main.csl:
ao_before_scene_loadRuns after the empty Scene is created but before its serialized entities and components are loaded. This is where you typically register definitions needed while the scene loads:
Item definitions (inventory system)
Currencies (economy system)
Global config values/constants
ao_startRuns once when the scene starts.
Common uses:
Spawn runtime entities/prefabs
Initialize global systems
Read game-wide save data
ao_update(dt)Runs every frame.
Common uses:
Game timers, wave managers
Spawning logic that depends on time
Gameplay rules
ao_late_update(dt)Runs every frame after ao_update.
Common uses:
Scene-wide work that depends on final positions/state for the frame
“Cleanup” work after updates
Player UI belongs in Player.ao_late_update, not this global callback.
Components (including Player) can implement:
ao_start()
ao_update(dt)
ao_late_update(dt)
ao_end()
ao_on_state_sync() (called when network state is synchronized)
ao_start() is not replayed for every client. When a client joins after an object has already started on the server, the synchronized component can arrive with its start lifecycle already complete. Do not use ao_start() for client-local presentation setup that every joining client must run; rebuild that presentation from synchronized state in ao_on_state_sync() instead.
Example:
Per-player state/logic: put it on Player (see Adding Player Logic)
Reusable entity behaviors: put them on custom components (see Entities and Components)
Global coordination / rules: put it in the global lifecycle (ao_* procs)
Global and component gameplay callbacks run on both the predicting client and the server. Do not guard gameplay with Game.is_server().
Draw all player UI from that player's ao_late_update call stack, wrapped in is_local_or_server(). Use is_local() only for player-specific visual overrides. State changed only under is_local() is replaced by the next server sync.
These are methods on Player_Base. Call them on a player reference, or as is_local_or_server() / is_local() inside a Player method (implicit this).
Last updated
Orbiter :: class : Component {
ao_start :: method() {
// init
}
ao_update :: method(dt: float) {
// per-frame behavior
}
ao_end :: method() {
// cleanup (when destroyed)
}
}