diff --git a/.gitignore b/.gitignore
index 04ce749..383ff42 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,4 @@
**/~$*
/DungeonShooting_ExcelTool/obj
/DungeonShooting_ExcelTool/bin
+/DungeonShooting_Godot/DungeonShooting.sln.DotSettings.user
diff --git a/DungeonShooting_Godot/.gitignore b/DungeonShooting_Godot/.gitignore
index 407c74e..4a80ac8 100644
--- a/DungeonShooting_Godot/.gitignore
+++ b/DungeonShooting_Godot/.gitignore
@@ -3,4 +3,12 @@
/.mono
/.vs
/.godot
-/build
\ No newline at end of file
+/build
+/excelTool/bin
+/excelTool/obj
+/excelTool/excel
+/excelTool/.idea
+/excelTool/.vs
+/excelTool/.vscode
+/excelTool/publish
+/excelTool/Folder.DotSettings.user
diff --git a/DungeonShooting_Godot/DungeonShooting.csproj b/DungeonShooting_Godot/DungeonShooting.csproj
index 1c27fa0..6da3a83 100644
--- a/DungeonShooting_Godot/DungeonShooting.csproj
+++ b/DungeonShooting_Godot/DungeonShooting.csproj
@@ -10,11 +10,10 @@
+
-
-
-
+
\ No newline at end of file
diff --git a/DungeonShooting_Godot/DungeonShooting.sln.DotSettings.user b/DungeonShooting_Godot/DungeonShooting.sln.DotSettings.user
deleted file mode 100644
index 43de714..0000000
--- a/DungeonShooting_Godot/DungeonShooting.sln.DotSettings.user
+++ /dev/null
@@ -1,8 +0,0 @@
-
- WARNING
- On
- On
- On
- <SessionState ContinuousTestingMode="0" IsActive="True" Name="解决方案中的所有测试" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
- <Solution />
-</SessionState>
\ No newline at end of file
diff --git a/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/ExcelGenerator.cs b/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/ExcelGenerator.cs
index 0915274..21df908 100644
--- a/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/ExcelGenerator.cs
+++ b/DungeonShooting_Godot/addons/dungeonShooting_plugin/generator/ExcelGenerator.cs
@@ -1,761 +1,119 @@
#if TOOLS
using System;
-using System.Collections.Generic;
using System.IO;
using System.Text.Json;
-using System.Text.RegularExpressions;
using Config;
using Godot;
-using NPOI.SS.UserModel;
-using NPOI.XSSF.UserModel;
using Array = Godot.Collections.Array;
-using Environment = System.Environment;
namespace Generator;
public static class ExcelGenerator
{
- private static HashSet _excelNames = new HashSet();
-
- private enum CollectionsType
- {
- None,
- Array,
- Map
- }
-
- private class MappingData
- {
- public string TypeStr;
- public string TypeName;
- public CollectionsType CollectionsType;
-
- public bool IsRefExcel;
- public string RefTypeStr;
- public string RefTypeName;
-
- public MappingData(string typeStr, string typeName, CollectionsType collectionsType)
- {
- TypeStr = typeStr;
- TypeName = typeName;
- CollectionsType = collectionsType;
- IsRefExcel = false;
- }
-
- public MappingData(string typeStr, string typeName, CollectionsType collectionsType, string refTypeStr, string refTypeName)
- {
- TypeStr = typeStr;
- TypeName = typeName;
- CollectionsType = collectionsType;
- IsRefExcel = true;
- RefTypeStr = refTypeStr;
- RefTypeName = refTypeName;
- }
- }
-
- private class ExcelData
- {
- public string TableName;
- public string OutCode;
- public List ColumnNames = new List();
- public Dictionary ColumnMappingData = new Dictionary();
- public Dictionary ColumnType = new Dictionary();
- public List> DataList = new List>();
- }
-
///
- /// 导出 Excel 表
+ /// 执行导出Excel表
///
- public static void ExportExcel()
+ public static bool ExportExcel()
{
+ var arr = new Array();
+ var toolDir = "excelTool";
var excelPath = "excel/";
var jsonPath = "resource/config/";
var codePath = "src/config/";
- ExportExcel(excelPath, jsonPath, codePath);
- }
-
- ///
- /// 导出 Excel 表
- ///
- /// excel文件路径
- /// json配置输出路径
- /// 代码输出路径
- public static bool ExportExcel(string excelFilePath, string jsonOutPath, string codeOutPath)
- {
- _excelNames.Clear();
- Debug.Log("当前路径: " + Environment.CurrentDirectory);
- Debug.Log("excel路径: " + excelFilePath);
- Debug.Log("json输出路径: " + jsonOutPath);
- Debug.Log("cs代码输出路径: " + codeOutPath);
+
+ //平台名称
+ var osName = OS.GetName();
+ //平台标识符
+ string rid;
+ string toolName;
+ if (osName == "Windows")
+ {
+ rid = "win-x64";
+ toolName = "ExcelTool.exe";
+ }
+ else if (osName == "macOS")
+ {
+ rid = "osx-x64";
+ toolName = "ExcelTool";
+ }
+ else
+ {
+ GD.PrintErr($"当前平台{osName}不支持导出Excel表");
+ return false;
+ }
+
+ var toolPath = $"{toolDir}/publish/{rid}";
+
+ if (!Directory.Exists(toolPath)) //判断是否编译过工具
+ {
+ GD.Print("开始编译导出工具");
+ var r = compilerTool(toolDir, rid, toolPath);
+ if (r != 0)
+ {
+ return false;
+ }
+ }
+ else if (File.ReadAllText($"{toolDir}/version") != File.ReadAllText($"{toolPath}/version")) //版本有变化
+ {
+ GD.Print("工具版本有变化,执行重新编译导出工具");
+ //删除编译目录
+ Directory.Delete(toolPath, true);
+ var r = compilerTool(toolDir, rid, toolPath);
+ if (r != 0)
+ {
+ return false;
+ }
+ }
+
+ var result = OS.Execute($"{toolPath}/{toolName}", new[] { excelPath, jsonPath, codePath }, arr);
+ foreach (var message in arr)
+ {
+ GD.Print(message);
+ }
+
+ if (result != 0)
+ {
+ return false;
+ }
+
try
{
- var excelDataList = new List();
-
- var directoryInfo = new DirectoryInfo(excelFilePath);
- if (directoryInfo.Exists)
- {
- var fileInfos = directoryInfo.GetFiles();
- //记录文件
- foreach (var fileInfo in fileInfos)
- {
- var fileName = Path.GetFileNameWithoutExtension(fileInfo.Name).FirstToUpper();
- _excelNames.Add(fileName);
- }
- //读取配置文件
- foreach (var fileInfo in fileInfos)
- {
- if (fileInfo.Extension == ".xlsx")
- {
- if (fileInfo.Name == "ExcelConfig.xlsx")
- {
- throw new Exception("excel表文件名称不允许叫'ExcelConfig.xlsx'!");
- }
- Debug.Log("excel表: " + fileInfo.FullName);
- excelDataList.Add(ReadExcel(fileInfo.FullName));
- }
- }
- }
-
- Debug.Log($"一共检测到excel表共{excelDataList.Count}张.");
- if (excelDataList.Count == 0)
- {
- return true;
- }
-
- if (Directory.Exists(codeOutPath))
- {
- Directory.Delete(codeOutPath, true);
- }
- if (Directory.Exists(jsonOutPath))
- {
- Directory.Delete(jsonOutPath, true);
- }
- Directory.CreateDirectory(codeOutPath);
- Directory.CreateDirectory(jsonOutPath);
-
- //保存配置和代码
- foreach (var excelData in excelDataList)
- {
- if (excelData.TableName == "ActivityBase")
- {
- //生成初始化 ActivityObject 代码
- GeneratorActivityObjectInit(excelData);
- }
- File.WriteAllText(codeOutPath + "ExcelConfig_" + excelData.TableName + ".cs", excelData.OutCode);
- var config = new JsonSerializerOptions();
- config.WriteIndented = true;
- File.WriteAllText(jsonOutPath + excelData.TableName + ".json", JsonSerializer.Serialize(excelData.DataList, config));
- }
-
- //生成加载代码
- var code = GeneratorInitCode(excelDataList);
- File.WriteAllText(codeOutPath + "ExcelConfig.cs", code);
+ GeneratorActivityObjectInit();
+ GD.Print("生成'src/framework/activity/ActivityObject_Init.cs'成功!");
}
catch (Exception e)
{
- PrintError(e.ToString());
+ GD.PrintErr(e.ToString());
return false;
}
return true;
}
- private static string GeneratorInitCode(List excelList)
+ //编译工具
+ private static int compilerTool(string csProjectPath, string rid, string outputPath)
{
- var code = $"using System;\n";
- code += $"using System.Collections.Generic;\n";
- code += $"using System.Text.Json;\n";
- code += $"using Godot;\n";
- code += $"\n";
- code += $"namespace Config;\n";
- code += $"\n";
- code += $"public static partial class ExcelConfig\n";
- code += $"{{\n";
+ //dotnet publish excelTool -c Release -r win-x64 -o ./excelTool/publish/win-x64
+ var outLog = new Array();
+ var result = OS.Execute("dotnet", new string[] { "publish", csProjectPath, "-c", "Release", "-r", rid, "-o", outputPath }, outLog);
+ foreach (var variant in outLog)
+ {
+ GD.Print(variant);
+ }
- var fieldCode = "";
- var callFuncCode = "";
- var callInitRefFuncCode = "";
- var funcCode = "";
- var initRefFuncCode = "";
+ return result;
+ }
+
+ //生成初始化 ActivityObject 代码
+ private static void GeneratorActivityObjectInit()
+ {
+ var text = File.ReadAllText($"resource/config/{nameof(ExcelConfig.ActivityBase)}.json");
+ var array = JsonSerializer.Deserialize[]>(text);
- foreach (var excelData in excelList)
- {
- var idName = excelData.ColumnNames[0];
- var idTypeStr = excelData.ColumnMappingData[idName].TypeStr;
-
- //---------------------------- 引用其他表处理 ----------------------------
- var hasRefColumn = false;
- var refColumnNoneCode = "";
- foreach (var columnName in excelData.ColumnNames)
- {
- var mappingData = excelData.ColumnMappingData[columnName];
- if (mappingData.IsRefExcel)
- {
- hasRefColumn = true;
- if (mappingData.CollectionsType == CollectionsType.None)
- {
- refColumnNoneCode += $" if (!string.IsNullOrEmpty(item.__{columnName}))\n";
- refColumnNoneCode += $" {{\n";
- refColumnNoneCode += $" item.{columnName} = {mappingData.RefTypeName}_Map[item.__{columnName}];\n";
- refColumnNoneCode += $" }}\n";
- }
- else if (mappingData.CollectionsType == CollectionsType.Array)
- {
- refColumnNoneCode += $" if (item.__{columnName} != null)\n";
- refColumnNoneCode += $" {{\n";
- refColumnNoneCode += $" item.{columnName} = new {mappingData.RefTypeName}[item.__{columnName}.Length];\n";
- refColumnNoneCode += $" for (var i = 0; i < item.__{columnName}.Length; i++)\n";
- refColumnNoneCode += $" {{\n";
- refColumnNoneCode += $" item.{columnName}[i] = {mappingData.RefTypeName}_Map[item.__{columnName}[i]];\n";
- refColumnNoneCode += $" }}\n";
- refColumnNoneCode += $" }}\n";
- }
- else
- {
- refColumnNoneCode += $" if (item.__{columnName} != null)\n";
- refColumnNoneCode += $" {{\n";
- refColumnNoneCode += $" item.{columnName} = new {mappingData.RefTypeStr}();\n";
- refColumnNoneCode += $" foreach (var pair in item.__{columnName})\n";
- refColumnNoneCode += $" {{\n";
- refColumnNoneCode += $" item.{columnName}.Add(pair.Key, {mappingData.RefTypeName}_Map[pair.Value]);\n";
- refColumnNoneCode += $" }}\n";
- refColumnNoneCode += $" }}\n";
- }
- refColumnNoneCode += $"\n";
- }
- }
-
- //----------------------------- 数据集合 ------------------------------------
- fieldCode += $" /// \n";
- fieldCode += $" /// {excelData.TableName}.xlsx表数据集合, 以 List 形式存储, 数据顺序与 Excel 表相同\n";
- fieldCode += $" /// \n";
- fieldCode += $" public static List<{excelData.TableName}> {excelData.TableName}_List {{ get; private set; }}\n";
- fieldCode += $" /// \n";
- fieldCode += $" /// {excelData.TableName}.xlsx表数据集合, 里 Map 形式存储, key 为 {idName}\n";
- fieldCode += $" /// \n";
- fieldCode += $" public static Dictionary<{idTypeStr}, {excelData.TableName}> {excelData.TableName}_Map {{ get; private set; }}\n";
- fieldCode += $"\n";
-
- //------------------------------- 初始化函数 -------------------------------------
- callFuncCode += $" _Init{excelData.TableName}Config();\n";
-
- funcCode += $" private static void _Init{excelData.TableName}Config()\n";
- funcCode += $" {{\n";
- funcCode += $" try\n";
- funcCode += $" {{\n";
- funcCode += $" var text = _ReadConfigAsText(\"res://resource/config/{excelData.TableName}.json\");\n";
- if (hasRefColumn) //存在引用列
- {
- funcCode += $" {excelData.TableName}_List = new List<{excelData.TableName}>(JsonSerializer.Deserialize>(text));\n";
- }
- else
- {
- funcCode += $" {excelData.TableName}_List = JsonSerializer.Deserialize>(text);\n";
- }
- funcCode += $" {excelData.TableName}_Map = new Dictionary<{idTypeStr}, {excelData.TableName}>();\n";
- funcCode += $" foreach (var item in {excelData.TableName}_List)\n";
- funcCode += $" {{\n";
- funcCode += $" {excelData.TableName}_Map.Add(item.{idName}, item);\n";
- funcCode += $" }}\n";
- funcCode += $" }}\n";
- funcCode += $" catch (Exception e)\n";
- funcCode += $" {{\n";
- funcCode += $" GD.PrintErr(e.ToString());\n";
- funcCode += $" throw new Exception(\"初始化表'{excelData.TableName}'失败!\");\n";
- funcCode += $" }}\n";
- funcCode += $" }}\n";
-
-
- //------------------------------- 初始化引用 ---------------------------------
- if (hasRefColumn)
- {
- callInitRefFuncCode += $" _Init{excelData.TableName}Ref();\n";
-
- initRefFuncCode += $" private static void _Init{excelData.TableName}Ref()\n";
- initRefFuncCode += $" {{\n";
- initRefFuncCode += $" foreach (Ref_{excelData.TableName} item in {excelData.TableName}_List)\n";
- initRefFuncCode += $" {{\n";
- initRefFuncCode += $" try\n";
- initRefFuncCode += $" {{\n";
- initRefFuncCode += refColumnNoneCode;
- initRefFuncCode += $" }}\n";
- initRefFuncCode += $" catch (Exception e)\n";
- initRefFuncCode += $" {{\n";
- initRefFuncCode += $" GD.PrintErr(e.ToString());\n";
- initRefFuncCode += $" throw new Exception(\"初始化'{excelData.TableName}'引用其他表数据失败, 当前行id: \" + item.Id);\n";
- initRefFuncCode += $" }}\n";
- initRefFuncCode += $" }}\n";
- initRefFuncCode += $" }}\n";
- }
- }
-
- code += fieldCode;
- code += $"\n";
- code += $" private static bool _init = false;\n";
- code += $" /// \n";
- code += $" /// 初始化所有配置表数据\n";
- code += $" /// \n";
- code += $" public static void Init()\n";
- code += $" {{\n";
- code += $" if (_init) return;\n";
- code += $" _init = true;\n";
- code += $"\n";
- code += callFuncCode;
- code += $"\n";
- code += callInitRefFuncCode;
- code += $" }}\n";
- code += funcCode;
- code += $"\n";
- code += initRefFuncCode;
- code += $" private static string _ReadConfigAsText(string path)\n";
- code += $" {{\n";
- code += $" var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);\n";
- code += $" var asText = file.GetAsText();\n";
- code += $" file.Dispose();\n";
- code += $" return asText;\n";
- code += $" }}\n";
- code += $"}}";
- return code;
- }
-
- private static ExcelData ReadExcel(string excelPath)
- {
- var excelData = new ExcelData();
- //文件名称
- var fileName = Path.GetFileNameWithoutExtension(excelPath).FirstToUpper();
- excelData.TableName = fileName;
- //输出代码
- var outStr = $"using System.Text.Json.Serialization;\n";
- outStr += $"using System.Collections.Generic;\n\n";
- outStr += $"namespace Config;\n\n";
- outStr += $"public static partial class ExcelConfig\n{{\n";
- outStr += $" public class {fileName}\n";
- outStr += $" {{\n";
- //继承的带有引用其他表的类代码
- var outRefStr = "";
-
- var cloneFuncStr = $" /// \n";
- cloneFuncStr += $" /// 返回浅拷贝出的新对象\n";
- cloneFuncStr += $" /// \n";
- cloneFuncStr += $" public {fileName} Clone()\n";
- cloneFuncStr += $" {{\n";
- cloneFuncStr += $" var inst = new {fileName}();\n";
-
- var sourceFile = excelPath;
-
- //行数
- var rowCount = -1;
- //列数
- var columnCount = -1;
-
- //加载表数据
- var workbook = new XSSFWorkbook(sourceFile);
- using (workbook)
- {
- var sheet1 = workbook.GetSheet("Sheet1");
- rowCount = sheet1.LastRowNum;
- //先解析表中的列名, 注释, 类型
- var names = sheet1.GetRow(0);
- var descriptions = sheet1.GetRow(1);
- var types = sheet1.GetRow(2);
- columnCount = names.LastCellNum;
- foreach (var cell in names)
- {
- //字段名称
- var field = GetCellStringValue(cell);
- if (string.IsNullOrEmpty(field))
- {
- if (cell.ColumnIndex == 0)
- {
- throw new Exception($"表'{fileName}'的列数为0!");
- }
- //到达最后一列了
- columnCount = cell.ColumnIndex;
- break;
- }
- field = field.FirstToUpper();
- excelData.ColumnNames.Add(field);
- if (field == "Clone")
- {
- throw new Exception($"表'{fileName}'中不允许有'Clone'字段!");
- }
-
- var descriptionCell = descriptions.GetCell(cell.ColumnIndex);
- //描述
- string description;
- if (descriptionCell != null)
- {
- description = GetCellStringValue(descriptionCell).Replace("\n", "
\n /// ");
- }
- else
- {
- description = "";
- }
- //类型
- var typeString = GetCellStringValue(types.GetCell(cell.ColumnIndex));
- if (string.IsNullOrEmpty(typeString))
- {
- throw new Exception($"表'{fileName}'中'{field}'这一列类型为空!");
- }
-
- //尝试解析类型
- MappingData mappingData;
- try
- {
- mappingData = ConvertToType(typeString.Replace(" ", ""));
- }
- catch (Exception e)
- {
- PrintError(e.ToString());
- throw new Exception($"表'{fileName}'中'{field}'这一列类型描述语法错误: {typeString}");
- }
-
- if (!excelData.ColumnMappingData.TryAdd(field, mappingData))
- {
- throw new Exception($"表'{fileName}'中存在相同名称的列: '{field}'!");
- }
- outStr += $" /// \n";
- outStr += $" /// {description}\n";
- outStr += $" /// \n";
- if (!mappingData.IsRefExcel) //没有引用其他表
- {
- outStr += $" [JsonInclude]\n";
- outStr += $" public {mappingData.TypeStr} {field};\n\n";
- }
- else
- {
- outStr += $" public {mappingData.RefTypeStr} {field};\n\n";
- }
-
- if (mappingData.IsRefExcel) //引用其他表
- {
- if (string.IsNullOrEmpty(outRefStr))
- {
- outRefStr += $" private class Ref_{fileName} : {fileName}\n";
- outRefStr += $" {{\n";
- }
- outRefStr += $" [JsonInclude]\n";
- outRefStr += $" public {mappingData.TypeStr} __{field};\n\n";
- }
-
- cloneFuncStr += $" inst.{field} = {field};\n";
- }
-
- cloneFuncStr += " return inst;\n";
- cloneFuncStr += " }\n";
- outStr += cloneFuncStr;
- outStr += " }\n";
-
- if (!string.IsNullOrEmpty(outRefStr))
- {
- outRefStr += " }\n";
- outStr += outRefStr;
- }
-
- outStr += "}";
-
- //解析字段类型
- foreach (var kv in excelData.ColumnMappingData)
- {
- var typeName = kv.Value.TypeName;
- var type = Type.GetType(typeName);
- if (type == null)
- {
- throw new Exception($"表'{fileName}'中'{kv.Key}'这一列类型未知! " + kv.Value.TypeStr);
- }
- excelData.ColumnType.Add(kv.Key, type);
- }
-
- //解析数据
- for (int i = 3; i <= rowCount; i++)
- {
- Dictionary data = null;
- var row = sheet1.GetRow(i);
- if (row == null)
- {
- continue;
- }
- for (int j = 0; j < columnCount; j++)
- {
- var cell = row.GetCell(j);
- var strValue = GetCellStringValue(cell);
- //如果这一行的第一列数据为空, 则跳过这一行
- if (j == 0 && string.IsNullOrEmpty(strValue))
- {
- break;
- }
- else if (data == null)
- {
- data = new Dictionary();
- excelData.DataList.Add(data);
- }
-
- var fieldName = excelData.ColumnNames[j];
- var mappingData = excelData.ColumnMappingData[fieldName];
- var field = mappingData.IsRefExcel ? "__" + fieldName : fieldName;
- try
- {
- switch (mappingData.TypeStr)
- {
- case "bool":
- case "boolean":
- data.Add(field, GetCellBooleanValue(cell));
- break;
- case "byte":
- data.Add(field, Convert.ToByte(GetCellNumberValue(cell)));
- break;
- case "sbyte":
- data.Add(field, Convert.ToSByte(GetCellNumberValue(cell)));
- break;
- case "short":
- data.Add(field, Convert.ToInt16(GetCellNumberValue(cell)));
- break;
- case "ushort":
- data.Add(field, Convert.ToUInt16(GetCellNumberValue(cell)));
- break;
- case "int":
- data.Add(field, Convert.ToInt32(GetCellNumberValue(cell)));
- break;
- case "uint":
- data.Add(field, Convert.ToUInt32(GetCellNumberValue(cell)));
- break;
- case "long":
- data.Add(field, Convert.ToInt64(GetCellNumberValue(cell)));
- break;
- case "ulong":
- data.Add(field, Convert.ToUInt64(GetCellNumberValue(cell)));
- break;
- case "float":
- data.Add(field, Convert.ToSingle(GetCellNumberValue(cell)));
- break;
- case "double":
- data.Add(field, GetCellNumberValue(cell));
- break;
- case "string":
- data.Add(field, GetCellStringValue(cell));
- break;
- default:
- {
- var cellStringValue = GetCellStringValue(cell);
- if (cellStringValue.Length == 0)
- {
- data.Add(field, null);
- }
- else
- {
- data.Add(field, JsonSerializer.Deserialize(cellStringValue, excelData.ColumnType[fieldName]));
- }
- }
- break;
- }
- }
- catch (Exception e)
- {
- PrintError(e.ToString());
- throw new Exception($"解析表'{fileName}'第'{i + 1}'行第'{j + 1}'列数据时发生异常");
- }
- }
- }
- }
-
- excelData.OutCode = outStr;
- return excelData;
- }
-
- private static string GetCellStringValue(ICell cell)
- {
- if (cell == null)
- {
- return "";
- }
- switch (cell.CellType)
- {
- case CellType.Numeric:
- return cell.NumericCellValue.ToString();
- case CellType.String:
- return cell.StringCellValue;
- case CellType.Formula:
- return cell.CellFormula;
- case CellType.Boolean:
- return cell.BooleanCellValue ? "true" : "false";
- }
-
- return "";
- }
-
- private static double GetCellNumberValue(ICell cell)
- {
- if (cell == null)
- {
- return 0;
- }
-
- return cell.NumericCellValue;
- }
-
- private static bool GetCellBooleanValue(ICell cell)
- {
- if (cell == null)
- {
- return false;
- }
-
- if (cell.CellType == CellType.Boolean)
- {
- return cell.BooleanCellValue;
- }
-
- var value = cell.StringCellValue;
- if (string.IsNullOrWhiteSpace(value))
- {
- return false;
- }
-
- return bool.Parse(value);
- }
-
- private static MappingData ConvertToType(string str, int depth = 0)
- {
- if (Regex.IsMatch(str, "^\\w+$"))
- {
- var typeStr = TypeStrMapping(str);
- var typeName = TypeNameMapping(str);
- return new MappingData(typeStr, typeName, CollectionsType.None);
- }
- else if (Regex.IsMatch(str, "^\\$\\w+$")) //引用其他表
- {
- var realName = str.Substring(1);
- if (!_excelNames.Contains(realName))
- {
- throw new Exception($"引用表数据失败, 未找到表: {realName}!");
- }
-
- if (depth > 1)
- {
- throw new Exception("引用表数据失败, 引用表数据仅支持放入第一层的数组和字典!");
- }
-
- return new MappingData(TypeStrMapping("string"), TypeNameMapping("string"), CollectionsType.None, realName, realName);
- }
- else if (str.StartsWith('{')) //字典
- {
- var tempStr = str.Substring(1, str.Length - 2);
- var index = tempStr.IndexOf(':');
- if (index == -1)
- {
- throw new Exception("类型描述语法错误!");
- }
-
- var keyStr = tempStr.Substring(0, index);
- if (!IsBaseType(keyStr))
- {
- throw new Exception($"字典key类型必须是基础类型!");
- }
-
- var type1 = ConvertToType(keyStr, depth + 1);
- var type2 = ConvertToType(tempStr.Substring(index + 1), depth + 1);
-
- var typeStr = $"Dictionary<{type1.TypeStr}, {type2.TypeStr}>";
- var typeName = $"System.Collections.Generic.Dictionary`2[[{type1.TypeName}],[{type2.TypeName}]]";
-
- if (type2.IsRefExcel) //引用过其他表
- {
- var refTypeStr = $"Dictionary<{type1.TypeStr}, {type2.RefTypeStr}>";
- return new MappingData(typeStr, typeName, CollectionsType.Map, refTypeStr, type2.RefTypeName);
- }
-
- return new MappingData(typeStr, typeName, CollectionsType.Map);
- }
- else if (str.StartsWith('[')) //数组
- {
- var tempStr = str.Substring(1, str.Length - 2);
- var typeData = ConvertToType(tempStr, depth + 1);
- var typeStr = typeData.TypeStr + "[]";
- var typeName = typeData.TypeName + "[]";
-
- if (typeData.IsRefExcel) //引用过其他表
- {
- var refTypeStr = typeData.RefTypeStr + "[]";
- return new MappingData(typeStr, typeName, CollectionsType.Array, refTypeStr, typeData.RefTypeName);
- }
-
- return new MappingData(typeStr, typeName, CollectionsType.Array);
- }
- throw new Exception("类型描述语法错误!");
- }
-
- private static string TypeStrMapping(string typeName)
- {
- switch (typeName)
- {
- case "boolean": return "bool";
- case "vector2": return "SerializeVector2";
- case "vector3": return "SerializeVector3";
- case "color": return "SerializeColor";
- }
-
- return typeName;
- }
-
- private static string TypeNameMapping(string typeName)
- {
- switch (typeName)
- {
- case "bool":
- case "boolean": return typeof(bool).FullName;
- case "byte": return typeof(byte).FullName;
- case "sbyte": return typeof(sbyte).FullName;
- case "short": return typeof(short).FullName;
- case "ushort": return typeof(ushort).FullName;
- case "int": return typeof(int).FullName;
- case "uint": return typeof(uint).FullName;
- case "long": return typeof(long).FullName;
- case "ulong": return typeof(ulong).FullName;
- case "string": return typeof(string).FullName;
- case "float": return typeof(float).FullName;
- case "double": return typeof(double).FullName;
- case "vector2": return "SerializeVector2";
- case "vector3": return "SerializeVector3";
- case "color": return "SerializeColor";
- }
-
- return typeName;
- }
-
- private static bool IsBaseType(string typeName)
- {
- switch (typeName)
- {
- case "bool":
- case "boolean":
- case "byte":
- case "sbyte":
- case "short":
- case "ushort":
- case "int":
- case "uint":
- case "long":
- case "ulong":
- case "string":
- case "float":
- case "double":
- return true;
- }
-
- return false;
- }
-
- private static void PrintError(string message)
- {
- Debug.LogError(message);
- }
-
- //生成 ActivityObject.Ids 代码
- private static void GeneratorActivityObjectInit(ExcelData activityExcelData)
- {
var code1 = "";
- foreach (var item in activityExcelData.DataList)
+
+ foreach (var item in array)
{
var id = item["Id"];
var name = item["Name"] + "";
diff --git a/DungeonShooting_Godot/excelTool/ExcelGenerator.cs b/DungeonShooting_Godot/excelTool/ExcelGenerator.cs
new file mode 100644
index 0000000..0268b2a
--- /dev/null
+++ b/DungeonShooting_Godot/excelTool/ExcelGenerator.cs
@@ -0,0 +1,769 @@
+
+using System.Text.Json;
+using System.Text.RegularExpressions;
+using Aspose.Cells;
+using Environment = System.Environment;
+
+public static class ExcelGenerator
+{
+ private static HashSet _excelNames = new HashSet();
+
+ private enum CollectionsType
+ {
+ None,
+ Array,
+ Map
+ }
+
+ private class MappingData
+ {
+ public string TypeStr;
+ public string TypeName;
+ public CollectionsType CollectionsType;
+
+ public bool IsRefExcel;
+ public string RefTypeStr;
+ public string RefTypeName;
+
+ public MappingData(string typeStr, string typeName, CollectionsType collectionsType)
+ {
+ TypeStr = typeStr;
+ TypeName = typeName;
+ CollectionsType = collectionsType;
+ IsRefExcel = false;
+ }
+
+ public MappingData(string typeStr, string typeName, CollectionsType collectionsType, string refTypeStr, string refTypeName)
+ {
+ TypeStr = typeStr;
+ TypeName = typeName;
+ CollectionsType = collectionsType;
+ IsRefExcel = true;
+ RefTypeStr = refTypeStr;
+ RefTypeName = refTypeName;
+ }
+ }
+
+ private class ExcelData
+ {
+ public string TableName;
+ public string OutCode;
+ public List ColumnNames = new List();
+ public Dictionary ColumnMappingData = new Dictionary();
+ public Dictionary ColumnType = new Dictionary();
+ public List> DataList = new List>();
+ }
+
+ ///
+ /// 导出 Excel 表
+ ///
+ public static bool ExportExcel()
+ {
+ var excelPath = "excel/";
+ var jsonPath = "config/";
+ var codePath = "src/";
+ return ExportExcel(excelPath, jsonPath, codePath);
+ }
+
+ ///
+ /// 导出 Excel 表
+ ///
+ /// excel文件路径
+ /// json配置输出路径
+ /// 代码输出路径
+ public static bool ExportExcel(string excelFilePath, string jsonOutPath, string codeOutPath)
+ {
+ _excelNames.Clear();
+ Console.WriteLine("当前路径: " + Environment.CurrentDirectory);
+ Console.WriteLine("excel路径: " + excelFilePath);
+ Console.WriteLine("json输出路径: " + jsonOutPath);
+ Console.WriteLine("cs代码输出路径: " + codeOutPath);
+ try
+ {
+ var excelDataList = new List();
+
+ var directoryInfo = new DirectoryInfo(excelFilePath);
+ if (directoryInfo.Exists)
+ {
+ var fileInfos = directoryInfo.GetFiles();
+ //记录文件
+ foreach (var fileInfo in fileInfos)
+ {
+ var fileName = Path.GetFileNameWithoutExtension(fileInfo.Name).FirstToUpper();
+ _excelNames.Add(fileName);
+ }
+ //读取配置文件
+ foreach (var fileInfo in fileInfos)
+ {
+ if (fileInfo.Extension == ".xlsx")
+ {
+ if (fileInfo.Name == "ExcelConfig.xlsx")
+ {
+ throw new Exception("excel表文件名称不允许叫'ExcelConfig.xlsx'!");
+ }
+ Console.WriteLine("excel表: " + fileInfo.FullName);
+ excelDataList.Add(ReadExcel(fileInfo.FullName));
+ }
+ }
+ }
+
+ Console.WriteLine($"一共检测到excel表共{excelDataList.Count}张.");
+ if (excelDataList.Count == 0)
+ {
+ return true;
+ }
+
+ if (Directory.Exists(codeOutPath))
+ {
+ Directory.Delete(codeOutPath, true);
+ }
+ if (Directory.Exists(jsonOutPath))
+ {
+ Directory.Delete(jsonOutPath, true);
+ }
+ Directory.CreateDirectory(codeOutPath);
+ Directory.CreateDirectory(jsonOutPath);
+
+ //保存配置和代码
+ foreach (var excelData in excelDataList)
+ {
+ File.WriteAllText(codeOutPath + "ExcelConfig_" + excelData.TableName + ".cs", excelData.OutCode);
+ var config = new JsonSerializerOptions();
+ config.WriteIndented = true;
+ File.WriteAllText(jsonOutPath + excelData.TableName + ".json", JsonSerializer.Serialize(excelData.DataList, config));
+ }
+
+ //生成加载代码
+ var code = GeneratorInitCode(excelDataList);
+ File.WriteAllText(codeOutPath + "ExcelConfig.cs", code);
+ }
+ catch (Exception e)
+ {
+ PrintError(e.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ private static string GeneratorInitCode(List excelList)
+ {
+ var code = $"using System;\n";
+ code += $"using System.Collections.Generic;\n";
+ code += $"using System.Text.Json;\n";
+ code += $"using Godot;\n";
+ code += $"\n";
+ code += $"namespace Config;\n";
+ code += $"\n";
+ code += $"public static partial class ExcelConfig\n";
+ code += $"{{\n";
+
+ var fieldCode = "";
+ var callFuncCode = "";
+ var callInitRefFuncCode = "";
+ var funcCode = "";
+ var initRefFuncCode = "";
+
+ foreach (var excelData in excelList)
+ {
+ var idName = excelData.ColumnNames[0];
+ var idTypeStr = excelData.ColumnMappingData[idName].TypeStr;
+
+ //---------------------------- 引用其他表处理 ----------------------------
+ var hasRefColumn = false;
+ var refColumnNoneCode = "";
+ foreach (var columnName in excelData.ColumnNames)
+ {
+ var mappingData = excelData.ColumnMappingData[columnName];
+ if (mappingData.IsRefExcel)
+ {
+ hasRefColumn = true;
+ if (mappingData.CollectionsType == CollectionsType.None)
+ {
+ refColumnNoneCode += $" if (!string.IsNullOrEmpty(item.__{columnName}))\n";
+ refColumnNoneCode += $" {{\n";
+ refColumnNoneCode += $" item.{columnName} = {mappingData.RefTypeName}_Map[item.__{columnName}];\n";
+ refColumnNoneCode += $" }}\n";
+ }
+ else if (mappingData.CollectionsType == CollectionsType.Array)
+ {
+ refColumnNoneCode += $" if (item.__{columnName} != null)\n";
+ refColumnNoneCode += $" {{\n";
+ refColumnNoneCode += $" item.{columnName} = new {mappingData.RefTypeName}[item.__{columnName}.Length];\n";
+ refColumnNoneCode += $" for (var i = 0; i < item.__{columnName}.Length; i++)\n";
+ refColumnNoneCode += $" {{\n";
+ refColumnNoneCode += $" item.{columnName}[i] = {mappingData.RefTypeName}_Map[item.__{columnName}[i]];\n";
+ refColumnNoneCode += $" }}\n";
+ refColumnNoneCode += $" }}\n";
+ }
+ else
+ {
+ refColumnNoneCode += $" if (item.__{columnName} != null)\n";
+ refColumnNoneCode += $" {{\n";
+ refColumnNoneCode += $" item.{columnName} = new {mappingData.RefTypeStr}();\n";
+ refColumnNoneCode += $" foreach (var pair in item.__{columnName})\n";
+ refColumnNoneCode += $" {{\n";
+ refColumnNoneCode += $" item.{columnName}.Add(pair.Key, {mappingData.RefTypeName}_Map[pair.Value]);\n";
+ refColumnNoneCode += $" }}\n";
+ refColumnNoneCode += $" }}\n";
+ }
+ refColumnNoneCode += $"\n";
+ }
+ }
+
+ //----------------------------- 数据集合 ------------------------------------
+ fieldCode += $" /// \n";
+ fieldCode += $" /// {excelData.TableName}.xlsx表数据集合, 以 List 形式存储, 数据顺序与 Excel 表相同\n";
+ fieldCode += $" /// \n";
+ fieldCode += $" public static List<{excelData.TableName}> {excelData.TableName}_List {{ get; private set; }}\n";
+ fieldCode += $" /// \n";
+ fieldCode += $" /// {excelData.TableName}.xlsx表数据集合, 里 Map 形式存储, key 为 {idName}\n";
+ fieldCode += $" /// \n";
+ fieldCode += $" public static Dictionary<{idTypeStr}, {excelData.TableName}> {excelData.TableName}_Map {{ get; private set; }}\n";
+ fieldCode += $"\n";
+
+ //------------------------------- 初始化函数 -------------------------------------
+ callFuncCode += $" _Init{excelData.TableName}Config();\n";
+
+ funcCode += $" private static void _Init{excelData.TableName}Config()\n";
+ funcCode += $" {{\n";
+ funcCode += $" try\n";
+ funcCode += $" {{\n";
+ funcCode += $" var text = _ReadConfigAsText(\"res://resource/config/{excelData.TableName}.json\");\n";
+ if (hasRefColumn) //存在引用列
+ {
+ funcCode += $" {excelData.TableName}_List = new List<{excelData.TableName}>(JsonSerializer.Deserialize>(text));\n";
+ }
+ else
+ {
+ funcCode += $" {excelData.TableName}_List = JsonSerializer.Deserialize>(text);\n";
+ }
+ funcCode += $" {excelData.TableName}_Map = new Dictionary<{idTypeStr}, {excelData.TableName}>();\n";
+ funcCode += $" foreach (var item in {excelData.TableName}_List)\n";
+ funcCode += $" {{\n";
+ funcCode += $" {excelData.TableName}_Map.Add(item.{idName}, item);\n";
+ funcCode += $" }}\n";
+ funcCode += $" }}\n";
+ funcCode += $" catch (Exception e)\n";
+ funcCode += $" {{\n";
+ funcCode += $" GD.PrintErr(e.ToString());\n";
+ funcCode += $" throw new Exception(\"初始化表'{excelData.TableName}'失败!\");\n";
+ funcCode += $" }}\n";
+ funcCode += $" }}\n";
+
+
+ //------------------------------- 初始化引用 ---------------------------------
+ if (hasRefColumn)
+ {
+ callInitRefFuncCode += $" _Init{excelData.TableName}Ref();\n";
+
+ initRefFuncCode += $" private static void _Init{excelData.TableName}Ref()\n";
+ initRefFuncCode += $" {{\n";
+ initRefFuncCode += $" foreach (Ref_{excelData.TableName} item in {excelData.TableName}_List)\n";
+ initRefFuncCode += $" {{\n";
+ initRefFuncCode += $" try\n";
+ initRefFuncCode += $" {{\n";
+ initRefFuncCode += refColumnNoneCode;
+ initRefFuncCode += $" }}\n";
+ initRefFuncCode += $" catch (Exception e)\n";
+ initRefFuncCode += $" {{\n";
+ initRefFuncCode += $" GD.PrintErr(e.ToString());\n";
+ initRefFuncCode += $" throw new Exception(\"初始化'{excelData.TableName}'引用其他表数据失败, 当前行id: \" + item.Id);\n";
+ initRefFuncCode += $" }}\n";
+ initRefFuncCode += $" }}\n";
+ initRefFuncCode += $" }}\n";
+ }
+ }
+
+ code += fieldCode;
+ code += $"\n";
+ code += $" private static bool _init = false;\n";
+ code += $" /// \n";
+ code += $" /// 初始化所有配置表数据\n";
+ code += $" /// \n";
+ code += $" public static void Init()\n";
+ code += $" {{\n";
+ code += $" if (_init) return;\n";
+ code += $" _init = true;\n";
+ code += $"\n";
+ code += callFuncCode;
+ code += $"\n";
+ code += callInitRefFuncCode;
+ code += $" }}\n";
+ code += funcCode;
+ code += $"\n";
+ code += initRefFuncCode;
+ code += $" private static string _ReadConfigAsText(string path)\n";
+ code += $" {{\n";
+ code += $" var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);\n";
+ code += $" var asText = file.GetAsText();\n";
+ code += $" file.Dispose();\n";
+ code += $" return asText;\n";
+ code += $" }}\n";
+ code += $"}}";
+ return code;
+ }
+
+ private static ExcelData ReadExcel(string excelPath)
+ {
+ var excelData = new ExcelData();
+ //文件名称
+ var fileName = Path.GetFileNameWithoutExtension(excelPath).FirstToUpper();
+ excelData.TableName = fileName;
+ //输出代码
+ var outStr = $"using System.Text.Json.Serialization;\n";
+ outStr += $"using System.Collections.Generic;\n\n";
+ outStr += $"namespace Config;\n\n";
+ outStr += $"public static partial class ExcelConfig\n{{\n";
+ outStr += $" public class {fileName}\n";
+ outStr += $" {{\n";
+ //继承的带有引用其他表的类代码
+ var outRefStr = "";
+
+ var cloneFuncStr = $" /// \n";
+ cloneFuncStr += $" /// 返回浅拷贝出的新对象\n";
+ cloneFuncStr += $" /// \n";
+ cloneFuncStr += $" public {fileName} Clone()\n";
+ cloneFuncStr += $" {{\n";
+ cloneFuncStr += $" var inst = new {fileName}();\n";
+
+ var sourceFile = excelPath;
+
+ //列数
+ var columnCount = -1;
+
+ //加载表数据
+ var workbook = new Workbook(sourceFile);
+ using (workbook)
+ {
+ var sheet1 = workbook.Worksheets[0];
+ var cells = sheet1.Cells;
+ //先解析表中的列名, 注释, 类型
+ var names = cells.Rows[0];
+ var descriptions = cells.Rows[1];
+ var types = cells.Rows[2];
+
+ columnCount = 0;
+ foreach (Cell cell in names)
+ {
+ //字段名称
+ var field = GetCellStringValue(cell);
+ if (string.IsNullOrEmpty(field))
+ {
+ if (cell.Column == 0)
+ {
+ throw new Exception($"表'{fileName}'的列数为0!");
+ }
+ //到达最后一列了
+ break;
+ }
+
+ columnCount++;
+ field = field.FirstToUpper();
+ excelData.ColumnNames.Add(field);
+ if (field == "Clone")
+ {
+ throw new Exception($"表'{fileName}'中不允许有'Clone'字段!");
+ }
+
+ var descriptionCell = descriptions[cell.Column];
+ //描述
+ string description;
+ if (descriptionCell != null)
+ {
+ description = GetCellStringValue(descriptionCell).Replace("\n", "
\n /// ");
+ }
+ else
+ {
+ description = "";
+ }
+ //类型
+ var typeString = GetCellStringValue(types[cell.Column]);
+ if (string.IsNullOrEmpty(typeString))
+ {
+ throw new Exception($"表'{fileName}'中'{field}'这一列类型为空!");
+ }
+
+ //尝试解析类型
+ MappingData mappingData;
+ try
+ {
+ mappingData = ConvertToType(typeString.Replace(" ", ""));
+ }
+ catch (Exception e)
+ {
+ PrintError(e.ToString());
+ throw new Exception($"表'{fileName}'中'{field}'这一列类型描述语法错误: {typeString}");
+ }
+
+ if (!excelData.ColumnMappingData.TryAdd(field, mappingData))
+ {
+ throw new Exception($"表'{fileName}'中存在相同名称的列: '{field}'!");
+ }
+ outStr += $" /// \n";
+ outStr += $" /// {description}\n";
+ outStr += $" /// \n";
+ if (!mappingData.IsRefExcel) //没有引用其他表
+ {
+ outStr += $" [JsonInclude]\n";
+ outStr += $" public {mappingData.TypeStr} {field};\n\n";
+ }
+ else
+ {
+ outStr += $" public {mappingData.RefTypeStr} {field};\n\n";
+ }
+
+ if (mappingData.IsRefExcel) //引用其他表
+ {
+ if (string.IsNullOrEmpty(outRefStr))
+ {
+ outRefStr += $" private class Ref_{fileName} : {fileName}\n";
+ outRefStr += $" {{\n";
+ }
+ outRefStr += $" [JsonInclude]\n";
+ outRefStr += $" public {mappingData.TypeStr} __{field};\n\n";
+ }
+
+ cloneFuncStr += $" inst.{field} = {field};\n";
+ }
+
+ cloneFuncStr += " return inst;\n";
+ cloneFuncStr += " }\n";
+ outStr += cloneFuncStr;
+ outStr += " }\n";
+
+ if (!string.IsNullOrEmpty(outRefStr))
+ {
+ outRefStr += " }\n";
+ outStr += outRefStr;
+ }
+
+ outStr += "}";
+
+ //解析字段类型
+ foreach (var kv in excelData.ColumnMappingData)
+ {
+ var typeName = kv.Value.TypeName;
+ var type = Type.GetType(typeName);
+ if (type == null)
+ {
+ throw new Exception($"表'{fileName}'中'{kv.Key}'这一列类型未知! " + kv.Value.TypeStr);
+ }
+ excelData.ColumnType.Add(kv.Key, type);
+ }
+
+ //解析数据
+ foreach (Row row in cells.Rows)
+ {
+ if (row == null || row.Index < 3)
+ {
+ continue;
+ }
+ Dictionary data = null;
+ for (int j = 0; j < columnCount; j++)
+ {
+ var cell = row[j];
+ var strValue = GetCellStringValue(cell);
+ //如果这一行的第一列数据为空, 则跳过这一行
+ if (j == 0 && string.IsNullOrEmpty(strValue))
+ {
+ break;
+ }
+ else if (data == null)
+ {
+ data = new Dictionary();
+ excelData.DataList.Add(data);
+ }
+
+ var fieldName = excelData.ColumnNames[j];
+ var mappingData = excelData.ColumnMappingData[fieldName];
+ var field = mappingData.IsRefExcel ? "__" + fieldName : fieldName;
+ try
+ {
+ switch (mappingData.TypeStr)
+ {
+ case "bool":
+ case "boolean":
+ data.Add(field, GetCellBooleanValue(cell));
+ break;
+ case "byte":
+ data.Add(field, Convert.ToByte(GetCellNumberValue(cell)));
+ break;
+ case "sbyte":
+ data.Add(field, Convert.ToSByte(GetCellNumberValue(cell)));
+ break;
+ case "short":
+ data.Add(field, Convert.ToInt16(GetCellNumberValue(cell)));
+ break;
+ case "ushort":
+ data.Add(field, Convert.ToUInt16(GetCellNumberValue(cell)));
+ break;
+ case "int":
+ data.Add(field, Convert.ToInt32(GetCellNumberValue(cell)));
+ break;
+ case "uint":
+ data.Add(field, Convert.ToUInt32(GetCellNumberValue(cell)));
+ break;
+ case "long":
+ data.Add(field, Convert.ToInt64(GetCellNumberValue(cell)));
+ break;
+ case "ulong":
+ data.Add(field, Convert.ToUInt64(GetCellNumberValue(cell)));
+ break;
+ case "float":
+ data.Add(field, Convert.ToSingle(GetCellNumberValue(cell)));
+ break;
+ case "double":
+ data.Add(field, GetCellNumberValue(cell));
+ break;
+ case "string":
+ data.Add(field, GetCellStringValue(cell));
+ break;
+ default:
+ {
+ var cellStringValue = GetCellStringValue(cell);
+ if (cellStringValue.Length == 0)
+ {
+ data.Add(field, null);
+ }
+ else
+ {
+ data.Add(field, JsonSerializer.Deserialize(cellStringValue, excelData.ColumnType[fieldName]));
+ }
+ }
+ break;
+ }
+ }
+ catch (Exception e)
+ {
+ PrintError(e.ToString());
+ throw new Exception($"解析表'{fileName}'第'{row.Index + 1}'行第'{j + 1}'列数据时发生异常");
+ }
+ }
+ }
+ }
+
+ excelData.OutCode = outStr;
+ return excelData;
+ }
+
+ private static string GetCellStringValue(Cell cell)
+ {
+ if (cell == null)
+ {
+ return "";
+ }
+ switch (cell.Type)
+ {
+ case CellValueType.IsNumeric:
+ return cell.DoubleValue.ToString();
+ case CellValueType.IsString:
+ return cell.StringValue;
+ case CellValueType.IsBool:
+ return cell.BoolValue ? "true" : "false";
+ }
+
+ return "";
+ }
+
+ private static double GetCellNumberValue(Cell cell)
+ {
+ if (cell == null)
+ {
+ return 0;
+ }
+
+ switch (cell.Type)
+ {
+ case CellValueType.IsNumeric:
+ return cell.DoubleValue;
+ case CellValueType.IsString:
+ return double.Parse(cell.StringValue);
+ case CellValueType.IsBool:
+ return cell.BoolValue ? 1 : 0;
+ }
+
+ return 0;
+ }
+
+ private static bool GetCellBooleanValue(Cell cell)
+ {
+ if (cell == null)
+ {
+ return false;
+ }
+
+ switch (cell.Type)
+ {
+ case CellValueType.IsNumeric:
+ return cell.DoubleValue != 0;
+ case CellValueType.IsString:
+ {
+ var value = cell.StringValue;
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return false;
+ }
+ return bool.Parse(value);
+ }
+ case CellValueType.IsBool:
+ return cell.BoolValue;
+ }
+
+ return false;
+ }
+
+ private static MappingData ConvertToType(string str, int depth = 0)
+ {
+ if (Regex.IsMatch(str, "^\\w+$"))
+ {
+ var typeStr = TypeStrMapping(str);
+ var typeName = TypeNameMapping(str);
+ return new MappingData(typeStr, typeName, CollectionsType.None);
+ }
+ else if (Regex.IsMatch(str, "^\\$\\w+$")) //引用其他表
+ {
+ var realName = str.Substring(1);
+ if (!_excelNames.Contains(realName))
+ {
+ throw new Exception($"引用表数据失败, 未找到表: {realName}!");
+ }
+
+ if (depth > 1)
+ {
+ throw new Exception("引用表数据失败, 引用表数据仅支持放入第一层的数组和字典!");
+ }
+
+ return new MappingData(TypeStrMapping("string"), TypeNameMapping("string"), CollectionsType.None, realName, realName);
+ }
+ else if (str.StartsWith('{')) //字典
+ {
+ var tempStr = str.Substring(1, str.Length - 2);
+ var index = tempStr.IndexOf(':');
+ if (index == -1)
+ {
+ throw new Exception("类型描述语法错误!");
+ }
+
+ var keyStr = tempStr.Substring(0, index);
+ if (!IsBaseType(keyStr))
+ {
+ throw new Exception($"字典key类型必须是基础类型!");
+ }
+
+ var type1 = ConvertToType(keyStr, depth + 1);
+ var type2 = ConvertToType(tempStr.Substring(index + 1), depth + 1);
+
+ var typeStr = $"Dictionary<{type1.TypeStr}, {type2.TypeStr}>";
+ var typeName = $"System.Collections.Generic.Dictionary`2[[{type1.TypeName}],[{type2.TypeName}]]";
+
+ if (type2.IsRefExcel) //引用过其他表
+ {
+ var refTypeStr = $"Dictionary<{type1.TypeStr}, {type2.RefTypeStr}>";
+ return new MappingData(typeStr, typeName, CollectionsType.Map, refTypeStr, type2.RefTypeName);
+ }
+
+ return new MappingData(typeStr, typeName, CollectionsType.Map);
+ }
+ else if (str.StartsWith('[')) //数组
+ {
+ var tempStr = str.Substring(1, str.Length - 2);
+ var typeData = ConvertToType(tempStr, depth + 1);
+ var typeStr = typeData.TypeStr + "[]";
+ var typeName = typeData.TypeName + "[]";
+
+ if (typeData.IsRefExcel) //引用过其他表
+ {
+ var refTypeStr = typeData.RefTypeStr + "[]";
+ return new MappingData(typeStr, typeName, CollectionsType.Array, refTypeStr, typeData.RefTypeName);
+ }
+
+ return new MappingData(typeStr, typeName, CollectionsType.Array);
+ }
+ throw new Exception("类型描述语法错误!");
+ }
+
+ private static string TypeStrMapping(string typeName)
+ {
+ switch (typeName)
+ {
+ case "boolean": return "bool";
+ case "vector2": return "SerializeVector2";
+ case "vector3": return "SerializeVector3";
+ case "color": return "SerializeColor";
+ }
+
+ return typeName;
+ }
+
+ private static string TypeNameMapping(string typeName)
+ {
+ switch (typeName)
+ {
+ case "bool":
+ case "boolean": return typeof(bool).FullName;
+ case "byte": return typeof(byte).FullName;
+ case "sbyte": return typeof(sbyte).FullName;
+ case "short": return typeof(short).FullName;
+ case "ushort": return typeof(ushort).FullName;
+ case "int": return typeof(int).FullName;
+ case "uint": return typeof(uint).FullName;
+ case "long": return typeof(long).FullName;
+ case "ulong": return typeof(ulong).FullName;
+ case "string": return typeof(string).FullName;
+ case "float": return typeof(float).FullName;
+ case "double": return typeof(double).FullName;
+ case "vector2": return "SerializeVector2";
+ case "vector3": return "SerializeVector3";
+ case "color": return "SerializeColor";
+ }
+
+ return typeName;
+ }
+
+ private static bool IsBaseType(string typeName)
+ {
+ switch (typeName)
+ {
+ case "bool":
+ case "boolean":
+ case "byte":
+ case "sbyte":
+ case "short":
+ case "ushort":
+ case "int":
+ case "uint":
+ case "long":
+ case "ulong":
+ case "string":
+ case "float":
+ case "double":
+ return true;
+ }
+
+ return false;
+ }
+
+ private static void PrintError(string message)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine(message);
+ Console.ResetColor();
+ }
+
+ ///
+ /// 字符串首字母小写
+ ///
+ public static string FirstToLower(this string str)
+ {
+ return str.Substring(0, 1).ToLower() + str.Substring(1);
+ }
+
+ ///
+ /// 字符串首字母大写
+ ///
+ public static string FirstToUpper(this string str)
+ {
+ return str.Substring(0, 1).ToUpper() + str.Substring(1);
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/excelTool/ExcelTool.csproj b/DungeonShooting_Godot/excelTool/ExcelTool.csproj
new file mode 100644
index 0000000..df4af1e
--- /dev/null
+++ b/DungeonShooting_Godot/excelTool/ExcelTool.csproj
@@ -0,0 +1,33 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ 12
+
+
+
+
+ PreserveNewest
+
+
+ Always
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DungeonShooting_Godot/excelTool/Program.cs b/DungeonShooting_Godot/excelTool/Program.cs
new file mode 100644
index 0000000..1dc0cdb
--- /dev/null
+++ b/DungeonShooting_Godot/excelTool/Program.cs
@@ -0,0 +1,26 @@
+
+public class Program
+{
+ public static int Main(string[] args)
+ {
+ Console.WriteLine("准备导出excel表...");
+ bool success;
+ if (args.Length >= 3)
+ {
+ success = ExcelGenerator.ExportExcel(args[0], args[1], args[2]);
+ }
+ else
+ {
+ success = ExcelGenerator.ExportExcel();
+ }
+
+ if (success)
+ {
+ Console.WriteLine("excel表导出成功!");
+ return 0;
+ }
+
+ Console.WriteLine("excel表导出失败!");
+ return -1;
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/excelTool/serialize/SerializeColor.cs b/DungeonShooting_Godot/excelTool/serialize/SerializeColor.cs
new file mode 100644
index 0000000..c1f6c1e
--- /dev/null
+++ b/DungeonShooting_Godot/excelTool/serialize/SerializeColor.cs
@@ -0,0 +1,31 @@
+
+
+using System.Text.Json.Serialization;
+
+///
+/// 可序列化的 Color 对象
+///
+public class SerializeColor
+{
+ public SerializeColor(float r, float g, float b, float a)
+ {
+ R = r;
+ G = g;
+ B = b;
+ A = a;
+ }
+
+ public SerializeColor()
+ {
+ }
+
+ [JsonInclude]
+ public float R { get; private set; }
+ [JsonInclude]
+ public float G { get; private set; }
+ [JsonInclude]
+ public float B { get; private set; }
+ [JsonInclude]
+ public float A { get; private set; }
+
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/excelTool/serialize/SerializeVector2.cs b/DungeonShooting_Godot/excelTool/serialize/SerializeVector2.cs
new file mode 100644
index 0000000..f3051d1
--- /dev/null
+++ b/DungeonShooting_Godot/excelTool/serialize/SerializeVector2.cs
@@ -0,0 +1,30 @@
+
+using System.Text.Json.Serialization;
+
+///
+/// 可序列化的 Vector2 对象
+///
+public class SerializeVector2
+{
+ public SerializeVector2(float x, float y)
+ {
+ X = x;
+ Y = y;
+ }
+
+ public SerializeVector2(SerializeVector2 v)
+ {
+ X = v.X;
+ Y = v.Y;
+ }
+
+ public SerializeVector2()
+ {
+
+ }
+
+ [JsonInclude]
+ public float X { get; private set; }
+ [JsonInclude]
+ public float Y { get; private set; }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/excelTool/serialize/SerializeVector3.cs b/DungeonShooting_Godot/excelTool/serialize/SerializeVector3.cs
new file mode 100644
index 0000000..60f74e8
--- /dev/null
+++ b/DungeonShooting_Godot/excelTool/serialize/SerializeVector3.cs
@@ -0,0 +1,32 @@
+using System.Text.Json.Serialization;
+
+///
+/// 可序列化的 Vector3 对象
+///
+public class SerializeVector3
+{
+ public SerializeVector3(float x, float y, float z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ }
+
+ public SerializeVector3(SerializeVector3 v)
+ {
+ X = v.X;
+ Y = v.Y;
+ }
+
+ public SerializeVector3()
+ {
+ }
+
+ [JsonInclude]
+ public float X { get; private set; }
+ [JsonInclude]
+ public float Y { get; private set; }
+ [JsonInclude]
+ public float Z { get; private set; }
+
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/excelTool/version b/DungeonShooting_Godot/excelTool/version
new file mode 100644
index 0000000..56a6051
--- /dev/null
+++ b/DungeonShooting_Godot/excelTool/version
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/DungeonShooting_Godot/export_presets.cfg b/DungeonShooting_Godot/export_presets.cfg
index e026db4..dbf459f 100644
--- a/DungeonShooting_Godot/export_presets.cfg
+++ b/DungeonShooting_Godot/export_presets.cfg
@@ -7,7 +7,7 @@
custom_features=""
export_filter="all_resources"
include_filter=""
-exclude_filter="excel/*,build/*"
+exclude_filter="excel/*,excelTool/*,build/*"
export_path="build/android/build.apk"
encryption_include_filters=""
encryption_exclude_filters=""
@@ -215,7 +215,7 @@
custom_features=""
export_filter="all_resources"
include_filter=""
-exclude_filter="resource/map/tileMaps/*,excel/*,build/*"
+exclude_filter="resource/map/tileMaps/*,excel/*,excelTool/*,build/*"
export_path="build/windows/game.exe"
encryption_include_filters=""
encryption_exclude_filters=""
diff --git a/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs b/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs
index 0f808aa..07195e8 100644
--- a/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs
+++ b/DungeonShooting_Godot/src/game/ui/editorTools/EditorToolsPanel.cs
@@ -294,8 +294,14 @@
///
private void ExportExcel()
{
- ExcelGenerator.ExportExcel();
- ShowTips("提示", "已启动导表程序, 注意查看控制台信息!");
+ if (ExcelGenerator.ExportExcel())
+ {
+ ShowTips("提示", "导出Excel表成功!");
+ }
+ else
+ {
+ ShowTips("错误", "导出Excel表失败,请查看控制台日志!");
+ }
}
///