91 lines
5.5 KiB
Go
91 lines
5.5 KiB
Go
package methods
|
||||
|
|
|
|||
|
|
// Client 4229938 police-career payloads (层 2a). Field order and framing are copied field-by-field
|
|||
|
|
// from the client's own reader table, lua/LuaGen/AutoGen/RPCDeserializeAuto.lua.
|
|||
|
|
//
|
|||
|
|
// Client 4229938 payload for SyncSpiritPoliceJobInfo (64349458) — the police phone app's data
|
|||
|
|
// backbone. Consumed by GameToClientImpl.SyncSpiritPoliceJobInfo ->
|
|||
|
|
// gPoliceJobManager.panelMgr:OnSpiritPoliceJobInfoSync (PolicePanelManager.lua:156), which indexes
|
|||
|
|
// serviceData / weeklyServiceData / violationInfo / dispatchInfo / fakeFileInfo by spiritId and then
|
|||
|
|
// dereferences DutyBasicInfo.ServiceData without a nil check.
|
|||
|
|
// Wire shape (lua RPCDeserializeAuto.midToReader[64349458]):
|
|||
|
|
// local spiritId = reader.ReadUInt32(reader)
|
|||
|
|
// local policeJobInfo = Base.ReadComplex(reader, Auto.Reader[353])
|
|||
|
|
// Two parameters — a bare scalar plus a complex value — so the frame is [spiritId][0xFF][fields],
|
|||
|
|
// i.e. Inline = true with no top-level marker (same family as SyncPoliceCompleteMissionCnt,
|
|||
|
|
// and the opposite of SyncHackerJobInfo's single-class-parameter frame).
|
|||
|
|
//
|
|||
|
|
//
|
|||
|
|
// Auto.Reader[353] — the whole police career state of one character, 8 fields.
|
|||
|
|
// ⛑️ Collection framing is the full-snapshot generation: Base.ReadList /
|
|||
|
|
// Base.ReadDict, i.e. an Int32 count, NOT the biased 7-bit count. The incremental police
|
|||
|
|
// packets use the other generation — SyncSpiritPoliceViolationInfos (64812240) and
|
|||
|
|
// SyncSpiritPoliceCaseInfos (64848107) call ReadList7Bit, SyncPoliceDispatchInfos (64393704)
|
|||
|
|
// calls ReadDict7Bit. Mixing the two silently desynchronises the whole frame.
|
|||
|
|
//
|
|||
|
|
//
|
|||
|
|
// C2S AskPoliceDispatch(63500791) — 执勤终端 / 轮盘上那颗派遣按钮真正发出的包。
|
|||
|
|
// Wire shape(lua ClientToGameDelegate.lua:3876 的 AskPoliceDispatch_Serializer):
|
|||
|
|
// <code>
|
|||
|
|
// SerializeBase.WritePrimitive(writer, dispatchid, writer.WriteUInt32, 0)
|
|||
|
|
// SerializeBase.WriteComplex(writer, extrainfo, Auto.WritePoliceDispatchExtraInfo, "extrainfo", true)
|
|||
|
|
// </code>
|
|||
|
|
// 即 u32 dispatchid + 一个 nullable complex(null ⇒ 单字节 0x00)。
|
|||
|
|
// 2026-09-24 23:46:42 的抓包正是 03000000 00(dispatchid=3,extrainfo=null),
|
|||
|
|
// 与这里的字段顺序逐字节对得上(硬规则 122:字段顺序只能看客户端序列化器,不能猜)。
|
|||
|
|
// ⛑ 返回体是空的:RPCDeserializeAuto.lua:11404 的
|
|||
|
|
// midToReturnMessageReader[63500791] 是一个空函数体 ⇒ 客户端不读任何回包字段,
|
|||
|
|
// 所以服务端只需回一个 empty OK(与 DefaultUnknownInvoke 兜底一致,不会改变客户端行为)。
|
|||
|
|
// ⛑⛑ Inline = true 不能省(2026-09-25 踩坑修复):序列化器的第一条语句是
|
|||
|
|
// WritePrimitive(dispatchid),说明 帧首没有对象 marker。少了 Inline 的话
|
|||
|
|
// UxSerializer.ReadValue 会把 dispatchid 的第一个字节当成 marker 吃掉,
|
|||
|
|
// 于是 dispatchid 读成 0、末尾还越界抛
|
|||
|
|
// Index was outside the bounds of the array —— 表现是「点了派遣按钮一点反应没有,
|
|||
|
|
// 日志刷 [POLICE] AskPoliceDispatch 解析失败」。判据见硬规则 133。
|
|||
|
|
//
|
|||
|
|
//
|
|||
|
|
// Auto.WritePoliceDispatchExtraInfo(RPCSerializeAuto.lua:8163)只有一个字段:
|
|||
|
|
// Base.WritePrimitive(writer, val.PrisonerId, writer.WriteUInt64, 0)。
|
|||
|
|
// 目前服务端不消费它,只是把字节吃掉,免得后面的字段错位。
|
|||
|
|
//
|
|||
|
|
//
|
|||
|
|
// C2S AskHelicopterNpc(67113443) — 直升机搜查里对一个被框住的 NPC 下判定。
|
|||
|
|
// Wire shape(ClientToGameSceneDelegate.lua:704):
|
|||
|
|
// <code>
|
|||
|
|
// SerializeBase.WritePrimitive(writer, instanceid, writer.WriteUInt64, 0)
|
|||
|
|
// SerializeBase.WritePrimitive(writer, SerializeBase.CheckEnum(optype, 55, 0), writer.WriteByte, 0)
|
|||
|
|
// </code>
|
|||
|
|
// 两个裸标量、没有对象 marker ⇒ Inline = true。
|
|||
|
|
// ⛑ 返回体是空的(RPCDeserializeAuto.lua:14935 的 return reader 空体)⇒ 只需 empty OK。
|
|||
|
|
// 但它是 INVOKE:不回执客户端 gReliableRpcManager:RegisterRPC 会永久挂起
|
|||
|
|
// (PoliceHelicopterPanelStore.lua:470 / :162 / :378 / :558 四个调用点全在等回调)。
|
|||
|
|
//
|
|||
|
|
//
|
|||
|
|
// C2S AskHelicopterScanChange(67898923) — 直升机扫描开关。
|
|||
|
|
// NOTIFY(ClientToGameSceneDelegate.lua:5197 用的是 self.Notify),无需回执。
|
|||
|
|
// 帧形 = 单个 bool,无 marker。
|
|||
|
|
//
|
|||
|
|
//
|
|||
|
|
// S2C SynExitHelicopterView(68309986) — 让客户端退出直升机视角。
|
|||
|
|
// 客户端实现(GameSceneToClientImpl.lua)就是 Close(gPanelId.S_POLICE_HELICOPTER),
|
|||
|
|
// reader 是空体 ⇒ 没有参数、没有字段。用 Inline 空契约,序列化出来是 0 字节。
|
|||
|
|
//
|
|||
|
|
// Auto.Reader[356]: one dispatch slot keyed by UrbanJobPoliceTaskConfig id.
|
|||
|
|
// Auto.Reader[424]: one live violation of the police duty state.
|
|||
|
|
//
|
|||
|
|
// Auto.Reader[1380]: duty counters. ServiceData / WeeklyServiceData are read as
|
|||
|
|
// complex values by the client with no nil check, so they must always be written.
|
|||
|
|
//
|
|||
|
|
// Auto.Reader[373]: the "今日服务" tally shown in the police app (daily and weekly).
|
|||
|
|
// Auto.Reader[391]: the fake-identity file archive (归档) carried by the police app.
|
|||
|
|
// Auto.Reader[333]: per-file state. State is a byte (PoliceFakeFileState).
|
|||
|
|
// Auto.Reader[390]: one archived clue holder; IsRead drives the side red dot.
|
|||
|
|
//
|
|||
|
|
// Auto.Reader[431]: one case record of the police career (16 fields).
|
|||
|
|
// Sentence is the only signed field; InterrogationInfo is a nested complex chain.
|
|||
|
|
//
|
|||
|
|
// Auto.Reader[1374]: interrogation state plus the RPS card payload.
|
|||
|
|
// Auto.Reader[1376].
|
|||
|
|
// Auto.Reader[1377].
|
|||
|
|
// Auto.Reader[1375].
|
|||
|
|
// Auto.Reader[1383] — struct (Base.ReadStruct), so no per-item object marker.
|