99 lines
5.0 KiB
Go
99 lines
5.0 KiB
Go
package routers
|
||
|
||
import (
|
||
"context"
|
||
"sync"
|
||
)
|
||
|
||
var _ = sync.Mutex{}
|
||
var _ = context.Background
|
||
|
||
//
|
||
// 巡卫官(里希 / 15021021)盘查链路的最后一步 —— 开罚单出结果。
|
||
// <code>
|
||
// 客户端 PoliceExamineManager.lua:1163 gPoliceJobManager.cs:AskPoliceFine(pid, fineIdList)
|
||
// ⇒ C2S AskPoliceFineNpc(63548238)
|
||
// ⇒ 服务端必须回 S2C ShowReceiveRewardDetail(64145515) 且 Reason == ItemReason.PoliceFine(180001)
|
||
// ⇒ GameToClientImpl.lua:266 gPoliceJobManager:OnDropPoliceJobExp(msg.Reward)
|
||
// ⇒ PoliceExamineManager.lua:618 填 fineMoney / JobExpInfo
|
||
// ⇒ PoliceExamineManager.lua:601 ShowFineResult(罚款结果面板)
|
||
// </code>
|
||
// ⛑⛑ 为什么之前"开罚单没结果":AskPoliceFineNpc 既没进
|
||
// Enabled4229938MethodIds(硬规则 94)也没 handler ⇒ 客户端 await 卡死,
|
||
// 服务端从来没回过掉落帧 ⇒ needShowFineResult=true 但 OnDropPoliceJobExp
|
||
// 永远不触发 ⇒ ShowFineResult 一次都没被调用。
|
||
// ⛑ 反编译陷阱(又是同一条,见已作废结论):
|
||
// GameToClientImpl.lua:266 里写的是 if msg.Reason ~= ItemReason.PoliceFine then,
|
||
// 字面读是"非罚款才回调",但同一函数里 if msg.Reason ~= Mall or msg.Reason ~= MallBundle
|
||
// 恒为真会无条件 return ⇒ 字面读整段逻辑自相矛盾 ⇒ 反编译器把 == 翻成了 ~=。
|
||
// 真意:Reason == PoliceFine 时才走 OnDropPoliceJobExp。
|
||
// ItemReason.PoliceFine = 180001(dump.cs:1737137,enum ItemReason TypeDefIndex:32206)。
|
||
// 回滚 = 删本文件 + 从 GameRouter.cs 白名单删掉 MethodId.AskPoliceFineNpc。
|
||
//
|
||
// =================================================================================
|
||
// ① C2S AskPoliceFineNpc(63548238)
|
||
// =================================================================================
|
||
//
|
||
// 玩家在盘查面板里选完罪名、点「开罚单」时由 C# 侧发出来的那条。
|
||
// 形状:AskPoliceFine(ulong pid, object data)(dump.cs:673124),data 是 int[]。
|
||
// 极性 CSharpOnly ⇒ lua 没有 writer 可抄、count 编码不确定 ⇒ 不硬解析,
|
||
// 只把前 8 字节当 u64 pid 记日志,其余原样打 hex 留作取证。
|
||
// ⛑ 用 HandlerPacketKind.Both:INVOKE / NOTIFY 都不能漏。
|
||
// INVOKE 不回执 ⇒ 客户端 await 到超时(硬规则 94 的同一类坑)。
|
||
//
|
||
func GameRouter_PoliceFine_AskPoliceFineNpc(ctx context.Context, conn any, msg any) any {
|
||
// Router implementation for GameRouter_PoliceFine_AskPoliceFineNpc
|
||
var zero any; return zero
|
||
}
|
||
|
||
// =================================================================================
|
||
// ② S2C ShowReceiveRewardDetail(64145515) —— 手搓字节
|
||
// =================================================================================
|
||
//
|
||
// 推一帧 ShowReceiveRewardDetail(64145515, LuaOnly),Reason = PoliceFine(180001)。
|
||
// 载荷(照 Auto.Reader[308] / Auto.Reader[500],RPCDeserializeAuto.lua:37641 / 37521):
|
||
// <code>
|
||
// int32 Reason = 180001
|
||
// uint32 RewardTemplate = 0
|
||
// list FirstItemInfo = FF + int32 count + uint32* (空)
|
||
// cplx ExtraInfo = 00(null —— 必须 null!DropManager.lua:126 见 ExtraInfo 非空
|
||
// 就会拿 ExtraInfo.Pos 判"掉落物在地上"并 return,罚款结果就没了)
|
||
// dict Reward = FF + int32 count + { byte key, cplx RewardDetail }
|
||
// </code>
|
||
// RewardDetail(Reader[500])28 个字段全按声明顺序写,空的集合一律 FF + int32 0
|
||
// (Serializer.ReadList / ReadDict = peek byte FF + 原始 int32 count,不带 +1 偏置;
|
||
// 只有 ReadList7Bit / ReadDict7Bit 才走 Int7 +1 偏置)。
|
||
// SpiritTalentExpInfo 是 ReadComplex ⇒ 写 00。
|
||
// ⛑⛑ 关键判据(PoliceExamineManager.lua:618):
|
||
// <code>
|
||
// fineMoney = Σ RewardDetail.Money
|
||
// if RewardDetail.JobExpInfo[Police] then JobExpInfo = RewardDetail.JobExpInfo end
|
||
// if JobExpInfo or fineMoney <= 0 then ShowFineResult() end
|
||
// </code>
|
||
// ⇒ JobExpInfo 里必须命中 Police(11300003),否则 money>0 时永远不弹。
|
||
// 所以这里 money 与 exp 都给,双保险。
|
||
//
|
||
func GameRouter_PoliceFine_PushFineRewardAsync(ctx context.Context, session *GameSession, money float64, jobExp uint32, token context.Context) any {
|
||
// Router implementation for GameRouter_PoliceFine_PushFineRewardAsync
|
||
var zero any; return zero
|
||
}
|
||
|
||
// 照 Auto.Reader[308] / Auto.Reader[500] 手搓 ShowReceiveRewardDetail。
|
||
func GameRouter_PoliceFine_BuildFineRewardWire(ctx context.Context, money float64, jobExp uint32) []byte {
|
||
// Router implementation for GameRouter_PoliceFine_BuildFineRewardWire
|
||
return nil
|
||
}
|
||
|
||
// Serializer.ReadList 的空集合:peek FF + 原始 int32 count = 0。
|
||
func GameRouter_PoliceFine_EmptyList(ctx context.Context, w any) any {
|
||
// Router implementation for GameRouter_PoliceFine_EmptyList
|
||
var zero any; return zero
|
||
}
|
||
|
||
// Serializer.ReadDict 的空字典:peek FF + 原始 int32 count = 0。
|
||
func GameRouter_PoliceFine_EmptyDict(ctx context.Context, w any) any {
|
||
// Router implementation for GameRouter_PoliceFine_EmptyDict
|
||
var zero any; return zero
|
||
}
|
||
|