/* Copyright (c) 2015-2016 topameng(topameng@qq.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ //打开开关没有写入导出列表的纯虚类自动跳过 //#define JUMP_NODEFINED_ABSTRACT using UnityEngine; using UnityEditor; using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Text; using System.IO; using System.Diagnostics; using LuaInterface; using LuaFramework; using Object = UnityEngine.Object; using Debug = UnityEngine.Debug; using Debugger = LuaInterface.Debugger; using System.Threading; [InitializeOnLoad] public static class ToLuaMenu { //不需要导出或者无法导出的类型 public static List dropType = new List { typeof(ValueType), //不需要 #if !UNITY_5 typeof(Motion), //很多平台只是空类 #endif typeof(UnityEngine.YieldInstruction), //无需导出的类 typeof(UnityEngine.WaitForEndOfFrame), //内部支持 typeof(UnityEngine.WaitForFixedUpdate), typeof(UnityEngine.WaitForSeconds), typeof(UnityEngine.Mathf), //lua层支持 typeof(Plane), typeof(LayerMask), typeof(Vector3), typeof(Vector4), typeof(Vector2), typeof(Quaternion), typeof(Ray), typeof(Bounds), typeof(Color), typeof(Touch), typeof(RaycastHit), typeof(TouchPhase), //typeof(LuaInterface.LuaOutMetatable), //手写支持 typeof(LuaInterface.NullObject), typeof(System.Array), typeof(System.Reflection.MemberInfo), typeof(System.Reflection.BindingFlags), typeof(LuaInterface.LuaFunction), typeof(LuaInterface.LuaTable), typeof(LuaInterface.LuaThread), typeof(LuaInterface.LuaByteBuffer), //只是类型标识符 //typeof(DelegateFactory), //无需导出,导出类支持lua函数转换为委托。如UIEventListener.OnClick(luafunc) }; //可以导出的内部支持类型 public static List baseType = new List { typeof(System.Object), typeof(System.Delegate), typeof(System.String), typeof(System.Enum), typeof(System.Type), typeof(System.Collections.IEnumerator), typeof(UnityEngine.Object), typeof(LuaInterface.EventObject), typeof(LuaInterface.LuaMethod), typeof(LuaInterface.LuaProperty), typeof(LuaInterface.LuaField), typeof(LuaInterface.LuaConstructor), }; private static bool beAutoGen = false; private static bool beCheck = false; // 不检测自动生成交互接口文件 static List allTypes = new List(); static ToLuaMenu() { if (!beCheck) return; string dir = CustomSettings.saveDir; string[] files = Directory.GetFiles(dir, "*.cs", SearchOption.TopDirectoryOnly); if (files.Length < 3 && beCheck) { if (EditorUtility.DisplayDialog("自动生成", "点击确定自动生成常用类型注册文件, 也可通过菜单逐步完成此功能", "确定", "取消")) { beAutoGen = true; GenLuaDelegates(); AssetDatabase.Refresh(); GenerateClassWraps(); GenLuaBinder(); beAutoGen = false; } beCheck = false; } } static string RemoveNameSpace(string name, string space) { if (space != null) { name = name.Remove(0, space.Length + 1); } return name; } public class BindType { public string name; //类名称 public Type type; public bool IsStatic; public string wrapName = ""; //产生的wrap文件名字 public string libName = ""; //注册到lua的名字 public Type baseType = null; public string nameSpace = null; //注册到lua的table层级 public List extendList = new List(); public BindType(Type t) { if (typeof(System.MulticastDelegate).IsAssignableFrom(t)) { throw new NotSupportedException(string.Format("\nDon't export Delegate {0} as a class, register it in customDelegateList", LuaMisc.GetTypeName(t))); } //if (IsObsolete(t)) //{ // throw new Exception(string.Format("\n{0} is obsolete, don't export it!", LuaMisc.GetTypeName(t))); //} type = t; nameSpace = ToLuaExport.GetNameSpace(t, out libName); name = ToLuaExport.CombineTypeStr(nameSpace, libName); libName = ToLuaExport.ConvertToLibSign(libName); if (name == "object") { wrapName = "System_Object"; name = "System.Object"; } else if (name == "string") { wrapName = "System_String"; name = "System.String"; } else { wrapName = name.Replace('.', '_'); wrapName = ToLuaExport.ConvertToLibSign(wrapName); } int index = CustomSettings.staticClassTypes.IndexOf(type); if (index >= 0 || (type.IsAbstract && type.IsSealed)) { IsStatic = true; } baseType = LuaMisc.GetExportBaseType(type); } public BindType SetBaseType(Type t) { baseType = t; return this; } public BindType AddExtendType(Type t) { if (!extendList.Contains(t)) { extendList.Add(t); } return this; } public BindType SetWrapName(string str) { wrapName = str; return this; } public BindType SetLibName(string str) { libName = str; return this; } public BindType SetNameSpace(string space) { nameSpace = space; return this; } public static bool IsObsolete(Type type) { object[] attrs = type.GetCustomAttributes(true); for (int j = 0; j < attrs.Length; j++) { Type t = attrs[j].GetType(); if (t == typeof(System.ObsoleteAttribute) || t == typeof(NoToLuaAttribute) || t.Name == "MonoNotSupportedAttribute" || t.Name == "MonoTODOAttribute") { return true; } } return false; } } static void AutoAddBaseType(BindType bt, bool beDropBaseType) { Type t = bt.baseType; if (t == null) { return; } if (t.IsInterface) { Debugger.LogWarning("{0} has a base type {1} is Interface, use SetBaseType to jump it", bt.name, t.FullName); bt.baseType = t.BaseType; } else if (dropType.IndexOf(t) >= 0) { Debugger.LogWarning("{0} has a base type {1} is a drop type", bt.name, t.FullName); bt.baseType = t.BaseType; } else if (!beDropBaseType || baseType.IndexOf(t) < 0) { int index = allTypes.FindIndex((iter) => { return iter.type == t; }); if (index < 0) { #if JUMP_NODEFINED_ABSTRACT if (t.IsAbstract && !t.IsSealed) { Debugger.LogWarning("not defined bindtype for {0}, it is abstract class, jump it, child class is {1}", t.FullName, bt.name); bt.baseType = t.BaseType; } else { Debugger.LogWarning("not defined bindtype for {0}, autogen it, child class is {1}", t.FullName, bt.name); bt = new BindType(t); allTypes.Add(bt); } #else Debugger.LogWarning("not defined bindtype for {0}, autogen it, child class is {1}", t.FullName, bt.name); bt = new BindType(t); allTypes.Add(bt); #endif } else { return; } } else { return; } AutoAddBaseType(bt, beDropBaseType); } static BindType[] GenBindTypes(BindType[] list, bool beDropBaseType = true) { allTypes = new List(list); for (int i = 0; i < list.Length; i++) { for (int j = i + 1; j < list.Length; j++) { if (list[i].type == list[j].type) throw new NotSupportedException("Repeat BindType:" + list[i].type); } if (dropType.IndexOf(list[i].type) >= 0) { LogManager.LogWarning(list[i].type.FullName + " in dropType table, not need to export"); allTypes.Remove(list[i]); continue; } else if (beDropBaseType && baseType.IndexOf(list[i].type) >= 0) { LogManager.LogWarning(list[i].type.FullName + " is Base Type, not need to export"); allTypes.Remove(list[i]); continue; } else if (list[i].type.IsEnum) { continue; } AutoAddBaseType(list[i], beDropBaseType); } return allTypes.ToArray(); } [MenuItem("Lua/Gen Lua Wrap Files", false, 1)] public static void GenerateClassWraps() { if (!beAutoGen && EditorApplication.isCompiling) { EditorUtility.DisplayDialog("警告", "请等待编辑器完成编译再执行此功能", "确定"); return; } if (!File.Exists(CustomSettings.saveDir)) { Directory.CreateDirectory(CustomSettings.saveDir); } allTypes.Clear(); BindType[] typeList = CustomSettings.customTypeList; BindType[] list = GenBindTypes(typeList); ToLuaExport.allTypes.AddRange(baseType); for (int i = 0; i < list.Length; i++) { ToLuaExport.allTypes.Add(list[i].type); } for (int i = 0; i < list.Length; i++) { ToLuaExport.Clear(); ToLuaExport.className = list[i].name; ToLuaExport.type = list[i].type; ToLuaExport.isStaticClass = list[i].IsStatic; ToLuaExport.baseType = list[i].baseType; ToLuaExport.wrapClassName = list[i].wrapName; ToLuaExport.libClassName = list[i].libName; ToLuaExport.extendList = list[i].extendList; ToLuaExport.Generate(CustomSettings.saveDir); } LogManager.Log("Generate lua binding files over"); ToLuaExport.allTypes.Clear(); allTypes.Clear(); AssetDatabase.Refresh(); } static HashSet GetCustomTypeDelegates() { BindType[] list = CustomSettings.customTypeList; HashSet set = new HashSet(); BindingFlags binding = BindingFlags.Public | BindingFlags.Static | BindingFlags.IgnoreCase | BindingFlags.Instance; for (int i = 0; i < list.Length; i++) { Type type = list[i].type; FieldInfo[] fields = type.GetFields(BindingFlags.GetField | BindingFlags.SetField | binding); PropertyInfo[] props = type.GetProperties(BindingFlags.GetProperty | BindingFlags.SetProperty | binding); MethodInfo[] methods = null; if (type.IsInterface) { methods = type.GetMethods(); } else { methods = type.GetMethods(BindingFlags.Instance | binding); } for (int j = 0; j < fields.Length; j++) { Type t = fields[j].FieldType; if (ToLuaExport.IsDelegateType(t)) { set.Add(t); } } for (int j = 0; j < props.Length; j++) { Type t = props[j].PropertyType; if (ToLuaExport.IsDelegateType(t)) { set.Add(t); } } for (int j = 0; j < methods.Length; j++) { MethodInfo m = methods[j]; if (m.IsGenericMethod) { continue; } ParameterInfo[] pifs = m.GetParameters(); for (int k = 0; k < pifs.Length; k++) { Type t = pifs[k].ParameterType; if (t.IsByRef) t = t.GetElementType(); if (ToLuaExport.IsDelegateType(t)) { set.Add(t); } } } } return set; } [MenuItem("Lua/Gen Lua Delegates", false, 2)] static void GenLuaDelegates() { if (!beAutoGen && EditorApplication.isCompiling) { EditorUtility.DisplayDialog("警告", "请等待编辑器完成编译再执行此功能", "确定"); return; } ToLuaExport.Clear(); List list = new List(); list.AddRange(CustomSettings.customDelegateList); HashSet set = GetCustomTypeDelegates(); foreach (Type t in set) { if (null == list.Find((p) => { return p.type == t; })) { list.Add(new DelegateType(t)); } } ToLuaExport.GenDelegates(list.ToArray()); set.Clear(); ToLuaExport.Clear(); AssetDatabase.Refresh(); LogManager.Log("Create lua delegate over"); } static ToLuaTree InitTree() { ToLuaTree tree = new ToLuaTree(); ToLuaNode root = tree.GetRoot(); BindType[] list = GenBindTypes(CustomSettings.customTypeList); for (int i = 0; i < list.Length; i++) { string space = list[i].nameSpace; AddSpaceNameToTree(tree, root, space); } DelegateType[] dts = CustomSettings.customDelegateList; string str = null; for (int i = 0; i < dts.Length; i++) { string space = ToLuaExport.GetNameSpace(dts[i].type, out str); AddSpaceNameToTree(tree, root, space); } return tree; } static void AddSpaceNameToTree(ToLuaTree tree, ToLuaNode parent, string space) { if (space == null || space == string.Empty) { return; } string[] ns = space.Split(new char[] { '.' }); for (int j = 0; j < ns.Length; j++) { List> nodes = tree.Find((_t) => { return _t == ns[j]; }, j); if (nodes.Count == 0) { ToLuaNode node = new ToLuaNode(); node.value = ns[j]; parent.childs.Add(node); node.parent = parent; node.layer = j; parent = node; } else { bool flag = false; int index = 0; for (int i = 0; i < nodes.Count; i++) { int count = j; int size = j; ToLuaNode nodecopy = nodes[i]; while (nodecopy.parent != null) { nodecopy = nodecopy.parent; if (nodecopy.value != null && nodecopy.value == ns[--count]) { size--; } } if (size == 0) { index = i; flag = true; break; } } if (!flag) { ToLuaNode nnode = new ToLuaNode(); nnode.value = ns[j]; nnode.layer = j; nnode.parent = parent; parent.childs.Add(nnode); parent = nnode; } else { parent = nodes[index]; } } } } static string GetSpaceNameFromTree(ToLuaNode node) { string name = node.value; while (node.parent != null && node.parent.value != null) { node = node.parent; name = node.value + "." + name; } return name; } static string RemoveTemplateSign(string str) { str = str.Replace('<', '_'); int index = str.IndexOf('>'); while (index > 0) { str = str.Remove(index, 1); index = str.IndexOf('>'); } return str; } [MenuItem("Lua/Gen LuaBinder File", false, 4)] static void GenLuaBinder() { if (!beAutoGen && EditorApplication.isCompiling) { EditorUtility.DisplayDialog("警告", "请等待编辑器完成编译再执行此功能", "确定"); return; } allTypes.Clear(); ToLuaTree tree = InitTree(); StringBuilder sb = new StringBuilder(); List dtList = new List(); List list = new List(); list.AddRange(CustomSettings.customDelegateList); HashSet set = GetCustomTypeDelegates(); List backupList = new List(); backupList.AddRange(allTypes); ToLuaNode root = tree.GetRoot(); string libname = null; foreach (Type t in set) { if (null == list.Find((p) => { return p.type == t; })) { DelegateType dt = new DelegateType(t); AddSpaceNameToTree(tree, root, ToLuaExport.GetNameSpace(t, out libname)); list.Add(dt); } } sb.AppendLineEx("//this source code was auto-generated by tolua#, do not modify it"); sb.AppendLineEx("using System;"); sb.AppendLineEx("using UnityEngine;"); sb.AppendLineEx("using LuaInterface;"); sb.AppendLineEx(); sb.AppendLineEx("public static class LuaBinder"); sb.AppendLineEx("{"); sb.AppendLineEx("\tpublic static void Bind(LuaState L)"); sb.AppendLineEx("\t{"); sb.AppendLineEx("\t\tfloat t = Time.realtimeSinceStartup;"); sb.AppendLineEx("\t\tL.BeginModule(null);"); GenRegisterInfo(null, sb, list, dtList); Action> begin = (node) => { if (node.value == null) { return; } sb.AppendFormat("\t\tL.BeginModule(\"{0}\");\r\n", node.value); string space = GetSpaceNameFromTree(node); GenRegisterInfo(space, sb, list, dtList); }; Action> end = (node) => { if (node.value != null) { sb.AppendLineEx("\t\tL.EndModule();"); } }; tree.DepthFirstTraversal(begin, end, tree.GetRoot()); sb.AppendLineEx("\t\tL.EndModule();"); if (CustomSettings.dynamicList.Count > 0) { sb.AppendLineEx("\t\tL.BeginPreLoad();"); for (int i = 0; i < CustomSettings.dynamicList.Count; i++) { Type t1 = CustomSettings.dynamicList[i]; BindType bt = backupList.Find((p) => { return p.type == t1; }); sb.AppendFormat("\t\tL.AddPreLoad(\"{0}\", LuaOpen_{1}, typeof({0}));\r\n", bt.name, bt.wrapName); } sb.AppendLineEx("\t\tL.EndPreLoad();"); } sb.AppendLineEx("\t\tDebugger.Log(\"Register lua type cost time: {0}\", Time.realtimeSinceStartup - t);"); sb.AppendLineEx("\t}"); for (int i = 0; i < dtList.Count; i++) { ToLuaExport.GenEventFunction(dtList[i].type, sb); } if (CustomSettings.dynamicList.Count > 0) { for (int i = 0; i < CustomSettings.dynamicList.Count; i++) { Type t = CustomSettings.dynamicList[i]; BindType bt = backupList.Find((p) => { return p.type == t; }); GenPreLoadFunction(bt, sb); } } sb.AppendLineEx("}\r\n"); allTypes.Clear(); string file = CustomSettings.saveDir + "LuaBinder.cs"; using (StreamWriter textWriter = new StreamWriter(file, false, Encoding.UTF8)) { textWriter.Write(sb.ToString()); textWriter.Flush(); textWriter.Close(); } AssetDatabase.Refresh(); Debugger.Log("Generate LuaBinder over !"); } static void GenRegisterInfo(string nameSpace, StringBuilder sb, List delegateList, List wrappedDelegatesCache) { for (int i = 0; i < allTypes.Count; i++) { Type dt = CustomSettings.dynamicList.Find((p) => { return allTypes[i].type == p; }); if (dt == null && allTypes[i].nameSpace == nameSpace) { string str = "\t\t" + allTypes[i].wrapName + "Wrap.Register(L);\r\n"; sb.Append(str); allTypes.RemoveAt(i--); } } string funcName = null; for (int i = 0; i < delegateList.Count; i++) { DelegateType dt = delegateList[i]; Type type = dt.type; string typeSpace = ToLuaExport.GetNameSpace(type, out funcName); if (typeSpace == nameSpace) { funcName = ToLuaExport.ConvertToLibSign(funcName); string abr = dt.abr; abr = abr == null ? funcName : abr; sb.AppendFormat("\t\tL.RegFunction(\"{0}\", {1});\r\n", abr, dt.name); wrappedDelegatesCache.Add(dt); } } } static void GenPreLoadFunction(BindType bt, StringBuilder sb) { string funcName = "LuaOpen_" + bt.wrapName; sb.AppendLineEx("\r\n\t[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]"); sb.AppendFormat("\tstatic int {0}(IntPtr L)\r\n", funcName); sb.AppendLineEx("\t{"); sb.AppendLineEx("\t\ttry"); sb.AppendLineEx("\t\t{"); sb.AppendLineEx("\t\t\tLuaState state = LuaState.Get(L);"); sb.AppendFormat("\t\t\tstate.BeginPreModule(\"{0}\");\r\n", bt.nameSpace); sb.AppendFormat("\t\t\t{0}Wrap.Register(state);\r\n", bt.wrapName); sb.AppendFormat("\t\t\tint reference = state.GetMetaReference(typeof({0}));\r\n", bt.name); sb.AppendLineEx("\t\t\tstate.EndPreModule(reference);"); sb.AppendLineEx("\t\t\treturn 1;"); sb.AppendLineEx("\t\t}"); sb.AppendLineEx("\t\tcatch(Exception e)"); sb.AppendLineEx("\t\t{"); sb.AppendLineEx("\t\t\treturn LuaDLL.toluaL_exception(L, e);"); sb.AppendLineEx("\t\t}"); sb.AppendLineEx("\t}"); } static string GetOS() { return LuaConst.osDir; } static string CreateStreamDir(string dir) { dir = Application.streamingAssetsPath + "/" + dir; if (!File.Exists(dir)) { Directory.CreateDirectory(dir); } return dir; } static void BuildLuaBundle(string subDir, string sourceDir) { string[] files = Directory.GetFiles(sourceDir + subDir, "*.bytes"); string bundleName = subDir == null ? "lua" + AppConst.ExtName : "lua" + subDir.Replace('/', '_') + AppConst.ExtName; bundleName = bundleName.ToLower(); #if UNITY_5 for (int i = 0; i < files.Length; i++) { AssetImporter importer = AssetImporter.GetAtPath(files[i]); if (importer) { importer.assetBundleName = bundleName; importer.assetBundleVariant = null; } } #else List list = new List(); for (int i = 0; i < files.Length; i++) { Object obj = AssetDatabase.LoadMainAssetAtPath(files[i]); list.Add(obj); } BuildAssetBundleOptions options = BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets | BuildAssetBundleOptions.DeterministicAssetBundle; if (files.Length > 0) { string output = string.Format("{0}/{1}/" + bundleName, Application.streamingAssetsPath, GetOS()); File.Delete(output); BuildPipeline.BuildAssetBundle(null, list.ToArray(), output, options, EditorUserBuildSettings.activeBuildTarget); } #endif } static void ClearAllLuaFiles() { string osPath = Application.streamingAssetsPath + "/" + GetOS(); if (Directory.Exists(osPath)) { string[] files = Directory.GetFiles(osPath, "Lua*" + AppConst.ExtName); for (int i = 0; i < files.Length; i++) { File.Delete(files[i]); } } string path = osPath + "/Lua"; if (Directory.Exists(path)) { Directory.Delete(path, true); } path = Application.streamingAssetsPath + "/Lua"; if (Directory.Exists(path)) { Directory.Delete(path, true); } path = Application.dataPath + "/temp"; if (Directory.Exists(path)) { Directory.Delete(path, true); } path = Application.dataPath + "/Resources/Lua"; if (Directory.Exists(path)) { Directory.Delete(path, true); } path = Application.persistentDataPath + "/" + GetOS() + "/Lua"; if (Directory.Exists(path)) { Directory.Delete(path, true); } } [MenuItem("Lua/Gen LuaWrap + Binder", false, 4)] static void GenLuaWrapBinder() { if (EditorApplication.isCompiling) { EditorUtility.DisplayDialog("警告", "请等待编辑器完成编译再执行此功能", "确定"); return; } beAutoGen = true; AssetDatabase.Refresh(); GenerateClassWraps(); GenLuaBinder(); beAutoGen = false; } [MenuItem("Lua/Generate All", false, 5)] static void GenLuaAll() { if (EditorApplication.isCompiling) { EditorUtility.DisplayDialog("警告", "请等待编辑器完成编译再执行此功能", "确定"); return; } beAutoGen = true; GenLuaDelegates(); AssetDatabase.Refresh(); GenerateClassWraps(); GenLuaBinder(); beAutoGen = false; EditorUtility.DisplayDialog("提示", "生成全部接口文件成功", "确定"); } [MenuItem("Lua/Clear wrap files", false, 6)] static void ClearLuaWraps() { string[] files = Directory.GetFiles(CustomSettings.saveDir, "*.cs", SearchOption.TopDirectoryOnly); for (int i = 0; i < files.Length; i++) { File.Delete(files[i]); } ToLuaExport.Clear(); List list = new List(); ToLuaExport.GenDelegates(list.ToArray()); ToLuaExport.Clear(); StringBuilder sb = new StringBuilder(); sb.AppendLineEx("using System;"); sb.AppendLineEx("using LuaInterface;"); sb.AppendLineEx(); sb.AppendLineEx("public static class LuaBinder"); sb.AppendLineEx("{"); sb.AppendLineEx("\tpublic static void Bind(LuaState L)"); sb.AppendLineEx("\t{"); sb.AppendLineEx("\t\tthrow new LuaException(\"Please generate LuaBinder files first!\");"); sb.AppendLineEx("\t}"); sb.AppendLineEx("}"); string file = CustomSettings.saveDir + "LuaBinder.cs"; using (StreamWriter textWriter = new StreamWriter(file, false, Encoding.UTF8)) { textWriter.Write(sb.ToString()); textWriter.Flush(); textWriter.Close(); } AssetDatabase.Refresh(); EditorUtility.DisplayDialog("提示", "清理全部接口文件成功", "确定"); } public static void CopyLuaBytesFiles(string sourceDir, string destDir, bool appendext = true, string searchPattern = "*.lua", SearchOption option = SearchOption.AllDirectories) { if (!Directory.Exists(sourceDir)) { return; } string[] files = Directory.GetFiles(sourceDir, searchPattern, option); int len = sourceDir.Length; if (sourceDir[len - 1] == '/' || sourceDir[len - 1] == '\\') { --len; } for (int i = 0; i < files.Length; i++) { string str = files[i].Remove(0, len); string dest = destDir + "/" + str; if (appendext) dest += ".bytes"; string dir = Path.GetDirectoryName(dest); Directory.CreateDirectory(dir); File.Copy(files[i], dest, true); } } [MenuItem("Lua/Copy Lua files to Resources", false, 51)] public static void CopyLuaFilesToRes() { ClearAllLuaFiles(); string destDir = Application.dataPath + "/Resources" + "/Lua"; CopyLuaBytesFiles(LuaConst.luaDir, destDir); AssetDatabase.Refresh(); LogManager.Log("Copy lua files over"); } [MenuItem("Lua/Copy Lua files to Persistent", false, 52)] public static void CopyLuaFilesToPersistent() { ClearAllLuaFiles(); string destDir = Application.persistentDataPath + "/" + GetOS() + "/Lua"; CopyLuaBytesFiles(LuaConst.luaDir, destDir, false); AssetDatabase.Refresh(); LogManager.Log("Copy lua files over"); } static void GetAllDirs(string dir, List list) { string[] dirs = Directory.GetDirectories(dir); list.AddRange(dirs); for (int i = 0; i < dirs.Length; i++) { GetAllDirs(dirs[i], list); } } static void CopyDirectory(string source, string dest, string searchPattern = "*.lua", SearchOption option = SearchOption.AllDirectories) { string[] files = Directory.GetFiles(source, searchPattern, option); for (int i = 0; i < files.Length; i++) { string str = files[i].Remove(0, source.Length); string path = dest + "/" + str; string dir = Path.GetDirectoryName(path); Directory.CreateDirectory(dir); File.Copy(files[i], path, true); } } [MenuItem("Lua/Build Lua files to Resources (PC)", false, 53)] public static void BuildLuaToResources() { ClearAllLuaFiles(); string tempDir = CreateStreamDir("Lua"); string destDir = Application.dataPath + "/Resources" + "/Lua"; string path = Application.dataPath.Replace('\\', '/'); path = path.Substring(0, path.LastIndexOf('/')); File.Copy(path + "/Luajit/Build.bat", tempDir + "/Build.bat", true); CopyLuaBytesFiles(LuaConst.luaDir, tempDir, false); Process proc = Process.Start(tempDir + "/Build.bat"); proc.WaitForExit(); CopyLuaBytesFiles(tempDir + "/Out/", destDir, false, "*.lua.bytes"); Directory.Delete(tempDir, true); AssetDatabase.Refresh(); } [MenuItem("Lua/Build Lua files to Persistent (PC)", false, 54)] public static void BuildLuaToPersistent() { ClearAllLuaFiles(); string tempDir = CreateStreamDir("Lua"); string destDir = Application.persistentDataPath + "/" + GetOS() + "/Lua/"; string path = Application.dataPath.Replace('\\', '/'); path = path.Substring(0, path.LastIndexOf('/')); File.Copy(path + "/Luajit/Build.bat", tempDir + "/Build.bat", true); CopyLuaBytesFiles(LuaConst.luaDir, tempDir, false); Process proc = Process.Start(tempDir + "/Build.bat"); proc.WaitForExit(); path = tempDir + "/Out/"; string[] files = Directory.GetFiles(path, "*.lua.bytes"); int len = path.Length; for (int i = 0; i < files.Length; i++) { path = files[i].Remove(0, len); path = path.Substring(0, path.Length - 6); path = destDir + path; File.Copy(files[i], path, true); } Directory.Delete(tempDir, true); AssetDatabase.Refresh(); } [MenuItem("Lua/Build bundle files not jit", false, 55)] public static void BuildNotJitBundles() { ClearAllLuaFiles(); CreateStreamDir(GetOS()); #if !UNITY_5 string tempDir = CreateStreamDir("Lua"); #else string tempDir = Application.dataPath + "/temp/Lua"; if (!File.Exists(tempDir)) { Directory.CreateDirectory(tempDir); } #endif CopyLuaBytesFiles(LuaConst.luaDir, tempDir); AssetDatabase.Refresh(); List dirs = new List(); GetAllDirs(tempDir, dirs); #if UNITY_5 for (int i = 0; i < dirs.Count; i++) { string str = dirs[i].Remove(0, tempDir.Length); BuildLuaBundle(str.Replace('\\', '/'), "Assets/temp/Lua"); } BuildLuaBundle(null, "Assets/temp/Lua"); AssetDatabase.SaveAssets(); string output = string.Format("{0}/{1}", Application.streamingAssetsPath, GetOS()); BuildPipeline.BuildAssetBundles(output, BuildAssetBundleOptions.DeterministicAssetBundle, EditorUserBuildSettings.activeBuildTarget); //Directory.Delete(Application.dataPath + "/temp/", true); #else for (int i = 0; i < dirs.Count; i++) { string str = dirs[i].Remove(0, tempDir.Length); BuildLuaBundle(str.Replace('\\', '/'), "Assets/StreamingAssets/Lua"); } BuildLuaBundle(null, "Assets/StreamingAssets/Lua"); Directory.Delete(Application.streamingAssetsPath + "/Lua/", true); #endif AssetDatabase.Refresh(); } [MenuItem("Lua/Build Luajit bundle files (PC)", false, 56)] public static void BuildLuaBundles() { ClearAllLuaFiles(); CreateStreamDir(GetOS()); #if !UNITY_5 string tempDir = CreateStreamDir("Lua"); #else string tempDir = Application.dataPath + "/temp/Lua"; if (!File.Exists(tempDir)) { Directory.CreateDirectory(tempDir); } #endif string path = Application.dataPath.Replace('\\', '/'); path = path.Substring(0, path.LastIndexOf('/')); File.Copy(path + "/Luajit/Build.bat", tempDir + "/Build.bat", true); CopyLuaBytesFiles(LuaConst.luaDir, tempDir, false); Process proc = Process.Start(tempDir + "/Build.bat"); proc.WaitForExit(); AssetDatabase.Refresh(); string sourceDir = tempDir + "/Out"; List dirs = new List(); GetAllDirs(sourceDir, dirs); #if UNITY_5 for (int i = 0; i < dirs.Count; i++) { string str = dirs[i].Remove(0, sourceDir.Length); BuildLuaBundle(str.Replace('\\', '/'), "Assets/temp/Lua/Out"); } BuildLuaBundle(null, "Assets/temp/Lua/Out"); AssetDatabase.Refresh(); string output = string.Format("{0}/{1}", Application.streamingAssetsPath, GetOS()); BuildPipeline.BuildAssetBundles(output, BuildAssetBundleOptions.DeterministicAssetBundle, EditorUserBuildSettings.activeBuildTarget); Directory.Delete(Application.dataPath + "/temp/", true); #else for (int i = 0; i < dirs.Count; i++) { string str = dirs[i].Remove(0, sourceDir.Length); BuildLuaBundle(str.Replace('\\', '/'), "Assets/StreamingAssets/Lua/Out"); } BuildLuaBundle(null, "Assets/StreamingAssets/Lua/Out/"); Directory.Delete(tempDir, true); #endif AssetDatabase.Refresh(); } [MenuItem("Lua/Clear all Lua files", false, 57)] public static void ClearLuaFiles() { ClearAllLuaFiles(); } [MenuItem("Lua/Gen BaseType Wrap", false, 101)] static void GenBaseTypeLuaWrap() { if (!beAutoGen && EditorApplication.isCompiling) { EditorUtility.DisplayDialog("警告", "请等待编辑器完成编译再执行此功能", "确定"); return; } string dir = CustomSettings.toluaBaseType; if (!File.Exists(dir)) { Directory.CreateDirectory(dir); } allTypes.Clear(); ToLuaExport.allTypes.AddRange(baseType); List btList = new List(); for (int i = 0; i < baseType.Count; i++) { btList.Add(new BindType(baseType[i])); } GenBindTypes(btList.ToArray(), false); BindType[] list = allTypes.ToArray(); for (int i = 0; i < list.Length; i++) { ToLuaExport.Clear(); ToLuaExport.className = list[i].name; ToLuaExport.type = list[i].type; ToLuaExport.isStaticClass = list[i].IsStatic; ToLuaExport.baseType = list[i].baseType; ToLuaExport.wrapClassName = list[i].wrapName; ToLuaExport.libClassName = list[i].libName; ToLuaExport.Generate(dir); } LogManager.Log("Generate base type files over"); allTypes.Clear(); AssetDatabase.Refresh(); } static void CreateDefaultWrapFile(string path, string name) { StringBuilder sb = new StringBuilder(); path = path + name + ".cs"; sb.AppendLineEx("using System;"); sb.AppendLineEx("using LuaInterface;"); sb.AppendLineEx(); sb.AppendLineEx("public static class " + name); sb.AppendLineEx("{"); sb.AppendLineEx("\tpublic static void Register(LuaState L)"); sb.AppendLineEx("\t{"); sb.AppendLineEx("\t\tthrow new LuaException(\"Please click menu Lua/Gen BaseType Wrap first!\");"); sb.AppendLineEx("\t}"); sb.AppendLineEx("}"); using (StreamWriter textWriter = new StreamWriter(path, false, Encoding.UTF8)) { textWriter.Write(sb.ToString()); textWriter.Flush(); textWriter.Close(); } } [MenuItem("Lua/Clear BaseType Wrap", false, 102)] static void ClearBaseTypeLuaWrap() { CreateDefaultWrapFile(CustomSettings.toluaBaseType, "System_ObjectWrap"); CreateDefaultWrapFile(CustomSettings.toluaBaseType, "System_DelegateWrap"); CreateDefaultWrapFile(CustomSettings.toluaBaseType, "System_StringWrap"); CreateDefaultWrapFile(CustomSettings.toluaBaseType, "System_EnumWrap"); CreateDefaultWrapFile(CustomSettings.toluaBaseType, "System_TypeWrap"); CreateDefaultWrapFile(CustomSettings.toluaBaseType, "System_Collections_IEnumeratorWrap"); CreateDefaultWrapFile(CustomSettings.toluaBaseType, "UnityEngine_ObjectWrap"); CreateDefaultWrapFile(CustomSettings.toluaBaseType, "LuaInterface_EventObjectWrap"); CreateDefaultWrapFile(CustomSettings.toluaBaseType, "LuaInterface_LuaMethodWrap"); CreateDefaultWrapFile(CustomSettings.toluaBaseType, "LuaInterface_LuaPropertyWrap"); CreateDefaultWrapFile(CustomSettings.toluaBaseType, "LuaInterface_LuaFieldWrap"); CreateDefaultWrapFile(CustomSettings.toluaBaseType, "LuaInterface_LuaConstructorWrap"); LogManager.Log("Clear base type wrap files over"); AssetDatabase.Refresh(); } }