using System; using System.IO; using UnityEngine; using UnityEditor; using System.Text; using XLua; namespace BFEditor { public static class ExportExcelTools { private const string DESIGN_EXCEL_KEY = "bf_excel_tool_excel_key"; private static bool failFlag = false; private static bool designSuccFlag = false; private static string failLog = ""; /// /// 提供给neo平台调用的一键导表 /// public static void ExportExcelToLua() { var designExcelPath = PlayerPrefs.GetString(DESIGN_EXCEL_KEY, ""); if (string.IsNullOrEmpty(designExcelPath) || !Directory.Exists(designExcelPath)) { Debug.LogError("[bferror]没有配置正确的excel路径 " + designExcelPath); throw new Exception(); } var luaPath = Application.dataPath + "/Developer/lua/app/config"; if (!Directory.Exists(luaPath)) { Debug.LogError("[bferror]没有找到lua路径 " + luaPath); throw new Exception(); } var relitivePath = Application.dataPath; relitivePath = relitivePath.Remove(relitivePath.Length - 6, 6); var pythonToolPath = relitivePath + "Tools/tranexcel"; if (!Directory.Exists(pythonToolPath)) { Debug.LogError("[bferror]没有找到pythonToolPath " + pythonToolPath); throw new Exception(); } var success = true; var localizationPythonToolPath = relitivePath + "Tools/localization"; BFEditorUtils.RunCommond("python", "tran.py " + designExcelPath + "/ " + luaPath + "/", pythonToolPath, (str) => { }, (str) => { Debug.LogError("[bferror] " + str); success = false; }); BFEditorUtils.RunCommond("python", "exceltolua.py " + designExcelPath + " " + luaPath + " " + "1", localizationPythonToolPath, (str) => { }, (str) => { Debug.LogError("[bferror] " + str); success = false; }); SpecialProcessSkill(true, (isSuccess) => { success = isSuccess; if (!isSuccess) { Debug.LogError("[bferror] " + "技能表转换失败"); } }); var sb = ExportExcelTools.CheckLuaConfig(true); if (sb.ToString().Length > 0) { success = false; Debug.LogError("[bferror] 导表规范检查异常:" + sb.ToString()); } if (!success) { throw new Exception(); } } public static StringBuilder CheckLuaConfig(bool isDeveloper) { //加载lua配置测试 LuaEnv env = new LuaEnv(); env.AddLoader((ref string scriptPath) => { var text = LoadGameLuaScriptText(scriptPath, isDeveloper); return text; }); // 检查多语言配置 String luaTextConfigPath = null; String suffix = ""; if(isDeveloper) { suffix = "*.lua"; luaTextConfigPath = "Assets/developer/lua/app/config/strings"; } else { suffix = "*.lua.bytes"; luaTextConfigPath = "Assets/lua/app/config/strings"; } var luaTextDirInfo = new DirectoryInfo(luaTextConfigPath); var luaTextFileInfos = luaTextDirInfo.GetFiles(suffix, SearchOption.AllDirectories); var sb = new StringBuilder(); foreach (var file in luaTextFileInfos) { var name = file.FullName.Replace("\\", "/"); var index = name.IndexOf(luaTextConfigPath); name = name.Substring(index + luaTextConfigPath.Length + 1).Replace(".lua", "").Replace(".bytes", ""); try { env.DoString("require " + "'app/config/strings/" + name + "'"); } catch (Exception e) { sb.Append(name + " 配置异常\n" + e.Message); } } // 检查monster String luaConfigPath = null; if(isDeveloper) { luaConfigPath = "Assets/developer/lua/app/config"; } else { luaConfigPath = "Assets/lua/app/config"; } var configDirInfo = new DirectoryInfo(luaConfigPath); var configFileInfos = configDirInfo.GetFiles(suffix, SearchOption.TopDirectoryOnly); string monsterConfigListLua = "{"; foreach (var file in configFileInfos) { var fileName = file.Name.ToLower(); if(fileName.Contains("monster_")) { monsterConfigListLua += "'" + fileName.Replace(".lua", "").Replace(".bytes", "") + "',"; } } monsterConfigListLua += "}"; var luaScriptString = "local ids = {}\n local MONSTER_LIST = " + monsterConfigListLua + "\n"; luaScriptString += @"local str = {} for i, name in ipairs(MONSTER_LIST) do if name ~= 'monster_base' and name ~= 'monster_position' and name ~= 'monster_position_base' then local data = require('app/config/' .. name).data for k, v in pairs(data) do if ids[k] then table.insert(str, name .. '和' .. ids[k] .. '存在相同的mosnter id:' .. k) end ids[k] = name end end end if #str > 0 then return table.concat(str, '\n'); end return ''"; var resultStr = env.DoString(luaScriptString); if (resultStr.Length > 0) { foreach(var strObj in resultStr) { var str = Convert.ToString(strObj); if(!String.IsNullOrEmpty(str)) { sb.Append(str + "\n"); } } } // 检查怪物的坐标信息 var luaScriptString2 = @"local MONSTER_POSITION_KEY = { 'monster_1','monster_2','monster_3','monster_4','monster_5','monster_6','monster_7','monster_8','monster_9','monster_10','monster_11','monster_12'} local list = {'enemy_id_1', 'enemy_id_2', 'enemy_id_3'} local list2 = {'enemy_position_1', 'enemy_position_2', 'enemy_position_3'} local positionConf = require('app/config/monster_position_base').data local monsterPositionConf = require('app/config/monster_position').data local stage = require('app/config/story_stage').data local str = {} for k, v in pairs(stage) do for k2, v2 in ipairs(list) do if v[v2] then local monsterPosition = v[list2[k2]] for i, monsterId in ipairs(v[v2]) do local monsterPositionInfo = monsterPositionConf[monsterPosition] local positionInfo = positionConf[monsterPositionInfo[MONSTER_POSITION_KEY[i]]] if positionInfo == nil then table.insert(str, 'stage表的id为' .. k .. '的第' .. k2 .. '波怪的坐标有问题') end end end end end local stage2 = require('app/config/adventure_stage').data for k, v in pairs(stage2) do for k2, v2 in ipairs(list) do if v[v2] then local monsterPosition = v[list2[k2]] for i, monsterId in ipairs(v[v2]) do local monsterPositionInfo = monsterPositionConf[monsterPosition] local positionInfo = positionConf[monsterPositionInfo[MONSTER_POSITION_KEY[i]]] if positionInfo == nil then table.insert(str, 'adventure_stage表的id为' .. k .. '的第' .. k2 .. '波怪的坐标有问题') end end end end end if #str > 0 then return table.concat(str, '\n'); end return ''"; var resultStr2 = env.DoString(luaScriptString2); if (resultStr2.Length > 0) { foreach(var strObj in resultStr2) { var str = Convert.ToString(strObj); if(!String.IsNullOrEmpty(str)) { sb.Append(str + "\n"); } } } env.Dispose(); return sb; } public static bool FastExportExcelToLua(bool isDeveloper, string designExcelPath) { failFlag = false; designSuccFlag = true; failLog = ""; string relitivePath = Application.dataPath; relitivePath = relitivePath.Remove(relitivePath.Length - 6, 6); string luaPath; string pythonToolPath; if(isDeveloper) { luaPath = Application.dataPath + "/Developer/lua/app/config"; pythonToolPath = relitivePath + "Tools/tranexcel"; } else { luaPath = Application.dataPath + "/lua/app/config"; pythonToolPath = relitivePath + "Tools/tranexcel2"; } string localizationPythonToolPath = relitivePath + "Tools/localization"; // 强制使用新的导表工具 python3.4以上 // pythonToolPath = relitivePath + "Tools/tranexcel_new"; // localizationPythonToolPath = relitivePath + "Tools/localization_new"; if (string.IsNullOrEmpty(pythonToolPath) || !Directory.Exists(pythonToolPath)) { Debug.LogError(string.Format("python工具不存在,请检查 {0}", pythonToolPath)); return false; } if (string.IsNullOrEmpty(luaPath) || !Directory.Exists(luaPath)) { Debug.LogWarning(string.Format("lua config path not exist!, auto create {0}", luaPath)); Directory.CreateDirectory(luaPath); } string isDevStr = isDeveloper?"1":"0"; // BFEditorUtils.RunCommond("python", "tran.py " + designExcelPath + "/ " + luaPath + "/" + " " + isDevStr, pythonToolPath, DesignOnOutput, OnError); BFEditorUtils.RunCommond("python", "tran.py " + designExcelPath + "/ " + luaPath + "/", pythonToolPath, DesignOnOutput, OnError); BFEditorUtils.RunCommond("python", "exceltolua.py " + designExcelPath + " " + luaPath + " " + isDevStr, localizationPythonToolPath, ProceduralOnOutput, OnError); // ExportExcelTools.SpecialProcessSkill(isDeveloper, SkillSpecialOnOutput); // ExportExcelTools.dealMonsterConfig(isDeveloper); // var sb = ExportExcelTools.CheckLuaConfig(isDeveloper); // if (sb.ToString().Length > 0) // { // failFlag = true; // designSuccFlag = false; // Debug.Log("导表规范检查异常!!!"); // Debug.Log(sb.ToString()); // EditorUtility.DisplayDialog("导入失败配置", sb.ToString(), "ok"); // } // else // { // Debug.Log("配置规范检查通过."); // } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); if(designSuccFlag && !failFlag) { return true; } return false; } private static void DesignOnOutput(string outputmsg) { if (outputmsg.Contains("转换成功")) { designSuccFlag = true; } if (outputmsg.Contains("转换失败")) { failFlag = true; failLog = failLog + outputmsg; } Debug.Log(outputmsg); } private static void OnError(string errorMsg) { failFlag = true; failLog = errorMsg; Debug.Log(errorMsg); } private static void ProceduralOnOutput(string outputmsg) { if (outputmsg.Contains("转换失败")) { failFlag = true; failLog = failLog + outputmsg; } Debug.Log(outputmsg); } private static void SkillSpecialOnOutput(bool isSuccess) { } private static byte[] LoadGameLuaScriptText(string scriptPath, bool isDeveloper) { byte[] result = null; String luaPath = null; // 开发路径加载 if (isDeveloper) { luaPath = Application.dataPath + "/Developer/lua/" + scriptPath + ".lua"; } else { luaPath = Application.dataPath + "/lua/" + scriptPath + ".lua.bytes"; } if (File.Exists(luaPath)) { result = File.ReadAllBytes(luaPath); } else { Debug.LogError("lua file is missing : " + luaPath); } return result; } /// /// 特殊处理技能多语言表 (加入程序导表和neo平台调用) /// /// public static void SpecialProcessSkill(bool isDeveloper, Action callback) { var result = ProcessSkillConfig(isDeveloper); if (result) { if (callback != null) { callback(result); } } } public static bool ProcessSkillConfig(bool isDeveloper) { LuaEnv luaEnv = new LuaEnv(); luaEnv.AddLoader(Loader); var rootPath = ""; if (isDeveloper) { rootPath = Application.dataPath + "/Developer/lua/app/config/strings"; } else { rootPath = Application.dataPath + "/lua/app/config/strings"; } if (!Directory.Exists(rootPath)) { Debug.LogError("没有找到配置表strings 文件夹"); throw new Exception(); } luaEnv.Global.Set("isDeveloper", isDeveloper); luaEnv.DoString(@"require 'Editor/BFOthersTools/ExportExcelTools/processSkillConfigTools.lua'"); var dirInfo = new DirectoryInfo(rootPath); var reWrite = luaEnv.Global.Get("reWrite"); foreach (var languagePath in dirInfo.GetDirectories()) { var skillPath = ""; if (isDeveloper) { skillPath = languagePath.FullName + "/skill.lua"; } else { skillPath = languagePath.FullName + "/skill.lua.bytes"; } if (!File.Exists(skillPath)) { Debug.LogWarning("skill表不存在 " + skillPath); continue; } var str = File.ReadAllText(skillPath); var result = reWrite.Call(languagePath.Name, str); // Debug.Log(result[0].ToString()); if (result[0].ToString() != "Error") { //重新写入文件 File.WriteAllText(skillPath,result[0].ToString()); } else { return false; } } return true; } private static byte[] Loader(ref string path) { path = Application.dataPath + "/" + path; if (!File.Exists(path)) { Debug.LogWarning("无文件lua " + path); return null; } return File.ReadAllBytes(path); } public static string GetDesignExcelPath() { return PlayerPrefs.GetString(DESIGN_EXCEL_KEY, ""); } public static void SetDesignExcelPath(string path) { PlayerPrefs.SetString(DESIGN_EXCEL_KEY, path); } public static void dealMonsterConfig(bool isDeveloper) { //加载lua配置测试 LuaEnv env = new LuaEnv(); env.AddLoader((ref string scriptPath) => { scriptPath = "app/config/" + scriptPath; var text = LoadGameLuaScriptText(scriptPath, isDeveloper); return text; }); String suffix = ""; String luaConfigPath = null; if(isDeveloper) { luaConfigPath = Application.dataPath + "/Developer/lua/app/config"; suffix = "*.lua"; } else { luaConfigPath = Application.dataPath + "/lua/app/config"; suffix = "*.lua.bytes"; } var configDirInfo = new DirectoryInfo(luaConfigPath); var configFileInfos = configDirInfo.GetFiles(suffix, SearchOption.TopDirectoryOnly); string monsterList = "local monsterList = {"; foreach (var file in configFileInfos) { var name = file.FullName.Replace("\\", "/"); var index = name.IndexOf(luaConfigPath); name = name.Substring(index + luaConfigPath.Length + 1).Replace(".lua", "").Replace(".bytes", ""); if(name.Contains("monster_") && !name.Contains("position") && !name.Contains("monster_base")) { monsterList += "'" + name + "',"; } } monsterList += "}"; string luaScriptString = @"function tableConfigToString(value, tab, tabCount) tab = tab or ' ' tabCount = tabCount and tabCount or 1 local t = {} for k, value in pairs(value) do local str = string.rep(tab, tabCount) if type(k) == 'number' then str = str .. '[' .. k .. ']' .. '=' elseif type(k) == 'string' then str = str .. '[\'' .. k .. '\']' .. '=' end if type(value) == 'number' then str = str .. value elseif type(value) == 'string' then str = str .. '\'' .. value .. '\'' elseif type(value) == 'table' then str = str .. '{\n' .. tableConfigToString(value, tab, tabCount + 1) .. '\n' .. string.rep(tab, tabCount) .. '}' end table.insert(t, str) end return table.concat(t, ',\n') end function configToFile(targetTable, tableLen, targetPath) local str = 'local monster = {\n' .. tableConfigToString(targetTable) .. '\n}\nlcoal config={\ndata=monster,count=' .. tableLen .. '\n}\nreturn config' local luaFile, msg = io.open(targetPath, 'w') if not luaFile then return end luaFile:write(str) io.close(luaFile) end function dealMonster(targetPath, monsterList) local monsterBase = require( 'monster_base') local baseData = monsterBase.data local monsterFullData = {} local count = 0 local function handleMonsterGrow(name) local monsterGrowConfig = require(name) local growData = monsterGrowConfig.data for k, v in pairs(growData) do monsterFullData[k] = v local data = baseData[v.monster_baseid] if data then monsterFullData[k].icon = data.icon monsterFullData[k].model_id = data.model_id else Logger.logHighlight('not data monster_baseid = ' .. v.monster_baseid) end count = count + 1 end end for _, name in ipairs(monsterList) do handleMonsterGrow(name) end configToFile(monsterFullData, count, targetPath) end " + monsterList + @" dealMonster('" + luaConfigPath + "/monster" + suffix.Substring(1) + "', monsterList)"; env.DoString(luaScriptString); } } }