From 4e7c993d535401dcc3d84e5a4f0edf46297a8aed Mon Sep 17 00:00:00 2001 From: walon Date: Tue, 12 Oct 2021 16:05:10 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Luban.Common/Source/Utils/FileUtil.cs | 10 +- .../Source/DataSources/DataSourceFactory.cs | 2 +- src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs | 6 +- src/Luban.Job.Cfg/Source/Defs/DefBean.cs | 6 +- .../TypeVisitors/DeepCompareTypeDefine.cs | 2 +- .../Source/Validators/RefValidator.cs | 8 +- .../Source/Defs/DefAssemblyBase.cs | 6 +- src/Luban.Job.Common/Source/Utils/DefUtil.cs | 4 +- src/LubanAssistant/AssistantTab.cs | 4 +- src/LubanAssistant/LoadUtil.cs | 29 +- src/LubanAssistant/LubanAssistant.cs | 2 + src/LubanAssistant/LubanAssistant.csproj | 17 +- .../Source/Defs/CfgDefLoader.cs | 428 +++++++++++++++++- src/LubanAssistant/Source/Defs/DefAssembly.cs | 90 +++- .../Source/Utils/CacheFileUtil.cs | 4 +- .../Source/Utils/DataLoaderUtil.cs | 56 +-- src/LubanAssistant/packages.config | 5 +- 17 files changed, 556 insertions(+), 123 deletions(-) diff --git a/src/Luban.Common/Source/Utils/FileUtil.cs b/src/Luban.Common/Source/Utils/FileUtil.cs index 3e26a39..3f2cd78 100644 --- a/src/Luban.Common/Source/Utils/FileUtil.cs +++ b/src/Luban.Common/Source/Utils/FileUtil.cs @@ -23,7 +23,7 @@ namespace Luban.Common.Utils public static string GetFileName(string path) { int index = path.Replace('\\', '/').LastIndexOf('/'); -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE return index >= 0 ? path[(index + 1)..] : path; #else return index >= 0 ? path.Substring(index + 1, path.Length - index - 1) : path; @@ -33,7 +33,7 @@ namespace Luban.Common.Utils public static string GetParent(string path) { int index = path.Replace('\\', '/').LastIndexOf('/'); -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE return index >= 0 ? path[..index] : "."; #else return index >= 0 ? path.Substring(0, index) : "."; @@ -70,7 +70,7 @@ namespace Luban.Common.Utils } var f = new FileInfo(file); string fname = f.Name; -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE return !fname.StartsWith('.') && !fname.StartsWith('_') && !fname.StartsWith('~'); #else return !fname.StartsWith(".") && !fname.StartsWith("_") && !fname.StartsWith("~"); @@ -129,7 +129,7 @@ namespace Luban.Common.Utils else { int lastPathSep = url.LastIndexOf('/', sheetSepIndex); -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE if (lastPathSep >= 0) { return (url[0..(lastPathSep + 1)] + url[(sheetSepIndex + 1)..], url[(lastPathSep + 1)..sheetSepIndex]); @@ -183,7 +183,7 @@ namespace Luban.Common.Utils } -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE await File.WriteAllBytesAsync(outputPath, content); #else await Task.Run(() => File.WriteAllBytes(outputPath, content)); diff --git a/src/Luban.Job.Cfg/Source/DataSources/DataSourceFactory.cs b/src/Luban.Job.Cfg/Source/DataSources/DataSourceFactory.cs index 8dda364..4a6caa8 100644 --- a/src/Luban.Job.Cfg/Source/DataSources/DataSourceFactory.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/DataSourceFactory.cs @@ -22,7 +22,7 @@ namespace Luban.Job.Cfg.DataSources { try { -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE string ext = url.Contains('.') ? Path.GetExtension(url)?[1..] : url; #else string ext = url.Contains(".") ? Path.GetExtension(url)?.Substring(1) : url; diff --git a/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs b/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs index 59c12c3..a02de99 100644 --- a/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs +++ b/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs @@ -140,7 +140,7 @@ namespace Luban.Job.Cfg.Defs { if (!string.IsNullOrWhiteSpace(attr)) { -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE foreach (var validatorStr in attr.Split('#', StringSplitOptions.RemoveEmptyEntries)) #else foreach (var validatorStr in attr.Split('#')) @@ -151,7 +151,7 @@ namespace Luban.Job.Cfg.Defs { throw new Exception($"定义文件:{defineFile} key:'{key}' attr:'{attr}' 不是合法的 validator 定义 (key1:value1#key2:value2 ...)"); } -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE result.Add(new Validator() { Type = validatorStr[..sepIndex], Rule = validatorStr[(sepIndex + 1)..] }); #else result.Add(new Validator() { Type = validatorStr.Substring(0, sepIndex), Rule = validatorStr.Substring(sepIndex + 1, validatorStr.Length - sepIndex - 1) }); @@ -365,7 +365,7 @@ namespace Luban.Job.Cfg.Defs for (int i = 1; i < attrs.Length; i++) { -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE var pair = attrs[i].Split('=', 2); #else var pair = attrs[i].Split(new char[] { '=' }, 2); diff --git a/src/Luban.Job.Cfg/Source/Defs/DefBean.cs b/src/Luban.Job.Cfg/Source/Defs/DefBean.cs index dac9cac..5cdf2ca 100644 --- a/src/Luban.Job.Cfg/Source/Defs/DefBean.cs +++ b/src/Luban.Job.Cfg/Source/Defs/DefBean.cs @@ -31,7 +31,7 @@ namespace Luban.Job.Cfg.Defs return DeepCompareTypeDefine.Ins.Compare(this, b, new Dictionary(), new HashSet()); } -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE public string GoBinImport { get @@ -219,7 +219,11 @@ namespace Luban.Job.Cfg.Defs Id = TypeUtil.ComputCfgHashIdByName(FullName); } // 检查别名是否重复 +#if !LUBAN_LITE HashSet nameOrAliasName = cs.Select(b => b.Name).ToHashSet(); +#else + HashSet nameOrAliasName = new HashSet(cs.Select(b => b.Name)); +#endif foreach (DefBean c in cs) { if (!string.IsNullOrWhiteSpace(c.Alias) && !nameOrAliasName.Add(c.Alias)) diff --git a/src/Luban.Job.Cfg/Source/TypeVisitors/DeepCompareTypeDefine.cs b/src/Luban.Job.Cfg/Source/TypeVisitors/DeepCompareTypeDefine.cs index 1e6802c..564ce67 100644 --- a/src/Luban.Job.Cfg/Source/TypeVisitors/DeepCompareTypeDefine.cs +++ b/src/Luban.Job.Cfg/Source/TypeVisitors/DeepCompareTypeDefine.cs @@ -104,7 +104,7 @@ namespace Luban.Job.Cfg.TypeVisitors || f1.NeedExport != f2.NeedExport || f1.Index != f2.Index || f1.Sep != f2.Sep -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE || f1.ResourceTag != f2.ResourceTag #endif || f1.IsMultiRow != f2.IsMultiRow diff --git a/src/Luban.Job.Cfg/Source/Validators/RefValidator.cs b/src/Luban.Job.Cfg/Source/Validators/RefValidator.cs index 2ad05bb..efbf561 100644 --- a/src/Luban.Job.Cfg/Source/Validators/RefValidator.cs +++ b/src/Luban.Job.Cfg/Source/Validators/RefValidator.cs @@ -16,7 +16,7 @@ namespace Luban.Job.Cfg.Validators public static string GetActualTableName(string table) { -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE return table.EndsWith("?") ? table[0..^1] : table; #else return table.EndsWith("?") ? table.Substring(0, table.Length - 1) : table; @@ -44,7 +44,7 @@ namespace Luban.Job.Cfg.Validators if (table.EndsWith("?")) { zeroAble = true; -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE actualTable = table[0..^1]; #else actualTable = table.Substring(0, table.Length - 1); @@ -72,7 +72,7 @@ namespace Luban.Job.Cfg.Validators string actualTable; if (table.EndsWith("?")) { -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE actualTable = table[0..^1]; #else actualTable = table.Substring(0, table.Length - 1); @@ -97,7 +97,7 @@ namespace Luban.Job.Cfg.Validators foreach (var table in Tables) { -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE string actualTable = table.EndsWith("?") ? table[0..^1] : table; #else string actualTable = table.EndsWith("?") ? table.Substring(0, table.Length - 1) : table; diff --git a/src/Luban.Job.Common/Source/Defs/DefAssemblyBase.cs b/src/Luban.Job.Common/Source/Defs/DefAssemblyBase.cs index 8cd0e18..680e929 100644 --- a/src/Luban.Job.Common/Source/Defs/DefAssemblyBase.cs +++ b/src/Luban.Job.Common/Source/Defs/DefAssemblyBase.cs @@ -117,7 +117,7 @@ namespace Luban.Job.Common.Defs public TType CreateType(string module, string type) { -#if LUBAN_ASSISTANT +#if LUBAN_LITE int sepIndex = type.IndexOf(','); #else int sepIndex = type.IndexOf(',', System.StringComparison.Ordinal); @@ -138,7 +138,7 @@ namespace Luban.Job.Common.Defs bool nullable; var (type, tags) = DefUtil.ParseType(rawType); -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE if (type.EndsWith('?')) #else if (type.EndsWith("?")) @@ -149,7 +149,7 @@ namespace Luban.Job.Common.Defs throw new Exception($"not support nullable type:'{module}.{type}'"); } nullable = true; -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE type = type[0..^1]; #else type = type.Substring(0, type.Length - 1); diff --git a/src/Luban.Job.Common/Source/Utils/DefUtil.cs b/src/Luban.Job.Common/Source/Utils/DefUtil.cs index fce18d4..13e7aa7 100644 --- a/src/Luban.Job.Common/Source/Utils/DefUtil.cs +++ b/src/Luban.Job.Common/Source/Utils/DefUtil.cs @@ -21,7 +21,7 @@ namespace Luban.Job.Common.Utils int sepIndex = pair.IndexOfAny(s_attrKeyValueSep); if (sepIndex >= 0) { -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE am.Add(pair[..sepIndex].Trim(), pair[(sepIndex + 1)..].Trim()); #else am.Add(pair.Substring(0, sepIndex).Trim(), pair.Substring(sepIndex + 1).Trim()); @@ -44,7 +44,7 @@ namespace Luban.Job.Common.Utils } else { -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE return (s[..sepIndex], ParseAttrs(s[(sepIndex + 1)..])); #else return (s.Substring(0, sepIndex), ParseAttrs(s.Substring(sepIndex + 1))); diff --git a/src/LubanAssistant/AssistantTab.cs b/src/LubanAssistant/AssistantTab.cs index 996bbd4..8aac8c9 100644 --- a/src/LubanAssistant/AssistantTab.cs +++ b/src/LubanAssistant/AssistantTab.cs @@ -119,7 +119,7 @@ namespace LubanAssistant { try { - await LoadUtil.LoadDataToCurrentDoc(RootDefineFile, InputDataDir, tableName); + await LoadUtil.LoadTableDataToCurrentWorkSheetAsync(RootDefineFile, InputDataDir, tableName); } catch (Exception e) { @@ -143,7 +143,7 @@ namespace LubanAssistant private bool HasNotsaveDataInCurrentWorksapce() { - return true; + return false; } private void BtnLoadDataClick(object sender, RibbonControlEventArgs e) diff --git a/src/LubanAssistant/LoadUtil.cs b/src/LubanAssistant/LoadUtil.cs index fac2efe..3d6fc26 100644 --- a/src/LubanAssistant/LoadUtil.cs +++ b/src/LubanAssistant/LoadUtil.cs @@ -14,33 +14,14 @@ namespace LubanAssistant { static class LoadUtil { - public static async Task LoadDataToCurrentDoc(string rootDefineFile, string inputDataDir, string tableName) + public static async Task LoadTableDataToCurrentWorkSheetAsync(string rootDefineFile, string inputDataDir, string tableName) { - IAgent agent = new LocalAgent(); - var loader = new CfgDefLoader(agent); - await loader.LoadAsync(rootDefineFile); + var tableDataInfo = await DataLoaderUtil.LoadTableDataAsync(rootDefineFile, inputDataDir, tableName); - var rawDefines = loader.BuildDefines(); + Console.WriteLine("load record num:{0}", tableDataInfo.MainRecords.Count); - TimeZoneInfo timeZoneInfo = null; - - var excludeTags = new List(); - var ass = new DefAssembly("", timeZoneInfo, excludeTags, agent); - - ass.Load(rawDefines); - - DefAssemblyBase.LocalAssebmly = ass; - - var table = ass.GetCfgTable(tableName); - - if (table == null) - { - throw new Exception($"table:{tableName}不存在"); - } - await DataLoaderUtil.LoadTableAsync(agent, table, inputDataDir, "", ""); - - var datas = ass.GetTableAllDataList(table); - MessageBox.Show($"table:{table.FullName} input:{StringUtil.CollectionToString(table.InputFiles)} record num:{datas.Count}"); + Microsoft.Office.Interop.Excel.Worksheet cur = Globals.LubanAssistant.Application.ActiveSheet; + Console.WriteLine("== active sheet name:{0}", cur.Name); } } } diff --git a/src/LubanAssistant/LubanAssistant.cs b/src/LubanAssistant/LubanAssistant.cs index 9d6a81d..d5123bd 100644 --- a/src/LubanAssistant/LubanAssistant.cs +++ b/src/LubanAssistant/LubanAssistant.cs @@ -7,6 +7,7 @@ using Excel = Microsoft.Office.Interop.Excel; using Office = Microsoft.Office.Core; using Microsoft.Office.Tools.Excel; using Microsoft.Office.Tools.Ribbon; +using Luban.Common.Utils; namespace LubanAssistant { @@ -14,6 +15,7 @@ namespace LubanAssistant { private void ThisAddIn_Startup(object sender, System.EventArgs e) { + LogUtil.InitSimpleNLogConfigure(NLog.LogLevel.Info); } private void ThisAddIn_Shutdown(object sender, System.EventArgs e) diff --git a/src/LubanAssistant/LubanAssistant.csproj b/src/LubanAssistant/LubanAssistant.csproj index 3ec3d1c..99e391f 100644 --- a/src/LubanAssistant/LubanAssistant.csproj +++ b/src/LubanAssistant/LubanAssistant.csproj @@ -1,5 +1,4 @@  - - - ..\packages\CommandLineParser.2.8.0\lib\net461\CommandLine.dll - ..\packages\ExcelDataReader.3.6.0\lib\net45\ExcelDataReader.dll @@ -122,9 +118,6 @@ ..\packages\NLog.4.7.11\lib\net45\NLog.dll - - ..\packages\Scriban.4.1.0\lib\netstandard2.0\Scriban.dll - ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll @@ -634,12 +627,4 @@ - - - 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 - - - - - \ No newline at end of file diff --git a/src/LubanAssistant/Source/Defs/CfgDefLoader.cs b/src/LubanAssistant/Source/Defs/CfgDefLoader.cs index d178997..ae03b55 100644 --- a/src/LubanAssistant/Source/Defs/CfgDefLoader.cs +++ b/src/LubanAssistant/Source/Defs/CfgDefLoader.cs @@ -18,7 +18,7 @@ using System.Xml.Linq; namespace Luban.Job.Cfg.Defs { - class CfgDefLoader : CommonDefLoader + public class CfgDefLoader : CommonDefLoader { private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger(); @@ -140,7 +140,7 @@ namespace Luban.Job.Cfg.Defs { if (!string.IsNullOrWhiteSpace(attr)) { -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE foreach (var validatorStr in attr.Split('#', StringSplitOptions.RemoveEmptyEntries)) #else foreach (var validatorStr in attr.Split('#')) @@ -151,7 +151,7 @@ namespace Luban.Job.Cfg.Defs { throw new Exception($"定义文件:{defineFile} key:'{key}' attr:'{attr}' 不是合法的 validator 定义 (key1:value1#key2:value2 ...)"); } -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE result.Add(new Validator() { Type = validatorStr[..sepIndex], Rule = validatorStr[(sepIndex + 1)..] }); #else result.Add(new Validator() { Type = validatorStr.Substring(0, sepIndex), Rule = validatorStr.Substring(sepIndex + 1, validatorStr.Length - sepIndex - 1) }); @@ -319,6 +319,428 @@ namespace Luban.Job.Cfg.Defs _cfgTables.Add(p); } + private async Task LoadTableValueTypeDefineFromFileAsync(Table table, string dataDir) + { + var inputFileInfos = await DataLoaderUtil.CollectInputFilesAsync(this.Agent, table.InputFiles, dataDir); + var file = inputFileInfos[0]; + var source = new ExcelDataSource(); + var stream = new MemoryStream(await this.Agent.GetFromCacheOrReadAllBytesAsync(file.ActualFile, file.MD5)); + var sheet = source.LoadFirstSheet(file.OriginFile, file.SheetName, stream); + + var cb = new CfgBean() { Namespace = table.Namespace, Name = table.ValueType, }; + + var rc = sheet.RowColumns; + var attrRow = sheet.RowColumns[0]; + if (rc.Count < sheet.AttrRowCount + 1) + { + throw new Exception($"table:'{table.Name}' file:{file.OriginFile} 至少包含 属性行和标题行"); + } + var titleRow = sheet.RowColumns[sheet.AttrRowCount]; + // 有可能没有注释行,此时使用标题行,这个是必须有的 + var descRow = sheet.HeaderRowCount >= sheet.AttrRowCount + 2 ? sheet.RowColumns[sheet.AttrRowCount + 1] : titleRow; + foreach (var f in sheet.RootFields) + { + var cf = new CfgField() { Name = f.Name, Id = 0 }; + + string[] attrs = (attrRow[f.FromIndex].Value?.ToString() ?? "").Trim().Split('&').Select(s => s.Trim()).ToArray(); + + if (attrs.Length == 0 || string.IsNullOrWhiteSpace(attrs[0])) + { + throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{f.Name}' type missing!"); + } + + // 优先取desc行,如果为空,则取title行 + + cf.Comment = descRow[f.FromIndex].Value?.ToString(); + if (string.IsNullOrWhiteSpace(cf.Comment)) + { + cf.Comment = titleRow[f.FromIndex].Value?.ToString(); + } + if (string.IsNullOrWhiteSpace(cf.Comment)) + { + cf.Comment = ""; + } + + cf.Type = attrs[0]; + + for (int i = 1; i < attrs.Length; i++) + { +#if !LUBAN_LITE + var pair = attrs[i].Split('=', 2); +#else + var pair = attrs[i].Split(new char[] { '=' }, 2); +#endif + if (pair.Length != 2) + { + throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{f.Name}' attr:'{attrs[i]}' is invalid!"); + } + var attrName = pair[0].Trim(); + var attrValue = pair[1].Trim(); + switch (attrName) + { + case "index": + { + cf.Index = attrValue; + break; + } + case "sep": + { + cf.Sep = attrValue; + break; + } + case "ref": + case "path": + case "range": + { + var validator = new Validator() { Type = attrName, Rule = attrValue }; + cf.Validators.Add(validator); + cf.ValueValidators.Add(validator); + break; + } + case "multi_rows": + { + cf.IsMultiRow = attrValue == "1" || attrValue.Equals("true", StringComparison.OrdinalIgnoreCase); + break; + } + case "group": + { + cf.Groups = attrValue.Split(',').Select(s => s.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)).ToList(); + break; + } + case "comment": + { + cf.Comment = attrValue; + break; + } + case "convert": + { + cf.Converter = attrValue; + break; + } + case "default": + { + cf.DefaultValue = attrValue; + break; + } + case "tags": + { + cf.Tags = attrValue; + break; + } + case "orientation": + { + cf.IsRowOrient = DefUtil.ParseOrientation(attrValue); + break; + } + default: + { + throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{f.Name}' attr:'{attrs[i]}' is invalid!"); + } + } + } + + cb.Fields.Add(cf); + } + return cb; + } + + private async Task LoadTableValueTypeDefinesFromFileAsync(string dataDir) + { + var loadTasks = new List>(); + foreach (var table in this._cfgTables.Where(t => t.LoadDefineFromFile)) + { + loadTasks.Add(Task.Run(async () => await this.LoadTableValueTypeDefineFromFileAsync(table, dataDir))); + } + + foreach (var task in loadTasks) + { + this._beans.Add(await task); + } + } + + private async Task LoadTableListFromFileAsync(string dataDir) + { + if (this._importExcelTableFiles.Count == 0) + { + return; + } + var inputFileInfos = await DataLoaderUtil.CollectInputFilesAsync(this.Agent, this._importExcelTableFiles, dataDir); + + var defTableRecordType = new DefBean(new CfgBean() + { + Namespace = "__intern__", + Name = "__TableRecord__", + Parent = "", + Alias = "", + IsValueType = false, + Sep = "", + TypeId = 0, + IsSerializeCompatible = false, + Fields = new List + { + new CfgField() { Name = "full_name", Type = "string" }, + new CfgField() { Name = "value_type", Type = "string" }, + new CfgField() { Name = "index", Type = "string" }, + new CfgField() { Name = "mode", Type = "string" }, + new CfgField() { Name = "group", Type = "string" }, + new CfgField() { Name = "comment", Type = "string" }, + new CfgField() { Name = "define_from_excel", Type = "bool" }, + new CfgField() { Name = "input", Type = "string" }, + new CfgField() { Name = "patch_input", Type = "string" }, + new CfgField() { Name = "tags", Type = "string" }, + } + }) + { + AssemblyBase = new DefAssembly("", null, new List(), Agent), + }; + defTableRecordType.PreCompile(); + defTableRecordType.Compile(); + defTableRecordType.PostCompile(); + var tableRecordType = TBean.Create(false, defTableRecordType); + + foreach (var file in inputFileInfos) + { + var source = new ExcelDataSource(); + var bytes = await this.Agent.GetFromCacheOrReadAllBytesAsync(file.ActualFile, file.MD5); + var records = DataLoaderUtil.LoadCfgRecords(tableRecordType, file.OriginFile, null, bytes, true); + foreach (var r in records) + { + DBean data = r.Data; + //s_logger.Info("== read text:{}", r.Data); + string fullName = (data.GetField("full_name") as DString).Value.Trim(); + string name = TypeUtil.GetName(fullName); + if (string.IsNullOrWhiteSpace(fullName) || string.IsNullOrWhiteSpace(name)) + { + throw new Exception($"file:{file.ActualFile} 定义了一个空的table类名"); + } + string module = TypeUtil.GetNamespace(fullName); + string valueType = (data.GetField("value_type") as DString).Value.Trim(); + string index = (data.GetField("index") as DString).Value.Trim(); + string mode = (data.GetField("mode") as DString).Value.Trim(); + string group = (data.GetField("group") as DString).Value.Trim(); + string comment = (data.GetField("comment") as DString).Value.Trim(); + bool isDefineFromExcel = (data.GetField("define_from_excel") as DBool).Value; + string inputFile = (data.GetField("input") as DString).Value.Trim(); + string patchInput = (data.GetField("patch_input") as DString).Value.Trim(); + string tags = (data.GetField("tags") as DString).Value.Trim(); + AddTable(file.OriginFile, name, module, valueType, index, mode, group, comment, isDefineFromExcel, inputFile, patchInput, tags); + }; + } + } + + private async Task LoadEnumListFromFileAsync(string dataDir) + { + if (this._importExcelEnumFiles.Count == 0) + { + return; + } + var inputFileInfos = await DataLoaderUtil.CollectInputFilesAsync(this.Agent, this._importExcelEnumFiles, dataDir); + + var defTableRecordType = new DefBean(new CfgBean() + { + Namespace = "__intern__", + Name = "__EnumInfo__", + Parent = "", + Alias = "", + IsValueType = false, + Sep = "", + TypeId = 0, + IsSerializeCompatible = false, + Fields = new List + { + new CfgField() { Name = "full_name", Type = "string" }, + new CfgField() { Name = "item", Type = "string" }, + new CfgField() { Name = "alias", Type = "string" }, + new CfgField() { Name = "value", Type = "int" }, + new CfgField() { Name = "comment", Type = "string" }, + new CfgField() { Name = "tags", Type = "string" }, + } + }) + { + AssemblyBase = new DefAssembly("", null, new List(), Agent), + }; + defTableRecordType.PreCompile(); + defTableRecordType.Compile(); + defTableRecordType.PostCompile(); + var tableRecordType = TBean.Create(false, defTableRecordType); + + foreach (var file in inputFileInfos) + { + var source = new ExcelDataSource(); + var bytes = await this.Agent.GetFromCacheOrReadAllBytesAsync(file.ActualFile, file.MD5); + var records = DataLoaderUtil.LoadCfgRecords(tableRecordType, file.OriginFile, null, bytes, true); + + PEnum curEnum = null; + foreach (var r in records) + { + DBean data = r.Data; + //s_logger.Info("== read text:{}", r.Data); + string fullName = (data.GetField("full_name") as DString).Value.Trim(); + string name = TypeUtil.GetName(fullName); + if (string.IsNullOrWhiteSpace(fullName) || string.IsNullOrWhiteSpace(name)) + { + throw new Exception($"file:{file.ActualFile} 定义了一个空的enum类名"); + } + string module = TypeUtil.GetNamespace(fullName); + + if (curEnum == null || curEnum.Name != name || curEnum.Namespace != module) + { + curEnum = new PEnum() { Name = name, Namespace = module, IsFlags = false, Comment = "", IsUniqueItemId = true }; + this._enums.Add(curEnum); + } + + string item = (data.GetField("item") as DString).Value.Trim(); + if (string.IsNullOrWhiteSpace(item)) + { + throw new Exception($"file:{file.ActualFile} module:'{module}' name:'{name}' 定义了一个空枚举项"); + } + string alias = (data.GetField("alias") as DString).Value.Trim(); + string value = (data.GetField("value") as DInt).Value.ToString(); + string comment = (data.GetField("comment") as DString).Value.Trim(); + string tags = (data.GetField("tags") as DString).Value.Trim(); + curEnum.Items.Add(new EnumItem() { Name = item, Alias = alias, Value = value, Comment = comment, Tags = tags }); + }; + } + } + + private async Task LoadBeanListFromFileAsync(string dataDir) + { + if (this._importExcelBeanFiles.Count == 0) + { + return; + } + var inputFileInfos = await DataLoaderUtil.CollectInputFilesAsync(this.Agent, this._importExcelBeanFiles, dataDir); + + + var ass = new DefAssembly("", null, new List(), Agent); + + var defBeanFieldType = new DefBean(new CfgBean() + { + Namespace = "__intern__", + Name = "__FieldInfo__", + Parent = "", + Alias = "", + IsValueType = false, + Sep = "", + TypeId = 0, + IsSerializeCompatible = false, + Fields = new List + { + new CfgField() { Name = "name", Type = "string" }, + new CfgField() { Name = "type", Type = "string" }, + new CfgField() { Name = "sep", Type = "string" }, + new CfgField() { Name = "is_multi_rows", Type = "bool" }, + new CfgField() { Name = "index", Type = "string" }, + new CfgField() { Name = "group", Type = "string" }, + new CfgField() { Name = "ref", Type = "string", IgnoreNameValidation = true }, + new CfgField() { Name = "path", Type = "string" }, + new CfgField() { Name = "comment", Type = "string" }, + new CfgField() { Name = "tags", Type = "string" }, + new CfgField() { Name = "orientation", Type = "string" }, + } + }) + { + AssemblyBase = ass, + }; + + defBeanFieldType.PreCompile(); + defBeanFieldType.Compile(); + defBeanFieldType.PostCompile(); + + ass.AddType(defBeanFieldType); + + var defTableRecordType = new DefBean(new CfgBean() + { + Namespace = "__intern__", + Name = "__BeanInfo__", + Parent = "", + Alias = "", + IsValueType = false, + Sep = "", + TypeId = 0, + IsSerializeCompatible = false, + Fields = new List + { + new CfgField() { Name = "full_name", Type = "string" }, + new CfgField() { Name = "sep", Type = "string" }, + new CfgField() { Name = "comment", Type = "string" }, + new CfgField() { Name = "tags", Type = "string" }, + new CfgField() { Name = "fields", Type = "list,__FieldInfo__", IsMultiRow = true }, + } + }) + { + AssemblyBase = ass, + }; + ass.AddType(defTableRecordType); + defTableRecordType.PreCompile(); + defTableRecordType.Compile(); + defTableRecordType.PostCompile(); + ass.MarkMultiRows(); + var tableRecordType = TBean.Create(false, defTableRecordType); + + foreach (var file in inputFileInfos) + { + var source = new ExcelDataSource(); + var bytes = await this.Agent.GetFromCacheOrReadAllBytesAsync(file.ActualFile, file.MD5); + var records = DataLoaderUtil.LoadCfgRecords(tableRecordType, file.OriginFile, null, bytes, true); + + foreach (var r in records) + { + DBean data = r.Data; + //s_logger.Info("== read text:{}", r.Data); + string fullName = (data.GetField("full_name") as DString).Value.Trim(); + string name = TypeUtil.GetName(fullName); + if (string.IsNullOrWhiteSpace(fullName) || string.IsNullOrWhiteSpace(name)) + { + throw new Exception($"file:{file.ActualFile} 定义了一个空bean类名"); + } + string module = TypeUtil.GetNamespace(fullName); + + + string sep = (data.GetField("sep") as DString).Value.Trim(); + string comment = (data.GetField("comment") as DString).Value.Trim(); + string tags = (data.GetField("tags") as DString).Value.Trim(); + DList fields = data.GetField("fields") as DList; + var curBean = new CfgBean() + { + Name = name, + Namespace = module, + Sep = sep, + Comment = comment, + Tags = tags, + Parent = "", + Fields = fields.Datas.Select(d => (DBean)d).Select(b => this.CreateField( + file.ActualFile, + (b.GetField("name") as DString).Value.Trim(), + (b.GetField("type") as DString).Value.Trim(), + (b.GetField("index") as DString).Value.Trim(), + (b.GetField("sep") as DString).Value.Trim(), + (b.GetField("is_multi_rows") as DBool).Value, + (b.GetField("group") as DString).Value, + "", + "", + (b.GetField("comment") as DString).Value.Trim(), + (b.GetField("ref") as DString).Value.Trim(), + (b.GetField("path") as DString).Value.Trim(), + "", + "", + "", + "", + (b.GetField("tags") as DString).Value.Trim(), + false, + DefUtil.ParseOrientation((b.GetField("orientation") as DString).Value) + )).ToList(), + }; + this._beans.Add(curBean); + }; + } + } + + public async Task LoadDefinesFromFileAsync(string dataDir) + { + await Task.WhenAll(LoadTableListFromFileAsync(dataDir), LoadEnumListFromFileAsync(dataDir), LoadBeanListFromFileAsync(dataDir)); + await LoadTableValueTypeDefinesFromFileAsync(dataDir); + } private static readonly List _fieldOptionalAttrs = new() { diff --git a/src/LubanAssistant/Source/Defs/DefAssembly.cs b/src/LubanAssistant/Source/Defs/DefAssembly.cs index f7d23b3..7cfad64 100644 --- a/src/LubanAssistant/Source/Defs/DefAssembly.cs +++ b/src/LubanAssistant/Source/Defs/DefAssembly.cs @@ -13,16 +13,19 @@ namespace Luban.Job.Cfg.Defs { public class TableDataInfo { + public DefTable Table { get; } + public List MainRecords { get; } public List PatchRecords { get; } - public List FinalRecords { get; set; } + //public List FinalRecords { get; set; } - public Dictionary FinalRecordMap { get; set; } + //public Dictionary FinalRecordMap { get; set; } - public TableDataInfo(List mainRecords, List patchRecords) + public TableDataInfo(DefTable table, List mainRecords, List patchRecords) { + Table = table; MainRecords = mainRecords; PatchRecords = patchRecords; } @@ -34,6 +37,8 @@ namespace Luban.Job.Cfg.Defs public new static DefAssembly LocalAssebmly { get => (DefAssembly)DefAssemblyBase.LocalAssebmly; set => DefAssemblyBase.LocalAssebmly = value; } + public Service CfgTargetService { get; private set; } + private readonly string _patchName; private readonly List _excludeTags; @@ -51,7 +56,11 @@ namespace Luban.Job.Cfg.Defs public bool NeedExport(List groups) { - return true; + if (groups.Count == 0) + { + return true; + } + return groups.Any(g => CfgTargetService.Groups.Contains(g)); } private readonly List _patches = new List(); @@ -62,6 +71,7 @@ namespace Luban.Job.Cfg.Defs public Dictionary CfgTables { get; } = new Dictionary(); + public Patch GetPatch(string name) { return _patches.Find(b => b.Name == name); @@ -82,30 +92,12 @@ namespace Luban.Job.Cfg.Defs public void AddDataTable(DefTable table, List mainRecords, List patchRecords) { - _recordsByTables[table.FullName] = new TableDataInfo(mainRecords, patchRecords); + _recordsByTables[table.FullName] = new TableDataInfo(table, mainRecords, patchRecords); } public List GetTableAllDataList(DefTable table) { - return _recordsByTables[table.FullName].FinalRecords; - } - - public List GetTableExportDataList(DefTable table) - { - var tableDataInfo = _recordsByTables[table.FullName]; - if (_excludeTags.Count == 0) - { - return tableDataInfo.FinalRecords; - } - else - { - var finalRecords = tableDataInfo.FinalRecords.Where(r => r.IsNotFiltered(_excludeTags)).ToList(); - if (table.IsOneValueTable && finalRecords.Count != 1) - { - throw new Exception($"配置表 {table.FullName} 是单值表 mode=one,但数据个数:{finalRecords.Count} != 1"); - } - return finalRecords; - } + return _recordsByTables[table.FullName].MainRecords; } public TableDataInfo GetTableDataInfo(DefTable table) @@ -118,12 +110,60 @@ namespace Luban.Job.Cfg.Defs return Types.Values.Where(t => t is DefTable ct && ct.NeedExport).Select(t => (DefTable)t).ToList(); } - public void Load(Defines defines) + public List GetExportTypes() + { + var refTypes = new Dictionary(); + 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 e in this.Types) + { + if (!refTypes.ContainsKey(e.Key) && (e.Value is DefEnum)) + { + refTypes.Add(e.Key, e.Value); + } + } + + 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) { SupportDatetimeType = true; TopModule = defines.TopModule; + CfgTargetService = defines.Services.Find(s => s.Name == outputService); + + if (CfgTargetService == null) + { + throw new ArgumentException($"service:{outputService} not exists"); + } + + if (!string.IsNullOrWhiteSpace(_patchName)) + { + TargetPatch = defines.Patches.Find(b => b.Name == _patchName); + if (TargetPatch == null) + { + throw new Exception($"patch '{_patchName}' not in valid patch set"); + } + } + this._patches.AddRange(defines.Patches); foreach (var e in defines.Enums) diff --git a/src/LubanAssistant/Source/Utils/CacheFileUtil.cs b/src/LubanAssistant/Source/Utils/CacheFileUtil.cs index 7a338ba..e3ff28e 100644 --- a/src/LubanAssistant/Source/Utils/CacheFileUtil.cs +++ b/src/LubanAssistant/Source/Utils/CacheFileUtil.cs @@ -38,7 +38,7 @@ namespace Luban.Job.Common.Utils throw new System.NotSupportedException(); } var md5 = FileUtil.CalcMD5(bytes); -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE CacheManager.Ins.AddCache(fileName, md5, bytes); #endif return md5; @@ -47,7 +47,7 @@ namespace Luban.Job.Common.Utils public static string GenMd5AndAddCache(string fileName, byte[] bytes) { var md5 = FileUtil.CalcMD5(bytes); -#if !LUBAN_ASSISTANT +#if !LUBAN_LITE CacheManager.Ins.AddCache(fileName, md5, bytes); #endif return md5; diff --git a/src/LubanAssistant/Source/Utils/DataLoaderUtil.cs b/src/LubanAssistant/Source/Utils/DataLoaderUtil.cs index a61dfea..1350852 100644 --- a/src/LubanAssistant/Source/Utils/DataLoaderUtil.cs +++ b/src/LubanAssistant/Source/Utils/DataLoaderUtil.cs @@ -4,6 +4,7 @@ using Luban.Job.Cfg.DataCreators; using Luban.Job.Cfg.Datas; using Luban.Job.Cfg.DataSources; using Luban.Job.Cfg.Defs; +using Luban.Job.Common.Defs; using Luban.Job.Common.Types; using Luban.Job.Common.Utils; using Luban.Server.Common; @@ -18,7 +19,7 @@ namespace Luban.Job.Cfg.Utils { public static class DataLoaderUtil { - private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger(); + //private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger(); public class InputFileInfo { @@ -95,7 +96,7 @@ namespace Luban.Job.Cfg.Utils } } - public static async Task LoadTableAsync(IAgent agent, DefTable table, string dataDir, string patchName, string patchDataDir) + public static async Task LoadTableAsync(IAgent agent, DefTable table, string dataDir, string patchName, string patchDataDir) { var mainLoadTasks = new List>>(); var mainGenerateTask = GenerateLoadRecordFromFileTasksAsync(agent, table, dataDir, table.InputFiles, mainLoadTasks); @@ -119,7 +120,7 @@ namespace Luban.Job.Cfg.Utils { mainRecords.AddRange(await task); } - s_logger.Trace("== load main records. count:{count}", mainRecords.Count); + //s_logger.Trace("== load main records. count:{count}", mainRecords.Count); List patchRecords = null; if (patchGenerateTask != null) @@ -130,12 +131,10 @@ namespace Luban.Job.Cfg.Utils { patchRecords.AddRange(await task); } - s_logger.Trace("== load patch records. count:{count}", patchRecords.Count); + //s_logger.Trace("== load patch records. count:{count}", patchRecords.Count); } - table.Assembly.AddDataTable(table, mainRecords, patchRecords); - - s_logger.Trace("table:{name} record num:{num}", table.FullName, mainRecords.Count); + return new TableDataInfo(table, mainRecords, patchRecords); } public static async Task LoadCfgDataAsync(IAgent agent, DefAssembly ass, string dataDir, string patchName, string patchDataDir) @@ -193,31 +192,34 @@ namespace Luban.Job.Cfg.Utils } } -#if !LUBAN_ASSISTANT - public static async Task LoadTextTablesAsync(IAgent agent, DefAssembly ass, string baseDir, string textTableFiles) + public static async Task LoadTableDataAsync(string rootDefineFile, string inputDataDir, string tableName) { - var tasks = new List>(); - var files = textTableFiles.Split(','); - foreach (var file in await CollectInputFilesAsync(agent, files, baseDir)) - { - tasks.Add(agent.GetFromCacheOrReadAllBytesAsync(file.ActualFile, file.MD5)); - } + IAgent agent = new LocalAgent(); + var loader = new CfgDefLoader(agent); + await loader.LoadAsync(rootDefineFile); + await loader.LoadDefinesFromFileAsync(inputDataDir); - var textTable = ass.ExportTextTable; - for (int i = 0; i < tasks.Count; i++) + var rawDefines = loader.BuildDefines(); + + TimeZoneInfo timeZoneInfo = null; + + var excludeTags = new List(); + var ass = new DefAssembly("", timeZoneInfo, excludeTags, agent); + + ass.Load("all", rawDefines); + + DefAssemblyBase.LocalAssebmly = ass; + + var table = ass.GetCfgTable(tableName); + + if (table == null) { - var bytes = await tasks[i]; - try - { - textTable.LoadFromFile(files[i], bytes); - } - catch (Exception e) - { - throw new Exception($"load text table file:{files[i]} fail", e); - } + throw new Exception($"table:{tableName}不存在"); } + var tableDataInfo = await LoadTableAsync(agent, table, inputDataDir, "", ""); + //MessageBox.Show($"table:{table.FullName} input:{StringUtil.CollectionToString(table.InputFiles)} record num:{datas.Count}"); + return tableDataInfo; } -#endif } } diff --git a/src/LubanAssistant/packages.config b/src/LubanAssistant/packages.config index 27dbb33..8d15c61 100644 --- a/src/LubanAssistant/packages.config +++ b/src/LubanAssistant/packages.config @@ -1,17 +1,14 @@  - - + - -