跳到主要内容
版本:0.4.1

游戏事件

WukongMP SDK 提供了对游戏中最常见事件做出反应的方式:关卡加载、玩家和怪物的出现与离开,以及死亡。

它们全都挂在 WukongApi.Events 上,就是普通的 C# 事件。

订阅

请在实现 IHostedService 的类中订阅,这样 SDK 会给你一个挂接和解除挂接的落脚点。在 OnScopeStart 中订阅,在 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);
}

然后在模组的 Initialize 中注册它:

services.RegisterSingleton<MyEventCallbacks>();

完整的生命周期请参见托管服务联机合作模组中的 CoopEventCallbacks 是一个可用的实例。

关卡与区域

区域指的是一张已加载的地图。如果游戏显示了加载画面,那就是在切换区域。

事件参数触发时机
OnLevelLoaded某个游戏关卡已加载完成,在加载画面关闭之前
OnLoadingScreenClose关卡加载完成后加载画面关闭
OnBeginPlayGameplayLevel玩家进入某个游戏关卡
OnEndPlayGameplayLevel玩家离开某个游戏关卡,回到菜单或前往另一个关卡
OnExitLevel玩家退出某个关卡
OnJoinedAreaAreaId本地玩家进入某个区域
OnLeftAreaAreaId本地玩家离开某个区域
搭建控件

OnLevelLoaded 在加载画面关闭之前触发,因此它是构建自定义 UI 的正确位置:玩家一旦能看到任何画面,你的控件就已经准备好了。至于那些应该等到玩家真正在看世界时才发生的事情,请用 OnLoadingScreenClose

玩家

事件参数触发时机
OnConnectedPlayerId任意玩家连接到服务器
OnDisconnectedPlayerIdDisconnectedReason任意玩家断开连接,无论是否出于本意
OnMainCharacterEntityInitializedReadyMainCharacter某个玩家的 ECS 实体已就绪
OnPlayerPawnSpawnedReadyMainCharacter某个玩家的游戏内角色已生成
OnPlayerChangedTeamReadyMainCharacter某个玩家切换队伍,例如复活或中途加入
OnPlayerDeadReadyMainCharacterReadyCharacter?任意玩家死亡。第二个参数是击杀者,如果存在的话
OnLocalPlayerBeforeRebirth本地玩家即将复活,此时仍处于死亡状态
OnLocalPlayerChangedSpectatorbool本地玩家进入或退出观战模式
OnOtherPlayerInsideAreaPlayerIdAreaId另一名玩家进入本地玩家所在的区域
OnOtherPlayerOutsideAreaPlayerIdAreaId另一名玩家离开本地玩家所在的区域
每名玩家两个事件,顺序如下

OnMainCharacterEntityInitializedOnPlayerPawnSpawned 之前触发。实体先存在,Pawn 后出现。

如果你要写入玩家的 ECS 组件,请用前者,这样你的数据会在任何东西渲染之前就位。如果你要操作 Pawn,也就是世界中的那个 Actor,请用后者,因为在前者触发时 Pawn 还不存在。

两者对每一名玩家都会触发,不只是本地玩家:你进入某个区域时会触发一次,之后每当有别人加入、他们的角色为你生成时都会再触发一次。

玩家为何断开连接

OnDisconnected 会带上一个 DisconnectedReason,因此你可以区分玩家是气得退出还是掉线了:

含义
Unknown无法确定原因
Timeout与服务器的连接超时
ClientDisconnected玩家主动离开
IncompatibleVersion玩家的 SDK 模组版本与服务器不匹配
ExpiredTicket服务器签发的连接凭据已过期
AlreadyConnected该玩家已在另一个会话中处于连接状态
ServerFull服务器不再接受新连接
Kicked管理员踢出了该玩家
Banned管理员在本服务器上封禁了该玩家
ServerBannedReadyM 封禁了整个服务器,因此它会拒绝所有人

大多数模组只关心一件事:玩家是有意离开,还是掉了线。ClientDisconnected 是有意的那种;Timeout 则值得为其保留状态,以防对方回来。

最后两个值得分清。Banned 说的是你服务器上的某一名玩家。ServerBanned 说的是服务器本身,所以每名玩家都会看到它,而且模组对此无能为力。

怪物

事件参数触发时机
OnMonsterSpawnedReadyTamer某个怪物在世界中出现
OnMonsterDeadReadyTamerReadyCharacter?某个怪物死亡。第二个参数是击杀者,如果存在的话
OnMonsterDestroyedReadyTamer某个怪物从世界中被移除

OnMonsterDeadOnMonsterDestroyed 不是一回事。怪物只会死一次,但它每次离开世界都会被销毁,其中包括因为玩家走远而被卸载的情况。没有死亡就被卸载的怪物只会引发 OnMonsterDestroyed

其他

事件参数触发时机
OnLanguageChangedCultureInfo游戏语言发生变化,来自设置或系统区域设置

OnLanguageChanged 来重新渲染你已经用译文绘制过的内容。

线程

处理程序在游戏线程上被调用,因此你可以直接操作 Unreal 对象和 ECS 世界,不需要任何跨线程处理。代价是处理程序一慢就会卡住一帧,所以请让它们保持简短,把真正的工作搬到系统里。