2010-08-21 166 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