package methods
//
// 黑客 APP 召唤物(蜘蛛机器人 / 送货无人机)的下行契约 — build 4229938。
// 三个接口的 C# 签名取自 dump.cs(IGameSceneToClient 抽象声明),不是猜的:
// line 1731952 SyncSwitchControl(ulong spiritId, ulong agentEntityId, bool enterOrLeave, SwitchControlReason reason) = 68552741
// line 1731949 SyncControllableAgent(ulong spiritId, ulong agentEntityId) = 68376522
// line 1731955 SyncCurrentControlSummonAgent(ulong spiritId, ulong agentEntityId) = 68857170
// 注意 68857170 的名字带 IGameSceneToClient_ 前缀,68552741 / 68376522 不带 —— 这是拖拽_export
// 表自身的命名,不影响 wire。
// ⛔ 这三个都是 服务端主动下行。客户端不会问,服务端才 Decide 何时把玩家塞进 / 退出
// 召唤物的操控位。
//
//
// SyncSwitchControl(68552741) — 玩家接管 / 交还召唤物。
// 客户端实现 GameSceneToClientImpl.SyncSwitchControl(lua.zip):
//
// gCS.BaseUnitModuleUtils.DoHackEnemy(spiritId, enemyId, enterOrLeave) -- 真正夺取控制权
// local cs_unit = gCS.SceneDataMgr.GetUnit(enemyId)
// if not cs_unit or not cs_unit.ClientData or not cs_unit.ClientData.AgentId then
// print_error("unit 数据错误", enemyId); return -- ← 卡死点①
// local summonCfg = LTConfig.SummonConfig.GetConfig(agentCfg.SummonTag)
// if not summonCfg then print_error(...); return end -- ← 卡死点②
// gMessageManager:SendMessage(gEventConstants.ANDROID_CONTROL_SWITCH, data)
//
// 两个前置反过来就是这个 服务端要负责的东西:
// ① 单位必须真实存在于 SceneDataMgr 且 ClientData.AgentId 非空 —— 只有在
// SyncAgentCampInfo / SyncManagedLogicAgent 那批 spawn 包走完并且客户端建号之后才成立,
// 所以本1724包必须在 spawn 完成后再发。
// ② AgentConfig[agentId].SummonTag 必须在 SummonConfig 里有对应条目。
// 40120908 SummonTag=2(蜘蛛)/ 40120909 SummonTag=1(无人机),SummonConfig 共 5 条,
// 两条都在 —— 挑 agentId 时必须落在带 SummonTag 的那 14 个模板里。
// reason 不参与任何分支判断,只是透传给 UI 的 data.reason。客户端
// SwitchControlReason 枚举(dump.cs line 1736857):
// None=0 Skill=1 Client=2 ClientWithdraw=3 ClientSwitch=4 System=5
// Desinger=6 DesignerLoading=7 Distance=8 SummonedAgentDead=9 ControllerDead=10
// 我们是从黑客技能进来的,填 Skill=1。
//
//
// SyncControllableAgent(68376522) — 告知客户端「当前可操控的 agent 是谁」。
// 客户端侧只做两件事:gBattleMgr.SummonAgentId = agentId,然后广播 SUMMON_STATE_SWITCH。
// 它不像 SyncSwitchControl 那样会去查 ClientData,因此可以先于 / 独立于接管发出。
//
//
// SyncCurrentControlSummonAgent(68857170) — 同上同签名,但语义是「当前正在操控」。
// 目前没有在 lua.zip 里找到 GameSceneToClientImpl.SyncCurrentControlSummonAgent 的实现,
// 所以它大概率由 C# 侧(BaseUnitModule)直接消费。先备着,未启用。
//
//
// C2S AskStopControlAgent(67046103) — 玩家主动放弃召唤物操控。
// 签名取自 dump.cs line 1730056:UXRPCTask AskStopControlAgent(bool clearAgent),
// 序列化器见 lua.zip ClientToGameSceneDelegate.AskStopControlAgent(u8 bool)。
// 两个调用点都在 RobotSpiderControlStore.lua:
//
// -- 长按 F 回收:progress > 1 时
// gLoadingManager:Quick_ViewFocusChange_Robot(SummonConfig.TypeType.SpiderBot)
// gReliableRpcManager:RegisterRPC(gClientToGameSceneDelegate.AskStopControlAgent, true, cb)
// -- N 键切换操控:OnBtnSwitchControlPress
// gReliableRpcManager:RegisterRPC(gClientToGameSceneDelegate.AskStopControlAgent, false, cb)
//
// 即 clearAgent=true = 回收并销毁单位,false = 只交还操控、单位留在场上。
// ⛔ 这是 INVOKE。客户端用 gReliableRpcManager:RegisterRPC 等回执,不回会让
// 操控面板的 await 永远不落地(表现为按钮按了没反应)。
//
//
// SyncAgentCompanionAI(68277327) — 把一个已经在场的单位标成「随从单位」。
// 签名取自 dump.cs line 1900945(IGameSceneToClient 抽象声明,非猜测):
// SyncAgentCompanionAI(ulong pid, bool isCompanionAI) = 68277327
// ⛑ 客户端 lua 里**没有**这个实现(lua.zip 只有 RPCMethodIdToName 里有它的名字),
// 消费方在客户端 C# —— 也就是说跟随/协战那一整套是客户端自己的 C# 状态机,
// 服务端要做的只是把这两个包推下去。主线此前零调用点。
//
//
// SyncCompanionMaster(68813982) — 把随从绑到主人身上(「这是谁的随从」)。
// 签名取自 dump.cs line 1901368:
// SyncCompanionMaster(ulong companionId, ulong masterId) = 68813982
// ⛑ masterId = 主人的 pid,与 SyncManagedLogicAgent.pid / 单位的
// ManagedPid 同源,都是 Profile.PlayerPid(本机日志里恒为 100)。
// ⛔ 不是 FightSpirit 模板 id(15020989 那一类)—— 主人是场上的实体。
//
//
// C2S AskControlAgent(67291468) — 重新接管一个已在场上的召唤物(N 键切回机器人的那一半)。
// 签名取自 dump.cs line 1730053:void AskControlAgent(ulong agentEntityId, SwitchControlReason reason)。
// lua.zip 里没找到调用方(C# 侧直发),但通道必须存在,否则切回去的路是死的。
//