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

397 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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>();
private readonly Dictionary<string, DefTypeBase> _notCaseSenseTypes = new();
private readonly HashSet<string> _namespaces = new();
private readonly Dictionary<string, DefTypeBase> _notCaseSenseNamespaces = new();
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 = GetOptionOr("editor.topmodule", 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");
}
if (!_notCaseSenseTypes.TryAdd(fullName.ToLower(), type))
{
throw new Exception($"type:'{fullName}' 和 type:'{_notCaseSenseTypes[fullName.ToLower()].FullName}' 类名小写重复. 在win平台有问题");
}
string namespaze = type.Namespace;
if (_namespaces.Add(namespaze) && !_notCaseSenseNamespaces.TryAdd(namespaze.ToLower(), type))
{
throw new Exception($"type:'{fullName}' 和 type:'{_notCaseSenseNamespaces[namespaze.ToLower()].FullName}' 命名空间小写重复. 在win平台有问题请修改定义并删除生成的代码目录后再重新生成");
}
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)
{
type = DefUtil.TrimBracePairs(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.ParseTypeAndVaildAttrs(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.ParseTypeAndVaildAttrs(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()),
CreateType(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, CreateType(module, elementType));
}
case "list": return TList.Create(false, containerTags, CreateType(module, elementType), true);
case "set":
{
TType type = CreateType(module, elementType);
if (type.IsCollection)
{
throw new Exception("set的元素不支持容器类型");
}
return TSet.Create(false, containerTags, type, false);
}
case "map": return CreateMapType(module, containerTags, elementType, false);
default:
{
throw new ArgumentException($"invalid container type. module:'{module}' container:'{containerType}' element:'{elementType}'");
}
}
}
}
}