Garry's Mod Wiki

Revision Difference

Creating_Binary_Modules#547581

<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) |⤶ ⤶ <note>Menu state modules are categorized under `gmsv_name_platform.dll`</note><page>Creating Binary Modules: CMake</page>