From 9db9aeabcdfaaffe33d24d595366d89b3ffcde6d Mon Sep 17 00:00:00 2001 From: SepComet <202308010230@stu.csust.edu.cn> Date: Wed, 4 Mar 2026 22:04:51 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重构 `RepoItem`,统一点击事件 - 重构 `PlayerInventoryComponent`: - `PlayerInventoryStateStore`:状态与库存写模型 - `PlayerInventoryTowerAssemblyService`:炮塔组装域 - `PlayerInventoryTowerRosterService`:编队/耐久域 - `InventoryParticipantUtility`/`InventoryCloneUtility`/`InventorySeedUtility`:通用工具类 --- .../CustomComponent/PlayerInventory.meta | 3 + .../PlayerInventoryComponent.cs | 128 +++ .../PlayerInventoryComponent.cs.meta | 0 .../PlayerInventoryStateStore.cs | 270 ++++++ .../PlayerInventoryStateStore.cs.meta} | 2 +- .../PlayerInventoryTowerAssemblyService.cs | 210 +++++ ...ayerInventoryTowerAssemblyService.cs.meta} | 4 +- .../PlayerInventoryTowerRosterService.cs | 125 +++ .../PlayerInventoryTowerRosterService.cs.meta | 11 + .../PlayerInventoryComponent.cs | 856 ------------------ ...entArgs.cs => RepoItemClickedEventArgs.cs} | 8 +- .../RepoForm/RepoItemClickedEventArgs.cs.meta | 11 + ...RepoParticipantRemoveRequestedEventArgs.cs | 27 - .../Controller/CombatFinishFormController.cs | 8 +- .../Combat/UseCase/CombatFinishFormUseCase.cs | 3 +- .../RepoFormController.ContextBuilder.cs | 366 ++++++++ .../RepoFormController.ContextBuilder.cs.meta | 3 + .../UI/Game/Controller/RepoFormController.cs | 426 +-------- .../UI/Game/UseCase/RepoFormUseCase.cs | 330 +------ .../GameMain/Scripts/UI/Game/View/RepoItem.cs | 64 +- .../UseCase/RewardSelectFormUseCase.cs | 3 +- .../Scripts/Utility/InventoryCloneUtility.cs | 207 +++++ .../Utility/InventoryCloneUtility.cs.meta | 11 + .../Utility/InventoryParticipantUtility.cs | 140 +++ .../InventoryParticipantUtility.cs.meta | 11 + .../Scripts/Utility/InventorySeedUtility.cs | 190 ++++ .../Utility/InventorySeedUtility.cs.meta | 3 + 27 files changed, 1755 insertions(+), 1665 deletions(-) create mode 100644 Assets/GameMain/Scripts/CustomComponent/PlayerInventory.meta create mode 100644 Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryComponent.cs rename Assets/GameMain/Scripts/CustomComponent/{ => PlayerInventory}/PlayerInventoryComponent.cs.meta (100%) create mode 100644 Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryStateStore.cs rename Assets/GameMain/Scripts/{Event/RepoForm/RepoParticipantRemoveRequestedEventArgs.cs.meta => CustomComponent/PlayerInventory/PlayerInventoryStateStore.cs.meta} (83%) create mode 100644 Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerAssemblyService.cs rename Assets/GameMain/Scripts/{Event/RepoForm/RepoItemDetailRequestedEventArgs.cs.meta => CustomComponent/PlayerInventory/PlayerInventoryTowerAssemblyService.cs.meta} (74%) create mode 100644 Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerRosterService.cs create mode 100644 Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerRosterService.cs.meta delete mode 100644 Assets/GameMain/Scripts/CustomComponent/PlayerInventoryComponent.cs rename Assets/GameMain/Scripts/Event/RepoForm/{RepoItemDetailRequestedEventArgs.cs => RepoItemClickedEventArgs.cs} (60%) create mode 100644 Assets/GameMain/Scripts/Event/RepoForm/RepoItemClickedEventArgs.cs.meta delete mode 100644 Assets/GameMain/Scripts/Event/RepoForm/RepoParticipantRemoveRequestedEventArgs.cs create mode 100644 Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.ContextBuilder.cs create mode 100644 Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.ContextBuilder.cs.meta create mode 100644 Assets/GameMain/Scripts/Utility/InventoryCloneUtility.cs create mode 100644 Assets/GameMain/Scripts/Utility/InventoryCloneUtility.cs.meta create mode 100644 Assets/GameMain/Scripts/Utility/InventoryParticipantUtility.cs create mode 100644 Assets/GameMain/Scripts/Utility/InventoryParticipantUtility.cs.meta create mode 100644 Assets/GameMain/Scripts/Utility/InventorySeedUtility.cs create mode 100644 Assets/GameMain/Scripts/Utility/InventorySeedUtility.cs.meta diff --git a/Assets/GameMain/Scripts/CustomComponent/PlayerInventory.meta b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory.meta new file mode 100644 index 0000000..bdb4f26 --- /dev/null +++ b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 584eceb75fd347b7952c8117c8738fd4 +timeCreated: 1772632229 \ No newline at end of file diff --git a/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryComponent.cs b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryComponent.cs new file mode 100644 index 0000000..06d6cd8 --- /dev/null +++ b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryComponent.cs @@ -0,0 +1,128 @@ +using GeometryTD.CustomUtility; +using GeometryTD.Definition; +using UnityGameFramework.Runtime; + +namespace GeometryTD.CustomComponent +{ + public class PlayerInventoryComponent : GameFrameworkComponent + { + private const int MaxParticipantTowerCount = 4; + + private PlayerInventoryState _state; + private PlayerInventoryQueryModel _queryModel; + private PlayerInventoryCommandModel _commandModel; + private PlayerInventoryTowerRosterService _towerRosterService; + private PlayerInventoryTowerAssemblyService _towerAssemblyService; + + public int Gold + { + get + { + EnsureInitialized(); + return _queryModel.Gold; + } + } + + public void OnInit() + { + EnsureServices(); + _commandModel.Initialize(InventorySeedUtility.CreateSampleInventory(), MaxParticipantTowerCount); + + BackpackInventoryData inventory = _queryModel.Inventory; + Log.Info( + "PlayerInventory initialized. Gold={0}, Tower={1}, Muzzle={2}, Bearing={3}, Base={4}.", + inventory.Gold, + inventory.Towers.Count, + inventory.MuzzleComponents.Count, + inventory.BearingComponents.Count, + inventory.BaseComponents.Count); + } + + public BackpackInventoryData GetInventorySnapshot() + { + EnsureInitialized(); + return _queryModel.GetSnapshot(); + } + + public void MergeInventory(BackpackInventoryData gainedInventory) + { + EnsureInitialized(); + PlayerInventoryMergeSummary summary = _commandModel.MergeInventory(gainedInventory); + if (!summary.HasAnyGain) + { + return; + } + + Log.Info( + "PlayerInventory merged reward. Gold+{0}, Tower+{1}, Muzzle+{2}, Bearing+{3}, Base+{4}.", + summary.GainedGold, + summary.GainedTowerCount, + summary.GainedMuzzleCount, + summary.GainedBearingCount, + summary.GainedBaseCount); + } + + public bool TryConsumeGold(int costGold) + { + EnsureInitialized(); + return _commandModel.TryConsumeGold(costGold); + } + + public void AddGold(int gainGold) + { + EnsureInitialized(); + _commandModel.AddGold(gainGold); + } + + public bool TryAddParticipantTower(long towerInstanceId, int maxCount = 4) + { + EnsureInitialized(); + return _towerRosterService.TryAddParticipantTower(towerInstanceId, maxCount); + } + + public bool TryRemoveParticipantTower(long towerInstanceId) + { + EnsureInitialized(); + return _towerRosterService.TryRemoveParticipantTower(towerInstanceId); + } + + public bool TryAssembleTower( + long muzzleInstanceId, + long bearingInstanceId, + long baseInstanceId, + out TowerItemData assembledTower) + { + EnsureInitialized(); + return _towerAssemblyService.TryAssembleTower( + muzzleInstanceId, + bearingInstanceId, + baseInstanceId, + out assembledTower); + } + + public int ReduceAllTowerEndurance(float enduranceLoss) + { + EnsureInitialized(); + return _towerRosterService.ReduceAllTowerEndurance(enduranceLoss); + } + + private void EnsureInitialized() + { + if (_queryModel.IsInitialized) + { + return; + } + + OnInit(); + } + + private void EnsureServices() + { + _state ??= new PlayerInventoryState(); + _queryModel ??= new PlayerInventoryQueryModel(_state); + _commandModel ??= new PlayerInventoryCommandModel(_state); + _towerRosterService ??= new PlayerInventoryTowerRosterService(_queryModel, MaxParticipantTowerCount); + _towerAssemblyService ??= new PlayerInventoryTowerAssemblyService(_queryModel, _commandModel); + } + } +} diff --git a/Assets/GameMain/Scripts/CustomComponent/PlayerInventoryComponent.cs.meta b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryComponent.cs.meta similarity index 100% rename from Assets/GameMain/Scripts/CustomComponent/PlayerInventoryComponent.cs.meta rename to Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryComponent.cs.meta diff --git a/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryStateStore.cs b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryStateStore.cs new file mode 100644 index 0000000..f2c433e --- /dev/null +++ b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryStateStore.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections.Generic; +using GeometryTD.CustomUtility; +using GeometryTD.Definition; +using UnityEngine; + +namespace GeometryTD.CustomComponent +{ + internal struct PlayerInventoryMergeSummary + { + public int GainedGold; + public int GainedMuzzleCount; + public int GainedBearingCount; + public int GainedBaseCount; + public int GainedTowerCount; + + public bool HasAnyGain => + GainedGold > 0 || GainedMuzzleCount > 0 || GainedBearingCount > 0 || GainedBaseCount > 0 || + GainedTowerCount > 0; + } + + internal sealed class PlayerInventoryState + { + public BackpackInventoryData Inventory = new BackpackInventoryData(); + public long NextInstanceId = 1; + public bool IsInitialized; + } + + internal sealed class PlayerInventoryQueryModel + { + private readonly PlayerInventoryState _state; + + public PlayerInventoryQueryModel(PlayerInventoryState state) + { + _state = state; + } + + public BackpackInventoryData Inventory => _state.Inventory; + public bool IsInitialized => _state.IsInitialized; + public int Gold => _state.Inventory.Gold; + + public BackpackInventoryData GetSnapshot() + { + return InventoryCloneUtility.CloneInventory(_state.Inventory); + } + + public bool TryGetTowerById(long towerInstanceId, out TowerItemData tower) + { + return InventoryParticipantUtility.TryGetTowerById(_state.Inventory, towerInstanceId, out tower); + } + + public bool TryGetComponentById(List components, long instanceId, out TComp result) + where TComp : TowerCompItemData + { + result = null; + if (components == null || instanceId <= 0) + { + return false; + } + + for (int i = 0; i < components.Count; i++) + { + TComp component = components[i]; + if (component != null && component.InstanceId == instanceId) + { + result = component; + return true; + } + } + + return false; + } + } + + internal sealed class PlayerInventoryCommandModel + { + private readonly PlayerInventoryState _state; + + public PlayerInventoryCommandModel(PlayerInventoryState state) + { + _state = state; + } + + public void Initialize(BackpackInventoryData sourceInventory, int maxParticipantTowerCount) + { + _state.Inventory = InventoryCloneUtility.CloneInventory(sourceInventory); + InventoryParticipantUtility.NormalizeParticipantState(_state.Inventory, maxParticipantTowerCount); + RebuildNextInstanceId(); + _state.IsInitialized = true; + } + + public PlayerInventoryMergeSummary MergeInventory(BackpackInventoryData gainedInventory) + { + PlayerInventoryMergeSummary summary = default; + if (gainedInventory == null) + { + return summary; + } + + summary.GainedGold = Mathf.Max(0, gainedInventory.Gold); + if (summary.GainedGold > 0) + { + _state.Inventory.Gold += summary.GainedGold; + } + + if (gainedInventory.MuzzleComponents != null) + { + for (int i = 0; i < gainedInventory.MuzzleComponents.Count; i++) + { + MuzzleCompItemData source = gainedInventory.MuzzleComponents[i]; + if (source == null) + { + continue; + } + + MuzzleCompItemData cloned = InventoryCloneUtility.CloneMuzzleComp(source); + cloned.InstanceId = AllocateInstanceId(); + _state.Inventory.MuzzleComponents.Add(cloned); + summary.GainedMuzzleCount++; + } + } + + if (gainedInventory.BearingComponents != null) + { + for (int i = 0; i < gainedInventory.BearingComponents.Count; i++) + { + BearingCompItemData source = gainedInventory.BearingComponents[i]; + if (source == null) + { + continue; + } + + BearingCompItemData cloned = InventoryCloneUtility.CloneBearingComp(source); + cloned.InstanceId = AllocateInstanceId(); + _state.Inventory.BearingComponents.Add(cloned); + summary.GainedBearingCount++; + } + } + + if (gainedInventory.BaseComponents != null) + { + for (int i = 0; i < gainedInventory.BaseComponents.Count; i++) + { + BaseCompItemData source = gainedInventory.BaseComponents[i]; + if (source == null) + { + continue; + } + + BaseCompItemData cloned = InventoryCloneUtility.CloneBaseComp(source); + cloned.InstanceId = AllocateInstanceId(); + _state.Inventory.BaseComponents.Add(cloned); + summary.GainedBaseCount++; + } + } + + if (gainedInventory.Towers != null) + { + for (int i = 0; i < gainedInventory.Towers.Count; i++) + { + TowerItemData source = gainedInventory.Towers[i]; + if (source == null) + { + continue; + } + + TowerItemData cloned = InventoryCloneUtility.CloneTower(source); + cloned.InstanceId = AllocateInstanceId(); + _state.Inventory.Towers.Add(cloned); + summary.GainedTowerCount++; + } + } + + return summary; + } + + public bool TryConsumeGold(int costGold) + { + int resolvedCost = Mathf.Max(0, costGold); + if (resolvedCost <= 0) + { + return true; + } + + if (_state.Inventory.Gold < resolvedCost) + { + return false; + } + + _state.Inventory.Gold -= resolvedCost; + return true; + } + + public void AddGold(int gainGold) + { + int resolvedGain = Mathf.Max(0, gainGold); + if (resolvedGain <= 0) + { + return; + } + + _state.Inventory.Gold += resolvedGain; + } + + public long AllocateInstanceId() + { + if (_state.NextInstanceId < 1) + { + _state.NextInstanceId = 1; + } + + return _state.NextInstanceId++; + } + + private void RebuildNextInstanceId() + { + long maxInstanceId = 0; + BackpackInventoryData inventory = _state.Inventory; + if (inventory.Towers != null) + { + for (int i = 0; i < inventory.Towers.Count; i++) + { + TowerItemData item = inventory.Towers[i]; + if (item != null) + { + maxInstanceId = Math.Max(maxInstanceId, item.InstanceId); + } + } + } + + if (inventory.MuzzleComponents != null) + { + for (int i = 0; i < inventory.MuzzleComponents.Count; i++) + { + MuzzleCompItemData item = inventory.MuzzleComponents[i]; + if (item != null) + { + maxInstanceId = Math.Max(maxInstanceId, item.InstanceId); + } + } + } + + if (inventory.BearingComponents != null) + { + for (int i = 0; i < inventory.BearingComponents.Count; i++) + { + BearingCompItemData item = inventory.BearingComponents[i]; + if (item != null) + { + maxInstanceId = Math.Max(maxInstanceId, item.InstanceId); + } + } + } + + if (inventory.BaseComponents != null) + { + for (int i = 0; i < inventory.BaseComponents.Count; i++) + { + BaseCompItemData item = inventory.BaseComponents[i]; + if (item != null) + { + maxInstanceId = Math.Max(maxInstanceId, item.InstanceId); + } + } + } + + _state.NextInstanceId = Math.Max(1, maxInstanceId + 1); + } + } +} diff --git a/Assets/GameMain/Scripts/Event/RepoForm/RepoParticipantRemoveRequestedEventArgs.cs.meta b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryStateStore.cs.meta similarity index 83% rename from Assets/GameMain/Scripts/Event/RepoForm/RepoParticipantRemoveRequestedEventArgs.cs.meta rename to Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryStateStore.cs.meta index ab8d93b..bb92981 100644 --- a/Assets/GameMain/Scripts/Event/RepoForm/RepoParticipantRemoveRequestedEventArgs.cs.meta +++ b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryStateStore.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1438388ea5334474da123eadd2a55fc8 +guid: 4aa101c4dd7c30845b0a84b2a04f9b9e MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerAssemblyService.cs b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerAssemblyService.cs new file mode 100644 index 0000000..88ba565 --- /dev/null +++ b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerAssemblyService.cs @@ -0,0 +1,210 @@ +using System.Collections.Generic; +using GameFramework.DataTable; +using GeometryTD.CustomUtility; +using GeometryTD.DataTable; +using GeometryTD.Definition; +using UnityEngine; + +namespace GeometryTD.CustomComponent +{ + internal sealed class PlayerInventoryTowerAssemblyService + { + private const int TowerLevelCount = 5; + + private readonly PlayerInventoryQueryModel _queryModel; + private readonly PlayerInventoryCommandModel _commandModel; + private IDataTable _drMuzzleComp; + private IDataTable _drBearingComp; + private IDataTable _drBaseComp; + + public PlayerInventoryTowerAssemblyService( + PlayerInventoryQueryModel queryModel, + PlayerInventoryCommandModel commandModel) + { + _queryModel = queryModel; + _commandModel = commandModel; + } + + public bool TryAssembleTower( + long muzzleInstanceId, + long bearingInstanceId, + long baseInstanceId, + out TowerItemData assembledTower) + { + assembledTower = null; + BackpackInventoryData inventory = _queryModel.Inventory; + if (muzzleInstanceId <= 0 || bearingInstanceId <= 0 || baseInstanceId <= 0) + { + return false; + } + + if (!_queryModel.TryGetComponentById(inventory.MuzzleComponents, muzzleInstanceId, out MuzzleCompItemData muzzleComp) || + !_queryModel.TryGetComponentById(inventory.BearingComponents, bearingInstanceId, out BearingCompItemData bearingComp) || + !_queryModel.TryGetComponentById(inventory.BaseComponents, baseInstanceId, out BaseCompItemData baseComp)) + { + return false; + } + + if (muzzleComp.IsAssembledIntoTower || bearingComp.IsAssembledIntoTower || baseComp.IsAssembledIntoTower) + { + return false; + } + + if (!TryBuildTowerStats(muzzleComp, bearingComp, baseComp, out TowerStatsData stats)) + { + return false; + } + + long towerInstanceId = _commandModel.AllocateInstanceId(); + TowerItemData tower = new TowerItemData + { + InstanceId = towerInstanceId, + Name = $"组装防御塔-{towerInstanceId}", + Rarity = ResolveAverageRarity(muzzleComp.Rarity, bearingComp.Rarity, baseComp.Rarity), + MuzzleComponentInstanceId = muzzleComp.InstanceId, + BearingComponentInstanceId = bearingComp.InstanceId, + BaseComponentInstanceId = baseComp.InstanceId, + Stats = stats + }; + + muzzleComp.IsAssembledIntoTower = true; + bearingComp.IsAssembledIntoTower = true; + baseComp.IsAssembledIntoTower = true; + inventory.Towers.Add(tower); + assembledTower = InventoryCloneUtility.CloneTower(tower); + return true; + } + + private bool TryBuildTowerStats( + MuzzleCompItemData muzzleComp, + BearingCompItemData bearingComp, + BaseCompItemData baseComp, + out TowerStatsData stats) + { + stats = null; + if (muzzleComp == null || bearingComp == null || baseComp == null) + { + return false; + } + + DRMuzzleComp muzzleConfig = EnsureMuzzleTable()?.GetDataRow(muzzleComp.ConfigId); + DRBearingComp bearingConfig = EnsureBearingTable()?.GetDataRow(bearingComp.ConfigId); + DRBaseComp baseConfig = EnsureBaseTable()?.GetDataRow(baseComp.ConfigId); + if (muzzleConfig == null || bearingConfig == null || baseConfig == null) + { + return false; + } + + stats = new TowerStatsData + { + AttackDamage = BuildLevelIntArray(muzzleComp.AttackDamage, muzzleComp.Rarity, muzzleConfig.AttackDamagePerLevel), + DamageRandomRate = Mathf.Max(0f, muzzleComp.DamageRandomRate), + RotateSpeed = BuildLevelFloatArray(bearingComp.RotateSpeed, bearingComp.Rarity, bearingConfig.RotateSpeedPerLevel), + AttackRange = BuildLevelFloatArray(bearingComp.AttackRange, bearingComp.Rarity, bearingConfig.AttackRangePerLevel), + AttackSpeed = BuildLevelFloatArray(baseComp.AttackSpeed, baseComp.Rarity, baseConfig.AttackSpeedPerLevel), + AttackMethodType = muzzleComp.AttackMethodType, + AttackPropertyType = baseComp.AttackPropertyType, + Tags = MergeTags(muzzleComp.Tags, bearingComp.Tags, baseComp.Tags) + }; + + return true; + } + + private static int[] BuildLevelIntArray(int[] rarityBaseArray, RarityType rarity, int perLevel) + { + int baseValue = ResolveRarityBaseValue(rarityBaseArray, rarity); + int[] values = new int[TowerLevelCount]; + for (int i = 0; i < values.Length; i++) + { + values[i] = baseValue + perLevel * i; + } + + return values; + } + + private static float[] BuildLevelFloatArray(float[] rarityBaseArray, RarityType rarity, float perLevel) + { + float baseValue = ResolveRarityBaseValue(rarityBaseArray, rarity); + float[] values = new float[TowerLevelCount]; + for (int i = 0; i < values.Length; i++) + { + values[i] = baseValue + perLevel * i; + } + + return values; + } + + private static int ResolveRarityBaseValue(int[] rarityBaseArray, RarityType rarity) + { + if (rarityBaseArray == null || rarityBaseArray.Length <= 0) + { + return 0; + } + + int rarityIndex = Mathf.Clamp((int)rarity - 1, 0, rarityBaseArray.Length - 1); + return rarityBaseArray[rarityIndex]; + } + + private static float ResolveRarityBaseValue(float[] rarityBaseArray, RarityType rarity) + { + if (rarityBaseArray == null || rarityBaseArray.Length <= 0) + { + return 0f; + } + + int rarityIndex = Mathf.Clamp((int)rarity - 1, 0, rarityBaseArray.Length - 1); + return rarityBaseArray[rarityIndex]; + } + + private static TagType[] MergeTags(params TagType[][] sources) + { + HashSet uniqueTags = new HashSet(); + if (sources != null) + { + for (int i = 0; i < sources.Length; i++) + { + TagType[] tags = sources[i]; + if (tags == null) + { + continue; + } + + for (int j = 0; j < tags.Length; j++) + { + uniqueTags.Add(tags[j]); + } + } + } + + TagType[] mergedTags = new TagType[uniqueTags.Count]; + uniqueTags.CopyTo(mergedTags); + return mergedTags; + } + + private static RarityType ResolveAverageRarity(RarityType muzzleRarity, RarityType bearingRarity, RarityType baseRarity) + { + float avg = ((int)muzzleRarity + (int)bearingRarity + (int)baseRarity) / 3f; + int rounded = Mathf.RoundToInt(avg); + int clamped = Mathf.Clamp(rounded, (int)RarityType.White, (int)RarityType.Red); + return (RarityType)clamped; + } + + private IDataTable EnsureMuzzleTable() + { + _drMuzzleComp ??= GameEntry.DataTable.GetDataTable(); + return _drMuzzleComp; + } + + private IDataTable EnsureBearingTable() + { + _drBearingComp ??= GameEntry.DataTable.GetDataTable(); + return _drBearingComp; + } + + private IDataTable EnsureBaseTable() + { + _drBaseComp ??= GameEntry.DataTable.GetDataTable(); + return _drBaseComp; + } + } +} diff --git a/Assets/GameMain/Scripts/Event/RepoForm/RepoItemDetailRequestedEventArgs.cs.meta b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerAssemblyService.cs.meta similarity index 74% rename from Assets/GameMain/Scripts/Event/RepoForm/RepoItemDetailRequestedEventArgs.cs.meta rename to Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerAssemblyService.cs.meta index 073e368..50cf738 100644 --- a/Assets/GameMain/Scripts/Event/RepoForm/RepoItemDetailRequestedEventArgs.cs.meta +++ b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerAssemblyService.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 6e6a01b06c4b4a468d40356dc05e003f +guid: b20e5ad5952075449bc89c483cd4723b MonoImporter: externalObjects: {} serializedVersion: 2 @@ -8,4 +8,4 @@ MonoImporter: icon: {instanceID: 0} userData: assetBundleName: - assetBundleVariant: \ No newline at end of file + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerRosterService.cs b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerRosterService.cs new file mode 100644 index 0000000..3a5eba8 --- /dev/null +++ b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerRosterService.cs @@ -0,0 +1,125 @@ +using System.Collections.Generic; +using GeometryTD.CustomUtility; +using GeometryTD.Definition; +using UnityEngine; + +namespace GeometryTD.CustomComponent +{ + internal sealed class PlayerInventoryTowerRosterService + { + private readonly PlayerInventoryQueryModel _queryModel; + private readonly int _maxParticipantTowerCount; + + public PlayerInventoryTowerRosterService(PlayerInventoryQueryModel queryModel, int maxParticipantTowerCount) + { + _queryModel = queryModel; + _maxParticipantTowerCount = Mathf.Max(1, maxParticipantTowerCount); + } + + public bool TryAddParticipantTower(long towerInstanceId, int maxCount) + { + int resolvedMaxCount = Mathf.Max(1, maxCount); + resolvedMaxCount = Mathf.Min(resolvedMaxCount, _maxParticipantTowerCount); + return InventoryParticipantUtility.TryAddParticipantTower( + _queryModel.Inventory, + towerInstanceId, + resolvedMaxCount); + } + + public bool TryRemoveParticipantTower(long towerInstanceId) + { + return InventoryParticipantUtility.TryRemoveParticipantTower( + _queryModel.Inventory, + towerInstanceId, + _maxParticipantTowerCount); + } + + public int ReduceAllTowerEndurance(float enduranceLoss) + { + float resolvedLoss = Mathf.Max(0f, enduranceLoss); + BackpackInventoryData inventory = _queryModel.Inventory; + if (resolvedLoss <= 0f || inventory.Towers == null || inventory.Towers.Count <= 0) + { + return 0; + } + + Dictionary muzzleMap = BuildComponentMap(inventory.MuzzleComponents); + Dictionary bearingMap = BuildComponentMap(inventory.BearingComponents); + Dictionary baseMap = BuildComponentMap(inventory.BaseComponents); + + int affectedCount = 0; + for (int i = 0; i < inventory.Towers.Count; i++) + { + TowerItemData tower = inventory.Towers[i]; + if (tower == null) + { + continue; + } + + bool towerAffected = false; + if (muzzleMap.TryGetValue(tower.MuzzleComponentInstanceId, out MuzzleCompItemData muzzleComp)) + { + towerAffected |= TryReduceComponentEndurance(muzzleComp, resolvedLoss); + } + + if (bearingMap.TryGetValue(tower.BearingComponentInstanceId, out BearingCompItemData bearingComp)) + { + towerAffected |= TryReduceComponentEndurance(bearingComp, resolvedLoss); + } + + if (baseMap.TryGetValue(tower.BaseComponentInstanceId, out BaseCompItemData baseComp)) + { + towerAffected |= TryReduceComponentEndurance(baseComp, resolvedLoss); + } + + if (towerAffected) + { + affectedCount++; + } + } + + return affectedCount; + } + + private static bool TryReduceComponentEndurance(TowerCompItemData component, float enduranceLoss) + { + if (component == null) + { + return false; + } + + float originalEndurance = component.Endurance; + float nextEndurance = Mathf.Clamp(originalEndurance - Mathf.Max(0f, enduranceLoss), 0f, 100f); + if (nextEndurance >= originalEndurance) + { + return false; + } + + component.Endurance = nextEndurance; + return true; + } + + private static Dictionary BuildComponentMap(List components) + where TComp : TowerCompItemData + { + Dictionary map = new Dictionary(); + if (components == null || components.Count <= 0) + { + return map; + } + + for (int i = 0; i < components.Count; i++) + { + TComp component = components[i]; + if (component == null || component.InstanceId <= 0) + { + continue; + } + + map[component.InstanceId] = component; + } + + return map; + } + } +} diff --git a/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerRosterService.cs.meta b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerRosterService.cs.meta new file mode 100644 index 0000000..62e3643 --- /dev/null +++ b/Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerRosterService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 45c950a847f55a04f9f780218f735d42 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/CustomComponent/PlayerInventoryComponent.cs b/Assets/GameMain/Scripts/CustomComponent/PlayerInventoryComponent.cs deleted file mode 100644 index ad9d185..0000000 --- a/Assets/GameMain/Scripts/CustomComponent/PlayerInventoryComponent.cs +++ /dev/null @@ -1,856 +0,0 @@ -using System; -using System.Collections.Generic; -using GameFramework.DataTable; -using GeometryTD.DataTable; -using GeometryTD.Definition; -using GeometryTD.UI; -using UnityEngine; -using UnityGameFramework.Runtime; - -namespace GeometryTD.CustomComponent -{ - public class PlayerInventoryComponent : GameFrameworkComponent - { - private const int TowerLevelCount = 5; - private const int MaxParticipantTowerCount = 4; - private BackpackInventoryData _inventory = new BackpackInventoryData(); - private long _nextInstanceId = 1; - private bool _initialized; - private IDataTable _drMuzzleComp; - private IDataTable _drBearingComp; - private IDataTable _drBaseComp; - - public int Gold - { - get - { - EnsureInitialized(); - return _inventory.Gold; - } - } - - public void OnInit() - { - _inventory = CloneInventory(RepoFormUseCase.SampleInventory()); - NormalizeParticipantState(); - RebuildNextInstanceId(); - _initialized = true; - Log.Info( - "PlayerInventory initialized. Gold={0}, Tower={1}, Muzzle={2}, Bearing={3}, Base={4}.", - _inventory.Gold, - _inventory.Towers.Count, - _inventory.MuzzleComponents.Count, - _inventory.BearingComponents.Count, - _inventory.BaseComponents.Count); - } - - public BackpackInventoryData GetInventorySnapshot() - { - EnsureInitialized(); - return CloneInventory(_inventory); - } - - public void MergeInventory(BackpackInventoryData gainedInventory) - { - EnsureInitialized(); - if (gainedInventory == null) - { - return; - } - - int gainedGold = Mathf.Max(0, gainedInventory.Gold); - int gainedMuzzleCount = 0; - int gainedBearingCount = 0; - int gainedBaseCount = 0; - int gainedTowerCount = 0; - - if (gainedGold > 0) - { - _inventory.Gold += gainedGold; - } - - if (gainedInventory.MuzzleComponents != null) - { - for (int i = 0; i < gainedInventory.MuzzleComponents.Count; i++) - { - MuzzleCompItemData source = gainedInventory.MuzzleComponents[i]; - if (source == null) - { - continue; - } - - MuzzleCompItemData cloned = CloneMuzzleComp(source); - cloned.InstanceId = AllocateInstanceId(); - _inventory.MuzzleComponents.Add(cloned); - gainedMuzzleCount++; - } - } - - if (gainedInventory.BearingComponents != null) - { - for (int i = 0; i < gainedInventory.BearingComponents.Count; i++) - { - BearingCompItemData source = gainedInventory.BearingComponents[i]; - if (source == null) - { - continue; - } - - BearingCompItemData cloned = CloneBearingComp(source); - cloned.InstanceId = AllocateInstanceId(); - _inventory.BearingComponents.Add(cloned); - gainedBearingCount++; - } - } - - if (gainedInventory.BaseComponents != null) - { - for (int i = 0; i < gainedInventory.BaseComponents.Count; i++) - { - BaseCompItemData source = gainedInventory.BaseComponents[i]; - if (source == null) - { - continue; - } - - BaseCompItemData cloned = CloneBaseComp(source); - cloned.InstanceId = AllocateInstanceId(); - _inventory.BaseComponents.Add(cloned); - gainedBaseCount++; - } - } - - if (gainedInventory.Towers != null) - { - for (int i = 0; i < gainedInventory.Towers.Count; i++) - { - TowerItemData source = gainedInventory.Towers[i]; - if (source == null) - { - continue; - } - - TowerItemData cloned = CloneTower(source); - cloned.InstanceId = AllocateInstanceId(); - _inventory.Towers.Add(cloned); - gainedTowerCount++; - } - } - - if (gainedGold > 0 || gainedMuzzleCount > 0 || gainedBearingCount > 0 || gainedBaseCount > 0 || - gainedTowerCount > 0) - { - Log.Info( - "PlayerInventory merged reward. Gold+{0}, Tower+{1}, Muzzle+{2}, Bearing+{3}, Base+{4}.", - gainedGold, - gainedTowerCount, - gainedMuzzleCount, - gainedBearingCount, - gainedBaseCount); - } - } - - public bool TryConsumeGold(int costGold) - { - EnsureInitialized(); - int resolvedCost = Mathf.Max(0, costGold); - if (resolvedCost <= 0) - { - return true; - } - - if (_inventory.Gold < resolvedCost) - { - return false; - } - - _inventory.Gold -= resolvedCost; - return true; - } - - public void AddGold(int gainGold) - { - EnsureInitialized(); - int resolvedGain = Mathf.Max(0, gainGold); - if (resolvedGain <= 0) - { - return; - } - - _inventory.Gold += resolvedGain; - } - - public bool TryAddParticipantTower(long towerInstanceId, int maxCount = 4) - { - EnsureInitialized(); - int resolvedMaxCount = Mathf.Max(1, maxCount); - resolvedMaxCount = Mathf.Min(resolvedMaxCount, MaxParticipantTowerCount); - if (!TryGetTowerById(towerInstanceId, out TowerItemData tower)) - { - return false; - } - - _inventory.ParticipantTowerInstanceIds ??= new List(); - if (_inventory.ParticipantTowerInstanceIds.Contains(towerInstanceId)) - { - tower.IsParticipatingInCombat = true; - return false; - } - - if (_inventory.ParticipantTowerInstanceIds.Count >= resolvedMaxCount) - { - return false; - } - - _inventory.ParticipantTowerInstanceIds.Add(towerInstanceId); - tower.IsParticipatingInCombat = true; - return true; - } - - public bool TryRemoveParticipantTower(long towerInstanceId) - { - EnsureInitialized(); - if (towerInstanceId <= 0 || _inventory.ParticipantTowerInstanceIds == null) - { - return false; - } - - bool removed = _inventory.ParticipantTowerInstanceIds.Remove(towerInstanceId); - if (!removed) - { - return false; - } - - if (TryGetTowerById(towerInstanceId, out TowerItemData tower)) - { - tower.IsParticipatingInCombat = false; - } - - return true; - } - - public bool TryAssembleTower( - long muzzleInstanceId, - long bearingInstanceId, - long baseInstanceId, - out TowerItemData assembledTower) - { - EnsureInitialized(); - assembledTower = null; - if (muzzleInstanceId <= 0 || bearingInstanceId <= 0 || baseInstanceId <= 0) - { - return false; - } - - if (!TryGetComponentById(_inventory.MuzzleComponents, muzzleInstanceId, - out MuzzleCompItemData muzzleComp) || - !TryGetComponentById(_inventory.BearingComponents, bearingInstanceId, - out BearingCompItemData bearingComp) || - !TryGetComponentById(_inventory.BaseComponents, baseInstanceId, out BaseCompItemData baseComp)) - { - return false; - } - - if (muzzleComp.IsAssembledIntoTower || bearingComp.IsAssembledIntoTower || baseComp.IsAssembledIntoTower) - { - return false; - } - - if (!TryBuildTowerStats(muzzleComp, bearingComp, baseComp, out TowerStatsData stats)) - { - return false; - } - - long towerInstanceId = AllocateInstanceId(); - TowerItemData tower = new TowerItemData - { - InstanceId = towerInstanceId, - Name = $"组装防御塔-{towerInstanceId}", - Rarity = ResolveAverageRarity(muzzleComp.Rarity, bearingComp.Rarity, baseComp.Rarity), - MuzzleComponentInstanceId = muzzleComp.InstanceId, - BearingComponentInstanceId = bearingComp.InstanceId, - BaseComponentInstanceId = baseComp.InstanceId, - Stats = stats - }; - - muzzleComp.IsAssembledIntoTower = true; - bearingComp.IsAssembledIntoTower = true; - baseComp.IsAssembledIntoTower = true; - _inventory.Towers.Add(tower); - assembledTower = CloneTower(tower); - return true; - } - - public int ReduceAllTowerEndurance(float enduranceLoss) - { - EnsureInitialized(); - float resolvedLoss = Mathf.Max(0f, enduranceLoss); - if (resolvedLoss <= 0f || _inventory.Towers == null || _inventory.Towers.Count <= 0) - { - return 0; - } - - Dictionary muzzleMap = BuildComponentMap(_inventory.MuzzleComponents); - Dictionary bearingMap = BuildComponentMap(_inventory.BearingComponents); - Dictionary baseMap = BuildComponentMap(_inventory.BaseComponents); - - int affectedCount = 0; - foreach (var tower in _inventory.Towers) - { - if (tower == null) - { - continue; - } - - bool towerAffected = false; - if (muzzleMap.TryGetValue(tower.MuzzleComponentInstanceId, out MuzzleCompItemData muzzleComp)) - { - towerAffected |= TryReduceComponentEndurance(muzzleComp, resolvedLoss); - } - - if (bearingMap.TryGetValue(tower.BearingComponentInstanceId, out BearingCompItemData bearingComp)) - { - towerAffected |= TryReduceComponentEndurance(bearingComp, resolvedLoss); - } - - if (baseMap.TryGetValue(tower.BaseComponentInstanceId, out BaseCompItemData baseComp)) - { - towerAffected |= TryReduceComponentEndurance(baseComp, resolvedLoss); - } - - if (towerAffected) - { - affectedCount++; - } - } - - return affectedCount; - } - - private static bool TryReduceComponentEndurance(TowerCompItemData component, float enduranceLoss) - { - if (component == null) - { - return false; - } - - float originalEndurance = component.Endurance; - float nextEndurance = Mathf.Clamp(originalEndurance - Mathf.Max(0f, enduranceLoss), 0f, 100f); - if (nextEndurance >= originalEndurance) - { - return false; - } - - component.Endurance = nextEndurance; - return true; - } - - private static Dictionary BuildComponentMap(List components) - where TComp : TowerCompItemData - { - Dictionary map = new Dictionary(); - if (components == null || components.Count <= 0) - { - return map; - } - - foreach (var component in components) - { - if (component == null || component.InstanceId <= 0) - { - continue; - } - - map[component.InstanceId] = component; - } - - return map; - } - - private static bool TryGetComponentById(List components, long instanceId, out TComp result) - where TComp : TowerCompItemData - { - result = null; - if (components == null || instanceId <= 0) - { - return false; - } - - foreach (TComp component in components) - { - if (component != null && component.InstanceId == instanceId) - { - result = component; - return true; - } - } - - return false; - } - - private bool TryGetTowerById(long towerInstanceId, out TowerItemData tower) - { - tower = null; - if (towerInstanceId <= 0 || _inventory.Towers == null) - { - return false; - } - - for (int i = 0; i < _inventory.Towers.Count; i++) - { - TowerItemData candidate = _inventory.Towers[i]; - if (candidate != null && candidate.InstanceId == towerInstanceId) - { - tower = candidate; - return true; - } - } - - return false; - } - - private bool TryBuildTowerStats( - MuzzleCompItemData muzzleComp, - BearingCompItemData bearingComp, - BaseCompItemData baseComp, - out TowerStatsData stats) - { - stats = null; - if (muzzleComp == null || bearingComp == null || baseComp == null) - { - return false; - } - - DRMuzzleComp muzzleConfig = EnsureMuzzleTable()?.GetDataRow(muzzleComp.ConfigId); - DRBearingComp bearingConfig = EnsureBearingTable()?.GetDataRow(bearingComp.ConfigId); - DRBaseComp baseConfig = EnsureBaseTable()?.GetDataRow(baseComp.ConfigId); - if (muzzleConfig == null || bearingConfig == null || baseConfig == null) - { - return false; - } - - stats = new TowerStatsData - { - AttackDamage = BuildLevelIntArray(muzzleComp.AttackDamage, muzzleComp.Rarity, - muzzleConfig.AttackDamagePerLevel), - DamageRandomRate = Mathf.Max(0f, muzzleComp.DamageRandomRate), - RotateSpeed = BuildLevelFloatArray(bearingComp.RotateSpeed, bearingComp.Rarity, - bearingConfig.RotateSpeedPerLevel), - AttackRange = BuildLevelFloatArray(bearingComp.AttackRange, bearingComp.Rarity, - bearingConfig.AttackRangePerLevel), - AttackSpeed = - BuildLevelFloatArray(baseComp.AttackSpeed, baseComp.Rarity, baseConfig.AttackSpeedPerLevel), - AttackMethodType = muzzleComp.AttackMethodType, - AttackPropertyType = baseComp.AttackPropertyType, - Tags = MergeTags(muzzleComp.Tags, bearingComp.Tags, baseComp.Tags) - }; - - return true; - } - - private static int[] BuildLevelIntArray(int[] rarityBaseArray, RarityType rarity, int perLevel) - { - int baseValue = ResolveRarityBaseValue(rarityBaseArray, rarity); - int[] values = new int[TowerLevelCount]; - for (int i = 0; i < values.Length; i++) - { - values[i] = baseValue + perLevel * i; - } - - return values; - } - - private static float[] BuildLevelFloatArray(float[] rarityBaseArray, RarityType rarity, float perLevel) - { - float baseValue = ResolveRarityBaseValue(rarityBaseArray, rarity); - float[] values = new float[TowerLevelCount]; - for (int i = 0; i < values.Length; i++) - { - values[i] = baseValue + perLevel * i; - } - - return values; - } - - private static float[] BuildConstantLevelFloatArray(float value) - { - float[] values = new float[TowerLevelCount]; - for (int i = 0; i < values.Length; i++) - { - values[i] = value; - } - - return values; - } - - private static int ResolveRarityBaseValue(int[] rarityBaseArray, RarityType rarity) - { - if (rarityBaseArray == null || rarityBaseArray.Length <= 0) - { - return 0; - } - - int rarityIndex = Mathf.Clamp((int)rarity - 1, 0, rarityBaseArray.Length - 1); - return rarityBaseArray[rarityIndex]; - } - - private static float ResolveRarityBaseValue(float[] rarityBaseArray, RarityType rarity) - { - if (rarityBaseArray == null || rarityBaseArray.Length <= 0) - { - return 0f; - } - - int rarityIndex = Mathf.Clamp((int)rarity - 1, 0, rarityBaseArray.Length - 1); - return rarityBaseArray[rarityIndex]; - } - - private static TagType[] MergeTags(params TagType[][] sources) - { - HashSet uniqueTags = new HashSet(); - if (sources != null) - { - for (int i = 0; i < sources.Length; i++) - { - TagType[] tags = sources[i]; - if (tags == null) - { - continue; - } - - for (int j = 0; j < tags.Length; j++) - { - uniqueTags.Add(tags[j]); - } - } - } - - TagType[] mergedTags = new TagType[uniqueTags.Count]; - uniqueTags.CopyTo(mergedTags); - return mergedTags; - } - - private static RarityType ResolveAverageRarity(RarityType muzzleRarity, RarityType bearingRarity, - RarityType baseRarity) - { - float avg = ((int)muzzleRarity + (int)bearingRarity + (int)baseRarity) / 3f; - int rounded = Mathf.RoundToInt(avg); - int clamped = Mathf.Clamp(rounded, (int)RarityType.White, (int)RarityType.Red); - return (RarityType)clamped; - } - - private IDataTable EnsureMuzzleTable() - { - _drMuzzleComp ??= GameEntry.DataTable.GetDataTable(); - return _drMuzzleComp; - } - - private IDataTable EnsureBearingTable() - { - _drBearingComp ??= GameEntry.DataTable.GetDataTable(); - return _drBearingComp; - } - - private IDataTable EnsureBaseTable() - { - _drBaseComp ??= GameEntry.DataTable.GetDataTable(); - return _drBaseComp; - } - - private void EnsureInitialized() - { - if (_initialized) - { - return; - } - - OnInit(); - } - - private long AllocateInstanceId() - { - if (_nextInstanceId < 1) - { - _nextInstanceId = 1; - } - - return _nextInstanceId++; - } - - private void RebuildNextInstanceId() - { - long maxInstanceId = 0; - if (_inventory.Towers != null) - { - foreach (var item in _inventory.Towers) - { - if (item != null) - { - maxInstanceId = Math.Max(maxInstanceId, item.InstanceId); - } - } - } - - if (_inventory.MuzzleComponents != null) - { - foreach (var item in _inventory.MuzzleComponents) - { - if (item != null) - { - maxInstanceId = Math.Max(maxInstanceId, item.InstanceId); - } - } - } - - if (_inventory.BearingComponents != null) - { - foreach (var item in _inventory.BearingComponents) - { - if (item != null) - { - maxInstanceId = Math.Max(maxInstanceId, item.InstanceId); - } - } - } - - if (_inventory.BaseComponents != null) - { - foreach (var item in _inventory.BaseComponents) - { - if (item != null) - { - maxInstanceId = Math.Max(maxInstanceId, item.InstanceId); - } - } - } - - _nextInstanceId = Math.Max(1, maxInstanceId + 1); - } - - private void NormalizeParticipantState() - { - if (_inventory == null) - { - return; - } - - _inventory.ParticipantTowerInstanceIds ??= new List(); - Dictionary towerMap = new Dictionary(); - if (_inventory.Towers != null) - { - for (int i = 0; i < _inventory.Towers.Count; i++) - { - TowerItemData tower = _inventory.Towers[i]; - if (tower == null || tower.InstanceId <= 0) - { - continue; - } - - tower.IsParticipatingInCombat = false; - towerMap[tower.InstanceId] = tower; - } - } - - List normalizedIds = new List(_inventory.ParticipantTowerInstanceIds.Count); - HashSet uniqueIds = new HashSet(); - for (int i = 0; i < _inventory.ParticipantTowerInstanceIds.Count; i++) - { - if (normalizedIds.Count >= MaxParticipantTowerCount) - { - break; - } - - long id = _inventory.ParticipantTowerInstanceIds[i]; - if (id <= 0 || !uniqueIds.Add(id)) - { - continue; - } - - if (!towerMap.TryGetValue(id, out TowerItemData tower)) - { - continue; - } - - tower.IsParticipatingInCombat = true; - normalizedIds.Add(id); - } - - _inventory.ParticipantTowerInstanceIds = normalizedIds; - } - - private static BackpackInventoryData CloneInventory(BackpackInventoryData source) - { - BackpackInventoryData cloned = new BackpackInventoryData(); - if (source == null) - { - return cloned; - } - - cloned.Gold = Mathf.Max(0, source.Gold); - - if (source.MuzzleComponents != null) - { - for (int i = 0; i < source.MuzzleComponents.Count; i++) - { - MuzzleCompItemData item = source.MuzzleComponents[i]; - if (item != null) - { - cloned.MuzzleComponents.Add(CloneMuzzleComp(item)); - } - } - } - - if (source.BearingComponents != null) - { - for (int i = 0; i < source.BearingComponents.Count; i++) - { - BearingCompItemData item = source.BearingComponents[i]; - if (item != null) - { - cloned.BearingComponents.Add(CloneBearingComp(item)); - } - } - } - - if (source.BaseComponents != null) - { - for (int i = 0; i < source.BaseComponents.Count; i++) - { - BaseCompItemData item = source.BaseComponents[i]; - if (item != null) - { - cloned.BaseComponents.Add(CloneBaseComp(item)); - } - } - } - - if (source.Towers != null) - { - for (int i = 0; i < source.Towers.Count; i++) - { - TowerItemData item = source.Towers[i]; - if (item != null) - { - cloned.Towers.Add(CloneTower(item)); - } - } - } - - if (source.ParticipantTowerInstanceIds != null) - { - for (int i = 0; i < source.ParticipantTowerInstanceIds.Count; i++) - { - long id = source.ParticipantTowerInstanceIds[i]; - if (id > 0) - { - cloned.ParticipantTowerInstanceIds.Add(id); - } - } - } - - return cloned; - } - - private static MuzzleCompItemData CloneMuzzleComp(MuzzleCompItemData source) - { - return new MuzzleCompItemData - { - InstanceId = source.InstanceId, - ConfigId = source.ConfigId, - Name = source.Name, - Rarity = source.Rarity, - Endurance = source.Endurance, - IsAssembledIntoTower = source.IsAssembledIntoTower, - Constraint = source.Constraint, - Tags = CloneTags(source.Tags), - AttackDamage = CloneIntArray(source.AttackDamage), - DamageRandomRate = source.DamageRandomRate, - AttackMethodType = source.AttackMethodType - }; - } - - private static BearingCompItemData CloneBearingComp(BearingCompItemData source) - { - return new BearingCompItemData - { - InstanceId = source.InstanceId, - ConfigId = source.ConfigId, - Name = source.Name, - Rarity = source.Rarity, - Endurance = source.Endurance, - IsAssembledIntoTower = source.IsAssembledIntoTower, - Constraint = source.Constraint, - Tags = CloneTags(source.Tags), - RotateSpeed = CloneFloatArray(source.RotateSpeed), - AttackRange = CloneFloatArray(source.AttackRange) - }; - } - - private static BaseCompItemData CloneBaseComp(BaseCompItemData source) - { - return new BaseCompItemData - { - InstanceId = source.InstanceId, - ConfigId = source.ConfigId, - Name = source.Name, - Rarity = source.Rarity, - Endurance = source.Endurance, - IsAssembledIntoTower = source.IsAssembledIntoTower, - Constraint = source.Constraint, - Tags = CloneTags(source.Tags), - AttackSpeed = CloneFloatArray(source.AttackSpeed), - AttackPropertyType = source.AttackPropertyType - }; - } - - private static TowerItemData CloneTower(TowerItemData source) - { - return new TowerItemData - { - InstanceId = source.InstanceId, - Name = source.Name, - Rarity = source.Rarity, - IsParticipatingInCombat = source.IsParticipatingInCombat, - MuzzleComponentInstanceId = source.MuzzleComponentInstanceId, - BearingComponentInstanceId = source.BearingComponentInstanceId, - BaseComponentInstanceId = source.BaseComponentInstanceId, - Stats = CloneTowerStats(source.Stats) - }; - } - - private static TowerStatsData CloneTowerStats(TowerStatsData source) - { - if (source == null) - { - return new TowerStatsData(); - } - - return new TowerStatsData - { - AttackDamage = CloneIntArray(source.AttackDamage), - DamageRandomRate = source.DamageRandomRate, - RotateSpeed = CloneFloatArray(source.RotateSpeed), - AttackRange = CloneFloatArray(source.AttackRange), - AttackSpeed = CloneFloatArray(source.AttackSpeed), - AttackMethodType = source.AttackMethodType, - AttackPropertyType = source.AttackPropertyType, - Tags = CloneTags(source.Tags) - }; - } - - private static int[] CloneIntArray(int[] source) - { - return source != null ? (int[])source.Clone() : Array.Empty(); - } - - private static float[] CloneFloatArray(float[] source) - { - return source != null ? (float[])source.Clone() : Array.Empty(); - } - - private static TagType[] CloneTags(TagType[] source) - { - return source != null ? (TagType[])source.Clone() : Array.Empty(); - } - } -} diff --git a/Assets/GameMain/Scripts/Event/RepoForm/RepoItemDetailRequestedEventArgs.cs b/Assets/GameMain/Scripts/Event/RepoForm/RepoItemClickedEventArgs.cs similarity index 60% rename from Assets/GameMain/Scripts/Event/RepoForm/RepoItemDetailRequestedEventArgs.cs rename to Assets/GameMain/Scripts/Event/RepoForm/RepoItemClickedEventArgs.cs index fc93d44..d6ecce0 100644 --- a/Assets/GameMain/Scripts/Event/RepoForm/RepoItemDetailRequestedEventArgs.cs +++ b/Assets/GameMain/Scripts/Event/RepoForm/RepoItemClickedEventArgs.cs @@ -4,9 +4,9 @@ using UnityEngine; namespace GeometryTD.CustomEvent { - public class RepoItemDetailRequestedEventArgs : GameEventArgs + public sealed class RepoItemClickedEventArgs : GameEventArgs { - public static int EventId => typeof(RepoItemDetailRequestedEventArgs).GetHashCode(); + public static int EventId => typeof(RepoItemClickedEventArgs).GetHashCode(); public override int Id => EventId; @@ -14,9 +14,9 @@ namespace GeometryTD.CustomEvent public Vector3 TargetPos { get; private set; } - public static RepoItemDetailRequestedEventArgs Create(long itemId, Vector3 targetPos) + public static RepoItemClickedEventArgs Create(long itemId, Vector3 targetPos) { - var args = ReferencePool.Acquire(); + RepoItemClickedEventArgs args = ReferencePool.Acquire(); args.ItemId = itemId; args.TargetPos = targetPos; return args; diff --git a/Assets/GameMain/Scripts/Event/RepoForm/RepoItemClickedEventArgs.cs.meta b/Assets/GameMain/Scripts/Event/RepoForm/RepoItemClickedEventArgs.cs.meta new file mode 100644 index 0000000..6dd8d3f --- /dev/null +++ b/Assets/GameMain/Scripts/Event/RepoForm/RepoItemClickedEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7a2f4fddc38d47c3bf891cc17e211f89 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/Event/RepoForm/RepoParticipantRemoveRequestedEventArgs.cs b/Assets/GameMain/Scripts/Event/RepoForm/RepoParticipantRemoveRequestedEventArgs.cs deleted file mode 100644 index 571cf3d..0000000 --- a/Assets/GameMain/Scripts/Event/RepoForm/RepoParticipantRemoveRequestedEventArgs.cs +++ /dev/null @@ -1,27 +0,0 @@ -using GameFramework; -using GameFramework.Event; - -namespace GeometryTD.CustomEvent -{ - public sealed class RepoParticipantRemoveRequestedEventArgs : GameEventArgs - { - public static int EventId => typeof(RepoParticipantRemoveRequestedEventArgs).GetHashCode(); - - public override int Id => EventId; - - public long TowerItemId { get; private set; } - - public static RepoParticipantRemoveRequestedEventArgs Create(long towerItemId) - { - RepoParticipantRemoveRequestedEventArgs args = - ReferencePool.Acquire(); - args.TowerItemId = towerItemId; - return args; - } - - public override void Clear() - { - TowerItemId = 0; - } - } -} diff --git a/Assets/GameMain/Scripts/UI/Combat/Controller/CombatFinishFormController.cs b/Assets/GameMain/Scripts/UI/Combat/Controller/CombatFinishFormController.cs index ef2a17f..6911352 100644 --- a/Assets/GameMain/Scripts/UI/Combat/Controller/CombatFinishFormController.cs +++ b/Assets/GameMain/Scripts/UI/Combat/Controller/CombatFinishFormController.cs @@ -31,13 +31,13 @@ namespace GeometryTD.UI protected override void SubscribeCustomEvents() { GameEntry.Event.Subscribe(CombatFinishReturnEventArgs.EventId, OnCombatFinishReturnButtonClicked); - GameEntry.Event.Subscribe(RepoItemDetailRequestedEventArgs.EventId, OnRepoItemDetailRequested); + GameEntry.Event.Subscribe(RepoItemClickedEventArgs.EventId, OnRepoItemClicked); } protected override void UnsubscribeCustomEvents() { GameEntry.Event.Unsubscribe(CombatFinishReturnEventArgs.EventId, OnCombatFinishReturnButtonClicked); - GameEntry.Event.Unsubscribe(RepoItemDetailRequestedEventArgs.EventId, OnRepoItemDetailRequested); + GameEntry.Event.Unsubscribe(RepoItemClickedEventArgs.EventId, OnRepoItemClicked); } public override int? OpenUI(object userData = null) @@ -342,14 +342,14 @@ namespace GeometryTD.UI _useCase?.TryReturnToMenu(); } - private void OnRepoItemDetailRequested(object sender, GameEventArgs e) + private void OnRepoItemClicked(object sender, GameEventArgs e) { if (!IsEventFromCurrentForm(sender)) { return; } - if (!(e is RepoItemDetailRequestedEventArgs args)) + if (!(e is RepoItemClickedEventArgs args)) { return; } diff --git a/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatFinishFormUseCase.cs b/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatFinishFormUseCase.cs index 1499d84..7eee4d7 100644 --- a/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatFinishFormUseCase.cs +++ b/Assets/GameMain/Scripts/UI/Combat/UseCase/CombatFinishFormUseCase.cs @@ -1,4 +1,5 @@ using GeometryTD.CustomComponent; +using GeometryTD.CustomUtility; using GeometryTD.Definition; using UnityEngine; @@ -56,7 +57,7 @@ namespace GeometryTD.UI BackpackInventoryData rewardInventory = _rewardInventory; if (rewardInventory == null) { - rewardInventory = RepoFormUseCase.SampleInventory(); + rewardInventory = InventorySeedUtility.CreateSampleInventory(); } return new CombatFinishFormRawData diff --git a/Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.ContextBuilder.cs b/Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.ContextBuilder.cs new file mode 100644 index 0000000..fd926df --- /dev/null +++ b/Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.ContextBuilder.cs @@ -0,0 +1,366 @@ +using System; +using System.Collections.Generic; +using GeometryTD.CustomUtility; +using GeometryTD.Definition; +using UnityEngine; + +namespace GeometryTD.UI +{ + public partial class RepoFormController + { + private RepoFormContext BuildContext(RepoFormRawData rawData) + { + _itemContextMap.Clear(); + _itemDescSeedMap.Clear(); + if (rawData?.Inventory == null) + { + _participantTowerIds.Clear(); + return null; + } + + Dictionary muzzleMap = BuildComponentMap(rawData.Inventory.MuzzleComponents); + Dictionary bearingMap = BuildComponentMap(rawData.Inventory.BearingComponents); + Dictionary baseMap = BuildComponentMap(rawData.Inventory.BaseComponents); + Dictionary towerMap = BuildTowerMap(rawData.Inventory.Towers); + 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, + EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap), + ClickActionType = RepoItemClickActionType.OpenDetail, + ComponentSlotType = TowerCompSlotType.None, + IconAreaContext = BuildIconAreaContext(tower) + }); + AddItemDescSeed( + tower.InstanceId, + tower.Name, + "Tower", + ItemDescUtility.BuildTowerDesc(tower, muzzleMap, bearingMap, baseMap) ?? 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, + EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item), + ClickActionType = RepoItemClickActionType.OpenDetail, + 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, + EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item), + ClickActionType = RepoItemClickActionType.OpenDetail, + 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, + EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item), + ClickActionType = RepoItemClickActionType.OpenDetail, + ComponentSlotType = TowerCompSlotType.Base, + IconAreaContext = BuildIconAreaContext(item) + }); + AddItemDescSeed( + item.InstanceId, + item.Name, + BuildComponentTypeText(item.SlotType), + ItemDescUtility.BuildBaseDesc(item) ?? string.Empty, + item.Tags); + } + } + + ParticipantAreaContext participantAreaContext = + BuildParticipantAreaContext(rawData.Inventory, towerMap, muzzleMap, bearingMap, baseMap); + + return new RepoFormContext + { + CombineAreaContext = new CombineAreaContext(), + CompAreaContext = new CompAreaContext + { + Items = items.ToArray() + }, + ParticipantAreaContext = participantAreaContext + }; + } + + 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 Dictionary BuildComponentMap(IReadOnlyList items) + where TComp : TowerCompItemData + { + Dictionary map = new Dictionary(); + if (items == null) + { + return map; + } + + for (int i = 0; i < items.Count; i++) + { + TComp item = items[i]; + if (item == null || item.InstanceId <= 0) + { + continue; + } + + map[item.InstanceId] = item; + } + + return map; + } + + private static Dictionary BuildTowerMap(IReadOnlyList towers) + { + Dictionary map = new Dictionary(); + if (towers == null) + { + return map; + } + + for (int i = 0; i < towers.Count; i++) + { + TowerItemData tower = towers[i]; + if (tower == null || tower.InstanceId <= 0) + { + continue; + } + + map[tower.InstanceId] = tower; + } + + return map; + } + + private ParticipantAreaContext BuildParticipantAreaContext( + BackpackInventoryData inventory, + IReadOnlyDictionary towerMap, + IReadOnlyDictionary muzzleMap, + IReadOnlyDictionary bearingMap, + IReadOnlyDictionary baseMap) + { + _participantTowerIds.Clear(); + List participantItems = new List(); + if (inventory?.ParticipantTowerInstanceIds != null && towerMap != null) + { + for (int i = 0; i < inventory.ParticipantTowerInstanceIds.Count; i++) + { + long towerId = inventory.ParticipantTowerInstanceIds[i]; + if (towerId <= 0) + { + continue; + } + + if (!towerMap.TryGetValue(towerId, out TowerItemData tower) || tower == null) + { + continue; + } + + if (!_participantTowerIds.Add(towerId)) + { + continue; + } + + participantItems.Add(new RepoItemContext + { + InstanceId = tower.InstanceId, + CanDrag = false, + EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap), + ClickActionType = RepoItemClickActionType.RemoveParticipant, + ComponentSlotType = TowerCompSlotType.None, + IconAreaContext = BuildIconAreaContext(tower) + }); + } + } + + return new ParticipantAreaContext + { + Items = participantItems.ToArray(), + MaxCount = MaxParticipantCount + }; + } + + private void ApplyParticipantSelection() + { + if (Form == null || _itemContextMap.Count <= 0) + { + return; + } + + foreach (KeyValuePair pair in _itemContextMap) + { + RepoItemContext itemContext = pair.Value; + if (itemContext == null || itemContext.ComponentSlotType != TowerCompSlotType.None) + { + continue; + } + + Form.SetRepoItemSelected(pair.Key, _participantTowerIds.Contains(pair.Key)); + } + } + + private void RefreshParticipantAreaOnly() + { + if (_useCase == null || Form == null) + { + return; + } + + RepoFormContext latestContext = BuildContext(_useCase.CreateInitialModel()); + if (latestContext?.ParticipantAreaContext == null) + { + return; + } + + Form.RefreshParticipantArea(latestContext.ParticipantAreaContext); + ApplyParticipantSelection(); + } + + 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 + }; + } + } +} diff --git a/Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.ContextBuilder.cs.meta b/Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.ContextBuilder.cs.meta new file mode 100644 index 0000000..d66b261 --- /dev/null +++ b/Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.ContextBuilder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 55cf579e25a94ec6987443b7c6e6ab5f +timeCreated: 1772629679 \ No newline at end of file diff --git a/Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.cs b/Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.cs index 5006816..016cba0 100644 --- a/Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.cs +++ b/Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.cs @@ -1,15 +1,13 @@ -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 + public partial class RepoFormController : UIFormControllerCommonBase { private const int MaxParticipantCount = 4; private RepoFormUseCase _useCase; @@ -35,23 +33,21 @@ namespace GeometryTD.UI protected override void SubscribeCustomEvents() { - GameEntry.Event.Subscribe(RepoItemDetailRequestedEventArgs.EventId, OnRepoItemDetailRequested); + GameEntry.Event.Subscribe(RepoItemClickedEventArgs.EventId, OnRepoItemClicked); GameEntry.Event.Subscribe(RepoItemDragEndedEventArgs.EventId, OnRepoItemDragEnded); GameEntry.Event.Subscribe(CombineSlotClickedEventArgs.EventId, OnCombineSlotClicked); GameEntry.Event.Subscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested); GameEntry.Event.Subscribe(RepoParticipantAssignRequestedEventArgs.EventId, OnRepoParticipantAssignRequested); - GameEntry.Event.Subscribe(RepoParticipantRemoveRequestedEventArgs.EventId, OnRepoParticipantRemoveRequested); GameEntry.Event.Subscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn); } protected override void UnsubscribeCustomEvents() { - GameEntry.Event.Unsubscribe(RepoItemDetailRequestedEventArgs.EventId, OnRepoItemDetailRequested); + GameEntry.Event.Unsubscribe(RepoItemClickedEventArgs.EventId, OnRepoItemClicked); GameEntry.Event.Unsubscribe(RepoItemDragEndedEventArgs.EventId, OnRepoItemDragEnded); GameEntry.Event.Unsubscribe(CombineSlotClickedEventArgs.EventId, OnCombineSlotClicked); GameEntry.Event.Unsubscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested); GameEntry.Event.Unsubscribe(RepoParticipantAssignRequestedEventArgs.EventId, OnRepoParticipantAssignRequested); - GameEntry.Event.Unsubscribe(RepoParticipantRemoveRequestedEventArgs.EventId, OnRepoParticipantRemoveRequested); GameEntry.Event.Unsubscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn); } @@ -100,375 +96,52 @@ namespace GeometryTD.UI _useCase = repoFormUseCase; } - private RepoFormContext BuildContext(RepoFormRawData rawData) - { - _itemContextMap.Clear(); - _itemDescSeedMap.Clear(); - if (rawData?.Inventory == null) - { - _participantTowerIds.Clear(); - return null; - } - - Dictionary muzzleMap = BuildComponentMap(rawData.Inventory.MuzzleComponents); - Dictionary bearingMap = BuildComponentMap(rawData.Inventory.BearingComponents); - Dictionary baseMap = BuildComponentMap(rawData.Inventory.BaseComponents); - Dictionary towerMap = BuildTowerMap(rawData.Inventory.Towers); - 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, - EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap), - ClickActionType = RepoItemClickActionType.OpenDetail, - ComponentSlotType = TowerCompSlotType.None, - IconAreaContext = BuildIconAreaContext(tower) - }); - AddItemDescSeed( - tower.InstanceId, - tower.Name, - "Tower", - ItemDescUtility.BuildTowerDesc(tower, muzzleMap, bearingMap, baseMap) ?? 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, - EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item), - ClickActionType = RepoItemClickActionType.OpenDetail, - 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, - EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item), - ClickActionType = RepoItemClickActionType.OpenDetail, - 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, - EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item), - ClickActionType = RepoItemClickActionType.OpenDetail, - ComponentSlotType = TowerCompSlotType.Base, - IconAreaContext = BuildIconAreaContext(item) - }); - AddItemDescSeed( - item.InstanceId, - item.Name, - BuildComponentTypeText(item.SlotType), - ItemDescUtility.BuildBaseDesc(item) ?? string.Empty, - item.Tags); - } - } - - ParticipantAreaContext participantAreaContext = - BuildParticipantAreaContext(rawData.Inventory, towerMap, muzzleMap, bearingMap, baseMap); - - return new RepoFormContext - { - CombineAreaContext = new CombineAreaContext(), - CompAreaContext = new CompAreaContext - { - Items = items.ToArray() - }, - ParticipantAreaContext = participantAreaContext - }; - } - - 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 Dictionary BuildComponentMap(IReadOnlyList items) - where TComp : TowerCompItemData - { - Dictionary map = new Dictionary(); - if (items == null) - { - return map; - } - - for (int i = 0; i < items.Count; i++) - { - TComp item = items[i]; - if (item == null || item.InstanceId <= 0) - { - continue; - } - - map[item.InstanceId] = item; - } - - return map; - } - - private static Dictionary BuildTowerMap(IReadOnlyList towers) - { - Dictionary map = new Dictionary(); - if (towers == null) - { - return map; - } - - for (int i = 0; i < towers.Count; i++) - { - TowerItemData tower = towers[i]; - if (tower == null || tower.InstanceId <= 0) - { - continue; - } - - map[tower.InstanceId] = tower; - } - - return map; - } - - private ParticipantAreaContext BuildParticipantAreaContext( - BackpackInventoryData inventory, - IReadOnlyDictionary towerMap, - IReadOnlyDictionary muzzleMap, - IReadOnlyDictionary bearingMap, - IReadOnlyDictionary baseMap) - { - _participantTowerIds.Clear(); - List participantItems = new List(); - if (inventory?.ParticipantTowerInstanceIds != null && towerMap != null) - { - for (int i = 0; i < inventory.ParticipantTowerInstanceIds.Count; i++) - { - long towerId = inventory.ParticipantTowerInstanceIds[i]; - if (towerId <= 0) - { - continue; - } - - if (!towerMap.TryGetValue(towerId, out TowerItemData tower) || tower == null) - { - continue; - } - - if (!_participantTowerIds.Add(towerId)) - { - continue; - } - - participantItems.Add(new RepoItemContext - { - InstanceId = tower.InstanceId, - CanDrag = false, - EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap), - ClickActionType = RepoItemClickActionType.RemoveParticipant, - ComponentSlotType = TowerCompSlotType.None, - IconAreaContext = BuildIconAreaContext(tower) - }); - } - } - - return new ParticipantAreaContext - { - Items = participantItems.ToArray(), - MaxCount = MaxParticipantCount - }; - } - - private void ApplyParticipantSelection() - { - if (Form == null || _itemContextMap.Count <= 0) - { - return; - } - - foreach (KeyValuePair pair in _itemContextMap) - { - RepoItemContext itemContext = pair.Value; - if (itemContext == null || itemContext.ComponentSlotType != TowerCompSlotType.None) - { - continue; - } - - Form.SetRepoItemSelected(pair.Key, _participantTowerIds.Contains(pair.Key)); - } - } - - private void RefreshParticipantAreaOnly() - { - if (_useCase == null || Form == null) - { - return; - } - - RepoFormContext latestContext = BuildContext(_useCase.CreateInitialModel()); - if (latestContext?.ParticipantAreaContext == null) - { - return; - } - - Form.RefreshParticipantArea(latestContext.ParticipantAreaContext); - ApplyParticipantSelection(); - } - - 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) + private void OnRepoItemClicked(object sender, GameEventArgs e) { if (!IsEventFromCurrentForm(sender)) { return; } - if (!(e is RepoItemDetailRequestedEventArgs args)) + if (!(e is RepoItemClickedEventArgs args)) { return; } + RepoItemClickActionType clickActionType = RepoItemClickActionType.OpenDetail; + if (sender is RepoItem clickedItem && clickedItem.Context != null) + { + clickActionType = clickedItem.Context.ClickActionType; + } + else if (_itemContextMap.TryGetValue(args.ItemId, out RepoItemContext itemContextFromMap) && + itemContextFromMap != null) + { + clickActionType = itemContextFromMap.ClickActionType; + } + + if (args.ItemId <= 0) + { + return; + } + + if (clickActionType == RepoItemClickActionType.RemoveParticipant) + { + if (_useCase == null || Form == null) + { + return; + } + + if (!_useCase.TryRemoveParticipantTower(args.ItemId)) + { + return; + } + + RefreshParticipantAreaOnly(); + return; + } + if (!_itemDescSeedMap.TryGetValue(args.ItemId, out ItemDescSeed seed)) { return; @@ -599,31 +272,6 @@ namespace GeometryTD.UI RefreshParticipantAreaOnly(); } - private void OnRepoParticipantRemoveRequested(object sender, GameEventArgs e) - { - if (!IsEventFromCurrentForm(sender)) - { - return; - } - - if (!(e is RepoParticipantRemoveRequestedEventArgs args)) - { - return; - } - - if (_useCase == null || Form == null || args.TowerItemId <= 0) - { - return; - } - - if (!_useCase.TryRemoveParticipantTower(args.TowerItemId)) - { - return; - } - - RefreshParticipantAreaOnly(); - } - private bool IsEventFromCurrentForm(object sender) { if (Form == null) diff --git a/Assets/GameMain/Scripts/UI/Game/UseCase/RepoFormUseCase.cs b/Assets/GameMain/Scripts/UI/Game/UseCase/RepoFormUseCase.cs index bacbb63..a15f1bf 100644 --- a/Assets/GameMain/Scripts/UI/Game/UseCase/RepoFormUseCase.cs +++ b/Assets/GameMain/Scripts/UI/Game/UseCase/RepoFormUseCase.cs @@ -1,3 +1,4 @@ +using GeometryTD.CustomUtility; using GeometryTD.Definition; namespace GeometryTD.UI @@ -37,7 +38,10 @@ namespace GeometryTD.UI if (GameEntry.PlayerInventory == null) { BackpackInventoryData fallbackInventory = GetOrCreateFallbackInventory(); - return TryAddParticipantTowerInternal(fallbackInventory, towerItemId, MaxParticipantCount); + return InventoryParticipantUtility.TryAddParticipantTower( + fallbackInventory, + towerItemId, + MaxParticipantCount); } return GameEntry.PlayerInventory.TryAddParticipantTower(towerItemId, 4); @@ -48,7 +52,10 @@ namespace GeometryTD.UI if (GameEntry.PlayerInventory == null) { BackpackInventoryData fallbackInventory = GetOrCreateFallbackInventory(); - return TryRemoveParticipantTowerInternal(fallbackInventory, towerItemId); + return InventoryParticipantUtility.TryRemoveParticipantTower( + fallbackInventory, + towerItemId, + MaxParticipantCount); } return GameEntry.PlayerInventory.TryRemoveParticipantTower(towerItemId); @@ -56,326 +63,15 @@ namespace GeometryTD.UI private BackpackInventoryData GetOrCreateFallbackInventory() { - _fallbackInventory ??= SampleInventory(); - NormalizeParticipantState(_fallbackInventory); + _fallbackInventory ??= InventorySeedUtility.CreateSampleInventory(); + InventoryParticipantUtility.NormalizeParticipantState(_fallbackInventory, MaxParticipantCount); return _fallbackInventory; } - private static bool TryAddParticipantTowerInternal( - BackpackInventoryData inventory, - long towerItemId, - int maxCount) - { - if (inventory == null || towerItemId <= 0) - { - return false; - } - - NormalizeParticipantState(inventory); - if (!TryGetTowerById(inventory, towerItemId, out TowerItemData tower)) - { - return false; - } - - inventory.ParticipantTowerInstanceIds ??= new System.Collections.Generic.List(); - if (inventory.ParticipantTowerInstanceIds.Contains(towerItemId)) - { - tower.IsParticipatingInCombat = true; - return false; - } - - if (inventory.ParticipantTowerInstanceIds.Count >= UnityEngine.Mathf.Max(1, maxCount)) - { - return false; - } - - inventory.ParticipantTowerInstanceIds.Add(towerItemId); - tower.IsParticipatingInCombat = true; - return true; - } - - private static bool TryRemoveParticipantTowerInternal(BackpackInventoryData inventory, long towerItemId) - { - if (inventory == null || towerItemId <= 0) - { - return false; - } - - NormalizeParticipantState(inventory); - if (inventory.ParticipantTowerInstanceIds == null) - { - return false; - } - - bool removed = inventory.ParticipantTowerInstanceIds.Remove(towerItemId); - if (!removed) - { - return false; - } - - if (TryGetTowerById(inventory, towerItemId, out TowerItemData tower)) - { - tower.IsParticipatingInCombat = false; - } - - return true; - } - - private static bool TryGetTowerById(BackpackInventoryData inventory, long towerItemId, out TowerItemData tower) - { - tower = null; - if (inventory?.Towers == null || towerItemId <= 0) - { - return false; - } - - for (int i = 0; i < inventory.Towers.Count; i++) - { - TowerItemData candidate = inventory.Towers[i]; - if (candidate != null && candidate.InstanceId == towerItemId) - { - tower = candidate; - return true; - } - } - - return false; - } - - private static void NormalizeParticipantState(BackpackInventoryData inventory) - { - if (inventory == null) - { - return; - } - - inventory.ParticipantTowerInstanceIds ??= new System.Collections.Generic.List(); - System.Collections.Generic.Dictionary towerMap = - new System.Collections.Generic.Dictionary(); - if (inventory.Towers != null) - { - for (int i = 0; i < inventory.Towers.Count; i++) - { - TowerItemData tower = inventory.Towers[i]; - if (tower == null || tower.InstanceId <= 0) - { - continue; - } - - tower.IsParticipatingInCombat = false; - towerMap[tower.InstanceId] = tower; - } - } - - System.Collections.Generic.HashSet uniqueIds = new System.Collections.Generic.HashSet(); - System.Collections.Generic.List normalizedIds = - new System.Collections.Generic.List(inventory.ParticipantTowerInstanceIds.Count); - for (int i = 0; i < inventory.ParticipantTowerInstanceIds.Count; i++) - { - if (normalizedIds.Count >= MaxParticipantCount) - { - break; - } - - long towerId = inventory.ParticipantTowerInstanceIds[i]; - if (towerId <= 0 || !uniqueIds.Add(towerId)) - { - continue; - } - - if (!towerMap.TryGetValue(towerId, out TowerItemData tower)) - { - continue; - } - - tower.IsParticipatingInCombat = true; - normalizedIds.Add(towerId); - } - - inventory.ParticipantTowerInstanceIds = normalizedIds; - } - public static BackpackInventoryData SampleInventory() { - BackpackInventoryData inventory = new BackpackInventoryData - { - Gold = 500 - }; - - MuzzleCompItemData muzzle = new MuzzleCompItemData - { - InstanceId = 10001, - ConfigId = 1, - Name = "元素枪口", - Rarity = RarityType.Green, - Endurance = 90f, - IsAssembledIntoTower = true, - AttackDamage = new[] { 20, 30, 40, 50, 80 }, - DamageRandomRate = 0.05f, - AttackMethodType = AttackMethodType.NormalBullet, - Constraint = string.Empty, - Tags = new[] { TagType.Fire } - }; - inventory.MuzzleComponents.Add(muzzle); - inventory.MuzzleComponents.Add(new MuzzleCompItemData - { - InstanceId = 10002, - ConfigId = 2, - Name = "控制枪口", - Rarity = RarityType.Blue, - Endurance = 80, - IsAssembledIntoTower = false, - AttackDamage = new[] { 30, 50, 70, 90, 100 }, - DamageRandomRate = 0.01f, - AttackMethodType = AttackMethodType.NormalBullet, - Constraint = string.Empty, - Tags = new[] { TagType.Ice, TagType.FreezeMask } - }); - inventory.MuzzleComponents.Add(new MuzzleCompItemData - { - InstanceId = 10003, - ConfigId = 3, - Name = "穿透枪口", - Rarity = RarityType.Purple, - Endurance = 97f, - IsAssembledIntoTower = false, - AttackDamage = new[] { 50, 55, 60, 80, 90 }, - DamageRandomRate = 0.02f, - AttackMethodType = AttackMethodType.NormalBullet, - Constraint = string.Empty, - Tags = new[] { TagType.Pierce, TagType.Crit } - }); - - BearingCompItemData bearing = new BearingCompItemData - { - InstanceId = 20001, - ConfigId = 1, - Name = "元素轴承", - Rarity = RarityType.Green, - Endurance = 1f, - IsAssembledIntoTower = true, - RotateSpeed = new[] { 10f, 12f, 13f, 14f, 15f }, - AttackRange = new[] { 2f, 2f, 2f, 2f, 2f }, - Constraint = string.Empty, - Tags = new[] { TagType.Fire } - }; - inventory.BearingComponents.Add(bearing); - inventory.BearingComponents.Add(new BearingCompItemData - { - InstanceId = 20002, - ConfigId = 2, - Name = "控制轴承", - Rarity = RarityType.Blue, - Endurance = 20, - IsAssembledIntoTower = false, - RotateSpeed = new[] { 20f, 25f, 30f, 32f, 35f }, - AttackRange = new[] { 6f, 6.5f, 7f, 8f, 8f }, - Constraint = string.Empty, - Tags = new[] { TagType.Ice, TagType.Shatter } - }); - inventory.BearingComponents.Add(new BearingCompItemData - { - InstanceId = 20003, - ConfigId = 3, - Name = "穿透轴承", - Rarity = RarityType.Purple, - Endurance = 96f, - IsAssembledIntoTower = false, - RotateSpeed = new[] { 60f, 70f, 80f, 90f, 100f }, - AttackRange = new[] { 4f, 4.5f, 5f, 5.5f, 6f }, - Constraint = string.Empty, - Tags = new[] { TagType.Pierce, TagType.Overpenetrate } - }); - - BaseCompItemData baseComp = new BaseCompItemData - { - InstanceId = 30001, - ConfigId = 1, - Name = "元素底座", - Rarity = RarityType.Green, - Endurance = 88f, - IsAssembledIntoTower = true, - AttackSpeed = new[] { 2f, 1.5f, 1f, 0.8f, 0.7f }, - AttackPropertyType = AttackPropertyType.Fire, - Constraint = string.Empty, - Tags = new[] { TagType.Fire } - }; - inventory.BaseComponents.Add(baseComp); - inventory.BaseComponents.Add(new BaseCompItemData - { - InstanceId = 30002, - ConfigId = 2, - Name = "控制底座", - Rarity = RarityType.Blue, - Endurance = 50f, - IsAssembledIntoTower = false, - AttackSpeed = new[] { 4f, 4.2f, 4.4f, 4.6f, 4.8f }, - AttackPropertyType = AttackPropertyType.Ice, - Constraint = string.Empty, - Tags = new[] { TagType.Ice, TagType.AbsoluteZero } - }); - inventory.BaseComponents.Add(new BaseCompItemData - { - InstanceId = 30003, - ConfigId = 3, - Name = "穿透底座", - Rarity = RarityType.Purple, - Endurance = 30f, - IsAssembledIntoTower = false, - AttackSpeed = new[] { 1f, 1f, 1f, 1f, 1f }, - AttackPropertyType = AttackPropertyType.Physics, - Constraint = string.Empty, - Tags = new[] { TagType.Pierce, TagType.Execution } - }); - - TowerItemData tower = new TowerItemData - { - InstanceId = 90001, - Name = "测试防御塔-A", - Rarity = RarityType.Green, - IsParticipatingInCombat = true, - MuzzleComponentInstanceId = muzzle.InstanceId, - BearingComponentInstanceId = bearing.InstanceId, - BaseComponentInstanceId = baseComp.InstanceId, - Stats = new TowerStatsData - { - AttackDamage = new[] { 200, 220, 240, 260, 300 }, - DamageRandomRate = 0f, - RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f }, - AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f }, - AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f }, - AttackMethodType = AttackMethodType.NormalBullet, - AttackPropertyType = AttackPropertyType.Fire, - Tags = new[] { TagType.Fire, TagType.BurnSpread } - } - }; - inventory.Towers.Add(tower); - - inventory.Towers.Add(new TowerItemData - { - InstanceId = 90002, - Name = "测试防御塔-B", - Rarity = RarityType.Blue, - IsParticipatingInCombat = false, - MuzzleComponentInstanceId = 0, - BearingComponentInstanceId = 0, - BaseComponentInstanceId = 0, - Stats = new TowerStatsData - { - AttackDamage = new[] { 200, 220, 240, 260, 300 }, - DamageRandomRate = 0.1f, - RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f }, - AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f }, - AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f }, - AttackMethodType = AttackMethodType.NormalBullet, - AttackPropertyType = AttackPropertyType.Physics, - Tags = new[] { TagType.Pierce } - } - }); - - inventory.ParticipantTowerInstanceIds.Add(90001); - - return inventory; + return InventorySeedUtility.CreateSampleInventory(); } } } + diff --git a/Assets/GameMain/Scripts/UI/Game/View/RepoItem.cs b/Assets/GameMain/Scripts/UI/Game/View/RepoItem.cs index 168ce9f..ddf0131 100644 --- a/Assets/GameMain/Scripts/UI/Game/View/RepoItem.cs +++ b/Assets/GameMain/Scripts/UI/Game/View/RepoItem.cs @@ -1,4 +1,3 @@ -using System.Collections; using GeometryTD.CustomEvent; using GeometryTD.Definition; using UnityEngine; @@ -27,8 +26,6 @@ namespace GeometryTD.UI private bool _isDragging; private bool _dropHandled; private bool _dropAssigned; - private Coroutine _pendingOpenDetailRoutine; - private bool _cancelPendingOpenDetail; public RepoItemContext Context => _context; @@ -43,7 +40,6 @@ namespace GeometryTD.UI private void OnDisable() { - CancelPendingOpenDetail(); ResetDragState(); } @@ -65,7 +61,6 @@ namespace GeometryTD.UI public void OnReset() { - CancelPendingOpenDetail(); _context = null; _iconArea.OnReset(); @@ -108,13 +103,7 @@ namespace GeometryTD.UI return; } - if (_context.ClickActionType == RepoItemClickActionType.RemoveParticipant) - { - GameEntry.Event.Fire(this, RepoParticipantRemoveRequestedEventArgs.Create(_context.InstanceId)); - return; - } - - StartPendingOpenDetail(); + GameEntry.Event.Fire(this, RepoItemClickedEventArgs.Create(_context.InstanceId, transform.position)); } public void OnBeginDrag(PointerEventData eventData) @@ -133,7 +122,6 @@ namespace GeometryTD.UI _isDragging = true; _dropHandled = false; _dropAssigned = false; - _cancelPendingOpenDetail = true; CloseItemDescFormIfOpen(); @@ -224,56 +212,6 @@ namespace GeometryTD.UI return true; } - private void StartPendingOpenDetail() - { - CancelPendingOpenDetail(); - _cancelPendingOpenDetail = false; - _pendingOpenDetailRoutine = StartCoroutine(WaitPointerReleaseAndOpenDetail()); - } - - private void CancelPendingOpenDetail() - { - _cancelPendingOpenDetail = true; - if (_pendingOpenDetailRoutine != null) - { - StopCoroutine(_pendingOpenDetailRoutine); - _pendingOpenDetailRoutine = null; - } - } - - private IEnumerator WaitPointerReleaseAndOpenDetail() - { - while (IsPrimaryPointerPressed()) - { - if (_cancelPendingOpenDetail || _isDragging) - { - _pendingOpenDetailRoutine = null; - yield break; - } - - yield return null; - } - - _pendingOpenDetailRoutine = null; - if (_cancelPendingOpenDetail || _isDragging || _context == null) - { - yield break; - } - - GameEntry.Event.Fire(this, - RepoItemDetailRequestedEventArgs.Create(_context.InstanceId, transform.position)); - } - - private static bool IsPrimaryPointerPressed() - { - if (Input.GetMouseButton(0)) - { - return true; - } - - return Input.touchCount > 0; - } - private static void CloseItemDescFormIfOpen() { var itemDescForm = GameEntry.UI.GetUIForm(UIFormType.ItemDescForm); diff --git a/Assets/GameMain/Scripts/UI/General/UseCase/RewardSelectFormUseCase.cs b/Assets/GameMain/Scripts/UI/General/UseCase/RewardSelectFormUseCase.cs index 57f3ea8..f617527 100644 --- a/Assets/GameMain/Scripts/UI/General/UseCase/RewardSelectFormUseCase.cs +++ b/Assets/GameMain/Scripts/UI/General/UseCase/RewardSelectFormUseCase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using GeometryTD.CustomUtility; using GeometryTD.Definition; using UnityEngine; using Random = UnityEngine.Random; @@ -211,7 +212,7 @@ namespace GeometryTD.UI private static List BuildDefaultRewardPool() { - BackpackInventoryData inventory = RepoFormUseCase.SampleInventory(); + BackpackInventoryData inventory = InventorySeedUtility.CreateSampleInventory(); List rewards = new List(); if (inventory?.MuzzleComponents != null) diff --git a/Assets/GameMain/Scripts/Utility/InventoryCloneUtility.cs b/Assets/GameMain/Scripts/Utility/InventoryCloneUtility.cs new file mode 100644 index 0000000..35a1652 --- /dev/null +++ b/Assets/GameMain/Scripts/Utility/InventoryCloneUtility.cs @@ -0,0 +1,207 @@ +using System; +using GeometryTD.Definition; +using UnityEngine; + +namespace GeometryTD.CustomUtility +{ + public static class InventoryCloneUtility + { + public static BackpackInventoryData CloneInventory(BackpackInventoryData source) + { + BackpackInventoryData cloned = new BackpackInventoryData(); + if (source == null) + { + return cloned; + } + + cloned.Gold = Mathf.Max(0, source.Gold); + + if (source.MuzzleComponents != null) + { + for (int i = 0; i < source.MuzzleComponents.Count; i++) + { + MuzzleCompItemData item = source.MuzzleComponents[i]; + if (item != null) + { + cloned.MuzzleComponents.Add(CloneMuzzleComp(item)); + } + } + } + + if (source.BearingComponents != null) + { + for (int i = 0; i < source.BearingComponents.Count; i++) + { + BearingCompItemData item = source.BearingComponents[i]; + if (item != null) + { + cloned.BearingComponents.Add(CloneBearingComp(item)); + } + } + } + + if (source.BaseComponents != null) + { + for (int i = 0; i < source.BaseComponents.Count; i++) + { + BaseCompItemData item = source.BaseComponents[i]; + if (item != null) + { + cloned.BaseComponents.Add(CloneBaseComp(item)); + } + } + } + + if (source.Towers != null) + { + for (int i = 0; i < source.Towers.Count; i++) + { + TowerItemData item = source.Towers[i]; + if (item != null) + { + cloned.Towers.Add(CloneTower(item)); + } + } + } + + if (source.ParticipantTowerInstanceIds != null) + { + for (int i = 0; i < source.ParticipantTowerInstanceIds.Count; i++) + { + long id = source.ParticipantTowerInstanceIds[i]; + if (id > 0) + { + cloned.ParticipantTowerInstanceIds.Add(id); + } + } + } + + return cloned; + } + + public static MuzzleCompItemData CloneMuzzleComp(MuzzleCompItemData source) + { + if (source == null) + { + return null; + } + + return new MuzzleCompItemData + { + InstanceId = source.InstanceId, + ConfigId = source.ConfigId, + Name = source.Name, + Rarity = source.Rarity, + Endurance = source.Endurance, + IsAssembledIntoTower = source.IsAssembledIntoTower, + Constraint = source.Constraint, + Tags = CloneTags(source.Tags), + AttackDamage = CloneIntArray(source.AttackDamage), + DamageRandomRate = source.DamageRandomRate, + AttackMethodType = source.AttackMethodType + }; + } + + public static BearingCompItemData CloneBearingComp(BearingCompItemData source) + { + if (source == null) + { + return null; + } + + return new BearingCompItemData + { + InstanceId = source.InstanceId, + ConfigId = source.ConfigId, + Name = source.Name, + Rarity = source.Rarity, + Endurance = source.Endurance, + IsAssembledIntoTower = source.IsAssembledIntoTower, + Constraint = source.Constraint, + Tags = CloneTags(source.Tags), + RotateSpeed = CloneFloatArray(source.RotateSpeed), + AttackRange = CloneFloatArray(source.AttackRange) + }; + } + + public static BaseCompItemData CloneBaseComp(BaseCompItemData source) + { + if (source == null) + { + return null; + } + + return new BaseCompItemData + { + InstanceId = source.InstanceId, + ConfigId = source.ConfigId, + Name = source.Name, + Rarity = source.Rarity, + Endurance = source.Endurance, + IsAssembledIntoTower = source.IsAssembledIntoTower, + Constraint = source.Constraint, + Tags = CloneTags(source.Tags), + AttackSpeed = CloneFloatArray(source.AttackSpeed), + AttackPropertyType = source.AttackPropertyType + }; + } + + public static TowerItemData CloneTower(TowerItemData source) + { + if (source == null) + { + return null; + } + + return new TowerItemData + { + InstanceId = source.InstanceId, + Name = source.Name, + Rarity = source.Rarity, + IsParticipatingInCombat = source.IsParticipatingInCombat, + MuzzleComponentInstanceId = source.MuzzleComponentInstanceId, + BearingComponentInstanceId = source.BearingComponentInstanceId, + BaseComponentInstanceId = source.BaseComponentInstanceId, + Stats = CloneTowerStats(source.Stats) + }; + } + + public static TowerStatsData CloneTowerStats(TowerStatsData source) + { + if (source == null) + { + return new TowerStatsData(); + } + + return new TowerStatsData + { + AttackDamage = CloneIntArray(source.AttackDamage), + DamageRandomRate = source.DamageRandomRate, + RotateSpeed = CloneFloatArray(source.RotateSpeed), + AttackRange = CloneFloatArray(source.AttackRange), + AttackSpeed = CloneFloatArray(source.AttackSpeed), + AttackMethodType = source.AttackMethodType, + AttackPropertyType = source.AttackPropertyType, + Tags = CloneTags(source.Tags) + }; + } + + public static int[] CloneIntArray(int[] source) + { + return source != null ? (int[])source.Clone() : Array.Empty(); + } + + public static float[] CloneFloatArray(float[] source) + { + return source != null ? (float[])source.Clone() : Array.Empty(); + } + + public static TagType[] CloneTags(TagType[] source) + { + return source != null ? (TagType[])source.Clone() : Array.Empty(); + } + } + + +} + diff --git a/Assets/GameMain/Scripts/Utility/InventoryCloneUtility.cs.meta b/Assets/GameMain/Scripts/Utility/InventoryCloneUtility.cs.meta new file mode 100644 index 0000000..e9138e9 --- /dev/null +++ b/Assets/GameMain/Scripts/Utility/InventoryCloneUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 71ce567f99e231a48a4c25a322c2b8cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/Utility/InventoryParticipantUtility.cs b/Assets/GameMain/Scripts/Utility/InventoryParticipantUtility.cs new file mode 100644 index 0000000..acff244 --- /dev/null +++ b/Assets/GameMain/Scripts/Utility/InventoryParticipantUtility.cs @@ -0,0 +1,140 @@ +using System.Collections.Generic; +using GeometryTD.Definition; +using UnityEngine; + +namespace GeometryTD.CustomUtility +{ + public static class InventoryParticipantUtility + { + public static bool TryAddParticipantTower(BackpackInventoryData inventory, long towerInstanceId, int maxCount) + { + if (inventory == null || towerInstanceId <= 0) + { + return false; + } + + int resolvedMaxCount = Mathf.Max(1, maxCount); + NormalizeParticipantState(inventory, resolvedMaxCount); + if (!TryGetTowerById(inventory, towerInstanceId, out TowerItemData tower)) + { + return false; + } + + inventory.ParticipantTowerInstanceIds ??= new List(); + if (inventory.ParticipantTowerInstanceIds.Contains(towerInstanceId)) + { + tower.IsParticipatingInCombat = true; + return false; + } + + if (inventory.ParticipantTowerInstanceIds.Count >= resolvedMaxCount) + { + return false; + } + + inventory.ParticipantTowerInstanceIds.Add(towerInstanceId); + tower.IsParticipatingInCombat = true; + return true; + } + + public static bool TryRemoveParticipantTower(BackpackInventoryData inventory, long towerInstanceId, int maxCount) + { + if (inventory == null || towerInstanceId <= 0) + { + return false; + } + + NormalizeParticipantState(inventory, maxCount); + if (inventory.ParticipantTowerInstanceIds == null) + { + return false; + } + + bool removed = inventory.ParticipantTowerInstanceIds.Remove(towerInstanceId); + if (!removed) + { + return false; + } + + if (TryGetTowerById(inventory, towerInstanceId, out TowerItemData tower)) + { + tower.IsParticipatingInCombat = false; + } + + return true; + } + + public static void NormalizeParticipantState(BackpackInventoryData inventory, int maxCount) + { + if (inventory == null) + { + return; + } + + int resolvedMaxCount = Mathf.Max(1, maxCount); + inventory.ParticipantTowerInstanceIds ??= new List(); + Dictionary towerMap = new Dictionary(); + if (inventory.Towers != null) + { + for (int i = 0; i < inventory.Towers.Count; i++) + { + TowerItemData tower = inventory.Towers[i]; + if (tower == null || tower.InstanceId <= 0) + { + continue; + } + + tower.IsParticipatingInCombat = false; + towerMap[tower.InstanceId] = tower; + } + } + + HashSet uniqueIds = new HashSet(); + List normalizedIds = new List(inventory.ParticipantTowerInstanceIds.Count); + for (int i = 0; i < inventory.ParticipantTowerInstanceIds.Count; i++) + { + if (normalizedIds.Count >= resolvedMaxCount) + { + break; + } + + long towerId = inventory.ParticipantTowerInstanceIds[i]; + if (towerId <= 0 || !uniqueIds.Add(towerId)) + { + continue; + } + + if (!towerMap.TryGetValue(towerId, out TowerItemData tower)) + { + continue; + } + + tower.IsParticipatingInCombat = true; + normalizedIds.Add(towerId); + } + + inventory.ParticipantTowerInstanceIds = normalizedIds; + } + + public static bool TryGetTowerById(BackpackInventoryData inventory, long towerInstanceId, out TowerItemData tower) + { + tower = null; + if (inventory?.Towers == null || towerInstanceId <= 0) + { + return false; + } + + for (int i = 0; i < inventory.Towers.Count; i++) + { + TowerItemData candidate = inventory.Towers[i]; + if (candidate != null && candidate.InstanceId == towerInstanceId) + { + tower = candidate; + return true; + } + } + + return false; + } + } +} diff --git a/Assets/GameMain/Scripts/Utility/InventoryParticipantUtility.cs.meta b/Assets/GameMain/Scripts/Utility/InventoryParticipantUtility.cs.meta new file mode 100644 index 0000000..ed0ab62 --- /dev/null +++ b/Assets/GameMain/Scripts/Utility/InventoryParticipantUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 24bb2803b971d424aaba0cb472ead5d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameMain/Scripts/Utility/InventorySeedUtility.cs b/Assets/GameMain/Scripts/Utility/InventorySeedUtility.cs new file mode 100644 index 0000000..b4d7388 --- /dev/null +++ b/Assets/GameMain/Scripts/Utility/InventorySeedUtility.cs @@ -0,0 +1,190 @@ +using GeometryTD.Definition; + +namespace GeometryTD.CustomUtility +{ + public static class InventorySeedUtility + { + public static BackpackInventoryData CreateSampleInventory() + { + BackpackInventoryData inventory = new BackpackInventoryData + { + Gold = 500 + }; + + MuzzleCompItemData muzzle = new MuzzleCompItemData + { + InstanceId = 10001, + ConfigId = 1, + Name = "元素枪口", + Rarity = RarityType.Green, + Endurance = 90f, + IsAssembledIntoTower = true, + AttackDamage = new[] { 20, 30, 40, 50, 80 }, + DamageRandomRate = 0.05f, + AttackMethodType = AttackMethodType.NormalBullet, + Constraint = string.Empty, + Tags = new[] { TagType.Fire } + }; + inventory.MuzzleComponents.Add(muzzle); + inventory.MuzzleComponents.Add(new MuzzleCompItemData + { + InstanceId = 10002, + ConfigId = 2, + Name = "控制枪口", + Rarity = RarityType.Blue, + Endurance = 80, + IsAssembledIntoTower = false, + AttackDamage = new[] { 30, 50, 70, 90, 100 }, + DamageRandomRate = 0.01f, + AttackMethodType = AttackMethodType.NormalBullet, + Constraint = string.Empty, + Tags = new[] { TagType.Ice, TagType.FreezeMask } + }); + inventory.MuzzleComponents.Add(new MuzzleCompItemData + { + InstanceId = 10003, + ConfigId = 3, + Name = "穿透枪口", + Rarity = RarityType.Purple, + Endurance = 97f, + IsAssembledIntoTower = false, + AttackDamage = new[] { 50, 55, 60, 80, 90 }, + DamageRandomRate = 0.02f, + AttackMethodType = AttackMethodType.NormalBullet, + Constraint = string.Empty, + Tags = new[] { TagType.Pierce, TagType.Crit } + }); + + BearingCompItemData bearing = new BearingCompItemData + { + InstanceId = 20001, + ConfigId = 1, + Name = "元素轴承", + Rarity = RarityType.Green, + Endurance = 1f, + IsAssembledIntoTower = true, + RotateSpeed = new[] { 10f, 12f, 13f, 14f, 15f }, + AttackRange = new[] { 2f, 2f, 2f, 2f, 2f }, + Constraint = string.Empty, + Tags = new[] { TagType.Fire } + }; + inventory.BearingComponents.Add(bearing); + inventory.BearingComponents.Add(new BearingCompItemData + { + InstanceId = 20002, + ConfigId = 2, + Name = "控制轴承", + Rarity = RarityType.Blue, + Endurance = 20, + IsAssembledIntoTower = false, + RotateSpeed = new[] { 20f, 25f, 30f, 32f, 35f }, + AttackRange = new[] { 6f, 6.5f, 7f, 8f, 8f }, + Constraint = string.Empty, + Tags = new[] { TagType.Ice, TagType.Shatter } + }); + inventory.BearingComponents.Add(new BearingCompItemData + { + InstanceId = 20003, + ConfigId = 3, + Name = "穿透轴承", + Rarity = RarityType.Purple, + Endurance = 96f, + IsAssembledIntoTower = false, + RotateSpeed = new[] { 60f, 70f, 80f, 90f, 100f }, + AttackRange = new[] { 4f, 4.5f, 5f, 5.5f, 6f }, + Constraint = string.Empty, + Tags = new[] { TagType.Pierce, TagType.Overpenetrate } + }); + + BaseCompItemData baseComp = new BaseCompItemData + { + InstanceId = 30001, + ConfigId = 1, + Name = "元素底座", + Rarity = RarityType.Green, + Endurance = 88f, + IsAssembledIntoTower = true, + AttackSpeed = new[] { 2f, 1.5f, 1f, 0.8f, 0.7f }, + AttackPropertyType = AttackPropertyType.Fire, + Constraint = string.Empty, + Tags = new[] { TagType.Fire } + }; + inventory.BaseComponents.Add(baseComp); + inventory.BaseComponents.Add(new BaseCompItemData + { + InstanceId = 30002, + ConfigId = 2, + Name = "控制底座", + Rarity = RarityType.Blue, + Endurance = 50f, + IsAssembledIntoTower = false, + AttackSpeed = new[] { 4f, 4.2f, 4.4f, 4.6f, 4.8f }, + AttackPropertyType = AttackPropertyType.Ice, + Constraint = string.Empty, + Tags = new[] { TagType.Ice, TagType.AbsoluteZero } + }); + inventory.BaseComponents.Add(new BaseCompItemData + { + InstanceId = 30003, + ConfigId = 3, + Name = "穿透底座", + Rarity = RarityType.Purple, + Endurance = 30f, + IsAssembledIntoTower = false, + AttackSpeed = new[] { 1f, 1f, 1f, 1f, 1f }, + AttackPropertyType = AttackPropertyType.Physics, + Constraint = string.Empty, + Tags = new[] { TagType.Pierce, TagType.Execution } + }); + + TowerItemData tower = new TowerItemData + { + InstanceId = 90001, + Name = "测试防御塔-A", + Rarity = RarityType.Green, + IsParticipatingInCombat = true, + MuzzleComponentInstanceId = muzzle.InstanceId, + BearingComponentInstanceId = bearing.InstanceId, + BaseComponentInstanceId = baseComp.InstanceId, + Stats = new TowerStatsData + { + AttackDamage = new[] { 200, 220, 240, 260, 300 }, + DamageRandomRate = 0f, + RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f }, + AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f }, + AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f }, + AttackMethodType = AttackMethodType.NormalBullet, + AttackPropertyType = AttackPropertyType.Fire, + Tags = new[] { TagType.Fire, TagType.BurnSpread } + } + }; + inventory.Towers.Add(tower); + + inventory.Towers.Add(new TowerItemData + { + InstanceId = 90002, + Name = "测试防御塔-B", + Rarity = RarityType.Blue, + IsParticipatingInCombat = false, + MuzzleComponentInstanceId = 0, + BearingComponentInstanceId = 0, + BaseComponentInstanceId = 0, + Stats = new TowerStatsData + { + AttackDamage = new[] { 200, 220, 240, 260, 300 }, + DamageRandomRate = 0.1f, + RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f }, + AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f }, + AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f }, + AttackMethodType = AttackMethodType.NormalBullet, + AttackPropertyType = AttackPropertyType.Physics, + Tags = new[] { TagType.Pierce } + } + }); + + inventory.ParticipantTowerInstanceIds.Add(90001); + + return inventory; + } + } +} \ No newline at end of file diff --git a/Assets/GameMain/Scripts/Utility/InventorySeedUtility.cs.meta b/Assets/GameMain/Scripts/Utility/InventorySeedUtility.cs.meta new file mode 100644 index 0000000..8fbb11d --- /dev/null +++ b/Assets/GameMain/Scripts/Utility/InventorySeedUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f6a4b82844aa4417a949907fadd92bb7 +timeCreated: 1772632267 \ No newline at end of file