当前位置: 首页 > news >正文

热更新解决方案3 —— xLua

概述

xLua框架导入和AB包相关准备

xLua导入

其它的导入

C#调用Lua

1.Lua解析器

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//引用命名空间
using XLua;public class Lesson1_LuaEnv : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){//Lua解析器 能够让我们在Unity中执行Lua//一般情况下 保存它的唯一性LuaEnv env = new LuaEnv();//执行Lua语言//第二个参数是 如果lua出错 会打印第二个参数env.DoString("print('Hello world')", "Lesson1_LuaEnv");//通常我们会执行一个Lua脚本,将要执行的多行代码放入脚本中(Lua知识点:多脚本执行 require)//默认寻找脚本的路径 是在 Resources下 并且 因为在这里估计是通过 Resources.Load去加载Lua脚本的//所以只支持 txt、bytes等文件名后缀,只能在Lua脚本后缀再加上 txt才能执行env.DoString("require('Main')");//帮助我们清除Lua中我们没有手动释放的对象 垃圾回收//帧更新中定时执行 或者 切场景时执行env.Tick();//销毁Lua解析器//通常只会用一个解析器 所以这个函数用的比较少env.Dispose();}// Update is called once per framevoid Update(){}
}

2.Lua文件加载重定向

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;public class Lesson2_Loader : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaEnv env = new LuaEnv();//xlua提供的一个 路径重定向 的方法//允许我们自定义 加载 Lua文件的规则//当我们执行Lua语言 require 时 相当于执行一个lua脚本//它就会 执行 我们自定义传入的这个函数env.AddLoader(MyCustomLoader);//最终我们其实 会去AB包中加载 lua文件env.DoString("require('Main')");env.DoString("require('ttt')");  //测试找不到时 会不会打印我们设置好的错误信息}// Update is called once per framevoid Update(){}//自动执行private byte[] MyCustomLoader(ref string filePath){//通过函数中的逻辑 去加载 Lua文件//传入的参数是 require执行的lua脚本文件名//拼接一个lua文件所在路径string path = Application.dataPath + "/Lua/" + filePath + ".lua";Debug.Log(path);//有路径 就去加载文件 //File 知识点 C#提供的文件读写的类//判断文件是否存在if (File.Exists(path)){return File.ReadAllBytes(path);   //这个方法会将文件中的数据转为二进制数组}return null;}
}

3.Lua解析器管理器

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;/// <summary>
/// Lua管理器
/// 提供 lua解析器
/// 保证解析器的唯一性
/// </summary>
public class LuaMgr : BaseManager<LuaMgr>
{//执行Lua语言的函数//释放垃圾//销毁//重定向private LuaEnv luaEnv;/// <summary>/// 得到Lua 中的_G   后面会频繁使用到/// </summary>public LuaTable Global{get{return luaEnv.Global;}}/// <summary>/// 初始化解析器/// </summary>public void Init(){//若已经初始化了 就直接returnif (luaEnv != null)return;//初始化luaEnv = new LuaEnv();//加载lua脚本 重定向luaEnv.AddLoader(MyCustomLoader);luaEnv.AddLoader(MyCustomABLoader);  // 会依次执行}//Lua脚本会放在AB包//最终我们会通过加载AB包再加载其中的Lua脚本资源 来执行它//AB包中如果加载文本 后缀还是有一定限制的 .lua还是不能被识别//打包时 要把lua文件后缀改为 txt//自动执行private byte[] MyCustomLoader(ref string filePath){//通过函数中的逻辑 去加载 Lua文件//传入的参数 是 require 执行的lua脚本文件名//拼接一个Lua文件所在路径string path = Application.dataPath + "/Lua/" + filePath + ".lua";//有路径 就去加载文件//File知识点 C#提供的文件读写的类//判断文件是否存在if (File.Exists(path))return File.ReadAllBytes(path);elseDebug.Log("MyCustomLoader重定向失败,文件名为:" + filePath);return null;}//重定向加载AB包的Lua脚本private byte[] MyCustomABLoader(ref string filePath){//Debug.Log("进入AB包加载 重定向函数");从AB包中加载lua文件加载AB包//string path = Application.streamingAssetsPath + "/lua";//AssetBundle ab = AssetBundle.LoadFromFile(path);加载Lua文件 返回//TextAsset tx = ab.LoadAsset<TextAsset>(filePath + ".lua");  //改变了文件名所以.lua也是文件名的一部分加载Lua文件 byte数组//return tx.bytes;string path = Application.streamingAssetsPath + "/lua";TextAsset lua = ABMgr.GetInstance().LoadRes<TextAsset>("lua", filePath + ".lua");if (lua != null)return lua.bytes;elseDebug.Log("MyCustomABLoader重定向失败,文件名为:" + filePath);return null;}/// <summary>/// 传入lua文件名 就可以执行luo脚本 (就是DoString 的优化)/// </summary>/// <param name="fileName"></param>public void DoLuaFile(string fileName){string str = string.Format("require('{0}')", fileName);DoString(str);}/// <summary>/// 执行Lua语言/// </summary>/// <param name="str"></param>public void DoString(string str){if(luaEnv == null){Debug.Log("解析器未初始化");return;}luaEnv.DoString(str);}/// <summary>/// 释放资源/// </summary>public void Tick(){if (luaEnv == null){Debug.Log("解析器未初始化");return;}luaEnv.Tick();}/// <summary>/// 销毁解析器/// </summary>public void Dispose(){if (luaEnv == null){Debug.Log("解析器未初始化");return;}luaEnv.Dispose();luaEnv = null;}}

测试

4.全局变量获取

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Lesson4_CallVariable : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");//我们通过C# 没办法直接获取本地局部变量int local = LuaMgr.GetInstance().Global.Get<int>("testLocal");Debug.Log("testLocal:" + local);//使用lua解析器luaenv中的 Global属性int i = LuaMgr.GetInstance().Global.Get<int>("testNumber");Debug.Log("testNumber:" + i);i = 10;//值copy 不会影响原来Lua中的值int i2 = LuaMgr.GetInstance().Global.Get<int>("testNumber");Debug.Log("testNumber:" + i2);//改值LuaMgr.GetInstance().Global.Set("testNumber", 55);i2 = LuaMgr.GetInstance().Global.Get<int>("testNumber");Debug.Log("testNumber:" + i2);bool b = LuaMgr.GetInstance().Global.Get<bool>("testBool");Debug.Log("testBool:" + b);float f = LuaMgr.GetInstance().Global.Get<float>("testFloat");Debug.Log("testFloat:" + f);double d = LuaMgr.GetInstance().Global.Get<double>("testFloat");Debug.Log("testFloat_Double:" + d);string str = LuaMgr.GetInstance().Global.Get<string>("testString");Debug.Log("testString:" + str);}// Update is called once per framevoid Update(){}
}

5.全局函数获取

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using XLua;public class Lesson5_CollFunction : MonoBehaviour
{//无参无返回值的委托public delegate void CustomCall();//有参有返回的委托//该特性是在XLua命名空间中的//加了过后 要在编辑器里 生成 Lua代码[CSharpCallLua]public delegate int CustomCall2(int a);//多返回值委托[CSharpCallLua]public delegate int CustomCall3(int a, out int b, out bool c, out string d, out int e);[CSharpCallLua]public delegate int CustomCall4(int a, ref int b, ref bool c, ref string d, ref int e);//变长参数委托//变长参数的类型 是根据实际情况来定的 如果想要什么类型都接就传 obj[CSharpCallLua]public delegate void CustomCall5(string a, params int[] args);// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");//无参无返回的获取//用什么来接收他们呢 —— 委托最合适CustomCall call = LuaMgr.GetInstance().Global.Get<CustomCall>("testFun");call();//Unity自带委托UnityAction ua = LuaMgr.GetInstance().Global.Get<UnityAction>("testFun");ua();//C#提供的委托Action ac = LuaMgr.GetInstance().Global.Get<Action>("testFun");ac();//XLua提供的一种 获取函数的方法 (尽量少用)LuaFunction lf = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFun");lf.Call();//有参有返回CustomCall2 call2 = LuaMgr.GetInstance().Global.Get<CustomCall2>("testFun2");Debug.Log("有参有返回:" + call2(10));//C#自带的泛型委托 (一般情况下我们都不会自己去申明委托,基本上都是有C#或Unity自带的委托)Func<int, int> sFun = LuaMgr.GetInstance().Global.Get<Func<int, int>>("testFun2");Debug.Log("有参有返回值:" + sFun(20));//XLua提供的LuaFunction lf2 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFun2");Debug.Log("有参有返回值:" + lf2.Call(30)[0]);//多返回值//使用out 和 ref 来接收  (out外面不需要初始化)//outCustomCall3 call3 = LuaMgr.GetInstance().Global.Get<CustomCall3>("testFun3");int b;bool c;string d;int e;Debug.Log("第一个返回值:" + call3(100, out b, out c, out d, out e));Debug.Log(b + "_" + c + "_" + d + "_" + e);//refCustomCall4 call4 = LuaMgr.GetInstance().Global.Get<CustomCall4>("testFun3");int b1 = 0;bool c1 = true;string d1 = "";int e1 = 0;Debug.Log("第一个返回值:" + call4(200, ref b1, ref c1, ref d1, ref e1));Debug.Log(b1 + "_" + c1 + "_" + d1 + "_" + e1);//XLua    (用于多返回值比较适用, 但是会产生垃圾,所以不是很建议使用)LuaFunction lf3 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFun3");object[] objs = lf3.Call(1000);for (int i = 0; i < objs.Length; i++){Debug.Log("第" + i + "个返回值是: " + objs[i]);}//变长参数CustomCall5 call5 = LuaMgr.GetInstance().Global.Get<CustomCall5>("testFun4");call5("123", 1, 2, 3, 4, 5, 5, 66, 666);//XLuaLuaFunction lf4 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFun4");lf4.Call("456", 5, 6, 7, 99);}// Update is called once per framevoid Update(){}
}

6.映射到List和Dictionary

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Lesson6_CollListDic : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");//同一类型ListList<int> list = LuaMgr.GetInstance().Global.Get<List<int>>("testList");Debug.Log("**********list**************");for (int i = 0; i < list.Count; i++){Debug.Log(list[i]);}//值拷贝(浅拷贝) 不会改变lua中的内容list[0] = 100;List<int> list2 = LuaMgr.GetInstance().Global.Get<List<int>>("testList");Debug.Log(list[0]);//不指定类型的话 就用objectList<object> list3 = LuaMgr.GetInstance().Global.Get<List<object>>("testList2");Debug.Log("*********list object***************");for (int i = 0; i < list3.Count; i++){Debug.Log(list3[i]);}Debug.Log("*********Dictionary***************");Dictionary<string, int> dic = LuaMgr.GetInstance().Global.Get<Dictionary<string, int>>("testDic");foreach (string item in dic.Keys){Debug.Log(item + "_" + dic[item]);}//检测是不是 值拷贝  —— 还是值拷贝dic["1"] = 10000;Dictionary<string, int> dic2 = LuaMgr.GetInstance().Global.Get<Dictionary<string, int>>("testDic");Debug.Log(dic2["1"]);//不指定类型 还是用 objectDebug.Log("*********Dictionary***************");Dictionary<object, object> dic3 = LuaMgr.GetInstance().Global.Get<Dictionary<object, object>>("testDic2");foreach (object item in dic3.Keys){Debug.Log(item + "_" + dic3[item]);}}// Update is called once per framevoid Update(){}
}

