修复已知问题
This commit is contained in:
@@ -183,11 +183,15 @@ namespace GeometryTD.Tests.EditMode
|
||||
CreateBoundPlayerInventory(CreateInventory(100f, 100f, 100f));
|
||||
CombatSettlementContext settlementContext = new CombatSettlementContext();
|
||||
settlementContext.Flags.ShouldOpenRewardSelection = true;
|
||||
int nextRewardOrdinal = 0;
|
||||
|
||||
bool prepared = new CombatSettlementService().TryPrepareRewardSelection(
|
||||
settlementContext,
|
||||
displayPhaseIndex: 1,
|
||||
themeType: LevelThemeType.Plain,
|
||||
runSeed: 1001,
|
||||
sequenceIndex: 3,
|
||||
ref nextRewardOrdinal,
|
||||
rewardSelectFormUseCase: null,
|
||||
onRewardSelected: _ => { },
|
||||
onGiveUp: null);
|
||||
|
||||
@@ -110,7 +110,43 @@ namespace GeometryTD.Tests.EditMode
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RewardSelectFormUseCase_Uses_Stable_Order_And_Deterministic_Refresh_Rotation()
|
||||
public void DropPoolRoller_Is_Reproducible_When_DropPool_Row_Order_Changes()
|
||||
{
|
||||
DROutGameDropPool whiteRow = CreateDropPoolRow(1, "MuzzleComp", 1, "[100,0,0,0,0]");
|
||||
DROutGameDropPool greenRow = CreateDropPoolRow(2, "BearingComp", 1, "[0,100,0,0,0]");
|
||||
DROutGameDropPool blueRow = CreateDropPoolRow(3, "BaseComp", 1, "[0,0,100,0,0]");
|
||||
DROutGameDropPool purpleRow = CreateDropPoolRow(4, "MuzzleComp", 2, "[0,0,0,100,0]");
|
||||
DROutGameDropPool redRow = CreateDropPoolRow(5, "BearingComp", 2, "[0,0,0,0,100]");
|
||||
|
||||
DropPoolRoller forwardOrderRoller = new DropPoolRoller(
|
||||
new InsertionOrderDataTable<DROutGameDropPool>(whiteRow, greenRow, blueRow, purpleRow, redRow));
|
||||
DropPoolRoller reverseOrderRoller = new DropPoolRoller(
|
||||
new InsertionOrderDataTable<DROutGameDropPool>(redRow, purpleRow, blueRow, greenRow, whiteRow));
|
||||
|
||||
for (int seed = 1; seed <= 64; seed++)
|
||||
{
|
||||
bool forwardRolled = forwardOrderRoller.TryRollRow(
|
||||
8,
|
||||
LevelThemeType.Plain,
|
||||
new System.Random(seed),
|
||||
out DROutGameDropPool forwardRow,
|
||||
out RarityType forwardRarity);
|
||||
bool reverseRolled = reverseOrderRoller.TryRollRow(
|
||||
8,
|
||||
LevelThemeType.Plain,
|
||||
new System.Random(seed),
|
||||
out DROutGameDropPool reverseRow,
|
||||
out RarityType reverseRarity);
|
||||
|
||||
Assert.That(forwardRolled, Is.True, $"seed={seed}");
|
||||
Assert.That(reverseRolled, Is.True, $"seed={seed}");
|
||||
Assert.That(reverseRarity, Is.EqualTo(forwardRarity), $"seed={seed}");
|
||||
Assert.That(reverseRow.Id, Is.EqualTo(forwardRow.Id), $"seed={seed}");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RewardSelectFormUseCase_Uses_Stable_Order_And_Deterministic_Selection_Rotation()
|
||||
{
|
||||
RewardSelectFormUseCase useCase = new RewardSelectFormUseCase();
|
||||
useCase.ConfigureRewardPool(
|
||||
@@ -123,11 +159,11 @@ namespace GeometryTD.Tests.EditMode
|
||||
},
|
||||
displayCount: 3,
|
||||
refreshCost: 0,
|
||||
allowRefreshOnce: true,
|
||||
allowRotateOnce: true,
|
||||
allowGiveUp: false);
|
||||
|
||||
RewardSelectFormRawData initialModel = useCase.CreateInitialModel();
|
||||
RewardSelectFormRawData refreshedModel = useCase.TryRefresh();
|
||||
RewardSelectFormRawData refreshedModel = useCase.TryRotateSelection();
|
||||
|
||||
Assert.That(initialModel.RewardItems.Select(item => item.Title).ToArray(), Is.EqualTo(new[] { "一号", "二号", "三号" }));
|
||||
Assert.That(refreshedModel.RewardItems.Select(item => item.Title).ToArray(), Is.EqualTo(new[] { "四号", "一号", "二号" }));
|
||||
@@ -141,15 +177,25 @@ namespace GeometryTD.Tests.EditMode
|
||||
|
||||
private string BuildEnemyDropSignature(int runSeed, int sequenceIndex)
|
||||
{
|
||||
_component.ConfigureRunContext(runSeed, sequenceIndex);
|
||||
EnemyDropResult result = _component.ResolveEnemyDrop(new EnemyDropContext(CreateEnemyRow(), 8, LevelThemeType.Plain));
|
||||
int nextDropOrdinal = 0;
|
||||
EnemyDropResult result = _component.ResolveEnemyDrop(
|
||||
new EnemyDropContext(CreateEnemyRow(), 8, LevelThemeType.Plain),
|
||||
runSeed,
|
||||
sequenceIndex,
|
||||
ref nextDropOrdinal);
|
||||
return BuildDropSignaturePart(result);
|
||||
}
|
||||
|
||||
private string BuildRewardCandidateSignature(int runSeed, int sequenceIndex)
|
||||
{
|
||||
_component.ConfigureRunContext(runSeed, sequenceIndex);
|
||||
IReadOnlyList<TowerCompItemData> candidates = _component.BuildRewardCandidates(8, LevelThemeType.Plain, 3);
|
||||
int nextRewardOrdinal = 0;
|
||||
IReadOnlyList<TowerCompItemData> candidates = _component.BuildRewardCandidates(
|
||||
8,
|
||||
LevelThemeType.Plain,
|
||||
3,
|
||||
runSeed,
|
||||
sequenceIndex,
|
||||
ref nextRewardOrdinal);
|
||||
return string.Join("|", candidates.Select(BuildItemSignaturePart));
|
||||
}
|
||||
|
||||
@@ -433,5 +479,185 @@ namespace GeometryTD.Tests.EditMode
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class InsertionOrderDataTable<TRow> : IDataTable<TRow> where TRow : class, IDataRow
|
||||
{
|
||||
private readonly List<TRow> _rows = new();
|
||||
private readonly Dictionary<int, TRow> _rowsById = new();
|
||||
|
||||
public InsertionOrderDataTable(params TRow[] rows)
|
||||
{
|
||||
if (rows == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < rows.Length; i++)
|
||||
{
|
||||
TRow row = rows[i];
|
||||
if (row == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_rows.Add(row);
|
||||
_rowsById[row.Id] = row;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name => typeof(TRow).Name;
|
||||
public string FullName => typeof(TRow).FullName;
|
||||
public Type Type => typeof(TRow);
|
||||
public int Count => _rows.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) => _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)
|
||||
{
|
||||
if (condition == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _rows.Count; i++)
|
||||
{
|
||||
TRow row = _rows[i];
|
||||
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;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _rows.Count; i++)
|
||||
{
|
||||
TRow row = _rows[i];
|
||||
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(_rows);
|
||||
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;
|
||||
}
|
||||
|
||||
results.AddRange(_rows);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!_rowsById.TryGetValue(id, out TRow row))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_rowsById.Remove(id);
|
||||
return _rows.Remove(row);
|
||||
}
|
||||
|
||||
public void RemoveAllDataRows()
|
||||
{
|
||||
_rows.Clear();
|
||||
_rowsById.Clear();
|
||||
}
|
||||
|
||||
public IEnumerator<TRow> GetEnumerator()
|
||||
{
|
||||
for (int i = 0; i < _rows.Count; i++)
|
||||
{
|
||||
yield return _rows[i];
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
private int[] GetOrderedIds()
|
||||
{
|
||||
int[] ids = _rowsById.Keys.ToArray();
|
||||
Array.Sort(ids);
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user