重构:修复 Shop 与 ItemTooltip 跨模块事件边界问题

- 将 _tooltipLocked 状态从 ItemTooltipController 移到 ShopController 维护
- DisplayItem 只发 Shop 模块 UI 事件(Hover/Lock/Hide)
- ItemTooltipForm 取消按钮发 ItemTooltip 模块事件自关闭
- ShopController 通过 UIRouter 跨模块控制 ItemTooltipForm
- 移除 DisplayItemHideEventArgs 的 Force 字段,分离两种关闭场景
This commit is contained in:
2026-06-17 09:37:44 +08:00
parent 2590f31250
commit c30b256d7a
24 changed files with 340 additions and 213 deletions
@@ -2,9 +2,9 @@ using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using SepCore.Event;
using SepCore.Definition;
using SepCore.CustomUtility;
using SepCore.Entity.Weapon;
using GameFramework.Event;
using SepCore.DataTable;
using UnityEngine;
using UnityGameFramework.Runtime;
@@ -14,6 +14,7 @@ namespace SepCore.UI
{
private ShopUseCase _useCase;
private ShopRawData _rawData;
private bool _tooltipLocked = false;
protected override UIFormType UIFormType => UIFormType.ShopForm;
@@ -24,18 +25,26 @@ namespace SepCore.UI
protected override void SubscribeCustomEvents()
{
GameEntry.Event.Subscribe(RefreshEventArgs.EventId, Refresh);
GameEntry.Event.Subscribe(ShopRefreshEventArgs.EventId, ShopRefresh);
GameEntry.Event.Subscribe(ShopPurchaseEventArgs.EventId, ShopPurchase);
GameEntry.Event.Subscribe(ShopContinueEventArgs.EventId, ShopContinue);
GameEntry.Event.Subscribe(ItemTooltipShowEventArgs.EventId, DisplayItemShow);
GameEntry.Event.Subscribe(DisplayItemHoverEventArgs.EventId, DisplayItemHover);
GameEntry.Event.Subscribe(DisplayItemLockEventArgs.EventId, DisplayItemLock);
GameEntry.Event.Subscribe(DisplayItemHideEventArgs.EventId, DisplayItemHide);
GameEntry.Event.Subscribe(PlayerCoinChangeEventArgs.EventId, PlayerCoinChange);
GameEntry.Event.Subscribe(OpenUIFormSuccessEventArgs.EventId, OpenUIFormComplete);
}
protected override void UnsubscribeCustomEvents()
{
GameEntry.Event.Unsubscribe(RefreshEventArgs.EventId, Refresh);
GameEntry.Event.Unsubscribe(ShopRefreshEventArgs.EventId, ShopRefresh);
GameEntry.Event.Unsubscribe(ShopPurchaseEventArgs.EventId, ShopPurchase);
GameEntry.Event.Unsubscribe(ShopContinueEventArgs.EventId, ShopContinue);
GameEntry.Event.Unsubscribe(ItemTooltipShowEventArgs.EventId, DisplayItemShow);
GameEntry.Event.Unsubscribe(DisplayItemHoverEventArgs.EventId, DisplayItemHover);
GameEntry.Event.Unsubscribe(DisplayItemLockEventArgs.EventId, DisplayItemLock);
GameEntry.Event.Unsubscribe(DisplayItemHideEventArgs.EventId, DisplayItemHide);
GameEntry.Event.Unsubscribe(PlayerCoinChangeEventArgs.EventId, PlayerCoinChange);
GameEntry.Event.Unsubscribe(OpenUIFormSuccessEventArgs.EventId, OpenUIFormComplete);
}
#region BuildContext
@@ -53,7 +62,8 @@ namespace SepCore.UI
List<GoodsItemContext> goodsItems = new List<GoodsItemContext>();
foreach (var item in rawData.GoodsItems)
{
goodsItems.Add(await GoodsItemContext.CreateAsync(item));
var context = await CreateGoodsItemContextAsync(item);
goodsItems.Add(context);
}
return new ShopContext
@@ -65,7 +75,12 @@ namespace SepCore.UI
PropListContext =
BuildDisplayListAreaContext(DisplayListAreaType.Prop, rawData.PropItems, rawData.PropMaxCount),
WeaponListContext = BuildDisplayListAreaContext(DisplayListAreaType.Weapon, rawData.WeaponItems,
rawData.WeaponMaxCount)
rawData.WeaponMaxCount),
NeedRefreshGoodsItems = true,
NeedRefreshPlayerCoin = true,
NeedRefreshPropList = true,
NeedRefreshWeaponList = true,
NeedRefreshPrice = true
};
}
@@ -199,14 +214,28 @@ namespace SepCore.UI
listContext.CurrentCount = oldCount + 1;
}
private async UniTask<GoodsItemContext> CreateGoodsItemContextAsync(GoodsItemRawData rawData,
float timeout = 30f)
{
var context = new GoodsItemContext(rawData);
context.Icon = context.ItemType switch
{
ItemType.Weapon => await GameEntry.SpriteCache.GetSprite(((DRWeapon)rawData.DataRow).IconAssetName),
ItemType.Prop => await GameEntry.SpriteCache.GetSprite(((DRProp)rawData.DataRow).IconAssetName),
_ => null
};
return context;
}
#endregion
#region UI Methods
public override async UniTask CloseUIAsync(object userData = null, float timeout = 30f)
{
GameEntry.Event.Fire(this, ItemTooltipHideEventArgs.Create(true));
GameEntry.UIRouter.CloseUIAsync(UIFormType.ItemTooltipForm).Forget();
_rawData = null;
_tooltipLocked = false;
await base.CloseUIAsync(userData, timeout);
}
@@ -271,8 +300,10 @@ namespace SepCore.UI
for (int i = 0; i < result.GoodsItems.Count; i++)
{
if (i < Context.GoodsItems.Count)
Context.GoodsItems[i] = await GoodsItemContext.CreateAsync(result.GoodsItems[i]);
else Context.GoodsItems.Add(await GoodsItemContext.CreateAsync(result.GoodsItems[i]));
{
Context.GoodsItems[i] = await CreateGoodsItemContextAsync(result.GoodsItems[i]);
}
else Context.GoodsItems.Add(await CreateGoodsItemContextAsync(result.GoodsItems[i]));
}
if (Context.GoodsItems.Count != result.GoodsItems.Count)
@@ -282,15 +313,10 @@ namespace SepCore.UI
}
Context.RefreshPrice = result.RefreshPrice;
Context.NeedRefreshGoodsItems = true;
Context.NeedRefreshPrice = true;
if (Form == null)
{
Log.Error("ShopFormController.RefreshGoodsItems() Form is null.");
return;
}
Form.RefreshGoodsItems(Context.GoodsItems);
Form.RefreshRefreshPrice(Context.RefreshPrice);
RefreshUI(Form, Context);
}
private void ApplyGoodsPurchased(ShopPurchaseResult result)
@@ -319,29 +345,17 @@ namespace SepCore.UI
if (result.DisplayItem.IsWeapon)
{
AppendDisplayItemContext(Context.WeaponListContext, context);
Context.NeedRefreshWeaponList = true;
}
else
{
AppendDisplayItemContext(Context.PropListContext, context);
Context.NeedRefreshPropList = true;
}
}
Form?.ApplyGoodsPurchased(result.GoodsIndex, context);
}
private bool IsCurrentFormEventSender(object sender)
{
if (sender is ShopForm shopForm)
{
return shopForm == Form;
}
if (sender is Component component && Form != null)
{
return component.transform.IsChildOf(Form.transform);
}
return false;
Context.NeedRefreshGoodsItems = true;
RefreshUI(Form, Context);
}
private bool TryGetWeaponInfoRawData(int index, Vector3 targetPos, out ItemTooltipRawData rawData)
@@ -380,8 +394,8 @@ namespace SepCore.UI
WeaponData = weapon.WeaponData,
Rarity = weapon.WeaponData.Rarity,
ItemType = ItemType.Weapon,
Price = Mathf.FloorToInt(weapon.WeaponData.Price * Context.WeaponRecycleRate),
OnRecycle = (recycleIndex, recyclePrice) => RecycleWeapon(recycleIndex, recyclePrice),
Price = _useCase.CalculateRecyclePrice(weapon.WeaponData.Price),
OnRecycle = RecycleWeapon,
};
return true;
}
@@ -441,22 +455,18 @@ namespace SepCore.UI
Context.WeaponListContext.CurrentCount = currentCount;
}
Form?.RemoveWeaponDisplayItem(index);
GameEntry.Event.Fire(this, ItemTooltipHideEventArgs.Create(true));
Context.NeedRefreshWeaponList = true;
RefreshUI(Form, Context);
GameEntry.UIRouter.CloseUIAsync(UIFormType.ItemTooltipForm).Forget();
}
#endregion
#region Event Handlers
private async void Refresh(object sender, GameEventArgs e)
private async void ShopRefresh(object sender, GameEventArgs e)
{
if (sender is not ShopForm)
{
return;
}
if (e is not RefreshEventArgs args)
if (e is not ShopRefreshEventArgs args)
{
return;
}
@@ -472,16 +482,11 @@ namespace SepCore.UI
private void ShopPurchase(object sender, GameEventArgs e)
{
ShopPurchaseAsync(sender, e).Forget();
OnPurchaseRequestAsync(sender, e).Forget();
}
private async UniTaskVoid ShopPurchaseAsync(object sender, GameEventArgs e)
private async UniTaskVoid OnPurchaseRequestAsync(object sender, GameEventArgs e)
{
if (sender is not ShopForm)
{
return;
}
if (e is not ShopPurchaseEventArgs args)
{
return;
@@ -498,11 +503,6 @@ namespace SepCore.UI
private void ShopContinue(object sender, GameEventArgs e)
{
if (sender is not ShopForm)
{
return;
}
if (e is not ShopContinueEventArgs)
{
return;
@@ -511,21 +511,16 @@ namespace SepCore.UI
_useCase?.Continue();
}
private void DisplayItemShow(object sender, GameEventArgs e)
private void DisplayItemHover(object sender, GameEventArgs e)
{
if (e is not ItemTooltipShowEventArgs args)
{
return;
}
if (!IsCurrentFormEventSender(sender))
if (e is not DisplayItemHoverEventArgs args)
{
return;
}
if (_rawData == null)
{
Log.Error("ShopFormController.DisplayItemShow() _rawData is null.");
Log.Error("ShopFormController.OnDisplayItemHover() _rawData is null.");
return;
}
@@ -539,9 +534,55 @@ namespace SepCore.UI
return;
}
_tooltipLocked = false;
GameEntry.UIRouter.OpenUIAsync(UIFormType.ItemTooltipForm, rawData).Forget();
}
private void DisplayItemLock(object sender, GameEventArgs e)
{
if (e is not DisplayItemLockEventArgs)
{
return;
}
_tooltipLocked = true;
}
private void DisplayItemHide(object sender, GameEventArgs e)
{
if (e is not DisplayItemHideEventArgs args)
{
return;
}
if (_tooltipLocked)
{
return;
}
GameEntry.UIRouter.CloseUIAsync(UIFormType.ItemTooltipForm).Forget();
}
private void PlayerCoinChange(object sender, GameEventArgs e)
{
if (e is not PlayerCoinChangeEventArgs args) return;
if (Context == null) return;
Context.PlayerCoin = args.CoinCount;
Context.NeedRefreshPlayerCoin = true;
RefreshUI(Form, Context);
}
private void OpenUIFormComplete(object sender, GameEventArgs e)
{
if (e is not OpenUIFormSuccessEventArgs ne) return;
if (ne.UIForm.Logic is ItemTooltipForm)
{
_tooltipLocked = false;
}
}
#endregion
}
}