Skip to content

枚举扩展机制 (EnumExtension) ​

概述 ​

EnumExtension 是 WasiCore 框架提供的代码生成工具,允许开发者扩展现有的可扩展枚举类型,无需修改原有代码。

支持的可扩展枚举 ​

框架中以下枚举支持扩展:

  • PropertyUnit - 单位基础属性
  • PropertyEntity - 实体属性
  • PropertySubType - 属性子类型
  • ComponentTag - 组件标签
  • EventType - 事件类型

基本用法 ​

图形化编辑器:预设值类型的“继承” ​

可扩展枚举在图形化触发编辑器中通过预设值类型的“继承”来扩展,物品分类只是其中一个使用场景。需要让新增枚举值出现在图形化数据编辑器的选项中时,应声明对应的预设值类型。仅在 src/**/*.cs 手写扩展枚举并编译成功,不会替代编辑器所需的触发器 JSON 声明。

  1. 在触发编辑器的公共页(Common)新建一个预设值类型(枚举类型)。建议将两端共用的枚举定义在这里,供客户端和服务端共同使用。
  2. 将新类型的**“继承”**设置为要扩展的预设值类型,例如 ItemCategory。
  3. 在新类型中添加预设值,例如 Woodcutting = 2001(伐木);数值应避免与已有枚举值冲突。
  4. 保存触发器声明并生成代码,双端编译后让编辑器加载最新项目声明,确认相应枚举字段能选择新增值;在物品分类示例中,对应物品的 Categories 字段。

界面中的“继承”对应 [EnumExtension(Extends = typeof(...))];“是否可被继承”对应 Extendable = true,表示允许后续类型继续扩展自己。扩展已有类型时,需要设置的是继承目标。这里的继承是框架的枚举扩展语义,并非 C# 原生 enum 继承。

例如图形化类型命名为 GatheringItemCategory、继承 ItemCategory,生成的源枚举为 EGatheringItemCategory(自动加 E 前缀)。纯代码项目仍可使用下文 C# 写法。使用 MCP 创建声明时,参见 触发器 MCP Skill,保存后检查继承关系与生成结果;不要手改生成文件或向 Categories 填写未声明的字符串来补选项。

语法格式 ​

csharp
[EnumExtension(Extends = typeof(TargetEnum))]
public enum ECustomEnum
{
    CustomValue1,
    CustomValue2,
    // ...
}

命名约定 ​

  • 源枚举:必须以 E 开头(如 ECustomPropertyUnit)
  • 生成枚举:自动去除 E 前缀(生成 CustomPropertyUnit)
  • 值命名:推荐使用 PascalCase 命名

实际示例 ​

扩展单位属性 ​

csharp
[EnumExtension(Extends = typeof(PropertyUnit))]
public enum EGameplayPropertyUnit
{
    // 战斗属性
    AttackPower,      // 攻击力
    DefensePower,     // 防御力
    CriticalRate,     // 暴击率
    
    // 角色属性
    Level,            // 等级
    Experience,       // 经验值
    SkillPoints,      // 技能点数
}

扩展属性子类型 ​

csharp
[EnumExtension(Extends = typeof(PropertySubType))]
public enum ECustomPropertySubType
{
    Equipment,        // 装备加成
    Buff,            // Buff效果
    Penalty,         // 负面效果
}

代码生成结果 ​

编译时,上述代码会生成:

csharp
// 自动生成的代码(不需要手写)
public static class GameplayPropertyUnit
{
    public static readonly PropertyUnit AttackPower = new PropertyUnit(1000);
    public static readonly PropertyUnit DefensePower = new PropertyUnit(1001);
    public static readonly PropertyUnit CriticalRate = new PropertyUnit(1002);
    // ...
}

使用生成的扩展 ​

csharp
// 设置扩展属性
unit.SetProperty(GameplayPropertyUnit.AttackPower, 150.0);
unit.SetProperty(GameplayPropertyUnit.Level, 25);

// 获取扩展属性
var attackPower = unit.GetProperty<double>(GameplayPropertyUnit.AttackPower);
var level = unit.GetProperty<int>(GameplayPropertyUnit.Level);

// 在数值公式系统中使用
propertyComplex.SetFixed(GameplayPropertyUnit.AttackPower, CustomPropertySubType.Equipment, 50.0);

最佳实践 ​

1. 合理分组 ​

csharp
// 推荐:按功能分组的扩展
[EnumExtension(Extends = typeof(PropertyUnit))]
public enum ECombatPropertyUnit
{
    AttackPower,
    DefensePower,
    CriticalRate,
}

[EnumExtension(Extends = typeof(PropertyUnit))]
public enum ECharacterPropertyUnit
{
    Level,
    Experience,
    SkillPoints,
}

2. 明确的命名 ​

csharp
// 推荐:清晰明确的命名
public enum EPlayerAttributeUnit
{
    MaxHealth,           // 最大生命值
    CurrentHealth,       // 当前生命值
    MovementSpeed,       // 移动速度
}

// 避免:模糊的命名
public enum EPlayerAttributeUnit
{
    Value1,    // 不清楚代表什么
    Data,      // 过于模糊
    Temp,      // 临时性命名
}

3. 文档注释 ​

csharp
[EnumExtension(Extends = typeof(PropertyUnit))]
public enum EAdvancedPropertyUnit
{
    /// <summary>
    /// 魔法强度,影响魔法技能的威力
    /// 数据类型: double, 范围: 0-1000
    /// </summary>
    MagicPower,
    
    /// <summary>
    /// 魔法抗性,减少受到的魔法伤害
    /// 数据类型: float, 范围: 0.0-1.0
    /// </summary>
    MagicResistance,
}

编译时行为 ​

构建过程 ​

  1. 代码分析:编译器分析所有带有 EnumExtension 特性的枚举
  2. ID分配:自动分配唯一的内部ID(通常从1000开始)
  3. 代码生成:生成对应的静态类和属性
  4. 类型注册:将生成的属性注册到框架的类型系统中

冲突检测 ​

框架会自动检测并报告以下冲突:

  • 重复命名:同一扩展目标中的重复属性名
  • ID冲突:手动指定ID时的冲突
  • 类型不匹配:扩展目标类型错误

故障排除 ​

常见错误 ​

  1. 枚举命名错误
错误:枚举名不以 'E' 开头
[EnumExtension(Extends = typeof(PropertyUnit))]
public enum CustomPropertyUnit  // 错误:应该是 ECustomPropertyUnit
  1. 目标类型不支持扩展
错误:尝试扩展不可扩展的枚举
[EnumExtension(Extends = typeof(DayOfWeek))]  // 错误:DayOfWeek 不支持扩展
  1. 循环依赖
错误:扩展枚举之间存在循环引用
[EnumExtension(Extends = typeof(EnumA))]
public enum EEnumB { ... }

[EnumExtension(Extends = typeof(EnumB))]  // 错误:循环引用
public enum EEnumA { ... }

调试技巧 ​

csharp
// 检查生成的属性是否正确注册
#if DEBUG
public static void ValidateExtensions()
{
    var attackPower = GameplayPropertyUnit.AttackPower;
    Game.Logger.LogInformation("AttackPower ID: {PropertyId}", attackPower.HashCode);
    Game.Logger.LogInformation("AttackPower Name: {PropertyName}", attackPower.FriendlyName);
}
#endif

性能考虑 ​

  • 编译时开销:代码生成只在编译时进行,不影响运行时性能
  • 内存占用:生成的静态属性会占用少量内存
  • 查找性能:使用哈希码进行快速查找,性能优秀

相关文档 ​