using Ananta.SDK.Logging; using Ananta.SDK.Rpc; using Ananta.Server.Protocol.Client4229938; namespace Ananta.Server.Handlers.Game; /// /// 飞镖(DartsGame,prefab 上的笼子小游戏;lua LX6/MiniGame/DartsGame/DartsGame.lua)。 /// /// ★ 只解决「await 拿不到回执」,治不了 T-pose。 /// /// 角色 T-pose 的根因不在这里: /// 动画整条链在客户端 —— DartsGame.lua:51 定 timelineName = "Gameplay_Dart", /// :1447 Timeline_LoadAndPlay,底层 L50.L50App.L50Game.CutsceneManager /// (LX6/Manager/Timeline/TimelineManager.lua:37),而这个 LoadAndPlay 是 void /// ⇒ 失败一个字节的日志都不留。2026-09-24 22:0x 已证资源不缺 /// (Blocks 93G、本局零 AssetBundle/timeline 加载失败、BindRealUnitFeature 0 次), /// ⇒ 要确认 timeline 到底播没播,只能 frida 实锤(脚本 _frida_dart_probe.py)。 /// /// 取证:2026-09-24 22:13:09 ~ 22:14:31 真机一局(handler 生效后首局,dartId=14): /// /// INVOKE StartDarts 63777955 bytes=12 hex=0E000000 14000000 03000000 /// dartId=14 challengeId=20 dartMode=3 /// INVOKE TriggerDartTiming 67926798 bytes=1 hex=00 / 01 / 02 /// INVOKE RecordDarts 63225711 bytes=15 hex=14000000 A8000000 00000000 00 FF01 /// challengeId=20 score=168 goal=0 finish=false [] /// /// ⛑ **`dartMode` 不是常量**:三局实测 20:26局=1 / 21:48局=1 / 22:13局=3, /// challengeId 恒 20。将来若要做"按模式给不同结算",第三个 u32 就是分支依据, /// 别照注释里的某一局写死。 /// /// 接之前服务端走的是框架兜底 /// ! [RPC4229938] unimplemented TriggerDartTiming -> typed-default void 0b, /// console 看着 e=0 0b 像是过了,但 typed-default 不是语义应答; /// dump.cs 三条都是非泛型 UXRPCTask(void)⇒ 空包 + err=0 就是客户端要的 OK。 /// 22:13 那局已验:接上后 grep "unimplemented.*Dart" console-latest.log → 空。 /// /// ⛑ 为什么只接这三条(硬规则 112): /// 另外五条 LeaveDart(67039599) / RecordDartEnd(67097646) / /// RecordDartScore(67483394) / RecordDartId(67567529) / /// RecordDartPerformEnd(67921918) 在 unknown-methods.log 里是 0 次 /// —— 客户端从没发过,注册它们只是增加维护面。等日志里真出现再照下面抄一行。 /// /// ⛑ 回滚:从 GameRouter.cs 的 Enabled4229938MethodIds 里删掉这三条即可 /// (handler 不注册 = 走 typed-neutral 兜底),不用删本文件。 /// internal sealed partial class GameRouter { [Handler(MethodId.StartDarts)] [Handler(MethodId.TriggerDartTiming)] [Handler(MethodId.RecordDarts)] private Task DartsAccept(Connection conn, UxRpcMessage msg) { // body 不长(1~15 字节),直接带 hex 落地:将来要写真契约时这份日志就是免费素材。 var body = msg.Body; var n = body.Length > 32 ? 32 : body.Length; var hex = n > 0 ? System.Convert.ToHexString(body.AsSpan(0, n)) : string.Empty; conn.Log.Info($"[DARTS] accepted {RpcMethodNames.Display(msg.MethodId)} bytes={body.Length} hex={hex}"); return conn.ReturnEmptyOkAsync(msg); } }