JS common APIs

Notation

  • A static prefix means the call goes straight through the class name (Resources.id(...)); without it you first need an instance (usually obtained from another function's return value).
  • Type annotations follow Java: str: String takes a Java string (JS strings convert automatically); a String? return may be null; String... means a variable number of string arguments.
  • Items marked Deprecated are NTE-era compatibility interfaces—don't use them in new scripts; items marked Yanyang are this fork's own extensions.

Resources and files

Identifier (resource paths)

Minecraft locates resources with Identifiers of the form namespace:path. Since JCM v2.3, most places that take an Identifier also accept a plain string: the full form "mtr:asd.png", or a path relative to the current script's directory with a ./ prefix (equivalent to idr()).

FunctionDescription
static Resources.id(idStr: String): IdentifierCreates an Identifier from a string
static Resources.idr(relPath: String): IdentifierResolves relative to the directory of the current script; usable only during the parsing stage (at runtime there is no notion of a 'current script')
static Resources.id(id: Identifier, suffix: String): IdentifierAppends a suffix to an existing Identifier—record the base with idr() during parsing, then build the path at runtime

Resources (resource pack reads)

Reading resources from disk is far slower than in-memory work: don't re-read every frame in render() what could have been read during the parsing stage.

FunctionDescription
static Resources.read(id): DataReader?Reads a resource pack file and returns a DataReader; returns null if the file does not exist
static Resources.exist(id): booleanWhether the file exists
static Resources.getSystemFont(name: String): FontFetches an AWT font. Built-in items: Noto Serif (a CJK serif), Noto Sans SemiBold, Noto Sans CJK TC Medium; also accepts Serif / SansSerif / Monospaced (depending on the fonts installed on the player's machine)
static Resources.hasSystemFont(name: String): booleanWhether the system has the font family (no built-in special-casing)
static Resources.getFontRenderContext(): FontRenderContextThe context used for AWT text metrics
static Resources.ensureStrFonts(text, primaryFont, fallbackFonts...): AttributedStringAssembles the text with a primary font plus a fallback font chain, falling back automatically when the primary font lacks a glyph—for multilingual mixed text it keeps the tofu away
static Resources.getAddonVersion(modId: String): StringFetches a mod version: "mtr" / "jcm" / "mtrscripting" (vehicle / eyecandy / lift scripts query mtrscripting; PIDS queries jcm)
DeprecatedDescription
Resources.readString(id) / readBufferedImage(id) / readFont(id)Use read() + DataReader instead
Resources.manager() / Resources.mgr()Not exposed by the MTR 4 cross-version framework; always returns null; the functions that need it accept null as well
Resources.getMTRVersion() and the other NTE version functionsUse getAddonVersion() instead; the NTE family only ever returns old values, for compatibility

Files (local files)

Confined to .minecraft: read + write + delete are limited to .minecraft/data/mtrscripting (the script data directory), whilst reading is open to the whole of .minecraft. Pass the path as multiple arguments, with no slashes: Files.read("config", "mtr.json").

FunctionDescription
static Files.read(path: String...): DataReader?Reads a file under .minecraft; returns null if it does not exist
static Files.readData(path: String...): DataReader?Same as above, but relative to data/mtrscripting
static Files.saveData(content: String | BufferedImage, path: String...): voidSaves text or an image; parent directories are created automatically
static Files.deleteData(path: String...): voidDeletes a file
static Files.hasData(path: String...): booleanWhether a file / directory exists

Maths and transforms

Vector3f (3D vectors)

Coordinates (x, y, z). The JCM implementation stores doubles underneath but takes and returns floats at the API; the arithmetic methods all return the vector itself, so calls can be chained:

new Vector3f(x, y, z) (also constructible from TSC's Vector / Position) · x() y() z() · copy() · normalize() · add(x,y,z) / add(v) · sub(v) · mul(x,y,z) / mul(n) · rotX(rad) / rotY(rad) / rotZ(rad) (radians) · cross(v) · distance(v) · distanceSq(v) · rawBlockPos(). The constants Vector3f.ZERO / XP / YP / ZP are read-only; do not modify them.

Matrices (transform stack)

Rendering often needs 'draw this section, then return to the previous transform'. Matrices is a transform stack; push and pop come in pairs:

new Matrices() (starts as the identity matrix) · translate(x,y,z) · rotateX/Y/Z(rad) (radians) · rotateX/Y/ZDegrees(deg) (degrees) · pushPose() (saves the current state) · popPose() (restores the last save) · popPushPose() (restores, then saves).

Rendering

Scripts run on background threads whilst rendering happens on the main thread—so drawing follows the draw-call pattern: inside render() you submit 'how to draw' to the RenderManager, and JCM remembers that batch of commands and keeps drawing with it until your next execution. The old commands are cleared after every script execution, so anything that should stay visible must be resubmitted each round; and a frame missed to slow execution is nothing to fear—JCM keeps using the previous batch until you hand over a new one.

RenderManager

Obtained from each kind's ctx.getRenderManager(); it carries a built-in 'base transform' (eyecandy = the block position plus the GUI offset and rotation; vehicles per car…—see the script types page for each kind), and everything submitted is drawn relative to it:

FunctionDescription
drawModel(model: Model, matrices?: Matrices)Submits a model; optional extra transform
drawModel(model, matrices?, light: int)Same, with a custom light value (take values from MinecraftClient.lightAt)
drawModel(holder: DynamicModelHolder, matrices?: Matrices)Submits a dynamic model holder directly—the gap before the upload lands next frame is handled internally, avoiding flicker
draw(call: DrawCall)Submits a raw draw call (QuadDrawCall and friends)

QuadDrawCall (quads)

Draws a quad face with configurable texture, UVs, tint and light—often used to mount a dynamic texture as a screen:

static QuadDrawCall.create() (optionally taking a comment argument) · quad(c1, c2, c3, c4) or corner1..4(pos) (four Vector3fs) · renderType(str) · color(rgb) · texture(id) · uv(u1,v1,u2,v2) (0–1) · matrices(m).

renderType values: EXTERIOR (the exterior paintwork, affected by positional lighting; the default), EXTERIOR_TRANSLUCENT, INTERIOR (in-car, always fully lit with face shading), INTERIOR_TRANSLUCENT, LIGHT (fully lit, no shading—suited to LCDs), LIGHT_TRANSLUCENT. The model side additionally has ALWAYS_ON_LIGHT.

Models

WaveFront OBJ and Metasequoia (.mqo) are supported; Blockbench's .bbmodel is not. OBJ exported by Blender / Blockbench needs the V axis flipped (flipV = true, the default); Metasequoia exports need an explicit false.

ClassKey points
ModelManagerloadModel(id, flipV=true): RawModel, loadModelParts(id, flipV=true): Map<String, RawModel> (split by object groups), upload(rawModel): Model (uploads to the GPU; parsing stage only—at runtime use DynamicModelHolder)
RawModelVertex data container: append(mesh|model), applyTranslation(x,y,z), applyRotation(dir, angleDeg), applyScale(x,y,z), applyMirror(x,y,z), applyUVMirror(u,v), setAllRenderType(str), copy(), replaceTexture(fileName, id), replaceAllTexture(id)
ModelAlready on the GPU: the vertices can no longer be edited, but replaceTexture(...) / replaceAllTexture(...) / copyForMaterialChanges() / close() still work
RawMeshBuilderCode-built models: after new RawMeshBuilder(faceSize, renderType, textureId), go vertex(pos) → normal(x,y,z) → uv(u,v) → endVertex() (optionally adding color(r,g,b,a)); finish with getMesh() or asRawModel()
DynamicModelHolderRuntime uploads: uploadLater(rawModel) (uploads on the render thread next frame), getUploadedModel() (may be the old model or null—prefer handing the holder straight to drawModel), close()
Tip

For simple runtime transforms (translate / rotate / scale), pass Matrices to drawModel instead of editing vertices and re-uploading every frame—the latter is several orders of magnitude slower.

Dynamic textures

GraphicsTexture

A fixed-resolution virtual texture plus a Java AWT canvas, uploaded for the game to display once painted—screens inside and outside vehicles and LED signboards all rest on it:

MemberDescription
new GraphicsTexture(width, height)Creates it. Per-screen / per-car content should be created in create and stored in state
.identifierThe texture's Identifier—hand it to QuadDrawCall.texture() or use it to replace a model texture
.bufferedImage / .graphicsThe AWT BufferedImage canvas and its Graphics2D (text antialiasing on by default, nothing else)
.fullAA() / .noAA()All antialiasing on / all off (noAA is common for dot-matrix screens)
.upload()Uploads the whole image to the GPU. Not cheap—throttle it with RateLimit (e.g. 10 Hz) and skip updates when far away
.upload(x, y, width, height)Uploads only a sub-region; the old content is kept. Second parameter form: upload(dstX, dstY, srcX, srcY, w, h); an external BufferedImage also works directly: upload(img, dstX, dstY, srcX, srcY, w, h)
.close()Releases the GPU memory. What was created in create must be closed in dispose, or it leaks
Yanyang .uploadRawABGR(bytes, dstX, dstY, w, h, lut)Writes a row-major byte array in BGRA order straight into the texture and uploads only that rectangle—a bandwidth saver for high-frequency per-pixel updates; see Yanyang extensions

Commonly used on the AWT side: Color.decode / new Color, graphics.setColor / setFont / setStroke, drawRect / fillRect / drawRoundRect / fillRoundRect, drawImage / drawString, Font.deriveFont, GradientPaint, AffineTransform, setClip, AlphaComposite; bring them in with Rhino's importPackage(java.awt). For a tutorial, see the Graphics2D JavaDoc.

Note

A freshly created texture's contents are not guaranteed clean (reused memory may show garbage)—call upload() once after creation to flush in your own content.

For multi-screen vehicles, consider the built-in DisplayHelper instead (include(Resources.id("mtrsteamloco:scripts/display_helper.js"))): one large texture carved into slots, with models generated automatically from the configuration—see the script types page.

Sound

SoundManager

Obtained from each kind's ctx.getSoundManager(); the base position depends on the kind:

playLocalSound(id, volume, pitch, category="MASTER") (unpositioned—announcement-style) · playSound(id, pos, volume, pitch, category="MASTER") (positioned in the world, relative to the base position) · play(soundInstance) / stop(soundInstance) (controllable instances).

TickableSoundInstance

A one-shot sound effect cannot be managed once it has played; use controllable instances for cases that need mid-flight volume changes or interruption (complex in-car announcements, motor sounds, looped music):

static create(id, category) · setSoundVolume(v) / setSoundPitch(v) (1.0 is the baseline) · setRepeatable(b) · setLoopDelay(tick) · setRelative(b) (follows the player at a constant volume) · setPos(v) (looping sounds must update their own position every frame) · isPlaying(). Playback is driven by play() / play(delayTick) / play(ctx), with abort() to cut a playing instance short (reworked in upstream v2.3.0-prerelease.3). Always stop looping instances in dispose.

Deprecated: setLoopable(b) — superseded by setRepeatable(b) in the v2.3.0-prerelease.3 rework; existing scripts keep working.

Sound categories: MASTER BLOCKS MUSIC RECORDS WEATHER HOSTILE NEUTRAL PLAYERS AMBIENT VOICE.

Networking and background work

Networking

static Networking.fetch(url, requestOption?): NetworkResponse<DataReader>. RequestOption is a plain JS object: method (GET by default), connectTimeout / readTimeout (milliseconds), headers (an object), body (a string; Content-Length is added automatically).

NetworkResponse: getResponseCode() · success() (true once any response has arrived—to test for business-level success use ok(), i.e. 200–299) · getData() (null on failure) · exception() · getHeaders().

Requests carry User-Agent: Joban Client Mod (https://jcm.joban.org) by default, which cannot be changed through normal means (unless the player disables the script restrictions). Do network requests on a background thread (see below).

BackgroundWorker

static BackgroundWorker.submit(task) hands a lambda task to a single-threaded background executor—don't lean on it too hard, other scripts need it as well; try/catch exceptions inside your task yourself. On a resource pack reload the queue is emptied, in-flight tasks are interrupted, and even a wedged state heals itself.

BackgroundWorker.submit(() => {
    let resp = Networking.fetch("https://example.com/data.json");
    if (resp.ok()) {
        let str = resp.getData().asString();
        // Process it, write it into state, and read it from render
    }
});

Console

print(...) and console.log(...) are equivalent (an NTE legacy; use either freely). The Console API aligns with web conventions but has no table / profiling methods:

console.log / warn / error / debug(...) (debug only outputs in debug mode) · console.count(label="default") / countReset(label) (counters are independent per label) · console.time(label) / timeLog(label) / timeEnd(label) (timers are independent per label). Placeholder interpolation is not supported; template strings are enough.

MTR data

MTR.ClientConfig (player preferences)

isChatAnnouncementEnabled() · isTtsAnnouncementEnabled() · shouldHideTranslucentParts() · getLanguageDisplay() (NORMAL / CJK_ONLY / NON_CJK_ONLY) · getDynamicTextureResolution() (0–8) · getVehicleOscillationMultiplier() (×10 for a percentage) · getDefaultRail3D() · isCustomFontEnabled().

MTR.Data (data known to the client)

MTR 4 only synchronises nearby data—don't be surprised when far-away things cannot be found; many functions return null:

GroupFunctions
Stations / depotsfindStation(pos) · getStation(id) · getKnownStations(); findDepot(pos) · getDepot(id) · getKnownDepots()
RoutesgetRoute(id) · getKnownRoutes() · getKnownRoutesPassingPlatform(platformId)
VehiclesgetVehicle(vehicleId) · getPlayerMountedVehicle() · getKnownVehicles() · isPlayerMounted(id) · getVehicleMountDetail(): MountDetail (ridingCarIndex(): int, pos(): Vector3f relative to the car centre — upstream v2.3.0-prerelease.3)
LiftsgetLift(id) · getPlayerMountedLift() · getKnownLifts() · getLiftFloors(tscLift): List<Floor> (the floors of a TSC lift — upstream v2.3.0-prerelease.3)
RailsgetRailFromPath(pathData) · getKnownRails() · isRailBlocked(hexId) · getKnownBlockedRails() · getBlockedSignalColors(hexId) · getConnectedRails(pathData, front, back, excludeSelf = false) / getConnectedRails(pos) (the rails connected to a path end / to a rail node position — upstream v2.3.0-prerelease.3)
Platforms / sidingsgetPlatform(id) · getKnownPlatforms() · findNearbyPlatforms(pos, radius); getSiding(id) · getKnownSidings() · findNearbySidings(pos, radius)
ArrivalsgetArrivals(platformId | platformIds[]): ArrivalEntries—the same object as pids.arrivals() in PIDS scripts

MTRClientData is a direct pass-through reference to MTR's internal data classes—use it only as a last resort; it carries no stability promise and may change across versions.

The Minecraft environment

MinecraftClient

worldIsRaining() · worldIsThundering() · worldIsRainingAt(pos) · worldDayTime() · blockLightAt(pos) · skyLightAt(pos) · lightAt(pos) (a packed value for rendering) · lightLevelAt(pos) · renderDistance() · localPlayer() · gamePaused() (the TSC simulation does not stop with the pause!) · narrate(msg) · displayMessage(msg, actionBar) (also accepts VanillaText) · spawnParticleInWorld(id, pos, velocity, alwaysSpawn=false) · getScoreboardScore(objective, player) · getWorldPlayers() · getCurrentWorldId() · getCameraMode() · getRedstoneLevel(pos) · getWorldBlockState(pos, stateName).

VanillaText (vanilla rich text)

Vanilla text components for building chat messages / overlays: literal(str) · translatable(key, ...) · append(other) · withBold() · withItalic() · withFont(id) · withColor(rgb | name) · clickToCopyText(str) · clickToOpenURL(url) · withHoverText(str | VanillaText) · getString() (yields the localised result).

VoxelShape (block outlines)

For custom eyecandy collision / outlines: empty() · fullCube() · create(minX, minY, minZ, maxX, maxY, maxZ, facing?) (units of 16 = one block) · combine(other); used together with ctx.setOutlineShape(...) / ctx.setCollisionShape(...).

ItemStack / PlayerEntity

ItemStack: itemId() · translationId() · empty() · count(). PlayerEntity (usually from MinecraftClient.localPlayer() or an event): uuid() · pos() / blockPos() / smoothPos() / velocity() · pitch() / yaw() / bodyYaw() · playerName() / displayName() · hasPermissionLevel(level) (client-side information—take it with a pinch of salt) · mainHandItem() / offHandItem() / activeItem() / isHoldingItem(id) · isSneaking() / isSprinting() / isSwimming() / isCreative() / isSpectator().

Utility classes

DataReader (unified decoding)

Returned by Resources.read, Files.read and Networking.fetch alike—a decoder over a byte sequence:

asString(): String? (UTF-8) · asBufferedImage(): BufferedImage? · asFont(): Font? (TTF/OTF; the implementation drops files into the temp directory—if disk space is tight, clear the +~JF-prefixed leftovers) · asByteArray(): byte[] · openInputStream(callback) (closes the stream for you) · asInputStream() (you close it yourself). A failed decode returns null and logs an error to the console.

Other utilities

ClassKey points
Timingelapsed() (seconds of game time; keeps running while paused) · delta() (seconds since the last render—what all frame-rate scaling of animation goes through) · currentTimeMillis() · nanoTime()
TextUtilSplits MTR's 中文|English||附加 naming format: getCjkParts / getNonCjkParts / getExtraParts / getNonExtraParts / getNonCjkAndExtraParts / isCjk / cycleString(src[, tick])
StateTrackerState-transition tracking (avoids 'fire every frame while the condition holds'): setState(value): boolean (true only on change) · stateNow() / stateLast() / stateNowDuration() / stateNowFirst() · changedTo(v) / changedFromTo(old, v); one per object, kept in state
CycleTrackerTimed cyclic rotation: new CycleTracker(["route", 5, "next", 5]) + tick() · stateNow() / stateLast() / stateNowDuration() / stateNowFirst()
RateLimitFrequency limiting: new RateLimit(intervalSec) + if (rl.shouldUpdate()) { ... }; resetCoolDown() brings the deadline forward immediately
JavaJava interop helpers: Java.newArray(class, length | dims), Java.toArray(class, list)—certain AWT methods want real Java arrays

Script features

include (scripts including each other)

include(Resources.id("mtrsteamloco:scripts/display_helper.js"));  // Absolute path
include("./util/common.js");                                     // Relative to the current script

Loads and executes another JS file during the parsing stage (accepts a string relative path or an Identifier).

Script entries referencing each other

A script entry that no content in the same pack references is refused by default (a guard against a forgotten scriptId); adding "forceLoad": true to the script entry forces it to load—used when sharing script entries across packs, or when MTR 3 entries borrow MTR 4 shared declarations; mind the resource pack load order (the declaring pack loads first).

ANTE compatibility classes

SoundHelper (ANTE-style sound playback), TickableSound, GlobalRegister, ComponentUtil (vanilla text component utilities) and the global asJavaArray(list, class) are available since v2.3, with signatures matching ANTE's to ease migrating ANTE content.


Next: JS script types — the per-kind APIs for vehicles / eyecandy / lifts / PIDS; Yanyang extensions — what this fork adds on top of JS.