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 void ReplaceInventorySnapshot(BackpackInventoryData sourceInventory, int maxParticipantTowerCount) { Initialize(sourceInventory, maxParticipantTowerCount); } 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); } } }