Xlua学习记录

先说说Unity热跟新方案

1.LuaInterface CS2Lua simpleFramWork  ulua (不再维护) 

2.tolua 基于tolua 开发了 luaFramwork

3 Slua 代码质量好,性能比tolua 低

4C#light (c#like) Lsharp 很少用于商业

5 腾讯的xlua

 

说说 LuaInterface

LuaForWindows下载地址:http://luaforge.net/projects/luaforwindows/

LuaInterface下载地址:http://luaforge.net/projects/luainterface/ (下载luainterface-1.5.3,这里面的资源比较多,还有比较完整的示例代码。)

LuaInterface.Lua类是CLR访问Lua解释器的主要接口,一个LuaInterface.Lua类对象就代表了一个Lua解释器(或Lua执行环境),Lua解释器可以同时存在多个,并且它们之间是完全相互独立的。

 

xlua传送门

https://github.com/Tencent/xLua

FAQ  常见问题

https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/faq.md

 

对于lua 不熟悉的

http://www.runoob.com/lua/lua-tutorial.html

 

 

xlua 运行过程


c#源代码  —— 编译 ——中间语言 IL——安装包

lua——安装包

xlua热跟新

 

开启 热跟新宏

C#代码写好了之后, 点击 Xlua-Generate Code 就会  在XLua下 Gen文件 下 生成C#的文件。 没出问题就 输出Finish

最后 再点下Hotfix Inject In Editor   就可以 开始 开始热跟新了。

 

 

 

对某个类打补丁

类名加[Hotfix]特性(标签)

源码

 

加了这个标签 后,就会注入 生成到xlua里面

提前要 在 一些 可能以后会出Bug 不确定的,会跟新的,变动的类,前面 加上[Hotfix]特性, 在可能需要改写,跟新的方法前 加上   [LuaCallCSharp]  特性, 这样 就可以在Lua里面  调用 HotFix方法。 不需要更新的,确定不用修改的可以加上黑名单[XLua.BlackList] 特性。

      var extensionMethods = Utils.GetExtensionMethodsOf(toBeWrap);

源代码 ,下面这个方法 会检查标签类型。

进行 迭代,遍历一个类 里所有 是成员方法,是否有加那些特性,  所有打包的

IEnumerable<MethodInfo> extend_methods = GetExtensionMethodsOf(type); 

  internal static IEnumerable<MethodInfo> GetExtensionMethodsOf(Type type_to_be_extend)
        {
            if (InternalGlobals.extensionMethodMap == null)
            {
                List<Type> type_def_extention_method = new List<Type>();

                IEnumerator<Type> enumerator = GetAllTypes().GetEnumerator();
                
                while(enumerator.MoveNext())
                {
                    Type type = enumerator.Current;
                    if (type.IsDefined(typeof(ExtensionAttribute), false)  && (
                            type.IsDefined(typeof(ReflectionUseAttribute), false)
#if UNITY_EDITOR || XLUA_GENERAL
                            || type.IsDefined(typeof(LuaCallCSharpAttribute), false)
#endif
                        ))
                    {
                        type_def_extention_method.Add(type);
                    }

                    if (!type.IsAbstract() || !type.IsSealed()) continue;

                    var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
                    for (int i = 0; i < fields.Length; i++)
                    {
                        var field = fields[i];
                        if ((field.IsDefined(typeof(ReflectionUseAttribute), false)
#if UNITY_EDITOR || XLUA_GENERAL
                            || field.IsDefined(typeof(LuaCallCSharpAttribute), false)
#endif
                            ) && (typeof(IEnumerable<Type>)).IsAssignableFrom(field.FieldType))
                        {
                            type_def_extention_method.AddRange((field.GetValue(null) as IEnumerable<Type>)
                                .Where(t => t.IsDefined(typeof(ExtensionAttribute), false)));
                        }
                    }

                    var props = type.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
                    for (int i = 0; i < props.Length; i++)
                    {
                        var prop = props[i];
                        if ((prop.IsDefined(typeof(ReflectionUseAttribute), false)
#if UNITY_EDITOR || XLUA_GENERAL
                            || prop.IsDefined(typeof(LuaCallCSharpAttribute), false)
#endif
                            ) && (typeof(IEnumerable<Type>)).IsAssignableFrom(prop.PropertyType))
                        {
                            type_def_extention_method.AddRange((prop.GetValue(null, null) as IEnumerable<Type>)
                                .Where(t => t.IsDefined(typeof(ExtensionAttribute), false)));
                        }
                    }
                }
                enumerator.Dispose();

                InternalGlobals.extensionMethodMap = (from type in type_def_extention_method
                                        from method in type.GetMethods(BindingFlags.Static | BindingFlags.Public)
                                        where method.IsDefined(typeof(ExtensionAttribute), false) && IsSupportedMethod(method)
                                        group method by getExtendedType(method)).ToDictionary(g => g.Key, g => g as IEnumerable<MethodInfo>);
            }
            IEnumerable<MethodInfo> ret = null;
            InternalGlobals.extensionMethodMap.TryGetValue(type_to_be_extend, out ret);
            return ret;
        }

