using Ananta.SDK.Rpc; using Ananta.Server.Handlers; using Ananta.Server.Protocol.Client4229938; namespace Ananta.Server.Handlers.Game; /// /// 对话启动线:`IGameSceneToClient.AskStartDialog(uint dialogId, DialogParameter param, bool interrupt)` /// — methodId 63754798 (0x03CCD22E, dump.cs:1871038)。 /// /// 这条以前完全没有 handler,客户端落到 typed-default 兜底,回包是 e=0 0b: /// err 位是 0,但包体 0 字节。而客户端封装是 /// DoAskStartDialog(dialogId, param, dialogSource, isBreaking, Action<uint> cb)(dump.cs:693697) /// —— 它 await 的是一个 uint 返回值,不是空包。 /// /// 实测后果:`unknown-methods.log` 里这条堆了 261 条 INVOKE(09-15 起,10 天,至少 10 个不同 /// dialogId);拨「Call vehicle」时能看到 AskStartDialog 之后卡 20 秒才继续发 /// AskPhoneContactOptionAction,而同场景「Express Depot」因为路径短,record → option → /// AskSummonVehicle 在同一秒内完成 —— 那 20 秒就是客户端在等这个永远不来的 uint。 /// /// 所以这里只做一件事:补回那个缺失的 uint,取值 0(=成功)。对话内容本身全在客户端本地 /// (拨通后是客户端 ShowGeneralDialog(dialogId)),服务端没有条件数据可供判定, /// 一律按成功回是最贴近官方的默认值。 /// /// 日志保留原始 hex,便于离线确认各个 dialogId 的实际触发情况。 /// internal sealed partial class GameRouter { [Handler(MethodId.AskStartDialog, HandlerPacketKind.Invoke)] private Task AskStartDialog(Connection conn, UxRpcMessage msg) { conn.Log.Info($"[DIALOG] start bytes={msg.Body.Length} hex={Convert.ToHexString(msg.Body.ToArray())}"); return conn.ReturnAsync(msg, 0u); } /// /// 对话推进动作:`IGameSceneToClient.AskDoDialogAction(uint dialogId)` — methodId 63723634 /// (0x03CC5872, dump.cs:1726318)。返回 `UXRPCTask`(void),所以回空 OK 即可。 /// 实测请求体 4 字节(一个 uint dialogId,例 `BA08FB02`)。 /// ⛑ 不回 = 客户端 await 卡死(unknown-methods.log 里 INVOKE 有记录)。 /// [Handler(MethodId.AskDoDialogAction, HandlerPacketKind.Invoke)] private Task AskDoDialogAction(Connection conn, UxRpcMessage msg) { conn.Log.Info($"[DIALOG] action bytes={msg.Body.Length} hex={Convert.ToHexString(msg.Body.ToArray())}"); return conn.ReturnEmptyOkAsync(msg); } /// /// 强制结束对话:`IGameSceneToClient.AskForceFinishDialog()` — methodId 63010951 /// (0x03C17887, dump.cs:1726324)。返回 `UXRPCTask`(void),**请求体 0 字节**(无参数)。 /// [Handler(MethodId.AskForceFinishDialog, HandlerPacketKind.Invoke)] private Task AskForceFinishDialog(Connection conn, UxRpcMessage msg) { conn.Log.Info($"[DIALOG] force-finish bytes={msg.Body.Length}"); return conn.ReturnEmptyOkAsync(msg); } }