Lua堆栈问题

时间:2010-08-21 21:18:40

标签: lua stack

我无法用一个简短的描述性标题来解释我的问题,对不起。

我正在从c ++调用一个名为hook.Call(event,...)的lua函数。它调用hook.Add(event,unique_name,function)添加的所有函数

问题是当我在一个钩子里面调用print(...)函数时,它不会打印出你希望它打印的东西,因为调用一个钩子的堆栈仍然存在。所以它从那个堆栈打印出来。 我无法删除堆栈,因为那样我就无法从钩子中获取返回值。

钩子调用如下所示:

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

    hook::StartCall("PreGameUpdate");
        hook::PushInteger(haveFocus);
        hook::PushInteger(updateFlags);
    hook::CallReturn(1, 2); //Calls hook.Call("PreGameUpdate", haveFocus, updateFlags) here 

        //The first argument is the amount of values to return to C++
        //The second argument is how many values that were pushed onto the stack (maybe I can monitor that?)

        if(hook::IsBoolean(1) && hook::GetBoolean(1) == false)
            return false; //skip the rest of the code if we return false in the Pre hook

    hook::End();

    //rest of the code in CGame::Update() here

}

我正在考虑打印下一帧,但听起来真的很糟糕,我甚至不确定我是怎么做的。

钩子功能

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

        //Remove any previous stack (just in case?)
        //Stack is now: nil
        lua_settop(L, 0);

        //Get the "hook" global and check if it exists
        //stack is now: hook
        lua_getglobal(L, "hook");
            if (!lua_istable(L, -1))            
                return;

        //Get the function "Call" and check if it exists
        //Stack is now: hook.Call()
        lua_getfield(L, -1, "Call");
            if (!lua_isfunction(L, -1))
                return;

        //Remove the "hook" table from the stack leaving only the Call function left
        //Stack is now: Call()
        lua_remove(L, 1);

        //Push the hookname onto the stack
        //Stack is now: Call(hookname)
        lua_pushstring(L, hookname);
    }

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

        //PrintStack("PRE PCALL"); 
        /* When printing the stack, this is the output:
            ===========PRE PCALL=================START

                1: 
            function: 2116D588

                2: 
            PreGameUpdate

                3: 
            1.000000

                4: 
            0.000000

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

        //Check if the first value is a function and if the stack is valid
        if (!lua_isfunction(L, 1) || lua_gettop(L) == 0)
        {
            PrintStack("NO FUNCTION IN STACK");
            return;
        }

        //pcall "Call" from the stack and check if it worked
        //Stack is now: pcall(Call(hookname, ...))
        int status = lua_pcall(L, args + 1, returns, 0);

        //Check if it errored
        if(status != 0)
        {
            //Print to debug output if it errored
            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();

        //Remove the stack again
        //Stack is now: 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);
        lua_pop(L, 1);
        return res;
    }

    //The rest of the code is just like the three functions above but for different types
}

打印功能

int print(lua_State *L)
{
    //PrintStack("PRINT PRE");
    int n = lua_gettop(L);  /* number of arguments */
    int i;
    lua_getglobal(L, "tostring");
    for (i=1; i<=n; i++) {
        const char *s;
        lua_pushvalue(L, -1);  /* function to be called */
        lua_pushvalue(L, i);   /* value to print */
        lua_call(L, 1, 1);
        s = lua_tostring(L, -1);  /* get result */
        if (s == NULL)
            return luaL_error(L, LUA_QL("tostring") " must return a string to "
                            LUA_QL("print"));
        if (i>1) CryLogAlways("\t");
            CryLogAlways(s);
        lua_pop(L, 1);  /* pop result */
    }
    CryLogAlways("\n");
    //PrintStack("PRINT POST");
    return 0;
}

我没有完成大部分的打印功能。我从我朋友的代码中取出它,这就是为什么它没有像那些钩子函数那样被注释。当没有在钩子中调用时,打印确实有效。

因此print的问题在于它会打印挂钩堆栈中的所有内容,因为在删除堆栈之前它已被调用。

我还发现推送和弹出非常令人困惑,所以它真的有助于注释代码,就像在钩子调用函数中显示堆栈当前是什么。

我猜测整个问题是c ++中钩子函数的一个设计缺陷,但我真的不知道我是怎么做的。

1 个答案:

答案 0 :(得分:1)

我在int print的底部弹出了堆栈的tostring作为注释中提到的interjay,它现在应该像它一样工作。

我很抱歉没有足够的描述性。