2025-05-15 22:41:22 +08:00

652 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 = "";
/// <summary>
/// 提供给neo平台调用的一键导表
/// </summary>
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.DoString(@"
print('当前 Lua 版本: ' .. _VERSION) -- 输出 Lua 5.1
");
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);
}
}
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);
// 检查棋盘文件格式
// checkBoard("chapter_board", env, sb);
// checkBoard("chapter_board_bossrush", env, sb);
// checkBoard("chapter_board_daily_challenge", env, sb);
// checkBoard("chapter_board_dungeon_armor", env, sb);
// checkBoard("chapter_board_dungeon_equip", env, sb);
// checkBoard("chapter_board_dungeon_gold", env, sb);
// checkBoard("chapter_board_dungeon_shards", env, sb);
// checkBoard("chapter_board_rune", env, sb);
// checkBoard("activity_pvp_board", env, sb);
// checkBoard("arena_board", env, sb);
// 检查monster
// 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 void checkBoard(string configName, LuaEnv env, in StringBuilder sb)
{
var luaScriptString = @"
if not cfg or not cfg.data then
return ''
end
cfg = cfg.data
local tempMap = {}
local addErrorInfo = function(errorInfo, cfgId, errorStr)
if not tempMap[cfgId] then
tempMap[cfgId] = true
table.insert(errorInfo, 'cfgId = ' .. cfgId)
end
table.insert(errorInfo, ' ' .. errorStr)
end
local errorInfo = {}
for k, info in pairs(cfg) do
local board = info.board or info.board_daily_challenge
if not board then
addErrorInfo(errorInfo, k, configName .. ' 没有board字段请检查')
else
if #board < 49 then
addErrorInfo(errorInfo, k, configName .. ' 没有board长度不足请检查当前长度为' .. #board)
end
for index, v in ipairs(board) do
if not v[1] then
addErrorInfo(errorInfo, k, configName .. ' board字段中' .. index .. '索引没有格子类型')
end
if not v[2] then
addErrorInfo(errorInfo, k, configName .. ' board字段中' .. index .. '索引没有元素类型')
elseif v[2] > 5 or v[2] < 0 then
addErrorInfo(errorInfo, k, configName .. ' board字段中' .. index .. '元素类型不合法,当前为' .. v[2])
end
end
local mystery_box_board = info.mystery_box_board
if mystery_box_board then
for index, v in ipairs(mystery_box_board) do
if not v[1] then
addErrorInfo(errorInfo, k, configName .. ' mystery_box_board字段中' .. index .. '索引没有格子类型')
end
if not v[2] then
addErrorInfo(errorInfo, k, configName .. ' mystery_box_board字段中' .. index .. '索引没有元素类型')
end
end
end
end
end
if #errorInfo > 0 then
return table.concat(errorInfo, '\n');
end
return ''";
var resultStr = env.DoString(" local cfg = require('app/config/" + configName + "')\n" + "local configName = '" + configName + "'\n" + luaScriptString);
if (resultStr.Length > 0)
{
foreach(var strObj in resultStr)
{
var str = Convert.ToString(strObj);
if(!String.IsNullOrEmpty(str))
{
sb.Append(str + "\n");
}
}
}
}
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;
}
/// <summary>
/// 特殊处理技能多语言表 (加入程序导表和neo平台调用)
/// </summary>
/// <param name="readLuaPath"></param>
public static void SpecialProcessSkill(bool isDeveloper, Action<bool> 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<string, bool>("isDeveloper", isDeveloper);
luaEnv.DoString(@"require 'Editor/BFOthersTools/ExportExcelTools/processSkillConfigTools.lua'");
var dirInfo = new DirectoryInfo(rootPath);
var reWrite = luaEnv.Global.Get<LuaFunction>("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);
}
}
}