/* changed from HaYaShi ToShiTaKa */ using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Reflection; using UnityEditor; using UnityEngine; using System.Text; using XLua; using System.Linq; static public class XLuaIDEAapiMaker { #region member private static string m_apiDir = Path.Combine(Path.GetDirectoryName(Application.dataPath), "UnityAPI"); private static Dictionary m_nameCounter = new Dictionary (); private static List m_constructs = new List (); private static List m_methods = new List (); private static List m_propertys = new List (); private static List m_fields = new List (); private static string m_argsText; public static bool IsMemberFilter (MemberInfo mi) { return false; // return ToLuaExport.memberFilter.Contains(mi.ReflectedType.Name + "." + mi.Name); } #endregion /// /// 获取类型的文件名 /// /// /// static string GetTypeFileName (Type type) { return type.ToString ().Replace ("+", ".").Replace (".", "").Replace ("`", "").Replace ("&", "").Replace ("[", "").Replace ("]", "").Replace (",", ""); } // /// // /// 获取类型标签名 // /// // /// // /// static string GetTypeTagName (Type type) { return type.ToString ().Replace ("+", ".").Replace ("`", "").Replace ("&", "").Replace ("[", "").Replace ("]", "").Replace (",", ""); } #region export api [MenuItem ("XLua/IDEA生成自动提示的文件")] public static void ExportLuaApi () { List classList = new List (); IEnumerable LuaCallCSharps = (from type in XLua.Utils.GetAllTypes () from method in type.GetFields (BindingFlags.Static | BindingFlags.Public) where method.IsDefined (typeof(LuaCallCSharpAttribute), false) select method); // object[] ccla = test.GetCustomAttributes(typeof(LuaCallCSharpAttribute), false); // if (ccla.Length == 1 && (((ccla[0] as LuaCallCSharpAttribute).Flag & GenFlag.GCOptimize) != 0)) // { // AddToList(GCOptimizeList, get_cfg); // } foreach (var memeber in LuaCallCSharps) { object LuaCallCSharpList = memeber.GetValue (null); if (LuaCallCSharpList is IEnumerable) { classList.AddRange (LuaCallCSharpList as IEnumerable); } } // return; // classList = XluaGenCodeConfig.LuaCallCSharp; // Dictionary s_apiTypeIdx = new Dictionary(); // //收集要生成的类 // List btList = new List(); // ToLuaExport.allTypes.Clear(); // ToLuaExport.allTypes.AddRange(ToLuaMenu.baseType); // ToLuaExport.allTypes.AddRange(CustomSettings.staticClassTypes); // for (int i = 0; i < ToLuaExport.allTypes.Count; i++) // { // btList.Add(new ToLuaMenu.BindType(ToLuaExport.allTypes[i])); // } // foreach(var bt in CustomSettings.customTypeList) // { // if (ToLuaExport.allTypes.Contains(bt.type)) continue; // ToLuaExport.allTypes.Add(bt.type); // btList.Add(bt); // } // ToLuaMenu.BindType[] allTypes = GenBindTypes(btList.ToArray(), false); // foreach(var bt in allTypes)//做最后的检查,进一步排除一些类 // { // if (bt.type.IsInterface && bt.type != typeof(System.Collections.IEnumerator)) // continue; // s_apiTypeIdx[bt.type] = bt; // if (classList.Contains (bt.type)) { // Debug.LogWarning ("type:"+bt.type.FullName+" has add"); // } else { // // classList.Add (bt.type); // } // } //一些类需要手动加 // { // ToLuaMenu.BindType bt = new ToLuaMenu.BindType(typeof(Array)); // s_apiTypeIdx[bt.type] = bt; // GetClassApi("System.Collections.IEnumerable").AddMethod("GetEnumerator", "()", "System.Collections.IEnumerator", "System.Collections.IEnumerator"); // } string unityAPI = ""; // add class here BindingFlags bindType = BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public; MethodInfo[] methods; FieldInfo[] fields; PropertyInfo[] properties; List constructors; ParameterInfo[] paramInfos; int delta; string path = m_apiDir; if (path == "") { return; } if (Directory.Exists (path)) { Directory.Delete (path, true); } Directory.CreateDirectory (path); foreach (Type t in classList) { FileStream fs = new FileStream (path + "/" + t.FullName.Replace ('.', '_') + "Wrap.lua", FileMode.Create); var utf8WithoutBom = new System.Text.UTF8Encoding (false); StreamWriter sw = new StreamWriter (fs, utf8WithoutBom); if (t.BaseType != null && t.BaseType != typeof(object)) { sw.WriteLine (string.Format ("---@class {0} : {1}", t.FullName, t.BaseType.FullName)); } else { sw.WriteLine (string.Format ("---@class {0}", t.FullName)); } #region field fields = t.GetFields (bindType); foreach (var field in fields) { if (IsObsolete (field)) { continue; } WriteField (sw, GetTypeTagName (field.FieldType), field.Name); } properties = t.GetProperties (bindType); foreach (var property in properties) { if (IsObsolete (property)) { continue; } WriteField (sw, GetTypeTagName (property.PropertyType), property.Name); } //sw.Write ("\n"); #endregion #region constructor constructors = new List (t.GetConstructors (bindType)); constructors.Sort ((left, right) => { return left.GetParameters ().Length - right.GetParameters ().Length; }); bool isDefineTable = false; if (constructors.Count > 0) { sw.WriteLine ("local m = { }"); WriteCtorComment (sw, constructors); paramInfos = constructors [constructors.Count - 1].GetParameters (); delta = paramInfos.Length - constructors [0].GetParameters ().Length; if (constructors [0].IsPublic) { WriteFun (sw, paramInfos, delta, t, "New", true); } isDefineTable = true; } #endregion #region method methods = t.GetMethods (bindType); MethodInfo method; Dictionary> methodDict = new Dictionary> (); if (methods.Length != 0 && !isDefineTable) { sw.WriteLine ("local m = { }"); } for (int i = 0; i < methods.Length; i++) { method = methods [i]; string methodName = method.Name; if (IsObsolete (method)) { continue; } if (method.IsGenericMethod) { continue; } if (!method.IsPublic) continue; if (methodName.StartsWith ("get_") || methodName.StartsWith ("set_")) continue; List list; if (!methodDict.TryGetValue (methodName, out list)) { list = new List (); methodDict.Add (methodName, list); } list.Add (method); } var itr = methodDict.GetEnumerator (); while (itr.MoveNext ()) { List list = itr.Current.Value; // RemoveRewriteFunHasTypeAndString(list); list.Sort ((left, right) => { return left.GetParameters ().Length - right.GetParameters ().Length; }); WriteFunComment (sw, list); paramInfos = list [list.Count - 1].GetParameters (); delta = paramInfos.Length - list [0].GetParameters ().Length; WriteFun (sw, paramInfos, delta, list [0].ReturnType, list [0].Name, list [0].IsStatic); } itr.Dispose (); if (methods.Length != 0 || isDefineTable) { sw.WriteLine (t.FullName + " = m"); if (t.FullName.Contains (".")) { unityAPI += t.FullName.Replace ('.', '_') + " = " + t.FullName + "\r\n"; } sw.WriteLine ("return m"); } #endregion //清空缓冲区 sw.Flush (); //关闭流 sw.Close (); fs.Close (); } File.WriteAllText (path + "/unity_api.lua", unityAPI); if (Directory.Exists (Application.dataPath + "/lua/")) { File.WriteAllText (Application.dataPath + "/lua/" + "/unity_api.lua", unityAPI); } Debug.Log ("转换完成"); } public static bool IsObsolete (MemberInfo mb) { object[] attrs = mb.GetCustomAttributes (true); for (int j = 0; j < attrs.Length; j++) { Type t = attrs [j].GetType (); if (t == typeof(System.ObsoleteAttribute)) { // || t.ToString() == "UnityEngine.WrapperlessIcall") return true; } } if (IsMemberFilter (mb)) { return true; } return false; } static void WriteField (StreamWriter sw, string returnType, string fieldName) { sw.WriteLine (string.Format ("---@field public {0} {1}", fieldName, returnType)); } static void WriteFunComment (StreamWriter sw, List list) { for (int i = 0, imax = list.Count; i < imax; i++) { WriteOneComment (sw, list [i]); } } static void WriteCtorComment (StreamWriter sw, List list) { for (int i = 0, imax = list.Count; i < imax; i++) { WriteOneComment (sw, list [i]); } } static void WriteOneComment (StreamWriter sw, MethodBase method) { ParameterInfo[] paramInfos; string argsStr = ""; paramInfos = method.GetParameters (); for (int i = 0, imax = paramInfos.Length; i < imax; i++) { if (i != 0) { argsStr += ", "; } argsStr += paramInfos [i].ParameterType.Name + " " + RepalceLuaKeyWord (paramInfos [i].Name); // sw.WriteLine ("---@param " + paramInfos [i].ParameterType.Name + " " + RepalceLuaKeyWord (paramInfos [i].Name)); } if (method is MethodInfo) { sw.WriteLine ("---public {0} {1}({2})", ((MethodInfo)method).ReturnType.Name, method.Name, argsStr); } else if (method is ConstructorInfo) { sw.WriteLine ("---public {0} {1}({2})", method.ReflectedType.Name, method.Name, argsStr); } } static void WriteFun (StreamWriter sw, ParameterInfo[] paramInfos, int delta, Type methodReturnType, string methodName, bool isStatic) { string typeStr = ConvertToLuaType (methodReturnType); if (methodReturnType != typeof(void)) { sw.WriteLine (string.Format ("---@return {0}", typeStr)); } string argsStr = ""; for (int i = 0, imax = paramInfos.Length; i < imax; i++) { if (i != 0) { argsStr += ", "; } // argsStr += RepalceLuaKeyWord(paramInfos[i].Name); argsStr += paramInfos [i].Name; if (i < delta) { sw.WriteLine ("---@param " + paramInfos [i].ParameterType.Name + " " + RepalceLuaKeyWord (paramInfos [i].Name)); } else { sw.WriteLine ("---@param optional " + paramInfos [i].ParameterType.Name + " " + RepalceLuaKeyWord (paramInfos [i].Name)); } } // for (int i = 1, imax = delta; i <= imax; i++) { // int index = paramInfos.Length - 1 - delta + i; // sw.WriteLine(string.Format("---@param optional {0} {1}", RepalceLuaKeyWord(paramInfos[index].Name), ConvertToLuaType(paramInfos[index].ParameterType))); // } if (isStatic) { sw.WriteLine (string.Format ("function m.{0}({1}) end", methodName, argsStr)); } else { sw.WriteLine (string.Format ("function m:{0}({1}) end", methodName, argsStr)); } } static string ConvertToLuaType (Type methodReturnType) { string result = ""; if (methodReturnType != typeof(void)) { if (methodReturnType == typeof(bool)) { result = "bool"; } else if (methodReturnType == typeof(long) || methodReturnType == typeof(ulong)) { result = "long"; } else if (methodReturnType.IsPrimitive || methodReturnType.IsEnum) { result = "number"; } else if (methodReturnType == typeof(LuaFunction)) { result = "function"; } else if (methodReturnType == typeof(Type)) { result = "string"; } else if (methodReturnType.IsArray) { result = "table"; } else if (methodReturnType.IsGenericType && methodReturnType.GetGenericTypeDefinition () == typeof(IDictionary<,>)) { result = "table"; } // else if (methodReturnType.IsGenericType && methodReturnType.IsSubclassOf(typeof(LuaValueBase))) { // result = "table"; // } else { result = methodReturnType.Name; } } return result; } static string RepalceLuaKeyWord (string name) { if (name == "table") { name = "tb"; } else if (name == "function") { name = "func"; } else if (name == "type") { name = "t"; } else if (name == "end") { name = "ed"; } else if (name == "local") { name = "loc"; } else if (name == "and") { name = "ad"; } else if (name == "or") { name = "orz"; } else if (name == "not") { name = "no"; } return name; } #endregion // // static List allTypes; // static ToLuaMenu.BindType[] GenBindTypes(ToLuaMenu.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 (ToLuaMenu.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 && ToLuaMenu.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(); // } // // static void AutoAddBaseType(ToLuaMenu.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 (ToLuaMenu.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 || ToLuaMenu.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 ToLuaMenu.BindType(t); // allTypes.Add(bt); // #endif // } // else // { // return; // } // } // else // { // return; // } // AutoAddBaseType(bt, beDropBaseType); // } }