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 _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(); private readonly Dictionary _notCaseSenseTypes = new(); private readonly HashSet _namespaces = new(); private readonly Dictionary _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 ExternalSelectors { get; private set; } private Dictionary ExternalTypes { get; set; } private readonly Dictionary _externalTypesByTypeName = new(); public List CurrentExternalSelectors { get; private set; } public Dictionary 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(); } 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 s_internalOriginTypes = new HashSet { "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 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) { type = DefUtil.TrimBracePairs(type, true); 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 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 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}'"); } } } } }