7.映射到类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;public class CallLuaClass
{//在这个类中去声明成员变量//名字一定要和 Lua那么的一样//要公共的  (私有和保护的 没办法赋值)//这个自定义中的 变量 可以更多也可以更少//如果变量比 lua中的少 就会忽略它//如果多了 不会赋值 也相当于忽略public int testInt;public bool testBool;//public float testFloat;public string testString;public int i;public UnityAction testFun;public CallLuaInClass testInClass;
}public class CallLuaInClass
{public int testInInt;
}public class Lesson7_CallClass : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");CallLuaClass obj = LuaMgr.GetInstance().Global.Get<CallLuaClass>("testClass");Debug.Log(obj.testInt);Debug.Log(obj.testBool);//Debug.Log(obj.testFloat);Debug.Log(obj.testString);Debug.Log(obj.i);Debug.Log("嵌套里的:" + obj.testInClass.testInInt);obj.testFun();//测试 是否是值拷贝//值拷贝 改变它 不会改变Lua表里的内容obj.testInt = 100;CallLuaClass obj2 = LuaMgr.GetInstance().Global.Get<CallLuaClass>("testClass");Debug.Log(obj2.testInt);}// Update is called once per framevoid Update(){}
}

8.映射到接口

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using XLua;//接口中是不允许有成员变量的 但是可以有属性
//我们可以用属性来接收
//接口和类规则一样 其中的属性多了少了 不影响结果 无非就是忽略
//嵌套几乎和类一样 无非 是要遵循接口的规则
[CSharpCallLua]
public interface ICSharpCallInterface
{int testInt{get;set;}bool testBool{get;set;}//float testFloat//{//    get;//    set;//}string testString{get;set;}UnityAction testFun{get;set;}float testFloat22{get;set;}
}public class Lesson8_CallInterface : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");ICSharpCallInterface obj = LuaMgr.GetInstance().Global.Get<ICSharpCallInterface>("testClass");Debug.Log(obj.testInt);Debug.Log(obj.testBool);Debug.Log("新加的:" + obj.testFloat22);Debug.Log(obj.testString);obj.testFun();//测试 是否 值拷贝//接口拷贝 是引用拷贝 改了值 lua表中的值也变了obj.testInt = 1000;ICSharpCallInterface obj2 = LuaMgr.GetInstance().Global.Get<ICSharpCallInterface>("testClass");Debug.Log(obj2.testInt);  // 1000}// Update is called once per framevoid Update(){}
}

9.映射到LuaTable

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using XLua;public class Lesson9_CallLuaTable : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");//官方不建议使用LuaTable 和 LuaFunction  因为效率低 并且会产生垃圾//引用对象LuaTable table = LuaMgr.GetInstance().Global.Get<LuaTable>("testClass");Debug.Log(table.Get<int>("testInt"));Debug.Log(table.Get<bool>("testBool"));Debug.Log(table.Get<float>("testFloat"));Debug.Log(table.Get<string>("testString"));table.Get<LuaFunction>("testFun").Call();//引用拷贝table.Set("testInt", 55);LuaTable table2 = LuaMgr.GetInstance().Global.Get<LuaTable>("testClass");Debug.Log(table2.Get<int>("testInt"));//用完 table 记得要 清除它 不然会产生垃圾table.Dispose();table2.Dispose();}// Update is called once per framevoid Update(){}
}

10.CSharpCallLua特性什么时候用

Lua调用C#

1.类

print("************Lua 调用 C#类相关知识点************")--lua中使用C#的类非常简单
--固定套路:
--CS.命名空间.类名
--Unity的类 比如 GameObject Transform等等 —— CS.UnityEngine.类名
--CS.UnityEngine.GameObject--通过C#中的类 实例化一个对象 lua中没有new 所以我们直接 类名括号就是实例化对象
--默认调用的 相当于就是无参构造
local obj1 = CS.UnityEngine.GameObject()
local obj1 = CS.UnityEngine.GameObject("Sunset")  --带传参--为了方便使用 并且节约性能 定义全局变量存储 C#中的类
--这样定义 相当于是取了一个别名
GameObject = CS.UnityEngine.GameObject
local obj3 = GameObject("山有木兮")--类中的静态对象 可以直接使用 .来调用
local obj4 = GameObject.Find("Sunset")--得到对象中的成员变量 直接对象 . 即可
print(obj4.transform.position)
Debug = CS.UnityEngine.Debug
Debug.Log(obj4.transform.position)Vector3 = CS.UnityEngine.Vector3
--如果使用对象中的 成员方法 !!! 一定要加 冒号 :
obj4.transform:Translate(Vector3.right)
Debug.Log(obj4.transform.position)--自定义类 使用方法 相同 只是命名空间不同而已
local t = CS.Test1()
t:Speak("说话")local t2 = CS.Sunset.Test2()
t2:Speak("说话")--继承了Mono的类
--继承了Mono的类 是不能直接 new
local obj5 = GameObject("加脚本测试")
--通过GameObject的 AddComponent 添加脚本
--xlua提供了一个重要方法 typeof 可以得到类的Type
--xlua中不支持 无参泛型函数 所以 我们要使用另一个重载
obj5:AddComponent(typeof(CS.LuaCallCSharp))

2.枚举

3.数组、List和Dictionary

