92 lines
5.7 KiB
Go
92 lines
5.7 KiB
Go
package methods
|
||
|
||
//
|
||
// 搜打撤(ExtractionShooter / 不要抬头!)在 4229938 上的 wire 契约。
|
||
// 两份依据,冲突时以第一条为准:
|
||
// 1. 客户端 RPCDeserializeAuto.lua 的 reader 本体 —— Reader[297] 物品基类 / Reader[1050]
|
||
// 容器元素 / Reader[530] 容器;这三个是逐字节抄下来的。
|
||
// 2. 捐赠端 handoff AI_HANDOFF不要抬头2.md §6。
|
||
// ⛑ 四条都要照做(写错一条整包报废):
|
||
// - complex 嵌套 = 1 字节 marker:null 写 0x00,有值写该契约的 TypeMark。
|
||
// 多态靠 marker 区分 —— 物品基类 1、容器元素 2。
|
||
// - 字典 = marker + Int32 count(默认就是 Int32,别改成 7bit)。
|
||
// - 列表 = marker + 7bit(count+1);空列表 = FF 01,不是 FF 00。
|
||
// - ⛑⛑ 顶层推送契约一律 Inline = true:每条 midToReader 都是
|
||
// reader.ReadUInt32(reader) / ReadUInt64 直接开局,不读 root 标记。
|
||
// 唯一例外是 67410186 的返回值 —— 它写的是 Base.ReadComplex(reader, Auto.Reader[530])
|
||
// ⇒ 那一处的 ExtractionShooterContainerInfo 必须带那个 FF(它是 complex 目标)。
|
||
// 「搜打撤的物品为什么不能用错的 TypeMark」:Auto.Dispatch[297] 按 marker 跳表,
|
||
// 写成 0xFF 会落到 undefined 分支,客户端整包 deserialize failed。
|
||
//
|
||
//
|
||
// 背包里的物品(Reader[297] 的派生类 ExtractionShooterBagItemInfo)。
|
||
// 与物品基类唯一的区别是 complex marker —— 背包/容器内通行的是 1,不是 0xFF。
|
||
//
|
||
//
|
||
// 容器里的物品(Reader[1050] = Concrete[297][2])—— 在基类前面多了一个
|
||
// Pid2SearchFinishTimeDict。
|
||
// 这个字典是搜索动画的开关:空字典 = 未搜索 = 客户端把图标藏起来。
|
||
// 而且时间戳必须是未来的 —— 客户端 StartSearchStateTracker 里
|
||
// waitSeconds < 0 会被钳成 0,过去时间戳 ⇒ wait(0) 空转、动画播不出来。
|
||
//
|
||
//
|
||
// 容器内容(Reader[530])。CfgId 必须是配置表里的容器行 id —— 客户端拿它取容量和图标,
|
||
// 填 0 会得到「格子正确但整箱空」。
|
||
//
|
||
// ------------------------------------------------------------------ push
|
||
// SyncExtractionShooterContainerInfo(68820459) —— 容器内容的推送形态。
|
||
//
|
||
// SyncExtractionShooterSetItemInfo(64091558) —— 单件进包。
|
||
// ⛑ 物品必须包成复杂值且 marker=1(ExtractionShooterBagItemInfo)。
|
||
//
|
||
//
|
||
// SyncExtractionShooterChangeBagCapacity(64119720) —— 扩容后的真实格数。
|
||
// ⛑ 列表是 [x, y] 两个 i32,不是「每格写一个 1」。写成后者客户端会把容量读成
|
||
// 「宽 = 格子数、高 = 1」,面板排布全错。
|
||
//
|
||
// SyncExtractionShooterClearBag(64282046) —— 整包重推前先清空。
|
||
// SyncExtractionShooterSortBagResult(64226140) —— 排序后的整包。
|
||
// SyncExtractionShooterBagExpansionUnlocked(64359472)。
|
||
// SyncExtractionShooterTokenCount(64840255)。
|
||
// SyncExtractionShooterEvacuationPlayerState(64763956) —— 裸 u8。
|
||
// ------------------------------------------------------------------ settlement
|
||
//
|
||
// 单个角色(spirit)的战斗数据统计(Auto.Reader[1334])。
|
||
// 我们只有出场那一条、而且恒发空表,所以这里不填字段 —— 一旦填错字段布局,
|
||
// 客户端会在幽灵数据上做算术然后把整棵 UI 树崩掉(参考 handoff §11 第 4 条)。
|
||
// 什么时候要真数据:按抓包样本逐个字段补,不要对着 dump.cs 的空壳猜。
|
||
//
|
||
//
|
||
// 结算主体(Auto.Reader[474]):
|
||
// u32 EnterRaidTime + f64 BattleTime + list7<complex[1334]> + u32 ElementEffectCount。
|
||
// 这是 complex 目标(SyncRaidSettlement 里写的是 ReadComplex),
|
||
// 所以它必须带 marker(默认 0xFF),与顶层那些 Inline 契约相反。
|
||
//
|
||
// ------------------------------------------------------------------ requests
|
||
//
|
||
// 搜打撤的客户端 → 服务端请求体。
|
||
// ⛑️⛑️ 每个契约都必须是 [UxContract(Inline = true)]:C2S 请求体是「裸标量」,
|
||
// 客户端 SerializerHelper.*_Serializer 只挨个 WritePrimitive,不写对象标记。
|
||
// 漏了 Inline 会让 UxSerializer.Deserialize 先吃掉一个字节当标记(期望 0xFF),
|
||
// 于是 8 字节的实例 id 被读成「标记 + 只剩 7 字节」⇒ 越界抛异常 ⇒
|
||
// TryGetArgs 把这个异常 catch 掉并返回 false(见 UxRpcMessage.TryGetArgs)
|
||
// ⇒ 处理器拿到全默认值:容器实例 id 恒为 0、全世界共用一份快照。
|
||
// ⛑️ 字段顺序就是线上顺序,不要按"看起来合理"调整:顺序取自
|
||
// ClientToGameDelegate.lua / ClientToGameSceneDelegate.lua 的 *_Serializer。
|
||
// 本版的所有字段顺序都是捐赠端 实机暴露后订正过的(handoff §14.8)——
|
||
// 第一版移植时按"常见布局"猜的槽位那两条是错的:
|
||
// · ShiftContainerItemToSlot 只有 5 个字段、没有 isRotated,
|
||
// 第 4 个是槽位组包 id(99952004)、第 5 个是槽位下标;
|
||
// · ShiftSlotItemToContainer 是 bag 在前,u64 container 在第三个。
|
||
// 这两处写错的表现是「容器里的东西搬不出来 / 装备永远落到错误格」。
|
||
//
|
||
// ShiftItem(63749738, 25B):六种右键动作全走这一条,区别只是 destBag。
|
||
// RaidSplitItem(67597775, 25B):bag | container(u64) | x | y | count | isRotated。
|
||
//
|
||
// SyncRaidSettlement(68995324) —— 副本结算。
|
||
// ⛑ 线格式 u64 instance + bool isWin + complex[474] + u32 closeTime,
|
||
// 零战斗数据时恒 32 字节(handoff §6.7),这就是笔算校验:
|
||
// 8 + 1 + (FF 1 + u32 4 + f64 8 + 空 list7 2 + u32 4) + 4 = 32。
|
||
// 改动这个结构后如果字节数变了,一定是 dosing 错了地方(多半是把 complex 写成 Inline)。
|
||
//
|