首先要说一下, 为什么我们需要按需注册. 这是有深刻的教训的, 项目里实际注册的数量, 数以万计. 虽然每项注册的消耗并不多, x10000之后, 就不容小觑了. 先说静态生成wrap代码的方式, 几万个wrap方法对应的代码行数, 几十万行c#代码. 再经过il2cpp之后, 又要乘以N. 所以, 导致unity项目里面的代码行数非常大, 也导致了text段很大. 这些注册项在运行时占用的内存, 也超过了15M. 注册时间消耗, 在编辑器上面就得100ms, 手机上的初始化时间应该更高. 甚至在xcode下面构造都成了一个问题, +-128M导致编译失败.
综上所述, 需要想办法减一减. 经过多次焦头烂额的尝试, 我觉得我找到了正确的方法: 按需注册. 当然光按需注册是不够的, 但起点就是按需注册.
这里简单说一下按需注册的实现原理:
local function Test3()
local function RegisterMethod(className, methodName)
print('register method', className, methodName)
return function(...)
print('call method', className, methodName, ...)
end
end
local GameObject = { className="UnityEngine.GameObject" }
setmetatable(GameObject, GameObject)
function GameObject.__index(tbl, key)
local method = RegisterMethod(GameObject.className, key)
rawset(tbl, key, method)
return method
end
GameObject.SayHello('hello', 1234)
GameObject.SayHello('hi', 5678)
end
控制台输出:
register method UnityEngine.GameObject SayHello
call method UnityEngine.GameObject SayHello hello 1234
call method UnityEngine.GameObject SayHello hi 5678
接下来, 就是要把RegisterMethod这个方法, 换成实际的注册方法.
private static int RegisterUnityMethod(IntPtr L)
{
CheckArgumentCount(L, 2);
var argumentCount = lua_gettop(L);
// classId methodName
var classId = TypeTrait<int>.pull(L, -2);
var methodName = lua_tostring(L, -1);
var cls = luaRegister.GetClass(classId);
luaRegister.FindAllMethods(cls, methodName, methodList);
var method = CreateUnityMethod(methodList[0]);
var methodId = unityMethodMap.Count;
unityMethodMap.Add(method);
lua_pushinteger(L, methodId);
return 1;
}
这里省略了一下代码, 把method映射成为一个methodId, 返回给了lua. lua那边记录了一个id. 毕竟存储效率, 访问速度, 还是c#更擅长一些.
CreateUnityMethod的实现细节, 未完待续.
或者先看这个 https://github.com/bianpeng001/bLua/blob/main/docs/LazyWrap.md, 比较完整, 但是看起来累一些.