luban/src/Luban.Job.Common/Source/Defs/DefEnum.cs

198 lines
6.4 KiB
C#

using Luban.Job.Common.RawDefs;
using Luban.Job.Common.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using Bright.Collections;
namespace Luban.Job.Common.Defs
{
public class DefEnum : DefTypeBase
{
public class Item
{
public string Name { get; set; }
public string Value { get; set; }
public string Alias { get; set; }
public string AliasOrName => string.IsNullOrWhiteSpace(Alias) ? Name : Alias;
public int IntValue { get; set; }
public string Comment { get; set; }
public string EscapeComment => DefUtil.EscapeCommentByCurrentLanguage(Comment);
public Dictionary<string, string> Tags { get; set; }
public bool HasTag(string attrName)
{
return Tags != null && Tags.ContainsKey(attrName);
}
public string GetTag(string attrName)
{
return Tags != null && Tags.TryGetValue(attrName, out var value) ? value : null;
}
}
public bool IsFlags { get; }
public bool IsUniqueItemId { get; }
public List<Item> Items { get; } = new List<Item>();
private readonly Dictionary<string, int> _nameOrAlias2Value = new();
private readonly Dictionary<int, string> _vaule2Name = new();
public bool TryValueByNameOrAlias(string name, out int value)
{
return _nameOrAlias2Value.TryGetValue(name, out value);
}
public int GetValueByNameOrAlias(string name)
{
// TODO flags ?
if (!name.Contains('|'))
{
return GetBasicValueByNameOrAlias(name);
}
int combindValue = 0;
foreach (var s in name.Split('|'))
{
combindValue |= GetBasicValueByNameOrAlias(s.Trim());
}
return combindValue;
}
private int GetBasicValueByNameOrAlias(string name)
{
if (_nameOrAlias2Value.TryGetValue(name, out var value))
{
return value;
}
else if (int.TryParse(name, out value))
{
if (!_vaule2Name.ContainsKey(value))
{
throw new Exception($"{value} 不是 enum:'{FullName}'的有效枚举值");
}
return value;
}
else
{
throw new Exception($"'{name}' 不是enum:'{FullName}'的有效枚举值");
}
}
public DefEnum(PEnum e)
{
Name = e.Name;
Namespace = e.Namespace;
IsFlags = e.IsFlags;
IsUniqueItemId = e.IsUniqueItemId;
Comment = e.Comment;
Tags = DefUtil.ParseAttrs(e.Tags);
foreach (var item in e.Items)
{
Items.Add(new Item
{
Name =
item.Name,
Alias = item.Alias,
Value = item.Value,
Comment = string.IsNullOrWhiteSpace(item.Comment) ? item.Alias : item.Comment,
Tags = DefUtil.ParseAttrs(item.Tags),
});
}
}
public override void Compile()
{
var fullName = FullName;
int lastEnumValue = -1;
var names = new HashSet<string>();
foreach (var item in Items)
{
string value = item.Value.ToLower();
if (!names.Add(item.Name))
{
throw new Exception($"enum:'{fullName}' 字段:'{item.Name}' 重复");
}
if (string.IsNullOrEmpty(value))
{
// A,
item.IntValue = ++lastEnumValue;
item.Value = item.IntValue.ToString();
}
else if (int.TryParse(item.Value, out var v))
{
// A = 5,
item.IntValue = v;
lastEnumValue = v;
}
else if (value.StartsWith("0x"))
{
if (int.TryParse(value.Substring(2), System.Globalization.NumberStyles.HexNumber, null, out var x))
{
item.IntValue = x;
lastEnumValue = x;
}
else
{
throw new Exception($"enum:'{fullName}' 枚举名:'{item.Name}' value:'{item.Value}' 非法");
}
}
else if (IsFlags)
{
// D = A | B | C,
string[] itemNames = item.Value.Split('|').Select(s => s.Trim()).ToArray();
foreach (var n in itemNames)
{
var index = Items.FindIndex(i => i.Name == n);
if (index < 0)
{
throw new Exception($"enum:'{fullName}' 枚举名:'{item.Name}' 值:'{item.Value}' 非法");
}
item.IntValue |= Items[index].IntValue;
}
}
else
{
throw new Exception($"enum:'{fullName}' 枚举名:'{item.Name}' value:'{item.Value}' 非法");
}
if (!string.IsNullOrWhiteSpace(item.Name) && !_nameOrAlias2Value.TryAdd(item.Name, item.IntValue))
{
throw new Exception($"enum:'{fullName}' 枚举名:'{Name}' 重复");
}
if (!string.IsNullOrWhiteSpace(item.Alias) && !_nameOrAlias2Value.TryAdd(item.Alias, item.IntValue))
{
throw new Exception($"enum:'{fullName}' 枚举名:'{Name}' alias:'{item.Alias}' 重复");
}
if (_vaule2Name.TryGetValue(item.IntValue, out var itemName))
{
if (IsUniqueItemId)
{
throw new Exception($"enum:'{fullName}' 枚举值:{item.IntValue} 重复. 枚举名:'{itemName}' <=> '{item.Name}'");
}
}
else
{
_vaule2Name.Add(item.IntValue, item.Name);
}
}
}
}
}