Overview

What is this?

The original Joban Client Mod (JCM) lets resource packs write dynamic display scripts in JavaScript. The Yanyang fork adds C++ native scripting on top: scripts are compiled into native shared libraries (.dll / .so / .dylib) which the mod loads in game and drives frame by frame.

C++ and JS scripts can be mixed within the same declaration entry and rendered at the same time. The mod detects the language automatically from file characteristics—.js is JavaScript, everything else is parsed as a C++ module. Each side captures its own draw commands and replays them independently, without interference.

🧩

The same script model

The create / render / dispose lifecycle and per-instance persistent state are exactly the same as in JS; the snapshot wrappers align with the JS wrappers field for field.

⚡

Zero-JNI transport

Java ↔ C++ communicates over the shared-memory polling plane (any JDK ≥ 16) or the Panama FFM plane (JDK 22+); JNI is never involved, and there is only one host crossing per frame per instance.

🖥️

Native bridge for 8 platforms

windows-x64 / windows-arm64 / linux-x64 / linux-arm64 / android-arm64 / macos-x64 / macos-arm64 / ios-arm64 are all bundled inside the jar and matched automatically by system architecture.

🛡️

Crash isolation

A script crash disables only the offending module itself and leaves a single log line behind; the game process is unaffected. C++ exceptions thrown inside a module are caught by the guard in the same way.

The journey of a frame

Resource packmtr_custom_resources.json declarations
natives/<platform>/ library files
→
JCM host (Java)Discovers modules · allocates state blocks
Serialises a compact snapshot every frame
Transport (zero JNI)Shared-memory polling plane · Panama FFM plane
Your C++ modulemtrCreate → mtrRender → mtrDispose
Reads the snapshot · writes draw records
→
Draw replayText / textures / models / sounds
Same render path as JS scripts
Data flows left to right: the snapshot (POD structures + a string pool) enters the module; the module writes a flat stream of draw records into five output arenas, which the host replays along the same code path used for JS. Drawing, fonts and pixels all stay on the native side—the snapshot marshalling is the only Java crossing enforced every frame.

A fifteen-line PIDS script

examples/pids_arrivals.cpp — arrival display
#include <mtr/script.hpp>

struct ArrivalState {};

struct ArrivalDisplay : mtr::PidsScript<ArrivalState> {
    static constexpr auto ID = "example:arrivals";

    void render(mtr::PidsContext& ctx, ArrivalState&, const mtr::Pids& pids) override {
        for (int row = 0; row < pids.rows(); row++) {
            if (pids.is_row_hidden(row)) continue;
            std::string text = pids.get_custom_message(row).str();
            if (text.empty() && row < pids.arrivals().size())
                text = pids.arrivals().at(row).destination().str();
            if (!text.empty())
                mtr::Text::create().text(text.c_str())
                    .pos(2, row * 10.0 + 2).size(pids.width() - 4, 9).draw(ctx);
        }
    }
};

MTR_REGISTER_PIDS_SCRIPT(ArrivalDisplay)

No JNI, no reflection, no per-call boxing—pids.rows() and arrivals().at(i).destination() are plain memory reads on a compact snapshot.

When to choose C++

ScenarioRecommendation
High-resolution LCD / dot-matrix screens that repaint large numbers of pixels every frameC++ Gfx2D software rasteriser + dirty-rectangle upload; pixels never cross the JVM
Complex string processing / per-frame sorting / mathematical computationC++ native computation with zero allocation
Needs to call many Java APIs (networking, files, the sound manager)Either both sides reach the same set of public objects through Api
Simple one-off display logicJS no compiler toolchain needed; faster iteration

Compatibility

ItemRequirement
Minecraft1.17.1 – 1.20.4 (Fabric / Forge)
PrerequisitesMinecraft Transit Railway 4.0.5+ (required); the Fabric build also needs Fabric API
Java16 or later; 22+ automatically enables the fully zero-JNI FFM plane
ABIThe host accepts ABI 6–13 modules; the current SDK compiles to ABI 13
ToolchainC++17; MSVC / GCC / Clang; CMake ≥ 3.16 (recommended)

Contents