Your first xScal plugin - how the hell do I start?

Copy the template, rename a few things, build it, and drop the DLL into the game folder.

Plugins may only interact with Scaleform. Trying to access any other part of the game core is prohibited.
  1. Get the SDK

    Unzip xScal-SDK.zip anywhere, for example C:\xscal-sdk. Inside is an sdk folder with include, cmake, bin and template.

  2. Get a certificate

    xScal only loads plugins that are signed with a certificate from the xScal maintainers.

    1. Run sdk\bin\xscal-sign.exe keygen dev.key dev.pub (on Linux, under Wine). dev.key is your private key: keep it to yourself and do not commit it. dev.pub is public.
    2. Send dev.pub and the plugin ID prefix you want, for example acme_, to the xScal maintainer.
    3. You get back dev.xcert. It is not secret.

    Set the environment variables XSCAL_SIGNING_KEY and XSCAL_SIGNING_CERTIFICATE to the full paths of dev.key and dev.xcert before you run CMake. Without them the build still works, but the DLL is unsigned and xScal will not load it.

  3. Copy the template

    Copy sdk\template to a new folder for your plugin, for example C:\MyPlugin. It holds two files: CMakeLists.txt and plugin.cpp.

  4. Rename things in CMakeLists.txt

    • example_plugin → your project name.
    • OUTPUT_NAME ExamplePlugin → the DLL name, for example MyPlugin.
  5. Rename things in plugin.cpp

    • .id = "example_plugin" → something unique that starts with your certificate prefix, such as "acme_myplugin" (at most 63 bytes). xScal rejects a plugin whose ID does not start with the prefix.
    • .name = "Example Plugin" → the name shown in xscal.log.
    • "ExamplePlugin.IsEnabled" → "MyPlugin.Whatever". Every call name starts with your plugin name so it does not clash with xScal or other plugins.
    • The option texts "Enabled", "Example Plugin" and "Enable the example feature".
  6. Add your code

    • Startup code goes in load(). Return 0 there to refuse loading.
    • Each function your SWF calls is a callback like isEnabled, plus one line in the scaleformCallbacks list.
    • Write to the log with xscal::log(host, "text %d", number);

    The comments in sdk\include\xscal\plugin_api.h describe every structure and callback.

  7. Build it

    Windows

    Install Visual Studio with the “Desktop development with C++” workload and CMake 3.25 or later, then run:

    cmake -S C:\MyPlugin -B C:\MyPlugin\build -A x64 -DxScalPlugin_DIR=C:\xscal-sdk\sdk\cmake
    cmake --build C:\MyPlugin\build --config Release

    Linux (cross-compile)

    Install CMake 3.29 or later, Ninja, LLVM (clang-cl, lld-link, llvm-lib, llvm-ml, llvm-mt, llvm-rc) and xwin. Download the Windows SDK and C runtime once:

    xwin --accept-license --arch x86_64 --variant desktop splat --output ~/.xwin

    Then build with the toolchain file that ships in the SDK:

    cmake -S ~/MyPlugin -B ~/MyPlugin/build -G Ninja -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_TOOLCHAIN_FILE=$HOME/xscal-sdk/sdk/cmake/toolchains/xwin-clang.cmake \
      -DXWIN_ROOT=$HOME/.xwin \
      -DxScalPlugin_DIR=$HOME/xscal-sdk/sdk/cmake
    cmake --build ~/MyPlugin/build

    The DLL is written to build\Release\Data\XSCAL\Plugins\MyPlugin.dll. When the signing variables are set, the build also writes MyPlugin.dll.sig next to it. Each rebuild replaces the .sig; a .sig from an older build no longer matches the DLL.

  8. Install it

    Copy MyPlugin.dll and MyPlugin.dll.sig to Data\XSCAL\Plugins\ in the game folder. Give other people both files too. xScal (dxgi.dll) must already be installed there.

  9. Check that it loaded

    Start the game and open xscal.log.

    Loaded: xScal module 'acme_myplugin' (My Plugin): loaded
    Rejected: xScal plugin '…': <reason>. The reason says what to fix, for example missing signature file or file does not match signature (the DLL was rebuilt after it was signed).
  10. Call it from your SWF

    try {
        var result:* = __SFCodeObj.call("MyPlugin.Whatever");
    } catch (error:Error) {
        // xScal or the plugin is not installed.
    }

    For everything else you can call from a SWF, see the Movie API guide.

Rename a plugin to MyPlugin.dll_disabled to turn it off. Restart the game after adding, removing or renaming a plugin.