Lua热重载
Lua热重载开源库地址:https://github.com/asqbtcupid/lua_hotupdate
只能更新函数逻辑,包括局部函数和全局函数,不能更新数据。
原理
- 首先需要知道的是变动的文件,在Unity中可以通过继承
AssetPostProcessor
类,并重写OnPostProcessAllAssets
函数来监听文件的改变,从而可以得知改变的Lua文件,并更新到hotupdatelist.lua
中去。 - 然后需要得到需要更新的函数,具体来说是旧函数和对应的新函数。对于变动的文件肯定需要重新
require
,但是为了防止改变已经保存在内存中的数据,库中使用了setfenv
来导入更新的lua文件,这样执行新文件之后,所有改变的东西都不会污染现有的_G
,而是会被保存到另一个table:HU.FakeENV
。我们需要的只是其中的函数,那些函数就是接下来需要更新的。对于这些新函数,还需要知道旧函数,也就是FakeENV
中每个新函数对应_G
中的函数(热重载只会替换更新函数逻辑,不能新增函数)。其实很简单,就是从_G
和FakeENV
访问路径相同的函数就当作是对应的。这里的访问路径不仅包括直接取table的value,还包括table的key、metatable、function、function的upvalue(如果牵扯到的又是table,则还要进一步递归进去),总之包含了可以想到的所有访问途径。 - 更新函数,这一步比较简单粗暴,直接按照上一步所说所有的访问途径从
_G
开始遍历HU.Travel_G()
,把所有与旧函数判定相等(==)的函数全都替换成新函数。除了_G
之外,debug.getregistry
也进行了相同的遍历替换操作(这里面保存了C#用到的Lua函数,比如一个Lua函数func1,在LuaFunction
中对应的reference为100,那么就有registry[100]=func1)。
注意
虽说热重载不会更新数据,但是其实可以把函数本身也当成一种数据。按照热重载原理,在更新之后所有引用到旧函数的地方会全部被替换为新函数,也就是各种table里的数据都会发生改变。这也就解释了为什么已经被绑定的回调函数(不论是Lua的还是C#的)也会被更新。