public static string ToMakeClasses(Type t, string[] props, MethodData[] methods, MethodData[] constructors, ExMethodData[] extmethods, string macros, string folder, List<string>[] errors ) { InitOp_FuncNames(); ParamTypeData T = new ParamTypeData(t); string str = string.Format("-------- generating Lua Interface for {0} ----------", T.csTypeName); Debug.Log(str); funcNames.Clear(); string className = string.Format("Lua{0}",T.csTypeName); string filename = string.Format("{0}/{1}.cs", folder, className); FileStream fs = new FileStream(filename, FileMode.Create); StreamWriter n = new StreamWriter(fs); if (string.IsNullOrEmpty(macros) == false) n.WriteLine(macros); writeHead(n, t); Dictionary<string,bool> ignoreProps = new Dictionary<string,bool>(); bool ignored = false; bool generatAllProps = false; bool ignore = false; for (int i = 0; props != null && i < props.Length; ++i) { string propname = props[i]; if( String.IsNullOrEmpty(propname)) continue; if (propname == "*") { if (!ignore) { generatAllProps = true; Debug.Log("generating all properties & fields ..."); } continue; } if (propname == "|") { ignore = true; continue; } if (ignore) { ignoreProps[propname] = true; continue; } if (generatAllProps) { continue; } string s = string.Format("generating prop:{0}", props[i]); Debug.Log(s); PropertyInfo info = t.GetProperty(props[i]); if (info == null) { FieldInfo finfo = t.GetField(props[i]); if (finfo == null) { string strerr = string.Format("can't find property:{0}.{1}", T.csTypeName, props[i]); errors[1].Add(strerr); continue; } if (IsDelegate(finfo.FieldType)) continue; bool isStatic = finfo.IsStatic; writeReadProp(n, t, finfo.FieldType, finfo.Name,isStatic, finfo.FieldType.IsEnum); if(finfo.IsLiteral == false) writeWriteProp(n, t, finfo.FieldType, finfo.Name, isStatic, finfo.FieldType.IsEnum); continue; } MethodInfo getM = info.GetGetMethod(); MethodInfo setM = info.GetSetMethod(); bool isStaticProp = getM != null ? getM.IsStatic : setM.IsStatic; if (info.CanRead) writeReadProp(n, t, info.PropertyType, info.Name, isStaticProp, info.PropertyType.IsEnum); if (info.CanWrite) writeWriteProp(n, t, info.PropertyType, info.Name, isStaticProp, info.PropertyType.IsEnum); } if (generatAllProps) { Debug.Log("auto props as follows:"); Dictionary<string, bool> haveProps = new Dictionary<string, bool>(); PropertyInfo[] infos = t.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly); foreach (PropertyInfo info in infos) { if(ignoreProps.TryGetValue(info.Name,out ignored)) continue; if (IsDelegate(info.PropertyType)) continue; MethodInfo getM = info.GetGetMethod(); MethodInfo setM = info.GetSetMethod(); bool isStaticProp = getM != null ? getM.IsStatic : setM.IsStatic; haveProps[info.Name] = true; Debug.Log(info.Name); if (info.CanRead) writeReadProp(n, t, info.PropertyType, info.Name, isStaticProp, info.PropertyType.IsEnum); if (info.CanWrite) writeWriteProp(n, t, info.PropertyType, info.Name, isStaticProp, info.PropertyType.IsEnum); } Debug.Log("-----------"); FieldInfo[] finfos = t.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly); foreach (FieldInfo finfo in finfos) { if (haveProps.TryGetValue(finfo.Name, out ignored)) continue; if(ignoreProps.TryGetValue(finfo.Name,out ignored)) continue; if (IsDelegate(finfo.FieldType)) continue; Debug.Log(finfo.Name); bool isStatic = finfo.IsStatic; writeReadProp(n, t, finfo.FieldType, finfo.Name, isStatic, finfo.FieldType.IsEnum); if( finfo.IsLiteral == false) writeWriteProp(n, t, finfo.FieldType, finfo.Name, isStatic, finfo.FieldType.IsEnum); } } Dictionary<string, bool> ignoreMethods = new Dictionary<string, bool>(); ignoreMethods["Equals"] = true; ignoreMethods["GetHashCode"] = true; ignoreMethods["GetType"] = true; ignoreMethods["ReferenceEquals"] = true; ignoreMethods["ToString"] = true; ignoreMethods["OnDrawGizmos"] = true; bool generatAllMethods = false; ignore = false; for (int i = 0; methods != null && i < methods.Length; ++i) { MethodData data = methods[i]; if (data.name == "*") { if (!ignore) { Debug.Log("generating all method ..."); generatAllMethods = true; } continue; } if (data.name == "|") { ignore = true; continue; } if (ignore) { ignoreMethods[data.name] = true; continue; } if (generatAllMethods) { continue; } string s = string.Format("generating method:{0}", string.IsNullOrEmpty(data.alias) ? data.name : data.alias); Debug.Log(s); MethodInfo info = null; if (methods[i].tlist != null) { info = t.GetMethod(data.name, data.tlist); } else { info = t.GetMethod(data.name); } if (info == null) { string strerr = string.Format("can't find function:{0}.{1}", T.csTypeName,data.name); errors[1].Add(strerr); continue; } writeLine(n, "//---------------------------------"); writeMethod(n, info, t,data.alias,errors); } if (generatAllMethods) { Dictionary<string, int> generatedMethods = new Dictionary<string, int>(); MethodInfo[] infos = t.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly); foreach (MethodInfo info in infos) { if (ignoreMethods.TryGetValue(info.Name, out ignored)) continue; if (info.Name.IndexOf("get_") >= 0) continue; if (info.Name.IndexOf("set_") >= 0) continue; string s = string.Format("generating method:{0}", info.Name); Debug.Log(s); writeLine(n, "//---------------------------------"); int count; if (generatedMethods.TryGetValue(info.Name, out count) == false) count = 0; ++count; generatedMethods[info.Name] = count; writeMethod(n, info, t, count == 1 ? "" : info.Name + "_"+count, errors); } } for (int i = 0; constructors != null && i < constructors.Length; ++i) { MethodData data = constructors[i]; Debug.Log("generating constructor"); ConstructorInfo info = default(ConstructorInfo); if (data.tlist != null) info = t.GetConstructor(data.tlist); else { ConstructorInfo[] infos = t.GetConstructors(); if (infos != null && infos.Length > 0) info = infos[0]; } if (info == null) { string strerr = string.Format("can't find Constructor:{0}.{1}", T.csTypeName,info.Name); errors[1].Add(strerr); continue; } writeConstructor(n, info, t,data.alias); } if (t.IsSubclassOf(typeof(UnityEngine.Object))) writeIsNilFunc(n, T); writeFuncsArray(n,t,extmethods); writeTail(n, t); if (string.IsNullOrEmpty(macros) == false) n.WriteLine("#endif"); n.Close(); fs.Close(); return className; }
static void writeMethod(StreamWriter n, MethodInfo info, Type t, string alias, List<string>[] errors) { //参数有效性检查,遇到不支持的参数类型,就报错返回 ParameterInfo[] pinfos = info.GetParameters(); List<ParamTypeData> paramTypsList = new List<ParamTypeData>(); try { for (int i = 0; i < pinfos.Length; ++i) { ParamTypeData paramType = new ParamTypeData(pinfos[i].ParameterType); paramTypsList.Add(paramType); } } catch (Exception e) { string err = string.Format("NOT SUPPORT Param type in: {0}.{1}(...) \n{2}", t.Name, info.Name, e.ToString()); errors[0].Add(err); return; } writeLine(n,"[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]"); string functionName = alias; if (string.IsNullOrEmpty(alias)) { functionName = info.Name; string luafuncName; if (op_funcLuaNames.TryGetValue(functionName, out luafuncName)) { functionName = luafuncName; } } funcNames.Add(functionName); ParamTypeData T = new ParamTypeData(t); ParamTypeData returnType = new ParamTypeData(info.ReturnType); writeLine(n,"public static int {0}(IntPtr L)", functionName); writeLine(n,"{"); WriteTryBegin(n); int paramIndexBegin = 1; if (info.IsStatic == false) { paramIndexBegin = 2; writeSelf(n,T); } bool isStatic = info.IsStatic; for (int i = 0; i < pinfos.Length; ++i) { ParamTypeData paramType = paramTypsList[i]; paraseParam(n, paramType, i, i + paramIndexBegin); } ParamTypeData[] paramTypes = paramTypsList.ToArray(); //写入方法调用 string opname; if ( op_funcNames.TryGetValue(info.Name,out opname) ) { if( info.Name != "op_UnaryNegation") //不是单目操作符 writeLine(n, "{0} ret = ({1})param0 {2} ({3})param1;", returnType.csFullTypeName, paramTypes[0].csFullTypeName, opname, paramTypes[1].csFullTypeName); else writeLine(n, "{0} ret = {2}({1})param0;",returnType.csFullTypeName, paramTypes[0].csFullTypeName, opname); } else { writeLine(n, "{1} {2}.{0}(", info.Name, returnType.luaTypeName == "void" ? "" : returnType.csFullTypeName + " ret = ", isStatic ? T.csFullTypeName : "self"); for (int i = 0; i < pinfos.Length; ++i) { writeLine(n, "({2})param{0}{1}", i, i == pinfos.Length - 1 ? "" : ",", paramTypes[i].csFullTypeName); } writeLine(n, ");"); } if (returnType.luaTypeName != "void") { if (returnType.isNeedMt) { if (info.Name == "AddComponent" || info.Name == "GetComponent") { writeLine(n, "string mt = {0};", "param0"); } else { if (returnType.IsNeedMetatable()) { if (returnType.IsClass) writeLine(n, "string mt = ({0});", "ret != null ? ret.GetType().Name : \"\" "); else writeLine(n, "string mt = {0};", "ret.GetType().Name"); int paramCount = pinfos.Length; if (isStatic == false) paramCount += 1; writeLine(n, "if(LuaDLL.lua_isstring(L,{0}))", paramCount + 1); writeLine(n, "\tmt = LuaDLL.lua_tostring(L,{0});", paramCount + 1); } } returnType.WriteToLuaFromCS(n, "ret", 0, "mt"); } else { returnType.WriteToLuaFromCS(n, "ret", 0); } } if (info.Name == "Destroy") { writeLine(n, "IntPtr idptr = LuaDLL.lua_touserdata(L, 1);"); writeLine(n, "LuaStatic.RemoveGameObject(idptr);"); } else if (isStatic == false && t.IsValueType) { writeLine(n, "IntPtr idptr = LuaDLL.lua_touserdata(L, 1);"); n.WriteLine("objs[idptr.ToInt64()] = self;"); } writeLine(n,"return {0};", returnType.luaTypeName == "void" ? "0" : "1"); WriteTryEnd(n); writeLine(n, "}"); writeLine(n, ""); writeLine(n, ""); }
//constructor static void writeConstructor(StreamWriter n, ConstructorInfo info, Type t, string alias) { writeLine(n, "//---------------------------------"); ParamTypeData T = new ParamTypeData(t); string functionName = alias; if (string.IsNullOrEmpty(alias)) functionName = T.csTypeName; funcNames.Add(functionName); writeLine(n,"[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]"); writeLine(n,"public static int {0}(IntPtr L)", functionName); writeLine(n,"{"); ParameterInfo[] pinfos = info.GetParameters(); for (int i = 0; i < pinfos.Length; ++i) { ParamTypeData paramType = new ParamTypeData(pinfos[i].ParameterType); paraseParam(n, paramType, i, i + 1); } ParamTypeData RetT = new ParamTypeData(info.DeclaringType); writeLine(n,"{0} ret = new {0}(", RetT.csFullTypeName); for (int i = 0; i < pinfos.Length; ++i) { writeLine(n,"param{0}{1}", i, i == pinfos.Length - 1 ? "" : ","); } writeLine(n,");"); writeLine(n,"LuaStatic.addGameObject2Lua(L,ret,\"{0}\");",T.csTypeName); writeLine(n,"return 1;"); writeLine(n,"}"); writeLine(n,""); writeLine(n,""); writeLine(n,""); }
//从Lua读数据写回cs的对象属性 static void writeWriteProp(StreamWriter n, Type objt, Type propt, string propName, bool isStatic, bool isEnum ) { ParamTypeData objT = new ParamTypeData(objt); string objectTypeFullName = objT.csFullTypeName; writeLine(n, "//---------------------------------"); funcNames.Add("set_" + propName); n.WriteLine("[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]"); ParamTypeData paramType = new ParamTypeData(propt); writeLine(n,"public static int set_{0}(IntPtr L)", propName); writeLine(n,"{"); WriteTryBegin(n); int index = 1; if (isStatic == false) { index = 2; writeSelf(n,objT); } string owner = isStatic ? objectTypeFullName : "self"; string variableExp = string.Format("{0}.{1}", owner, propName); paramType.ReadFromLua2CS(n, index, variableExp,0); if (isStatic == false && objt.IsValueType) { writeLine(n, "IntPtr idptr = LuaDLL.lua_touserdata(L, 1);"); n.WriteLine("objs[idptr.ToInt64()] = self;"); } n.WriteLine("return 0;"); WriteTryEnd(n); n.WriteLine("}"); n.WriteLine(""); n.WriteLine(""); n.WriteLine(""); }
//从lua读取每个参数的值 static void paraseParam(StreamWriter n, ParamTypeData paramType, int i, int index) { string variableExp = string.Format("param{0}", i); writeLine(n, "{0} {1} = default({0});", paramType.csFullTypeName, variableExp); paramType.ReadFromLua2CS(n, index, variableExp,0); }
static void writeSelf(StreamWriter n,ParamTypeData T) { string objectTypeFullName = T.csFullTypeName; if (T.t.IsValueType) writeLine(n, "{0} self = ({0})Funcs.GetObj(L,1);", objectTypeFullName); else writeLine(n, "{0} self = Funcs.GetObj(L,1) as {0};", objectTypeFullName); if (T.IsClass) { writeLine(n, "if(self == null)"); writeLine(n, "{"); writeLine(n,"\tLuaStatic.traceback(L,\"nullobj call\");"); writeLine(n,"\tLuaDLL.lua_error(L); return 1;"); writeLine(n,"}"); } }
//从cs对象读属性写回Lua static void writeReadProp(StreamWriter n, Type objt, Type propt, string propName, bool isStatic, bool isEnum ) { ParamTypeData objT = new ParamTypeData(objt); string objectTypeFullName = objT.csFullTypeName; //需要如下信息 //属性名 info.Name --> propName //属性类型 info.PropertyType.FullName --> propTypeFullName //属性类型 info.PropertyType.Name --> propTypeName //isStatic //对象类型 t.FullName --> objectTypeFullName //info.PropertyType.IsEnum --> isEnum //namespace info.PropertyType.Namesapce --> propNamespace writeLine(n, "//---------------------------------"); funcNames.Add("get_"+propName); n.WriteLine("[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]"); ParamTypeData paramType = new ParamTypeData(propt); writeLine(n,"public static int get_{0}(IntPtr L)", propName); writeLine(n,"{"); WriteTryBegin(n); if (isStatic == false) { writeSelf(n,objT); } string owner = isStatic ? objectTypeFullName : "self"; string variableExp = string.Format("{0}.{1}", owner, propName); paramType.WriteToLuaFromCS(n, variableExp, 0); n.WriteLine("return 1;"); WriteTryEnd(n); n.WriteLine("}"); n.WriteLine(""); n.WriteLine(""); n.WriteLine(""); }
static void writeFuncsArray(StreamWriter n,Type t,ExMethodData[] extmethods) { ParamTypeData T = new ParamTypeData(t); string str; string tableName = T.csTypeName; n.WriteLine("public static void Register(IntPtr L)"); n.WriteLine("{"); writeLine(n, "LuaDLL.lua_newtable(L);"); List<string> metafuncs = new List<string>(); foreach( string each in funcNames) { if (each.StartsWith("__")) { metafuncs.Add(each); metafuncs.Add(each); continue; } n.WriteLine("LuaDLL.lua_pushstdcallcfunction(L,new LuaCSFunction({0}) );", each); n.WriteLine("LuaDLL.lua_setfield(L, -2, \"{0}\");", each); } //write unbind n.WriteLine("LuaDLL.lua_pushstdcallcfunction(L,new LuaCSFunction(LuaStatic.removeGameObjectFrameCache) );"); n.WriteLine("LuaDLL.lua_setfield(L, -2, \"unbind\");"); if (extmethods != null) { foreach (ExMethodData extmethod in extmethods) { if (extmethod.luaName.StartsWith("__")) { metafuncs.Add(extmethod.luaName); metafuncs.Add(extmethod.csName); continue; } n.WriteLine("LuaDLL.lua_pushstdcallcfunction(L,new LuaCSFunction({0}) );", extmethod.csName); n.WriteLine("LuaDLL.lua_setfield(L, -2, \"{0}\");", extmethod.luaName); } } //gc metafuncs.Add("__gc"); metafuncs.Add("LuaStatic.GameObjectGC"); writeLine(n, "LuaDLL.lua_pushvalue(L,-1);"); writeLine(n, "LuaDLL.lua_setglobal(L,\"{0}\");","mt" + tableName); //mt writeLine(n, "LuaDLL.lua_newtable(L);"); writeLine(n, "LuaDLL.lua_pushvalue(L,-2);"); writeLine(n, "LuaDLL.lua_setfield(L,-2,\"__index\");"); writeLine(n, "LuaDLL.lua_setglobal(L,\"{0}\");", "mtp"+tableName); //{ __index = mt } writeLine(n, "LuaDLL.lua_pop(L,1);"); n.WriteLine("}"); n.WriteLine("public static void SetMtLink(IntPtr L)"); n.WriteLine("{"); str = string.Format("LuaDLL.lua_getglobal(L,\"{0}\");", "mt"+tableName); //mt n.WriteLine(str); string parentName = (T.csTypeName == "Object" || t.BaseType.FullName == "System.Object") ? "" : t.BaseType.Name; //__index if(string.IsNullOrEmpty(parentName) == false) { n.WriteLine("LuaDLL.lua_getglobal(L,\"{0}\");","mtp"+parentName); //mt,mtp writeLine(n, "LuaDLL.lua_setmetatable(L,-2);");//mt } writeLine(n, "LuaDLL.lua_newtable(L);"); //mt,cs writeLine(n, "LuaDLL.lua_pushstring(L,\"{0}\");", tableName); //mt,cs,tablename writeLine(n, "LuaDLL.lua_setfield(L,-2,\"name\");"); //mt,cs //metafuncs { for (int i = 0; i < metafuncs.Count; i += 2) { n.WriteLine("LuaDLL.lua_pushstdcallcfunction(L,new LuaCSFunction({0}) );", metafuncs[i + 1]); n.WriteLine("LuaDLL.lua_setfield(L, -2, \"{0}\");", metafuncs[i]); } } writeLine(n, "LuaDLL.lua_newtable(L);"); //mt,cs,cst n.WriteLine("LuaDLL.lua_getglobal(L,\"createcstable\");"); //mt,cs,cst,f n.WriteLine("LuaDLL.lua_pushvalue(L,-4);"); //mt,cs,cst,f,mt n.WriteLine("LuaDLL.lua_pushvalue(L,-4);"); //mt,cs,cst,f,mt,cs n.WriteLine("LuaDLL.lua_pushvalue(L,-4);"); //mt,cs,cst,f,mt,cs,cst n.WriteLine("LuaDLL.lua_pcall(L,3,0,0);"); //mt,cs,cst writeLine(n, "LuaDLL.lua_setmetatable(L,-2);"); //mt,cs writeLine(n, "LuaDLL.lua_setglobal(L,\"{0}\");", tableName);//mt n.WriteLine("LuaDLL.lua_pop(L,1);"); n.WriteLine("}"); n.WriteLine(""); }
static void writeHead(StreamWriter n, Type t) { n.WriteLine("namespace LuaInterface"); n.WriteLine("{"); n.WriteLine("using System;"); n.WriteLine("using System.Collections.Generic;"); n.WriteLine("using System.Collections;"); n.WriteLine("using UnityEngine;"); n.WriteLine(""); n.WriteLine(""); ParamTypeData T = new ParamTypeData(t); string str = string.Format("public partial class Lua{0}", T.csTypeName); n.WriteLine(str); n.WriteLine("{"); n.WriteLine("public static readonly Dictionary<long, System.Object> objs = LuaStatic.objs;"); n.WriteLine(""); }
public ParamTypeData(Type _t) { luaTypeName = ""; paramType = PARAMTYPE.NONE; t = _t; if (t.IsArray) { paramType = PARAMTYPE.ARRAY; subtdata = new ParamTypeData(t.GetElementType()); } else if (t.Name == "ArrayList") { paramType = PARAMTYPE.ARRAYLIST; subtdata = new ParamTypeData(typeof(System.Object)); } else { Type[] subts = t.GetGenericArguments(); if (subts.Length == 0) //简单类型 { paramType = PARAMTYPE.SIMPLE; luaTypeName = getTypeForLua(Name); } else { getTypeForLua(Name);//for check error paramType = PARAMTYPE.CONTAINER; luaTypeName = "List"; //List is enough likely if (Name.IndexOf("BetterList") >= 0) luaTypeName = "BetterList"; subtdata = new ParamTypeData(subts[0]); } } if (paramType == PARAMTYPE.ARRAY) //int[], List<>[], int[][] { csFullTypeName = string.Format("{0}[]", subtdata.csFullTypeName); csTypeName = string.Format("{0}[]", subtdata.csTypeName); } else if (paramType == PARAMTYPE.ARRAYLIST) { csFullTypeName = "ArrayList"; csTypeName = "ArrayList"; } else if (paramType == PARAMTYPE.CONTAINER) //list<int>, list<list<int>> { csFullTypeName = string.Format("{0}<{1}>", luaTypeName, subtdata.csFullTypeName); csTypeName = string.Format("{0}<{1}>", luaTypeName, subtdata.csTypeName); } else { csFullTypeName = FullName; csTypeName = Name; } }
static void writeIsNilFunc(StreamWriter n, ParamTypeData T) { funcNames.Add("get_isnil"); writeLine(n, "[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]"); writeLine(n, "public static int get_isnil(IntPtr L)"); writeLine(n, "{"); string objectTypeFullName = T.csFullTypeName; writeLine(n, "IntPtr idptr = LuaDLL.lua_touserdata(L, 1);"); writeLine(n, "{0} self = default({0});", objectTypeFullName); writeLine(n, "System.Object temp = default(System.Object);"); writeLine(n, "if(objs.TryGetValue(idptr.ToInt64(),out temp))"); writeLine(n, "{"); writeLine(n, "\tself = ({0})temp;", objectTypeFullName); writeLine(n, "\tLuaDLL.lua_pushboolean(L, self == null);"); writeLine(n, "}"); writeLine(n, "else {"); writeLine(n, "\tLuaDLL.lua_pushboolean(L, true);"); writeLine(n, "}"); writeLine(n, "return 1;"); writeLine(n, "}"); writeLine(n, "\n"); }
static void WriteEnum(StreamWriter n, Type t) { Array values = Enum.GetValues(t); Array names = Enum.GetNames(t); ParamTypeData T = new ParamTypeData(t); string enumName = T.csTypeName; string str = string.Format("-------- generating Lua Enum for {0} ----------", enumName); str = string.Format("// {0}", enumName); n.WriteLine(str); str = string.Format("LuaDLL.lua_newtable(L);"); n.WriteLine(str); for (int i = 0; i < values.Length; ++i) { int v = (int)values.GetValue(i); str = string.Format("LuaDLL.lua_pushnumber(L,(double){0});", v); n.WriteLine(str); string name = (string)names.GetValue(i); str = string.Format("LuaDLL.lua_setfield(L,-2,\"{0}\");", name); n.WriteLine(str); } str = string.Format("LuaDLL.lua_setglobal(L,\"{0}\");", enumName); n.WriteLine(str); n.WriteLine(""); }