print("**********Lua调用C# 数组 相关知识点********")-- 实例化出对象
local obj = CS.Lesson3()--Lua使用C#数组相关知识
--长度 userdata
--C#怎么用 lua就怎么用 不能使用#去获取长度
print(obj.array.Length)--访问元素
print(obj.array[0])--遍历要注意 虽然lua中索引从1开始
--但是数组是C#那边的规则 所以 还是按C#的0开始
--注意最大值 一定要减1
for i=0,obj.array.Length-1 doprint(obj.array[i])
end--Lua中创建一个C#的数组 Lua中表示数组和List可以用比表
--但是若要使用C#中???
--创建C#中的数组 使用 Array类中的静态方法即可
--该方法就是创建一个数组,第一个参数是数组类型,第二个参数是数组大小
local array2 = CS.System.Array.CreateInstance(typeof(CS.System.Int32), 10)
print(array2.Length)
print(array2[0])
print(array2[1])
print(array2)print("**********Lua调用C# list 相关知识点********")
--调用成员方法 用冒号
obj.list:Add(1)
obj.list:Add(2)
obj.list:Add(3)
--长度
print(obj.list.Count)
--遍历
for i = 0,obj.list.Count-1 doprint(obj.list[i])
end
print(obj.list)--在Lua中创建一个List对象
--老版本中
local list2 = CS.System.Collections.Generic["List`1[System.String]"]()
print(list2)
list2:Add("123")
print(list2[0])--新版本 > v2.1.12
--相当于得到一个 List<string> 的一个类别名 需要再实例化
local List_String = CS.System.Collections.Generic.List(CS.System.String)
local list3 = List_String()
list3:Add("555555")
print(list3[0])print("**********Lua调用C# Dictionary 相关知识点********")
--使用和C#一致
obj.dic:Add(1, "123")
print(obj.dic[1])--遍历
for k,v in pairs(obj.dic) doprint(k,v)
end--在Lua中创建一个字典对象
--也分老版本和新版本
--这里只讲解 新版本(老版本可以去了解)
local Dic_String_Vector3 = CS.System.Collections.Generic.Dictionary(CS.System.String, CS.UnityEngine.Vector3)
local dic2 = Dic_String_Vector3()
dic2:Add("123",CS.UnityEngine.Vector3.right)
for k,v in pairs(dic2) doprint(k,v)
end
--在Lua中创建的字典 直接通过键中括号得 是得不到 返回的是nil
print(dic2["123"])
--字典里还有一个方法也能够正常得到值
print(dic2:TryGetValue("123"))  -- 返回两个值 true 值
--如果要通过键获取值 要通过这个固定方法
print(dic2:get_Item("123"))
dic2:set_Item("123", nil)
print(dic2:get_Item("123"))

4.函数(拓展方法)

5.函数(ref 和 out)

print("***********Lua调用C# ref 方法相关知识点***********")Lesson5 = CS.Lesson5local obj = Lesson5()--ref参数 会以多返回值的形式返回给lua
--如果函数存在返回值 那么第一个值 就是该返回值
--之后的返回值 就是ref的结果 从左到右一一对应
--ref参数 需要传入一个默认值 占位置
--a 相当于 函数返回值
--b 第一个ref
--c 第二个ref
local a,b,c = obj:RefFun(1, 0, 0, 1)
print(a)
print(b)
print(c)print("***********Lua调用C# out 方法相关知识点***********")
--out参数 也会以多返回值的形式返回给lua
--如果函数存在返回值 那么第一个值 就是该返回值
--之后的返回值 就是out的结果 从左到右一一对应
--out参数 不需要传占位置的值
local a,b,c = obj:OutFun(20, 30)
print(a)
print(b)
print(c)--混合使用时 综合上面的规则
--ref 需要占位  out不用传
--第一个是函数的返回值 之后 从左到右依次对应ref或者out
local a,b,c = obj:RefOutFun(20, 1)  --ref 的占位值不一定要是0,可以用其他数
print(a)  --300
print(b)  --200
print(c)  --400

6.函数(重载)

print("**********Lua调用C# 重载函数相关知识点**********")Lesson6 = CS.Lesson6
local obj = Lesson6()--虽然Lua自己不支持写重载函数
--但是Lua支持调用C#中的重要函数
print(obj:Calc())
print(obj:Calc(15, 1))--Lua虽然支持调用C#重载函数
--但是因为Lua中的数值类型 只有Number
--对C#中多精度的重载函数支持的不好  会傻傻分不清
--在使用时 可能出现意向不到的问题
print(obj:Calc(10))
print(obj:Calc(10.2))--解决重载函数含糊的问题
--xlua提供了解决方案 通过反射机制
--这种方法只做了解 尽量别用 (因为效率低)
--Type是反射的关键类
--得到指定函数的相关信息
local m1 = typeof(CS.Lesson6):GetMethod("Calc", {typeof(CS.System.Int32)})
local m2 = typeof(CS.Lesson6):GetMethod("Calc", {typeof(CS.System.Single)})--通过xlua提供的一个方法 把它转成lua函数来使用
--一般我们转一次 然后重复来使用
local f1 = xlua.tofunction(m1)
local f2 = xlua.tofunction(m2)
--成员方法  第一个参数传对象
--静态方法  不用传对象
print(f1(obj, 10))
print(f2(obj, 10.2))

7.委托和事件

print("**********Lua调用C# 委托 相关知识点********")local obj = CS.Lesson7()--委托是用来装函数的
--使用C#中的委托 就是用来装lua函数的
local fun = function()print("Lua函数Fun")
endprint("********加函数********")
--Lua中没有复合运算符 不能 +=
--如果第一次往委托中加函数 因为是nil 不能直接+
--所以第一次 要先等 +
obj.del = fun
obj.del = obj.del + fun
--不建议这么写 最好还是 先声明函数再加 (因为这个像匿名函数,后面移除会不好找)
obj.del = obj.del + function()print("临时声明的函数")
end
--委托执行
obj.del()print("********减函数********")
obj.del = obj.del - fun
obj.del = obj.del - fun
obj.del()print("********清空函数********")
--第三个函数没有函数名
--只能清空所有存储的函数
obj.del = nil
--清空后得先 等于
obj.del = fun
--调用
obj.del()print("**********Lua调用C# 事件 相关知识点********")
local fun2 = function()print("事件加的函数")
endprint("********事件加函数********")
--事件加减函数 和 委托非常不一样
--Lua中使用C#事件 加函数
--有点类似使用成员方法 冒号 事件名("+", 函数变量)
obj:eventAction("+", fun2)
--最好也不要这么写
obj:eventAction("+", function()print("事件加的匿名函数")
end)
--调用只能在内部给出方法
obj:DoEvent()print("********事件减函数********")
obj:eventAction("-", fun2)
obj:DoEvent()print("********事件清除********")
--请事件 不能直接设空
--因为在C#中事件是不允许在外部等于和调用的
--obj:eventAction = nil
--但是我们可以在这个事件的类的内部写一个清除的方法出来调用
obj:ClearEvent()
obj:DoEvent()

