tags:

views:

67

answers:

1
+1  Q: 

Lua stack issue

I can't really make a short yet descriptive title to explain my problem, so sorry for that.

I'm calling a lua function called hook.Call(event, ...) from c++. It calls all functions added with hook.Add(event, unique_name, function)

The problem is that when I call the print(...) function inside a hook it won't print what you'd expect it to print because the stack from calling a hook is still there. So it prints from that stack. And I can't remove the stack because then I wouldn't be able to get the return values from the hook.

The hook call looks like this:

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

}

I was thinking of printing the next frame but that sounds really bad and I'm not even sure how I'd do it.

The hook functions

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
}

The print function

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;
}

I didn't make most of that print function. I took it from my friend's code so that's why it isn't commented like those hook functions. The print does work when not called in a hook.

So the problem with print is that it prints everything that is in the hook stack because it's called before I remove the stack.

I also find pushing and popping very confusing so it really helps commenting the code like in the hook call functions showing what the stack currently is.

I'm guessing the whole problem is a design flaw in the hook functions from c++ but I really don't see how I'd do it otherwise.

A: 

I popped tostring of the stack at the bottom of int print as interjay mentioned in a comment and it's working like it should now.

I'm sorry for not being descriptive enough.

CapsAdmin