- 支持 主版本+分支版本的 多分支数据合并,用于发布多地区版本极其有用
parent
e9166ac462
commit
9e4ba72950
|
|
@ -53,8 +53,8 @@ Luban适合有以下需求的开发者:
|
||||||
- 支持res资源标记。可以一键导出配置中引用的所有资源列表(icon,ui,assetbundle等等)
|
- 支持res资源标记。可以一键导出配置中引用的所有资源列表(icon,ui,assetbundle等等)
|
||||||
- 生成代码良好模块化。
|
- 生成代码良好模块化。
|
||||||
- **支持文本静态本地化。导出时所有text类型数据正确替换为最终的本地化字符串。**
|
- **支持文本静态本地化。导出时所有text类型数据正确替换为最终的本地化字符串。**
|
||||||
|
- **支持main + braches 多地区版本数据。对于需要针对不同地区有部分差异配置的海外项目非常有用。
|
||||||
- **[TODO] 支持文本动态本地化。运行时动态切换所有text类型数据为目标本地化字符串。**
|
- **[TODO] 支持文本动态本地化。运行时动态切换所有text类型数据为目标本地化字符串。**
|
||||||
- **[TODO] 支持main + braches 多地区版本数据。对于需要针对不同地区有部分差异配置的海外项目非常有用。**
|
|
||||||
- 支持主流的游戏开发语言
|
- 支持主流的游戏开发语言
|
||||||
- c++ (11+)
|
- c++ (11+)
|
||||||
- c# (.net framework 4+. dotnet core 3+)
|
- c# (.net framework 4+. dotnet core 3+)
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -6,6 +6,10 @@
|
||||||
<group name="e" default="1"/> editor分组
|
<group name="e" default="1"/> editor分组
|
||||||
|
|
||||||
<import name="."/>
|
<import name="."/>
|
||||||
|
|
||||||
|
<branch name="en"/>
|
||||||
|
<branch name="jp"/>
|
||||||
|
<branch name="cn"/>
|
||||||
|
|
||||||
<service name="server" manager="Tables" group="s"/>
|
<service name="server" manager="Tables" group="s"/>
|
||||||
<service name="client" manager="Tables" group="c"/>
|
<service name="client" manager="Tables" group="c"/>
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@
|
||||||
<var name="k15" type="array,DemoDynamic" sep=","/>
|
<var name="k15" type="array,DemoDynamic" sep=","/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<table name="TbFullTypes" index="x3" value="DemoType2" input="test/full_type.xlsx"/> 最常见的普通 key-value表
|
<table name="TbFullTypes" index="x3" value="DemoType2" input="test/full_type.xlsx" branch_input="cn:test/full_type_cn1.xlsx,test/full_type_cn2.xlsx|en:texx/full_type_en.xlsx"/> 最常见的普通 key-value表
|
||||||
|
|
||||||
<bean name="DateTimeRange" sep=";">
|
<bean name="DateTimeRange" sep=";">
|
||||||
<var name="start_time" type="datetime"/>
|
<var name="start_time" type="datetime"/>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
..\src\Luban.Client\bin\Debug\net5.0\Luban.Client.exe ^
|
||||||
|
-h %LUBAN_SERVER_IP% ^
|
||||||
|
-j cfg ^
|
||||||
|
-- ^
|
||||||
|
-d Defines/__root__.xml ^
|
||||||
|
--input_data_dir Datas ^
|
||||||
|
--output_data_dir output_lua ^
|
||||||
|
-s client ^
|
||||||
|
--gen_types data_lua ^
|
||||||
|
--export_test_data ^
|
||||||
|
--branch cn ^
|
||||||
|
--branch_input_data_dir Datas/l10n/cn
|
||||||
|
|
||||||
|
pause
|
||||||
|
|
@ -12,6 +12,8 @@ namespace Luban.Job.Cfg.Datas
|
||||||
|
|
||||||
public string Source { get; }
|
public string Source { get; }
|
||||||
|
|
||||||
|
public int Index { get; set; }
|
||||||
|
|
||||||
public Record(DBean data, string source)
|
public Record(DBean data, string source)
|
||||||
{
|
{
|
||||||
Data = data;
|
Data = data;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using Luban.Common.Utils;
|
using Luban.Common.Utils;
|
||||||
using Luban.Config.Common.RawDefs;
|
using Luban.Job.Cfg.RawDefs;
|
||||||
using Luban.Job.Common.Defs;
|
using Luban.Job.Common.Defs;
|
||||||
using Luban.Job.Common.RawDefs;
|
using Luban.Job.Common.RawDefs;
|
||||||
using Luban.Server.Common;
|
using Luban.Server.Common;
|
||||||
|
|
@ -14,6 +14,8 @@ namespace Luban.Job.Cfg.Defs
|
||||||
{
|
{
|
||||||
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
|
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
private readonly List<Branch> _branches = new();
|
||||||
|
|
||||||
private readonly List<Table> _cfgTables = new List<Table>();
|
private readonly List<Table> _cfgTables = new List<Table>();
|
||||||
|
|
||||||
private readonly List<Service> _cfgServices = new List<Service>();
|
private readonly List<Service> _cfgServices = new List<Service>();
|
||||||
|
|
@ -24,11 +26,13 @@ namespace Luban.Job.Cfg.Defs
|
||||||
|
|
||||||
public CfgDefLoader(RemoteAgent agent) : base(agent)
|
public CfgDefLoader(RemoteAgent agent) : base(agent)
|
||||||
{
|
{
|
||||||
|
RegisterRootDefineHandler("branch", AddBranch);
|
||||||
RegisterRootDefineHandler("service", AddService);
|
RegisterRootDefineHandler("service", AddService);
|
||||||
RegisterRootDefineHandler("group", AddGroup);
|
RegisterRootDefineHandler("group", AddGroup);
|
||||||
|
|
||||||
RegisterModuleDefineHandler("table", AddTable);
|
RegisterModuleDefineHandler("table", AddTable);
|
||||||
|
|
||||||
|
|
||||||
IsBeanFieldMustDefineId = false;
|
IsBeanFieldMustDefineId = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,6 +41,7 @@ namespace Luban.Job.Cfg.Defs
|
||||||
return new Defines()
|
return new Defines()
|
||||||
{
|
{
|
||||||
TopModule = TopModule,
|
TopModule = TopModule,
|
||||||
|
Branches = _branches,
|
||||||
Consts = this._consts,
|
Consts = this._consts,
|
||||||
Enums = _enums,
|
Enums = _enums,
|
||||||
Beans = _beans,
|
Beans = _beans,
|
||||||
|
|
@ -47,6 +52,21 @@ namespace Luban.Job.Cfg.Defs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static readonly List<string> _branchRequireAttrs = new List<string> { "name" };
|
||||||
|
private void AddBranch(XElement e)
|
||||||
|
{
|
||||||
|
var branchName = e.Attribute("name").Value;
|
||||||
|
if (string.IsNullOrWhiteSpace(branchName))
|
||||||
|
{
|
||||||
|
throw new Exception("branch 属性name不能为空");
|
||||||
|
}
|
||||||
|
if (this._branches.Any(b => b.Name == branchName))
|
||||||
|
{
|
||||||
|
throw new Exception($"branch {branchName} 重复");
|
||||||
|
}
|
||||||
|
_branches.Add(new Branch(branchName));
|
||||||
|
}
|
||||||
|
|
||||||
private static readonly List<string> _groupOptionalAttrs = new List<string> { "default" };
|
private static readonly List<string> _groupOptionalAttrs = new List<string> { "default" };
|
||||||
private static readonly List<string> _groupRequireAttrs = new List<string> { "name" };
|
private static readonly List<string> _groupRequireAttrs = new List<string> { "name" };
|
||||||
|
|
||||||
|
|
@ -132,7 +152,7 @@ namespace Luban.Job.Cfg.Defs
|
||||||
_cfgServices.Add(new Service() { Name = name, Manager = manager, Groups = groups, Refs = refs });
|
_cfgServices.Add(new Service() { Name = name, Manager = manager, Groups = groups, Refs = refs });
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<string> _tableOptionalAttrs = new List<string> { "index", "mode", "group" };
|
private readonly List<string> _tableOptionalAttrs = new List<string> { "index", "mode", "group", "branch_input" };
|
||||||
private readonly List<string> _tableRequireAttrs = new List<string> { "name", "value", "input" };
|
private readonly List<string> _tableRequireAttrs = new List<string> { "name", "value", "input" };
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -236,6 +256,24 @@ namespace Luban.Job.Cfg.Defs
|
||||||
}
|
}
|
||||||
p.InputFiles.AddRange(XmlUtil.GetRequiredAttribute(e, "input").Split(','));
|
p.InputFiles.AddRange(XmlUtil.GetRequiredAttribute(e, "input").Split(','));
|
||||||
|
|
||||||
|
var branchInputAttr = e.Attribute("branch_input");
|
||||||
|
if (branchInputAttr != null)
|
||||||
|
{
|
||||||
|
foreach (var subBranchStr in branchInputAttr.Value.Split('|').Select(s => s.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)))
|
||||||
|
{
|
||||||
|
var nameAndDirs = subBranchStr.Split(':');
|
||||||
|
if (nameAndDirs.Length != 2)
|
||||||
|
{
|
||||||
|
throw new Exception($"定义文件:{CurImportFile} table:{p.Name} branch_input:{subBranchStr} 定义不合法");
|
||||||
|
}
|
||||||
|
var branchDirs = nameAndDirs[1].Split(',', ';').ToList();
|
||||||
|
if (!p.BranchInputFiles.TryAdd(nameAndDirs[0], branchDirs))
|
||||||
|
{
|
||||||
|
throw new Exception($"定义文件:{CurImportFile} table:{p.Name} branch_input:{subBranchStr} 子branch:{nameAndDirs[0]} 重复");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!_name2CfgTable.TryAdd(p.Name, p))
|
if (!_name2CfgTable.TryAdd(p.Name, p))
|
||||||
{
|
{
|
||||||
var exist = _name2CfgTable[p.Name];
|
var exist = _name2CfgTable[p.Name];
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using Luban.Config.Common.RawDefs;
|
|
||||||
using Luban.Job.Cfg.Datas;
|
using Luban.Job.Cfg.Datas;
|
||||||
using Luban.Job.Cfg.l10n;
|
using Luban.Job.Cfg.l10n;
|
||||||
|
using Luban.Job.Cfg.RawDefs;
|
||||||
using Luban.Job.Cfg.TypeVisitors;
|
using Luban.Job.Cfg.TypeVisitors;
|
||||||
using Luban.Job.Common.Defs;
|
using Luban.Job.Common.Defs;
|
||||||
using Luban.Server.Common;
|
using Luban.Server.Common;
|
||||||
|
|
@ -11,12 +11,31 @@ using System.Linq;
|
||||||
|
|
||||||
namespace Luban.Job.Cfg.Defs
|
namespace Luban.Job.Cfg.Defs
|
||||||
{
|
{
|
||||||
|
public class TableDataInfo
|
||||||
|
{
|
||||||
|
public List<Record> MainRecords { get; }
|
||||||
|
|
||||||
|
public List<Record> BranchRecords { get; }
|
||||||
|
|
||||||
|
public List<Record> FinalRecords { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<DType, Record> FinalRecordMap { get; set; }
|
||||||
|
|
||||||
|
public TableDataInfo(List<Record> mainRecords, List<Record> branchRecords)
|
||||||
|
{
|
||||||
|
MainRecords = mainRecords;
|
||||||
|
BranchRecords = branchRecords;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class DefAssembly : DefAssemblyBase
|
public class DefAssembly : DefAssemblyBase
|
||||||
{
|
{
|
||||||
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
|
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
public Service CfgTargetService { get; private set; }
|
public Service CfgTargetService { get; private set; }
|
||||||
|
|
||||||
|
public Branch TargetBranch { get; private set; }
|
||||||
|
|
||||||
public TimeZoneInfo TimeZone { get; }
|
public TimeZoneInfo TimeZone { get; }
|
||||||
|
|
||||||
public DefAssembly(TimeZoneInfo timezone)
|
public DefAssembly(TimeZoneInfo timezone)
|
||||||
|
|
@ -33,10 +52,11 @@ namespace Luban.Job.Cfg.Defs
|
||||||
return groups.Any(g => CfgTargetService.Groups.Contains(g));
|
return groups.Any(g => CfgTargetService.Groups.Contains(g));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly List<Branch> _branches = new List<Branch>();
|
||||||
|
|
||||||
private readonly List<Service> _cfgServices = new List<Service>();
|
private readonly List<Service> _cfgServices = new List<Service>();
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, List<Record>> _recordsByTables = new();
|
private readonly ConcurrentDictionary<string, TableDataInfo> _recordsByTables = new();
|
||||||
private readonly ConcurrentDictionary<string, Dictionary<DType, Record>> _recordsMapByTables = new();
|
|
||||||
|
|
||||||
public Dictionary<string, DefTable> CfgTables { get; } = new Dictionary<string, DefTable>();
|
public Dictionary<string, DefTable> CfgTables { get; } = new Dictionary<string, DefTable>();
|
||||||
|
|
||||||
|
|
@ -52,6 +72,11 @@ namespace Luban.Job.Cfg.Defs
|
||||||
NotConvertTextSet = new NotConvertTextSet();
|
NotConvertTextSet = new NotConvertTextSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Branch GetBranch(string name)
|
||||||
|
{
|
||||||
|
return _branches.Find(b => b.Name == name);
|
||||||
|
}
|
||||||
|
|
||||||
public void AddCfgTable(DefTable table)
|
public void AddCfgTable(DefTable table)
|
||||||
{
|
{
|
||||||
if (!CfgTables.TryAdd(table.FullName, table))
|
if (!CfgTables.TryAdd(table.FullName, table))
|
||||||
|
|
@ -65,24 +90,24 @@ namespace Luban.Job.Cfg.Defs
|
||||||
return CfgTables.TryGetValue(name, out var t) ? t : null;
|
return CfgTables.TryGetValue(name, out var t) ? t : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddDataTable(DefTable table, List<Record> records)
|
public void AddDataTable(DefTable table, List<Record> mainRecords, List<Record> branchRecords)
|
||||||
{
|
{
|
||||||
_recordsByTables[table.FullName] = records;
|
_recordsByTables[table.FullName] = new TableDataInfo(mainRecords, branchRecords);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetDataTableMap(DefTable table, Dictionary<DType, Record> recordMap)
|
//public void SetDataTableMap(DefTable table, Dictionary<DType, Record> recordMap)
|
||||||
{
|
//{
|
||||||
_recordsMapByTables[table.FullName] = recordMap;
|
// _recordsByTables[table.FullName].FinalRecordMap = recordMap;
|
||||||
}
|
//}
|
||||||
|
|
||||||
public List<Record> GetTableDataList(DefTable table)
|
public List<Record> GetTableDataList(DefTable table)
|
||||||
{
|
{
|
||||||
return _recordsByTables[table.FullName];
|
return _recordsByTables[table.FullName].FinalRecords;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<DType, Record> GetTableDataMap(DefTable table)
|
public TableDataInfo GetTableDataInfo(DefTable table)
|
||||||
{
|
{
|
||||||
return _recordsMapByTables[table.FullName];
|
return _recordsByTables[table.FullName];
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DefTable> GetExportTables()
|
public List<DefTable> GetExportTables()
|
||||||
|
|
@ -122,7 +147,7 @@ namespace Luban.Job.Cfg.Defs
|
||||||
return refTypes.Values.ToList();
|
return refTypes.Values.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Load(string outputService, Defines defines, RemoteAgent agent)
|
public void Load(string outputService, string branchName, Defines defines, RemoteAgent agent)
|
||||||
{
|
{
|
||||||
this.Agent = agent;
|
this.Agent = agent;
|
||||||
SupportDatetimeType = true;
|
SupportDatetimeType = true;
|
||||||
|
|
@ -136,6 +161,17 @@ namespace Luban.Job.Cfg.Defs
|
||||||
throw new ArgumentException($"service:{outputService} not exists");
|
throw new ArgumentException($"service:{outputService} not exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(branchName))
|
||||||
|
{
|
||||||
|
TargetBranch = defines.Branches.Find(b => b.Name == branchName);
|
||||||
|
if (TargetBranch == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"branch {branchName} not in valid branch set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._branches.AddRange(defines.Branches);
|
||||||
|
|
||||||
foreach (var c in defines.Consts)
|
foreach (var c in defines.Consts)
|
||||||
{
|
{
|
||||||
AddType(new DefConst(c));
|
AddType(new DefConst(c));
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using Luban.Common.Utils;
|
using Luban.Common.Utils;
|
||||||
using Luban.Config.Common.RawDefs;
|
using Luban.Job.Cfg.RawDefs;
|
||||||
using Luban.Job.Cfg.TypeVisitors;
|
using Luban.Job.Cfg.TypeVisitors;
|
||||||
using Luban.Job.Common.Defs;
|
using Luban.Job.Common.Defs;
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using Luban.Common.Utils;
|
using Luban.Common.Utils;
|
||||||
using Luban.Config.Common.RawDefs;
|
using Luban.Job.Cfg.RawDefs;
|
||||||
using Luban.Job.Cfg.Validators;
|
using Luban.Job.Cfg.Validators;
|
||||||
using Luban.Job.Common.Defs;
|
using Luban.Job.Common.Defs;
|
||||||
using Luban.Job.Common.Types;
|
using Luban.Job.Common.Types;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using Luban.Config.Common.RawDefs;
|
using Luban.Job.Cfg.RawDefs;
|
||||||
using Luban.Job.Common.Types;
|
using Luban.Job.Common.Types;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
@ -19,6 +19,7 @@ namespace Luban.Job.Cfg.Defs
|
||||||
Mode = b.Mode;
|
Mode = b.Mode;
|
||||||
InputFiles = b.InputFiles;
|
InputFiles = b.InputFiles;
|
||||||
Groups = b.Groups;
|
Groups = b.Groups;
|
||||||
|
_branchInputFiles = b.BranchInputFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -36,6 +37,8 @@ namespace Luban.Job.Cfg.Defs
|
||||||
|
|
||||||
public List<string> InputFiles { get; }
|
public List<string> InputFiles { get; }
|
||||||
|
|
||||||
|
private readonly Dictionary<string, List<string>> _branchInputFiles;
|
||||||
|
|
||||||
public List<string> Groups { get; }
|
public List<string> Groups { get; }
|
||||||
|
|
||||||
public TType KeyTType { get; private set; }
|
public TType KeyTType { get; private set; }
|
||||||
|
|
@ -62,11 +65,24 @@ namespace Luban.Job.Cfg.Defs
|
||||||
|
|
||||||
public string JsonOutputDataFile => $"{FullName}.json";
|
public string JsonOutputDataFile => $"{FullName}.json";
|
||||||
|
|
||||||
|
public List<string> GetBranchInputFiles(string branchName)
|
||||||
|
{
|
||||||
|
return _branchInputFiles.GetValueOrDefault(branchName);
|
||||||
|
}
|
||||||
|
|
||||||
public override void Compile()
|
public override void Compile()
|
||||||
{
|
{
|
||||||
var pass = Assembly;
|
var ass = Assembly;
|
||||||
|
|
||||||
if ((ValueTType = (TBean)pass.CreateType(Namespace, ValueType)) == null)
|
foreach (var branchName in _branchInputFiles.Keys)
|
||||||
|
{
|
||||||
|
if (ass.GetBranch(branchName) == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"table:{FullName} branch_input branch:{branchName} 不存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ValueTType = (TBean)ass.CreateType(Namespace, ValueType)) == null)
|
||||||
{
|
{
|
||||||
throw new Exception($"table:{FullName} 的 value类型:{ValueType} 不存在");
|
throw new Exception($"table:{FullName} 的 value类型:{ValueType} 不存在");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ namespace Luban.Job.Cfg
|
||||||
[Option("export_test_data", Required = false, HelpText = "export test data")]
|
[Option("export_test_data", Required = false, HelpText = "export test data")]
|
||||||
public bool ExportTestData { get; set; } = false;
|
public bool ExportTestData { get; set; } = false;
|
||||||
|
|
||||||
[Option('t', "i10n_timezone", Required = false, HelpText = "timezone")]
|
[Option('t', "l10n_timezone", Required = false, HelpText = "timezone")]
|
||||||
public string TimeZone { get; set; }
|
public string TimeZone { get; set; }
|
||||||
|
|
||||||
[Option("input_l10n_text_files", Required = false, HelpText = "input l10n text table files. can be multi, sep by ','")]
|
[Option("input_l10n_text_files", Required = false, HelpText = "input l10n text table files. can be multi, sep by ','")]
|
||||||
|
|
@ -66,6 +66,12 @@ namespace Luban.Job.Cfg
|
||||||
|
|
||||||
[Option("output_l10n_not_converted_text_file", Required = false, HelpText = "the file save not converted l10n texts.")]
|
[Option("output_l10n_not_converted_text_file", Required = false, HelpText = "the file save not converted l10n texts.")]
|
||||||
public string OutputNotConvertTextFile { get; set; }
|
public string OutputNotConvertTextFile { get; set; }
|
||||||
|
|
||||||
|
[Option("branch", Required = false, HelpText = "branch name")]
|
||||||
|
public string BranchName { get; set; }
|
||||||
|
|
||||||
|
[Option("branch_input_data_dir", Required = false, HelpText = "branch input data root dir")]
|
||||||
|
public string BranchInputDataDir { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICodeRender CreateCodeRender(string genType)
|
private ICodeRender CreateCodeRender(string genType)
|
||||||
|
|
@ -95,7 +101,7 @@ namespace Luban.Job.Cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static bool TryParseArg(List<string> args, out GenArgs result, out string errMsg)
|
private static bool TryParseArg(List<string> args, out GenArgs options, out string errMsg)
|
||||||
{
|
{
|
||||||
var helpWriter = new StringWriter();
|
var helpWriter = new StringWriter();
|
||||||
var parser = new Parser(ps =>
|
var parser = new Parser(ps =>
|
||||||
|
|
@ -106,19 +112,19 @@ namespace Luban.Job.Cfg
|
||||||
if (parseResult.Tag == ParserResultType.NotParsed)
|
if (parseResult.Tag == ParserResultType.NotParsed)
|
||||||
{
|
{
|
||||||
errMsg = helpWriter.ToString();
|
errMsg = helpWriter.ToString();
|
||||||
result = null;
|
options = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = (parseResult as Parsed<GenArgs>).Value;
|
options = (parseResult as Parsed<GenArgs>).Value;
|
||||||
errMsg = null;
|
errMsg = null;
|
||||||
|
|
||||||
string inputDataDir = result.InputDataDir;
|
string inputDataDir = options.InputDataDir;
|
||||||
string outputCodeDir = result.OutputCodeDir;
|
string outputCodeDir = options.OutputCodeDir;
|
||||||
string outputDataDir = result.OutputDataDir;
|
string outputDataDir = options.OutputDataDir;
|
||||||
|
|
||||||
var genTypes = result.GenType.Split(',').Select(s => s.Trim()).ToList();
|
var genTypes = options.GenType.Split(',').Select(s => s.Trim()).ToList();
|
||||||
|
|
||||||
if (genTypes.Any(t => t.StartsWith("code_", StringComparison.Ordinal)) && string.IsNullOrWhiteSpace(outputCodeDir))
|
if (genTypes.Any(t => t.StartsWith("code_", StringComparison.Ordinal)) && string.IsNullOrWhiteSpace(outputCodeDir))
|
||||||
{
|
{
|
||||||
|
|
@ -137,24 +143,30 @@ namespace Luban.Job.Cfg
|
||||||
errMsg = "--outputdatadir missing";
|
errMsg = "--outputdatadir missing";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (genTypes.Contains("data_resources") && string.IsNullOrWhiteSpace(result.OutputDataResourceListFile))
|
if (genTypes.Contains("data_resources") && string.IsNullOrWhiteSpace(options.OutputDataResourceListFile))
|
||||||
{
|
{
|
||||||
errMsg = "--output_data_resource_list_file missing";
|
errMsg = "--output_data_resource_list_file missing";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (genTypes.Contains("data_json_monolithic") && string.IsNullOrWhiteSpace(result.OutputDataJsonMonolithicFile))
|
if (genTypes.Contains("data_json_monolithic") && string.IsNullOrWhiteSpace(options.OutputDataJsonMonolithicFile))
|
||||||
{
|
{
|
||||||
errMsg = "--output_data_json_monolithic_file missing";
|
errMsg = "--output_data_json_monolithic_file missing";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(result.InputTextTableFiles) ^ string.IsNullOrWhiteSpace(result.OutputNotConvertTextFile))
|
if (string.IsNullOrWhiteSpace(options.InputTextTableFiles) ^ string.IsNullOrWhiteSpace(options.OutputNotConvertTextFile))
|
||||||
{
|
{
|
||||||
errMsg = "--input_l10n_text_files must be provided with --output_l10n_not_converted_text_file";
|
errMsg = "--input_l10n_text_files must be provided with --output_l10n_not_converted_text_file";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(options.BranchName) ^ string.IsNullOrWhiteSpace(options.BranchInputDataDir))
|
||||||
|
{
|
||||||
|
errMsg = "--branch must be provided with --branch_input_data_dir";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -197,7 +209,7 @@ namespace Luban.Job.Cfg
|
||||||
|
|
||||||
var ass = new DefAssembly(timeZoneInfo);
|
var ass = new DefAssembly(timeZoneInfo);
|
||||||
|
|
||||||
ass.Load(args.Service, rawDefines, agent);
|
ass.Load(args.Service, args.BranchName, rawDefines, agent);
|
||||||
|
|
||||||
var targetService = ass.CfgTargetService;
|
var targetService = ass.CfgTargetService;
|
||||||
|
|
||||||
|
|
@ -216,7 +228,7 @@ namespace Luban.Job.Cfg
|
||||||
hasLoadCfgData = true;
|
hasLoadCfgData = true;
|
||||||
var timer = new ProfileTimer();
|
var timer = new ProfileTimer();
|
||||||
timer.StartPhase("load config data");
|
timer.StartPhase("load config data");
|
||||||
await DataLoaderUtil.LoadCfgDataAsync(agent, ass, args.InputDataDir, args.ExportTestData);
|
await DataLoaderUtil.LoadCfgDataAsync(agent, ass, args.InputDataDir, args.BranchName, args.BranchInputDataDir, args.ExportTestData);
|
||||||
timer.EndPhaseAndLog();
|
timer.EndPhaseAndLog();
|
||||||
|
|
||||||
if (needL10NTextConvert)
|
if (needL10NTextConvert)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Luban.Job.Cfg.RawDefs
|
||||||
|
{
|
||||||
|
public class Branch
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public Branch(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using Luban.Job.Common.RawDefs;
|
using Luban.Job.Common.RawDefs;
|
||||||
|
|
||||||
namespace Luban.Config.Common.RawDefs
|
namespace Luban.Job.Cfg.RawDefs
|
||||||
{
|
{
|
||||||
public class CfgBean : Bean
|
public class CfgBean : Bean
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using Luban.Job.Common.RawDefs;
|
using Luban.Job.Common.RawDefs;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Luban.Config.Common.RawDefs
|
namespace Luban.Job.Cfg.RawDefs
|
||||||
{
|
{
|
||||||
|
|
||||||
public class Validator
|
public class Validator
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
|
using Luban.Job.Cfg.RawDefs;
|
||||||
using Luban.Job.Common.RawDefs;
|
using Luban.Job.Common.RawDefs;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Luban.Config.Common.RawDefs
|
namespace Luban.Job.Cfg.RawDefs
|
||||||
{
|
{
|
||||||
public class Defines
|
public class Defines
|
||||||
{
|
{
|
||||||
public string TopModule { get; set; } = "";
|
public string TopModule { get; set; } = "";
|
||||||
|
|
||||||
|
public List<Branch> Branches { get; set; } = new List<Branch>();
|
||||||
|
|
||||||
public List<Bean> Beans { get; set; } = new List<Bean>();
|
public List<Bean> Beans { get; set; } = new List<Bean>();
|
||||||
|
|
||||||
public List<Const> Consts { get; set; } = new List<Const>();
|
public List<Const> Consts { get; set; } = new List<Const>();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Luban.Config.Common.RawDefs
|
namespace Luban.Job.Cfg.RawDefs
|
||||||
{
|
{
|
||||||
public class Group
|
public class Group
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Luban.Config.Common.RawDefs
|
namespace Luban.Job.Cfg.RawDefs
|
||||||
{
|
{
|
||||||
public class Service
|
public class Service
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Luban.Config.Common.RawDefs
|
namespace Luban.Job.Cfg.RawDefs
|
||||||
{
|
{
|
||||||
public enum ETableMode
|
public enum ETableMode
|
||||||
{
|
{
|
||||||
|
|
@ -35,5 +35,7 @@ namespace Luban.Config.Common.RawDefs
|
||||||
public List<string> Groups { get; set; } = new List<string>();
|
public List<string> Groups { get; set; } = new List<string>();
|
||||||
|
|
||||||
public List<string> InputFiles { get; set; } = new List<string>();
|
public List<string> InputFiles { get; set; } = new List<string>();
|
||||||
|
|
||||||
|
public Dictionary<string, List<string>> BranchInputFiles { get; set; } = new Dictionary<string, List<string>>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using Luban.Config.Common.RawDefs;
|
|
||||||
using Luban.Job.Cfg.Defs;
|
using Luban.Job.Cfg.Defs;
|
||||||
|
using Luban.Job.Cfg.RawDefs;
|
||||||
using Luban.Job.Common.Defs;
|
using Luban.Job.Common.Defs;
|
||||||
using Luban.Job.Common.Types;
|
using Luban.Job.Common.Types;
|
||||||
using Luban.Job.Common.TypeVisitors;
|
using Luban.Job.Common.TypeVisitors;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using Bright.Serialization;
|
using Bright.Serialization;
|
||||||
using Luban.Config.Common.RawDefs;
|
|
||||||
using Luban.Job.Cfg.Datas;
|
using Luban.Job.Cfg.Datas;
|
||||||
using Luban.Job.Cfg.DataVisitors;
|
using Luban.Job.Cfg.DataVisitors;
|
||||||
using Luban.Job.Cfg.Defs;
|
using Luban.Job.Cfg.Defs;
|
||||||
|
|
|
||||||
|
|
@ -71,16 +71,14 @@ namespace Luban.Job.Cfg.Utils
|
||||||
// return CollectInputFilesAsync(agent, table.InputFiles, dataDir)
|
// return CollectInputFilesAsync(agent, table.InputFiles, dataDir)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
public static async Task LoadTableAsync(RemoteAgent agent, DefTable table, string dataDir, bool exportTestData)
|
public static async Task GenerateLoadRecordFromFileTasksAsync(RemoteAgent agent, DefTable table, string dataDir, List<string> inputFiles2, bool exportTestData, List<Task<List<Record>>> tasks)
|
||||||
{
|
{
|
||||||
var tasks = new List<Task<List<Record>>>();
|
var inputFileInfos = await CollectInputFilesAsync(agent, inputFiles2, dataDir);
|
||||||
|
|
||||||
var inputFiles = await CollectInputFilesAsync(agent, table.InputFiles, dataDir);
|
|
||||||
|
|
||||||
// check cache (table, exporttestdata) -> (list<InputFileInfo>, List<DType>)
|
// check cache (table, exporttestdata) -> (list<InputFileInfo>, List<DType>)
|
||||||
// (md5, sheetName,exportTestData) -> (value_type, List<DType>)
|
// (md5, sheetName,exportTestData) -> (value_type, List<DType>)
|
||||||
|
|
||||||
foreach (var file in inputFiles)
|
foreach (var file in inputFileInfos)
|
||||||
{
|
{
|
||||||
var actualFile = file.ActualFile;
|
var actualFile = file.ActualFile;
|
||||||
//s_logger.Info("== get input file:{file} actualFile:{actual}", file, actualFile);
|
//s_logger.Info("== get input file:{file} actualFile:{actual}", file, actualFile);
|
||||||
|
|
@ -103,21 +101,52 @@ namespace Luban.Job.Cfg.Utils
|
||||||
return res;
|
return res;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
var records = new List<Record>(tasks.Count);
|
|
||||||
foreach (var task in tasks)
|
|
||||||
{
|
|
||||||
records.AddRange(await task);
|
|
||||||
}
|
|
||||||
|
|
||||||
s_logger.Trace("== load recors. count:{count}", records.Count);
|
|
||||||
|
|
||||||
table.Assembly.AddDataTable(table, records);
|
|
||||||
|
|
||||||
s_logger.Trace("table:{name} record num:{num}", table.FullName, records.Count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task LoadCfgDataAsync(RemoteAgent agent, DefAssembly ass, string dataDir, bool exportTestData)
|
public static async Task LoadTableAsync(RemoteAgent agent, DefTable table, string dataDir, string branchName, string branchDataDir, bool exportTestData)
|
||||||
|
{
|
||||||
|
var mainLoadTasks = new List<Task<List<Record>>>();
|
||||||
|
var mainGenerateTask = GenerateLoadRecordFromFileTasksAsync(agent, table, dataDir, table.InputFiles, exportTestData, mainLoadTasks);
|
||||||
|
|
||||||
|
var branchLoadTasks = new List<Task<List<Record>>>();
|
||||||
|
|
||||||
|
Task branchGenerateTask = null;
|
||||||
|
if (!string.IsNullOrWhiteSpace(branchName))
|
||||||
|
{
|
||||||
|
var branchInputFiles = table.GetBranchInputFiles(branchName);
|
||||||
|
if (branchInputFiles != null)
|
||||||
|
{
|
||||||
|
branchGenerateTask = GenerateLoadRecordFromFileTasksAsync(agent, table, branchDataDir, branchInputFiles, exportTestData, branchLoadTasks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await mainGenerateTask;
|
||||||
|
|
||||||
|
var mainRecords = new List<Record>(256);
|
||||||
|
foreach (var task in mainLoadTasks)
|
||||||
|
{
|
||||||
|
mainRecords.AddRange(await task);
|
||||||
|
}
|
||||||
|
s_logger.Trace("== load main records. count:{count}", mainRecords.Count);
|
||||||
|
|
||||||
|
List<Record> branchRecords = null;
|
||||||
|
if (branchGenerateTask != null)
|
||||||
|
{
|
||||||
|
branchRecords = new List<Record>(64);
|
||||||
|
await branchGenerateTask;
|
||||||
|
foreach (var task in branchLoadTasks)
|
||||||
|
{
|
||||||
|
branchRecords.AddRange(await task);
|
||||||
|
}
|
||||||
|
s_logger.Trace("== load branch records. count:{count}", branchRecords.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
table.Assembly.AddDataTable(table, mainRecords, branchRecords);
|
||||||
|
|
||||||
|
s_logger.Trace("table:{name} record num:{num}", table.FullName, mainRecords.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task LoadCfgDataAsync(RemoteAgent agent, DefAssembly ass, string dataDir, string branchName, string branchDataDir, bool exportTestData)
|
||||||
{
|
{
|
||||||
var ctx = agent;
|
var ctx = agent;
|
||||||
List<DefTable> exportTables = ass.Types.Values.Where(t => t is DefTable ct && ct.NeedExport).Select(t => (DefTable)t).ToList();
|
List<DefTable> exportTables = ass.Types.Values.Where(t => t is DefTable ct && ct.NeedExport).Select(t => (DefTable)t).ToList();
|
||||||
|
|
@ -130,7 +159,7 @@ namespace Luban.Job.Cfg.Utils
|
||||||
genDataTasks.Add(Task.Run(async () =>
|
genDataTasks.Add(Task.Run(async () =>
|
||||||
{
|
{
|
||||||
long beginTime = TimeUtil.NowMillis;
|
long beginTime = TimeUtil.NowMillis;
|
||||||
await LoadTableAsync(agent, c, dataDir, exportTestData);
|
await LoadTableAsync(agent, c, dataDir, branchName, branchDataDir, exportTestData);
|
||||||
long endTime = TimeUtil.NowMillis;
|
long endTime = TimeUtil.NowMillis;
|
||||||
if (endTime - beginTime > 100)
|
if (endTime - beginTime > 100)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
using Luban.Common.Utils;
|
using Luban.Common.Utils;
|
||||||
using Luban.Config.Common.RawDefs;
|
|
||||||
using Luban.Job.Cfg.Datas;
|
using Luban.Job.Cfg.Datas;
|
||||||
using Luban.Job.Cfg.DataVisitors;
|
using Luban.Job.Cfg.DataVisitors;
|
||||||
using Luban.Job.Cfg.Defs;
|
using Luban.Job.Cfg.Defs;
|
||||||
|
using Luban.Job.Cfg.RawDefs;
|
||||||
using Luban.Job.Cfg.Utils;
|
using Luban.Job.Cfg.Utils;
|
||||||
using Luban.Job.Cfg.Validators;
|
using Luban.Job.Cfg.Validators;
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -27,6 +27,8 @@ namespace Luban.Job.Cfg
|
||||||
|
|
||||||
public class ValidatorContext
|
public class ValidatorContext
|
||||||
{
|
{
|
||||||
|
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static ValidatorVisitor t_visitor;
|
private static ValidatorVisitor t_visitor;
|
||||||
|
|
||||||
|
|
@ -67,8 +69,7 @@ namespace Luban.Job.Cfg
|
||||||
{
|
{
|
||||||
tasks.Add(Task.Run(() =>
|
tasks.Add(Task.Run(() =>
|
||||||
{
|
{
|
||||||
var records = t.Assembly.GetTableDataList(t);
|
ValidateTableModeIndex(t);
|
||||||
ValidateTableModeIndex(t, records);
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
await Task.WhenAll(tasks);
|
await Task.WhenAll(tasks);
|
||||||
|
|
@ -171,58 +172,134 @@ namespace Luban.Job.Cfg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidateTableModeIndex(DefTable table, List<Record> records)
|
private void ValidateTableModeIndex(DefTable table)
|
||||||
{
|
{
|
||||||
var recordMap = new Dictionary<DType, Record>();
|
var tableDataInfo = Assembly.GetTableDataInfo(table);
|
||||||
|
|
||||||
|
List<Record> mainRecords = tableDataInfo.MainRecords;
|
||||||
|
List<Record> branchRecords = tableDataInfo.BranchRecords;
|
||||||
|
|
||||||
|
// 这么大费周张是为了保证被覆盖的id仍然保持原来的顺序,而不是出现在最后
|
||||||
|
int index = 0;
|
||||||
|
foreach (var r in mainRecords)
|
||||||
|
{
|
||||||
|
r.Index = index++;
|
||||||
|
}
|
||||||
|
if (branchRecords != null)
|
||||||
|
{
|
||||||
|
foreach (var r in branchRecords)
|
||||||
|
{
|
||||||
|
r.Index = index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var mainRecordMap = new Dictionary<DType, Record>();
|
||||||
|
|
||||||
switch (table.Mode)
|
switch (table.Mode)
|
||||||
{
|
{
|
||||||
case ETableMode.ONE:
|
case ETableMode.ONE:
|
||||||
{
|
{
|
||||||
if (records.Count != 1)
|
if (mainRecords.Count != 1)
|
||||||
{
|
{
|
||||||
throw new Exception($"配置表 {table.FullName} 是单值表 mode=one,但数据个数:{records.Count} != 1");
|
throw new Exception($"配置表 {table.FullName} 是单值表 mode=one,但主文件数据个数:{mainRecords.Count} != 1");
|
||||||
|
}
|
||||||
|
if (branchRecords != null && branchRecords.Count != 1)
|
||||||
|
{
|
||||||
|
throw new Exception($"配置表 {table.FullName} 是单值表 mode=one,但分支文件数据个数:{branchRecords.Count} != 1");
|
||||||
|
}
|
||||||
|
if (branchRecords != null)
|
||||||
|
{
|
||||||
|
mainRecords[0] = branchRecords[0];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ETableMode.MAP:
|
case ETableMode.MAP:
|
||||||
{
|
{
|
||||||
foreach (Record r in records)
|
foreach (Record r in mainRecords)
|
||||||
{
|
{
|
||||||
DType key = r.Data.Fields[table.IndexFieldIdIndex];
|
DType key = r.Data.Fields[table.IndexFieldIdIndex];
|
||||||
if (!recordMap.TryAdd(key, r))
|
if (!mainRecordMap.TryAdd(key, r))
|
||||||
{
|
{
|
||||||
throw new Exception($@"配置表 {table.FullName} 主键字段:{table.Index} 主键值:{key} 重复.
|
throw new Exception($@"配置表 {table.FullName} 主文件 主键字段:{table.Index} 主键值:{key} 重复.
|
||||||
记录1 来自文件:{r.Source}
|
记录1 来自文件:{r.Source}
|
||||||
记录2 来自文件:{recordMap[key].Source}
|
记录2 来自文件:{mainRecordMap[key].Source}
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (branchRecords != null)
|
||||||
|
{
|
||||||
|
var branchRecordMap = new Dictionary<DType, Record>();
|
||||||
|
foreach (Record r in branchRecords)
|
||||||
|
{
|
||||||
|
DType key = r.Data.Fields[table.IndexFieldIdIndex];
|
||||||
|
if (!branchRecordMap.TryAdd(key, r))
|
||||||
|
{
|
||||||
|
throw new Exception($@"配置表 {table.FullName} 分支文件 主键字段:{table.Index} 主键值:{key} 重复.
|
||||||
|
记录1 来自文件:{r.Source}
|
||||||
|
记录2 来自文件:{branchRecordMap[key].Source}
|
||||||
|
");
|
||||||
|
}
|
||||||
|
if (mainRecordMap.TryGetValue(key, out var old))
|
||||||
|
{
|
||||||
|
s_logger.Debug("配置表 {} 分支文件 主键:{} 覆盖 主文件记录", table.FullName, key);
|
||||||
|
mainRecords[old.Index] = r;
|
||||||
|
}
|
||||||
|
mainRecordMap[key] = r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ETableMode.BMAP:
|
case ETableMode.BMAP:
|
||||||
{
|
{
|
||||||
var twoKeyMap = new Dictionary<(DType, DType), Record>();
|
var mainTwoKeyMap = new Dictionary<(DType, DType), Record>();
|
||||||
foreach (Record r in records)
|
foreach (Record r in mainRecords)
|
||||||
{
|
{
|
||||||
DType key1 = r.Data.Fields[table.IndexFieldIdIndex1];
|
DType key1 = r.Data.Fields[table.IndexFieldIdIndex1];
|
||||||
DType key2 = r.Data.Fields[table.IndexFieldIdIndex2];
|
DType key2 = r.Data.Fields[table.IndexFieldIdIndex2];
|
||||||
if (!twoKeyMap.TryAdd((key1, key2), r))
|
if (!mainTwoKeyMap.TryAdd((key1, key2), r))
|
||||||
{
|
{
|
||||||
throw new Exception($@"配置表 {table.FullName} 主键字段:{table.Index} 主键值:({key1},{key2})重复.
|
throw new Exception($@"配置表 {table.FullName} 主文件 主键字段:{table.Index} 主键值:({key1},{key2})重复.
|
||||||
记录1 来自文件:{r.Source}
|
记录1 来自文件:{r.Source}
|
||||||
记录2 来自文件:{twoKeyMap[(key1, key2)].Source}
|
记录2 来自文件:{mainTwoKeyMap[(key1, key2)].Source}
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
// 目前不支持 双key索引检查,但支持主key索引检查.
|
// 目前不支持 双key索引检查,但支持主key索引检查.
|
||||||
// 所以至少塞入一个,让ref检查能通过
|
// 所以至少塞入一个,让ref检查能通过
|
||||||
recordMap[key1] = r;
|
mainRecordMap[key1] = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (branchRecords != null)
|
||||||
|
{
|
||||||
|
var branchTwoKeyMap = new Dictionary<(DType, DType), Record>();
|
||||||
|
foreach (Record r in branchRecords)
|
||||||
|
{
|
||||||
|
DType key1 = r.Data.Fields[table.IndexFieldIdIndex1];
|
||||||
|
DType key2 = r.Data.Fields[table.IndexFieldIdIndex2];
|
||||||
|
if (!branchTwoKeyMap.TryAdd((key1, key2), r))
|
||||||
|
{
|
||||||
|
throw new Exception($@"配置表 {table.FullName} 分支文件 主键字段:{table.Index} 主键值:({key1},{key2})重复.
|
||||||
|
记录1 来自文件:{r.Source}
|
||||||
|
记录2 来自文件:{branchTwoKeyMap[(key1, key2)].Source}
|
||||||
|
");
|
||||||
|
}
|
||||||
|
if (mainTwoKeyMap.TryGetValue((key1, key2), out var old))
|
||||||
|
{
|
||||||
|
s_logger.Debug("配置表 {} 分支文件 主键:({},{}) 覆盖 主文件记录", table.FullName, key1, key2);
|
||||||
|
mainRecords[old.Index] = r;
|
||||||
|
}
|
||||||
|
mainTwoKeyMap[(key1, key2)] = r;
|
||||||
|
// 目前不支持 双key索引检查,但支持主key索引检查.
|
||||||
|
// 所以至少塞入一个,让ref检查能通过
|
||||||
|
mainRecordMap[key1] = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
table.Assembly.SetDataTableMap(table, recordMap);
|
tableDataInfo.FinalRecords = mainRecords;
|
||||||
|
tableDataInfo.FinalRecordMap = mainRecordMap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ namespace Luban.Job.Cfg.Validators
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DefTable ct = assembly.GetCfgTable(actualTable);
|
DefTable ct = assembly.GetCfgTable(actualTable);
|
||||||
var recordMap = assembly.GetTableDataMap(ct);
|
var recordMap = assembly.GetTableDataInfo(ct).FinalRecordMap;
|
||||||
if (/*recordMap != null &&*/ recordMap.ContainsKey(key))
|
if (/*recordMap != null &&*/ recordMap.ContainsKey(key))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using Luban.Config.Common.RawDefs;
|
using Luban.Job.Cfg.RawDefs;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using Luban.Config.Common.RawDefs;
|
using Luban.Job.Cfg.Datas;
|
||||||
using Luban.Job.Cfg.Datas;
|
|
||||||
using Luban.Job.Cfg.DataVisitors;
|
using Luban.Job.Cfg.DataVisitors;
|
||||||
using Luban.Job.Cfg.Defs;
|
using Luban.Job.Cfg.Defs;
|
||||||
|
using Luban.Job.Cfg.RawDefs;
|
||||||
using Luban.Job.Cfg.Utils;
|
using Luban.Job.Cfg.Utils;
|
||||||
using Luban.Job.Common.Types;
|
using Luban.Job.Common.Types;
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue