Game Events
Technically, game events are already a deprecated feature in Source 2. Many of the game events are currently not working.
SwiftlyS2 provides a plugin-scoped game-event service for firing generated game events and hooking them in pre/post mode.
Accessing Game Event Service
Game events are available through Core.GameEvent.
public override void Load(bool hotReload)
{
var gameEvents = Core.GameEvent;
}Firing Game Events
Fire to All Players
Core.GameEvent.Fire<EventShowSurvivalRespawnStatus>(@event =>
{
@event.LocToken = "survival_respawn_status";
@event.Duration = 5;
});You can also fire without configuration:
Core.GameEvent.Fire<EventShowSurvivalRespawnStatus>();Fire to a Specific Player Slot
Core.GameEvent.FireToPlayer<EventShowSurvivalRespawnStatus>(slot: 0, @event =>
{
@event.LocToken = "private_status";
@event.Duration = 3;
});Fire to Server
Core.GameEvent.FireToServer<EventShowSurvivalRespawnStatus>(@event =>
{
@event.LocToken = "server_only_status";
});Async Fire Variants
Use async variants in non-main-thread contexts:
await Core.GameEvent.FireAsync<EventShowSurvivalRespawnStatus>();
await Core.GameEvent.FireToPlayerAsync<EventShowSurvivalRespawnStatus>(0);
await Core.GameEvent.FireToServerAsync<EventShowSurvivalRespawnStatus>();The event object (@event) in fire configure lambdas is temporary and must not be used outside that lambda.
Hooking Game Events
Game events can be hooked programmatically or by attributes.
private Guid _preHookGuid;
private Guid _postHookGuid;
public override void Load(bool hotReload)
{
_preHookGuid = Core.GameEvent.HookPre<EventPlayerDeath>(OnPlayerDeathPre);
_postHookGuid = Core.GameEvent.HookPost<EventPlayerDeath>(OnPlayerDeathPost);
}
public override void Unload(bool hotReload)
{
if (_preHookGuid != Guid.Empty)
{
Core.GameEvent.Unhook(_preHookGuid);
}
if (_postHookGuid != Guid.Empty)
{
Core.GameEvent.Unhook(_postHookGuid);
}
}
private HookResult OnPlayerDeathPre(EventPlayerDeath @event)
{
Console.WriteLine($"[PRE] victim={@event.UserId}, attacker={@event.Attacker}");
return HookResult.Continue;
}
private HookResult OnPlayerDeathPost(EventPlayerDeath @event)
{
Console.WriteLine($"[POST] headshot={@event.Headshot}, weapon={@event.Weapon}");
return HookResult.Continue;
}[GameEventHandler(HookMode.Pre)]
public HookResult OnPlayerDeathPre(EventPlayerDeath @event)
{
Console.WriteLine($"[PRE] victim={@event.UserId}, attacker={@event.Attacker}");
return HookResult.Continue;
}
[GameEventHandler(HookMode.Post)]
public HookResult OnPlayerDeathPost(EventPlayerDeath @event)
{
Console.WriteLine($"[POST] headshot={@event.Headshot}, weapon={@event.Weapon}");
return HookResult.Continue;
}In pre-hooks, returning HookResult.Stop blocks the game event.
Hook callback event objects are temporary and only valid during the callback. If you need data later, copy the values you need.
You can also remove all hooks for a specific event type:
Core.GameEvent.UnhookPre<EventPlayerDeath>();
Core.GameEvent.UnhookPost<EventPlayerDeath>();Callback Signature
Hook callbacks follow this delegate signature:
public delegate HookResult IGameEventService.GameEventHandler<T>(T eventObj) where T : IGameEvent<T>Working with Event Data
Generated game-event interfaces (for example EventPlayerDeath) expose typed properties.
private HookResult OnPlayerDeath(EventPlayerDeath @event)
{
if (@event.AttackerPlayer != null && @event.UserIdPlayer != null)
{
Console.WriteLine($"{@event.AttackerPlayer.Name} killed {@event.UserIdPlayer.Name}");
}
return HookResult.Continue;
}IGameEvent<T> also exposes common members:
DontBroadcastAccessor(IGameEventAccessor) for raw payload field access
Example with Accessor:
private HookResult OnPlayerDeath(EventPlayerDeath @event)
{
string weapon = @event.Accessor.GetString("weapon");
int attackerSlot = @event.Accessor.GetPlayerSlot("attacker");
Console.WriteLine($"attacker slot={attackerSlot}, weapon={weapon}");
return HookResult.Continue;
}Checking Event Listening
You can check whether a player slot is listening for an event:
bool listensByName = Core.GameEvent.IsListeningToEvent(0, "player_death");
bool listensByType = Core.GameEvent.IsListeningToEvent<EventPlayerDeath>(0);Reference
See IGameEventService for fire/hook APIs.
See GameEventHandler for attribute-based event hooks.
See IGameEvent<T> and IGameEventAccessor for common event members.
See GameEventDefinitions for all generated game event interfaces.