1.介紹
使用腳本開發游戲業務邏輯其中一個好處就是代碼可線上熱更,不停機修復bug。而熱更代碼的寫法與需要被熱更的文件的代碼又有着密切的關系,本文介紹一種熱更方法。
2.熱更原理
Lua提供一個叫require的函數,實現文件的加載,require的作用可查看雲風大大的參考手冊說明 http://cloudwu.github.io/lua53doc/manual.html#pdf-require
要熱更一個已經被加載(require)過的模塊,要做兩件事件.
1. 將package.loaded[filename] = nil, 將模塊置空.
2. 重新調用require,require(filename).
如果要熱更的模塊里面所用到的都是全局變量,那么只需要這樣寫:
global_var = global_var
ok,新的模塊內容就會重新被加載進內存了,而且全局變量也成功保留了熱更前的值。
然而每個文件里面只定義全局變量,會破壞模塊的可讀性,試想一下,定義了一個類,但它並沒有成員變量,用到的變量全是全局變量,這是一種怎樣的感受。
所以我們要換一種寫法,模塊既可以有自己的變量,又可以被熱更。
3. 實現
形如一個類既有成員變量,又有成員函數,要實現熱更一個模塊同時又保留其原有變量,我們可以把模塊的變量定義和函數定義分開,分別寫在兩個文件。
目錄如下:
data目錄: modA.lua; modB.lua; modC.lua
logic目錄: modA.lua; modB.lua; modC.lua
把模塊的變量定義放在data文件夾,把模塊函數的實現放在logic目錄。
下面是實現:
1 -- data.modA 2 local mod = {} 3 -- 這里定義模塊變量 4 mod.players = {} 5 mod.total_online = 0 6 7 -- 最后記得return這個表 8 return mod
1 -- logic.lua 2 local mod = require("data.modA") 3 4 -- 定義函數 5 function mod.login() 6 -- xxxxxx 7 end 8 9 function mod.load_data() 10 -- xxxxxxx 11 end
這里只是一個例子,logic.modA想要執行 `require("data.modA")` 成功,還要修改package.path,這個是Lua虛擬機啟動時自己去定義了,這里不做討論。
這里把模塊的變量和函數的定義分離了,我們只熱更function目錄下的文件,data目錄下的則不管。
熱更文件的實現如下:
1 -- require_ex.lua 2 function require_ex(filename) 3 local old_content 4 if package.loaded[filename] then 5 -- 把舊的模塊保存起來 6 old = package.loaded[filename] 7 -- 然后package.loaded[filename]賦空 8 package.loaded[filename] = nil 9 end 10 11 -- xpcall下執行require 12 local ok,err = pcall(require, filename) 13 if not ok then 14 --熱更失敗,將舊值賦回去 15 print("hotfix fail, err msg ",err) 16 package.loaded[filename] = old_content 17 return false 18 end 19 20 return true 21 end
切記: 重新require模塊的時候,必須在pcall下執行,萬一模塊有語法錯誤,require掛掉的話,package.loaded[filename]就會一直為nil。當有其他文件需要執行 require(filename)的時候,則會報錯,后面的邏輯無法執行。