diff --git a/README.md b/README.md
index 39278fa..f1341a4 100644
--- a/README.md
+++ b/README.md
@@ -53,8 +53,8 @@ Luban适合有以下需求的开发者:
- 支持res资源标记。可以一键导出配置中引用的所有资源列表(icon,ui,assetbundle等等)
- 生成代码良好模块化。
- **支持文本静态本地化。导出时所有text类型数据正确替换为最终的本地化字符串。**
+- **支持main + braches 多地区版本数据。对于需要针对不同地区有部分差异配置的海外项目非常有用。
- **[TODO] 支持文本动态本地化。运行时动态切换所有text类型数据为目标本地化字符串。**
-- **[TODO] 支持main + braches 多地区版本数据。对于需要针对不同地区有部分差异配置的海外项目非常有用。**
- 支持主流的游戏开发语言
- c++ (11+)
- c# (.net framework 4+. dotnet core 3+)
diff --git a/config/Datas/l10n/cn/test/full_type_cn1.xlsx b/config/Datas/l10n/cn/test/full_type_cn1.xlsx
new file mode 100644
index 0000000..8d3025f
Binary files /dev/null and b/config/Datas/l10n/cn/test/full_type_cn1.xlsx differ
diff --git a/config/Datas/l10n/cn/test/full_type_cn2.xlsx b/config/Datas/l10n/cn/test/full_type_cn2.xlsx
new file mode 100644
index 0000000..f525910
Binary files /dev/null and b/config/Datas/l10n/cn/test/full_type_cn2.xlsx differ
diff --git a/config/Datas/l10n/en/texx/full_type_en.xlsx b/config/Datas/l10n/en/texx/full_type_en.xlsx
new file mode 100644
index 0000000..bb5374a
Binary files /dev/null and b/config/Datas/l10n/en/texx/full_type_en.xlsx differ
diff --git a/config/Defines/__root__.xml b/config/Defines/__root__.xml
index b2b2af7..f3b7df4 100644
--- a/config/Defines/__root__.xml
+++ b/config/Defines/__root__.xml
@@ -6,6 +6,10 @@
editor分组
+
+
+
+
diff --git a/config/Defines/test.xml b/config/Defines/test.xml
index 2d32cbe..44a65bc 100644
--- a/config/Defines/test.xml
+++ b/config/Defines/test.xml
@@ -79,7 +79,7 @@
-
最常见的普通 key-value表
+ 最常见的普通 key-value表
diff --git a/config/branch生成.bat b/config/branch生成.bat
new file mode 100644
index 0000000..d79687a
--- /dev/null
+++ b/config/branch生成.bat
@@ -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
\ No newline at end of file
diff --git a/src/Luban.Job.Cfg/Source/Datas/Record.cs b/src/Luban.Job.Cfg/Source/Datas/Record.cs
index 67d0450..cfe442a 100644
--- a/src/Luban.Job.Cfg/Source/Datas/Record.cs
+++ b/src/Luban.Job.Cfg/Source/Datas/Record.cs
@@ -12,6 +12,8 @@ namespace Luban.Job.Cfg.Datas
public string Source { get; }
+ public int Index { get; set; }
+
public Record(DBean data, string source)
{
Data = data;
diff --git a/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs b/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs
index f8f2f61..b15695d 100644
--- a/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs
+++ b/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs
@@ -1,5 +1,5 @@
using Luban.Common.Utils;
-using Luban.Config.Common.RawDefs;
+using Luban.Job.Cfg.RawDefs;
using Luban.Job.Common.Defs;
using Luban.Job.Common.RawDefs;
using Luban.Server.Common;
@@ -14,6 +14,8 @@ namespace Luban.Job.Cfg.Defs
{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
+ private readonly List _branches = new();
+
private readonly List _cfgTables = new List();
private readonly List _cfgServices = new List();
@@ -24,11 +26,13 @@ namespace Luban.Job.Cfg.Defs
public CfgDefLoader(RemoteAgent agent) : base(agent)
{
+ RegisterRootDefineHandler("branch", AddBranch);
RegisterRootDefineHandler("service", AddService);
RegisterRootDefineHandler("group", AddGroup);
RegisterModuleDefineHandler("table", AddTable);
+
IsBeanFieldMustDefineId = false;
}
@@ -37,6 +41,7 @@ namespace Luban.Job.Cfg.Defs
return new Defines()
{
TopModule = TopModule,
+ Branches = _branches,
Consts = this._consts,
Enums = _enums,
Beans = _beans,
@@ -47,6 +52,21 @@ namespace Luban.Job.Cfg.Defs
}
+ private static readonly List _branchRequireAttrs = new List { "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 _groupOptionalAttrs = new List { "default" };
private static readonly List _groupRequireAttrs = new List { "name" };
@@ -132,7 +152,7 @@ namespace Luban.Job.Cfg.Defs
_cfgServices.Add(new Service() { Name = name, Manager = manager, Groups = groups, Refs = refs });
}
- private readonly List _tableOptionalAttrs = new List { "index", "mode", "group" };
+ private readonly List _tableOptionalAttrs = new List { "index", "mode", "group", "branch_input" };
private readonly List _tableRequireAttrs = new List { "name", "value", "input" };
@@ -236,6 +256,24 @@ namespace Luban.Job.Cfg.Defs
}
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))
{
var exist = _name2CfgTable[p.Name];
diff --git a/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs b/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs
index 33d3330..d2d4888 100644
--- a/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs
+++ b/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs
@@ -1,6 +1,6 @@
-using Luban.Config.Common.RawDefs;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.l10n;
+using Luban.Job.Cfg.RawDefs;
using Luban.Job.Cfg.TypeVisitors;
using Luban.Job.Common.Defs;
using Luban.Server.Common;
@@ -11,12 +11,31 @@ using System.Linq;
namespace Luban.Job.Cfg.Defs
{
+ public class TableDataInfo
+ {
+ public List MainRecords { get; }
+
+ public List BranchRecords { get; }
+
+ public List FinalRecords { get; set; }
+
+ public Dictionary FinalRecordMap { get; set; }
+
+ public TableDataInfo(List mainRecords, List branchRecords)
+ {
+ MainRecords = mainRecords;
+ BranchRecords = branchRecords;
+ }
+ }
+
public class DefAssembly : DefAssemblyBase
{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
public Service CfgTargetService { get; private set; }
+ public Branch TargetBranch { get; private set; }
+
public TimeZoneInfo TimeZone { get; }
public DefAssembly(TimeZoneInfo timezone)
@@ -33,10 +52,11 @@ namespace Luban.Job.Cfg.Defs
return groups.Any(g => CfgTargetService.Groups.Contains(g));
}
+ private readonly List _branches = new List();
+
private readonly List _cfgServices = new List();
- private readonly ConcurrentDictionary> _recordsByTables = new();
- private readonly ConcurrentDictionary> _recordsMapByTables = new();
+ private readonly ConcurrentDictionary _recordsByTables = new();
public Dictionary CfgTables { get; } = new Dictionary();
@@ -52,6 +72,11 @@ namespace Luban.Job.Cfg.Defs
NotConvertTextSet = new NotConvertTextSet();
}
+ public Branch GetBranch(string name)
+ {
+ return _branches.Find(b => b.Name == name);
+ }
+
public void AddCfgTable(DefTable 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;
}
- public void AddDataTable(DefTable table, List records)
+ public void AddDataTable(DefTable table, List mainRecords, List branchRecords)
{
- _recordsByTables[table.FullName] = records;
+ _recordsByTables[table.FullName] = new TableDataInfo(mainRecords, branchRecords);
}
- public void SetDataTableMap(DefTable table, Dictionary recordMap)
- {
- _recordsMapByTables[table.FullName] = recordMap;
- }
+ //public void SetDataTableMap(DefTable table, Dictionary recordMap)
+ //{
+ // _recordsByTables[table.FullName].FinalRecordMap = recordMap;
+ //}
public List GetTableDataList(DefTable table)
{
- return _recordsByTables[table.FullName];
+ return _recordsByTables[table.FullName].FinalRecords;
}
- public Dictionary GetTableDataMap(DefTable table)
+ public TableDataInfo GetTableDataInfo(DefTable table)
{
- return _recordsMapByTables[table.FullName];
+ return _recordsByTables[table.FullName];
}
public List GetExportTables()
@@ -122,7 +147,7 @@ namespace Luban.Job.Cfg.Defs
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;
SupportDatetimeType = true;
@@ -136,6 +161,17 @@ namespace Luban.Job.Cfg.Defs
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)
{
AddType(new DefConst(c));
diff --git a/src/Luban.Job.Cfg/Source/Defs/DefBean.cs b/src/Luban.Job.Cfg/Source/Defs/DefBean.cs
index b93cd1a..1167453 100644
--- a/src/Luban.Job.Cfg/Source/Defs/DefBean.cs
+++ b/src/Luban.Job.Cfg/Source/Defs/DefBean.cs
@@ -1,5 +1,5 @@
using Luban.Common.Utils;
-using Luban.Config.Common.RawDefs;
+using Luban.Job.Cfg.RawDefs;
using Luban.Job.Cfg.TypeVisitors;
using Luban.Job.Common.Defs;
using System;
diff --git a/src/Luban.Job.Cfg/Source/Defs/DefField.cs b/src/Luban.Job.Cfg/Source/Defs/DefField.cs
index 7ebda3a..8a64bdd 100644
--- a/src/Luban.Job.Cfg/Source/Defs/DefField.cs
+++ b/src/Luban.Job.Cfg/Source/Defs/DefField.cs
@@ -1,5 +1,5 @@
using Luban.Common.Utils;
-using Luban.Config.Common.RawDefs;
+using Luban.Job.Cfg.RawDefs;
using Luban.Job.Cfg.Validators;
using Luban.Job.Common.Defs;
using Luban.Job.Common.Types;
diff --git a/src/Luban.Job.Cfg/Source/Defs/DefTable.cs b/src/Luban.Job.Cfg/Source/Defs/DefTable.cs
index 5acd608..58ebba3 100644
--- a/src/Luban.Job.Cfg/Source/Defs/DefTable.cs
+++ b/src/Luban.Job.Cfg/Source/Defs/DefTable.cs
@@ -1,4 +1,4 @@
-using Luban.Config.Common.RawDefs;
+using Luban.Job.Cfg.RawDefs;
using Luban.Job.Common.Types;
using System;
using System.Collections.Generic;
@@ -19,6 +19,7 @@ namespace Luban.Job.Cfg.Defs
Mode = b.Mode;
InputFiles = b.InputFiles;
Groups = b.Groups;
+ _branchInputFiles = b.BranchInputFiles;
}
@@ -36,6 +37,8 @@ namespace Luban.Job.Cfg.Defs
public List InputFiles { get; }
+ private readonly Dictionary> _branchInputFiles;
+
public List Groups { get; }
public TType KeyTType { get; private set; }
@@ -62,11 +65,24 @@ namespace Luban.Job.Cfg.Defs
public string JsonOutputDataFile => $"{FullName}.json";
+ public List GetBranchInputFiles(string branchName)
+ {
+ return _branchInputFiles.GetValueOrDefault(branchName);
+ }
+
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} 不存在");
}
diff --git a/src/Luban.Job.Cfg/Source/JobController.cs b/src/Luban.Job.Cfg/Source/JobController.cs
index 5a0cb80..0c49b61 100644
--- a/src/Luban.Job.Cfg/Source/JobController.cs
+++ b/src/Luban.Job.Cfg/Source/JobController.cs
@@ -58,7 +58,7 @@ namespace Luban.Job.Cfg
[Option("export_test_data", Required = false, HelpText = "export test data")]
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; }
[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.")]
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)
@@ -95,7 +101,7 @@ namespace Luban.Job.Cfg
}
- private static bool TryParseArg(List args, out GenArgs result, out string errMsg)
+ private static bool TryParseArg(List args, out GenArgs options, out string errMsg)
{
var helpWriter = new StringWriter();
var parser = new Parser(ps =>
@@ -106,19 +112,19 @@ namespace Luban.Job.Cfg
if (parseResult.Tag == ParserResultType.NotParsed)
{
errMsg = helpWriter.ToString();
- result = null;
+ options = null;
return false;
}
else
{
- result = (parseResult as Parsed).Value;
+ options = (parseResult as Parsed).Value;
errMsg = null;
- string inputDataDir = result.InputDataDir;
- string outputCodeDir = result.OutputCodeDir;
- string outputDataDir = result.OutputDataDir;
+ string inputDataDir = options.InputDataDir;
+ string outputCodeDir = options.OutputCodeDir;
+ 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))
{
@@ -137,24 +143,30 @@ namespace Luban.Job.Cfg
errMsg = "--outputdatadir missing";
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";
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";
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";
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;
}
}
@@ -197,7 +209,7 @@ namespace Luban.Job.Cfg
var ass = new DefAssembly(timeZoneInfo);
- ass.Load(args.Service, rawDefines, agent);
+ ass.Load(args.Service, args.BranchName, rawDefines, agent);
var targetService = ass.CfgTargetService;
@@ -216,7 +228,7 @@ namespace Luban.Job.Cfg
hasLoadCfgData = true;
var timer = new ProfileTimer();
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();
if (needL10NTextConvert)
diff --git a/src/Luban.Job.Cfg/Source/RawDefs/Branch.cs b/src/Luban.Job.Cfg/Source/RawDefs/Branch.cs
new file mode 100644
index 0000000..9cfc04c
--- /dev/null
+++ b/src/Luban.Job.Cfg/Source/RawDefs/Branch.cs
@@ -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;
+ }
+ }
+}
diff --git a/src/Luban.Job.Cfg/Source/RawDefs/CfgBean.cs b/src/Luban.Job.Cfg/Source/RawDefs/CfgBean.cs
index 9790d7f..ab6b176 100644
--- a/src/Luban.Job.Cfg/Source/RawDefs/CfgBean.cs
+++ b/src/Luban.Job.Cfg/Source/RawDefs/CfgBean.cs
@@ -1,6 +1,6 @@
using Luban.Job.Common.RawDefs;
-namespace Luban.Config.Common.RawDefs
+namespace Luban.Job.Cfg.RawDefs
{
public class CfgBean : Bean
{
diff --git a/src/Luban.Job.Cfg/Source/RawDefs/CfgField.cs b/src/Luban.Job.Cfg/Source/RawDefs/CfgField.cs
index a6014e3..4237334 100644
--- a/src/Luban.Job.Cfg/Source/RawDefs/CfgField.cs
+++ b/src/Luban.Job.Cfg/Source/RawDefs/CfgField.cs
@@ -1,7 +1,7 @@
using Luban.Job.Common.RawDefs;
using System.Collections.Generic;
-namespace Luban.Config.Common.RawDefs
+namespace Luban.Job.Cfg.RawDefs
{
public class Validator
diff --git a/src/Luban.Job.Cfg/Source/RawDefs/Defines.cs b/src/Luban.Job.Cfg/Source/RawDefs/Defines.cs
index 4b4ed22..4760f1c 100644
--- a/src/Luban.Job.Cfg/Source/RawDefs/Defines.cs
+++ b/src/Luban.Job.Cfg/Source/RawDefs/Defines.cs
@@ -1,12 +1,15 @@
+using Luban.Job.Cfg.RawDefs;
using Luban.Job.Common.RawDefs;
using System.Collections.Generic;
-namespace Luban.Config.Common.RawDefs
+namespace Luban.Job.Cfg.RawDefs
{
public class Defines
{
public string TopModule { get; set; } = "";
+ public List Branches { get; set; } = new List();
+
public List Beans { get; set; } = new List();
public List Consts { get; set; } = new List();
diff --git a/src/Luban.Job.Cfg/Source/RawDefs/Group.cs b/src/Luban.Job.Cfg/Source/RawDefs/Group.cs
index bd63340..30ceb44 100644
--- a/src/Luban.Job.Cfg/Source/RawDefs/Group.cs
+++ b/src/Luban.Job.Cfg/Source/RawDefs/Group.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace Luban.Config.Common.RawDefs
+namespace Luban.Job.Cfg.RawDefs
{
public class Group
{
diff --git a/src/Luban.Job.Cfg/Source/RawDefs/Service.cs b/src/Luban.Job.Cfg/Source/RawDefs/Service.cs
index 59bd7c9..3054710 100644
--- a/src/Luban.Job.Cfg/Source/RawDefs/Service.cs
+++ b/src/Luban.Job.Cfg/Source/RawDefs/Service.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace Luban.Config.Common.RawDefs
+namespace Luban.Job.Cfg.RawDefs
{
public class Service
{
diff --git a/src/Luban.Job.Cfg/Source/RawDefs/Table.cs b/src/Luban.Job.Cfg/Source/RawDefs/Table.cs
index 038547e..fe7ef88 100644
--- a/src/Luban.Job.Cfg/Source/RawDefs/Table.cs
+++ b/src/Luban.Job.Cfg/Source/RawDefs/Table.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace Luban.Config.Common.RawDefs
+namespace Luban.Job.Cfg.RawDefs
{
public enum ETableMode
{
@@ -35,5 +35,7 @@ namespace Luban.Config.Common.RawDefs
public List Groups { get; set; } = new List();
public List InputFiles { get; set; } = new List();
+
+ public Dictionary> BranchInputFiles { get; set; } = new Dictionary>();
}
}
diff --git a/src/Luban.Job.Cfg/Source/TypeVisitors/DeepCompareTypeDefine.cs b/src/Luban.Job.Cfg/Source/TypeVisitors/DeepCompareTypeDefine.cs
index 0c49151..561ea8d 100644
--- a/src/Luban.Job.Cfg/Source/TypeVisitors/DeepCompareTypeDefine.cs
+++ b/src/Luban.Job.Cfg/Source/TypeVisitors/DeepCompareTypeDefine.cs
@@ -1,5 +1,5 @@
-using Luban.Config.Common.RawDefs;
using Luban.Job.Cfg.Defs;
+using Luban.Job.Cfg.RawDefs;
using Luban.Job.Common.Defs;
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
diff --git a/src/Luban.Job.Cfg/Source/Utils/DataExporterUtil.cs b/src/Luban.Job.Cfg/Source/Utils/DataExporterUtil.cs
index a14efbf..3b91cb5 100644
--- a/src/Luban.Job.Cfg/Source/Utils/DataExporterUtil.cs
+++ b/src/Luban.Job.Cfg/Source/Utils/DataExporterUtil.cs
@@ -1,5 +1,4 @@
using Bright.Serialization;
-using Luban.Config.Common.RawDefs;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.DataVisitors;
using Luban.Job.Cfg.Defs;
diff --git a/src/Luban.Job.Cfg/Source/Utils/DataLoaderUtil.cs b/src/Luban.Job.Cfg/Source/Utils/DataLoaderUtil.cs
index ea72aa6..14b1fff 100644
--- a/src/Luban.Job.Cfg/Source/Utils/DataLoaderUtil.cs
+++ b/src/Luban.Job.Cfg/Source/Utils/DataLoaderUtil.cs
@@ -71,16 +71,14 @@ namespace Luban.Job.Cfg.Utils
// 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 inputFiles2, bool exportTestData, List>> tasks)
{
- var tasks = new List>>();
-
- var inputFiles = await CollectInputFilesAsync(agent, table.InputFiles, dataDir);
+ var inputFileInfos = await CollectInputFilesAsync(agent, inputFiles2, dataDir);
// check cache (table, exporttestdata) -> (list, List)
// (md5, sheetName,exportTestData) -> (value_type, List)
- foreach (var file in inputFiles)
+ foreach (var file in inputFileInfos)
{
var actualFile = file.ActualFile;
//s_logger.Info("== get input file:{file} actualFile:{actual}", file, actualFile);
@@ -103,21 +101,52 @@ namespace Luban.Job.Cfg.Utils
return res;
}));
}
-
- var records = new List(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>>();
+ var mainGenerateTask = GenerateLoadRecordFromFileTasksAsync(agent, table, dataDir, table.InputFiles, exportTestData, mainLoadTasks);
+
+ var branchLoadTasks = new List>>();
+
+ 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(256);
+ foreach (var task in mainLoadTasks)
+ {
+ mainRecords.AddRange(await task);
+ }
+ s_logger.Trace("== load main records. count:{count}", mainRecords.Count);
+
+ List branchRecords = null;
+ if (branchGenerateTask != null)
+ {
+ branchRecords = new List(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;
List 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 () =>
{
long beginTime = TimeUtil.NowMillis;
- await LoadTableAsync(agent, c, dataDir, exportTestData);
+ await LoadTableAsync(agent, c, dataDir, branchName, branchDataDir, exportTestData);
long endTime = TimeUtil.NowMillis;
if (endTime - beginTime > 100)
{
diff --git a/src/Luban.Job.Cfg/Source/ValidatorContext.cs b/src/Luban.Job.Cfg/Source/ValidatorContext.cs
index ba6152a..55add5d 100644
--- a/src/Luban.Job.Cfg/Source/ValidatorContext.cs
+++ b/src/Luban.Job.Cfg/Source/ValidatorContext.cs
@@ -1,8 +1,8 @@
using Luban.Common.Utils;
-using Luban.Config.Common.RawDefs;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.DataVisitors;
using Luban.Job.Cfg.Defs;
+using Luban.Job.Cfg.RawDefs;
using Luban.Job.Cfg.Utils;
using Luban.Job.Cfg.Validators;
using System;
@@ -27,6 +27,8 @@ namespace Luban.Job.Cfg
public class ValidatorContext
{
+ private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
+
[ThreadStatic]
private static ValidatorVisitor t_visitor;
@@ -67,8 +69,7 @@ namespace Luban.Job.Cfg
{
tasks.Add(Task.Run(() =>
{
- var records = t.Assembly.GetTableDataList(t);
- ValidateTableModeIndex(t, records);
+ ValidateTableModeIndex(t);
}));
}
await Task.WhenAll(tasks);
@@ -171,58 +172,134 @@ namespace Luban.Job.Cfg
}
}
- private void ValidateTableModeIndex(DefTable table, List records)
+ private void ValidateTableModeIndex(DefTable table)
{
- var recordMap = new Dictionary();
+ var tableDataInfo = Assembly.GetTableDataInfo(table);
+
+ List mainRecords = tableDataInfo.MainRecords;
+ List 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();
switch (table.Mode)
{
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;
}
case ETableMode.MAP:
{
- foreach (Record r in records)
+ foreach (Record r in mainRecords)
{
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}
- 记录2 来自文件:{recordMap[key].Source}
+ 记录2 来自文件:{mainRecordMap[key].Source}
");
}
-
+ }
+ if (branchRecords != null)
+ {
+ var branchRecordMap = new Dictionary();
+ 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;
}
case ETableMode.BMAP:
{
- var twoKeyMap = new Dictionary<(DType, DType), Record>();
- foreach (Record r in records)
+ var mainTwoKeyMap = new Dictionary<(DType, DType), Record>();
+ foreach (Record r in mainRecords)
{
DType key1 = r.Data.Fields[table.IndexFieldIdIndex1];
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}
- 记录2 来自文件:{twoKeyMap[(key1, key2)].Source}
+ 记录2 来自文件:{mainTwoKeyMap[(key1, key2)].Source}
");
}
// 目前不支持 双key索引检查,但支持主key索引检查.
// 所以至少塞入一个,让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;
}
}
- table.Assembly.SetDataTableMap(table, recordMap);
+ tableDataInfo.FinalRecords = mainRecords;
+ tableDataInfo.FinalRecordMap = mainRecordMap;
}
}
}
diff --git a/src/Luban.Job.Cfg/Source/Validators/RefValidator.cs b/src/Luban.Job.Cfg/Source/Validators/RefValidator.cs
index 2a8b307..eacc928 100644
--- a/src/Luban.Job.Cfg/Source/Validators/RefValidator.cs
+++ b/src/Luban.Job.Cfg/Source/Validators/RefValidator.cs
@@ -53,7 +53,7 @@ namespace Luban.Job.Cfg.Validators
return;
}
DefTable ct = assembly.GetCfgTable(actualTable);
- var recordMap = assembly.GetTableDataMap(ct);
+ var recordMap = assembly.GetTableDataInfo(ct).FinalRecordMap;
if (/*recordMap != null &&*/ recordMap.ContainsKey(key))
{
return;
diff --git a/src/Luban.Job.Cfg/Source/Validators/ValidatorFactory.cs b/src/Luban.Job.Cfg/Source/Validators/ValidatorFactory.cs
index 4efe0cc..e6a13fc 100644
--- a/src/Luban.Job.Cfg/Source/Validators/ValidatorFactory.cs
+++ b/src/Luban.Job.Cfg/Source/Validators/ValidatorFactory.cs
@@ -1,4 +1,4 @@
-using Luban.Config.Common.RawDefs;
+using Luban.Job.Cfg.RawDefs;
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/src/Luban.Job.Cfg/Source/l10n/TextTable.cs b/src/Luban.Job.Cfg/Source/l10n/TextTable.cs
index 65ee6b9..ca8cde8 100644
--- a/src/Luban.Job.Cfg/Source/l10n/TextTable.cs
+++ b/src/Luban.Job.Cfg/Source/l10n/TextTable.cs
@@ -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.Defs;
+using Luban.Job.Cfg.RawDefs;
using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Types;
using System;