This repository has been archived on 2026-10-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Ananta-ps/pkg/protocol/methods/police_methods.go
T

92 lines
5.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.