From 3c7f8fab99120b6a75929601c39d46788756097a Mon Sep 17 00:00:00 2001 From: daixiawu Date: Sun, 28 Jun 2026 00:54:41 +0800 Subject: [PATCH] Delay first-meet UI until owner turn --- .../TH1_Core/Managers/PresentationManager.cs | 80 +++++++++++++++++++ .../Scripts/TH1_Logic/Action/ActionLogic.cs | 1 + .../Scripts/TH1_Logic/Player/PlayerLogic.cs | 11 +-- 3 files changed, 84 insertions(+), 8 deletions(-) diff --git a/Unity/Assets/Scripts/TH1_Core/Managers/PresentationManager.cs b/Unity/Assets/Scripts/TH1_Core/Managers/PresentationManager.cs index da4d80574..0104bf6db 100644 --- a/Unity/Assets/Scripts/TH1_Core/Managers/PresentationManager.cs +++ b/Unity/Assets/Scripts/TH1_Core/Managers/PresentationManager.cs @@ -29,6 +29,7 @@ namespace TH1_Core.Managers private static Queue _taskNextFrameQueue = new Queue(); private static Queue _taskNotCurPlayList = new Queue(); private static readonly List _pendingHakureiPaymentNotices = new(); + private static readonly List _pendingFirstMeetNotices = new(); private static bool _isBusy; private static ISequencerTask _currentTask; @@ -75,6 +76,7 @@ namespace TH1_Core.Managers _taskNextFrameQueue.Clear(); _taskNotCurPlayList.Clear(); _pendingHakureiPaymentNotices.Clear(); + _pendingFirstMeetNotices.Clear(); _currentTask = null; CurrentScope = null; } @@ -91,6 +93,7 @@ namespace TH1_Core.Managers _taskNextFrameQueue.Clear(); _taskNotCurPlayList.Clear(); _pendingHakureiPaymentNotices.Clear(); + _pendingFirstMeetNotices.Clear(); _currentTask = null; CurrentScope = null; BusyType = null; @@ -216,6 +219,52 @@ namespace TH1_Core.Managers _pendingHakureiPaymentNotices.Add(notice); } + public static void AddPendingFirstMeetNotice(MapData map, PlayerData receiver, PlayerData metPlayer, + int coinAmount) + { + if (map == null || map != Main.MapData) return; + if (receiver == null || metPlayer == null) return; + if (!map.CanLocalControlPlayer(receiver.Id)) return; + + var notice = new PendingFirstMeetNotice + { + ReceiverPlayerId = receiver.Id, + MetPlayerId = metPlayer.Id, + CoinAmount = coinAmount + }; + if (HasPendingFirstMeetNotice(notice)) return; + _pendingFirstMeetNotices.Add(notice); + EnqueuePendingFirstMeetNotices(map, receiver); + } + + public static void EnqueuePendingFirstMeetNotices(MapData map, PlayerData receiver) + { + if (map == null || receiver == null) return; + if (map != Main.MapData) return; + if (map.CurPlayer == null || map.CurPlayer.Id != receiver.Id) return; + if (!map.CanLocalControlPlayer(receiver.Id)) return; + if (map.PlayerMap?.SelfPlayerData != receiver) return; + + for (var i = 0; i < _pendingFirstMeetNotices.Count;) + { + var notice = _pendingFirstMeetNotices[i]; + if (notice.ReceiverPlayerId != receiver.Id) + { + i++; + continue; + } + + _pendingFirstMeetNotices.RemoveAt(i); + EnqueueTask(new UISequencerTask(ViewControllerManager.UIAnnounceMajorEventController, + new ShowUIAnnounceMajorEvent + { + EventType = UIAnnounceMajorEventType.FirstMeet, + Param1 = (int)notice.MetPlayerId, + Param2 = notice.CoinAmount + }), true); + } + } + public static void EnqueuePendingHakureiPaymentNotices(MapData map, PlayerData receiver) { if (map == null || receiver == null) return; @@ -290,6 +339,25 @@ namespace TH1_Core.Managers return false; } + private static bool HasPendingFirstMeetNotice(PendingFirstMeetNotice notice) + { + foreach (var pending in _pendingFirstMeetNotices) + { + if (pending.ReceiverPlayerId == notice.ReceiverPlayerId + && pending.MetPlayerId == notice.MetPlayerId) + return true; + } + + return false; + } + + private struct PendingFirstMeetNotice + { + public uint ReceiverPlayerId; + public uint MetPlayerId; + public int CoinAmount; + } + private static bool HasQueuedCityLevelUpChoice(uint cityId, int cityLevel) { return IsCityLevelUpChoiceTask(_currentTask, cityId, cityLevel) @@ -469,6 +537,17 @@ namespace TH1_Core.Managers while(_taskNotCurPlayList.Count > 0) _taskQueue.Enqueue(_taskNotCurPlayList.Dequeue()); } + + private static void CheckPendingLocalPlayerNotices() + { + var mapData = Main.MapData; + var curPlayer = mapData?.CurPlayer; + if (curPlayer == null) return; + if (!mapData.CanLocalControlPlayer(curPlayer.Id)) return; + if (mapData.PlayerMap?.SelfPlayerData != curPlayer) return; + + EnqueuePendingFirstMeetNotices(mapData, curPlayer); + } @@ -493,6 +572,7 @@ namespace TH1_Core.Managers { //如果当前是我的回合,并且_taskNotCurPlayList缓存队列不为空,把所有这些加入队列 CheckNotCurQueue(); + CheckPendingLocalPlayerNotices(); //每帧开始前,检查“下一帧队列”的是否有内容,将所有内容加入当前的队列 CheckNextFrameQueue(); TryProcessNext(); diff --git a/Unity/Assets/Scripts/TH1_Logic/Action/ActionLogic.cs b/Unity/Assets/Scripts/TH1_Logic/Action/ActionLogic.cs index 04974a840..a3dd78c47 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Action/ActionLogic.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Action/ActionLogic.cs @@ -3270,6 +3270,7 @@ namespace Logic.Action && actionParams.MapData.CanLocalControlPlayer(actionParams.PlayerData.Id); if(canLocalControlTurnPlayer) { + PresentationManager.EnqueuePendingFirstMeetNotices(actionParams.MapData, actionParams.PlayerData); PresentationManager.EnqueuePendingHakureiPaymentNotices(actionParams.MapData, actionParams.PlayerData); PresentationManager.EnqueuePendingDanegeldChoices(actionParams.MapData, actionParams.PlayerData); PresentationManager.EnqueuePendingCityLevelUpChoices(actionParams.MapData, actionParams.PlayerData); diff --git a/Unity/Assets/Scripts/TH1_Logic/Player/PlayerLogic.cs b/Unity/Assets/Scripts/TH1_Logic/Player/PlayerLogic.cs index f29141f8c..bacbf8e1f 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Player/PlayerLogic.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Player/PlayerLogic.cs @@ -1174,14 +1174,9 @@ namespace Logic } //step #5 - //如果是玩家,出发ui提示。加钱的操作要在ui提示关闭的时候由ui来出发 - //只在真实 Main.MapData 上弹,避免 AI 预测/模拟的虚假 MapData 误触发 - if (map == Main.MapData && p1 == map.PlayerMap.SelfPlayerData) - { - var announcement = new ShowUIAnnounceMajorEvent { EventType = UIAnnounceMajorEventType.FirstMeet,Param1 = (int)p2.Id,Param2 = coin}; - EventManager.Publish(announcement); - //UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.MeetNewPlayer,player1,grid); - } + //首遇 UI 按归属玩家延后到其本机可操作回合展示,避免队友回合中的被动视野刷新阻塞后续演出。 + //真实金币已在上方 AddCoin_LogicOnly 同步写入;UI 关闭时只播放 ViewOnly 金币动画。 + PresentationManager.AddPendingFirstMeetNotice(map, p1, p2, coin); } public void InitSingleTeammateMeetAndSight(MapData map)