Garry's Mod Wiki

Revision Difference

Creating_Binary_Modules#544772

<cat>Dev</cat> Binary modules allow you to extend Lua's functionality using C++. # Dependencies Binary Modules only need CMake and a C++ compiler for building. You can install both through either the Visual Studio Installer ("Desktop development with C++" in Visual Studio 2019) on Windows, Xcode/homebrew on macOS, or by using your favorite package manager on Linux. For CMake, downloads are also available on the [CMake website](https://cmake.org/download/). If you want to use an IDE, you should be able to choose any as long as it has support for CMake projects (Visual Studio, CLion, etc.). If you don't want to use an IDE you can also build the module manually, but that approach will not be detailed in this guide. # Project setup The headers you need are [available here](https://github.com/Facepunch/gmod-module-base/tree/development). They will provide your project with information about how to interface with the game and set a few common settings for compiling the module. First, create an empty folder. This will contain all the files related to your module and will be referred to as "main folder" from now on. Now, download a copy of the headers into a subfolder of the main folder. While you can name it freely, for this guide I will use `gmod-headers` as the name of the subfolder. You will have to replace that name accordingly if you chose something different. To check whether you extracted the files in the correct location, make sure that the paths `gmod-headers/include` and `gmod-headers/examples` are present in the main folder. Next, we will set up a CMake project definition. To do that, create a file called `CMakeLists.txt` in the main folder and paste the following content in there: ``` cmake_minimum_required(VERSION 3.10) # The project name is rather unimportant and you can name it anything you want. # It just mustn't conflict with the module name that is defined further below. project(gmod-module-guide LANGUAGES CXX) set(CMAKE_CONFIGURATION_TYPES Release Debug) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Load the gmod-module-base project that sets up headers and settings. add_subdirectory(gmod-headers/include) # The library name defined here (in this case, "testmodule") will be the name of the module. add_library(testmodule SHARED) # Add the source files required for the module. # Again, the file names don't matter and you can even add multiple files by adding more space-delimited filenames after "module.cpp". target_sources(testmodule PRIVATE module.cpp) # Actually apply the headers and settings to our module. target_link_libraries(testmodule gmod-module-base) set_gmod_suffix_prefix(testmodule) ``` Now that we have our project defined, we just need something that we can compile into a module. For demonstration purposes the "Hello World" example works just fine, so copy `gmod-headers/examples/HelloWorld/HelloWorld.cpp` and paste it into the main folder as `module.cpp`. This file you can now change and experiment with. For building, simply open the main folder in your chosen IDE (any half-decent one should detect the `CMakeLists.txt` file and set up a CMake project) and press "Build" in there. Developers without IDE can now follow any existing "how to build a CMake project" guide. The binary module will end up whereever the CMake output was placed, with the correct name already applied. # A note on userdata & metatables Userdata and metatables are handled differently in Garry's Mod. This helps the engine determine userdata type much faster. First create your metatable (ideally in GMOD_MODULE_OPEN), then create a reference to it and store it globally in a variable. ``` LUA->CreateTable(); LUA->PushCFunction(gcDeleteWrapper); LUA->SetField(-2, "__gc"); LUA->PushCFunction(toStringWrapper); LUA->SetField(-2, "__tostring"); LUA->PushCFunction(indexWrapper); LUA->SetField(-2, "__index"); LUA->PushCFunction(newIndexWrapper); LUA->SetField(-2, "__newindex"); metatable = LUA->ReferenceCreate(); ``` To push your userdata to the stack: ``` GarrysMod::Lua::UserData* ud = ( GarrysMod::Lua::UserData* )LUA->NewUserdata( sizeof( GarrysMod::Lua::UserData ) ); ud->data = pointer_to_your_c_class; ud->type = your_type_id; LUA->ReferencePush( metatable ); LUA->SetMetaTable(-2); ``` To get your userdata from the stack: ``` GarrysMod::Lua::UserData* obj = (GarrysMod::Lua::UserData* )LUA->GetUserdata(position); your_c_class* var = (your_c_class*)(obj->data); ``` # Naming & Location The module files should be placed in the garrysmod/lua/bin/ folder. The names differ between platform and Lua realm. |File name|Side| require(name) | Platform | |---|---|---|---| | `gmsv_example_win32.dll` | Server | example | Windows x32 | | `gmcl_example_win32.dll` | Client | example | Windows x32 | | `gmsv_example_win64.dll` | Server | example | Windows x64 (`x86-64` branch is required) | | `gmcl_example_win64.dll` | Client | example | Windows x64 (`x86-64` branch is required) | | `gmsv_example_osx.dll` | Server | example | OSX (actually a `.so` file, just renamed) | | `gmcl_example_osx.dll` | Client | example | OSX (actually a `.so` file, just renamed) | | `gmsv_example_linux.dll` | Server | example | Linux x32 (actually a `.so` file, just renamed) | | `gmcl_example_linux.dll` | Client | example | Linux x32 (actually a `.so` file, just renamed) | | `gmsv_example_linux64.dll` | Server | example | Linux x64 (actually a `.so` file, just renamed; `x86-64` branch is required) | | `gmcl_example_linux64.dll` | Client | example | Linux x64 (actually a `.so` file, just renamed; `x86-64` branch is required) | | `gmcl_example_linux64.dll` | Client | example | Linux x64 (actually a `.so` file, just renamed; `x86-64` branch is required) | # Converting From GMod 12 The interface in GMod 13 is very different to that of GMod 12 - the handy object wrappers are gone and the interface is very very similar to the standard Lua C API. Infact, nearly all of the functions in the interface work exactly the same way as their equivalents in the Lua C API, they're just named slightly differently. You should be able to work out what most of the functions do from the example and the [Lua C API Documentation](http://www.lua.org/manual/5.2/manual.html#4.8). If you find this kind of stack-level programming too hard, BlackAwps has created some "backwards headers", which should work exactly how the GMod 12 interface worked, you can find them [here](https://bitbucket.org/breakpointservers/bkacjios-glua-modules/src).