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

267 lines
10 KiB
C#

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<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 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<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.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<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 "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}'");
}
}
}
}
}