下面是 生成反射包装的方法 

 static void makeReflectionWrap(RealStatePtr L, Type type, int cls_field, int cls_getter, int cls_setter,
            int obj_field, int obj_getter, int obj_setter, int obj_meta, out LuaCSFunction item_getter, out LuaCSFunction item_setter, bool private_access = false)
        {
            ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
            BindingFlags flag = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | (private_access ? BindingFlags.NonPublic : BindingFlags.Public);
            FieldInfo[] fields = type.GetFields(flag);
            EventInfo[] all_events = type.GetEvents(flag | BindingFlags.Public | BindingFlags.NonPublic);

            for (int i = 0; i < fields.Length; ++i)
            {
                FieldInfo field = fields[i];
                string fieldName = field.Name;
                if (private_access)
                {
                    // skip hotfix inject field
                    if (field.IsStatic && (field.Name.StartsWith("__Hotfix") || field.Name.StartsWith("_c__Hotfix")) && typeof(Delegate).IsAssignableFrom(field.FieldType))
                    {
                        continue;
                    }
                    if (all_events.Any(e => e.Name == fieldName))
                    {
                        fieldName = "&" + fieldName;
                    }
                }
                if (field.IsStatic && (field.IsInitOnly || field.IsLiteral))
                {
                    LuaAPI.xlua_pushasciistring(L, fieldName);
                    translator.PushAny(L, field.GetValue(null));
                    LuaAPI.lua_rawset(L, cls_field);
                }
                else
                {
                    LuaAPI.xlua_pushasciistring(L, fieldName);
                    translator.PushFixCSFunction(L, genFieldGetter(type, field));
                    LuaAPI.lua_rawset(L, field.IsStatic ? cls_getter : obj_getter);

                    LuaAPI.xlua_pushasciistring(L, fieldName);
                    translator.PushFixCSFunction(L, genFieldSetter(type, field));
                    LuaAPI.lua_rawset(L, field.IsStatic ? cls_setter : obj_setter);
                }
            }

            EventInfo[] events = type.GetEvents(flag);
            for (int i = 0; i < events.Length; ++i)
            {
                EventInfo eventInfo = events[i];
                LuaAPI.xlua_pushasciistring(L, eventInfo.Name);
                translator.PushFixCSFunction(L, translator.methodWrapsCache.GetEventWrap(type, eventInfo.Name));
                bool is_static = (eventInfo.GetAddMethod() != null) ? eventInfo.GetAddMethod().IsStatic : eventInfo.GetRemoveMethod().IsStatic;
                LuaAPI.lua_rawset(L, is_static ? cls_field : obj_field);
            }

            Dictionary<string, PropertyInfo> prop_map = new Dictionary<string, PropertyInfo>();
            List<PropertyInfo> items = new List<PropertyInfo>();
            PropertyInfo[] props = type.GetProperties(flag);
            for (int i = 0; i < props.Length; ++i)
            {
                PropertyInfo prop = props[i];
                if (prop.Name == "Item" && prop.GetIndexParameters().Length > 0)
                {
                    items.Add(prop);
                }
                else
                {
                    prop_map.Add(prop.Name, prop);
                }
            }

            var item_array = items.ToArray();
            item_getter = item_array.Length > 0 ? genItemGetter(type, item_array) : null;
            item_setter = item_array.Length > 0 ? genItemSetter(type, item_array) : null; ;
            MethodInfo[] methods = type.GetMethods(flag);
            Dictionary<MethodKey, List<MemberInfo>> pending_methods = new Dictionary<MethodKey, List<MemberInfo>>();
            for (int i = 0; i < methods.Length; ++i)
            {
                MethodInfo method = methods[i];
                string method_name = method.Name;

                MethodKey method_key = new MethodKey { Name = method_name, IsStatic = method.IsStatic };
                List<MemberInfo> overloads;
                if (pending_methods.TryGetValue(method_key, out overloads))
                {
                    overloads.Add(method);
                    continue;
                }

                PropertyInfo prop = null;
                if (method_name.StartsWith("add_") || method_name.StartsWith("remove_")
                    || method_name == "get_Item" || method_name == "set_Item")
                {
                    continue;
                }

                if (method_name.StartsWith("op_")) // 操作符
                {
                    if (InternalGlobals.supportOp.ContainsKey(method_name))
                    {
                        if (overloads == null)
                        {
                            overloads = new List<MemberInfo>();
                            pending_methods.Add(method_key, overloads);
                        }
                        overloads.Add(method);
                    }
                    continue;
                }
                else if (method_name.StartsWith("get_") && method.IsSpecialName) // getter of property
                {
                    string prop_name = method.Name.Substring(4);
                    if (!prop_map.TryGetValue(prop_name, out prop))
                    {
                        prop = type.GetProperty(prop_name);
                    }
                    LuaAPI.xlua_pushasciistring(L, prop.Name);
                    translator.PushFixCSFunction(L, translator.methodWrapsCache._GenMethodWrap(method.DeclaringType, prop.Name, new MethodBase[] { method }).Call);
                    LuaAPI.lua_rawset(L, method.IsStatic ? cls_getter : obj_getter);
                }
                else if (method_name.StartsWith("set_") && method.IsSpecialName) // setter of property
                {
                    string prop_name = method.Name.Substring(4);
                    if (!prop_map.TryGetValue(prop_name, out prop))
                    {
                        prop = type.GetProperty(prop_name);
                    }
                    LuaAPI.xlua_pushasciistring(L, prop.Name);
                    translator.PushFixCSFunction(L, translator.methodWrapsCache._GenMethodWrap(method.DeclaringType, prop.Name, new MethodBase[] { method }).Call);
                    LuaAPI.lua_rawset(L, method.IsStatic ? cls_setter : obj_setter);
                }
                else if (method_name == ".ctor" && method.IsConstructor)
                {
                    continue;
                }
                else
                {
                    if (overloads == null)
                    {
                        overloads = new List<MemberInfo>();
                        pending_methods.Add(method_key, overloads);
                    }
                    overloads.Add(method);
                }
            }


            IEnumerable<MethodInfo> extend_methods = GetExtensionMethodsOf(type);
            if (extend_methods != null)
            {
                foreach (var extend_method in extend_methods)
                {
                    MethodKey method_key = new MethodKey { Name = extend_method.Name, IsStatic = false };
                    List<MemberInfo> overloads;
                    if (pending_methods.TryGetValue(method_key, out overloads))
                    {
                        overloads.Add(extend_method);
                        continue;
                    }
                    else
                    {
                        overloads = new List<MemberInfo>() { extend_method };
                        pending_methods.Add(method_key, overloads);
                    }
                }
            }

            foreach (var kv in pending_methods)
            {
                if (kv.Key.Name.StartsWith("op_")) // 操作符
                {
                    LuaAPI.xlua_pushasciistring(L, InternalGlobals.supportOp[kv.Key.Name]);
                    translator.PushFixCSFunction(L,
                        new LuaCSFunction(translator.methodWrapsCache._GenMethodWrap(type, kv.Key.Name, kv.Value.ToArray()).Call));
                    LuaAPI.lua_rawset(L, obj_meta);
                }
                else
                {
                    LuaAPI.xlua_pushasciistring(L, kv.Key.Name);
                    translator.PushFixCSFunction(L,
                        new LuaCSFunction(translator.methodWrapsCache._GenMethodWrap(type, kv.Key.Name, kv.Value.ToArray()).Call));
                    LuaAPI.lua_rawset(L, kv.Key.IsStatic ? cls_field : obj_field);
                }
            }
        }


发出类型打包,通过 ILGenerator 接口,调用 IL(中间语言)里 的方法,传送门 : https://blog.csdn.net/dodream/article/details/4726421

Emit类 的是CodeEmit类里的

 public Type EmitTypeWrap(Type toBeWrap)
        {
            TypeBuilder wrapTypeBuilder = CodeEmitModule.DefineType(toBeWrap.Name + "Wrap" + (genID++), TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Abstract | TypeAttributes.Sealed);

            var methodBuilder = wrapTypeBuilder.DefineMethod("__Register", MethodAttributes.Static | MethodAttributes.Public, null, parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            var instanceFlag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
            var staticFlag = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;

            var instanceFields = toBeWrap.GetFields(instanceFlag);
            var instanceProperties = toBeWrap.GetProperties(instanceFlag);
            var extensionMethods = Utils.GetExtensionMethodsOf(toBeWrap);
            var instanceMethods = toBeWrap.GetMethods(instanceFlag)
                .Concat(extensionMethods == null ? Enumerable.Empty<MethodInfo>() : Utils.GetExtensionMethodsOf(toBeWrap))
                .Where(m => Utils.IsSupportedMethod(m))
                .Where(m => !m.IsSpecialName).GroupBy(m => m.Name).ToList();
            var supportOperators = toBeWrap.GetMethods(staticFlag)
                .Where(m => m.IsSpecialName && InternalGlobals.supportOp.ContainsKey(m.Name))
                .GroupBy(m => m.Name);

            //begin obj
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_M1);
            il.Emit(OpCodes.Call, Utils_BeginObjectRegister);

            foreach(var field in instanceFields)
            {
                emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, true), Utils.GETTER_IDX, field.Name);
                emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, false), Utils.SETTER_IDX, field.Name);
            }

            List<MethodBase> itemGetter = new List<MethodBase>();
            List<MethodBase> itemSetter = new List<MethodBase>();

            foreach(var prop in instanceProperties)
            {
                var getter = prop.GetGetMethod();
                if (getter != null && getter.IsPublic)
                {
                    if (prop.Name == "Item" && prop.GetIndexParameters().Length > 0)
                    {
                        if (!prop.GetIndexParameters()[0].ParameterType.IsAssignableFrom(typeof(string)))
                        {
                            itemGetter.Add(getter);
                        }
                    }
                    else
                    {
                        emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, getter, true), Utils.GETTER_IDX, prop.Name);
                    }
                }

                var setter = prop.GetSetMethod();
                if (setter != null && setter.IsPublic)
                {
                    if (prop.Name == "Item" && prop.GetIndexParameters().Length > 0)
                    {
                        if (!prop.GetIndexParameters()[0].ParameterType.IsAssignableFrom(typeof(string)))
                        {
                            itemSetter.Add(setter);
                        }
                    }
                    else
                    {
                        emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, setter, false), Utils.SETTER_IDX, prop.Name);
                    }
                }
            }

            foreach (var group in instanceMethods)
            {
                emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.METHOD_IDX, group.Key);
            }

            foreach (var group in supportOperators)
            {
                emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.OBJ_META_IDX, InternalGlobals.supportOp[group.Key]);
            }

            foreach (var ev in toBeWrap.GetEvents(instanceFlag))
            {
                emitRegisterFunc(il, emitEventWrap(wrapTypeBuilder, ev), Utils.METHOD_IDX, ev.Name);
            }

            //end obj
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Ldnull);
            if (itemGetter.Count > 0)
            {
                il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder, itemGetter, true, toBeWrap));
                il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            }
            il.Emit(OpCodes.Ldnull);
            if (itemSetter.Count > 0)
            {
                il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder, itemSetter, true, toBeWrap));
                il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            }
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Call, Utils_EndObjectRegister);

            // begin class
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder,
                toBeWrap.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)
                .Cast<MethodBase>().ToList(), false, toBeWrap, toBeWrap.ToString() + " constructor"));
            il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Call, Utils_BeginClassRegister);

            var staticMethods = toBeWrap.GetMethods(staticFlag)
                .Where(m => Utils.IsSupportedMethod(m))
                .Where(m => !m.IsSpecialName).GroupBy(m => m.Name);

            var staticFields = toBeWrap.GetFields(staticFlag);

            var staticProperties = toBeWrap.GetProperties(staticFlag);

            foreach (var group in staticMethods)
            {
                emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.CLS_IDX, group.Key);
            }

            foreach (var ev in toBeWrap.GetEvents(staticFlag))
            {
                emitRegisterFunc(il, emitEventWrap(wrapTypeBuilder, ev), Utils.CLS_IDX, ev.Name);
            }

            foreach (var prop in staticProperties)
            {
                var getter = prop.GetGetMethod();
                if (getter != null && getter.IsPublic)
                {
                    emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, getter, true), Utils.GETTER_IDX, prop.Name);
                }

                var setter = prop.GetSetMethod();
                if (setter != null && setter.IsPublic)
                {
                    emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, setter, false), Utils.SETTER_IDX, prop.Name);
                }
            }

            foreach (var field in staticFields)
            {
                if (field.IsInitOnly || field.IsLiteral)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldloc, translator);
                    il.Emit(OpCodes.Ldc_I4, Utils.CLS_IDX);
                    il.Emit(OpCodes.Ldstr, field.Name);
                    if (field.IsLiteral)
                    {
                        LocalBuilder literalStore = il.DeclareLocal(field.FieldType);
                        emitLiteralLoad(il, field.FieldType, field.GetValue(null), literalStore.LocalIndex);
                        il.Emit(OpCodes.Stloc, literalStore);
                        il.Emit(OpCodes.Ldloc, literalStore);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldsfld, field);
                    }
                    if (field.FieldType.IsValueType)
                    {
                        il.Emit(OpCodes.Box, field.FieldType);
                    }
                    il.Emit(OpCodes.Call, Utils_RegisterObject);
                }
                else
                {
                    emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, true), Utils.CLS_GETTER_IDX, field.Name);
                    emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, false), Utils.CLS_SETTER_IDX, field.Name);
                }
            }

            //end class
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Call, Utils_EndClassRegister);

            il.Emit(OpCodes.Ret);

            return wrapTypeBuilder.CreateType();
        }

