S4-07 process 2

当前 `Tag.txt -> DRTag -> TagGenerationRuleRegistry` 已形成组件 Tag 生成规则闭环:
- `InventoryTagRuleService` 不再主要依赖内部 `MinRarity` 硬编码,而是统一消费 `DRTag` 提供的 `MinRarity + Weight`
- `ShopFormUseCase`、`EnemyDropResolver`、`InventorySeedUtility` 也已切回这一统一入口。
- 现阶段的职责边界明确为:`Tag.txt` 负责基础字典与生成规则,`TagConfig.txt` 负责触发阶段、描述与效果参数。
This commit is contained in:
SepComet
2026-03-11 11:20:16 +08:00
parent 9de2e50262
commit b1b68ebde5
46 changed files with 615 additions and 452 deletions
@@ -0,0 +1,9 @@
namespace GeometryTD.Definition
{
public enum ProcedureMainCombatEntryBlockReason
{
None = 0,
InventoryUnavailable = 1,
NoValidParticipantTower = 2
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f6d8af9f1d7d4041bfcee904724303e9
timeCreated: 1773198097
@@ -0,0 +1,9 @@
namespace GeometryTD.Definition
{
public enum ProcedureMainFlowPhase
{
Hub = 0,
NodeActive = 1,
RunCompletedPendingFinish = 2
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 01450486bd824f47bcd74dda8a160ba4
timeCreated: 1773198057
@@ -0,0 +1,10 @@
namespace GeometryTD.Definition
{
public enum ProcedureMainRunAdvanceResult
{
NoChange = 0,
NodeException = 1,
AdvancedToNextNode = 2,
RunCompleted = 3
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e9e0fa56d7e84874ac0f9d4a400fda13
timeCreated: 1773198071
@@ -0,0 +1,9 @@
namespace GeometryTD.Definition
{
public enum ProcedureMainRunCompletionResult
{
NoChange = 0,
ShowCompletionDialog = 1,
ReturnToMenu = 2
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e3d0df05f77043a99c463a790b5ac35f
timeCreated: 1773198084
@@ -1,33 +1,22 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using Random = System.Random;
namespace GeometryTD.Definition
{
public static class InventoryTagRuleService
{
private static readonly IReadOnlyDictionary<TagType, RarityType> DefaultMinRarityByTag =
new Dictionary<TagType, RarityType>
{
{ TagType.Fire, RarityType.White },
{ TagType.Ice, RarityType.White },
{ TagType.Crit, RarityType.White },
{ TagType.Shatter, RarityType.Green },
{ TagType.Inferno, RarityType.Purple },
{ TagType.AbsoluteZero, RarityType.Purple },
{ TagType.Execution, RarityType.Purple },
};
private static readonly HashSet<TagType> SupportedLaunchTags = new HashSet<TagType>(DefaultMinRarityByTag.Keys);
public static TagType[] ResolveComponentTags(
IReadOnlyList<TagType> possibleTags,
RarityType rarity,
InventoryTagSourceType sourceType,
long itemInstanceId,
int configId,
IReadOnlyDictionary<TagType, RarityType> minRarityByTag = null)
IReadOnlyDictionary<TagType, TagGenerationRuleData> rulesByTag = null)
{
TagType[] eligibleTags = GetEligibleTags(possibleTags, rarity, minRarityByTag);
IReadOnlyDictionary<TagType, TagGenerationRuleData> ruleLookup = rulesByTag ?? TagGenerationRuleRegistry.Rules;
TagType[] eligibleTags = GetEligibleTags(possibleTags, rarity, ruleLookup);
if (eligibleTags.Length <= 0)
{
return Array.Empty<TagType>();
@@ -45,7 +34,7 @@ namespace GeometryTD.Definition
TagType[] result = new TagType[finalCount];
for (int i = 0; i < finalCount; i++)
{
int index = random.Next(0, pool.Count);
int index = RollWeightedIndex(pool, ruleLookup, random);
result[i] = pool[index];
pool.RemoveAt(index);
}
@@ -56,7 +45,7 @@ namespace GeometryTD.Definition
public static TagType[] GetEligibleTags(
IReadOnlyList<TagType> possibleTags,
RarityType rarity,
IReadOnlyDictionary<TagType, RarityType> minRarityByTag = null)
IReadOnlyDictionary<TagType, TagGenerationRuleData> rulesByTag = null)
{
if (possibleTags == null || possibleTags.Count <= 0)
{
@@ -64,23 +53,23 @@ namespace GeometryTD.Definition
}
RarityType normalizedRarity = InventoryRarityRuleService.NormalizeComponentRarity(rarity);
IReadOnlyDictionary<TagType, RarityType> rarityLookup = minRarityByTag ?? DefaultMinRarityByTag;
IReadOnlyDictionary<TagType, TagGenerationRuleData> ruleLookup = rulesByTag ?? TagGenerationRuleRegistry.Rules;
HashSet<TagType> uniqueTags = new HashSet<TagType>();
for (int i = 0; i < possibleTags.Count; i++)
{
TagType tagType = possibleTags[i];
if (!IsSupportedLaunchTag(tagType) || tagType == TagType.None || !Enum.IsDefined(typeof(TagType), tagType))
if (tagType == TagType.None || !Enum.IsDefined(typeof(TagType), tagType) || !IsSupportedLaunchTag(tagType))
{
continue;
}
if (!TryGetMinRarity(tagType, rarityLookup, out RarityType minRarity))
if (!TryGetRule(tagType, ruleLookup, out TagGenerationRuleData rule))
{
continue;
}
if (normalizedRarity < InventoryRarityRuleService.NormalizeComponentRarity(minRarity))
if (normalizedRarity < InventoryRarityRuleService.NormalizeComponentRarity(rule.MinRarity))
{
continue;
}
@@ -123,28 +112,55 @@ namespace GeometryTD.Definition
private static bool IsSupportedLaunchTag(TagType tagType)
{
return SupportedLaunchTags.Contains(tagType);
return TagConfigRegistry.TryGetDefinition(tagType, out TagDefinitionData definition) &&
definition.Config != null &&
definition.Config.IsImplemented;
}
private static bool TryGetMinRarity(
private static bool TryGetRule(
TagType tagType,
IReadOnlyDictionary<TagType, RarityType> rarityLookup,
out RarityType minRarity)
IReadOnlyDictionary<TagType, TagGenerationRuleData> ruleLookup,
out TagGenerationRuleData rule)
{
if (rarityLookup != null && rarityLookup.TryGetValue(tagType, out minRarity))
if (ruleLookup != null && ruleLookup.TryGetValue(tagType, out rule))
{
return true;
}
if (DefaultMinRarityByTag.TryGetValue(tagType, out minRarity))
{
return true;
}
minRarity = RarityType.White;
rule = null;
return false;
}
private static int RollWeightedIndex(
IReadOnlyList<TagType> pool,
IReadOnlyDictionary<TagType, TagGenerationRuleData> ruleLookup,
Random random)
{
int totalWeight = 0;
for (int i = 0; i < pool.Count; i++)
{
TagGenerationRuleData rule = ruleLookup[pool[i]];
Debug.Assert(rule.Weight > 0);
totalWeight += rule.Weight;
}
Debug.Assert(totalWeight > 0);
int roll = random.Next(1, totalWeight + 1);
int cumulative = 0;
for (int i = 0; i < pool.Count; i++)
{
TagGenerationRuleData rule = ruleLookup[pool[i]];
cumulative += rule.Weight;
if (roll <= cumulative)
{
return i;
}
}
return pool.Count - 1;
}
private static int BuildStableSeed(
RarityType rarity,
InventoryTagSourceType sourceType,
@@ -0,0 +1,9 @@
namespace GeometryTD.Definition
{
public sealed class TagGenerationRuleData
{
public TagType TagType { get; set; }
public RarityType MinRarity { get; set; }
public int Weight { get; set; }
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cfe508e818ce47649a112ecdf86cf26a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,74 @@
using System.Collections.Generic;
using GeometryTD.DataTable;
using UnityEngine;
namespace GeometryTD.Definition
{
public static class TagGenerationRuleRegistry
{
private static readonly Dictionary<TagType, TagGenerationRuleData> RulesByTag = CreateDefaultRules();
public static IReadOnlyDictionary<TagType, TagGenerationRuleData> Rules => RulesByTag;
public static void ResetToDefaults()
{
RulesByTag.Clear();
foreach (KeyValuePair<TagType, TagGenerationRuleData> pair in CreateDefaultRules())
{
RulesByTag.Add(pair.Key, pair.Value);
}
}
public static void LoadFromRows(IEnumerable<DRTag> rows)
{
ResetToDefaults();
foreach (DRTag row in rows)
{
ApplyRow(row);
}
}
public static bool TryGetRule(TagType tagType, out TagGenerationRuleData rule)
{
return RulesByTag.TryGetValue(tagType, out rule);
}
private static Dictionary<TagType, TagGenerationRuleData> CreateDefaultRules()
{
return new Dictionary<TagType, TagGenerationRuleData>
{
[TagType.Fire] = CreateRule(TagType.Fire, RarityType.White, 20),
[TagType.BurnSpread] = CreateRule(TagType.BurnSpread, RarityType.White, 20),
[TagType.IgniteBurst] = CreateRule(TagType.IgniteBurst, RarityType.Green, 15),
[TagType.Inferno] = CreateRule(TagType.Inferno, RarityType.Purple, 5),
[TagType.Ice] = CreateRule(TagType.Ice, RarityType.White, 20),
[TagType.FreezeMask] = CreateRule(TagType.FreezeMask, RarityType.White, 20),
[TagType.Shatter] = CreateRule(TagType.Shatter, RarityType.Green, 15),
[TagType.AbsoluteZero] = CreateRule(TagType.AbsoluteZero, RarityType.Purple, 5),
[TagType.Pierce] = CreateRule(TagType.Pierce, RarityType.White, 20),
[TagType.Crit] = CreateRule(TagType.Crit, RarityType.White, 20),
[TagType.Overpenetrate] = CreateRule(TagType.Overpenetrate, RarityType.Green, 15),
[TagType.Execution] = CreateRule(TagType.Execution, RarityType.Purple, 5)
};
}
private static TagGenerationRuleData CreateRule(TagType tagType, RarityType minRarity, int weight)
{
return new TagGenerationRuleData
{
TagType = tagType,
MinRarity = minRarity,
Weight = weight
};
}
private static void ApplyRow(DRTag row)
{
Debug.Assert(row != null);
Debug.Assert(row.Id > 0);
Debug.Assert(row.Weight > 0);
RulesByTag[row.TagType] = CreateRule(row.TagType, row.MinRarity, row.Weight);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2e72e26721274985ba2d44ca825d7f75
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: