unity-lua运行时重载重启
开发环境中, 在不停止运行游戏的情况下, 刷新修改后的脚本逻辑, 提升开发效率
lua 虚拟机重启
就是销毁掉 旧的 luastate, 实例化新的 luastate
另一个使用场景是在热更完之后, 需要重启 lua 虚拟机, 使最新的 lua 脚本生效
csharp 重启逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// 重启 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
1
2
3
4
5
6
7
8CUIPnlSettingLogic = CUIPnlSettingLogic or class() -- 这里使用全局变量
CUIPnlSettingLogic.__name = "CUIPnlSettingLogic" -- 类名标记
function CUIPnlSettingLogic.Init(self, id, obj)
print("--- CUIPnlSettingLogic.Init 111")
end
return CUIPnlSettingLogic重写 require
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101local 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
即可编辑器扩展提供一个按钮