XLua運行時熱更新原理與實現


前言

感謝提供思路兩個博客主以下是博客地址:
https://gameinstitute.qq.com/community/detail/120538

https://www.jianshu.com/p/7b8ae23ecd81


基本知識(熱更新原理)

我們在require一個Lua文件的時候是將Lua文件加載到package.loaded[modelname]中。當我們加載模塊的時候,會先判斷是否在package.loaded中已存在,若存在則返回改模塊,不存在纔會加載(loadfile),防止重複加載。

package.loaded是一個Table,其中包含了全局表_G、默認加載的模塊(string, debug, package, io, os, table, math, coroutine)和用戶加載的模塊


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

第一種加載方式
將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

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章