93 lines
5.4 KiB
Go
93 lines
5.4 KiB
Go
package methods
|
||
|
||
//
|
||
// AetherCity 人群(crowd / 行人)S2C 契约,build 4229938。
|
||
// ⛑️ 字段与顺序的唯一权威 = `dump.cs` 里 `IGameSceneToClient` 接口的 abstract 签名
|
||
// (`Assembly-CSharp-ULTIMATE/ux_rpc/ux_game_all.dump.cs`)。本文件逐条对齐,不要按
|
||
// RPCSerializeAuto.lua 改(那份对这批包不可信 —— 见硬规则 34)。
|
||
// 关键设计:客户端 AetherCity 的人群是**客户端自驱**的(AetherPedManager 用
|
||
// ContextSteering + ZoneGraph Wander 自己走)。服务端要做的只有两件事:
|
||
// ① SyncAetherAIInitDatas 打开 HasZoneGraph(已有 EnsureAetherVehicleInit 负责)
|
||
// ② SyncSetCrowdDensity + SyncCrowdSpecifiedDensityRefresh 告诉客户端"在玩家周围生成多少人"
|
||
// 服务端**不发任何移动包**(没有 AskUpdateMoveDatas 这类 RPC)。
|
||
//
|
||
//
|
||
// IGameSceneToClient.SyncSetCrowdDensity(bool revertToNormal, float overrideDensity) = 68996045。
|
||
// 打开客户端 ECS 人群生成器(覆盖全局密度)。
|
||
//
|
||
//
|
||
// IGameSceneToClient.SyncCrowdSpecifiedDensityRefresh(UXVector3 position, UXVector3 extends,
|
||
// float densityFactor) = 68195167。
|
||
// 在 position 周围 extends 这个盒子里按 densityFactor 生成/补齐行人。玩家走远了要重发。
|
||
//
|
||
//
|
||
// UX.Game.ClientCrowdInitData : ClientBaseEntityData(TypeDefIndex 32676)。
|
||
// 单个行人的出生数据。字段顺序 = 本类 7 个字段在前,继承的 ClientBaseEntityData
|
||
// 4 个字段(Id / Position / Facing / EulerAngles)在**最后** —— 与客户端派生字段列表一致。
|
||
// ⛑️ NpcFormworkId 是 **AgentConfig** 的 id(4013xxxx),不是 AgentPersonaConfig(452xxxxx)。
|
||
// 填错客户端打 `创建AgentUnit失败!AgentConfigId为0!` 并丢掉这个人。
|
||
//
|
||
//
|
||
// IGameSceneToClient.SyncAetherAICrowdAdd(ClientCrowdInitData crowd) = 68757757。
|
||
// 手动投放一个行人给客户端的 Aether AI。单 class 参数 ⇒ 内部类走 Complex(0xFF 标记)。
|
||
//
|
||
//
|
||
// IGameSceneToClient.AskAetherNpcUpdatePathForObstacle(67228857) —— C→S,**行人自己撞墙求助**。
|
||
// 三个字段:`ulong entityId + UXVector3 障碍点 + float radius`(donor v2 的 `CrowdMethods.cs`,
|
||
// 他们整场只收到 1 次,但那一次 = 那个人**站着 12.8 秒**)。
|
||
// ⛑️ 字段顺序照 donor 的契约抄;当前只用于打日志观察,解析错了也不会影响别的包。
|
||
//
|
||
//
|
||
// IGameSceneToClient.AskClientNpcFindPath(67974714) —— C→S INVOKE,客户端为它手下的单位问路。
|
||
// 请求体 = ulong id + UXVector3 from + UXVector3 to(28 字节;长度不符客户端会拒收)。
|
||
//
|
||
//
|
||
// AskClientNpcFindPath 的应答 FindPathResult。
|
||
// ⛑️ 字段与顺序真源 = `RPCDeserializeAuto.lua`:`midToReturnMessageReader[67974714]`
|
||
// → `Base.ReadStruct(reader, Auto.Reader[688])`;`Auto.Reader[688]` =
|
||
// `Points:list7<UXVector3>` + `Flags:list7<byte>`。
|
||
// 与兜底字节 `FF 01 FF 01`(两个空 list7)完全吻合。
|
||
// 顶层是 struct(**无 marker**);list7 计数带 +1 偏置,空集合 = `FF 01`。
|
||
//
|
||
//
|
||
// IGameSceneToClient.SyncAetherAINpcRemove(ulong pid) = 68332284。
|
||
// ⛑️ dump 权威签名是**单个 ulong**,不是 List<ulong>。
|
||
// (donor_lyco082 那份写成 List 是猜的,别抄。)pid = 当初 ClientCrowdInitData.Id。
|
||
//
|
||
//
|
||
// IGameSceneToClient.SyncCrowdSurroundZone(int spoonId, UXVector3 center, float radius, bool add,
|
||
// float removeRadius) = 68024180。把圆形区域登记成客户端自己人群的聚集区(add=true)。
|
||
//
|
||
//
|
||
// IGameSceneToClient.SyncCrowdClearZone(int spoonId, UXVector3 center, float radius, bool add,
|
||
// float removeRadius, CrowdClearZoneType zoneType) = 68910103。禁人区。
|
||
//
|
||
//
|
||
// SyncAgentForceGo(ulong id, bool isForceGo) = 68698324。
|
||
// 已生成但站着不动的 agent 用它启动行为树。
|
||
//
|
||
//
|
||
// UX.Game.MoveWanderingData : BattleMoveDataBase(TypeDefIndex 32747)= 68745518 的参数。
|
||
// ⛑️ 字段顺序照抄 donor1 `WorldMethods.cs`(它实机验证过,49 字节):
|
||
// **本类 8 个字段在前,扁平化的基类字段在后** —— 与 dump 的内存布局一致。
|
||
// 不要重排、不要删字段。
|
||
//
|
||
//
|
||
// IGameSceneToClient.SyncMoveWandering(MoveWanderingData data) = 68745518。
|
||
// ★★ 让一个已投放的 NPC/行人"自己走起来"的唯一官方包。
|
||
// 它**不带目的地**——只有半径、角度窗口和时间预算,路径由客户端 ZoneGraph/AetherAI 自己挑。
|
||
// ⇒ 服务端根本不需要路网来做"行走",只需要周期续期(MaxTime 是总时长,走完就永久站住)。
|
||
//
|
||
//
|
||
// SyncChangeNpcMoveDesiredSpeed(entityId u64, desiredSpeed f32) = 68739456。
|
||
// ⛑️ `ClientStaticNpcInitData` **没有 DesiredSpeed 字段**,速度只能靠这个包单独下发;
|
||
// 不发 ⇒ 客户端 `AgentEntitySyncHandler.GetDesiredSpeed` 拿 0 ⇒ 即使有目的地也不动。
|
||
//
|
||
//
|
||
// Client -> server AskAgentPoiActionDone(67016793):12 字节,u64 agentId + u32 poiActionId,
|
||
// poiActionId 就是 UrbanDiversityPOIActionConfig 的 Id。
|
||
// 移植自捐赠端 DremkaPS(2026-09-24,其 GameScene/CrowdMethods.cs)。他们的注释写得很直接:
|
||
// 没有这个 handler,agent 会保持在动作播完那一刻的姿势 —— 「动作演完就定格」这个症状。
|
||
// ⛑ 客户端是**成串**上报的(350 ms 内 31 条、间隔约 10 ms),所以任何应答都要做过流闸门。
|
||
//
|