上面基本上就 点下Generate Code 和 Hotfix Inject In Editor 做的事情,还有一些没贴出来,他们的源码实在是太多了

 

 

xlua在 Unity中的使用:

在代码发布之前要做的

[Hotfix]
public class FishHotFix : MonoBehaviour {

    LuaEnv lua = new LuaEnv();
    // Use this for initialization

    public static Dictionary<string, GameObject> prefabsDic = new Dictionary<string, GameObject>();
    private void Awake()
    {
        lua.AddLoader(MyLoader);

        lua.DoString("require 'FishLua'");
    }

    private byte[] MyLoader(ref string filePath)
    {
        string luaPath = Application.streamingAssetsPath + @"\" + filePath + ".lua.txt";

        return System.Text.Encoding.UTF8.GetBytes(System.IO.File.ReadAllText(luaPath)); 
    }
	// Update is called once per frame
	void Update ()
    {
        
    }
    [LuaCallCSharp]
    public   void LoadResource(string resName,string filePath)
    {

        StartCoroutine(LoadResourceCorotine(resName, filePath));
    }

    IEnumerator LoadResourceCorotine(string resName,string filePath )
    {
       UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(@"http://localhost/AssetBundles/"+filePath);
       yield return request.SendWebRequest();

        AssetBundle bundle= DownloadHandlerAssetBundle.GetContent(request);

        //AssetBundle assetBundle = AssetBundle.LoadFromFile(@"" + Application.streamingAssetsPath + @"/" + filePath);
        GameObject gameObject = bundle.LoadAsset<GameObject>(resName);
        if (!prefabsDic.ContainsKey(resName))
        {
            prefabsDic.Add(resName, gameObject);
        }
        bundle.LoadAsset<GameObject>(resName);
    }
    [LuaCallCSharp]
    public static GameObject GetPrefabs(string  name)
    {
        if (prefabsDic.ContainsKey(name))
        {
            return prefabsDic[name];    
        }        
        return null;
    }
    private void OnDisable()
    {
        lua.DoString("require 'FishDispose'");   
    }
    private void OnDestroy()
    {
        lua.Dispose();
    }
}

 
lua.AddLoader(MyLoader);