8.特殊问题(二维数组遍历)

9.特殊问题(null和ni比较)

拓展方法记得加特性

10.特殊问题(让系统类型和Lua能相互访问)

11.协程

print("************Lua调用C# 协程 相关知识点**************")
--xlua提供的一个工具表
--一定是要通过require 调用后 才能用
util = require("xlua.util")--C#中协程启动都是通过继承了Mono的类 通过里面的启动函数StartCoroutineGameObject = CS.UnityEngine.GameObject
WaitForSeconds = CS.UnityEngine.WaitForSeconds--在场景中新建一个空物体 然后挂一个脚本上去 脚本继承momo使用它来开启协程
local obj = GameObject("Coroutine")
local mono = obj:AddComponent(typeof(CS.LuaCallCSharp))--希望用来被开启的协程函数
fun = function()local a = 1while true do--lua中 不能直接使用 C#中的 yield return--那就使用lua中的协程返回coroutine.yield(WaitForSeconds(1)) --后面的每隔一秒打印其实就是我们C#的方法print(a)a = a + 1if a > 10 thenmono:StopCoroutine(b)endend
end--我们不能直接将 lua函数传入到C#开启协程中!!!
--mono:StartCoroutine(fun)
--如果要把lua函数当中协程函数传入
--必须 先调用 xlua.util中的 cs_generator(lua函数)
--它的返回值才是一个协程函数
--关闭的话 我们就先存起它来
b = mono:StartCoroutine(util.cs_generator(fun))

12.泛型函数

print("**************Lua调用C# 泛型函数相关知识点***************")local obj = CS.Lesson12()local child = CS.Lesson12.TestChild()
local father = CS.Lesson12.TestFather()--支持有约束有参数的泛型函数
obj:TestFun1(child, fater)
obj:TestFun1(father, child)--lua中不支持 没有约束的泛型函数
--obj:TestFun2(child)  -- 会报错--lua中不支持 有约束 但是没有参数的泛型函数
--obj:TestFun3()--lua中不支持 非class的约束 (如不支持 接口约束)
--obj:TestFun4()--下面的方法有一定的使用限制
--Mono打包 这种方式支持使用
--il2cpp打包 如果泛型参数是引用类型才可以使用
--il2cpp打包 如果泛型参数是值类型,除非C#那边已经调用过了同类型的泛型参数 lua中才能够被使用--补充知识 让上面 不支持使用的泛型函数 变得能用
--得到通用的函数 
--设置泛型类型再使用
--xlua.get_generic_method(类,"函数名")
local testFun2 = xlua.get_generic_method(CS.Lesson12, "TestFun2")
local testFun2_R = testFun2(CS.System.Int32)
--调用
--成员方法 第一个参数 传调用函数的对象
--静态方法 不用传
testFun2_R(obj, 1)

完结:接xLua背包小实践

相关文章:

热更新解决方案3 —— xLua

概述 xLua框架导入和AB包相关准备 xLua导入 其它的导入 C#调用Lua 1.Lua解析器 using System.Collections; using System.Collections.Generic; using UnityEngine; //引用命名空间 using XLua;public class Lesson1_LuaEnv : MonoBehaviour {// Start is called before the fi…...

【Linux】——权限

文章目录 权限的概念创建与删除普通用户普通用户与root用户的切换权限管理权限设置 文件掩码权限的作用粘滞位 权限的概念 在Linux系统中&#xff0c;存在两种主要用户类型&#xff0c;即超级用户root与普通用户。超级用户拥有极高的权限&#xff0c;可以在 Linux 统下执行几乎…...

elasticsearch 使用enrich processor填充数据

文章目录 使用 POST 请求手动插入用户数据1. 创建 Enrich Policy步骤 1.1: 创建 Enrich Policy步骤 1.2: 执行 Enrich Policy 2. 创建 Ingest Pipeline步骤 2.1: 创建 Ingest Pipeline步骤 2.2: 配置 Enrich Processor 参数 3. 使用 Ingest Pipeline步骤 3.1: 使用 Pipeline 进…...

etcd性能调优

性能指标 决定 etcd 性能的关键因素&#xff0c;包括&#xff1a; 延迟 (latency)&#xff1a;延迟是完成操作的时间。吞吐量 (throughput)&#xff1a;吞吐量是在某个时间期间之内完成操作的总数量。当 etcd 接收并发客户端请求时&#xff0c;通常平均延迟随着总体吞吐量增加…...

docker离线安装、linux 安装docker

之前写过一篇docker的离线安装&#xff0c;现在从头再看繁琐了&#xff0c;服务器换了&#xff0c;既然要重搭一遍就要改进一下了。下面步入正题&#xff1a; 1.下载离线软件包 https://download.docker.com/linux/static/stable/x86_64/docker-20.10.6.tgz 2.下载安装工具包…...

信息安全工程师-选择题考点总结

密码理论知识 基础理论 一个密码系统至少由明文、密文、加密算法、解密算法和密钥五个部分组成,而其安全性是由密钥决定的。 按照密钥特征的不同,密码体制分为:对称密码体制和非对称密码体制。 按照对明文加密方式的不同,密码体制分为:流密码和分组密码。 非对称密码体…...

