C Lua: Functions

From Garry's Mod
Jump to: navigation, search

Contents

Prerequisites

If you haven't already set up your IDE, it is recommended that you read this first: Setting Visual Studio Up for Making Binary Modules.

Creating C++ functions for Lua

Making C++ functions for Lua is absolutely essential for your binaries. Without it, your modules just won't be as useful. In this section I will cover how to create functions in C++ for use in Lua, checking the arguments and return values.

Defining Our Function in C++

The first thing we will do is define our C++ function.

int MyFirstFunction( lua_State* state )
{
    //We'll add stuff here in a sec
}

Now that we have a blank function, lets have it return a value. To do this we push something onto the stack and then return the number of values we want to return. So in this case we'll push a bool, true, and then return 1.

int MyFirstFunction( lua_State* state )
{
    LUA->PushBool( true ); // Push our bool onto the stack.
    
    return 1; // How many values we are returning
}

Now if we were to call this function in Lua, which we can't yet because we have only defined it in C++, then it would always return true.

Alright, so now that you have a basic understanding of how it works, let's make it more complex. How about we add a parameter and if it's over a certain value we return true, otherwise false.

int MyFirstFunction( lua_State* state )
{
    LUA->CheckType( 1, GarrysMod::Lua::Type::NUMBER ); // Make sure a number is the first argument
    
    double number = (LUA->GetNumber( 1 )); // Get the first argument

    if (number > 9.0) // If the number is over 9...
    {
        LUA->PushBool( true ); // push true...
    }
    else
    {
        LUA->PushBool( false ); // otherwise, push false false.
    }
    
    return 1; // How many values we are returning
}

Now that we have our function defined, it's

Defining Our C++ Function in Lua

So now that we have or function created, we need a way to call it in Lua. This is the easy part.

GMOD_MODULE_OPEN()
{
    LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Push the global table
         LUA->PushCFunction( MyFirstFunction ); // Push our function
         LUA->SetField( -2, "MyFirstFunction" ); // Set MyFirstFunction in lua to our C++ function
    LUA->Pop(); // Pop the global table off the stack

    return 0;
}

This sets the Lua variable "MyFirstFunction" to the C++ function "MyFirstFunction", so you can call it in Lua using

MyFirstFunction( <number> )



Calling Lua Function In C++

It is very useful if you know how to call Lua functions using Lua C. In this section I will cover how to calling functions and getting the return values. Now a brief explanation of how Call works. If I did the following:

LUA->Call( 0, 0 );

Then it would call my function with 0 arguments and not get a return value. The next example would call with 1 argument and still get no return value:

LUA->Call( 1, 0 );

My next example would pass 3 arguments and get 1 return value:

LUA->Call( 3, 1 );

Finally my last example would pass 2 arguments and get 4 return values:

LUA->Call( 2, 4 );



Call and PCall

The only difference between Call and PCall is PCall is short for protected call. In other words if something goes horribly wrong, PCall won't freak out but call will. So it's a good habit to use PCall if your arguments aren't constants, but for these examples we will be using Call.



Calling from the Global Table

So calling from the global table is probably what you will use the most. It's very simple to call from the global table and easy. It just doesn't look very pretty.

LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Push the global table
    LUA->GetField( -1, "print" ); // Get the print function
    LUA->PushString( "Swag" ); // Push our argument
    LUA->Call( 1, 0 ); // Call the function
LUA->Pop(); // Pop the global table off the stack

This would output "Swag" in the console. Below is an example of using multiple arguments.

LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Push the global table
    LUA->GetField( -1, "print" ); // Get the print function
    LUA->PushString( "Swag" ); // Push our argument
    LUA->PushNumber( 1337 ); // Push our second argument
    LUA->Call( 2, 0 ); // Call the function
LUA->Pop(); // Pop the global table off the stack

This would output "Swag 1337" in console. Below is an example of a pseudo-practical use.

int MyFirstFunction( lua_State* state )
{
    LUA->CheckType( 1, GarrysMod::Lua::Type::STRING ); // Make sure a string is the first argument

    LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Push the global table
        LUA->GetField( -1, "print" ); // Get the print function
        LUA->Push( 1 ); // Push the first argument
        LUA->Call( 1, 0 ); // Call the function
    LUA->Pop(); // Pop the global table off the stack

    return 0; // How many values we are returning
}

If you wanted to call more than one functions you would do the following:

LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Push the global table
    LUA->GetField( -1, "print" ); // Get the print function
    LUA->PushString( "Swag" ); // Push our argument
    LUA->Call( 1, 0 ); // Call the function

    LUA->GetField( -1, "print" ); // Get the print function
    LUA->PushString( "Garry feels like a new man." ); // Push our argument
    LUA->Call( 1, 0 ); // Call the function

    LUA->GetField( -1, "Msg" ); // Get the Msg function
    LUA->PushString( "Double swag\n" ); // Push our argument
    LUA->Call( 1, 0 ); // Call the function
LUA->Pop(); // Pop the global table off the stack



Calling Functions Passed as Arguments

Calling functions passed as arguments is very useful. In another section I will cover how to store a function and then call it later, but for now we will start with the basics.

int MyFirstFunction( lua_State* state )
{
    LUA->CheckType( 1, GarrysMod::Lua::Type::FUNCTION ); // Make sure the first argument is a function

    LUA->PushString( "Hey... swag swag swag swag" ); // Push our argument
    LUA->Push( 1 ); // Push the function
    LUA->Call( 1, 0 ); // Call the function
    
    return 0;
}

So now if you did something like below in Lua, it would output in console "Hey... swag swag swag swag"

MyFirstFunction( print )



Getting the Return Value

So you know how to call the functions, you just don't know how to get the return value. I will fix that for you. Below is an example of getting the return value of math.abs:

LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Push the global table
    LUA->GetField( -1, "math" ); // Get the math table
    LUA->GetField( -1, "abs" ); // Get the abs function from the math table
    LUA->PushNumber( -666 ); // Push our argument
    LUA->Call( 1, 1 ); // Call the function and get 1 return value
    
    int iReturnValue = (int)LUA->GetNumber( -1 );
LUA->Pop( 3 ); // Pop the global table, the math table, and the return value off the stack

Now we have the return value of math.abs( -666 ) in iReturnValue. So iReturnValue is equal to 666. In the following example I get the result of math.abs( 1337 ) then I print it to my console.

LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); // Push the global table
    LUA->GetField( -1, "math" ); // Get the math table
    LUA->GetField( -1, "abs" ); // Get the abs function from the math table
    LUA->PushNumber( -666 ); // Push our argument
    LUA->Call( 1, 1 ); // Call the function and get 1 return value
    
    LUA->GetField( -3, "print" ); // Get the print function
    LUA->Push( -2 ); // Push the return value
    LUA->Call( 1, 0 ); // Call the print function
LUA->Pop( 3 ); // Pop the global table, math table, and return value off the stack

This would output "666" to my console.

Personal tools
Navigation