创建 C++ Mod

创建 C++ Mod

本指南介绍如何使用 UE4SS 创建 C++ Mod,分为四部分:第一部分说明先决条件;第二部分创建最基本的 C++ Mod;第三部分展示如何与 UE4SS 以及 UE 本身(通过 UE4SS)交互;第四部分说明 Mod 的安装。

本指南要求具备可用的 C++ 开发环境,并安装 CMake 和 git。最好采用与从源码构建 UE4SS 所需环境类似的配置。

第一部分

执行以下步骤前,务必安装 README 中列出的所有构建依赖!

  1. 创建 Epic 账号,并关联到 GitHub 账号。
  2. 检查邮箱,接受加入 @EpicGames GitHub 组织的邀请,从而获得 Unreal 源码访问权限。
  3. 为 GitHub 账号配置 SSH 密钥,让 git 能访问前面步骤中取得权限的 Unreal 源码。
  4. 在计算机上创建目录,名称不限,本例命名为 MyMods。
  5. 克隆 RE-UE4SS 仓库,使路径为 MyMods/RE-UE4SS。
  6. 打开 CMD,进入 RE-UE4SS,执行 git submodule update --init --recursive。
  7. 返回 MyMods 目录并创建一个新目录,用于保存 Mod 源码。本例命名为 MyAwesomeMod。
  8. 在 MyMods 中创建 CMakeLists.txt,写入以下内容:
cmake_minimum_required(VERSION 3.22)
project(MyMods)

add_subdirectory(RE-UE4SS)
add_subdirectory(MyAwesomeMod)

第二部分

  1. 在 MyMods/MyAwesomeMod 中创建 CMakeLists.txt,写入以下内容:
set(TARGET MyAwesomeMod)

add_library(${TARGET} SHARED
    dllmain.cpp
)

target_include_directories(${TARGET} PRIVATE .)
target_link_libraries(${TARGET} PUBLIC UE4SS)

# Copy the DLL to the game's mod directory after building (optional, adjust path as needed)
# add_custom_command(TARGET ${TARGET} POST_BUILD
#     COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${TARGET}> "path/to/game/Binaries/Win64/Mods/${TARGET}/dlls/"
# )

代码中的注释译文:构建完成后将 DLL 复制到游戏的 Mod 目录(可选,请根据需要调整路径)。

  1. 在 MyMods/MyAwesomeMod 中创建 dllmain.cpp,写入以下内容:
#include <stdio.h>
#include <Mod/CppUserModBase.hpp>

class MyAwesomeMod : public RC::CppUserModBase
{
public:
    MyAwesomeMod() : CppUserModBase()
    {
        ModName = STR("MyAwesomeMod");
        ModVersion = STR("1.0");
        ModDescription = STR("This is my awesome mod");
        ModAuthors = STR("UE4SS Team");
        // Do not change this unless you want to target a UE4SS version
        // other than the one you're currently building with somehow.
        //ModIntendedSDKVersion = STR("2.6");
        
        printf("MyAwesomeMod says hello\n");
    }

    ~MyAwesomeMod() override
    {
    }
};

#define MY_AWESOME_MOD_API __declspec(dllexport)
extern "C"
{
    MY_AWESOME_MOD_API RC::CppUserModBase* start_mod()
    {
        return new MyAwesomeMod();
    }

    MY_AWESOME_MOD_API void uninstall_mod(RC::CppUserModBase* mod)
    {
        delete mod;
    }
}

代码中的注释译文:除非确实需要以某种方式面向与当前构建版本不同的 UE4SS 版本,否则不要修改 ModIntendedSDKVersion。

  1. 在命令提示符中进入 MyMods 目录,执行以下任一方案。

A. 使用 Ninja 从命令行构建:

# Configure (Ninja is single-configuration)
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Game__Shipping__Win64

# Build (no --config needed for Ninja)
cmake --build build

注释译文:先配置(Ninja 为单配置生成器),再构建(Ninja 不需要 --config)。

或 B. 生成 Visual Studio 解决方案:

# Configure (MSVC is multi-configuration)
cmake -B build -G "Visual Studio 17 2022"

# Build from command line (MSVC requires --config)
cmake --build build --config Game__Shipping__Win64

注释译文:先配置(MSVC 为多配置生成器),再从命令行构建(MSVC 需要 --config)。

如果选择方案 B,VS 解决方案位于 build 目录。

  1. 在 Visual Studio 中打开 MyMods/build/MyMods.sln。
  2. 除非要调试,否则确保选择 Game__Shipping__Win64 配置。
  3. 在解决方案资源管理器中找到项目(本例为 MyAwesomeMod),右键点击并选择 Build。

第三部分

这一部分将学习如何向文件及两个控制台写日志,按名称查找 UObject,并记录它的名称。

  1. 在 #include <Mod/CppUserModBase.hpp> 下添加 #include <DynamicOutput/DynamicOutput.hpp>。此时也可以删除 #include <stdio.h>,因为接下来将移除唯一需要它的 printf 调用。
  2. 为节省时间、减少重复,并让代码更简洁,在所有 include 下添加:
using namespace RC;
  1. 将 MyAwesomeMod 构造函数中的 printf 调用替换为:
Output::send<LogLevel::Verbose>(STR("MyAwesomeMod says hello\n"));

它比 printf 调用更长,但消息会同时发送到日志文件、普通控制台和 GUI 控制台,还可通过 LogLevel 枚举获得颜色支持。

  1. 在 DynamicOutput 的 include 下添加:
#include <Unreal/UObjectGlobals.hpp>
#include <Unreal/UObject.hpp>
  1. 再次使用 using namespace 简化名称,在前一个声明下添加 using namespace RC::Unreal;。
  2. 在 Mod 构造函数中使用 register_on_unreal_init 注册 on_unreal_init 回调。完整构造函数如下:
    MyAwesomeMod() : CppUserModBase()
    {
        ModName = STR("MyAwesomeMod");
        ModVersion = STR("1.0");
        ModDescription = STR("This is my awesome mod");
        ModAuthors = STR("UE4SS Team");
        // Do not change this unless you want to target a UE4SS version
        // other than the one you're currently building with somehow.
        //ModIntendedSDKVersion = STR("2.6");
        
        register_on_unreal_init(&on_unreal_init);
        
        printf("MyAwesomeMod says hello\n");
    }

代码中的注释译文:除非需要面向不同于当前构建版本的 UE4SS 版本,否则不要修改 ModIntendedSDKVersion。

  1. 如下定义 on_unreal_init:
static auto on_unreal_init(CppModUserBase* self) -> void
{
    // You are allowed to use the 'Unreal' namespace in this function and anywhere else after this function has fired.
    auto Object = UObjectGlobals::StaticFindObject<UObject*>(nullptr, nullptr, STR("/Script/CoreUObject.Object"));
    Output::send<LogLevel::Verbose>(STR("Object Name: {}\n"), Object->GetFullName());
}

代码中的注释译文:可以在此函数中,以及此函数触发之后的任何位置使用 Unreal 命名空间。

注意,Output::send 不要求传入 LogLevel,并且格式字符串使用 {} 而非 %s。Output::send 的底层使用 std::format,如需了解更多,请查阅 std::format 或 libfmt。

  1. 右键点击项目,选择 Build。

译注:本节示例按原文保留。原文在替换 printf 后给出的完整构造函数仍包含 printf,且回调示例参数类型写为 CppModUserBase,与前文 CppUserModBase 拼写不同。实际编译时请核对目标 UE4SS 版本的声明并相应调整。

第四部分

前往 C++ Mod 安装指南


原文:docs/guides/creating-a-c++-mod.md · 固定提交 560411f18512 · 来源与 MIT 许可