package methods // ---------------------------------------------------------------- agent commands(donor1 第 39/40 轮实机验证) // // SyncLogicAgentCommand(ulong agentId, int commandId, AgentCommandData data) 是唯一能给 // 服务端接管的 logic agent 派移动任务的通道:客户端的 LogicBehaviorSchedulerModule 负责跑 // 任务 —— ZoneGraph 寻路、避障、以及随之而来的 locomotion 状态;纯位置流(SyncLogicAgentSyncData) // 不携带任何任务,产生不了步态(donor1 第 39 轮实测:Servo 流 = 走两秒动画然后站住)。 // // 每个 AgentCommandData 具体子类的线格式由反汇编客户端得到(GameAssembly, image base 0x180000000): // TypeSerializer.ReadStaticAgentCommandData RVA 0x9EAA8A0 - reads the tag byte and dispatches // jump table RVA 0x1DAC574 - 45 entries for tag 3..47 // ReadTaskWayPointMoveCommandData RVA 0x9F67ED0 // ReadTaskMoveCommandData RVA 0x9F66940 // ReadMoveCommandData RVA 0x9F1DA10 // ReadNavigationMoveCommandData RVA 0x9F1F870 // ReadZoneGraphPathCommandData RVA 0x9F745A0 // ReadClientZoneGraphPathPoint RVA 0x9EF12A0 // 一个具体命令 = 一个 tag 字节 + 扁平化字段(0x00 = null,0xFF = 基类型,具体子类 = 自己的 tag), // 这正是 [UxContract(TypeMark = n)] 写出来的东西。tag = 类型名按字母序从 3 起的位置: // 47 = ZoneGraphPathCommandData, 39 = TaskWayPointMoveCommandData, 28 = MoveCommandData, // 31 = NavigationMoveCommandData, 38 = TaskMoveCommandData, 27 = MotionLookAtCommandData. // Drmk.Proxy 里的 Lua 表(RPCDeserializeAuto.Concrete / Auto.Reader)偏了 1(key = 真实 tag - 1), // ⛔ 不能当 tag 来源(与 KNOWLEDGEBASE「crowd locomotion 是纯 C#」互证)。 // // 两个基类贡献每个命令的最后三字节,顺序如下(IL2CPP 偏移): // AgentMoveTokenCommandData.MoveId [0x18] 1 字节; // AgentCommandData.DataSource [0x10] 占 2 字节(enum 是 byte 底、但客户端读 1 字节后 // 游标前进 2 —— 第二字节是 padding,也必须发)。非 stim 来源的命令 DataSource = Other(255), // MoveId = 0(客户端自己的移动上报里就是 0)。 // UX ByteAngle: one byte quantised yaw, the last byte of a ClientZoneGraphPathPoint. // One point of a path command (client reader ReadClientZoneGraphPathPoint 0x9EF12A0): // three singles then one byte, 13 bytes per point. // // ZoneGraphPathCommandData - wire tag 47, LogicAgentCommandType.ZoneGraphPath (2). // The client picks the lane itself and walks the agent towards these world positions, which is why // TargetLocationReason exists: it tells the navigation what the points mean (1 = Wander). // // // TaskWayPointMoveCommandData - wire tag 39, LogicAgentCommandType.TaskWayPointMove (8). // The self-contained variant: it carries the speed, the move action and the animation group with the // waypoints, so the client needs no navigation data at all to run the walk. // ★ donor1 第 51 轮用户亲测:这就是"完整路人"(一直有走路动画、会移动、到目的地停下)的驱动协议。 // // AgentCommandDataSource (client enum, values from the IL2CPP dump). const ( LogicAgentCommandDataSources_None int16 = 0 LogicAgentCommandDataSources_Stim int16 = 1 LogicAgentCommandDataSources_Other int16 = 255 ) // The remaining two walks are the "aim at one target" family - MoveCommandData (tag 28) and // NavigationMoveCommandData (tag 31, the same fields preceded by the navigation tolerances). Both aim at a // ClientActionTarget, which is why the position target needs StimTargetType.Position: the client resolves // the command against that enum, and a target of type None would be thrown away as "nothing to do". // Field order is again "most derived class first", read straight off the client readers // ReadMoveCommandData (0x9F1DA10) and ReadNavigationMoveCommandData (0x9F1F870). // StimTargetType (client enum, values from the IL2CPP dump). const ( StimTargetTypes_None byte = 0 StimTargetTypes_Player byte = 1 StimTargetTypes_Agent byte = 2 StimTargetTypes_Destructible byte = 3 StimTargetTypes_Position byte = 4 StimTargetTypes_Vehicle byte = 5 StimTargetTypes_Metro byte = 6 ) // MovementMethod (client enum, values from the IL2CPP dump): the gait a move picks. const ( AgentMovementMethods_Dynamic byte = 0 AgentMovementMethods_Walk byte = 1 AgentMovementMethods_Run byte = 2 AgentMovementMethods_Flee byte = 3 AgentMovementMethods_MatchPlayer byte = 4 AgentMovementMethods_Appointed byte = 5 AgentMovementMethods_FearWalk byte = 6 AgentMovementMethods_VariablePaceMove byte = 7 AgentMovementMethods_Scurry byte = 8 AgentMovementMethods_Rush byte = 9 AgentMovementMethods_PogoStick byte = 10 AgentMovementMethods_Skateboard byte = 11 AgentMovementMethods_Prowl byte = 12 ) // ClientActionTarget - client reader ReadClientActionTarget 0x9B3AF40: what a move // command aims at. A plain world position is StimTargetTypes.Position with the id left at // zero. // MoveCommandData - wire tag 28, LogicAgentCommandType.Move (1). // // NavigationMoveCommandData - wire tag 31, LogicAgentCommandType.NavigationMove. Same payload as // MoveCommandData with the three navigation fields in front; the client navigates to the // target itself instead of walking straight at it. // // // Body of SyncLogicAgentCommand (mid 68050574) with a zone graph path payload. The marker byte // written in front of data is the declared field type's, so this body is only correct for // ZoneGraphPathCommandData - hence one body per command kind instead of one body with a // base typed field. // // Body of SyncLogicAgentCommand (mid 68050574) with a waypoint move payload. // Body of SyncLogicAgentCommand (mid 68050574) with a plain move payload. // Body of SyncLogicAgentCommand (mid 68050574) with a navigating move payload. // ───────────────────────────────────────────────────────────────────────────── // 回报侧(2026-09-24 自捐赠端 DremkaPS 移植) // // SyncLogicAgentCommand 对服务端是 fire-and-forget:客户端装了这条命令、还是拿到就丢了, // 在出站日志里长得一模一样。下面这两条就是客户端的回答 —— 有了它们, // 「行人还是不走」才能细分成「收了 12 条一条没跑」还是「每一条都被拒了」。 // 布局照抄客户端自己的 writer(RPCSerializeAuto.WriteLogicAgentCommandSuccessData / // WriteLogicAgentCommandReportData)。 // ───────────────────────────────────────────────────────────────────────────── // // Client -> server WriteLogicAgentCommandSuccessData:一条命令的回执。 // ⛔⛔ 本服不用这个契约解包 —— 它照抄自捐赠端 DremkaPS,而捐赠端声称 // AskReportLogicAgentCommandSuccess2(67057559) 与 AskReportLogicAgentCommandFail(67193144) // 共用这一个 12 字节布局(u64 + int,无标记)。本服抓包证伪了这一点: // // Success2 bytes=14 FF 02 | u64 agentId | int commandId // Fail bytes=16 u64 agentId | int commandId | int 0 // // 两条的 agentId 起点不同(2 与 0),长度也不同。实际解析走 // GameRouter.AgentCommandAck.cs 的 TryReadCommandAck(按实测偏移读字节)。 // 保留这个契约仅供参考,别拿它去 TryGetArgs。 // // // Client -> server WriteLogicAgentCommandReportData(AskReportLogicAgentCommandData2 // 67780469):一个 agent 的状态 / 层报告。Data 是 7Bit 计数的字节列表。 //