luban/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs

234 lines
7.6 KiB
C#

using Luban.Config.Common.RawDefs;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.TypeVisitors;
using Luban.Job.Common.Defs;
using Luban.Server.Common;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Luban.Job.Cfg.Defs
{
public class DefAssembly : DefAssemblyBase
{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
public Service CfgTargetService { get; private set; }
public TimeZoneInfo TimeZone { get; }
public DefAssembly(TimeZoneInfo timezone)
{
this.TimeZone = timezone;
}
public bool NeedExport(List<string> groups)
{
if (groups.Count == 0)
{
return true;
}
return groups.Any(g => CfgTargetService.Groups.Contains(g));
}
private readonly List<Service> _cfgServices = new List<Service>();
private readonly ConcurrentDictionary<string, List<DType>> _recordsByTables = new ConcurrentDictionary<string, List<DType>>();
private readonly ConcurrentDictionary<string, Dictionary<DType, DBean>> _recordsMapByTables = new ConcurrentDictionary<string, Dictionary<DType, DBean>>();
public Dictionary<string, DefTable> CfgTables { get; } = new Dictionary<string, DefTable>();
public void AddCfgTable(DefTable table)
{
if (!CfgTables.TryAdd(table.FullName, table))
{
throw new Exception($"table:{table.FullName} duplicated");
}
}
public DefTable GetCfgTable(string name)
{
return CfgTables.TryGetValue(name, out var t) ? t : null;
}
public void AddDataTable(DefTable table, List<DType> records)
{
_recordsByTables[table.FullName] = records;
}
public void SetDataTableMap(DefTable table, Dictionary<DType, DBean> recordMap)
{
_recordsMapByTables[table.FullName] = recordMap;
}
public List<DType> GetTableDataList(DefTable table)
{
return _recordsByTables[table.FullName];
}
public Dictionary<DType, DBean> GetTableDataMap(DefTable table)
{
return _recordsMapByTables[table.FullName];
}
public List<DefTable> GetExportTables()
{
return Types.Values.Where(t => t is DefTable ct && ct.NeedExport).Select(t => (DefTable)t).ToList();
}
public List<DefTypeBase> GetExportTypes()
{
var refTypes = new Dictionary<string, DefTypeBase>();
var targetService = CfgTargetService;
foreach (var refType in targetService.Refs)
{
if (!this.Types.ContainsKey(refType))
{
throw new Exception($"service:{targetService.Name} ref:{refType} 类型不存在");
}
if (!refTypes.TryAdd(refType, this.Types[refType]))
{
throw new Exception($"service:{targetService.Name} ref:{refType} 重复引用");
}
}
foreach ((var fullTypeName, var type) in this.Types)
{
if (!refTypes.ContainsKey(fullTypeName) && (type is DefConst || type is DefEnum))
{
refTypes.Add(fullTypeName, type);
}
}
foreach (var table in GetExportTables())
{
refTypes[table.FullName] = table;
table.ValueTType.Apply(RefTypeVisitor.Ins, refTypes);
}
return refTypes.Values.ToList();
}
public void Load(string outputService, Defines defines, RemoteAgent agent)
{
this.Agent = agent;
SupportDatetimeType = true;
TopModule = defines.TopModule;
CfgTargetService = defines.Services.Find(s => s.Name == outputService);
if (CfgTargetService == null)
{
throw new ArgumentException($"service:{outputService} not exists");
}
foreach (var c in defines.Consts)
{
AddType(new DefConst(c));
}
foreach (var e in defines.Enums)
{
AddType(new DefEnum(e));
}
foreach (var b in defines.Beans)
{
AddType(new DefBean((CfgBean)b));
}
foreach (var p in defines.Tables)
{
var table = new DefTable(p);
AddType(table);
AddCfgTable(table);
}
_cfgServices.AddRange(defines.Services);
foreach (var type in Types.Values)
{
type.AssemblyBase = this;
}
foreach (var type in Types.Values)
{
try
{
s_logger.Trace("precompile type:{0} begin", type.FullName);
type.PreCompile();
s_logger.Trace("precompile type:{0} end", type.FullName);
}
catch (Exception)
{
agent.Error("precompile type:{0} error", type.FullName);
throw;
}
}
foreach (var type in Types.Values)
{
try
{
s_logger.Trace("compile type:{0} begin", type.FullName);
type.Compile();
s_logger.Trace("compile type:{0} end", type.FullName);
}
catch (Exception)
{
agent.Error("compile type:{0} error", type.FullName);
s_logger.Error("compile type:{0} error", type.FullName);
throw;
}
}
foreach (var type in Types.Values)
{
try
{
s_logger.Trace("post compile type:{0} begin", type.FullName);
type.PostCompile();
s_logger.Trace("post compile type:{0} end", type.FullName);
}
catch (Exception)
{
agent.Error("post compile type:{0} error", type.FullName);
s_logger.Error("post compile type:{0} error", type.FullName);
throw;
}
}
// 丑陋. 怎么写更好?
// 递归 设置DefBean及DefField 的 IsMultiRow
var multiRowBeans = new HashSet<DefBean>();
for (bool anyMark = true; anyMark;)
{
anyMark = false;
foreach (var type in this.Types.Values)
{
if (type is DefBean beanType && !beanType.IsMultiRow)
{
bool isMultiRows;
if (beanType.IsNotAbstractType)
{
isMultiRows = beanType.HierarchyFields.Any(f => ((DefField)f).ComputeIsMultiRow());
}
else
{
isMultiRows = beanType.HierarchyNotAbstractChildren.Any(c => ((DefBean)c).IsMultiRow);
}
if (isMultiRows)
{
beanType.IsMultiRow = true;
//s_logger.Info("bean:{bean} is multi row", beanType.FullName);
anyMark = true;
}
}
}
}
}
}
}