72 lines
4.8 KiB
Go
72 lines
4.8 KiB
Go
package methods
|
||
|
||
//
|
||
// 骑乘 / 厕所 QTE(马桶鸵鸟)契约 — 处理器在 GameRouter.ToiletQte.cs。
|
||
// <para>★★ 触发链(2026-09-30 从客户端反查,三条证据都实锤)</para>
|
||
// <list type="number">
|
||
// <item>Lua/LuaFiles/LX6/SGUI/StoreDefine/ToiletOstrichGamePanelStore.lua 就是那个 QTE 面板:
|
||
// 音游式三键判定,本地常量 QTE_DURATION=2 / PERFECT_WINDOW=0.1 /
|
||
// GREAT_WINDOW=0.2,满分 100(perfect 30 / normal 20)。判定纯客户端,
|
||
// 服务端不参与打分。</item>
|
||
// <item>面板由 C#→lua 回调打开,不是服务端推的:
|
||
// LX6/Manager/CsToLuaHandler.lua 里
|
||
// module.OnStartRideQTE(riderPid, beRidenPid) ⇒
|
||
// gPanelManager:CheckShow(gPanelId.TOILET_OSTRICH_GAME_PANEL, { npcPid = beRidenPid })。
|
||
// 所以 C# 只在「骑乘成立」时才 fire ⇒ 我们要做的是让骑乘坐实。</item>
|
||
// <item>面板里 SceneDataMgr.GetUnit(self.npcPid) ⇒ 被骑的那只必须是**世界里真实存在的 unit**。</item>
|
||
// </list>
|
||
// <para>★★ 马桶鸵鸟 = 标准 Agent,不是 Gadget / SceneItem</para>
|
||
// NpcCatalog.json 里 5 条同名(40122028 / 40652007 / 40922011 / 42046401 / 45000446),
|
||
// 同一具模型 GeneralModelId=86963029,EnemyClassType=1(与普通敌人同类),
|
||
// faction 18000300「通用怪物」;AgentConfig.ToiletOstrich = 42046401 是客户端自己的常量。
|
||
// 骑乘能力由**客户端 AI 状态树**给出(MassAI.Npc.MassAetherAI.Tasks.TryOnRideAgent /
|
||
// TryDownRideAgent,走 BehaviorActionConfigId 40214321 + AISetting 40213146),
|
||
// 服务端不需要给任何「可骑」标记 ⇒ 现有的 NPC/敌人生成通道(GameAdminBridge.SpawnAgentAsync)
|
||
// 直接就能出。
|
||
//
|
||
//
|
||
// AskRideAgent(67575069) —— 玩家请求骑上 agentId 这只单位。
|
||
// <para>形状(LuaGen/AutoGen/ClientToGameSceneDelegate.lua:3314,C2S Invoke):
|
||
// SerializeBase.WritePrimitive(writer, agentid, writer.WriteUInt64, 0) ⇒ 单个 u64。</para>
|
||
// 回包(RPCDeserializeAuto.lua:15516 midToReturnMessageReader[67575069])
|
||
// 函数体是空的 ⇒ 服务端必须回 0 字节;ReturnEmptyOkAsync 正是这个形状。
|
||
// ⛑ DefaultReturnCatalog4229938 里 没有 这个 mid ⇒ 不注册的话框架会走
|
||
// ReturnEmptyOkAsync 兜底,**形状恰好也是对的**,所以这一条不注册也未必报错;
|
||
// 注册的意义是:能观测(打日志)、以及把「骑上去了」这件事变成服务端可推的状态。
|
||
//
|
||
//
|
||
// AskToiletOstrichFlee(67154315) —— QTE 失败时**客户端主动上报**「鸵鸟跑了」。
|
||
// <para>形状(ClientToGameSceneDelegate.lua:945-951):self.Notify(self, 67154315, …)
|
||
// ⇒ Notify,不是 Invoke(无回包);载荷单个 u64 agentid。</para>
|
||
// 调用点是 ToiletOstrichGamePanelStore.lua:485 的失败分支:
|
||
// <code>
|
||
// gCS.BaseUnitUtils.DismountCheckScore()
|
||
// gCS.LogicStateMachineManager.SendGameplayInwardSignal(unit, 5754)
|
||
// gClientToGameSceneDelegate:AskToiletOstrichFlee(self.npcPid)
|
||
// </code>
|
||
// 成功分支则是 SendGameplayInwardSignal(unit, 5753),**不发这条**。
|
||
// ⛑ 因为它是 Notify,不注册只会落进 DefaultUnknownNotify(无害),但服务端就永远不知道
|
||
// QTE 失败过 ⇒ 这条必须接住,否则「鸵鸟该跑不跑」。
|
||
//
|
||
//
|
||
// SyncRideAgent(68906846) —— 服务端权威的骑乘状态(IGameSceneToClient.SyncRideAgent
|
||
// (ulong rider, ulong ridee, bool hasRideOn))。
|
||
// <para>形状:RPCDeserializeAuto.lua:7142 midToReader[68906846] 读
|
||
// UInt64 + UInt64 + Boolean = 17 字节,无对象 marker ⇒ Inline = true;
|
||
// 且 midToExportOption[68906846] = LuaAndCSharp(lua 侧也有 reader)。</para>
|
||
// ⛑ 是否必需尚未实测:OnStartRideQTE 也可能由 AskRideAgent 的回包路径直接 fire。
|
||
// 所以这条挂在开关 gameplay.toiletQte.pushRideState 后面,**默认关**;
|
||
// 若只注册骑乘回执时面板不出,把它打开(这与自动驾驶那条「服务端推状态」是同一个模式,
|
||
// 见 GameRouter.VehicleNav.cs 的包序教训:状态包要**早于**动作包)。
|
||
//
|
||
//
|
||
// SyncToiletPosture(68122107) —— 马桶鸵鸟的「蹲 / 起」姿态。
|
||
// <para>形状:ulong agentId + bool isSquatting = 9 字节(Inline = true)。
|
||
// ⛑ RPCDeserializeAuto.lua:714 把它标成 CSharpOnly ⇒ lua 侧没有 reader,
|
||
// 只由 C# 表现层消费。**别指望在 lua 日志里看到它**,判据只能在实机画面上。</para>
|
||
// ⛔ 官方还有一个「直接生成一只蹲着的马桶」的 GM 入口
|
||
// GmCreateToilet / GmCreateToiletSquatting(69686776 / 69250152,**无参** C2S GM Invoke),
|
||
// 那是开发调试用的,我们不走那条路(我们的生成都在服务端,见面板的
|
||
// /api/agent/spawn)⇒ 这条 S2C 挂在开关 gameplay.toiletQte.pushPosture 后面,默认关。
|
||
//
|