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);
}
}
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;
}
///
/// 特殊处理技能多语言表 (加入程序导表和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);
}
}
}