Unity xlua 为全部按钮添加点击事件

用途

与其他模块交互的时候,找一个按钮对应执行的函数要找很久。如果可以直接获取事件所在代码行数就好了

错误思路

思路1:在lua侧获取按钮的userdata,并为其设置metatable
错误原因:按钮的userdata是C#对象,是xlua为其设置的元表,lua无法修改。

思路2:在C#侧,获取按钮实例,获取其点击事件并获得这个点击事件的debug信息。
错误原因:C#侧的点击事件已经被包装成了System.Action这个C#类型,无法获得lua的函数debug信息。

正确思路

其实从上面的错误思路2,就可以想到正确的写法了。找到包装System.Action的地方就好了,那怎么查呢?
lua的函数为btn.clickevent = function() end,我们需要考虑这一行函数调用后,C#上面的btn是如何接受到这个lua函数的。
可以看wrap文件:

Utils.RegisterFunc(L, Utils.SETTER_IDX, "clickevent", _s_set_clickevent);
static int _s_set_clickevent(RealStatePtr L)
{
	try {
		ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
		Button gen_to_be_invoked = (Button)translator.FastGetCSObj(L, 1);
		gen_to_be_invoked.clickevent = translator.GetDelegate<System.Action<...>>(L, 2);
	} catch(System.Exception gen_e) {
		return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
	}
	return 0;
}

不难看出,是在translator.GetDelegate>(L, 2);这段函数中,将luafunction转为的System.Action. 这样思路就很清晰了,我们只需要在这一段中插入代码,获取这个即将被转为Action的luaFunction,获取它的debug信息就可以了。所以我们只需要:

#if UNITY_EDITOR
    /// <summary>
    /// 存储 Lua 函数位置信息,用于调试
    /// </summary>
    public static class LuaFunctionLocationTracker
    {
        /// <summary>
        /// 最后一次创建的 Delegate 对应的 Lua 函数位置
        /// 在 CreateDelegateBridge 返回前设置,供外部立即读取
        /// </summary>
        public static string LastCreatedDelegateLocation;
    }
#endif

public object CreateDelegateBridge(RealStatePtr L, Type delegateType, int idx)
        {
#if UNITY_EDITOR
            // 在栈上的 Lua 函数还未被包装前,获取其位置信息
            string luaFuncLocation = GetLuaFunctionLocation(L, idx);
            LuaFunctionLocationTracker.LastCreatedDelegateLocation = luaFuncLocation;
#endif

修改ObjectTranslator,使得在任何lua函数包装前,都将这个lua函数的debug信息获取出来,存储到静态变量中。然后我们把button的luaFunction设置修改为属性。这样的话,在这个button的setter中,我们获取objectTranslator中的静态变量,就是上一次,也就是刚刚在CreateDelegateBridge中设置的位置信息了。

public System.Action clickevent
{
	get => _clickevent;
	set
	{
		_clickevent = value;
		// 从 XLua ObjectTranslator 获取刚刚创建的 Lua 函数位置
		if (value != null && GetLastDelegateLocationFunc != null)
		{
			luaClickLocation = GetLastDelegateLocationFunc();
		}
		else
		{
			luaClickLocation = null;
		}
	}
}

最后,我们只需要在C#中调用这个点击事件的地方,插入一行print luaClickLocation的代码就好了!

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

大纲

Share the Post:
滚动至顶部