【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 ...
随机推荐
- iptables(一)基础概念、filter表常用语法规则
iptables简介 netfilter/iptables(简称为iptables)组成Linux平台下的包过滤防火墙,与大多数的Linux软件一样,这个包过滤防火墙是免费的,它可以代替昂贵的商业防火 ...
- MySQL 5.7升级8.0过程(详解)
记一次MySQL 5.7升级8.0的详细过程,聊聊我的思路,希望可以帮助大家. 以一个例子为切入点 一.升级背景 为什么要升级到MySQL8.0?大概多久进行一次? 大家可以参考下图记录的各个版本的发 ...
- vuex状态管理器
vuex核心概念 // vuex中一共有五个状态 State Getter Mutation Action Module import Vue from 'vue' import Vuex from ...
- MSSQL Always Encrypted 加密
载自:https://zhuanlan.zhihu.com/p/63674006 文档资源:https://docs.microsoft.com/zh-CN/sql/relational-databa ...
- VUE+elementUI 分页请求回显问题解决方案
一直专注写后台的本人,之前新产品回显问题,一直没处理,这对实施配置系统,会产生很大影响 由于写页面的同事要离职,一直在游泳,只能自己上手去干了.本人对 vue 和elementUI 处于一知半解,所以 ...
- 部分jdk网盘链接
链接:https://pan.baidu.com/s/1Nw84qVRL3Buarh2LY1lWEg 提取码:6q2z 含 6u45 7u80 8u202 11.0.X 的win及linux版 没有网 ...
- nginx文件上传模块 nginx_upload_module
1.编译安装nginx wget https://github.com/fdintino/nginx-upload-module/archive/refs/heads/master.zip PS:原先 ...
- 5.docker安装redis
下载redis镜像 不讲那么细了,可以参考docker安装mysql的介绍 docker pull redis 不加冒号和版本表示下载最新版本的 镜像下载完后可以数据 docker images 命令 ...
- .NET在单台Windows2008下百万TCP连接测试
测试客户端: 客户端程序建立TCP连接,发送一条几个字节的数据. 虚拟机8台,PC机8台,服务器1台. 设置MaxUserPort=60000,有一台机没有设置约在1.5万左右.最后因为差一点到100 ...
- Coursera Programming Languages, Part C 华盛顿大学 Week 2
week 2 我们采用一种新的视角来对比 FP 与 OOP,即将问题分解 (decompose) 与实现 (implement) 的方式 OOP Versus Functional Decomposi ...