Add L0 IDataRow implementation for Tag system

- Add TagRow and RarityTagBudgetRow implementing GameFramework IDataRow
- Migrate TagGenerationRule and RarityTagBudgetRule to Domain layer
- Migrate TagGenerationRuleRegistry and RarityTagBudgetRuleRegistry
  to use IEnumerable<TagRow> instead of DRTag

This establishes the foundation for DR migration: L0 now has pure C#
IDataRow implementations while L1 will provide DataRowBase wrappers.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Basil 2026-05-01 09:09:42 +08:00
parent 4c413ccd6d
commit ee969e4e3e
6 changed files with 253 additions and 0 deletions

View File

@ -0,0 +1,44 @@
using System;
using GameFramework.DataTable;
using GeometryTD.Definition;
namespace GeometryTD.Domain.DataTable
{
public sealed class RarityTagBudgetRow : IDataRow
{
private static readonly char[] DataSplitSeparators = new char[] { '\t' };
private static readonly char[] DataTrimSeparators = new char[] { '"' };
public int Id { get; private set; }
public RarityType Rarity { get; private set; }
public int MinCount { get; private set; }
public int MaxCount { get; private set; }
public bool ParseDataRow(string dataRowString, object userData)
{
string[] columnStrings = dataRowString.Split(DataSplitSeparators);
for (int i = 0; i < columnStrings.Length; i++)
{
columnStrings[i] = columnStrings[i].Trim(DataTrimSeparators);
}
int index = 0;
index++;
Id = int.Parse(columnStrings[index++]);
index++;
Rarity = Enum.Parse<RarityType>(columnStrings[index++]);
MinCount = int.Parse(columnStrings[index++]);
MaxCount = int.Parse(columnStrings[index++]);
return true;
}
public bool ParseDataRow(byte[] dataRowBytes, int startIndex, int length, object userData)
{
throw new NotSupportedException("Binary parsing is not supported.");
}
}
}

View File

@ -0,0 +1,59 @@
using System;
using GameFramework.DataTable;
using GeometryTD.Definition;
namespace GeometryTD.Domain.DataTable
{
public sealed class TagRow : IDataRow
{
private static readonly char[] DataSplitSeparators = new char[] { '\t' };
private static readonly char[] DataTrimSeparators = new char[] { '"' };
public int Id { get; private set; }
public TagType TagType => (TagType)Id;
public RarityType MinRarity { get; private set; }
public int Weight { get; private set; }
public bool IsImplemented { get; private set; }
public bool ParseDataRow(string dataRowString, object userData)
{
string[] columnStrings = dataRowString.Split(DataSplitSeparators);
for (int i = 0; i < columnStrings.Length; i++)
{
columnStrings[i] = columnStrings[i].Trim(DataTrimSeparators);
}
int index = 0;
index++;
Id = int.Parse(columnStrings[index++]);
index++;
index++;
bool hasExtendedColumns = columnStrings.Length - index >= 4;
if (hasExtendedColumns)
{
index++;
MinRarity = Enum.Parse<RarityType>(columnStrings[index++]);
Weight = int.Parse(columnStrings[index++]);
IsImplemented = bool.Parse(columnStrings[index++]);
}
else
{
MinRarity = Enum.Parse<RarityType>(columnStrings[index++]);
Weight = int.Parse(columnStrings[index++]);
IsImplemented = true;
}
return true;
}
public bool ParseDataRow(byte[] dataRowBytes, int startIndex, int length, object userData)
{
throw new NotSupportedException("Binary parsing is not supported.");
}
}
}

View File

@ -0,0 +1,9 @@
namespace GeometryTD.Definition
{
public sealed class RarityTagBudgetRule
{
public RarityType Rarity { get; set; }
public int MinCount { get; set; }
public int MaxCount { get; set; }
}
}

View File

