【Unity】Lua热重载
写在前面
- 本文讨论的“Lua热重载”是基于他人现成工具和相关博文上展开的,所以这里并不会重复实现一遍工具,主要记录我的理解过程。
Lua热重载
探索
- 偶然在知乎上翻到一篇文章“使用ILRuntime遇到的一些问题”,文章最后提到Lua特有的加载机制(如下图),我第一个念头就是“怎么用Lua做了那么久的热更,我却没想到用Lua来做测试呢!”,如果能在不重新启动Unity的前提下重载Lua脚本,测试效率肯定会大大提升,而我最想提升的就是程序员在写好UI脚本后的测试效率,于是我开始在网上搜索有没有现成工具。
刚开始搜索到的博客们实现重点都差不多,代码如下图:
function reimport(name)
local package = package
package.loaded[name] = nil
package.preload[name] = nil
return require(name)
end
于是我直接用这段代码拿工作项目里的图鉴UI做测试,结果没有成功。我没懂为啥不成功,于是我继续搜资料。以下是我主要参考的3篇资料。
【参考A】
【参考A】它是我找到的第一个示例,作者提供了两个G站链接,一个是作者自己的,另一个是作者参考的,而我先误点开的是参考链接,下载代码后发现运行时直接上while(true)的话Unity会卡死(尽管作者有写sleep),肇事代码如下图:
将肇事代码修好后开始测试,第一次测试,可以正常热重载,放到另一个项目的第二次测试,却不能正常热重载。因为这个没有Unity示例,代码一时半会看不懂,所以我暂时放弃……
后来我也打开看过作者的链接,不过那时我已经找到了【参考B】,所以只是粗略的翻了翻。
【参考B】
【参考B】有Unity示例,有代码讲解!是这3篇参考资料里读起来最轻松的(我在阅读的时候发现【参考A】作者链接的代码其实就是【参考B】的完整版,那里update_func()的内容会更加详细)。
它的Unity示例内容简单来说,就是在C#那边监听文件改动,如有改动,调用Lua那边的hotfix脚本。作者写了两个重载时机:管理者的Update和具体脚本的Reload。重载实现以package.loaded为前提。
以下是我在阅读、测试【参考B】代码时冒出的问题和解答(用“——>”符号标识):
- updated_tables感觉只是更新函数,和记录访问过的table,没看出哪里体现更新table ?——> 其实重点就是“更新函数”。
- 为什么会想到upvalue?——> 我最开始猜想是为了不破坏旧引用,后来测试证实,使用旧引用具体是为了维持其他地方的引用不变,所以不能直接拿新引用直接覆盖旧引用。(不过在测试中,正常重载后依然会显示老代码对应的行号,容易误导)
- 作者提供的代码只能在update函数里改,我想在任意函数里改,咋整?——> 写在作者提供的Reload函数中。
- 我在读作者博客时有一段没读懂(如下图),package.load[filename] 拿到的不是布尔值吗,类的类型哪里体现?filename即对应Lua脚本,不管多少次require,都会指向同一对象,怎么会不是类的实例呢?
——> 这里我的理解出错了。package.load[filename] 拿到的不是布尔值,是filename对应的Lua脚本具体返回值,如果没有写返回值,则require会记返回值是true。
“调用package.load[filename] 获得的是类的类型,并不是类的实例。”,首先,作者用的是云风写的Lua类,在class的代码里(如下图,我截图用的是云风版class,作者用的是自己修改后的BaseClass)能看到返回的是class_type(即“类-类型”),class_type用了new()才能拿到实例。
以作者的PlayerMove.lua为例,在PlayerMove.lua代码末尾,他return的是PlayerMove,所以在require("PlayerMove")时,返回的是PlayerMove类型。
如果作者在PlayerMove.lua代码末尾return的是PlayerMove.New(),则在require("PlayerMove")时,返回的是PlayerMove实例。
【参考C】
KSFramework:它的热重载实现写的很简单,完全没碰Lua那边,只是在C#这边把UI的老引用清了,换成新引用。
接入工作项目
我尝试将【参考B】这个现成的重载工具接入工作项目,过程依然问题多多,以下是遇到问题和解决方法记录:
最开始我在C#这新开了一个LuaState来负责监听Lua脚本变化工作,但不行,会出问题(Unity崩溃;工作项目的一些Lua脚本报错但看代码无问题),所以去掉了新开的LuaState。
- 工作项目中基本UI都是用dofile加载的,而不是require,所以在package.loaded[...]中找不到记录(前面提到的图鉴UI就是用dofile加载的,所以最开始测试失败),这里需要我另写函数来处理,如下:
- 虽然【参考B】用的是Lua脚本变化时自动触发重载,但因为工作项目是Unity2017版本,我在Unity2017上测试时发现自动重载时内容未发生变化,而此时Unity自己正在加载,卡住了一小会;如果是在Unity加载完后再触发重载,此时内容有变化,重载正常。因此我将自动触发改为了手动触发。
- 测试发现【参考B】脚本不让在运行时加新函数,会有断言报错。可以改成“在运行时加新函数”,但我不认为有改的必要。
因为UI在C#那边记录的引用比较多,再加上正常重载Lua脚本后还显示旧行号的问题,所以这个工具我用的不多,研究到此告一段落。
【Unity】Lua热重载的更多相关文章
- lua热重载
热重载,就是不重新开unity让代码的变化直接看出来,一般在开发时候使用 lua中通过require导入的文件,最终都存在package.loaded这个table中.require会判断是否文件已经 ...
- 出售一套Unity + Lua热更新框架代码
出售一套Unity + Lua的客户端框架代码,功能有资源管理.网络通信.配置文件解析.热更新.文件读写.Lua加密揭秘.UI框架.打包工具.编辑器工具等,已经在多个实际项目(已上线)中使用.代码优雅 ...
- KSFramework常见问题:Lua脚本热重载,内存状态数据丢失?
Lua热重载 内存数据在重载后会丢失 KSFramework中,所有的UI Lua脚本是可以重载的.脚本中的一些内存数据,在重载后会丢失,比如: -- 记录一个UI界面被打开了多少次 function ...
- KSFramework:集成U3D热重载框架 - README
KSFramework KEngine + SLua+ Framework = KSFramework KSFramework是一个整合KEngine.SLua的Unity 5开发框架,并为程序.美术 ...
- Unity代码热更新方案 JSBinding + SharpKit 首页
目前Unity的代码更新方案有很多,主要以lua为主. JSBinding + SharpKit 是一种新的技术,他做了两件事情: JSBinding将C#导出到 JavaScript (引擎是 Mo ...
- lua热更框架之XLua
框架介绍 xLua是当下最流行的unity热更方案之一,作者是腾讯的车雄生前辈,自2016年初推出以来,已经在腾讯的多款游戏项目上应用,目前xLua已经开源到了GitHub.xLua最大的特色是不仅支 ...
- unity游戏热更新总结
1.利用反射来做Dll更新 这种方式只支持windows以及安卓这种支持JIT的平台,对于IOS就不适用了,IOS这种Full-AOT的平台不支持生成新的代码,因此这种热更方式很少用到. 2.利用 ...
- webpack使用webpack-dev-middleware进行热重载
新手,刚开始学习webpack,想使用webdevserver,但定制性太差,于是研究了一下使用webpack-dev-middleware进行指定. 根据文档https://www.npmjs.co ...
- .Net 4.X 提前用上 .Net Core 的配置模式以及热重载配置
1. 前言 在提倡微服务及 Serverless 越来越普及的当下,在 .Net Core 之前,.Net 应用的配置模式往往依赖于一个名为 web.config 的 XML 文件,耦合性高,而可扩展 ...
- Node.js + gulp 合并静态页模版,文件更新自动热重载。浏览器可预览
github地址:https://github.com/Liaozhenting/template 使用的是ejs的语法.其实你用什么文件后缀都可以,都是按ejs来解析. 模板文件放在componen ...
随机推荐
- Physics Informed Deep Learning for Flow and Transport in Porous Media
Paper presented at the SPE Reservoir Simulation Conference, On-Demand, October 2021. 这篇论文关注石油储藏模拟问题, ...
- pycharm中运行shell脚本
为了跑一份深度学习工程文件,这份文件夹有好几份子文件夹,子文件夹里有.sh脚本.我以前跟盛哥来跑强化学习的代码时,盛哥教我装了git,所以用git是可以来跑脚本的.费力搞了半天装cygwin来跑,实际 ...
- mount无响应
mount -t xfs /dev/sdb /data 挂载不成功,且命令无任何回显. dmesg 查看到有报错 tailf /var/log/messages -n 100 systemctl da ...
- git通过ssh方式免密克隆代码仓库
git上添加ssh公钥 略过 终端命令行 格式: git clone ssh://[user@]host.xz[:port]/path/to/repo.git/ 栗子: git clone ssh:/ ...
- Linux详解
什么是操作系统?1.操作系统:(Operating System,OS)是计算机系统中的一个系统软件,它们管理和控制计算机系统中的硬件及软件资源,为用户提供一个功能强大.使用方便的和可扩展的工作环境. ...
- 在MyBatis-Plus整合dynamic-datasource @DS失效
因为是事务导致的 解决方案: 1.删除事务 2.使用分布式事务 3.修改事务的传播机制 3.使用DS的本地事务 @DSTransactional 但切记不可和Spring的事务共存 附传播机制 事务传 ...
- Docker安装 Redis Stack(开发适配-提供 Redis Stack 服务器和RedisInsight可视化) (6.2.4-v2版本)
一.使用docker安装(开发适配-提供 Redis Stack 服务器和RedisInsight) (6.2.4-v2版本) 简介 安装命令根据实际部署情况调整 版本地址:官方镜像主页 | 发布版T ...
- Resport 四则运算
使用FormatNumber 即可 [FormatNumber([Total2]/[Total1]*100)]%
- 杭电oj 青年歌手大奖赛_评委会打分
Problem Description 青年歌手大奖赛中,评委会给参赛选手打分.选手得分规则为去掉一个最高分和一个最低分,然后计算平均得分,请编程输出某选手的得分. Input 输入数据有多组,每 ...
- 异步按照同步顺序执行的function
function step1 (callback) { console.log(111111) callback.call() } function step2 (callback ...