using System; using System.Collections; using System.Collections.Generic; using GameFramework.DataTable; using GeometryTD.CustomComponent; using GeometryTD.DataTable; using GeometryTD.Definition; using NUnit.Framework; namespace GeometryTD.Tests.EditMode { public sealed class PlayerInventoryTradeServiceTests { [Test] public void TrySellItems_Sells_Selected_Component_And_Tower_Atomically() { BackpackInventoryData inventory = CreateInventory(); PlayerInventoryState state = new PlayerInventoryState(); PlayerInventoryQueryModel queryModel = new PlayerInventoryQueryModel(state); PlayerInventoryCommandModel commandModel = new PlayerInventoryCommandModel(state); commandModel.Initialize(inventory, maxParticipantTowerCount: 4); PlayerInventoryTradeService tradeService = new PlayerInventoryTradeService( queryModel, commandModel, CreatePriceTable( CreateShopPriceRow(1, RarityType.Blue, 30, 34), CreateShopPriceRow(2, RarityType.Purple, 60, 64))); bool success = tradeService.TrySellItems(new long[] { 101, 201 }, out PlayerInventorySaleResult result); Assert.That(success, Is.True); Assert.That(result, Is.Not.Null); Assert.That(result.IsSuccess, Is.True); Assert.That(result.SoldComponentCount, Is.EqualTo(1)); Assert.That(result.SoldTowerCount, Is.EqualTo(1)); Assert.That(queryModel.Inventory.Gold, Is.EqualTo(138)); Assert.That(queryModel.Inventory.MuzzleComponents.Exists(item => item.InstanceId == 101), Is.False); Assert.That(queryModel.Inventory.Towers.Exists(item => item.InstanceId == 201), Is.False); Assert.That(queryModel.Inventory.MuzzleComponents.Exists(item => item.InstanceId == 202), Is.False); Assert.That(queryModel.Inventory.BearingComponents.Exists(item => item.InstanceId == 203), Is.False); Assert.That(queryModel.Inventory.BaseComponents.Exists(item => item.InstanceId == 204), Is.False); } [Test] public void TryGetSaleCandidate_Rejects_Participant_Tower() { BackpackInventoryData inventory = CreateInventory(); inventory.ParticipantTowerInstanceIds.Add(201); PlayerInventoryState state = new PlayerInventoryState(); PlayerInventoryQueryModel queryModel = new PlayerInventoryQueryModel(state); PlayerInventoryCommandModel commandModel = new PlayerInventoryCommandModel(state); commandModel.Initialize(inventory, maxParticipantTowerCount: 4); PlayerInventoryTradeService tradeService = new PlayerInventoryTradeService( queryModel, commandModel, CreatePriceTable(CreateShopPriceRow(1, RarityType.Blue, 30, 34))); bool resolved = tradeService.TryGetSaleCandidate(201, out PlayerInventorySaleCandidate candidate); Assert.That(resolved, Is.True); Assert.That(candidate, Is.Not.Null); Assert.That(candidate.IsSellable, Is.False); Assert.That(candidate.FailureReason, Is.EqualTo(PlayerInventorySaleFailureReason.ParticipantTower)); } private static BackpackInventoryData CreateInventory() { BackpackInventoryData inventory = new BackpackInventoryData { Gold = 10 }; inventory.MuzzleComponents.Add(new MuzzleCompItemData { InstanceId = 101, ConfigId = 1, Name = "Loose Muzzle", Rarity = RarityType.Blue, Endurance = 100f, IsAssembledIntoTower = false }); inventory.MuzzleComponents.Add(new MuzzleCompItemData { InstanceId = 202, ConfigId = 2, Name = "Tower Muzzle", Rarity = RarityType.Blue, Endurance = 100f, IsAssembledIntoTower = true }); inventory.BearingComponents.Add(new BearingCompItemData { InstanceId = 203, ConfigId = 3, Name = "Tower Bearing", Rarity = RarityType.Blue, Endurance = 100f, IsAssembledIntoTower = true }); inventory.BaseComponents.Add(new BaseCompItemData { InstanceId = 204, ConfigId = 4, Name = "Tower Base", Rarity = RarityType.Blue, Endurance = 100f, IsAssembledIntoTower = true }); inventory.Towers.Add(new TowerItemData { InstanceId = 201, Name = "Tower #201", Rarity = RarityType.Blue, MuzzleComponentInstanceId = 202, BearingComponentInstanceId = 203, BaseComponentInstanceId = 204 }); return inventory; } private static IDataTable CreatePriceTable(params DRShopPrice[] rows) { return new FakeDataTable(rows); } private static DRShopPrice CreateShopPriceRow(int id, RarityType rarity, int minPrice, int maxPrice) { DRShopPrice row = new DRShopPrice(); Assert.That(row.ParseDataRow($"\t{id}\t\t{rarity}\t{minPrice}\t{maxPrice}", null), Is.True); return row; } private sealed class FakeDataTable : IDataTable where TRow : class, IDataRow { private readonly Dictionary _rowsById = new(); public FakeDataTable(params TRow[] rows) { if (rows == null) { return; } for (int i = 0; i < rows.Length; i++) { TRow row = rows[i]; if (row != null) { _rowsById[row.Id] = row; } } } public string Name => typeof(TRow).Name; public string FullName => typeof(TRow).FullName; public Type Type => typeof(TRow); public int Count => _rowsById.Count; public TRow this[int id] => GetDataRow(id); public TRow MinIdDataRow => null; public TRow MaxIdDataRow => null; public bool HasDataRow(int id) => _rowsById.ContainsKey(id); public bool HasDataRow(Predicate condition) => GetDataRow(condition) != null; public TRow GetDataRow(int id) => _rowsById.TryGetValue(id, out TRow row) ? row : null; public TRow GetDataRow(Predicate condition) { foreach (TRow row in _rowsById.Values) { if (row != null && condition != null && condition(row)) { return row; } } return null; } public TRow[] GetDataRows(Predicate condition) { List results = new(); GetDataRows(condition, results); return results.ToArray(); } public void GetDataRows(Predicate condition, List results) { results?.Clear(); if (condition == null || results == null) { return; } foreach (TRow row in _rowsById.Values) { if (row != null && condition(row)) { results.Add(row); } } } public TRow[] GetDataRows(Comparison comparison) { List results = new(); GetDataRows(comparison, results); return results.ToArray(); } public void GetDataRows(Comparison comparison, List results) { results?.Clear(); if (results == null) { return; } results.AddRange(_rowsById.Values); if (comparison != null) { results.Sort(comparison); } } public TRow[] GetDataRows(Predicate condition, Comparison comparison) { List results = new(); GetDataRows(condition, comparison, results); return results.ToArray(); } public void GetDataRows(Predicate condition, Comparison comparison, List results) { GetDataRows(condition, results); if (results != null && comparison != null) { results.Sort(comparison); } } public TRow[] GetAllDataRows() { List results = new(); GetAllDataRows(results); return results.ToArray(); } public void GetAllDataRows(List results) { results?.Clear(); if (results == null) { return; } foreach (int id in GetOrderedIds()) { results.Add(_rowsById[id]); } } public bool AddDataRow(string dataRowString, object userData) => throw new NotSupportedException(); public bool AddDataRow(byte[] dataRowBytes, int startIndex, int length, object userData) => throw new NotSupportedException(); public bool RemoveDataRow(int id) => _rowsById.Remove(id); public void RemoveAllDataRows() { _rowsById.Clear(); } public IEnumerator GetEnumerator() { foreach (int id in GetOrderedIds()) { yield return _rowsById[id]; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private int[] GetOrderedIds() { int[] ids = new int[_rowsById.Count]; _rowsById.Keys.CopyTo(ids, 0); Array.Sort(ids); return ids; } } } }