这个方法 在   执行   lua.DoString("require 'xxx"); 时 就会运行 MyLoader这个函数。

源码

public void AddLoader(CustomLoader loader)

CustomLoader 是一个委托,我们调用 AddLoader的时候, 只需要把自己定义的Loader函数传进入就好了,

   //loader : CustomLoader, filepath参数:(ref类型)输入是require的参数,如果需要支持调试,需要输出真实路径。
   //                        返回值:如果返回null,代表加载该源下无合适的文件,否则返回UTF8编码的byte[]

 public delegate byte[] CustomLoader(ref string filepath);

 public void AddLoader(CustomLoader loader)
  {
            customLoaders.Add(loader);
   }

DoString方法, 一般我们调用的是第二个,方法,它会先把string 转成Byt[]再去调用第一个方法

public object[] DoString(byte[] chunk, string chunkName = "chunk", LuaTable env = null)
        {
#if THREAD_SAFE || HOTFIX_ENABLE
            lock (luaEnvLock)
            {
#endif
                var _L = L;
                int oldTop = LuaAPI.lua_gettop(_L);
                int errFunc = LuaAPI.load_error_func(_L, errorFuncRef);
                if (LuaAPI.xluaL_loadbuffer(_L, chunk, chunk.Length, chunkName) == 0)
                {
                    if (env != null)
                    {
                        env.push(_L);
                        LuaAPI.lua_setfenv(_L, -2);
                    }

                    if (LuaAPI.lua_pcall(_L, 0, -1, errFunc) == 0)
                    {
                        LuaAPI.lua_remove(_L, errFunc);
                        return translator.popValues(_L, oldTop);
                    }
                    else
                        ThrowExceptionFromError(oldTop);
                }
                else
                    ThrowExceptionFromError(oldTop);

                return null;
#if THREAD_SAFE || HOTFIX_ENABLE
            }
#endif
        }

        public object[] DoString(string chunk, string chunkName = "chunk", LuaTable env = null)
        {
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(chunk);
            return DoString(bytes, chunkName, env);
        }

