Template for creating Union plugins based on union-api and CMake as the buildsystem generator.
Clone this repository and update submodules to fetch the dependencies.
git clone git@github.com:Silver-Ore-Team/union-plugin-template.git MyUnionPlugin
cd MyUnionPlugin
git submodule init
git submodule update --remote --recursive
If you'd like to push it to other Git repository, you can remove remote origin and add your own:
git remote rm origin
git remote add origin <YOUR_REPOSITORY_LINK>
Change CMakeLists.txt
project name to your plugin name, like:
cmake_minimum_required(VERSION 3.26)
# Project Settings
project(MyUnionPlugin)
# ...
The project name is used as DLL file name.
Plugin code is created in plugin/src/
.
This template is designed for multiplatform plugin development, so it contains some non-standard includes trickery.
Plugin.cpp
is a compiled file and the entrypoint for compilation. It includes Plugin.hpp
for each engine version and Plugin_[Engine].hpp
for the specific engine.
Plugin.hpp
contains the code that's the same for each engine by using GOTHIC_NAMESPACE
define that's correspond to one of engine namespaces.
If you need to write some part of code specifically for single engine, you can put it into a special Plugin_[Engine].hpp
file.
Game.hpp
is also included by the entrypoint, and it contains exports for Union events outside of GOTHIC_NAMESPACE
.
If you are new to union-api
, you should also read:
The template already implements the multiplaform setup, but please try to read about this, because it's easy to mess up and crash the game 😨
List of .cpp
to compile is available at the start of plugin/CMakeLists.txt
and you can add it there:
# Sources to compile
set(UNION_PLUGIN_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/Plugin.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/MyNewCppFile.cpp")
add_library(${CMAKE_PROJECT_NAME} SHARED)
# ...
GOTHIC_NAMESPACE
is a compile-time definition for Plugin.hpp
to generate same code for different namespaces.
During the runtime we have the code for all 4 engines, so we need to use GetGameVersion()
function and dispatch our call dynamically, like:
__declspec(dllexport) void Game_Entry() {
int virtualPos = 42;
int pixelPos;
switch(GetGameVersion())
{
case Engine_G1:
pixelPos = Gothic_I_Classic::VirtualToPixelX(virtualPos);
break;
case Engine_G1A:
pixelPos = Gothic_I_Addon::VirtualToPixelX(virtualPos);
break;
case Engine_G2:
pixelPos = Gothic_II_Classic::VirtualToPixelX(virtualPos);
break;
case Engine_G2A:
pixelPos = Gothic_II_Addon::VirtualToPixelX(virtualPos);
break;
}
// pixelPos = GOTHIC_NAMESPACE::VirtualToPixelX(virtualPos)
}
Alternative method is to use zSwitch
to get the method reference.
__declspec(dllexport) void Game_Entry() {
int virtualPos = 42;
int pixelPos;
auto VirtualToPixelFunction = zSwitch(Gothic_I_Classic::VirtualToPixelX, Gothic_I_Addon::VirtualToPixelX, Gothic_II_Classic::VirtualToPixelX, Gothic_II_Addon::VirtualToPixelX)
pixelPos = VirtualToPixelFunction(virtualPos);
}
gothic-api includes an inline file for every ZenGin class and let us define additional methods that are handly for hooks on __thiscall
functions.
The template holds all these inline files in gothic-userapi
and dynamically overlays them on original gothic-api
files copied to working directory during a build.
This way we can make use of them without editing anything in gothic-api
submodule.
By default the tempalate builds the plugin for each of Gothic engine versions. If you'd like to restrict that, remove compile flags from plugin/CMakeLists.txt
# Build for every engine
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE _UNION_API_DLL __G1 __G1A __G2 __G2A)
# Build only for Gothic I and Gothic II NotR
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE _UNION_API_DLL __G1 __G2A)
# Build only for Gothic I
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE _UNION_API_DLL __G1)
# Build only for Gothic II NotR
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE _UNION_API_DLL __G2A)
The simplest way to build the project is to open it inside Visual Studio 2022 with MSVC toolset 14.34+. It will automatically parse and configure CMake.
To build the project we have to configure buildsystem using CMake and execute Ninja on it.
We define presets for Debug and Release targets as x86-debug
and x86-release
.
# Debug
cmake --preset x86-debug
ninja -C out/build/x86-debug -j 20
cmake --install out/build/x86-debug --prefix out/install/x86-debug
# Release
cmake --preset x86-release
ninja -C out/build/x86-release -j 20
cmake --install out/build/x86-release --prefix out/install/x86-release
Then we should have UnionAPI.dll and our plugin DLL inside out/install/x86-debug
or out/install/x86-release
depending on selected target.
You can easily link external libraries to the project with CMake. Libraries may provide a .cmake
file to include or be configured using a package manager like vcpkg or Conan.
After you get the dependency to expose a CMake target, you can link the plugin against it in plugin/CMakeLists.txt
.
# ...
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE union-api gothic-api MyDependency::MyDependency)
# ...
union-plugin-template is licensed under MIT license, excluding dependencies.
union-api and gothic-api are licensed under GNU GENERAL PUBLIC LICENSE V3.