名牌网站设计的图片,安徽网站建设推广,可以访问违规网站的浏览器,植物提取网站做的比较好的厂家上篇链接#xff1a;【Lua热更新】上篇 文章目录 三、xLua热更新#x1f4d6;1.概述#x1f4da;︎2.导入xLua框架#x1f516;3. C#调用Lua3.1Lua解析器3.2Lua文件夹的重定向3.3Lua解析器管理器3.4全局变量获取3.5全局函数获取3.6映射到List和Dictionary3.7映射到类3.8映…上篇链接【Lua热更新】上篇 文章目录 三、xLua热更新1.概述︎2.导入xLua框架3. C#调用Lua3.1Lua解析器3.2Lua文件夹的重定向3.3Lua解析器管理器3.4全局变量获取3.5全局函数获取3.6映射到List和Dictionary3.7映射到类3.8映射到接口3.9映射到LuaTable 4.Lua调用C#5.xLua热补丁 三、xLua热更新
1.概述
C#代码和Resoureces文件夹不能实现热更新所以需要使用Lua通过AB包来进行更新脚本 ︎2.导入xLua框架
1.获得xLua包GitHub地址Tencent/xLua: xLua is a lua programming solution for C#
2.导入文件夹 增加了xLua编辑栏导入成功
3.点击Generate Code生成相关代码 4.导入AssetBundles-Browser
GitHub地址Unity-Technologies/ AssetBundles -Browser
如果有报错删除文件中的报错的Test文件即可
3. C#调用Lua
3.1Lua解析器
Lua解析器让我们在Unity中执行Lua
简述一下原理就是Lua是一种解释型语言代码在运行时才被解释器一行行动态翻译和执行先由Lua编译器编译为字节码然后交给Lua虚拟机执行将Lua虚拟机源代码整合给Unity使用实现之间的交互
// 创建一个解析器
LuaEnv luaEnv new LuaEnv();
// 使用Lua解析器执行Lua语言
luaEnv.DoString(print(First Lua));
// Lua垃圾回收手动释放对象
luaEnv.Tick();
// 销毁Lua解析器
luaEnv.Dispose();Lua默认调用Resources文件夹下的Lua脚本
执行以下代码会发现脚本报错没有找到脚本原因是因为.lua不是Unity中的文件格式所以我们需要给.lua在添加一个.txt后缀才能查找到这个查找函数的源码估计是通过Resourece.Load加载所以查找不到Lua文件
luaEnv.DoString(require(FistTest));❓存在的问题从Resources文件夹下读取无法进行热更新其次每个文件都要手动添加.txt后缀十分麻烦所以后续需要进行文件夹的重定向和自动
3.2Lua文件夹的重定向
通过AddLoader方法进行重定向进行自定义加载Lua文件规则
void Start()
{luaEnv.AddLoader(MyCustomLoader);luaEnv.DoString(require(FistTest));
}private byte[] MyCustomLoader(ref string path)
{string newPath Application.dataPath /Lua/ path .lua;if (File.Exists(newPath))return File.ReadAllBytes(newPath);elseDebug.Log(重定向失败 path);return null;
}我们看一下AddLoader源码
传入一个委托添加到 List 列表中在我们使用require(文件名)时如果在列表中按顺序查找该文件那么最后将在Resoureces文件夹中查找 ❓存在问题最终我们需要在AB包中进行加载
3.3Lua解析器管理器
通过实现Lua解析器管理器保证解析器的唯一性
️LuaMgr管理器源码
public class LuaMgr : BaseManagerLuaMgr
{private const string LUA_PATH Lua;private LuaEnv luaEnv;public LuaTable Global {get luaEnv.Global;} // 获得_G表// 初始化解析器public void Init(){if (luaEnv ! null) return;luaEnv new LuaEnv();luaEnv.AddLoader(MyCustomLoader); // 后缀.lua时日常开发重定向到的位置luaEnv.AddLoader(MyCustomABLoader); // 后缀.txt使用AB包时重定向到的位置}// 重定向加载AB包中的Lua脚本private byte[] MyCustomABLoader(ref string path){TextAsset txtLua ABMgr.GetInstance().LoadResTextAsset(LUA_PATH, path .lua);if (txtLua null){Debug.LogError(在AB包中重定向失败);return null;}return txtLua.bytes;}private byte[] MyCustomLoader(ref string path){string newPath Application.dataPath / LUA_PATH / path .lua;if (File.Exists(newPath)){return File.ReadAllBytes(newPath);}else{Debug.LogError(重定向失败 path);}return null;}// 执行lua语言public void DoString(string filename){if (luaEnv null){Debug.LogError(解析器未初始化);return;}luaEnv.DoString(string.Format(require({0}), filename));}// 释放垃圾public void Tick(){if (luaEnv null){Debug.LogError(解析器未初始化);return;}luaEnv.Tick();}// 销毁解析器public void Dispose(){luaEnv.Dispose();luaEnv null;}
}️BaseManager 源码
//1.C#中 泛型的知识
//2.设计模式中 单例模式的知识
public class BaseManagerT where T:new()
{private static T instance;public static T GetInstance(){if (instance null)instance new T();return instance;}
}❓现在只实现了重定向文件夹并没有实现重定向AB包加载接下来继续完成将Lua脚本放在AB包中通过AB包加载脚本。需要注意的是AB包加载文本后缀不能使用.Lua所以在打包时需要将后缀改为.txt不过这一步后续将改成自动的
我们将后缀暂时手动的修改后缀为.txt进行进行打包如果打包过程中存在报错XLua → Clear Generated Code即可 打包成功后刷新界面 重定向加载AB包
这里建议实际开发中仍然使用.Lua后缀那么将重定向读取普通文件夹进行热更新时在修改为.txt后缀重定向到AB包文件夹
// 重定向加载AB包中的Lua脚本
private byte[] MyCustomABLoader(ref string path)
{string newPath Application.streamingAssetsPath / LUA_PATH;AssetBundle ab AssetBundle.LoadFromFile(newPath); // 加载AB包TextAsset tx ab.LoadAssetTextAsset(path .lua); // 加载Lua文件return tx.bytes;
} 3.4全局变量获取
️Main.Lua源码
print( Main )
require(FirstTest) -- 在Unity中已经重定向️FirstTest.Lua 源码
print( First Test )
myNumber 1
myFloat 1.2
myBool true
myString OvO️Unity中代码
无法直接获得local本地变量因为不在_G表中
LuaMgr.GetInstance().Init();
LuaMgr.GetInstance().DoString(Main);// Get
int myNumber LuaMgr.GetInstance().Global.Getint(myNumber);
float myFloat LuaMgr.GetInstance().Global.Getfloat(myFloat);
bool myBool LuaMgr.GetInstance().Global.Getbool(myBool);
string myString LuaMgr.GetInstance().Global.Getstring(myString);// Set
LuaMgr.GetInstance().Global.Set(myNumber, 99);
myNumber LuaMgr.GetInstance().Global.Getint(myNumber);3.5全局函数获取
️FirstTest.Lua 源码
myFun1 function ()print(这是一个无参无返回的函数)
endmyFun2 function (x)print(这是一个有参有返回的函数)return x x
endmyFun3 function ()print(这是一个多返回值的函数)return 99, apple, 1.2f
endmyFun4 function (x, ...)print(这是一个变长参数的函数)arg {...}for k, v in pairs(arg) doprint(k, v)end
end无参数无返回函数获取
// Unity自带委托
UnityAction ua1 LuaMgr.GetInstance().Global.GetUnityAction(myFun1);
ua1.Invoke();
// C#委托
Action ac LuaMgr.GetInstance().Global.GetAction(myFun1);
// xLua提供不建议使用
LuaFunction lf LuaMgr.GetInstance().Global.GetLuaFunction(myFun1);
lf.Call();有参数有返回函数获取
定义一个委托需要使用特性否则Lua无法识别XLua → Generate Code在编译器重新生成一下代码否则也会报错
[CSharpCallLua]
public delegate int MyFunc2(int x);调用函数
MyFunc2 ua2 LuaMgr.GetInstance().Global.GetmyFunc2(myFun2);
int x ua2.Invoke(2);
print(返回值是 x);或者使用C#封装的委托如果报错就XLua → Generate Code
Funcint, int ua2 LuaMgr.GetInstance().Global.GetFuncint, int(myFun2);
int x ua2.Invoke(2);
print(返回值是 x);多返回值函数获取
// 第一个返回值即委托返回值
// 之后的返回值使用out或者ref
[CSharpCallLua]
public delegate int MyFun3(int x, out string fruit, out float value);调用
MyFun3 fc3 LuaMgr.GetInstance().Global.GetMyFun3(myFun3);
string fruit;
float value;
int a fc3.Invoke(12, out fruit, out value);或者使用xLua自带的获取方法
LuaFunction lf3 LuaMgr.GetInstance().Global.GetLuaFunction(myFun3);
object[] ojb lf3.Call(100);多返回值函数获取
// 如果变长参数每个类型都不确定传入Object
[CSharpCallLua]
public delegate void MyFun4(string a, params int[] args);3.6映射到List和Dictionary
️FirstTest.Lua 源码
testList {1, 2, 3, 4}
testDic {[a] 1,[b] 2,[c] 3
}获取
LuaMgr.GetInstance().Init();
LuaMgr.GetInstance().DoLuaFile(Main);Listint testList LuaMgr.GetInstance().Global.GetListint(testList);
Dictionarystring, int testDic LuaMgr.GetInstance().Global.GetDictionarystring, int(testDic);3.7映射到类
️FirstTest.Lua 源码
testClass {name 咪咪,age 1,eat function ()print(吃猫粮)end
}C#中声明该类成员名称必须和lua中一致类名可以不需要一致成员必须是公共的
// 少于lua中的变量则获取不到多余lua中的变量则不会赋值并不会报错
public class TestClass
{public string name;public int age;public UnityAction eat;
}3.8映射到接口
声明接口接口中不允许声明成员变量所以使用成员属性来接收
接口拷贝是引用拷贝在C#中修改值Lua中也会被修改
[CSharpCallLua] // 需要特性
public interface MyInterface
{public string name { get; set; }public int age { get; set; }public UnityAction eat{ get; set; }
}获取
MyInterface myInterface LuaMgr.GetInstance().Global.GetMyInterface(TestClass);3.9映射到LuaTable
官方不建议使用LuaTable和LuaFunction会有垃圾占用LuaTable需要手动销毁否则会一致占用内存
LuaTable table LuaMgr.GetInstance().Global.GetLuaTable(TestClass);
// 获得
string name table.Getstring(name);
int age table.Getint(age);
UnityAction ac table.GetUnityAction(eat);// 修改
table.Set(age, 55);
// 释放table垃圾
table.Dispose();4.Lua调用C#
5.xLua热补丁