S&box Wiki

Revision Difference

EventSystem#549746

<cat>Code.Intro</cat> <title>Event System</title> 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] [GameEvent.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. ## Registering a Callback⤶ Adding a `[GameEvent.*]` or `[Event.*]` attribute will add it to the list to be called. ``` [Event( "server.tick" )]⤶ [GameEvent.Tick.Server]⤶ public void MyCallback() { // will get called every server tick } ``` ## Engine events⤶ ## Built-in Events⤶ The various events called from the engine currently: ### buildinput⤶ ### Build Input⤶ Called clientside every frame to process input and encode outputs into a user command. ```csharp [Event.Client.BuildInput] [GameEvent.Client.BuildInput] public void MyBuildInput() { } ``` ### client.disconnect⤶ ### Client Disconnect⤶ Called when a client disconnects. ⤶ ```csharp⤶ [GameEvent.Server.ClientDisconnect]⤶ private void ClientDisconnect( ClientDisconnectEvent e )⤶ {⤶ Log.Info( e.Client );⤶ }⤶ ```⤶ ⤶ ⤶ ### Client Joined⤶ ⤶ Called when a client joins.⤶ ```csharp [Event( "client.disconnected" )]⤶ [GameEvent.Server.ClientJoined]⤶ private void ClientJoined( ClientJoinedEvent e )⤶ {⤶ Log.Info( e.Client );⤶ }⤶ ``` ⤶ Called from `GameLoop.ClientDisconnected`⤶ ⤶ ### frame⤶ ⤶ ⤶ ### Frame⤶ Called just before the beginning of a rendering frame. ```csharp [Event.Frame] [GameEvent.Client.Frame] ``` ⤶ Called from `GameLoop.PreRender`⤶ ⤶ ### tick⤶ ⤶ ⤶ ### Tick⤶ Called every <page text="server or client tick">GameLoop#everytick</page> (60 times a second by default). ```csharp [Event.Tick] [Event( "server.tick" )]⤶ [Event( "client.tick" )] [GameEvent.Tick] [GameEvent.Tick.Server]⤶ [GameEvent.Tick.Client)] ``` ⤶ Called from `GameLoop.ServerFrame_Think` and `GameLoop.ClientFrame_Think`.⤶ ⤶ ### physics.step⤶ Called after each physics step, this is usually every tick but can be more depending on <page text="Global.PhysicsSubSteps">Sandbox.Global.PhysicsSubSteps</page>. ⤶ ⤶ ### Physics Step⤶ Called before each physics step, this is usually every tick but can be more depending on <page text="Global.PhysicsSubSteps">Sandbox.Global.PhysicsSubSteps</page>. ⤶ ```csharp⤶ [GameEvent.Physics.PreStep]⤶ ```⤶ ⤶ Called after each physics step.⤶ ```csharp [Event( "physics.step" )]⤶ [GameEvent.Physics.PostStep]⤶ ``` ⤶ Called from `GameLoop.PostPhysicsStep`.⤶ ⤶ ### hotloaded⤶ ⤶ ### Hotload⤶ Called each time your C# is hotloaded after successful recompile. ```csharp [Event.Hotload] ``` ⤶ Called from `HotloadManager.DoSwap`.⤶ ⤶ ### client.postspawn⤶ ⤶ ⤶ ### Post Entity Spawn⤶ Called after all map entities have spawned in, including after map cleanups. ```csharp [Event.Entity.PostSpawn] [GameEvent.Entity.PostSpawn] ``` ## Custom Events You can register your own custom event callbacks and call them. ```csharp [Event( "mygame.gameover" )] public void OnGameOver() { } public void DoGameOver() { Event.Run( "mygame.gameover" ) } ``` ### Event arguments⤶ Events can pass any amount of arguments too. ### Event Arguments⤶ Events can pass up to three arguments too. ```csharp [Event( "mygame.gameover" )] public void OnGameOver( Player winner ) { } public void DoGameOver( Player winner ) { Event.Run( "mygame.gameover", winner ) } ``` ### EventAttributes⤶ ### Event Attributes⤶ 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.) ```csharp // 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 ); ```⤶ ⤶ ### Defining Method Arguments⤶ ⤶ When using custom event attributes you can define the required method arguments. This way, any methods that listen for this event *must* have matching arguments.⤶ ⤶ ```csharp⤶ // This event requires a string as the first argument.⤶ [MethodArguments( typeof( string ) )⤶ public class CustomAttribute : EventAttribute⤶ {⤶ public CustomAttribute() : base( Custom ) { }⤶ }⤶ ```