title: unity-lua運行時重載重啓
categories: Unity3d
tags: [unity, lua, runtime, reload, restart]
date: 2020-06-30 11:20:08
comments: false
mathjax: true
toc: true
開發環境中, 在不停止運行遊戲的情況下, 刷新修改後的腳本邏輯, 提升開發效率
lua 虛擬機重啓
就是銷燬掉 舊的 luastate, 實例化新的 luastate
另一個使用場景是在熱更完之後, 需要重啓 lua 虛擬機, 使最新的 lua 腳本生效
-
csharp 重啓邏輯
// 重啓 lua 虛擬機 public void RestartLua() { StartCoroutine(RestartLuaEngine()); } IEnumerator RestartLuaEngine() { yield return 1; if (_luaMgr != null) { GameObject.Destroy(_luaMgr); yield return 1; _luaMgr = gameObject.AddComponent<LuaMgr>(); yield return StartLuaMain(); } } IEnumerator StartLuaMain() { yield return 1; // 跳一幀執行lua LuaMgr.GetMainState().DoFile("main.lua"); _luaMgr.OnStart(); CallLuaFunction("Main"); }
-
編輯器擴展提供一個按鈕
lua 重載
重載只是刷新腳本的方法, 使修改後的方法邏輯生效
原理:
- 將 require 方法保存起來, 然後重寫 require 邏輯
- 在 require 邏輯中捕獲需要重載的 lua 文件
- 重新加載 這些 lua 文件.
例如:
-
某個 class
CUIPnlSettingLogic = CUIPnlSettingLogic or class() -- 這裏使用全局變量 CUIPnlSettingLogic.__name = "CUIPnlSettingLogic" -- 類名標記 function CUIPnlSettingLogic.Init(self, id, obj) print("--- CUIPnlSettingLogic.Init 111") end return CUIPnlSettingLogic
-
重寫 require
local ipairs = ipairs local pairs = pairs local string = string local print = print local orgRequire = require local error = error local checkTbl = { "logic.", "module.", "main", "tolua_patch", } local ignoreTbl = { "debug_unit_test", } local notUsTbl = {} -- 不是我們的 lua 文件 local usTbl1 = {} -- 有 xxx.__name local usTbl2 = {} -- 無 xxx.__name local function checkSameName(name, path) for k,v in pairs(usTbl1) do if name == v then error(string.format("--- same name: %s\npath1: %s\npath2: %s", name, k, path)) end end end local function isCheck(path) for k,v in ipairs(checkTbl) do local i, _ = string.find(path, v) if i ~= nil then return true end end return false end local function isIgnore(path) for k,v in ipairs(ignoreTbl) do local i, _ = string.find(path, v) if i ~= nil then return true end end end require = function(path) local retTbl = orgRequire(path) if isIgnore(path) or not isCheck(path) then notUsTbl[path] = true return retTbl end if usTbl1[path] or usTbl2[path] then return retTbl end if type(retTbl) == "table" and retTbl.__name then checkSameName(retTbl.__name, path) usTbl1[path] = retTbl.__name else usTbl2[path] = true end return retTbl end gDumpReqTbl = function() dump(usTbl1, "--- usTbl1, has xxx.__name") dump(usTbl2, "--- usTbl2, no xxx.__name") dump(notUsTbl, "--- notUsTbl, has xxx.__name") end gRefreshReqTbl = function() local usTmpTbl1 = usTbl1 usTbl1 = {} for k,_ in pairs(usTmpTbl1) do package.loaded[k] = nil end local usTmpTbl2 = usTbl2 usTbl2 = {} for k,_ in pairs(usTmpTbl2) do package.loaded[k] = nil end for k,_ in pairs(usTmpTbl1) do require(k) end for k,_ in pairs(usTmpTbl2) do require(k) end gLog("<color=#00ff00ff>--- 重載 lua ok</color>") end
需要刷的時候調用一下
gRefreshReqTbl
即可 -
編輯器擴展提供一個按鈕