我真的不能做一個簡短但描述性的標題來解釋我的問題,所以很抱歉。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++鉤函數的設計缺陷,但我真的不明白我會怎麼做,否則。
你說打印功能不符合你的期望,但你從未說過你期望它做什麼。它看起來應該打印堆棧的全部內容,並根據你的問題,它是做什麼的。順便說一下,在'print'結尾處似乎缺少一個pop(tostring的值將保留在堆棧中)。 – interjay 2010-08-22 00:21:51
是的,我認爲我的問題中缺少一些東西: 打印的問題在於,它會打印鉤子堆棧中的所有內容,因爲在刪除堆棧之前會調用它。 我很新的C++和lua api;當我完成某些事情後,我應該刪除堆棧嗎?我使用lua_settop(L,0)在hook中刪除它:End() 通常人們使用lua_pop從結尾刪除堆棧中的值。他們不應該把它全部清除嗎? 我會在最後添加lua_pop,但它仍然不能解決我認爲的問題。 – CapsAdmin 2010-08-22 00:46:35
您能否詳細說明您想要的print()函數來完成。正如用戶interjay指出的那樣,它以當前的形式從堆棧中檢索內容。 – Adam 2010-08-22 01:45:25