420 lines
16 KiB
C#
420 lines
16 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using GameFramework.DataTable;
|
|
using GeometryTD.CustomComponent;
|
|
using GeometryTD.DataTable;
|
|
using GeometryTD.Definition;
|
|
using NUnit.Framework;
|
|
using UnityEngine;
|
|
|
|
namespace GeometryTD.Tests.EditMode
|
|
{
|
|
public sealed class PlayerInventoryTowerAssemblyServiceTests
|
|
{
|
|
private GameObject _inventoryObject;
|
|
private PlayerInventoryComponent _originalPlayerInventory;
|
|
|
|
[TearDown]
|
|
public void TearDown()
|
|
{
|
|
SetStaticPlayerInventory(_originalPlayerInventory);
|
|
if (_inventoryObject != null)
|
|
{
|
|
UnityEngine.Object.DestroyImmediate(_inventoryObject);
|
|
_inventoryObject = null;
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void TryAssembleTower_Builds_Expected_Rarity_Stats_And_Tags()
|
|
{
|
|
PlayerInventoryComponent inventoryComponent = CreateBoundPlayerInventory(new BackpackInventoryData
|
|
{
|
|
MuzzleComponents =
|
|
{
|
|
new MuzzleCompItemData
|
|
{
|
|
InstanceId = 10001,
|
|
ConfigId = 1,
|
|
Name = "测试枪口",
|
|
Rarity = RarityType.Green,
|
|
AttackDamage = new[] { 10, 20, 30, 40, 50 },
|
|
DamageRandomRate = 0.15f,
|
|
AttackMethodType = AttackMethodType.NormalBullet,
|
|
Tags = new[] { TagType.Fire }
|
|
}
|
|
},
|
|
BearingComponents =
|
|
{
|
|
new BearingCompItemData
|
|
{
|
|
InstanceId = 20001,
|
|
ConfigId = 1,
|
|
Name = "测试轴承",
|
|
Rarity = RarityType.Blue,
|
|
RotateSpeed = new[] { 1f, 2f, 3f, 4f, 5f },
|
|
AttackRange = new[] { 10f, 20f, 30f, 40f, 50f },
|
|
Tags = new[] { TagType.Ice }
|
|
}
|
|
},
|
|
BaseComponents =
|
|
{
|
|
new BaseCompItemData
|
|
{
|
|
InstanceId = 30001,
|
|
ConfigId = 1,
|
|
Name = "测试底座",
|
|
Rarity = RarityType.Purple,
|
|
AttackSpeed = new[] { 2f, 4f, 6f, 8f, 10f },
|
|
AttackPropertyType = AttackPropertyType.Fire,
|
|
Tags = new[] { TagType.Fire }
|
|
}
|
|
}
|
|
});
|
|
InjectAssemblyTables(
|
|
inventoryComponent,
|
|
new FakeDataTable<DRMuzzleComp>(CreateMuzzleRow()),
|
|
new FakeDataTable<DRBearingComp>(CreateBearingRow()),
|
|
new FakeDataTable<DRBaseComp>(CreateBaseRow()));
|
|
|
|
bool assembled = inventoryComponent.TryAssembleTower(10001, 20001, 30001, out TowerItemData tower);
|
|
BackpackInventoryData committedInventory = inventoryComponent.GetInventorySnapshot();
|
|
|
|
Assert.That(assembled, Is.True);
|
|
Assert.That(tower, Is.Not.Null);
|
|
Assert.That(tower.Rarity, Is.EqualTo(RarityType.Blue));
|
|
Assert.That(tower.Stats.AttackDamage, Is.EqualTo(new[] { 20, 23, 26, 29, 32 }));
|
|
Assert.That(tower.Stats.RotateSpeed, Is.EqualTo(new[] { 3f, 3.5f, 4f, 4.5f, 5f }));
|
|
Assert.That(tower.Stats.AttackRange, Is.EqualTo(new[] { 30f, 31f, 32f, 33f, 34f }));
|
|
Assert.That(tower.Stats.AttackSpeed, Is.EqualTo(new[] { 8f, 7.75f, 7.5f, 7.25f, 7f }));
|
|
Assert.That(tower.Stats.DamageRandomRate, Is.EqualTo(0.15f));
|
|
Assert.That(tower.Stats.AttackMethodType, Is.EqualTo(AttackMethodType.NormalBullet));
|
|
Assert.That(tower.Stats.AttackPropertyType, Is.EqualTo(AttackPropertyType.Fire));
|
|
Assert.That(tower.Stats.Tags, Is.EqualTo(new[] { TagType.Fire, TagType.Ice }));
|
|
Assert.That(tower.Stats.TagRuntimes, Has.Length.EqualTo(2));
|
|
Assert.That(tower.Stats.TagRuntimes[0].TagType, Is.EqualTo(TagType.Fire));
|
|
Assert.That(tower.Stats.TagRuntimes[0].TotalStack, Is.EqualTo(2));
|
|
Assert.That(tower.Stats.TagRuntimes[1].TagType, Is.EqualTo(TagType.Ice));
|
|
Assert.That(tower.Stats.TagRuntimes[1].TotalStack, Is.EqualTo(1));
|
|
Assert.That(committedInventory.Towers, Has.Count.EqualTo(1));
|
|
Assert.That(committedInventory.MuzzleComponents[0].IsAssembledIntoTower, Is.True);
|
|
Assert.That(committedInventory.BearingComponents[0].IsAssembledIntoTower, Is.True);
|
|
Assert.That(committedInventory.BaseComponents[0].IsAssembledIntoTower, Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public void TryAssembleTower_Returns_False_When_Required_Config_Row_Is_Missing()
|
|
{
|
|
PlayerInventoryComponent inventoryComponent = CreateBoundPlayerInventory(new BackpackInventoryData
|
|
{
|
|
MuzzleComponents =
|
|
{
|
|
new MuzzleCompItemData
|
|
{
|
|
InstanceId = 10001,
|
|
ConfigId = 1,
|
|
Rarity = RarityType.White,
|
|
AttackDamage = new[] { 10, 20, 30, 40, 50 },
|
|
AttackMethodType = AttackMethodType.NormalBullet
|
|
}
|
|
},
|
|
BearingComponents =
|
|
{
|
|
new BearingCompItemData
|
|
{
|
|
InstanceId = 20001,
|
|
ConfigId = 1,
|
|
Rarity = RarityType.White,
|
|
RotateSpeed = new[] { 1f, 2f, 3f, 4f, 5f },
|
|
AttackRange = new[] { 1f, 2f, 3f, 4f, 5f }
|
|
}
|
|
},
|
|
BaseComponents =
|
|
{
|
|
new BaseCompItemData
|
|
{
|
|
InstanceId = 30001,
|
|
ConfigId = 999,
|
|
Rarity = RarityType.White,
|
|
AttackSpeed = new[] { 1f, 2f, 3f, 4f, 5f },
|
|
AttackPropertyType = AttackPropertyType.Physics
|
|
}
|
|
}
|
|
});
|
|
InjectAssemblyTables(
|
|
inventoryComponent,
|
|
new FakeDataTable<DRMuzzleComp>(CreateMuzzleRow()),
|
|
new FakeDataTable<DRBearingComp>(CreateBearingRow()),
|
|
new FakeDataTable<DRBaseComp>(CreateBaseRow()));
|
|
|
|
bool assembled = inventoryComponent.TryAssembleTower(10001, 20001, 30001, out TowerItemData tower);
|
|
BackpackInventoryData committedInventory = inventoryComponent.GetInventorySnapshot();
|
|
|
|
Assert.That(assembled, Is.False);
|
|
Assert.That(tower, Is.Null);
|
|
Assert.That(committedInventory.Towers, Has.Count.EqualTo(0));
|
|
Assert.That(committedInventory.MuzzleComponents[0].IsAssembledIntoTower, Is.False);
|
|
Assert.That(committedInventory.BearingComponents[0].IsAssembledIntoTower, Is.False);
|
|
Assert.That(committedInventory.BaseComponents[0].IsAssembledIntoTower, Is.False);
|
|
}
|
|
|
|
private PlayerInventoryComponent CreateBoundPlayerInventory(BackpackInventoryData inventory)
|
|
{
|
|
_originalPlayerInventory = GameEntry.PlayerInventory;
|
|
_inventoryObject = new GameObject("TestPlayerInventory");
|
|
PlayerInventoryComponent inventoryComponent = _inventoryObject.AddComponent<PlayerInventoryComponent>();
|
|
SetStaticPlayerInventory(inventoryComponent);
|
|
inventoryComponent.ReplaceInventorySnapshot(inventory);
|
|
return inventoryComponent;
|
|
}
|
|
|
|
private static void SetStaticPlayerInventory(PlayerInventoryComponent inventoryComponent)
|
|
{
|
|
FieldInfo backingField = typeof(GameEntry).GetField(
|
|
"<PlayerInventory>k__BackingField",
|
|
BindingFlags.Static | BindingFlags.NonPublic);
|
|
Assert.That(backingField, Is.Not.Null);
|
|
backingField.SetValue(null, inventoryComponent);
|
|
}
|
|
|
|
private static void InjectAssemblyTables(
|
|
PlayerInventoryComponent inventoryComponent,
|
|
IDataTable<DRMuzzleComp> muzzleTable,
|
|
IDataTable<DRBearingComp> bearingTable,
|
|
IDataTable<DRBaseComp> baseTable)
|
|
{
|
|
FieldInfo serviceField = typeof(PlayerInventoryComponent).GetField(
|
|
"_towerAssemblyService",
|
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
|
Assert.That(serviceField, Is.Not.Null);
|
|
object assemblyService = serviceField.GetValue(inventoryComponent);
|
|
Assert.That(assemblyService, Is.Not.Null);
|
|
|
|
SetPrivateField(assemblyService, "_drMuzzleComp", muzzleTable);
|
|
SetPrivateField(assemblyService, "_drBearingComp", bearingTable);
|
|
SetPrivateField(assemblyService, "_drBaseComp", baseTable);
|
|
}
|
|
|
|
private static void SetPrivateField(object instance, string fieldName, object value)
|
|
{
|
|
FieldInfo field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
|
|
Assert.That(field, Is.Not.Null);
|
|
field.SetValue(instance, value);
|
|
}
|
|
|
|
private static DRMuzzleComp CreateMuzzleRow()
|
|
{
|
|
DRMuzzleComp row = new DRMuzzleComp();
|
|
Assert.That(row.ParseDataRow("\t1\t\t测试枪口\t[10,20,30,40,50]\t3\t0.15\tNormalBullet\t\t[Fire]", null), Is.True);
|
|
return row;
|
|
}
|
|
|
|
private static DRBearingComp CreateBearingRow()
|
|
{
|
|
DRBearingComp row = new DRBearingComp();
|
|
Assert.That(row.ParseDataRow("\t1\t\t测试轴承\t[1,2,3,4,5]\t0.5\t[10,20,30,40,50]\t1\t\t[Ice]", null), Is.True);
|
|
return row;
|
|
}
|
|
|
|
private static DRBaseComp CreateBaseRow()
|
|
{
|
|
DRBaseComp row = new DRBaseComp();
|
|
Assert.That(row.ParseDataRow("\t1\t\t测试底座\t[2,4,6,8,10]\t-0.25\tFire\t\t[Fire]", 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)
|
|
{
|
|
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 => _rowsById.Count <= 0 ? null : GetDataRow(GetOrderedIds()[0]);
|
|
|
|
public TRow MaxIdDataRow => _rowsById.Count <= 0 ? null : GetDataRow(GetOrderedIds()[^1]);
|
|
|
|
public bool HasDataRow(int id)
|
|
{
|
|
return _rowsById.ContainsKey(id);
|
|
}
|
|
|
|
public bool HasDataRow(Predicate<TRow> condition)
|
|
{
|
|
return GetDataRow(condition) != null;
|
|
}
|
|
|
|
public TRow GetDataRow(int id)
|
|
{
|
|
return _rowsById.TryGetValue(id, out TRow row) ? row : null;
|
|
}
|
|
|
|
public TRow GetDataRow(Predicate<TRow> condition)
|
|
{
|
|
if (condition == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
foreach (TRow row in _rowsById.Values)
|
|
{
|
|
if (row != 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)
|
|
{
|
|
return _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;
|
|
}
|
|
}
|
|
}
|
|
}
|