S7-01 + S7-02

This commit is contained in:
2026-03-12 10:46:11 +08:00
parent d34af661b9
commit 185ea43323
20 changed files with 468 additions and 112 deletions
@@ -55,31 +55,44 @@ namespace GeometryTD.Tests.EditMode
TagType[] first = ComponentTagGenerationService.ResolveComponentTags(
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter },
RarityType.Blue,
InventoryTagSourceType.Shop,
12345,
7,
InventoryTagRandomContext.CreateShop(1001, 2, 0, 7),
RulesByTag);
TagType[] second = ComponentTagGenerationService.ResolveComponentTags(
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter },
RarityType.Blue,
InventoryTagSourceType.Shop,
12345,
7,
InventoryTagRandomContext.CreateShop(1001, 2, 0, 7),
RulesByTag);
Assert.That(second, Is.EqualTo(first));
}
[Test]
public void ResolveComponentTags_Distinguishes_Different_RunSeed_With_Same_Other_Context()
{
TagType[] first = ComponentTagGenerationService.ResolveComponentTags(
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter, TagType.Inferno, TagType.Execution },
RarityType.Purple,
InventoryTagRandomContext.CreateDrop(1001, 3, 0, 7),
RulesByTag,
RarityTagBudgetRulesByRarity);
TagType[] second = ComponentTagGenerationService.ResolveComponentTags(
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter, TagType.Inferno, TagType.Execution },
RarityType.Purple,
InventoryTagRandomContext.CreateDrop(2002, 3, 0, 7),
RulesByTag,
RarityTagBudgetRulesByRarity);
Assert.That(second, Is.Not.EqualTo(first));
}
[Test]
public void ResolveComponentTags_Uses_Purple_Budget_And_Does_Not_Repeat()
{
TagType[] result = ComponentTagGenerationService.ResolveComponentTags(
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter, TagType.Inferno, TagType.Execution },
RarityType.Purple,
InventoryTagSourceType.Drop,
9001,
4,
InventoryTagRandomContext.CreateDrop(1001, 1, 0, 4),
RulesByTag,
RarityTagBudgetRulesByRarity);
@@ -93,9 +106,7 @@ namespace GeometryTD.Tests.EditMode
TagType[] result = ComponentTagGenerationService.ResolveComponentTags(
new[] { TagType.Fire, TagType.BurnSpread },
RarityType.Red,
InventoryTagSourceType.Seed,
42,
1,
InventoryTagRandomContext.CreateSeed(1001, 42, 1),
RulesByTag,
RarityTagBudgetRulesByRarity);
@@ -116,9 +127,7 @@ namespace GeometryTD.Tests.EditMode
TagType[] result = ComponentTagGenerationService.ResolveComponentTags(
new[] { TagType.Fire, TagType.Ice, TagType.Crit },
RarityType.Green,
InventoryTagSourceType.Shop,
1,
1,
InventoryTagRandomContext.CreateShop(1001, 0, 0, 1),
weightedRules,
RarityTagBudgetRulesByRarity);
@@ -144,9 +153,7 @@ namespace GeometryTD.Tests.EditMode
TagType[] result = ComponentTagGenerationService.ResolveComponentTags(
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter },
RarityType.Green,
InventoryTagSourceType.Shop,
1000 + i,
1,
InventoryTagRandomContext.CreateShop(1001 + i, 0, 0, 1),
weightedRules,
RarityTagBudgetRulesByRarity);
@@ -189,6 +196,46 @@ namespace GeometryTD.Tests.EditMode
Assert.That(absoluteZeroRule.Weight, Is.EqualTo(1));
}
[Test]
public void GetEligibleTags_Uses_Final_TagDefinition_State_When_TagConfig_Loads_First()
{
DRTagConfig fireConfigRow = CreateFireConfigRow();
DRTag fireTagRow = CreateFireDisabledRow();
TagDefinitionRegistry.ReloadFromRows(new[] { fireConfigRow }, null);
TagDefinitionRegistry.ReloadFromRows(new[] { fireConfigRow }, new[] { fireTagRow });
TagType[] result = ComponentTagGenerationService.GetEligibleTags(
new[] { TagType.Fire, TagType.Ice },
RarityType.White,
RulesByTag);
Assert.That(result, Is.EqualTo(new[] { TagType.Ice }));
TagDefinitionRegistry.ResetToDefaults();
}
[Test]
public void ResolveComponentTags_Uses_Final_TagDefinition_State_When_Tag_Loads_First()
{
DRTagConfig fireConfigRow = CreateFireConfigRow();
DRTag fireTagRow = CreateFireDisabledRow();
TagDefinitionRegistry.ReloadFromRows(null, new[] { fireTagRow });
TagDefinitionRegistry.ReloadFromRows(new[] { fireConfigRow }, new[] { fireTagRow });
TagType[] result = ComponentTagGenerationService.ResolveComponentTags(
new[] { TagType.Fire, TagType.Ice },
RarityType.Green,
InventoryTagRandomContext.CreateShop(1001, 0, 0, 11),
RulesByTag,
RarityTagBudgetRulesByRarity);
Assert.That(result, Is.EqualTo(new[] { TagType.Ice }));
TagDefinitionRegistry.ResetToDefaults();
}
[Test]
public void ResolveRarityTagBudget_Uses_TableDriven_Range_Rules()
{
@@ -227,9 +274,7 @@ namespace GeometryTD.Tests.EditMode
TagType[] result = ComponentTagGenerationService.ResolveComponentTags(
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter, TagType.Inferno, TagType.Execution },
RarityType.Purple,
InventoryTagSourceType.Drop,
99,
7,
InventoryTagRandomContext.CreateDrop(1001, 1, 0, 7),
RulesByTag,
customBudgetRules);
@@ -277,7 +322,7 @@ namespace GeometryTD.Tests.EditMode
[Test]
public void CreateSampleInventory_Generates_SeedTags_Within_Launch_Set_And_Matches_Tower_Stats()
{
BackpackInventoryData inventory = InventorySeedUtility.CreateSampleInventory();
BackpackInventoryData inventory = InventorySeedUtility.CreateSampleInventory(1001);
TowerItemData tower = inventory.Towers[0];
MuzzleCompItemData muzzle = inventory.MuzzleComponents[0];
BearingCompItemData bearing = inventory.BearingComponents[0];
@@ -291,5 +336,44 @@ namespace GeometryTD.Tests.EditMode
Assert.That(tower.Stats.TagRuntimes[0].TotalStack, Is.EqualTo(3));
Assert.That(tower.Stats.Tags, Is.EqualTo(new[] { TagType.Fire }));
}
[Test]
public void CreateSampleInventory_Is_Deterministic_For_Same_RunSeed()
{
BackpackInventoryData first = InventorySeedUtility.CreateSampleInventory(1001);
BackpackInventoryData second = InventorySeedUtility.CreateSampleInventory(1001);
Assert.That(first.MuzzleComponents[1].Tags, Is.EqualTo(second.MuzzleComponents[1].Tags));
Assert.That(first.BearingComponents[1].Tags, Is.EqualTo(second.BearingComponents[1].Tags));
Assert.That(first.BaseComponents[1].Tags, Is.EqualTo(second.BaseComponents[1].Tags));
}
[Test]
public void InventoryTagRandomContext_Composes_Stable_Local_InstanceIds_Per_Source()
{
InventoryTagRandomContext shop = InventoryTagRandomContext.CreateShop(1001, 2, 1, 7);
InventoryTagRandomContext drop = InventoryTagRandomContext.CreateDrop(1001, 2, 1, 7);
InventoryTagRandomContext reward = InventoryTagRandomContext.CreateReward(1001, 2, 1, 7);
Assert.That(shop.ItemInstanceId, Is.EqualTo(InventoryTagRandomContext.ComposeLocalItemInstanceId(2, 1)));
Assert.That(drop.ItemInstanceId, Is.EqualTo(reward.ItemInstanceId));
Assert.That(shop.SourceType, Is.EqualTo(InventoryTagSourceType.Shop));
Assert.That(drop.SourceType, Is.EqualTo(InventoryTagSourceType.Drop));
Assert.That(reward.SourceType, Is.EqualTo(InventoryTagSourceType.Reward));
}
private static DRTagConfig CreateFireConfigRow()
{
DRTagConfig row = new DRTagConfig();
Assert.That(row.ParseDataRow("\t1\t元素\tFire\tOnAfterHit\t火焰测试描述\t{\"BurnDurationSeconds\":4,\"BurnDamagePerSecondPerStack\":25,\"MaxEffectiveStack\":3}", null), Is.True);
return row;
}
private static DRTag CreateFireDisabledRow()
{
DRTag row = new DRTag();
Assert.That(row.ParseDataRow("\t1\t元素\tFire\tElement\tWhite\t20\tFalse", null), Is.True);
return row;
}
}
}
+27
View File
@@ -29,6 +29,7 @@ namespace GeometryTD.Tests.EditMode
"run-test");
Assert.That(runState.RunId, Is.EqualTo("run-test"));
Assert.That(runState.RunSeed, Is.Not.EqualTo(0));
Assert.That(runState.ThemeType, Is.EqualTo(LevelThemeType.Plain));
Assert.That(runState.CurrentNodeIndex, Is.EqualTo(0));
Assert.That(runState.IsCompleted, Is.False);
@@ -83,6 +84,31 @@ namespace GeometryTD.Tests.EditMode
Assert.That(runState.RunInventorySnapshot.Gold, Is.EqualTo(130));
}
[Test]
public void Factory_Preserves_Explicit_RunSeed_And_Generates_NonZero_Default_RunSeed()
{
RunState explicitSeedRun = RunStateFactory.Create(
LevelThemeType.Plain,
new BackpackInventoryData(),
new[]
{
new RunNodeSeed { NodeType = RunNodeType.Combat, LinkedLevelId = 1 }
},
"run-explicit",
123456);
RunState generatedSeedRun = RunStateFactory.Create(
LevelThemeType.Plain,
new BackpackInventoryData(),
new[]
{
new RunNodeSeed { NodeType = RunNodeType.Combat, LinkedLevelId = 1 }
},
"run-generated");
Assert.That(explicitSeedRun.RunSeed, Is.EqualTo(123456));
Assert.That(generatedSeedRun.RunSeed, Is.Not.EqualTo(0));
}
[Test]
public void AdvanceService_Exception_Marks_Current_Node_Exception_Without_Completing_Run()
{
@@ -234,6 +260,7 @@ namespace GeometryTD.Tests.EditMode
"fixed-run");
Assert.That(runState.RunId, Is.EqualTo("fixed-run"));
Assert.That(runState.RunSeed, Is.Not.EqualTo(0));
Assert.That(runState.NodeCount, Is.EqualTo(10));
Assert.That(runState.CurrentNodeIndex, Is.EqualTo(0));
Assert.That(runState.CurrentNode.NodeType, Is.EqualTo(RunNodeType.Combat));
@@ -435,6 +435,34 @@ namespace GeometryTD.Tests.EditMode
TagDefinitionRegistry.ResetToDefaults();
}
[Test]
public void ReloadFromRows_Uses_TagTable_As_IsImplemented_Source_When_TagConfig_Loads_First()
{
DRTagConfig fireConfigRow = CreateFireConfigRow();
DRTag fireTagRow = CreateFireDisabledRow();
TagDefinitionRegistry.ReloadFromRows(new[] { fireConfigRow }, null);
TagDefinitionRegistry.ReloadFromRows(new[] { fireConfigRow }, new[] { fireTagRow });
AssertFireDefinition(false);
TagDefinitionRegistry.ResetToDefaults();
}
[Test]
public void ReloadFromRows_Uses_TagTable_As_IsImplemented_Source_When_Tag_Loads_First()
{
DRTagConfig fireConfigRow = CreateFireConfigRow();
DRTag fireTagRow = CreateFireDisabledRow();
TagDefinitionRegistry.ReloadFromRows(null, new[] { fireTagRow });
TagDefinitionRegistry.ReloadFromRows(new[] { fireConfigRow }, new[] { fireTagRow });
AssertFireDefinition(false);
TagDefinitionRegistry.ResetToDefaults();
}
[Test]
public void BuildTagDescriptionText_Uses_Registry_Descriptions()
{
@@ -502,6 +530,34 @@ namespace GeometryTD.Tests.EditMode
Assert.That(definition.Category, Is.EqualTo(expectedCategory));
Assert.That(definition.TriggerPhase, Is.EqualTo(expectedPhase));
}
private static DRTagConfig CreateFireConfigRow()
{
DRTagConfig row = new DRTagConfig();
Assert.That(row.ParseDataRow("\t1\t元素\tFire\tOnAfterHit\t火焰测试描述\t{\"BurnDurationSeconds\":4,\"BurnDamagePerSecondPerStack\":25,\"MaxEffectiveStack\":3}", null), Is.True);
return row;
}
private static DRTag CreateFireDisabledRow()
{
DRTag row = new DRTag();
Assert.That(row.ParseDataRow("\t1\t元素\tFire\tElement\tWhite\t20\tFalse", null), Is.True);
return row;
}
private static void AssertFireDefinition(bool isImplemented)
{
Assert.That(TagDefinitionRegistry.TryGetDefinition(TagType.Fire, out TagDefinition fire), Is.True);
Assert.That(fire.TriggerPhase, Is.EqualTo(TagTriggerPhase.OnAfterHit));
Assert.That(fire.Description, Is.EqualTo("火焰测试描述"));
Assert.That(fire.Config, Is.TypeOf<FireTagConfig>());
FireTagConfig config = (FireTagConfig)fire.Config;
Assert.That(config.IsImplemented, Is.EqualTo(isImplemented));
Assert.That(config.BurnDurationSeconds, Is.EqualTo(4f).Within(0.001f));
Assert.That(config.BurnDamagePerSecondPerStack, Is.EqualTo(25f).Within(0.001f));
Assert.That(config.MaxEffectiveStack, Is.EqualTo(3));
}
}
public sealed class AttackPayloadFlowTests