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# 侧直发),但通道必须存在,否则切回去的路是死的。 //