Lua热更新解析

热更新介绍

原理

任何一款手游上线之后,我们都需要进行游戏Bug的修复或者是在遇到节日时发布一些活动,这些都需要进行游戏的更新,而且通常都会涉及到代码的更新。

热更新是指用户直接重启客户端就能实现的客户端资源代码更新操作。游戏热更新会减少游戏中的打包次数,提升程序调试效率,游戏运营时候减少大版本更新次数,可以有效防止用户流失。

lua语言在热更新中会被广泛使用,我们这里采取的是ulua,ulua是unity+lua+cstolua组成的,开发者已经为我们封装成SimpleFramework_UGUI和SimpleFramework_NGUI框架,让开发者在使用的时候更加快捷方便。

要点分析

1.Lua语言

再热更新功能开发过程中,我们需要用到一款新的语言:Lua语言。

Lua和C#对比:C#是编译型语言,Lua是解析型语言

Lua语言不可以单独完成一个项目的开发,Lua语言出现的目的是“嵌入式”,为其他语言开发出来的项目进行功能的扩展和补丁的更新。

2.Lua语言与C#语言交互

Unity项目是使用C#开发的,后续热更新的功能需要使用Lua语言实现。而我们在最开始使用C#开发项目的时候,需要预留和Lua代码的“交互接口”,这就涉及到两门语言的代码相互调用访问。

3.AssetBundle

AssetBundle是Unity内资源的一种打包格式,和电脑上的rar、zip压缩包比较类似,客户端热更新过程中,从服务器上下载下来的资源,都是AssetBundle打包过的资源。

4.ULua和XLua热更新框架

ULua和XLua是两个热更新框架,专门用于Unity客户端项目热更新开发。其实就是两个“资源包”,导入到我们的项目中,在框架的基础之上,完成我们项目需要的热更新逻辑。

Lua热更新的实现

整理一下热更新的思路主要有两点:
1.将模块中旧的函数替换成新的函数,这个新的函数可以放到一个lua文件中,或者以字符串的形式给出。
2.将模块中旧的函数,当前用到的所有上值,(什么是上值,后面有讲到)保存到起来,用于新函数引用,保证新函数作为模块中的一部分能够正确运行。

下面以一个demo为例,这也是抽取 snax 模块中热更新部分:

./main.lua                调用 test.lua,做为运行文件,显示最终运行效果
./test.lua                一个简单模块文件,用于提供热更新的来源
./test_hot.lua            用于更新替换 test 模块中的某些函数,更新文件
./hotfix.lua              实现热更新机制

在这里插入图片描述
通过这幅关系图,可以了解到,test 模块和 test_hot 之间的关系,test_hot 负责更新 test 模块中的某些函数,但更新后的这些函数依然属于 test 模块中的一部分,并没有脱离 test 模块的掌控,而独立出来。
在这里插入图片描述
现在我们看看 test.lua 包含了哪些内容,分别有 一个局部变量 index,两个函数 print_index,show ,函数体分别是圆圈1和2,两个函数都引用到了这个局部变量 index。
假设当前,我们想更新替换掉 print_index 函数,让其 index 加1 操作,并打印 index 值,那么我们可以在 test_hot.lua 文件中这么写,见下图黄色框部分:
在这里插入图片描述
我们希望在 print_index 更新后, index 加 1 后,show 函数获取到的 index 值是 1,即把更新函数也看作是 test.lua 模块中的一部分。而不应该是 index 加 1 后,show 函数获取到的还是原值 0。

假设我们希望更新 print_index 后,再一次更新,把 index 值直接设置为 100,那么它又应该是这样子的,见下图最左侧黄色部分:
在这里插入图片描述

_ENV 和Upvalue

1._ENV 环境变量

在 lua 程序设计一书中有过这样的解释,lua 语言并没有全局变量,所谓的全局变量都是通过某种手段模拟出来的。

Lua 语言是在一个名为 _ENV 的预定义上值(一个外部的局部变量,upvalue)存在的情况下编译所有的代码段的。因此,所有的变量要么绑定到一个名称的局部变量,要么是 _ENV 中的一个字段,而 _ENV 本身是一个局部变量。
例如:
local z = 10
x = 0
y = 1
x = y + z
等价于
local z = 10
_ENV.x = 0
_ENV.y = 1
_ENV.x = _ENV.y + z

x,y 都是不用 local 声明,z 是 local 声明。
所以,我们用到的全局变量其实是保存到 _ENV 变量中。lua 语言在内部维护了一个表来作用全局环境(_G),通常,我们在 load 一个代码段,一个模块时,lua 会用这个表(_G)来初始化 _ENV。如果上面的几行代码是写在一个文件中,那么当 load 调用它时,又会等价于:

-- xxx.lua 文件
local _ENV = the global environment (全局环境)
return function(...)
local z = 10
_ENV.x = 0
_ENV.y = 1
_ENV.x = _ENV.y +z
end

2.上值 upvalue

当一个局部变量被内层的函数中使用的时候, 它被内层函数称作 上值,或是 外部局部变量。引用 Lua 5.3 参考手册
例如:
local x = 10
function hello(a, b)
local c = a + b + x
print(c)
end
那么在这段代码中,hello 函数的上值有 变量 x,_ENV,而我们刚刚讲到,print 没有经过声明,就可以直接使用,那么它肯定是保存于 _ENV 表中,print(c) 等价于 _ENV
  • 6
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值