xLua教程
Unity热更新XLua
Unity热更新XLua 什么是冷更新开发者将测试好的代码,发布到应⽤商店的审核平台,平台⽅会进⾏稳定性及性能测试。
测试成功后,⽤户即可在AppStore看到应⽤的更新信息,⽤户点击应⽤更新后,需要先关闭应⽤,再进⾏更新。
什么是热更新⼴义:⽆需关闭应⽤,不停机状态下修复漏洞,更新资源等,重点是更新逻辑代码。
狭义定义( iOS热更新):⽆需将代码重新打包提交⾄AppStore,即可更新客户端的执⾏代码,即不⽤下载app⽽⾃动更新程序。
现状:苹果禁⽌了C#的部分反射操作,禁⽌JIT(即时编译,程序运⾏时创建并运⾏新代码),不允许逻辑热更新,只允许使⽤AssetBundle进⾏资源热更新。
注意:2017年,苹果更新了热更新政策说明,上线后的项⽬,⼀旦发现使⽤热更新,⼀样会以下架处理为何要热更新缩短⽤户获取新版应⽤的客户端的流程,改善⽤户体验具体到iOS平台的应⽤上,有以下⼏个原因AppStore的审核周期难控制⼿机应⽤更新频繁对于⼤型应⽤,更新成本太⼤终极⽬标不重新下载、不停机状态下完全变换⼀个应⽤的内容每个平台如何做热更新Android,PC(C#)将执⾏代码预编译为AssemblyDLL将代码作为TextAsset打包进AssetBundle运⾏时调⽤AssemblyDLL代码更新相应的AssetBundle即可实现热更新iOS(Lua)苹果官⽅禁⽌iOS下的程序热更新;JIT在iOS下⽆效热更新⽅案:Unity + Lua插件常见的Unity热更新插件sLua:最快的Lua插件toLua:由uLua发展⽽来的,第三代Lua热更新⽅案xLua:特性最先进的Lua插件ILRuntime:纯C#实现的热更新插件xLua的安装将Assets⽬录下所有⽂件拷贝到项⽬中xLua解析器的获得DoString函数执⾏Lua代码Lua代码调⽤C#代码C#加载Lua⽂件根据加载提⽰,发现可以将Lua⽂件放在StreamingAssets⽬录下StreamingAssets被抛弃,所以移动到Resources下(以txt为结尾)⾃定义加载器LuaEnv.AddLoader()接触⼀个新的Lua项⽬时,先要弄懂Lua的加载器规则,只有这样,才能弄懂项⽬的Lua执⾏流程 xLua的单例运⾏环境xLua解析器创建销毁xLua加载器编写xLua中Lua调⽤C#代码为什么? C#实现的系统,因为Lua可以调⽤,所以完全可以换成Lua实现,因为Lua可 以即时更改,即时运⾏,所以游戏的代码逻辑就可以随时修改。
PhpStorm2020+phpstudyV8+XDebug的教程详解
PhpStorm2020+phpstudyV8+XDebug的教程详解WNMP(Windows+Nginx+Mysql+Php)环境安装操作:1、安装phpStudy1.1、下载phpStudy下载地址:/解压后运⾏exe进⾏安装,我的安装⽬录是:D:\phpstudy_pro1.2、配置环境:在桌⾯启动⼩⽪进⾏配置,我的配置如下:⾸页⾯板:启动"WNMP"⽹站⾯板:PHP版本环境⾯板:数据库、PHP运⾏环境2、安装PhpStorm20202.1、下载phpStudy我使⽤的是缺省⽬录进⾏安装,如何激活在这就不详细说了。
2.1、配置PHP版本信息我们点击“File->Settings”菜单进⾏PHP版本配置,使⽤和phpstudy对应的版本PHP7.3.4。
注意:Interpreter默认是没有的,我们需要点击右边的按钮进⾏配置。
3、新建测试⼯程3.1、使⽤PhpStorm新建⼯程"HelloPHP"第⼀步:打开PhpStorm软件,点击创建新项⽬,在输⼊框填写带项⽬存放地址的项⽬名称,完成后点击创建。
3.2、配置⼯程的本地服务我们点击“⼯具/部署/配置”菜单进⾏本地服务配置点击确定后进⾏具体配置:Connection⾯板:配置部署⽬录Mappings⾯板:配置相对⽬录和访问地址配置完之后点击“确定”。
3.3、配置运⾏环境我们点击“运⾏/编辑配置”菜单进⾏运⾏环境配置选择⼯程,单击右键->New->PHP File输⼊⽂件的名称,点击确定增加PHP⽂件在新建的⽂件⾥输⼊代码:<?phpecho "Hello PHP!"; // 在页⾯上输出“Hello PHP!”phpinfo(); // 调⽤PHP内置的函数显⽰PHP的基本信息3.5、部署⼯程在菜单中选择Tools->Deployment->Upload to localhost上传⼯程。
腾讯开源手游热更新方案,Unity3D下的Lua编程
腾讯开源⼿游热更新⽅案,Unity3D下的Lua编程作者|车雄⽣编辑|⽊环腾讯最近在开源⽅⾯的动作不断:先是微信跨平台基础组件Mars宣布开源,腾讯⼿游⼜于近期开源了Unity3D下Lua编程解决⽅案——xLua。
xLua,何⽅神圣?有哪些技术细节可以说道说道?写在前⾯xLua是Unity3D下Lua编程解决⽅案,⾃2016年初推⼴以来,已经应⽤于⼗多款腾讯⾃研游戏,因其良好性能、易⽤性、扩展性⽽⼴受好评。
现在腾讯已经将xLua开源到GitHub。
2016年12⽉末,xLua刚刚实现新的突破:全平台⽀持⽤Lua修复C#代码bug。
⽬前Unity下的Lua热更新⽅案⼤多都是要求要热更新的部分⼀开始就要⽤Lua语⾔实现,不⾜之处在于:1. 接⼊成本⾼,有的项⽬已经⽤C#写完了,这时要接⼊需要把需要热更的地⽅⽤Lua重新实现;2. 即使⼀开始就接⼊了,也存在同时⽤两种语⾔开发难度较⼤的问题;3. Lua性能不如C#;xLua热补丁技术⽀持在运⾏时把⼀个C#实现(函数,操作符,属性,事件,或者整个类)替换成Lua实现,意味着你可以:1. 平时⽤C#开发;2. 运⾏也是C#,性能秒杀Lua;3. 有bug的地⽅下发个Lua脚本fix了,下次整体更新时可以把Lua的实现换回正确的C#实现,更新时甚⾄可以做到不重启游戏;这个新特性iOS,Android,Windows,Mac都测试通过了,⽬前在做⼀些易⽤性优化。
那么,腾讯开源的xLua究竟是怎样的技术?它是为何如此设计的?更令⼈关⼼的是,xLua的性能如何?带着这些问题,InfoQ对其作者进⾏了采访并将内容整理成⽂。
技术背景腾讯⾃研⼿游,就我了解的项⽬来说,⼤多数游戏引擎都是Unity3D,少数⽤coco2d。
xLua这个插件具体⽤到了哪些游戏中?虽说xLua是2015年3⽉就完成了第⼀个版本,但由于当时项⽬组热更的意识并没有很普遍,需求不是很强烈,xLua的开发资源都调到更紧急的项⽬了。
XLua增加删除第三方lua库
What&WhyXLua目前内置的扩展库:1、针对luajit的64位整数支持;2、函数调用耗时以及内存泄漏定位工具;3、用于支持ZeroBraneStudio的luasocket库;4、tdr 4 lua;随着使用项目的增加以及项目使用的深入程度,仅有这几个扩展已经没法满足项目组了,而由于各个项目对扩展差异化比较大,以及手机平台对安装包大小的敏感,XLua是无法通过预集成去满足这些需求,这也是这篇教程的由来。
这篇教程,将以lua-rapidjson为例,一步步的讲述怎么往xLua添加c/c++扩展,当然,会添加了,自然删除也就会了,项目组可以自行删除不需要用到的预集成扩展。
How分三步1、修改build文件、工程设置,把要集成的扩展编译到XLua Plugin里头;2、调用xLua的C# API,使得扩展可以被按需(在lua代码里头require的时候)加载;3、可选,如果你的扩展里头需要用到64位整数,你可以通过XLua的64位扩展库来实现和C#的配合。
一、添加扩展&编译准备工作把xLua的C源码包解压到你Unity工程的Assets同级目录下。
下载lua-rapidjson代码,按你的习惯放置。
本教程是把rapidjson头文件放到$UnityProj\build\lua-rapidjson\include目录下,而扩展的源码rapidjson.cpp放到$UnityProj\build\lua-rapidjson\source目录下(注:$UnityProj指的是你工程的目录)在CMakeLists.txt加入扩展xLua的各平台Plugins编译使用cmake编译,好处是所有平台的编译都写在一个makefile,大部分编译处理逻辑是跨平台的。
xLua配套的CMakeLists.txt为第三方扩展提供了扩展点(都是list):THIRDPART_INC:第三方扩展的头文件搜索路径。
xlua framework 基础用法
xlua framework 基础用法xlua framework 是一种面向游戏开发的 Lua 扩展框架,它提供了一些额外的功能和优化,以提高 Lua 在游戏开发中的性能和灵活性。
基本用法如下所示:1. 导入 xlua 框架:```luarequire("xlua")```2. 定义一个类:```lualocal MyClass = {}MyClass.__index = MyClassfunction MyClass.new()local self = setmetatable({}, MyClass)return selfendfunction MyClass:MyMethod()print("Hello from MyClass!")end```3. 创建对象并调用方法:```lualocal myObject = MyClass.new()myObject:MyMethod()```4. 继承和重写方法:```lualocal DerivedClass = {}setmetatable(DerivedClass, { __index = MyClass }) DerivedClass.__index = DerivedClassfunction DerivedClass.new()local self = setmetatable({}, DerivedClass)return selfendfunction DerivedClass:MyMethod()print("Hello from DerivedClass!")end```5. 调用基类方法:```lualocal derivedObject = DerivedClass.new()derivedObject:MyMethod() -- 输出 "Hello from DerivedClass!" getmetatable(derivedObject).__index.MyMethod(derivedObject) -- 输出 "Hello from MyClass!"```这仅仅是 xlua framework 的基础用法,该框架还提供了很多其他的功能和工具,如自动绑定 C# 类、导出 Unity3D 引擎的接口等,你可以根据具体需求来进一步学习和使用。
Unity使用xLua遇到的坑
Unity使⽤xLua遇到的坑在我们使⽤xLua作为Unity中lua集成的解决⽅案时,遇到了⼀个问题,就是当我们使⽤在lua中把UI中的某个控件绑定相应的事件(如按钮的onClick事件),xLua绑定这个事件是⽤委托实现的,具体代码可以查看xLua的代码。
⽽在程序退出的时候xLua会检查对应的委托有没有被正确的释放掉,如果没有释放掉的话就会抛出异常。
代码如表所⽰:1public virtual void Dispose(bool dispose)2 {3#if THREAD_SAFE || HOTFIX_ENABLE4lock (luaEnvLock)5 {6#endif7if (disposed) return;8 Tick();910if (!translator.AllDelegateBridgeReleased())11 {12throw new InvalidOperationException("try to dispose a LuaEnv with C# callback!");13 }1415 LuaAPI.lua_close(L);1617 ObjectTranslatorPool.Instance.Remove(L);18 translator = null;1920 rawL = IntPtr.Zero;2122 disposed = true;23#if THREAD_SAFE || HOTFIX_ENABLE24 }25#endif26 }这说明我们并没有把对应的委托给释放掉。
所以我们需要确保在程序退出之前所有的委托要正确地释放掉。
⽅案⼤体如下,每⼀个UI都对应⼀个实例,这样在绑定控件的时候创建⼀个匿名函数,这个函数⽤于控件把这个控件绑定的事件清除掉,同时把这个匿名函数放到⼀个数组⾥⾯去,在这个UI销毁的时候调⽤⼀个函数(⽐如我们叫做Destroy),这个函数的作⽤就是负责⼀些清理⼯作,其中就包括遍历前⾯提到的匿名函数的数组并挨个调⽤。
UnityVSCodeXLua断点调试
UnityVSCodeXLua断点调试去官网下个相对较新的版本,我这里是使用的2023.2.6f1,证书选择个人版。
IDE安装个人习惯使用VSCode,去官网下个新版就行。
为了保证能对C#代码进行断点调试,我们还需要给IDE装上这个C#和DebuggerForUnity的插件。
编写C#代码并断点调试新建一个HelloWorld.csCtrl+Shift+P呼出面板按F5进入调试模式,选择当前正在运行的Unity程序再回到Unity工程将HelloWorld.cs挂载到当前场景内,点击运行代码热更方案我选择的是腾讯的XLua,虽然没怎么深入了解过,但市面上已经有很多商业游戏对其进行过了验证,要满足我们的需求那自然是绰绰有余。
1.需要将Assets文件夹内的东西拷进Unity工程目录下的Assets文件夹内。
(当然如果你有目录洁癖也可以删掉XLua文件夹下的Doc、Examples、Tutorial)2.用c#执行一个Lua脚本。
新建一个c#脚本,挂载到当前Unity场景内,脚本内容如下:using XLua; using System.IO; void Start( { // 启动lua管理器 LuaEnv _l uaEnv = new LuaEnv(; // 重写lua内的require函数回调,方便自定义载入路径 _luaEnv.AddLoader(CustomLoader); // 启动一个脚本载体 LuaTable _scriptEnv = _luaEnv.NewTable(; // 为该脚本添加XLua提供的全局变量及函数 LuaTable meta = _luaEnv.NewTable(; meta.Set("__index", _luaEnv.Globa l); _scriptEnv.SetMetaTable(meta); meta.Dispose(; _scriptEnv.Set("self", this); // 执行该脚本 var _luaScript = LoadLuaFile("HelloWorld"); _luaE nv.DoString(_luaScript, "HelloWorld", _scriptEnv); // 取到Lua脚本内的指定名称函数并运行 Action _luaFunction; _scriptEnv.Get("MyFunction", out _luaFunction); _luaFunction(; // 最后当你不再需要的时候,记得使用.Dispose(销毁脚本载体及管理器 }/// <summary> /// 自定义载入回调 /// </summary> /// <param name="f ilepath"></param> /// <returns></returns> byte[] CustomLoader(ref string fil epath) { filepath = filepath.Replace(".", "/"); return LoadLuaFile(filepat h); }print("Hello World") function MyFunction( print("This is MyFunction") end最后回到Unity运行场景,正常情况下这时控制台就会打印出你的"Hello World"和"This is MyFunction"了。
xlua 热更异步async方法
xlua 热更异步async方法在使用xlua进行热更新时,异步async方法可以帮助我们在热更新过程中处理异步操作,提高程序的并发性能和响应速度。
在xlua中,我们可以使用C#的async和await关键字来实现异步操作。
下面我将从多个角度来介绍xlua中热更异步async方法的相关内容。
首先,xlua是一个针对Unity3D引擎的Lua绑定库,它允许我们使用Lua语言来编写Unity3D游戏的逻辑部分,同时也支持在Lua中调用C#代码。
在xlua中,我们可以通过异步async方法来实现热更新过程中的异步操作,比如网络请求、文件读写等。
在xlua中使用异步async方法,我们可以在C#中定义一个返回Task或Task<T>类型的异步方法,然后在Lua中通过xlua提供的语法来调用这些异步方法。
在C#中,我们可以使用async关键字来定义异步方法,使用await关键字来等待异步操作的完成。
在Lua中,我们可以通过xlua.async来调用C#中的异步方法,并使用lua表达式来处理异步操作的结果。
另外,在热更新过程中,我们可能会遇到一些需要异步处理的情况,比如下载资源、解压文件等。
使用异步async方法可以帮助我们在热更新过程中更加灵活地处理这些异步操作,提高程序的并发性能和用户体验。
总之,xlua中的热更异步async方法可以帮助我们在热更新过程中处理异步操作,提高程序的并发性能和响应速度。
通过使用C#的async和await关键字,以及xlua提供的语法,我们可以更加灵活地处理热更新过程中的异步操作,从而提升游戏的性能和用户体验。
希望这些信息能够对你有所帮助。
xlua重复利用协程函数
xlua重复利用协程函数如何在Lua编程语言中使用协程函数实现重复利用功能?协程函数是一种可以被挂起和恢复的特殊函数。
在Lua中,我们可以使用xlua库来实现协程功能。
协程函数可以让我们在代码执行的不同点之间切换,以此实现重复利用的功能。
在本文中,我们将探讨如何使用xlua库来实现重复利用协程函数。
我们将按照以下步骤进行:第一步:安装xlua库在开始之前,我们需要先安装xlua库。
可以在Lua的官方网站上找到相关的安装包和文档。
第二步:导入xlua库在我们的代码中,首先需要导入xlua库。
可以使用require函数来导入。
lualocal xlua = require("xlua")第三步:定义协程函数我们需要定义一个协程函数,用于实现重复利用的功能。
协程函数是一个普通的Lua函数,但是在函数内部可以使用一些特殊的函数来控制协程的执行流程。
在本文中,我们将定义一个名为repeatCoroutine的协程函数,它会重复执行一些代码块。
我们使用了xlua库提供的特殊函数coroutine.yield来实现协程的暂停和恢复。
lualocal function repeatCoroutine()while true doprint("Hello, World!")xlua.coroutine.yield()endend在上面的代码中,我们使用了一个无限循环来表示代码块的重复执行。
在每次循环中,我们打印了"Hello, World!"并使用xlua.coroutine.yield函数来暂停协程的执行。
第四步:创建协程对象在我们的代码中,我们需要创建一个协程对象,以便在需要的时候启动协程执行。
lualocal repeatCoroutineObj = xlua.coroutine.create(repeatCoroutine)在上面的代码中,我们使用xlua.coroutine.create函数来创建一个协程对象。
热更新框架设计之Xlua基础视频课程课件PPT模板
托映射lua中的Funct
4
3-11C#CallLua_委托与
5
Action映射lua的F
3-12C#CallLua_复杂委托通
过配置文件映射lua中
6
202x
感谢聆听
03
第3章c#调用lua的各种方式
第3章c#调用lua的各种方式
3-1C#CallLua_调用lua
1
全局变量(A)
3-2C#CallLua_调用lua
全局变量(B)
2
3-3C#CallLua_使用class
3
映射得到lua中表
3-4C#CallLua_interface
映射lua简单
4
3-5C#CallLua_interface
202x
热更新框架设计之xlua基础 视频课程
演讲人
2 0 2 x - 11 - 11
目录
第1章热更框架整体讲 解与xlua热更新简介 第2章lua文件的加载方 式 第3章c#调用lua的各 种方式
01
第1章热更框架整体讲解与xlua热更 新简介
第1章热更框架整体讲 解与xlua热更新简介
1-1热更新框架整体技术揭秘热更 新框架整体技术揭秘 1-2xlua基础课程概述xlua基础 课程概述 1-3xlua插件简介 1-4配置环境编写helloworld 1-2Xlua基础课程概述Xlua基础 课程概述 1-3Xlua插件简介
02
第2章lua文件的加载方式Βιβλιοθήκη 第2章lua文件的 加载方式
2-1lua文件的普通加载方式 2-2使用require加载lua文件 2-3自定义路径加载lua文件(a) 2-4自定义路径加载lua文件(b) 2-2使用Require加载lua文件 2-3自定义路径加载lua文件(A) 2-4自定义路径加载lua文件(B)
XLua教程
xLua教程Lua文件加载一、执行字符串最基本是直接用LuaEnv.DoString执行一个字符串,当然,字符串得符合Lua语法比如:luaenv.DoString("print('hello world')")完整代码见XLua\Tutorial\LoadLuaScript\ByString目录但这种方式并不建议,更建议下面介绍这种方法。
二、加载Lua文件用lua的require函数即可比如:DoString("require 'byfile'")完整代码见XLua\Tutorial\LoadLuaScript\ByFile目录require实际上是调一个个的loader去加载,有一个成功就不再往下尝试,全失败则报文件找不到。
目前xLua除了原生的loader外,还添加了从Resource加载的loader,需要注意的是因为Resource只支持有限的后缀,放Resources下的lua文件得加上txt后缀(见附带的例子)。
建议的加载Lua脚本方式是:整个程序就一个DoString("require 'main'"),然后在main.lua加载其它脚本(类似lua脚本的命令行执行:lua main.lua)。
有童鞋会问:要是我的Lua文件是下载回来的,或者某个自定义的文件格式里头解压出来,或者需要解密等等,怎么办?问得好,xLua的自定义Loader可以满足这些需求。
三、自定义Loader在xLua加自定义loader是很简单的,只涉及到一个接口:public delegate byte[] CustomLoader(ref string filepath);public void LuaEnv.AddLoader(CustomLoader loader)通过AddLoader可以注册个回调,该回调参数是字符串,lua代码里头调用require时,参数将会透传给回调,回调中就可以根据这个参数去加载指定文件,如果需要支持调试,需要把filepath修改为真实路径传出。
wxlua教程
Wxlua 教程2013-3-4Wxlua是lua for windows 自带的比较强大界面库,当然自带的还有iup,iup 虽然用起来非常方便,但是功能不够齐全。
如果你对iup有兴趣,可以下载我的iup简单介绍。
Wxlua是wxwidgets封装的,所以熟悉wxwidgets的话。
Wxlua更本不需要学习。
Wxlua英文文档貌似只有一篇api参考,中文文档基本没有,不过到是有不少例子,但是都好像比较难懂,最长的还有几千行的,谁敢看啊,所以学习起来是非常艰难的。
其实在我写这篇文档时候,我也还是个菜鸟。
那么这篇文档献给那些比我还菜的菜鸟把。
好了,我们开始把。
第一章窗口首先新建一个文本文档改名为“1.wlua”,注意后缀是wlua,因为使用wlua运行起来不会显示那个烦人的黑色命令窗口。
然后右键单击选择edit script,然后就可以开始写代码了。
这两步估计没人不会把。
那么写wx程序我们必须包含他的包进来,所以一般程序开头都会写require (x)首先我们学习创建一个简单的窗口。
window=wx.wxFrame(wx.NULL,wx.wxID_ANY,"First window")上面这句就是创建一个对话框。
第一个参数为窗口的父节点。
这里我们填null,因为他不需要父节点。
那为什么要填父节点呢,做过相关工作的人应该不陌生。
简单说是因为指定父节点后,我们的程序才能找到这个控件(就是一个窗口或者一个按钮等),对父节点的操作也会对子节点影响,比如移动父节点的位置,显示和隐藏等。
不知道这样解释对不对。
第二个参数是他的id,我们这里填的是任意id。
那为什么又要填id呢。
因为我们可以用一个唯一的id来标识我们定义的控件。
在我们给他绑定事件的时候方便。
不过一直用任意id都可以。
第三个参数为窗口名字。
当然这个函数还有其他的一些参数。
那我这里就不介绍了。
那么,创建了这个窗口还没有显示出来我们应该调用显示函数window:Show()接下来就是每个一句进入循环状态。
UnityXLua官方教程学习
UnityXLua官⽅教程学习⼀、Lua ⽂件加载1. 执⾏字符串1using UnityEngine;2using XLua;34public class ByString : MonoBehaviour {5 LuaEnv luaenv = null;6// Use this for initialization7void Start () {8 luaenv = new LuaEnv();9// 执⾏代码块,输出 hello world10 luaenv.DoString("print('hello world')");11 }1213// Update is called once per frame14void Update () {15if (luaenv != null)16 {17// 清楚 Lua 未⼿动释放的 LuaBase 对象18 luaenv.Tick();19 }20 }2122void OnDestroy()23 {24// 销毁25 luaenv.Dispose();26 }27 } 其中 Dostring 函数返回值即为代码块⾥ return 语句的返回值。
2. 加载 Lua ⽂件1 luaenv = new LuaEnv();2// 加载 byfile Lua ⽂件3 luaenv.DoString("require 'byfile'"); 其中 Lua ⽂件代码为:print('hello world') 需要注意的是因为 Resource 只⽀持有限的后缀,放 Resources 下 lua ⽂件得加上 txt 后缀,如:byfile.lua.txt。
3. ⾃定义 Loader1void Start()2 {3 luaenv = new LuaEnv();4// ⾃定义 loader5 luaenv.AddLoader((ref string filename) => {6// 若要加载 InMemory7if (filename == "InMemory")8 {9string script = "return {ccc = 9999}";10// 将字符串转换成byte[]11return System.Text.Encoding.UTF8.GetBytes(script);12 }13return null;14 });15// 执⾏代码块,访问table中的常量ccc16 luaenv.DoString("print('c=', require('InMemory').ccc)");17 } 通过 Addloader 可以注册个回调,该回调参数是字符串,返回⼀个 byte 数组。
XLua(热更新)的基础使用
XLua(热更新)的基础使⽤
在官⽅下在xlua框架,将Asset⾥⾯的两个⽂件夹,Plugins和XLua拖到⼯程⽬录⾥,这样就完成对xlua的导⼊
接下来先从xlua的⼀些简单语法开始
⾸先是这个Lua虚拟机类,官⽅建议全局只有⼀个,因为消耗性能
上⾯的代码会直接从lua⾥输出这段字符
那么我们如何使⽤xLua来获得⼀个lua脚本呢,下⾯就来演⽰⼀下,
先新建个lua脚本,格式为⽂件名+.lua+.txt,然后放在 Resources⽂件夹下⾯
lua 脚本只输出⼀句话,那么我们可以使⽤"require "关键字来找到lua 脚本,后⾯只要加上脚本名
然后来讲下c#如何调⽤lua⾥的变量,在这之前,需要先来修改下之前的lua脚本
⾥⾯定义了三种变量和⼀个⽅法,现在回到C# 中开始写代码来获取
很简单,基本就是利⽤luaEnv.Global.Get<T>来取得变量,函数取得就是使⽤LuaFunction myName 下⾯来输出这些从lua⾥获取到的数据
这样就可以运⾏后看到控制台输出的值
好了,前⾯的都是简单的C#调⽤lua的数据,那现在来讲讲如何从lua中来调⽤C#的类和⽅法
⾸先为了⽅便,就直接在脚本前⾯加上这⼏句lua代码
就是在在调⽤C#类命名空间前要加上"CS",这样就可以调⽤C#的函数,下⾯来调⽤这些脚本执⾏
成功输出了C#类⾥的数据,也创建了个新的空物体,并给定名字。
XLua的配置
xLua的配置xLua所有的配置都支持三种方式:打标签;静态列表;动态列表。
打标签xLua用白名单来指明生成哪些代码,而白名单通过attribute来配置,比如你想从lua调用c#的某个类,希望生成适配代码,你可以为这个类型打一个LuaCallCSharp标签:[LuaCallCSharp]public class A{}该方式方便,但在il2cpp下会增加不少的代码量,不建议使用。
静态列表有时我们无法直接给一个类型打标签,比如系统api,没源码的库,或者实例化的泛化类型,这时你可以在一个静态类里声明一个静态字段,该字段的类型除BlackList和AdditionalProperties之外只要实现了IEnumerable<Type>就可以了(这两个例外后面具体会说),然后为这字段加上标签:[LuaCallCSharp]public static List<Type> mymodule_lua_call_cs_list = new List<Type>(){typeof(GameObject),typeof(Dictionary<string, int>),};这个字段需要放到一个静态类里头,建议放到Editor目录。
动态列表声明一个静态属性,打上相应的标签即可。
[Hotfix]public static List<Type> by_property{get{return (from type in Assembly.GetExecutingAssembly().GetTypes()where space == "XXXX"select type).ToList();}}Getter是代码,你可以实现很多效果,比如按名字空间配置,按程序集配置等等。
这个属性需要放到一个静态类里头,建议放到Editor目录。
XLua.LuaCallCSharp一个C#类型加了这个配置,xLua会生成这个类型的适配代码(包括构造该类型实例,访问其成员属性、方法,静态属性、方法),否则将会尝试用性能较低的反射方式来访问。
深入理解xLua热更新原理
深⼊理解xLua热更新原理热更新简介热更新是指在不需要重新编译打包游戏的情况下,在线更新游戏中的⼀些⾮核⼼代码和资源,⽐如活动运营和打补丁。
热更新分为资源热更新和代码热更新两种,代码热更新实际上也是把代码当成资源的⼀种热更新,但通常所说的热更新⼀般是指代码热更新。
资源热更新主要通过AssetBundle来实现,在Unity编辑器内为游戏中所⽤到的资源指定AB包的名称和后缀,然后进⾏打包并上传服务器,待游戏运⾏时动态加载服务器上的AB资源包。
代码热更新主要包括Lua热更新、ILRuntime热更新和C#直接反射热更新等。
由于ILRuntime热更新还不成熟可能存在⼀些坑,⽽C#直接反射热更新⼜不⽀持IOS平台,因此⽬前⼤多采⽤更成熟的、没有平台限制的Lua热更新⽅案。
为什么需要热更新⼀般情况下,游戏开发并测试完后就要提交应⽤商店审核,其中苹果商店审核周期最长,审核通过后才能上线发布,这时玩家才能下载安装游戏。
在如今快节奏的⼿游时代,游戏的⽣命周期⼤幅缩短⽽且更新还很频繁,如果每次游戏更新都要重新编译游戏打包,然后等待审核发布,最后⽤户再下载安装游戏,那玩家的耐性早没了。
⽽且游戏安装包还不能太⼤,不然玩家还没等到游戏下载安装好就失去兴趣了。
正确的⽅式是将游戏中⼀些⾮核⼼的资源打包并上传服务器,等游戏下载安装好实际运⾏时才在线动态加载资源,从⽽减少游戏安装包的⼤⼩。
因此,我们急需⼀种不需要重新编译打包就能在线更新游戏中的⼀些⾮核⼼代码和资源,⽽这种⽅式就是热更新。
热更新分为资源热更新和代码热更新,资源热更新主要是指将游戏中⼀些资源打包成AB包,并上传服务器,等游戏运⾏时才从服务器上加载资源。
通过这种⽅式可以减少游戏安装包的⼤⼩,减少⽤户下载游戏的时间。
其次,可以通过这种⽅式动态加载游戏中的资源,⽐如节假⽇有活动运营时,可以直接在线更新游戏中的场景,不需要重新发布游戏和重新下载安装游戏,进⽽提⾼玩家的游戏体验。
toLua与Xlua使用方法总结
toLua与Xlua使⽤⽅法总结两者都是常见的基于Unity的热更需求开发出来成熟⽅案。
实现原理是在Unity启动后加载⼀个lua虚拟机。
解释lua脚本。
再通过各种⽅法⽀持C# <> lua 层的互相调⽤。
委托。
反射。
传值传址调⽤。
本处只作为初学者对⽐⼀下双⽅在上⼿和使⽤时候的⼀些异同。
以两种⽅法实现的跳⼀跳⼩游戏为例。
⼀ lua配置和exaple⽰例1. tolua2 xlua⼆ lua Wrap⽂件⽣成⽅法1 tolua 根据配置⽂件CustomSetting 指定相关的输出⽬录需要注册委托的类。
事件。
类型等2 xlua 3种⽅式进⾏配置。
1) 使⽤标签[CSharpCallLua] / [LuaCallCSharp] ⾃动识别对应的类和⽅法。
2) 静态配置⽂件统⼀配置3) 动态配置三 lua启动环境和C#调⽤lua1 tolua 全局统⼀的LuaClient。
直接加载lua⽂件.使⽤*.lua⽂件public class LuaManager : MonoBehaviour {private static LuaManager _instance;public static LuaManager Instance{get{return _instance;}}private LuaClient _luaClient;public LuaClient LuaClient{get{return _luaClient;}}// Use this for initializationvoid Awake () {_instance = this;DontDestroyOnLoad(this.gameObject);_luaClient = this.gameObject.AddComponent<LuaClient>();}}//使⽤DoFile调⽤lua,使⽤CallFunc调⽤lua函数LuaManager.Instance.LuaClient.luaState.DoFile("Login.lua");LuaManager.Instance.LuaClient.CallFunc("Login.Awake", this.gameObject);2 xlua 也是初始化1个luaenv后。
Unity热更新04-XLua调用C#-06-Lua调用C#重载方法
Unity热更新04-XLua调用C#-06-Lua调用C#重载方法Unity热更新04-XLua调⽤C#-06-Lua调⽤C#重载⽤法print("*********Lua调⽤C# 重载函数相关知识点***********") local obj = CS.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))。
Vscode+Unity断点调试三部曲(一):xlua环境搭建
Vscode+Unity断点调试三部曲(⼀):xlua环境搭建断点调试三部曲(⼀):xlua环境搭建Unity新建⼯程,⼯程名不可以是中⽂,版本⽆所谓下载Xlua插件,版本⽆所谓下载Vscode,本教程⽤的是1.44.2版本,版本过低会不兼容emmylua这个插件开始搭建环境HOTFIX_ENABLE新增的Hotfix Inject In Editor,在该教程中其实没⽤,当C#的类被打上[XLua.Hotfix]标签,并且修改了该类的时候,才需要⽤该功能,意为标签注⼊在该教程中,我们只需要⽤,⽣成代码,第⼀次⽤xlua的功能才需要点击⼀下,作⽤类似关联xlua⼯具开始测试⼀个Test_C.cs⽂件,随便挂载到场景中⼀个Test_L.lua⽂件,放在Asset/LuaScripts⽬录下运⾏得到输出结果就是成功了《Test_C.cs》using System.IO;using UnityEngine;using XLua;public class Test_C : MonoBehaviour {void Start (){LuaStart();}LuaFunction func;LuaEnv env;//启动lua虚拟机并加载lua⽂件void LuaStart(){Debug.Log("启动lua");float t = Time.realtimeSinceStartup;//⽤于计算lua虚拟机耗时env = new LuaEnv();//启动lua虚拟机env.AddLoader(CustomLoader);//AddLoader()修改默认路径,参数是路径env.DoString(@"require 'Test_L'");//加载"Test_L.lua"⽂件func = env.Global.Get<LuaFunction>("OnStart");//获取到OnStart⽅法func.Call(gameObject);//调⽤OnStart⽅法,传⼊参数Debug.Log("lua虚拟机加载完毕耗时:" + (Time.realtimeSinceStartup - t) + " s");}//修改lua⽂件的默认路径private static byte[] CustomLoader(ref string filename){filename = "LuaScripts/" + filename.Replace('.', '/');filename = "Assets/" + filename + ".lua";return File.ReadAllBytes(filename);}void OnApplicationQuit(){env.Dispose();//关闭虚拟机}}《Test_L.lua》function OnStart(gObj)print("测试OnStart函数执⾏")end。
Xlua对c#的vector3等结构体的优化
Xlua对c#的vector3等结构体的优化⽬录:参考⽂章::⼀、lua如何操作Vector3,中间做了什么操作?1.获取Vector3对象由于Vector3的⽅法、属性都是成员⽅法、属性(如x、y、z、Slerp),那么调⽤这些⽅法前需要先获取Vector3对应的对象。
⽐如Vector3()新建、transform.position获取等。
以transform.position为例:_g_get_position⽅法创建了⼀个CSharpStruct类型的ud,并把x,y,z存在这个ud⾥。
这个ud的元表指向Vector3的obj_meta,通过这个元表可以访问Vector3Wrap注册的所有⽅法、属性,进⽽间接访问到Vector3。
ud ={["fake_id"] = -1["len"] = 12 //存储3个float值的⼤⼩,的对应xyz,float是4字节32位。
["data"][0] = x["data"][1] = y["data"][0] = z["__index"] = obj_meta}static int _g_get_position(RealStatePtr L){try {ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);UnityEngine.Transform gen_to_be_invoked = (UnityEngine.Transform)translator.FastGetCSObj(L, 1);translator.PushUnityEngineVector3(L, gen_to_be_invoked.position);} catch(System.Exception gen_e) {return LuaAPI.luaL_error(L, "c# exception:" + gen_e);}return1;}public void PushUnityEngineVector3(RealStatePtr L, UnityEngine.Vector3 val){if (UnityEngineVector3_TypeID == -1){bool is_first;UnityEngineVector3_TypeID = getTypeId(L, typeof(UnityEngine.Vector3), out is_first);}//创建⼀个⼤⼩为(12+4+4)字节的userdata,元表Vector3的元表IntPtr buff = LuaAPI.xlua_pushstruct(L, 12, UnityEngineVector3_TypeID);if (!CopyByValue.Pack(buff, 0, val)) //把vector3拆成3个float传⼊cc,在c的结构体buff存储数据{throw new Exception("pack fail fail for UnityEngine.Vector3 ,value="+val);}}xlua.c⾥的接⼝:LUA_API void *xlua_pushstruct(lua_State *L, unsigned int size, int meta_ref) {CSharpStruct *css = (CSharpStruct *)lua_newuserdata(L, size + sizeof(int) + sizeof(unsigned int));css->fake_id = -1;css->len = size;lua_rawgeti(L, LUA_REGISTRYINDEX, meta_ref);lua_setmetatable(L, -2);return css;}LUALIB_API int xlua_pack_float3(void *p, int offset, float f1, float f2, float f3) {CSharpStruct *css = (CSharpStruct *)p;if (css->fake_id != -1 || css->len < offset + sizeof(float) * 3) {return0;} else {float *pos = (float *)(&(css->data[0]) + offset);pos[0] = f1;pos[1] = f2;pos[2] = f3;return1;}}2.设置transform.position代码如下:主要是UnPack⽅法调⽤xlua的xlua_unpack_float3⽅法,从上⾯的ud结构⾥取到x,y,c的值压栈并赋值给UnPack的x,y,z参数,再由UnPack组装⼀个新的Vevtor3返回给_s_set_position进⾏赋值。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
教程
文件加载
一、执行字符串
最基本是直接用执行一个字符串,当然,字符串得符合语法
比如:("(' ')")
完整代码见\\\目录
但这种方式并不建议,更建议下面介绍这种方法。
二、加载文件
用的函数即可
比如:(" ''")
完整代码见\\\目录
实际上是调一个个的去加载,有一个成功就不再往下尝试,全失败则报文件找不到。
目前除了原生的外,还添加了从加载的,需要注意的是因为只支持有限的后缀,放下的文件得加上后缀(见附带的例子)。
建议的加载脚本方式是:整个程序就一个(" ''"),然后在加载其它脚本(类似脚本的命令行执行:)。
有童鞋会问:要是我的文件是下载回来的,或者某个自定义的文件格式里头解压出来,或者需要解密等等,怎么办?问得好,的自定义可以满足这些需求。
三、自定义
在加自定义是很简单的,只涉及到一个接口:
[] ( );
( )
通过可以注册个回调,该回调参数是字符串,代码里头调用时,参数将会透传给回调,回调中就可以根据这个参数去加载指定文件,如果需要支持调试,需要把修改为真实路径传出。
该回调返回值是一个数组,如果为空表示该找不到,否则则为文件的内容。
有了这个就简单了,用的?没问题。
写个调用的接口读文件内容即可。
文件已经加密?没问题,自己写读取文件解密后返回即可。
完整示例见\\\
访问
这里指的是主动发起对数据结构的访问。
本章涉及到的例子都可以在\\下找到。
一、获取一个全局基本数据类型
访问就可以了,上面有个模版方法,可指定返回的类型。
<>("")
<>("")
<>("")
二、访问一个全局的
也是用上面的方法,那类型要指定成啥呢?
、映射到普通或
定义一个,有对应于的字段的属性,而且有无参数构造函数即可,比如对于{ , }可以定义一个包含;的。
这种方式下会帮你一个实例,并把对应的字段赋值过去。
的属性可以多于或者少于的属性。
可以嵌套其它复杂类型。
要注意的是,这个过程是值拷贝,如果比较复杂代价会比较大。
而且修改的字段值不会同步到,反过来也不会。
这个功能可以通过把类型加到生成降低开销,详细可参见配置介绍文档。
那有没有引用方式的映射呢?有,下面这个就是:
、映射到一个
这种方式依赖于生成代码(如果没生成代码会抛异常),代码生成器会生成这个的实例,如果一个属性,生成代码会对应的字段,如果属性也会设置对应的字段。
甚至可以通过的方法访问的函数。
、更轻量级的方式:映射到<>,<>
不想定义或者的话,可以考虑用这个,前提下和的类型都是一致的。
、另外一种方式:映射到类
这种方式好处是不需要生成代码,但也有一些问题,比如慢,比方式要慢一个数量级,
比如没有类型检查。
三、访问一个全局的
仍然是用方法,不同的是类型映射。
、映射到
这种是建议的方式,性能好很多,而且类型安全。
缺点是要生成代码(如果没生成代码会抛异常)。
要怎样声明呢?
对于的每个参数就声明一个输入类型的参数。
多返回值要怎么处理?从左往右映射到的输出参数,输出参数包括返回值,参数,参数。
参数、返回值类型支持哪些呢?都支持,各种复杂类型,,修饰的,甚至可以返回另外一个。
的使用就更简单了,直接像个函数那样用就可以了。
、映射到
这种方式的优缺点刚好和第一种相反。
使用也简单,上有个变参的函数,可以传任意类型,任意个数的参数,返回值是的数组,对应于的多返回值。
四、使用建议
、访问全局数据,特别是以及,代价比较大,建议尽量少做,比如在初始化时把要调用的获取一次(映射到)后,保存下来,后续直接调用该即可。
也类似。
、如果测的实现的部分都以和的方式提供,使用方可以完全和解耦:由一个专门的模块负责的初始化以及、的映射,然后把这些和设置到要用到它们的地方。
调用
本章节涉及到的实例均在\\下
对象
你在这样一个对象:
();
对应到是这样:
()
基本类似,除了:
1、里头没有关键字;
2、所有相关的都放到下,包括构造函数,静态成员属性、方法;
如果有多个构造函数呢?放心,支持重载,比如你要调用的带一个参数的构造函数,这么写:
('')
访问静态属性,方法
读静态属性
写静态属性
调用静态方法
('')
小技巧:如果需要经常访问的类,可以先用局部变量引用后访问,除了减少敲代码的时间,还能提高性能:
('')
访问成员属性,方法
读成员属性
写成员属性
调用成员方法
注意:调用成员方法,第一个参数需要传该对象,建议用冒号语法糖,如下
()
父类属性,方法
支持(通过派生类)访问基类的静态属性,静态方法,(通过派生类实例)访问基类的成员属性,成员方法
参数的输入输出属性(,)
调用测的参数处理规则:的普通参数算一个输入形参,修饰的算一个输入形参,不算,
然后从左往右对应调用测的实参列表;
调用测的返回值处理规则:函数的返回值(如果有的话)算一个返回值,算一个返回值,算一个返回值,然后从左往右对应的多返回值。
重载方法
直接通过不同的参数类型进行重载函数的访问,例如:
()
('')
将分别访问整数参数的和字符串参数的。
注意:只一定程度上支持重载函数的调用,因为的类型远远不如丰富,存在一对多的情况,比如的,,都对应于的,上面的例子中如果有这些重载参数,第一行将无法区分开来,只能调用到其中一个(生成代码中排前面的那个)
操作符
支持的操作符有:,,*,,,一元,<,<,,[]
参数带默认值的方法
和调用有默认值参数的函数一样,如果所给的实参少于形参,则会用默认值补上。
可变参数方法
对于的如下方法:
( , [] )
可以在里头这样调用:
(, '', '')
使用
在里定义了,里就能直接使用。
泛化(模版)方法
不直接支持,可以通过功能进行封装后调用。
枚举类型
枚举值就像枚举类型下的静态属性一样。
()
上面的函数参数是类型的
另外,如果枚举类加入到生成代码的话,枚举类将支持方法,可以实现从一个整数或者字符串到枚举值的转换,例如:
()
('')
使用(调用,,)
的调用:和调用普通函数一样
操作符:对应的操作符,把两个调用串成一个调用链,右操作数可以是同类型的或者是函数。
操作符:和相反,把一个从调用链中移除。
:属性可以用一个来赋值。
比如里头有个事件定义是这样: ;
增加事件回调
('', )
移除事件回调
('', )
位整数支持
版本位整数(,)映射到原生的未整数,而版本,相当于的标准,本身不支持位,做了个位支持的扩展库,的和都将映射到:
1、支持在里头进行位的运算,比较,打印
2、支持和的运算,比较
3、要注意的是,在扩展库中,实际上只有,也会先强转成再传递到,而对的一些运算,比较,我们采取和一样的支持方式,提供一组,详情请看文档。
复杂类型和的自动转换
对于一个有无参构造函数的复杂类型,在侧可以直接用一个来代替,该对应复杂类型的字段有相应字段即可,支持函数参数传递,属性赋值等,例如:
下结构体(也支持)定义如下:
{
;
}
{
;
;
}
某个类有成员函数如下:
( )
在可以这么调用
({ { }, })
获取类型(相当于的)
比如要获取类的信息,可以这样
()
“强”转
没类型,所以不会有强类型语言的“强转”,但有个有点像的东西:告诉要用指定的生成代码去调用一个对象,这在什么情况下能用到呢?有的时候第三方库对外暴露的是一个或者抽象类,实现类是隐藏的,这样我们无法对实现类进行代码生成。
该实现类将会被识别为未生成代码而用反射来访问,如果这个调用是很频繁的话还是很影响性能的,这时我们就可以把这个或者抽象类加到生成代码,然后指定用该生成代码来访问:
(, ())
上面就是指定用的生成代码来访问对象。