using Luban.Common.Utils; using Luban.Job.Common.Types; 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 _localAssembly = new(); public static DefAssemblyBase LocalAssebmly { get { return _localAssembly.Value; } set { _localAssembly.Value = value; } } public static bool IsUseUnityVectors => LocalAssebmly?.CsUseUnityVectors == true; public Dictionary Types { get; } = new Dictionary(); 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 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 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(type, out var t)) { return t; } else if (Types.TryGetValue(TypeUtil.MakeFullName(module, 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 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 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 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 GetDefTypesByType() 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.IndexOfElementTypeSep(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 !LUBAN_LITE if (type.EndsWith('?')) #else if (type.EndsWith("?")) #endif { if (!SupportNullable) { throw new Exception($"not support nullable type:'{module}.{type}'"); } nullable = true; #if !LUBAN_LITE type = type[0..^1]; #else type = type.Substring(0, type.Length - 1); #endif } 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 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 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 "linkedlist": return TList.Create(false, containerTags, CreateNotContainerType(module, elementType), false); case "arraylist": return TList.Create(false, containerTags, CreateNotContainerType(module, elementType), true); case "set": return TSet.Create(false, containerTags, CreateNotContainerType(module, elementType), false); case "hashset": return TSet.Create(false, containerTags, CreateNotContainerType(module, elementType), false); case "treeset": return TSet.Create(false, containerTags, CreateNotContainerType(module, elementType), true); case "map": return CreateMapType(module, containerTags, elementType, false); case "treemap": return CreateMapType(module, containerTags, elementType, true); case "hashmap": return CreateMapType(module, containerTags, elementType, false); default: { throw new ArgumentException($"invalid container type. module:'{module}' container:'{containerType}' element:'{elementType}'"); } } } } }