说下  lua.DoString("require 'LuaFileName'" ); 如果 你没有用  lua.AddLoader(MyLoader),去自定义 路径的话,

那么lua会自动从 当前文件下Resources文件夹下去查找LuaFileName的 文件, 再说下这个坑, 后缀为Lua的时候,Unity是没办法读取的,这这个时候怎么办呢,再后缀加上.txt就好了, 例如: mylua.lua.txt 这样。

Dispose 会释放下GC

        public void Dispose()
        {
            FullGc();
            System.GC.Collect();
            System.GC.WaitForPendingFinalizers();

            Dispose(true);

            System.GC.Collect();
            System.GC.WaitForPendingFinalizers();
        }

在 Dispose之前  要清空下委托里面的函数,不然会报错。

一般  不需要运行的时候  清空  ,上面的例子是加在OnDisable里

 private void OnDisable()
    {
        lua.DoString("require 'FishDispose'");   
    }

用法如下

xlua.hotfix( ClassName,'MethodName',nil)

 

在lua中调用,打补丁

xlua.hotfix(ClassName,'MethodName',function (self)
end

对于 我们写的 类  通过 CS.ClassName来访问,如果有命名空间 直接通过CS+命名空间名+.className 来访问 例如访问 GameObject类里的Instantiate() 方法, CS.UnityEngine.GameObject.Instantiate()  这个方法是静态的 所以可以直接通过.来访问。

Q1 在 C#中 不需要重新写某个方法,只需要修改几个值 。

 可以引入util 库,util.hotfix_ex(ClassName,'MethodName',function (self) end

local util =require('util') 

util.hotfix_ex(ClassName,'MethodName',function (self)

 self:MethodName()

end

官方说这个方法 要少用, 减少 性能消耗。

源码

--和xlua.hotfix的区别是:这个可以调用原来的函数
local function hotfix_ex(cs, field, func)
    assert(type(field) == 'string' and type(func) == 'function', 'invalid argument: #2 string needed, #3 function needed!')
    local function func_after(...)
        xlua.hotfix(cs, field, nil)
        local ret = {func(...)}
        xlua.hotfix(cs, field, func_after)
        return unpack(ret)
    end
    xlua.hotfix(cs, field, func_after)
end

xlua.hotfix的

    xlua.hotfix = function(cs, field, func)
                if func == nil then func = false end
                local tbl = (type(field) == 'table') and field or {[field] = func}
                for k, v in pairs(tbl) do
                    local cflag = ''
                    if k == '.ctor' then
                        cflag = '_c'
                        k = 'ctor'
                    end
                    local f = type(v) == 'function' and v or nil
                    xlua.access(cs, cflag .. '__Hotfix0_'..k, f) -- at least one
                    pcall(function()
                        for i = 1, 99 do
                            xlua.access(cs, cflag .. '__Hotfix'..i..'_'..k, f)
                        end
                    end)
                end
            end

 

Q2 访问 私用属性

xlua.private_accessible(ClassName),

另外 访问 普通方法 通过 “:” 来访问,静态方法就可以用 ”.“ 来访问 function(self)  这里self表示 是 自身,相对于C# 里是无参数的方法, 所以在传递参数的时候,只需要在self 后面加上就可以了

 

说下可能遇到的坑

坑1   可能 build之后会报错, 这个时候检查下Xlua 下的Example有没有被删除,把Exapmle删除掉即可。

坑2  在 运行lua 环境 时,一定 要在所有初始化完成(生命周期函数执行)之前 才有效,例如,想要修改一个方法,这个方法在Awake调用,而 lua环境 在Start里面执行, 这样就是无效的了。

坑3  在Unity 里 Random.Range 有int 和float 两个方法,而在Lua中是没有int  float的,怎么办呢, 可以调用Unity里的Math方法进行取整,一般在Lua中调用Ran'dom.Range方法都是识别为float的,或者调用 C#里的强制转换类型。 也就是说,在lua中无法做到的,一般都交给Unity/C#里做。

最后在CS脚本中 打上热跟新的标签的,都需要在Disable中 释放它,减少性能上的开销,不这么做会包错的。

 

 

 

关于 另一个 版本 luainterface :

https://mp.csdn.net/postedit/83502947 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用XLua可以在Unity中实现Lua脚本的编写,同时也可以让Lua脚本与C#代码进行交互。 以下是基本的使用步骤: 1. 下载XLua插件并导入到Unity中。 2. 在Unity中创建一个Lua文件,编写Lua脚本代码。 3. 在C#代码中使用XLua的API来加载并运行Lua脚本,例如: ``` using XLua; public class LuaManager : MonoBehaviour { private LuaEnv luaEnv; void Awake() { luaEnv = new LuaEnv(); luaEnv.DoString("require 'main'"); // 加载并执行Lua脚本 } void Update() { luaEnv.Tick(); // 更Lua环境 } void OnDestroy() { luaEnv.Dispose(); // 释放Lua环境 } } ``` 在上面的例子中,`Awake()`方法中创建了一个Lua环境,然后通过`DoString()`方法加载并执行了Lua脚本。`Update()`方法中每帧都调用了`Tick()`方法来更Lua环境,`OnDestroy()`方法中释放了Lua环境。需要注意的是,在实际的项目中,可能需要更加复杂的逻辑和管理方式来处理Lua脚本的加载和运行。 4. 在Lua脚本中使用XLua提供的API来调用C#代码或者导出Lua模块,例如: ``` -- 导出一个Lua模块 local module = {} module.foo = function() print("Hello from Lua!") end return module -- 调用C#代码 local gameObject = CS.UnityEngine.GameObject("LuaObject") local transform = gameObject.transform transform.position = CS.UnityEngine.Vector3(1, 2, 3) ``` 在上面的例子中,导出了一个名为`module`的Lua模块,并定义了其中的一个函数`foo()`。同时,也调用了C#代码的API来创建了一个的GameObject,并修改了它的Transform组件的位置。 XLua还提供了其他的功能,例如自定义导出规则、GC优化等。在使用XLua之前,建议先了解一些基本的Lua语法和C#与Lua交互的机制,以便更好地使用XLua
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值