【C++】四季分类题目分析与讨论

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目说明&#x1f4af;题目代码实现1.我的做法代码示例解析 2. 老师的类C解法代码示例解析 3. 老师的类C解法代码示例解析 4. 老师新增的基于if的解法代码示例解析 &#x…...

mysqlbinglog如何查看进度呢

要查看 MySQL binlog 的进度&#xff0c;通常是指查看 binlog 文件的当前位置&#xff0c;这对于了解复制进度或者进行恢复操作非常重要。以下是一些常用的方法和 SQL 语句来查看 binlog 进度&#xff1a; 查看当前 binlog 文件和位置&#xff1a; SHOW MASTER STATUS;这个命令…...

CSS系列(11)-- 滤镜与混合模式详解

前端技术探索系列&#xff1a;CSS 滤镜与混合模式详解 &#x1f3a8; 致读者&#xff1a;探索视觉效果的艺术 &#x1f44b; 前端开发者们&#xff0c; 今天我们将深入探讨 CSS 滤镜与混合模式&#xff0c;学习如何创建独特的视觉效果。 滤镜效果详解 &#x1f680; 基础滤…...

Cesium进阶教程——自定义图形、外观、绘图基础、现有着色器移植至Cesium、ShadowMapping、视频GIS、模型压平、卷帘

基础必看 WEBGL基础&#xff08;从渲染管线角度解读&#xff09; 参考路线 http://www.xt3d.online/tutorial/further/article.html 自定义图形 https://blog.csdn.net/m0_55049655/article/details/138908327 https://blog.csdn.net/m0_55049655/article/details/140306837 …...

搭建Tomcat(一)---SocketServerSocket

目录 引入1 引入2--socket 流程 Socket&#xff08;应用程序之间的通讯保障&#xff09; 网卡(计算机之间的通讯保障) 端口 端口号 实例 client端 解析 server端 解析 相关方法 问题1&#xff1a;ServerSocket和Socket有什么关系&#xff1f; ServerSocket Soc…...

Sublime Text 64位:前端及全栈开发利器

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;Sublime Text作为一款高效的文本编辑器&#xff0c;在前端网页开发领域受到广泛青睐&#xff0c;特别是其64位版本在处理大型项目和高内存需求的场景下表现出色。编辑器内置Emmet插件&#xff0c;提供代码高亮、…...

CNCF云原生生态版图-分类指南(一)- 观测和分析

CNCF云原生生态版图-分类指南&#xff08;一&#xff09;- 观测和分析 CNCF云原生生态版图-分类指南一、观测和分析&#xff08;Observability and Analysis&#xff09;&#xff08;一&#xff09;可观测性&#xff08;Observablility&#xff09;1. 是什么&#xff1f;2. 解决…...

Ubuntu本地快速搭建web小游戏网站,公网用户远程访问【内网穿透】

文章目录 前言1. 本地环境服务搭建2. 局域网测试访问3. 内网穿透3.1 ubuntu本地安装cpolar内网穿透3.2 创建隧道3.3 测试公网访问4. 配置固定二级子域名4.1 保留一个二级子域名4.2 配置二级子域名4.3 测试访问公网固定二级子域名前言 网:我们通常说的是互联网;站:可以理解成…...

VMware ubuntu12.04怎么设置静态IP联网

记得刚开始学习嵌入式就是从ubuntu12.04的环境开始学习的C语言&#xff0c;当时没有弄清楚怎么设置静态IP联网&#xff0c;现在写一篇文章。 1.首先&#xff0c;关闭ubuntu的网络&#xff1b; 2.电脑使用的是wifi,将VMware桥接到该网卡上&#xff1b; 3.在虚拟机设置里面选择桥…...

Qt WORD/PDF(一)使用 QtPdfium库实现 PDF 预览

文章目录 一、简介二、下载 QtPdfium三、加载 QtPdfium 动态库四、Demo 使用 关于QT Widget 其它文章请点击这里: QT Widget 姊妹篇: Qt WORD/PDF&#xff08;一&#xff09;使用 QtPdfium库实现 PDF 操作 Qt WORD/PDF&#xff08;二&#xff09;使用 QtPdfium库实现…...

UE5 C++ Subsystem 和 多线程

一.Subsystem先做一个简单的介绍&#xff0c;其实可以去看大钊的文章有一篇专门讲这个的。 GamePlay框架基础上的一个增强功能&#xff0c;属于GamePlay架构的范围。Subsystems是一套可以定义自动实例化和释放的类的框架。这个框架允许你从5类里选择一个来定义子类(只能在C定义…...

23.DDD与微服务

学习视频来源&#xff1a;DDD独家秘籍视频合集 https://space.bilibili.com/24690212/channel/collectiondetail?sid1940048&ctype0 文章目录 DDD与微服务的关系1. DDD可以用微服务实现&#xff0c;也可以不用微服务实现2. DDD是微服务拆分的必须参考项之一3. 微服务架构…...

vue3+ant design vue实现日期选择器不展示清除按钮

1、代码&#xff1a;只需设置:allowClear"false"即可 <a-date-pickerv-model:value"value1":disabledDate"disabledDate"change"queryRate":allowClear"false" />const disabledDate (current: Dayjs) > {// 获取…...

Amazon Bedrock与AWS服务的无缝集成,如何打造智能化应用

在AI和大数据飞速发展的今天&#xff0c;Amazon Bedrock作为AWS的一项新兴服务&#xff0c;正逐渐成为开发者和企业拥抱生成式AI的核心工具。那么&#xff0c;Amazon Bedrock与AWS其他服务结合&#xff0c;究竟能够带来哪些强大的应用场景呢&#xff1f;今天九河云就来和大家探…...

Rust之抽空学习系列(四)—— 编程通用概念(下)

Rust之抽空学习系列&#xff08;四&#xff09;—— 编程通用概念&#xff08;下&#xff09; 1、函数 函数用来对功能逻辑进行封装&#xff0c;能够增强复用、提高代码的可读 以下是函数的主要组成部分&#xff1a; 名称参数返回类型函数体 1.1、函数名称 在Rust中&…...

