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

125 lines
6.2 KiB
Go
Raw Permalink 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 routers
import (
"context"
"sync"
)
var _ = sync.Mutex{}
var _ = context.Background
//
// T2-32 路人骇入(Seymour 骇入路人的手机看信息)—— 2026-09-24 接入。
// 整条链路客户端早就写好了,服务端只缺两样东西(取证见
// modules/黑客大停电与广告牌坐标.md §7.8):
// 1. 从来没推过 SyncUnitHackableState(68941159) ⇒ C# 的 HackManager.hackUnitTarget
// 永远是 nil ⇒ GadgetManager.RefreshHackInteract 不会把路人装进
// HackInteractList ⇒ 路人身上根本没有骇入按钮;
// 2. 三个 C2S(AskHackingNpc 67070057 / AskHackingNpcPress 67747341 /
// ReportBeHacked 67093669)没进白名单 ⇒ 就算玩家按了也是静默落兜底,
// 而前两个是 Invoke,不 ack 会让客户端 await 卡死。
// 两者完全自洽:logs/unknown-methods.log 里 AskHackingNpc 命中 0 次。
// ⛑️ 本文件不实现"看信息"的内容:面板(HackerInfoPanelStore.lua:267 /
// HintInfosHudStore.lua:2132)读的是客户端手里的 NPC 数据,服务端只负责放行。
//
//
// 把一个 NPC 标记为可骇 / 取消标记。
// 与载具那套(SyncVehicleHackableState + SyncVehicleBrokenCollision)对齐:
// 只在状态翻转时发,重复发同一个值没有意义(C# 侧就是个集合/标志位)。
//
func GameRouter_HackNpc_PublishNpcHackableAsync(ctx context.Context, session *GameSession, unitId uint64, hackable bool, token context.Context) any {
// Router implementation for GameRouter_HackNpc_PublishNpcHackableAsync
var zero any; return zero
}
//
// NPC 出场时调一次。 gate:Gameplay.HackNpc.MarkSpawnedNpcs。
// 放在 SendCivilianAsync / SendAmbientCrowdPedAsync 的尾部 ——
// 必须先有单位(StaticNpcAddData / CrowdAdd + ManagedLogicAgent),
// C# 才能在 SceneDataMgr.GetUnit(unitId) 里找到它。
//
func GameRouter_HackNpc_MarkNpcHackableOnSpawnAsync(ctx context.Context, session *GameSession, unitId uint64, channel any, token context.Context, skipPhone bool) any {
// Router implementation for GameRouter_HackNpc_MarkNpcHackableOnSpawnAsync
var zero any; return zero
}
//
// ⭐ 给 NPC 发一部手机并让他正在玩/正在打 —— 骇入面板下面那排按钮就是从这儿来的。
// 证据链(2026-09-24,用户回报"骇入路人后只能看名字,不像汽车/售货机有选项"):
// 1. HackerInfoPanelStore.lua:119(反编译,比较符极性反转)路人分支走
// self.textIds = HackManager:GetUnitHackBtns(data.unit),
// btnNum = min(#textIds,3) ⇒ 列表为空就是"只剩标题(名字)";
// 2. GetUnitHackBtns 遍历六个 NpcHackSkill,逐个问 CanUse(unit, tracker, debug);
// 3. PhoneUsageSkillBase.CanUseInternal 看的是
// BelongingBelongingUsageConfig.HackType,全三条非 0 的 usage 都要求持有手机
// BelongingSceneItem = 80003481;
// 4. 我们下发的 crowd 行人没有任何 belongings,而 static NPC 用的是 POI 的 usage
// (18/86/93/237/238/241 —— HackType 全 0)⇒ 一条都对不上 ⇒ 零按钮。
// 与 GameRouter.Civilians.cs / GameRouter.DonorNpc.cs 给 NPC 递道具的路径完全同包同结构,
// 只是把"POI 决定拿什么"换成"一律给手机"。
//
func GameRouter_HackNpc_PublishNpcPhoneAsync(ctx context.Context, session *GameSession, unitId uint64, channel any, token context.Context) any {
// Router implementation for GameRouter_HackNpc_PublishNpcPhoneAsync
var zero any; return zero
}
//
// 敌人版本的手持道具 —— 与 PublishNpcPhoneAsync 同一套 wire
// (SyncAgentBelongings → SyncAgentUseBelongingChanged),只是配置源换成
// gameplay.combat.enemies,调敌人手里的东西时不会动到全城路人。
// 为什么单独一份:两者的生命周期完全不同。路人的手机要在每次 SendCivilianAsync
// / crowd ped 出场时按 MaxPhonedNpcs 计数限量推;敌人是 GM 面板一次性指令,
// 数量本来就很少,再套那层保险丝只会让第 N 个敌人之后突然不带东西,很难解释。
// ⛑ 调用时机必须在单位已经在客户端落地之后(SyncManagedLogicAgent +
// SyncRaidBattleUnitAgent 都已发出),否则 SceneDataMgr.GetUnit(uid)
// 查不到这个单位,两个包都会被静默丢掉。
//
func GameRouter_HackNpc_PublishEnemyPropAsync(ctx context.Context, session *GameSession, unitId uint64, templateId uint32, token context.Context) any {
// Router implementation for GameRouter_HackNpc_PublishEnemyPropAsync
var zero any; return zero
}
//
// AskHackingNpc(67070057) — 玩家点下了路人骇入按钮。
// ⛑️ 必须 HandlerPacketKind.Both:客户端走的是 Invoke
// (ClientToGameSceneDelegate.lua:489),但按 AskControlAgent 那次的教训,
// 同族 RPC 会有 NOTIFY 变体,只注册 Invoke 就是静默丢包。
// 返回体是空 reader ⇒ ReturnEmptyOkAsync(对 NOTIFY 是 no-op)。
//
func GameRouter_HackNpc_OnAskHackingNpc(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_HackNpc_OnAskHackingNpc
var zero any; return zero
}
//
// AskHackingNpcPress(67747341) — 长按骇入的那一下(GadgetManager.lua:1851)。
// 同样是 Invoke + 空 reader。
//
func GameRouter_HackNpc_OnAskHackingNpcPress(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_HackNpc_OnAskHackingNpcPress
var zero any; return zero
}
//
// ReportBeHacked(67093669) — NOTIFY,客户端告知"这些单位被骇了"。
// 纯记账:没有 ack,也没有需要回推的包(面板内容在客户端)。
//
func GameRouter_HackNpc_OnReportBeHacked(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_HackNpc_OnReportBeHacked
var zero any; return zero
}
//
// NPC 的来路。手机要不要发,两条通道的政策不同(HackNpcSettings 里各有一个开关):
// crowd 行人本来一件 belongings 都没有,static NPC 则由 POI 决定拿什么在做什么。
//
type HackNpcChannel int32
const (
// crowd 行人(SendAmbientCrowdPedAsync,SyncAetherAICrowdAdd)。
HackNpcChannel_Crowd HackNpcChannel = iota
// 服务端自己生成的 static NPC(SendCivilianAsync,SyncAetherAIStaticNpcAddData)。
HackNpcChannel_Static
)