2010-08-21 121 views
1

我真的不能做一个简短但描述性的标题来解释我的问题,所以很抱歉。Lua堆栈问题

我打电话给一个叫做hook.Call(event,...)的C++函数。它调用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相关的问题是,它会打印hook堆栈中的所有内容,因为它在调用堆栈之前被调用。

我还发现推送和弹出非常混乱,所以它确实有助于评论代码,如显示堆栈当前所处的钩子调用函数。

我猜整个问题是从C++钩函数的设计缺陷,但我真的不明白我会怎么做,否则。

+1

你说打印功能不符合你的期望,但你从未说过你期望它做什么。它看起来应该打印堆栈的全部内容,并根据你的问题,它是做什么的。顺便说一下,在'print'结尾处似乎缺少一个pop(tostring的值将保留在堆栈中)。 – interjay 2010-08-22 00:21:51

+0

是的,我认为我的问题中缺少一些东西: 打印的问题在于,它会打印钩子堆栈中的所有内容,因为在删除堆栈之前会调用它。 我很新的C++和lua api;当我完成某些事情后,我应该删除堆栈吗?我使用lua_settop(L,0)在hook中删除它:End() 通常人们使用lua_pop从结尾删除堆栈中的值。他们不应该把它全部清除吗? 我会在最后添加lua_pop,但它仍然不能解决我认为的问题。 – CapsAdmin 2010-08-22 00:46:35

+0

您能否详细说明您想要的print()函数来完成。正如用户interjay指出的那样,它以当前的形式从堆栈中检索内容。 – Adam 2010-08-22 01:45:25

回答

1

我在int print的底部弹出了堆栈的tostring,作为评论中提到的interjay,它的工作方式与现在一样。

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

+0

我建议你接受你自己的答案。否则,此问题在列表中显示为“未答复”。 – kikito 2010-11-02 23:26:43