为 RepoForm 添加出售功能,ShopNode 只承载玩家购买组件的逻辑
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
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<DRShopPrice> CreatePriceTable(params DRShopPrice[] rows)
|
||||
{
|
||||
return new FakeDataTable<DRShopPrice>(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<TRow> : IDataTable<TRow> where TRow : class, IDataRow
|
||||
{
|
||||
private readonly Dictionary<int, TRow> _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<TRow> condition) => GetDataRow(condition) != null;
|
||||
public TRow GetDataRow(int id) => _rowsById.TryGetValue(id, out TRow row) ? row : null;
|
||||
|
||||
public TRow GetDataRow(Predicate<TRow> condition)
|
||||
{
|
||||
foreach (TRow row in _rowsById.Values)
|
||||
{
|
||||
if (row != null && condition != null && condition(row))
|
||||
{
|
||||
return row;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public TRow[] GetDataRows(Predicate<TRow> condition)
|
||||
{
|
||||
List<TRow> results = new();
|
||||
GetDataRows(condition, results);
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
public void GetDataRows(Predicate<TRow> condition, List<TRow> 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<TRow> comparison)
|
||||
{
|
||||
List<TRow> results = new();
|
||||
GetDataRows(comparison, results);
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
public void GetDataRows(Comparison<TRow> comparison, List<TRow> results)
|
||||
{
|
||||
results?.Clear();
|
||||
if (results == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
results.AddRange(_rowsById.Values);
|
||||
if (comparison != null)
|
||||
{
|
||||
results.Sort(comparison);
|
||||
}
|
||||
}
|
||||
|
||||
public TRow[] GetDataRows(Predicate<TRow> condition, Comparison<TRow> comparison)
|
||||
{
|
||||
List<TRow> results = new();
|
||||
GetDataRows(condition, comparison, results);
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
public void GetDataRows(Predicate<TRow> condition, Comparison<TRow> comparison, List<TRow> results)
|
||||
{
|
||||
GetDataRows(condition, results);
|
||||
if (results != null && comparison != null)
|
||||
{
|
||||
results.Sort(comparison);
|
||||
}
|
||||
}
|
||||
|
||||
public TRow[] GetAllDataRows()
|
||||
{
|
||||
List<TRow> results = new();
|
||||
GetAllDataRows(results);
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
public void GetAllDataRows(List<TRow> 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<TRow> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eae86223cf354e758fad4be62efd678d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user