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): // // SerializeBase.WritePrimitive(writer, dispatchid, writer.WriteUInt32, 0) // SerializeBase.WriteComplex(writer, extrainfo, Auto.WritePoliceDispatchExtraInfo, "extrainfo", true) // // 即 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): // // SerializeBase.WritePrimitive(writer, instanceid, writer.WriteUInt64, 0) // SerializeBase.WritePrimitive(writer, SerializeBase.CheckEnum(optype, 55, 0), writer.WriteByte, 0) // // 两个裸标量、没有对象 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.