XLua运行时热更新原理与实现

Lua热更新原理与实现

  • 前言
  • 基本知识
  • 最基本的热更新的方式(不可用)
  • __G
  • 完整热更新的方法
  • Xlua热更新方案

前言

感谢提供思路两个博客主以下是博客地址:
https://gameinstitute.qq.com/community/detail/120538
https://www.jianshu.com/p/7b8ae23ecd81

基本知识

我们在require一个Lua文件的时候是将Lua文件加载到package.loaded[modelname]中。当我们加载模块的时候会先从package.loaded中读取,如果文件不存在才会Load文件。

最基本的热更新的方式(不可用)

  • 第一种加载方式
    将package.loaded[modelname]的值置为nil,强制重新加载:
function reload_module(module_name)
   package.loaded[modulename] = nil
   require(modulename)
end

在上面的操作中我们直接将模块赋值为空,然后重新加载。在这样的过程中虽然我们能够重新加载model了,但是其他引用了该的地方是无法更新的,所以我们则需要找到所有引用了该文件的模块。

__G

_G是一个变量而不是一个函数,它掌控了整个全局环境,我们需要找到引用了该模块的其他模块也可以在此处找到
它的结构可能会如下

_G
├── string: 
|    ├── sub: function: 006AEB70
|    ├── upper: function: 006AEBB8
|    ├── len: function: 006AE290
|    ├── gfind: function: 006AE170
|    ├── rep: function: 006AE3F8
|    ├── find: function: 006ADFC0
|    ├── match: function: 006AE368
|    ├── char: function: 006ADEA0
|    ├── dump: function: 006ADF30
|    ├── gmatch: function: 006AE170
|    ├── reverse: function: 006AE440
|    ├── byte: function: 006ADE10
|    ├── format: function: 006AE050
|    ├── gsub: function: 006AE200
|    └── lower: function: 006AE2D8
├── xpcall: function: 006AA630
├── package: 
|    ├── preload: 
|    |    └── { }
|    ├── loadlib: function: 006AAD80
|    ├── loaded: 
|    |    └── { }
|    ├── loaders: 
|    |    ├── 1] function: 006AAEA0
|    |    ├── 2] function: 006AAEE8
|    |    ├── 4] function: 006AAF78
|    |    └── 3] function: 006AAF30
...
  • _G保存了lua所用的所有全局函数和全局变量,初始情况是只包含lua程序库的函数和变量。
  • lua程序中定义的全局函数和变量会自动加入到_G中,而局部函数和变量不会这样做。
  • 但是我们可以把局部函数使用键值对的方式保存在_G中,这样我们就可以通过_G和名字来访问原来的局部函数了

完整热更新的方法

我们的做法是要加载新模块,然后再把新模块里的东西塞给老模块,这样其他引用的地方就能引用到新的模块了

function reload_module(module_name)
   local old_module = _G[module_name]	--获取老模块
   package.loaded[module_name] = nil	--赋值为空
   require (module_name)				--加载新模块
   local new_module = _G[module_name]   --获取新模块
   for k, v in pairs(new_module) do     --循环新模块中的所有属性方法等内容
       old_module[k] = v					--把心模块的改变都塞给老模块
   end
   package.loaded[module_name] = old_module	--最后我们再把老模块塞回来。那么引用老模块的其他模块引用的东西也就改变了
end

Xlua热更新方案

按照上面的步骤其实任然无法做到Xlua运行时热更新。可能是跟XLua自身的机制有关,我们是无法直接替换方法,必须先将方法设置为空,然后再进行替换才可(此过程曲折波多,就不解释了)。
我们的__G也可以直接使用require获取到模块

function reload_module(module_name)
   local old_module = require (module_name)	--获取老模块
   package.loaded[module_name] = nil	--赋值为空
   require (module_name)				--加载新模块
   local new_module = require (module_name)   --获取新模块
   for k, v in pairs(new_module) do     --循环新模块中的所有属性方法等内容
  		 old_module[k] = nil					--把心模块的改变都塞给老模块
       old_module[k] = v					--把心模块的改变都塞给老模块
   end
   package.loaded[module_name] = old_module	--最后我们再把老模块塞回来。那么引用老模块的其他模块引用的东西也就改变了
end

你可能感兴趣的:(Unity优化,热更新,Xlua,Unity,Lua)