Skip to main content
Version: 0.4.1

Game events

The WukongMP SDK provides means to react to the most common events in the game: levels loading, players and monsters coming and going, and deaths.

All of them hang off WukongApi.Events as ordinary C# events.

Subscribing

Subscribe in a class implementing IHostedService, so the SDK hands you a place to attach and detach. Subscribe in OnScopeStart and unsubscribe in Dispose:

MyEventCallbacks.cs
public sealed class MyEventCallbacks(ILogger logger) : IHostedService
{
public void OnScopeStart()
{
WukongApi.Events.OnJoinedArea += OnJoinedArea;
WukongApi.Events.OnMonsterDead += OnMonsterDead;
}

public void Dispose()
{
WukongApi.Events.OnJoinedArea -= OnJoinedArea;
WukongApi.Events.OnMonsterDead -= OnMonsterDead;
}

private void OnJoinedArea(AreaId area)
=> logger.LogInformation("Entered area {Area}", area);

private void OnMonsterDead(ReadyTamer monster, ReadyCharacter? killer)
=> logger.LogInformation("{Monster} killed by {Killer}", monster.Nickname, killer?.Nickname);
}

Then register it in your mod's Initialize:

services.RegisterSingleton<MyEventCallbacks>();

See Hosted services for the lifecycle in full. The co-op mod's CoopEventCallbacks is a working example.

Levels and areas

An area is a loaded map. If the game shows a loading screen, you are changing area.

EventArgumentFires when
OnLevelLoadeda gameplay level has loaded, before the loading screen closes
OnLoadingScreenClosethe loading screen closes after a level loads
OnBeginPlayGameplayLevelthe player enters a gameplay level
OnEndPlayGameplayLevelthe player leaves a gameplay level, to the menu or another level
OnExitLevelthe player exits a level
OnJoinedAreaAreaIdthe local player enters an area
OnLeftAreaAreaIdthe local player leaves an area
Setting up widgets

OnLevelLoaded fires before the loading screen closes, which makes it the right place to build custom UI: your widget is ready the moment the player can see anything. Use OnLoadingScreenClose for things that should happen once the player is actually looking at the world.

Players

EventArgumentsFires when
OnConnectedPlayerIdany player connects to the server
OnDisconnectedPlayerId, DisconnectedReasonany player disconnects, deliberately or not
OnMainCharacterEntityInitializedReadyMainCharactera player's ECS entity is ready
OnPlayerPawnSpawnedReadyMainCharactera player's in-game character is spawned
OnPlayerChangedTeamReadyMainCharactera player changes team, by rebirthing or joining in progress
OnPlayerDeadReadyMainCharacter, ReadyCharacter?any player dies. The second argument is the killer, if there was one
OnLocalPlayerBeforeRebirththe local player is about to rebirth, while still dead
OnLocalPlayerChangedSpectatorboolthe local player enters or leaves spectator mode
OnOtherPlayerInsideAreaPlayerId, AreaIdanother player enters the local player's area
OnOtherPlayerOutsideAreaPlayerId, AreaIdanother player leaves the local player's area
Two events per player, in this order

OnMainCharacterEntityInitialized fires before OnPlayerPawnSpawned. The entity exists first, the pawn appears second.

If you are writing to the player's ECS components, use the first one so your data is in place before anything renders. If you are touching the pawn, the actor in the world, use the second, because the pawn does not exist yet during the first.

Both fire for every player, not just the local one: once when you enter an area, and again whenever someone else joins and their character spawns for you.

Why a player disconnected

OnDisconnected carries a DisconnectedReason, so you can tell a rage quit from a dropped connection:

ValueMeaning
UnknownThe reason could not be determined
TimeoutThe connection to the server timed out
ClientDisconnectedThe player left voluntarily
IncompatibleVersionThe player's SDK mod version does not match the server's
ExpiredTicketThe connection ticket the server issued had expired
AlreadyConnectedThat player is already connected in another session
ServerFullThe server is not accepting new connections
KickedAn admin kicked the player
BannedAn admin banned the player from this server
ServerBannedReadyM banned the whole server, so it refuses everyone

Most mods only care about the difference between a player who meant to leave and one who fell off. ClientDisconnected is the deliberate one; Timeout is the one worth holding state for in case they come back.

The last two are worth telling apart. Banned is about one player on your server. ServerBanned is about the server itself, so every player sees it and there is nothing a mod can do about it.

Monsters

EventArgumentsFires when
OnMonsterSpawnedReadyTamera monster appears in the world
OnMonsterDeadReadyTamer, ReadyCharacter?a monster dies. The second argument is the killer, if there was one
OnMonsterDestroyedReadyTamera monster is removed from the world

OnMonsterDead and OnMonsterDestroyed are not the same thing. A monster dies once, but it is destroyed whenever it leaves the world, which includes being despawned because the player walked away. A monster that despawns without dying raises only OnMonsterDestroyed.

Other

EventArgumentFires when
OnLanguageChangedCultureInfothe game's language changes, from the settings or from the system locale

Use OnLanguageChanged to re-render anything you have already drawn with translated text.

Threading

Handlers are invoked on the game thread, so you can touch Unreal objects and the ECS world directly with no marshalling. The flip side is that a slow handler stalls a frame, so keep them short and move real work into a system.