using System; using System.Collections.Generic; using GeometryTD.CustomEvent; using GeometryTD.Definition; using GameFramework.Event; using GeometryTD.CustomUtility; using UnityEngine; using UnityGameFramework.Runtime; namespace GeometryTD.UI { public class RepoFormController : UIFormControllerCommonBase { private RepoFormUseCase _useCase; private readonly Dictionary _itemContextMap = new Dictionary(); private readonly Dictionary _itemDescSeedMap = new Dictionary(); private sealed class ItemDescSeed { public string Title; public string TypeText; public string Description; public TagType[] Tags; } protected override UIFormType UIFormTypeId => UIFormType.RepoForm; protected override void RefreshUI(RepoForm form, RepoFormContext context) { form.RefreshUI(context); } protected override void SubscribeCustomEvents() { GameEntry.Event.Subscribe(RepoItemDetailRequestedEventArgs.EventId, OnRepoItemDetailRequested); GameEntry.Event.Subscribe(RepoItemDragEndedEventArgs.EventId, OnRepoItemDragEnded); GameEntry.Event.Subscribe(CombineSlotClickedEventArgs.EventId, OnCombineSlotClicked); GameEntry.Event.Subscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested); GameEntry.Event.Subscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn); } protected override void UnsubscribeCustomEvents() { GameEntry.Event.Unsubscribe(RepoItemDetailRequestedEventArgs.EventId, OnRepoItemDetailRequested); GameEntry.Event.Unsubscribe(RepoItemDragEndedEventArgs.EventId, OnRepoItemDragEnded); GameEntry.Event.Unsubscribe(CombineSlotClickedEventArgs.EventId, OnCombineSlotClicked); GameEntry.Event.Unsubscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested); GameEntry.Event.Unsubscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn); } public override int? OpenUI(object userData = null) { if (userData is RepoFormContext repoFormContext) { return OpenUIInternal(repoFormContext); } if (userData is RepoFormRawData rawDataFromUserData) { return OpenUI(rawDataFromUserData); } if (userData != null) { Log.Warning("RepoFormController.OpenUI() userData type is invalid."); return null; } if (_useCase == null) { Log.Error("RepoFormController.OpenUI() useCase is null."); return null; } RepoFormRawData rawData = _useCase.CreateInitialModel(); return OpenUI(rawData); } public int? OpenUI(RepoFormRawData rawData) { RepoFormContext context = BuildContext(rawData); return OpenUIInternal(context); } public override void BindUseCase(IUIUseCase useCase) { if (!(useCase is RepoFormUseCase repoFormUseCase)) { Log.Error("RepoFormController.BindUseCase() useCase is invalid."); return; } _useCase = repoFormUseCase; } private RepoFormContext BuildContext(RepoFormRawData rawData) { _itemContextMap.Clear(); _itemDescSeedMap.Clear(); if (rawData?.Inventory == null) { return null; } List items = new List(); if (rawData.Inventory.Towers != null) { foreach (TowerItemData tower in rawData.Inventory.Towers) { if (tower == null) { continue; } AddItemContext(items, new RepoItemContext { InstanceId = tower.InstanceId, CanDrag = true, ComponentSlotType = TowerCompSlotType.None, IconAreaContext = BuildIconAreaContext(tower) }); AddItemDescSeed( tower.InstanceId, tower.Name, "Tower", ItemDescUtility.BuildTowerDesc(tower.Stats) ?? string.Empty, tower.Stats != null ? tower.Stats.Tags : null); } } if (rawData.Inventory.MuzzleComponents != null) { foreach (MuzzleCompItemData item in rawData.Inventory.MuzzleComponents) { if (item == null || item.IsAssembledIntoTower) { continue; } AddItemContext(items, new RepoItemContext { InstanceId = item.InstanceId, CanDrag = true, ComponentSlotType = TowerCompSlotType.Muzzle, IconAreaContext = BuildIconAreaContext(item) }); AddItemDescSeed( item.InstanceId, item.Name, BuildComponentTypeText(item.SlotType), ItemDescUtility.BuildMuzzleDesc(item) ?? string.Empty, item.Tags); } } if (rawData.Inventory.BearingComponents != null) { foreach (BearingCompItemData item in rawData.Inventory.BearingComponents) { if (item == null || item.IsAssembledIntoTower) { continue; } AddItemContext(items, new RepoItemContext { InstanceId = item.InstanceId, CanDrag = true, ComponentSlotType = TowerCompSlotType.Bearing, IconAreaContext = BuildIconAreaContext(item) }); AddItemDescSeed( item.InstanceId, item.Name, BuildComponentTypeText(item.SlotType), ItemDescUtility.BuildBearingDesc(item) ?? string.Empty, item.Tags); } } if (rawData.Inventory.BaseComponents != null) { foreach (BaseCompItemData item in rawData.Inventory.BaseComponents) { if (item == null || item.IsAssembledIntoTower) { continue; } AddItemContext(items, new RepoItemContext { InstanceId = item.InstanceId, CanDrag = true, ComponentSlotType = TowerCompSlotType.Base, IconAreaContext = BuildIconAreaContext(item) }); AddItemDescSeed( item.InstanceId, item.Name, BuildComponentTypeText(item.SlotType), ItemDescUtility.BuildBaseDesc(item) ?? string.Empty, item.Tags); } } return new RepoFormContext { CombineAreaContext = new CombineAreaContext(), CompAreaContext = new CompAreaContext { Items = items.ToArray() } }; } private void AddItemContext(List items, RepoItemContext itemContext) { if (itemContext == null) { return; } items.Add(itemContext); _itemContextMap[itemContext.InstanceId] = itemContext; } private void AddItemDescSeed(long itemId, string title, string typeText, string description, TagType[] tags) { if (itemId <= 0) { return; } _itemDescSeedMap[itemId] = new ItemDescSeed { Title = string.IsNullOrWhiteSpace(title) ? $"Item {itemId}" : title, TypeText = typeText ?? string.Empty, Description = description ?? string.Empty, Tags = CloneTags(tags) }; } private static TagType[] CloneTags(TagType[] tags) { return tags != null ? (TagType[])tags.Clone() : Array.Empty(); } private static string BuildComponentTypeText(TowerCompSlotType slotType) { return slotType switch { TowerCompSlotType.Muzzle => "Muzzle Component", TowerCompSlotType.Bearing => "Bearing Component", TowerCompSlotType.Base => "Base Component", TowerCompSlotType.Accessory => "Accessory", _ => "Component" }; } private static IconAreaContext BuildIconAreaContext(TowerItemData tower) { if (tower == null) { return new IconAreaContext { ComponentSlotType = TowerCompSlotType.None, Rarity = RarityType.None, Color = Color.white, Icon = null }; } return new IconAreaContext { ComponentSlotType = TowerCompSlotType.None, Rarity = tower.Rarity, Color = IconColorGenerator.GenerateForTower(tower), Icon = null }; } private static IconAreaContext BuildIconAreaContext(TowerCompItemData item) { if (item == null) { return new IconAreaContext { ComponentSlotType = TowerCompSlotType.None, Rarity = RarityType.None, Color = Color.white, Icon = null }; } return new IconAreaContext { ComponentSlotType = item.SlotType, Rarity = item.Rarity, Color = IconColorGenerator.GenerateForComponent(item), Icon = null }; } #region Event Handlers private void OnRepoItemDetailRequested(object sender, GameEventArgs e) { if (!IsEventFromCurrentForm(sender)) { return; } if (!(e is RepoItemDetailRequestedEventArgs args)) { return; } if (!_itemDescSeedMap.TryGetValue(args.ItemId, out ItemDescSeed seed)) { return; } GameEntry.UIRouter.OpenUI(UIFormType.ItemDescForm, new ItemDescFormRawData { Title = seed.Title, TypeText = seed.TypeText, Description = seed.Description ?? string.Empty, Price = 0, TargetPos = args.TargetPos, Tags = CloneTags(seed.Tags) }); } private void OnRepoItemDragEnded(object sender, GameEventArgs e) { if (!IsEventFromCurrentForm(sender)) { return; } if (!(e is RepoItemDragEndedEventArgs args)) { return; } if (Form == null || !_itemContextMap.ContainsKey(args.ItemId)) { return; } Form.SetRepoItemSelected(args.ItemId, args.Assigned); } private void OnCombineSlotClicked(object sender, GameEventArgs e) { if (!IsEventFromCurrentForm(sender)) { return; } if (!(e is CombineSlotClickedEventArgs args)) { return; } if (Form == null) { return; } if (Form.TryClearCombineSlot(args.SlotIndex, out long removedItemId) && removedItemId > 0) { Form.SetRepoItemSelected(removedItemId, false); } } private void OnRepoFormReturn(object sender, GameEventArgs e) { if (!IsEventFromCurrentForm(sender) || !(e is RepoFormReturnEventArgs)) { return; } if (Form == null) { return; } this.CloseUI(); } private void OnRepoCombineRequested(object sender, GameEventArgs e) { if (!IsEventFromCurrentForm(sender)) { return; } if (!(e is RepoCombineRequestedEventArgs args)) { return; } if (_useCase == null || Form == null) { return; } if (!_useCase.TryAssembleTower(args.MuzzleItemId, args.BearingItemId, args.BaseItemId)) { return; } RepoFormRawData latestRawData = _useCase.CreateInitialModel(); RepoFormContext latestContext = BuildContext(latestRawData); if (latestContext != null) { Form.RefreshUI(latestContext); } } private bool IsEventFromCurrentForm(object sender) { if (Form == null) { return false; } if (ReferenceEquals(sender, Form)) { return true; } if (sender is Component component) { RepoForm ownerForm = component.GetComponentInParent(); return ownerForm == Form; } return false; } #endregion } }