S&box Wiki

Event System

The event system is like the Hook system in Garry's Mod. It allows you to register functions on classes to receive a callback on certain global events.

Setting up your Class

Entities and panels are automatically registered/unregistered for you - for everything else, you just need to call Event.Register and Event.Unregister:

public class TeamManager { public TeamManager() { Event.Register( this ); // Do this on things that aren't entities or panels } [Event.Tick] public void OnTick() { Log.Trace( "blah" ); } ~TeamManager() { Event.Unregister( this ); } }

Registering a callback

Adding an [Event] attribute will add it to the list to be called.

[Event( "server.tick" )] public void MyCallback() { // will get called every server tick }

Engine events

The various events called from the engine currently:


Called clientside every frame to process input and encode outputs into a user command.

[Event.BuildInput] public void MyBuildInput( InputBuilder input ) { }


Called when a client disconnects.

[Event( "client.disconnected" )]

Called from GameLoop.ClientDisconnected


Called just before the beginning of a rendering frame.


Called from GameLoop.PreRender


Called every server or client tick (60 times a second by default).

[Event.Tick] [Event( "server.tick" )] [Event( "client.tick" )]

Called from GameLoop.ServerFrame_Think and GameLoop.ClientFrame_Think.


Called after each physics step, this is usually every tick but can be more depending on PhysicsSubSteps.

[Event( "physics.step" )]

Called from GameLoop.PostPhysicsStep.


Called each time your C# is hotloaded after successful recompile.


Called from HotloadManager.DoSwap.


Called after all map entities have spawned in, including after map cleanups.


Custom Events

You can register your own custom event callbacks and call them.

[Event( "mygame.gameover" )] public void OnGameOver() { } public void DoGameOver() { Event.Run( "mygame.gameover" ) }

Event arguments

Events can pass any amount of arguments too.

[Event( "mygame.gameover" )] public void OnGameOver( Player winner ) { } public void DoGameOver( Player winner ) { Event.Run( "mygame.gameover", winner ) }


If you want, you can also make your own custom EventAttributes (like [Event.Tick]) and use them to register handlers. The behavior is the same as raw event names but they have all the benefits of a type (picked up by IntelliSense, checked at compile time, etc.)

// Defining the event type public static class GameEvent { public const string Custom = "custom"; public class CustomAttribute : EventAttribute { public CustomAttribute() : base(Custom) { } } } // Register it like this [GameEvent.Custom] public void OnCustomEvent() { // do something } // Fire it like this Event.Run(GameEvent.Custom);