@ -0,0 +1,62 @@
using System.Collections.Generic;
using GeometryTD.Domain.DataTable;
namespace GeometryTD.Definition
{
public static class RarityTagBudgetRuleRegistry
{
private static readonly Dictionary<RarityType, RarityTagBudgetRule> RulesByRarity = CreateDefaultRules();
public static IReadOnlyDictionary<RarityType, RarityTagBudgetRule> Rules => RulesByRarity;
public static void ResetToDefaults()
{
RulesByRarity.Clear();
foreach (KeyValuePair<RarityType, RarityTagBudgetRule> pair in CreateDefaultRules())
{
RulesByRarity.Add(pair.Key, pair.Value);
}
}
public static void LoadFromRows(IEnumerable<RarityTagBudgetRow> rows)
{
ResetToDefaults();
foreach (RarityTagBudgetRow row in rows)
{
ApplyRow(row);
}
}
public static bool TryGetRule(RarityType rarity, out RarityTagBudgetRule rule)
{
return RulesByRarity.TryGetValue(rarity, out rule);
}
private static Dictionary<RarityType, RarityTagBudgetRule> CreateDefaultRules()
{
return new Dictionary<RarityType, RarityTagBudgetRule>
{
[RarityType.White] = CreateRule(RarityType.White, 0, 1),
[RarityType.Green] = CreateRule(RarityType.Green, 0, 2),
[RarityType.Blue] = CreateRule(RarityType.Blue, 1, 3),
[RarityType.Purple] = CreateRule(RarityType.Purple, 1, 3),
[RarityType.Red] = CreateRule(RarityType.Red, 2, 4)
};
}
private static RarityTagBudgetRule CreateRule(RarityType rarity, int minCount, int maxCount)
{
return new RarityTagBudgetRule
{
Rarity = rarity,
MinCount = minCount,
MaxCount = maxCount
};
}
private static void ApplyRow(RarityTagBudgetRow row)
{
RulesByRarity[row.Rarity] = CreateRule(row.Rarity, row.MinCount, row.MaxCount);
}
}
}

View File

@ -0,0 +1,9 @@
namespace GeometryTD.Definition
{
public sealed class TagGenerationRule
{
public TagType TagType { get; set; }
public RarityType MinRarity { get; set; }
public int Weight { get; set; }
}
}

View File

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using GeometryTD.Domain.DataTable;
namespace GeometryTD.Definition
{
public static class TagGenerationRuleRegistry
{
private static readonly Dictionary<TagType, TagGenerationRule> RulesByTag = CreateDefaultRules();
public static IReadOnlyDictionary<TagType, TagGenerationRule> Rules => RulesByTag;
public static void ResetToDefaults()
{
RulesByTag.Clear();
foreach (KeyValuePair<TagType, TagGenerationRule> pair in CreateDefaultRules())
{
RulesByTag.Add(pair.Key, pair.Value);
}
}
public static void LoadFromRows(IEnumerable<TagRow> rows)
{
ResetToDefaults();
foreach (TagRow row in rows)
{
ApplyRow(row);
}
}
public static bool TryGetRule(TagType tagType, out TagGenerationRule rule)
{
return RulesByTag.TryGetValue(tagType, out rule);
}
private static Dictionary<TagType, TagGenerationRule> CreateDefaultRules()
{
return new Dictionary<TagType, TagGenerationRule>
{
[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, 1),
[TagType.FreezeMask] = CreateRule(TagType.FreezeMask, RarityType.White, 20),
[TagType.Shatter] = CreateRule(TagType.Shatter, RarityType.Green, 15),
[TagType.AbsoluteZero] = CreateRule(TagType.AbsoluteZero, RarityType.Purple, 1),
[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 TagGenerationRule CreateRule(TagType tagType, RarityType minRarity, int weight)
{
return new TagGenerationRule
{
TagType = tagType,
MinRarity = minRarity,
Weight = weight
};
}
private static void ApplyRow(TagRow row)
{
RulesByTag[row.TagType] = CreateRule(row.TagType, row.MinRarity, row.Weight);
}
}
}