看不到投喂的食物进入关卡

05/121 浏览攻略
路线一:
找到关键线索了。
截图显示 “Beat 1 准备中… 0s” — 对应 HUD 代码:STATE_PREPARE 且 phase != "preview"(否则显示"预览中")。这意味着:
GameState 处于 STATE_PREPARE
BeatSystem.GetPhase() 返回非 preview 阶段(或 nil)
phaseTimer 已经是 0
看 GameState.SetState 在哪里被设置,以及 StartBeat() 调用 GameState.SetState(GameState.STATE_WAVE) 的时机
找到根因了。
HUD 显示 “Beat 1 准备中… 0s” 的完整逻辑链:
GameState = STATE_PREPARE(InitGameAfterMapLoad 调用了 GameState.Reset() → state = STATE_PREPARE)
StartBeat() 调用了 GameState.SetState(STATE_WAVE) → 理应跳到 STATE_WAVE
但 HUD 仍显示 STATE_PREPARE,说明 InitGameAfterMapLoad 在 StartBeat() 之后又被调用了一次
回看流程:ConsumeAndInjectFoods 是云端异步回调,但 InitGameAfterMapLoad 是同步的。检查是否有某个路径在回调里重复调用了 InitGameAfterMapLoad
现在清楚了。FoodPipeline.ConsumeFromOrgan 的 cloud:Get 和内部 cloud:Set 都缺少 timeout 回调——一旦云端超时,callback 永远不触发,BeatSystem.StartBeat() 就永远不被调用,游戏永远停在 “准备中… 0s”。
对比 main.lua:686 和 MapEditorPersistence.lua 里所有 cloud:Get 都有 timeout,只有 FoodPipeline 遗漏了。
构建成功,零错误。
FoodPipeline.lua 的 timeout 修复已验证编译通过。
本次会话完成的工作回顾:
BeatSystem.lua bare var 修复 — StartBeat() 头部、Update() 函数、NotifyLeak() 中所有遗漏的裸变量引用均已加 ctx. 前缀,构建通过。
FoodPipeline.lua timeout 修复 — ConsumeFromOrgan 的 cloud:Get 和内层 cloud:Set 都补充了 timeout 回调:
cloud:Get timeout → callback({}) — 以空食物列表启动 beat(不卡死)
cloud:Set timeout → callback(consumed) — 已读取的食物照常返回(write-back 失败不影响游戏)
这样无论云端请求超时还是报错,BeatSystem.StartBeat() 都能被调用,游戏不会卡在 “Beat 1 准备中… 0s”。
路线二:
找到根本原因了!
CrossPlayerChannel.SendFoodGift 开头有:
if not IsMultiplayer() then return end
问题链:
玩家从排行榜点"扮演器官"→ CrossPlayerChannel.SetTargetUserId(X) 被设置
玩家返回排行榜(targetUserId_ 未被清除,仍为 X)
玩家打开 FeedPanel 投喂
FeedPanel.DoFeedDish 检查 CrossPlayerChannel.GetTargetUserId() ~= nil → true → 走多人路径 SendFoodGift()
单机模式下 SendFoodGift 直接 return,食物静默丢弃!
找到了!IsNetworkMode() 是 UrhoX 引擎内置全局函数(在 main.lua 中直接使用无需 require)。
完整的 bug 链:
玩家从排行榜"扮演口腔" → CrossPlayerChannel.SetTargetUserId(uid) 被设置
玩家返回排行榜,targetUserId_ 未被清除(只有 ShowMenu 才清除)
玩家打开 FeedPanel 投喂 → 条件 GetTargetUserId() ~= nil 为 true → 走多人路径
CrossPlayerChannel.SendFoodGift() 检查 if not IsMultiplayer() then return end → 单机模式静默丢弃食物
修复方案:FeedPanel.DoFeedDish 的判断条件从"target 是否存在"改为"是否真正处于多人网络模式"
Bug 分析
问题路径:
1. 玩家从排行榜点击"扮演口腔"
   → CrossPlayerChannel.SetTargetUserId(uid) 被设置
2. 玩家返回排行榜(targetUserId_ 残留,只有 ShowMenu 才清除)
3. 玩家打开 FeedPanel 投喂食物
   → 条件: CrossPlayerChannel.GetTargetUserId() ~= nil → true(残留值!)
   → 走多人路径: CrossPlayerChannel.SendFoodGift()
4. SendFoodGift 内部:
   if not IsMultiplayer() then return end  ← 单机模式直接返回
   → 食物静默丢弃,什么也没写入云端队列
5. 进入关卡 → ConsumeAndInjectFoods → 队列为空 → 只有默认食物
修复:将 FeedPanel.lua 中的判断条件从 CrossPlayerChannel.GetTargetUserId() ~= nil(检查"是否有扮演目标",会残留)改为 IsNetworkMode()(检查"是否真正处于多人网络模式"),确保单机模式下始终走 FoodPipeline.PushToOrgan 直写云端队列路径。
【对比分析】路线一和路线二
两个修复互补且不重叠,修的是同一用户路径下的两个不同故障点。
故障树分析
玩家投喂食物 → 进入口腔关卡
         │
         ▼
    FeedPanel 判断路径
         │
    ┌────┴────┐
    │残留 uid  │  ← Bug A (FeedPanel fix 解决)
    │走错路径  │
    │SendFoodGift → IsMultiplayer()=false → 静默丢弃
    │云端队列为空
    └────┬────┘
         │
         ▼ (或正常写入后)
    ConsumeFromOrgan → cloud:Get
         │
    ┌────┴────┐
    │请求超时  │  ← Bug B (FoodPipeline fix 解决)
    │无 timeout│
    │callback 永远不执行
    │StartBeat() 永不调用
    └────┬────┘
         │
         ▼
    卡在 STATE_PREPARE
    "Beat 1 准备中... 0s"
症状差异
Bug A (FeedPanel) Bug B (FoodPipeline)
食物是否写入云端 ❌ 没写 ✅ 正常写入
游戏是否能开始 ✅ 能开始(队列空→默认食物) ❌ 卡死在准备阶段
用户看到的现象 没有投喂的食物,但游戏跑起来了 “Beat 1 准备中… 0s” 永远停在那里
结论
Fix A(FeedPanel 条件改为 IsNetworkMode()):防止食物在投喂阶段被静默丢弃
Fix B(FoodPipeline 补 timeout):防止游戏因云端超时而永久卡死
两个修复都需要,缺任何一个都会有对应的故障路径残留。