【Apache paimon】-- 集成 hive3.1.3 异常

目录 1、场景再现 Step1:在 hive cli beeline 执行创建 hive paimon 表 Step2:使用 insert into 写入数据 Step3:抛出异常 2、原因分析 Step1:在 yarn resource manager 作业界面查询 hive sql mr job 的 yarn log Step2:搜索job 使用的 zstd jar 版本 Step3:定…...

SpringCloud微服务实战系列:01让SpringCloud项目在你机器上运行起来

目录 项目选型 项目安装-本地运行起来 软件安装&#xff1a; 项目启动&#xff1a; 总结&答疑 项目选型 软件开发&#xff0c;基本上都不会从0开始&#xff0c;一般都是在其他项目或者组件的基础上进行整合优化迭代&#xff0c;站在巨人肩膀上才能看得更远&#xff0c…...

分布式锁【Redis场景分布式锁篇】

文章目录 1.Redis分布式锁2.分布式锁其它方案1.主动轮询型1.MySQL分布式锁2.Redis分布式锁 2.监听回调型1.Etcd2.Zookeeper 总结 1.Redis分布式锁 锁通常用来控制共享资源&#xff0c;比如一个进程内有多个线程竞争一个数据的使用权限&#xff0c;解决方式之一就是加锁。分布式…...

BGP协议

BGP&#xff08;Border Gateway Protocol&#xff0c;边界网关协议&#xff09;是一种用于在不同网络之间传输可达性信息的路由协议。它是互联网上使用的主要协议之一&#xff0c;用于连接不同的自治系统&#xff08;AS&#xff09;&#xff0c;即由单个实体控。边界网关协议_百…...

iframe webview打开外链内嵌video标签导致视频无法全屏展示

iframe webview打开外链内嵌video标签导致视频无法全屏展示 解决方法iframe 添加属性webview 添加属性 解决方法 iframe 添加属性 <iframe style"width: 100%;height: 100vh;" src"http://xxx.xxx........" allowfullscreen"true" w…...

学习日志024--opencv中处理轮廓的函数

目录 前言​​​​​​​ 一、 梯度处理的sobel算子函数 功能 参数 返回值 代码演示 二、梯度处理拉普拉斯算子 功能 参数 返回值 代码演示 三、Canny算子 功能 参数 返回值 代码演示 四、findContours函数与drawContours函数 功能 参数 返回值 代码演示 …...

【从零开始入门unity游戏开发之——C#篇05】转义字符、@处理多行文本或者不使用转义字符、随机数

文章目录 一、转义字符1、什么是转义字符&#xff1f;2、常见的转义字符3、总结 二、使用处理多行文本或者不使用转义字符1、多行字符串2、不使用转义字符 三、随机数1、Random.Next()生成随机整数示例&#xff1a;生成一个随机整数生成指定范围内的随机整数 2、Random.NextSin…...

PHP获取指定日期的下周日至下周六的日期(下周几的日期)

PHP获取指定日期的下周日至下周六的日期&#xff08;下周几的日期&#xff09; 在PHP中&#xff0c;可以使用strtotime()函数来获取指定日期的下周日至下周六的日期。 // 周天 sunday // 周一 monday // 周二 tuesday // 周三 wednesday // 周四 thursday // 周五 friday // …...

超越飞书钉钉:探索高效内部知识库平替方案与应用

在团队协作日益频繁的今天&#xff0c;飞书与钉钉作为两大主流的企业沟通与协作平台&#xff0c;广受企业青睐。然而&#xff0c;随着企业规模的扩大和知识的累积&#xff0c;单纯的沟通与协作已难以满足企业对知识管理与传承的需求。因此&#xff0c;寻找一款能够高效整合内部…...

3D相框案例讲解(详细)

前言 通过现阶段的学习&#xff0c;我们已经掌握了HTML&#xff0c;CSS和JS部分的相关知识点&#xff0c;现在让我们通过一篇案例&#xff0c;来巩固我们近期所学的知识点。 详细视频讲解戳这里 任务一 了解目标案例样式 1.1了解案例 3D相框 1.2 分析案例 首先我们看到一个…...

一、基于langchain使用Qwen搭建金融RAG问答机器人--技术准备

一,LangChain框架介绍 LangChain 框架是一个开源工具&#xff0c;通过为各种 LLM 提供通用接口来简化应用程序的开发流程&#xff0c;帮助开发者自由构建 LLM应用。 LangChain封装了很多组件&#xff0c;通过这些组件的组合可以构建多种类型的RAG应用。开发者可以直接将私有数…...

2024年全球安全光幕装置行业总体规模、主要企业国内外市场占有率及排名

根据研究团队调研统计&#xff0c;2023年全球安全光幕装置市场销售额达到了46亿元&#xff0c;预计2030年将达到70亿元&#xff0c;年复合增长率&#xff08;CAGR&#xff09;为6.4%&#xff08;2024-2030&#xff09;。中国市场在过去几年变化较快&#xff0c;2023年市场规模为…...

uniapp跨端适配—条件编译

在uniapp中&#xff0c;跨端适配是通过条件编译实现的。条件编译允许开发者根据不同的平台&#xff08;如iOS、Android、微信小程序、百度小程序等&#xff09;编写不同的代码。这样可以确保每个平台上的应用都能得到最优的性能和用户体验。 以下是uniapp中条件编译的基本语法…...

HTML、CSS表格的斜表头样式设置title 画对角线

我里面有用到layui框架的影响&#xff0c;实际根据你自己的框架来小调下就可以 效果如下 上代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-wi…...

自动驾驶控制与规划——Project 2: 车辆横向控制

