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

367 lines
14 KiB
C#

using Luban.Common.Utils;
using Luban.Job.Common.RawDefs;
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
using Luban.Job.Common.Utils;
using Luban.Server.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace Luban.Job.Common.Defs
{
public abstract class DefAssemblyBase
{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
private static readonly AsyncLocal<DefAssemblyBase> _localAssembly = new();
public static DefAssemblyBase LocalAssebmly
{
get
{
return _localAssembly.Value;
}
set
{
_localAssembly.Value = value;
}
}
public static bool IsUseUnityVectors => LocalAssebmly?.CsUseUnityVectors == true;
public Dictionary<string, DefTypeBase> Types { get; } = new Dictionary<string, DefTypeBase>();
public IAgent Agent { get; protected set; }
public string TopModule { get; protected set; }
public bool SupportDatetimeType { get; protected set; } = false;
public bool SupportNullable { get; protected set; } = true;
public bool CsUseUnityVectors { get; set; }
public GenArgsBase Args { get; private set; }
public NamingConvention NamingConventionModule { get; set; } = NamingConvention.LanguangeRecommend;
public NamingConvention NamingConventionType { get; set; } = NamingConvention.LanguangeRecommend;
public NamingConvention NamingConventionBeanMember { get; set; } = NamingConvention.LanguangeRecommend;
public NamingConvention NamingConventionEnumMember { get; set; } = NamingConvention.LanguangeRecommend;
public AccessConvention AccessConventionBeanMember { get; set; } = AccessConvention.LanguangeRecommend;
public ELanguage CurrentLanguage { get; set; } = ELanguage.INVALID;
public HashSet<string> ExternalSelectors { get; private set; }
private Dictionary<string, ExternalType> ExternalTypes { get; set; }
private readonly Dictionary<string, ExternalType> _externalTypesByTypeName = new();
public List<string> CurrentExternalSelectors { get; private set; }
public Dictionary<string, string> Options { get; private set; }
public string EditorTopModule { get; private set; }
public bool ContainsOption(string optionName)
{
return Options.ContainsKey(optionName);
}
public string GetOption(string optionName)
{
return Options.TryGetValue(optionName, out var value) ? value : null;
}
public string GetOptionOr(string optionName, string defaultValue)
{
return Options.TryGetValue(optionName, out var value) ? value : defaultValue;
}
private void SetCurrentExternalSelectors(string selectors)
{
if (string.IsNullOrEmpty(selectors))
{
CurrentExternalSelectors = new List<string>();
}
else
{
CurrentExternalSelectors = selectors.Split(',').Select(s => s.Trim()).ToList();
foreach (var selector in CurrentExternalSelectors)
{
if (!ExternalSelectors.Contains(selector))
{
throw new Exception($"未知 externalselector:{selector}, 有效值应该为 '{Bright.Common.StringUtil.CollectionToString(ExternalSelectors)}'");
}
}
}
}
public void LoadCommon(DefinesCommon defines, IAgent agent, GenArgsBase args)
{
LocalAssebmly = this;
this.Agent = agent;
this.TopModule = defines.TopModule;
this.ExternalSelectors = defines.ExternalSelectors;
this.ExternalTypes = defines.ExternalTypes;
this.Options = defines.Options;
this.EditorTopModule = defines.Options.TryGetValue("editor.topmodule", out var editorTopModule) ? editorTopModule : TypeUtil.MakeFullName("editor", defines.TopModule);
this.Args = args;
SetCurrentExternalSelectors(args.ExternalSelectors);
CsUseUnityVectors = args.CsUseUnityVectors;
NamingConventionModule = args.NamingConventionModule;
NamingConventionType = args.NamingConventionType;
NamingConventionBeanMember = args.NamingConventionBeanMember;
NamingConventionEnumMember = args.NamingConventionEnumMember;
}
public ExternalTypeMapper GetExternalTypeMapper(TType type)
{
return GetExternalTypeMapper(type.Apply(RawDefineTypeNameVisitor.Ins));
}
public ExternalTypeMapper GetExternalTypeMapper(string typeName)
{
ExternalType externalType = _externalTypesByTypeName.GetValueOrDefault(typeName);
if (externalType == null)
{
return null;
}
return externalType.Mappers.Find(m => m.Lan == CurrentLanguage && CurrentExternalSelectors.Contains(m.Selector));
}
public ExternalType GetExternalType(string typeName)
{
return _externalTypesByTypeName.GetValueOrDefault(typeName);
}
private static readonly HashSet<string> s_internalOriginTypes = new HashSet<string>
{
"vector2",
"vector3",
"vector4",
"datetime",
};
public void AddExternalType(ExternalType type)
{
string originTypeName = type.OriginTypeName;
if (!Types.ContainsKey(originTypeName) && !s_internalOriginTypes.Contains(originTypeName))
{
throw new LoadDefException($"externaltype:'{type.Name}' originTypeName:'{originTypeName}' 不存在");
}
if (!_externalTypesByTypeName.TryAdd(originTypeName, type))
{
throw new LoadDefException($"type:'{originTypeName} 被重复映射. externaltype1:'{type.Name}' exteraltype2:'{_externalTypesByTypeName[originTypeName].Name}'");
}
}
public void AddType(DefTypeBase type)
{
string fullName = type.FullName;
if (Types.ContainsKey(fullName))
{
throw new Exception($"type:'{fullName}' duplicate");
}
Types.Add(fullName, type);
}
public DefTypeBase GetDefType(string fullName)
{
return Types.TryGetValue(fullName, out var type) ? type : null;
}
public DefTypeBase GetDefType(string module, string type)
{
if (Types.TryGetValue(TypeUtil.MakeFullName(module, type), out var t))
{
return t;
}
else if (Types.TryGetValue(type, out t))
{
return t;
}
else
{
return null;
}
}
private readonly Dictionary<(DefTypeBase, bool), TType> _cacheDefTTypes = new Dictionary<(DefTypeBase, bool), TType>();
protected TType GetOrCreateTEnum(DefEnum defType, bool nullable, Dictionary<string, string> tags)
{
if (tags == null || tags.Count == 0)
{
if (_cacheDefTTypes.TryGetValue((defType, nullable), out var t))
{
return t;
}
else
{
return _cacheDefTTypes[(defType, nullable)] = TEnum.Create(nullable, defType, tags);
}
}
else
{
return TEnum.Create(nullable, defType, tags); ;
}
}
protected TType GetOrCreateTBean(DefTypeBase defType, bool nullable, Dictionary<string, string> tags)
{
if (tags == null || tags.Count == 0)
{
if (_cacheDefTTypes.TryGetValue((defType, nullable), out var t))
{
return t;
}
else
{
return _cacheDefTTypes[(defType, nullable)] = TBean.Create(nullable, (DefBeanBase)defType, tags);
}
}
else
{
return TBean.Create(nullable, (DefBeanBase)defType, tags);
}
}
public TType GetDefTType(string module, string type, bool nullable, Dictionary<string, string> tags)
{
var defType = GetDefType(module, type);
switch (defType)
{
case DefBeanBase d: return GetOrCreateTBean(d, nullable, tags);
case DefEnum d: return GetOrCreateTEnum(d, nullable, tags);
default: return null;
}
}
public List<T> GetDefTypesByType<T>() where T : DefTypeBase
{
return Types.Values.Where(v => typeof(T).IsAssignableFrom(v.GetType())).Select(v => (T)v).ToList();
}
public TType CreateType(string module, string type)
{
int sepIndex = DefUtil.IndexOfBaseTypeEnd(type);
if (sepIndex > 0)
{
string containerTypeAndTags = DefUtil.TrimBracePairs(type.Substring(0, sepIndex));
var elementTypeAndTags = type.Substring(sepIndex + 1);
var (containerType, containerTags) = DefUtil.ParseType(containerTypeAndTags);
return CreateContainerType(module, containerType, containerTags, elementTypeAndTags.Trim());
}
else
{
return CreateNotContainerType(module, type);
}
}
protected TType CreateNotContainerType(string module, string rawType)
{
bool nullable;
// 去掉 rawType 两侧的匹配的 ()
rawType = DefUtil.TrimBracePairs(rawType);
var (type, tags) = DefUtil.ParseType(rawType);
if (type.EndsWith('?'))
{
if (!SupportNullable)
{
throw new Exception($"not support nullable type:'{module}.{type}'");
}
nullable = true;
type = type.Substring(0, type.Length - 1);
}
else
{
nullable = false;
}
switch (type)
{
case "bool": return TBool.Create(nullable, tags);
case "uint8":
case "byte": return TByte.Create(nullable, tags);
case "int16":
case "short": return TShort.Create(nullable, tags);
case "fint16":
case "fshort": return TFshort.Create(nullable, tags);
case "int32":
case "int": return TInt.Create(nullable, tags);
case "fint32":
case "fint": return TFint.Create(nullable, tags);
case "int64":
case "long": return TLong.Create(nullable, tags, false);
case "bigint": return TLong.Create(nullable, tags, true);
case "fint64":
case "flong": return TFlong.Create(nullable, tags);
case "float32":
case "float": return TFloat.Create(nullable, tags);
case "float64":
case "double": return TDouble.Create(nullable, tags);
case "bytes": return TBytes.Create(nullable, tags);
case "string": return TString.Create(nullable, tags);
case "text": return TText.Create(nullable, tags);
case "vector2": return TVector2.Create(nullable, tags);
case "vector3": return TVector3.Create(nullable, tags);
case "vector4": return TVector4.Create(nullable, tags);
case "time":
case "datetime": return SupportDatetimeType ? TDateTime.Create(nullable, tags) : throw new NotSupportedException($"只有配置支持datetime数据类型");
default:
{
var dtype = GetDefTType(module, type, nullable, tags);
if (dtype != null)
{
return dtype;
}
else
{
throw new ArgumentException($"invalid type. module:'{module}' type:'{type}'");
}
}
}
}
protected TMap CreateMapType(string module, Dictionary<string, string> tags, string keyValueType, bool isTreeMap)
{
int typeSepIndex = DefUtil.IndexOfElementTypeSep(keyValueType);
if (typeSepIndex <= 0 || typeSepIndex >= keyValueType.Length - 1)
{
throw new ArgumentException($"invalid map element type:'{keyValueType}'");
}
return TMap.Create(false, tags,
CreateNotContainerType(module, keyValueType.Substring(0, typeSepIndex).Trim()),
CreateNotContainerType(module, keyValueType.Substring(typeSepIndex + 1).Trim()), isTreeMap);
}
protected TType CreateContainerType(string module, string containerType, Dictionary<string, string> containerTags, string elementType)
{
switch (containerType)
{
case "array": return TArray.Create(false, containerTags, CreateNotContainerType(module, elementType));
case "list": return TList.Create(false, containerTags, CreateNotContainerType(module, elementType), true);
case "set": return TSet.Create(false, containerTags, CreateNotContainerType(module, elementType), false);
case "map": return CreateMapType(module, containerTags, elementType, false);
default:
{
throw new ArgumentException($"invalid container type. module:'{module}' container:'{containerType}' element:'{elementType}'");
}
}
}
}
}