sk-client/Assets/ToLua/Editor/ToLuaMenu.cs

1447 lines
47 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
Copyright (c) 2015-2017 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 Object = UnityEngine.Object;
using Debug = UnityEngine.Debug;
using Debugger = LuaInterface.Debugger;
using System.Threading;
[InitializeOnLoad]
public static class ToLuaMenu
{
//不需要导出或者无法导出的类型
public static List<Type> dropType = new List<Type>
{
typeof(ValueType), //不需要
#if UNITY_4_6 || UNITY_4_7
typeof(Motion), //很多平台只是空类
#endif
#if UNITY_5_3_OR_NEWER
typeof(UnityEngine.CustomYieldInstruction),
#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(LuaClient),
typeof(LuaInterface.LuaFunction),
typeof(LuaInterface.LuaTable),
typeof(LuaInterface.LuaThread),
typeof(LuaInterface.LuaByteBuffer), //只是类型标识符
typeof(DelegateFactory), //无需导出导出类支持lua函数转换为委托。如UIEventListener.OnClick(luafunc)
};
//可以导出的内部支持类型
public static List<Type> baseType = new List<Type>
{
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 = true;
static List<BindType> allTypes = new List<BindType>();
static ToLuaMenu()
{
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<Type> extendList = new List<Type>();
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 (CustomSettings.sealedList.Contains(t))
{
CustomSettings.sealedList.Remove(t);
Debugger.LogError("{0} not a sealed class, it is parent of {1}", LuaMisc.GetTypeName(t), bt.name);
}
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}", LuaMisc.GetTypeName(t), bt.name);
bt.baseType = t.BaseType;
}
else
{
Debugger.LogWarning("not defined bindtype for {0}, autogen it, child class is {1}", LuaMisc.GetTypeName(t), bt.name);
bt = new BindType(t);
allTypes.Add(bt);
}
#else
Debugger.LogWarning("not defined bindtype for {0}, autogen it, child class is {1}", LuaMisc.GetTypeName(t), 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<BindType>(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)
{
Debug.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)
{
Debug.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);
}
Debug.Log("Generate lua binding files over");
ToLuaExport.allTypes.Clear();
allTypes.Clear();
AssetDatabase.Refresh();
}
static HashSet<Type> GetCustomTypeDelegates()
{
BindType[] list = CustomSettings.customTypeList;
HashSet<Type> set = new HashSet<Type>();
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<DelegateType> list = new List<DelegateType>();
list.AddRange(CustomSettings.customDelegateList);
HashSet<Type> 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();
Debug.Log("Create lua delegate over");
}
static ToLuaTree<string> InitTree()
{
ToLuaTree<string> tree = new ToLuaTree<string>();
ToLuaNode<string> 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<string> tree, ToLuaNode<string> 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<ToLuaNode<string>> nodes = tree.Find((_t) => { return _t == ns[j]; }, j);
if (nodes.Count == 0)
{
ToLuaNode<string> node = new ToLuaNode<string>();
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<string> 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<string> nnode = new ToLuaNode<string>();
nnode.value = ns[j];
nnode.layer = j;
nnode.parent = parent;
parent.childs.Add(nnode);
parent = nnode;
}
else
{
parent = nodes[index];
}
}
}
}
static string GetSpaceNameFromTree(ToLuaNode<string> 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<string> tree = InitTree();
StringBuilder sb = new StringBuilder();
List<DelegateType> dtList = new List<DelegateType>();
List<DelegateType> list = new List<DelegateType>();
list.AddRange(CustomSettings.customDelegateList);
HashSet<Type> set = GetCustomTypeDelegates();
List<BindType> backupList = new List<BindType>();
backupList.AddRange(allTypes);
ToLuaNode<string> 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<ToLuaNode<string>> 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<ToLuaNode<string>> 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; });
if (bt != null) 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; });
if (bt != null) 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<DelegateType> delegateList, List<DelegateType> 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(L, 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.unity3d" : "lua" + subDir.Replace('/', '_') + ".unity3d";
bundleName = bundleName.ToLower();
#if UNITY_4_6 || UNITY_4_7
List<Object> list = new List<Object>();
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);
}
#else
for (int i = 0; i < files.Length; i++)
{
AssetImporter importer = AssetImporter.GetAtPath(files[i]);
if (importer)
{
importer.assetBundleName = bundleName;
importer.assetBundleVariant = null;
}
}
#endif
}
static void ClearAllLuaFiles()
{
string osPath = Application.streamingAssetsPath + "/" + GetOS();
if (Directory.Exists(osPath))
{
string[] files = Directory.GetFiles(osPath, "Lua*.unity3d");
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;
}
[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<DelegateType> list = new List<DelegateType>();
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();
}
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);
CopyLuaBytesFiles(LuaConst.toluaDir, destDir);
AssetDatabase.Refresh();
Debug.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);
CopyLuaBytesFiles(LuaConst.toluaDir, destDir, false);
AssetDatabase.Refresh();
Debug.Log("Copy lua files over");
}
static void GetAllDirs(string dir, List<string> 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);
}
}
static void CopyBuildBat(string path, string tempDir)
{
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows64)
{
File.Copy(path + "/Luajit64/Build.bat", tempDir + "/Build.bat", true);
}
else if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows)
{
if (IntPtr.Size == 4)
{
File.Copy(path + "/Luajit/Build.bat", tempDir + "/Build.bat", true);
}
else if (IntPtr.Size == 8)
{
File.Copy(path + "/Luajit64/Build.bat", tempDir + "/Build.bat", true);
}
}
#if UNITY_5_3_OR_NEWER
else if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.iOS)
#else
else if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.iPhone)
#endif
{
//Debug.Log("iOS默认用64位32位自行考虑");
File.Copy(path + "/Luajit64/Build.bat", tempDir + "/Build.bat", true);
}
else
{
File.Copy(path + "/Luajit/Build.bat", tempDir + "/Build.bat", 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('/'));
CopyBuildBat(path, tempDir);
CopyLuaBytesFiles(LuaConst.luaDir, tempDir, false);
Process proc = Process.Start(tempDir + "/Build.bat");
proc.WaitForExit();
CopyLuaBytesFiles(tempDir + "/Out/", destDir, false, "*.lua.bytes");
CopyLuaBytesFiles(LuaConst.toluaDir, destDir);
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('/'));
CopyBuildBat(path, tempDir);
CopyLuaBytesFiles(LuaConst.luaDir, tempDir, false);
Process proc = Process.Start(tempDir + "/Build.bat");
proc.WaitForExit();
CopyLuaBytesFiles(LuaConst.toluaDir, destDir, false);
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_4_6 || UNITY_4_7
string tempDir = CreateStreamDir("Lua");
#else
string tempDir = Application.dataPath + "/temp/Lua";
if (!File.Exists(tempDir))
{
Directory.CreateDirectory(tempDir);
}
#endif
CopyLuaBytesFiles(LuaConst.luaDir, tempDir);
CopyLuaBytesFiles(LuaConst.toluaDir, tempDir);
AssetDatabase.Refresh();
List<string> dirs = new List<string>();
GetAllDirs(tempDir, dirs);
#if UNITY_5 || UNITY_5_3_OR_NEWER
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_4_6 || UNITY_4_7
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('/'));
CopyBuildBat(path, tempDir);
CopyLuaBytesFiles(LuaConst.luaDir, tempDir, false);
Process proc = Process.Start(tempDir + "/Build.bat");
proc.WaitForExit();
CopyLuaBytesFiles(LuaConst.toluaDir, tempDir + "/Out");
AssetDatabase.Refresh();
string sourceDir = tempDir + "/Out";
List<string> dirs = new List<string>();
GetAllDirs(sourceDir, dirs);
#if UNITY_5 || UNITY_5_3_OR_NEWER
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<BindType> btList = new List<BindType>();
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);
}
Debug.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");
Debug.Log("Clear base type wrap files over");
AssetDatabase.Refresh();
}
[MenuItem("Lua/Enable Lua Injection &e", false, 102)]
static void EnableLuaInjection()
{
bool EnableSymbols = false;
if (UpdateMonoCecil(ref EnableSymbols) != -1)
{
BuildTargetGroup curBuildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
string existSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(curBuildTargetGroup);
if (!existSymbols.Contains("ENABLE_LUA_INJECTION"))
{
PlayerSettings.SetScriptingDefineSymbolsForGroup(curBuildTargetGroup, existSymbols + ";ENABLE_LUA_INJECTION");
}
AssetDatabase.Refresh();
}
}
#if ENABLE_LUA_INJECTION
[MenuItem("Lua/Injection Remove &r", false, 5)]
#endif
static void RemoveInjection()
{
if (Application.isPlaying)
{
EditorUtility.DisplayDialog("警告", "游戏运行过程中无法操作", "确定");
return;
}
BuildTargetGroup curBuildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
string existSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(curBuildTargetGroup);
PlayerSettings.SetScriptingDefineSymbolsForGroup(curBuildTargetGroup, existSymbols.Replace("ENABLE_LUA_INJECTION", ""));
Debug.Log("Lua Injection Removed!");
}
public static int UpdateMonoCecil(ref bool EnableSymbols)
{
string appFileName = Environment.GetCommandLineArgs()[0];
string appPath = Path.GetDirectoryName(appFileName);
string directory = appPath + "/Data/Managed/";
if (UnityEngine.Application.platform == UnityEngine.RuntimePlatform.OSXEditor)
{
directory = appPath.Substring(0, appPath.IndexOf("MacOS")) + "Managed/";
}
string suitedMonoCecilPath = directory +
#if UNITY_2017_1_OR_NEWER
"Unity.Cecil.dll";
#else
"Mono.Cecil.dll";
#endif
string suitedMonoCecilMdbPath = directory +
#if UNITY_2017_1_OR_NEWER
"Unity.Cecil.Mdb.dll";
#else
"Mono.Cecil.Mdb.dll";
#endif
string suitedMonoCecilPdbPath = directory +
#if UNITY_2017_1_OR_NEWER
"Unity.Cecil.Pdb.dll";
#else
"Mono.Cecil.Pdb.dll";
#endif
string suitedMonoCecilToolPath = directory + "Unity.CecilTools.dll";
if (!File.Exists(suitedMonoCecilPath)
#if UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_3_OR_NEWER
&& !File.Exists(suitedMonoCecilMdbPath)
&& !File.Exists(suitedMonoCecilPdbPath)
#endif
)
{
EnableSymbols = false;
Debug.Log("Haven't found Mono.Cecil.dll!Symbols Will Be Disabled");
return -1;
}
bool bInjectionToolUpdated = false;
string injectionToolPath = CustomSettings.injectionFilesPath + "Editor/";
string existMonoCecilPath = injectionToolPath + Path.GetFileName(suitedMonoCecilPath);
string existMonoCecilPdbPath = injectionToolPath + Path.GetFileName(suitedMonoCecilPdbPath);
string existMonoCecilMdbPath = injectionToolPath + Path.GetFileName(suitedMonoCecilMdbPath);
string existMonoCecilToolPath = injectionToolPath + Path.GetFileName(suitedMonoCecilToolPath);
try
{
bInjectionToolUpdated = TryUpdate(suitedMonoCecilPath, existMonoCecilPath) ? true : bInjectionToolUpdated;
#if UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_3_OR_NEWER
bInjectionToolUpdated = TryUpdate(suitedMonoCecilPdbPath, existMonoCecilPdbPath) ? true : bInjectionToolUpdated;
bInjectionToolUpdated = TryUpdate(suitedMonoCecilMdbPath, existMonoCecilMdbPath) ? true : bInjectionToolUpdated;
#endif
TryUpdate(suitedMonoCecilToolPath, existMonoCecilToolPath);
}
catch (Exception e)
{
Debug.LogError(e.ToString());
return -1;
}
EnableSymbols = true;
return bInjectionToolUpdated ? 1 : 0;
}
static bool TryUpdate(string srcPath, string destPath)
{
if (GetFileContentMD5(srcPath) != GetFileContentMD5(destPath))
{
File.Copy(srcPath, destPath, true);
return true;
}
return false;
}
static string GetFileContentMD5(string file)
{
if (!File.Exists(file))
{
return string.Empty;
}
FileStream fs = new FileStream(file, FileMode.Open);
System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(fs);
fs.Close();
StringBuilder sb = StringBuilderCache.Acquire();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return StringBuilderCache.GetStringAndRelease(sb);
}
}