目录 零、任务介绍一、环境配置二、算法三、代码实现四、效果展示 零、任务介绍 补全src/ros-bridge/carla_shenlan_projects/carla_shenlan_stanley_pid_controller/src/stanley_controller.cpp中的TODO部分。 一、环境配置 上一次作业中没有配置docker使用gpu&#xff0c;…...

Docker的初识

目录 1. 容器技术发展史1.1 Jail 时代1.2 云时代1.3 云原生时代1.3.1 Google & Docker 竞争1.3.2 k8s 成为云原生事实标准 2. 虚拟化和容器化的概念2.1 什么是虚拟化、容器化2.2 为什么要虚拟化、容器化&#xff1f;2.3 虚拟化实现方式2.3.1 应用程序执行环境分层2.3.2 虚拟…...

R-Studio Technician,无网络负担地进行远程数据分析和数据恢复任务

对于数据恢复技术人员和技术支持团队来说&#xff0c;时间就是金钱。这不仅包括您在客户机器上花费的时间 - 还包括您往返公司办公室的时间&#xff0c;这可能会带来巨大的不便&#xff0c;特别是如果客户位于其他省市。电话支持通常不适用于需要数小时才能完成的复杂任务&…...

Couchbase的OLAP支持情况

Couchbase 是一个高性能的 NoSQL 数据库&#xff0c;主要用于在线事务处理&#xff08;OLTP&#xff09;场景&#xff0c;但它也提供了一些功能来支持在线分析处理&#xff08;OLAP&#xff09;需求。以下是 Couchbase 对 OLAP 支持的几个方面&#xff1a; 1. N1QL 查询语言 …...

路径规划之启发式算法之十六:和声搜索算法(Harmony Search, HS)

和声搜索算法(Harmony Search, HS)是一种新兴的启发式全局搜索算法,是一种模拟音乐家即兴演奏过程的群体智能优化算法。这种算法由Zong Woo Geem等人在2001年提出,灵感来源于音乐家在寻找和声时的创造性思维过程。HS算法通过模拟音乐家演奏音乐时的选择过程来寻找问题的最优…...

服务器---centos上安装docker并使用docker配置jenkins

要在 Docker 中安装 Jenkins 并进行管理,可以按照以下步骤操作: 1. 安装 Docker 首先,确保你的系统已经安装了 Docker。如果尚未安装,可以使用以下命令进行安装: 在 CentOS 上安装 Docker sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://…...

面试题整理1---正向代理和反向代理的含义及异同

面试题整理1---正向代理和反向代理的含义及异同 1. 正向代理 (Forward Proxy)1.1 正向代理定义&#xff1a;1.2 正向代理的工作流程&#xff1a;1.3 正向代理的应用场景&#xff1a; 2. 反向代理 (Reverse Proxy)2.1 反向代理的定义&#xff1a;2.2 反向代理的工作流程&#xf…...

记录学习《手动学习深度学习》这本书的笔记(五)

这一章是循环神经网络&#xff0c;太难了太难了&#xff0c;有很多卡壳的地方理解了好久&#xff0c;比如隐藏层和隐状态的区别、代码的含义&#xff08;为此专门另写了一篇【笔记】记录对自主实现一个神经网络的步骤的理解&#xff09;、梯度计算相关&#xff08;【笔记】记录…...

鸿蒙调试打包(非正式打包)

文章目录 前言第一步&#xff1a;生成.p12和.csr文件第二步&#xff1a;申请证书的前置步骤第三步&#xff1a;申请证书 前言 HarmonyOS 应用打包后的文件为.app 格式&#xff0c; android 打包后的文件为.apk&#xff0c;IOS 打包后的文件为.apa HarmonyOS通过数字证书&#…...

Python中的容器化服务监控:结合Prometheus和Grafana实现高效监控与可视化

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在现代的DevOps和微服务架构中,容器化技术(如Docker)已成为主流的部署方式。然而,容器环境的动态特性使得服务监控和性能分析变得更加复…...

【大数据】-- 读放大和写放大

目录 一、定义 1. 读放大(Read Amplification) 定义 原因 优化方法 2. 写放大(Write Amplification) 定义 原因 优化方法 对比与联系 二、举例 1. Hadoop(HDFS) 读放大 写放大 2. Flink 读放大 写放大 3. Hive 读放大 写放大 4. Presto 读放大 写放…...

[工具升级问题] 钉钉(linux版)升级带来的小麻烦

本文由Markdown语法编辑器编辑完成。 1. 背景: 今日钉钉又发布了新的升级版本。由于我工作时使用的是Ubuntu 20.04版本&#xff0c;收到的升级推送信息是&#xff0c;可以升级到最新的7.6.25-Release版本。根据钉钉官方给出的历次更新版说明&#xff0c;这个新的版本&#xf…...

Maven学习(Maven项目模块化。模块间“继承“机制。父(工程),子项目(模块)间聚合)

目录 一、Maven项目模块化&#xff1f; &#xff08;1&#xff09;基本介绍。 &#xff08;2&#xff09;汽车模块化生产再聚合组装。 &#xff08;3&#xff09;Maven项目模块化图解。 1、maven_parent。 2、maven_pojo。 3、maven_dao。 4、maven_service。 5、maven_web。 6…...

Opencv之图像添加水印

一、实验原理 在图片处理领域&#xff0c;添加水印是一种常见的操作。通过叠加图像的方式&#xff0c;可以将水印无缝嵌入目标图像的指定位置。其基本原理包括以下步骤&#xff1a; 1、模板输入&#xff08;掩膜生成&#xff09;&#xff1a; 将水印图片转换为灰度图&#xf…...

在线预约陪诊小程序

一、前言 随着社会老龄化加剧以及人们健康意识的提高&#xff0c;就医过程中的陪伴需求日益增长。许多患者在面对复杂的医院环境、繁琐的就医流程时&#xff0c;需要有人协助挂号、候诊、取药等&#xff0c;而家属可能因工作繁忙无法全程陪同。同时&#xff0c;异地就医的患者更…...