Lua堆栈问题

我正在从 C++ 中调用名为 hook.Call(event, ...) 的 Lua 函数。它调用所有添加了 hook.Add(event, unique_name, function) 的函数。

问题是,当我在 hook 中调用 print(...) 函数时,它不会打印出我们期望的内容,因为调用 hook 时的堆栈仍然存在。所以它会从该堆栈中打印出来。 如果我删除该堆栈,那么我将无法获取 hook 的返回值。

hook 调用看起来像这样:

int CGame::Update(bool haveFocus, unsigned int updateFlags)
{

    hook::StartCall("PreGameUpdate");
        hook::PushInteger(haveFocus);
        hook::PushInteger(updateFlags);
    hook::CallReturn(1, 2); //在这里调用 hook.Call("PreGameUpdate", haveFocus, updateFlags)

        //第一个参数是要返回给 C++ 的值的数量
        //第二个参数是已推到堆栈上的值的数量(也许我可以监视它?)

        if(hook::IsBoolean(1) && hook::GetBoolean(1) == false)
            return false; //如果在 Pre 钩子中返回 false,则跳过余下的代码

    hook::End();

    //在此处编写 CGame::Update() 的其余代码

}

我考虑在下一帧打印,但那听起来很糟糕,而且我甚至不确定如何实现它。

hook 函数:

namespace hook
{
    void StartCall(string hookname)
    { lua_State *L = LuaJIT::GetState();

        //删除任何先前的堆栈(以防万一?)
        //堆栈现在是:nil
        lua_settop(L, 0);

        //获取“hook”全局变量并检查它是否存在
        //堆栈现在是:hook
        lua_getglobal(L, "hook");
            if (!lua_istable(L, -1))
                return;

        //获取函数“Call”并检查它是否存在
        //堆栈现在是:hook.Call()
        lua_getfield(L, -1, "Call");
            if (!lua_isfunction(L, -1))
                return;

        //将“hook”表从堆栈中删除,只留下 Call 函数
        //堆栈现在是:Call()
        lua_remove(L, 1);

        //将 hookname 推到堆栈上
        //堆栈现在是:Call(hookname)
        lua_pushstring(L, hookname);
    }

    void CallReturn(int returns, int args)
    { lua_State *L = LuaJIT::GetState();

        //PrintStack("PRE PCALL");
        /* 打印堆栈时,输出如下:
            ===========PRE PCALL=================START

                1:
            function: 2116D588

                2:
            PreGameUpdate

                3:
            1.000000

                4:
            0.000000

            ===========PRE PCALL=================END
        */

        //检查堆栈是否有效,是否有函数值
        if (!lua_isfunction(L, 1) || lua_gettop(L) == 0)
        {
            PrintStack("NO FUNCTION IN STACK");
            return;
        }

        //从堆栈中调用 pcall“Call”并检查它是否可行
        //堆栈现在是:pcall(Call(hookname, ...))
        int status = lua_pcall(L, args + 1, returns, 0);

        //检查是否出现错误
        if(status != 0)
        {
            //如果出现错误,则打印到调试输出
            PrintStack("STACK");
            Msg("PCALL ERROR[%s]: %s", lua_tostring(L, 1), lua_tostring(L, -1));
        }
        //PrintStack("POST PCALL");
    }

    void End()
    {   lua_State *L = LuaJIT::GetState();

        //再次删除堆栈
        //堆栈现在是:nil
        lua_settop(L, 0);
    }

    void EndNoReturn(int args)
    {
        CallReturn(0, args);
        End();
    }

    void StartCallNoPush(string hookname, int returns)
    {
        StartCall(hookname);
        CallReturn(0, returns);
    }

    void CallSimple(string hookname)
    {
        StartCall(hookname);
        CallReturn(0, 0);
        End();
    }

    void PushBoolean(bool res)
    { lua_State *L = LuaJIT::GetState();

        int test = toint(res);

        lua_pushboolean(L, test);
    }
    bool GetBoolean(int idx)
    { lua_State *L = LuaJIT::GetState();

        int res = lua_toboolean(L, idx);
        lua_pop(L, 1);
        return tobool(res);
    }
    int IsBoolean(int idx)
    { lua_State *L = LuaJIT::GetState();

        int res = lua_isboolean(L, idx);&#

原文链接 https://stackoverflow.com/questions/3539023

点赞
stackoverflow用户427310
stackoverflow用户427310

我按照 interjay 在评论中提到的做法,在 int print 函数的底部弹出了 stack 的 tostring,并且现在它正在按照预期工作。

对于我的描述不够清晰,我感到抱歉。

2010-08-22 02:46:03