API communes JS

Conventions de notation

  • Le préfixe static = appel direct au nom de la classe (Resources.id(...)) ; sans lui, il faut d’abord obtenir une instance (en général via la valeur de retour d’une autre fonction).
  • Les annotations de types suivent l’écriture Java : str: String accepte une chaîne Java (les chaînes JS sont converties automatiquement) ; un retour String? signifie « peut valoir null » ; String... désigne un nombre variable d’arguments chaîne.
  • Les entrées marquées Obsolète sont des interfaces de compatibilité de l’ère NTE — ne les utilisez plus dans les nouveaux scripts ; celles marquées Yanyang sont des extensions propres à cette branche.

Ressources et fichiers

Identifier (chemin de ressource)

Minecraft localise ses ressources au moyen d’Identifier de la forme espace_de_noms:chemin. Depuis JCM v2.3, la plupart des emplacements qui attendent un Identifier acceptent aussi une simple chaîne : forme complète "mtr:asd.png", ou chemin relatif au répertoire du script courant avec le préfixe ./ (équivalent d’idr()).

FonctionDescription
static Resources.id(idStr: String): Identifiercrée un Identifier à partir d’une chaîne
static Resources.idr(relPath: String): Identifierrésout relativement au répertoire du script courant ; à n’utiliser qu’en phase d’analyse (en phase d’exécution, la notion de « script courant » n’existe plus)
static Resources.id(id: Identifier, suffix: String): Identifierajoute un suffixe à un Identifier existant — notez la base avec idr() pendant l’analyse, puis composez le chemin en exécution

Resources (lecture dans le pack de ressources)

Lire une ressource sur disque est bien plus lent qu’une opération en mémoire : ce qui peut être lu pendant la phase d’analyse n’a pas à être relu à chaque frame dans render().

FonctionDescription
static Resources.read(id): DataReader?lit un fichier du pack de ressources et retourne un DataReader ; null si le fichier n’existe pas
static Resources.exist(id): booleanle fichier existe-t-il
static Resources.getSystemFont(name: String): Fontretourne une police AWT. Polices intégrées : Noto Serif (sérif CJK), Noto Sans SemiBold, Noto Sans CJK TC Medium ; accepte aussi Serif / SansSerif / Monospaced (selon les polices installées sur la machine du joueur)
static Resources.hasSystemFont(name: String): booleanla famille de police existe-t-elle sur le système (sans traitement spécial des polices intégrées)
static Resources.getFontRenderContext(): FontRenderContextle contexte utilisé pour les métriques de texte AWT
static Resources.ensureStrFonts(text, primaryFont, fallbackFonts...): AttributedStringassemble le texte avec la police principale + une chaîne de polices de repli, en basculant automatiquement quand un glyphe manque — l’outil anti « carrés de tofu » pour la composition multilingue
static Resources.getAddonVersion(modId: String): Stringretourne la version du mod : "mtr" / "jcm" / "mtrscripting" (les scripts véhicule / décoration / ascenseur consultent mtrscripting, les PIDS jcm)
ObsolèteDescription
Resources.readString(id) / readBufferedImage(id) / readFont(id)remplacez uniformément par read() + DataReader
Resources.manager() / Resources.mgr()le framework inter-versions de MTR 4 ne l’expose pas : retourne toujours null ; les fonctions qui en ont besoin acceptent null
Resources.getMTRVersion() et autres fonctions de version NTEremplacez par getAddonVersion() ; les fonctions de la série NTE retournent toujours les anciennes valeurs, uniquement par compatibilité

Files (fichiers locaux)

L’activité est confinée à .minecraft : lecture + écriture + suppression limitées à .minecraft/data/mtrscripting (le répertoire de données des scripts), lecture ouverte à tout .minecraft. Les chemins se transmettent en plusieurs arguments, sans barres obliques : Files.read("config", "mtr.json").

FonctionDescription
static Files.read(path: String...): DataReader?lit un fichier sous .minecraft ; null s’il n’existe pas
static Files.readData(path: String...): DataReader?comme ci-dessus, mais relatif à data/mtrscripting
static Files.saveData(content: String | BufferedImage, path: String...): voidenregistre du texte ou une image ; le répertoire parent est créé automatiquement
static Files.deleteData(path: String...): voidsupprime le fichier
static Files.hasData(path: String...): booleanle fichier / répertoire existe-t-il

Mathématiques et transformations

Vector3f (vecteur tridimensionnel)

Coordonnées (x, y, z). L’implémentation JCM travaille en double en interne, reçoit et restitue des float à l’extérieur ; toutes les méthodes de calcul retournent l’objet lui-même pour permettre les appels chaînés :

new Vector3f(x, y, z) (constructible aussi depuis Vector / Position de la TSC) · 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(). Constantes Vector3f.ZERO / XP / YP / ZP — en lecture seule, ne les modifiez pas.

Matrices (pile de transformations)

Le rendu exige souvent « dessiner ce passage, puis revenir à la transformation précédente ». Matrices est une pile de transformations ; push et pop s’emploient par paires :

new Matrices() (matrice identité au départ) · translate(x,y,z) · rotateX/Y/Z(rad) (radians) · rotateX/Y/ZDegrees(deg) (degrés) · pushPose() (enregistre l’état courant) · popPose() (restaure le dernier enregistrement) · popPushPose() (restaure puis enregistre).

Rendu

Le script tourne sur un thread d’arrière-plan, le rendu a lieu sur le thread principal — le dessin suit donc le modèle des appels de dessin (draw calls) : dans render(), vous soumettez « comment dessiner » au RenderManager ; JCM mémorise ce lot d’instructions et continue de le dessiner tel quel jusqu’à votre prochaine exécution. L’ancien lot est effacé après chaque exécution du script — pour un affichage continu, soumettez-le à nouveau à chaque tour ; mais rien à craindre si une exécution lente fait sauter des frames : JCM continue de rejouer le lot précédent jusqu’à ce que vous en livriez un nouveau.

RenderManager

Obtenu via le ctx.getRenderManager() de chaque type ; il embarque une « transformation de base » (eyecandy = position du bloc + décalage et rotation GUI ; véhicule = par voiture… — détails par type sur la page Types de scripts) et toutes les soumissions se dessinent relativement à elle :

FonctionDescription
drawModel(model: Model, matrices?: Matrices)soumet un modèle ; transformation additionnelle facultative
drawModel(model, matrices?, light: int)comme ci-dessus, avec éclairage personnalisé (valeur de MinecraftClient.lightAt)
drawModel(holder: DynamicModelHolder, matrices?: Matrices)soumet directement un détenteur de modèle dynamique — l’intervalle « le transfert ne complète qu’à la frame suivante » est géré en interne, évitant le scintillement
draw(call: DrawCall)soumet un appel de dessin brut (QuadDrawCall, etc.)

QuadDrawCall (quadrilatère)

Dessine une face quadrilatère, avec texture, UV, teinte et éclairage au choix — l’usage typique est d’y plaquer une texture dynamique pour simuler un écran :

static QuadDrawCall.create() (accepte un paramètre de commentaire) · quad(c1, c2, c3, c4) ou corner1..4(pos) (quatre Vector3f) · renderType(str) · color(rgb) · texture(id) · uv(u1,v1,u2,v2) (0–1) · matrices(m).

Valeurs de renderType : EXTERIOR (livrée extérieure du véhicule, éclairée selon sa position, par défaut), EXTERIOR_TRANSLUCENT, INTERIOR (habitacle, pleine luminosité avec teinte par face), INTERIOR_TRANSLUCENT, LIGHT (pleine luminosité sans ombrage, adapté aux LCD), LIGHT_TRANSLUCENT. Côté modèles existe en outre ALWAYS_ON_LIGHT.

Modèles

Sont pris en charge WaveFront OBJ et Metasequoia (.mqo) ; le .bbmodel de Blockbench n’est pas pris en charge. Les OBJ exportés par Blender / Blockbench exigent l’inversement de l’axe V (flipV = true, la valeur par défaut) ; ceux exportés par Metasequoia exigent un false explicite.

ClasseL’essentiel
ModelManagerloadModel(id, flipV=true): RawModel, loadModelParts(id, flipV=true): Map<String, RawModel> (découpe par groupes d’objets), upload(rawModel): Model (téléversement vers le GPU ; phase d’analyse uniquement — en phase d’exécution, passez par DynamicModelHolder)
RawModelconteneur de données de sommets : 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)
Modeltéléversé sur le GPU : les sommets ne se modifient plus, mais replaceTexture(...) / replaceAllTexture(...) / copyForMaterialChanges() / close() restent disponibles
RawMeshBuildermodélisation par code : après new RawMeshBuilder(faceSize, renderType, textureId), vertex(pos) → normal(x,y,z) → uv(u,v) → endVertex() (color(r,g,b,a) en option), finalisez avec getMesh() ou asRawModel()
DynamicModelHoldertéléversement en phase d’exécution : uploadLater(rawModel) (téléverse sur le thread de rendu à la frame suivante), getUploadedModel() (peut être l’ancien modèle ou null — préférez remettre le détenteur directement à drawModel), close()
Astuce

Pour les transformations simples en phase d’exécution (translation / rotation / mise à l’échelle), passez des Matrices à drawModel au lieu de modifier les sommets puis de re-téléverser à chaque frame — cette dernière voie est plus lente de plusieurs ordres de grandeur.

Textures dynamiques

GraphicsTexture

Une texture virtuelle à résolution fixe + un canevas Java AWT, téléversée au jeu pour affichage une fois dessinée — c’est elle qui porte les écrans intérieurs et extérieurs des véhicules comme les panonceaux LED :

MembreDescription
new GraphicsTexture(width, height)création. Créez dans create, et stockez dans state, le contenu propre à chaque écran / chaque véhicule
.identifierl’Identifier de cette texture — remettez-le à QuadDrawCall.texture() ou utilisez-le en remplacement de texture de modèle
.bufferedImage / .graphicsle canevas AWT BufferedImage et son Graphics2D (seul l’anticrénelage du texte est activé par défaut)
.fullAA() / .noAA()anticrénelage complet / entièrement désactivé (noAA est courant sur les écrans à matrice de points)
.upload()téléverse l’image entière vers le GPU. Le coût n’est pas négligeable — réduisez la cadence avec RateLimit (par ex. 10 Hz) et ne mettez plus à jour au loin
.upload(x, y, width, height)ne téléverse qu’une sous-zone, l’ancien contenu est conservé. Forme 2 : upload(dstX, dstY, srcX, srcY, w, h) ; accepte aussi une BufferedImage externe : upload(img, dstX, dstY, srcX, srcY, w, h)
.close()libère la mémoire du GPU. Ce qui est créé dans create doit être fermé dans dispose, sans quoi la mémoire fuit
Yanyang .uploadRawABGR(bytes, dstX, dstY, w, h, lut)écrit directement dans la texture un tableau d’octets en ordre BGRA, puis ne téléverse que ce rectangle — le canal économe en bande passante pour les mises à jour pixel par pixel à haute fréquence, voir Extensions Yanyang

Côté AWT, on utilise couramment : Color.decode / new Color, graphics.setColor / setFont / setStroke, drawRect / fillRect / drawRoundRect / fillRoundRect, drawImage / drawString, Font.deriveFont, GradientPaint, AffineTransform, setClip, AlphaComposite ; importez le tout avec l’importPackage(java.awt) de Rhino. Pour un guide, consultez la JavaDoc de Graphics2D.

Note

Le contenu d’une texture fraîchement créée n’est pas garanti propre (de la mémoire réutilisée peut afficher du bruit visuel) — faites un premier upload() après création pour imposer votre propre contenu.

Pour les besoins multi-écrans des véhicules, tournez-vous plutôt vers le DisplayHelper intégré (include(Resources.id("mtrsteamloco:scripts/display_helper.js"))) : une grande texture découpée en emplacements, des modèles générés automatiquement selon la configuration — voir la page Types de scripts.

Sons

SoundManager

Obtenu via le ctx.getSoundManager() de chaque type ; la position de référence dépend du type :

playLocalSound(id, volume, pitch, category="MASTER") (sans spatialisation, pour les annonces) · playSound(id, pos, volume, pitch, category="MASTER") (positionnée dans le monde, relativement à la position de référence) · play(soundInstance) / stop(soundInstance) (instances contrôlables).

TickableSoundInstance

Un effet sonore ponctuel, une fois joué, ne se contrôle plus ; pour régler le volume en cours de lecture ou interrompre, employez des instances contrôlables (annonces embarquées complexes, sons de moteur, musiques en boucle) :

static create(id, category) · setSoundVolume(v) / setSoundPitch(v) (1.0 est la référence) · setRepeatable(b) · setLoopDelay(tick) · setRelative(b) (volume constant en suivant le joueur) · setPos(v) (une boucle doit mettre à jour sa position frame par frame elle-même) · isPlaying(). La lecture passe par play() / play(delayTick) / play(ctx), avec abort() pour couper une instance en cours (retravaillé dans l’amont v2.3.0-prerelease.3). Une instance en boucle doit impérativement être arrêtée (stop) dans dispose.

Déprécié : setLoopable(b) — remplacé par setRepeatable(b) dans la refonte v2.3.0-prerelease.3 ; les scripts existants continuent de fonctionner.

Catégories de sons : MASTER BLOCKS MUSIC RECORDS WEATHER HOSTILE NEUTRAL PLAYERS AMBIENT VOICE.

Réseau et arrière-plan

Networking

static Networking.fetch(url, requestOption?): NetworkResponse<DataReader>. RequestOption est un simple objet JS : method (GET par défaut), connectTimeout / readTimeout (millisecondes), headers (objet), body (chaîne, Content-Length ajouté automatiquement).

NetworkResponse : getResponseCode() · success() (vrai dès qu’une réponse est parvenue — pour un succès métier, jugez avec ok(), c’est-à-dire 200–299) · getData() (null en cas d’échec) · exception() · getHeaders().

Les requêtes partent par défaut avec User-Agent: Joban Client Mod (https://jcm.joban.org), impossible à modifier par les voies normales (sauf si le joueur relâche les restrictions de scripts). Passez les requêtes réseau sur un thread d’arrière-plan (voir ci-dessous).

BackgroundWorker

static BackgroundWorker.submit(task) confie une tâche lambda à un exécuteur d’arrière-plan monothread — n’en abusez pas, les autres scripts y recourent aussi ; interceptez vous-même par try/catch les exceptions levées dans la tâche. Au rechargement du pack de ressources, la file d’attente est purgée et les tâches en cours interrompues ; un blocage finit par se résorber de lui-même.

BackgroundWorker.submit(() => {
    let resp = Networking.fetch("https://example.com/data.json");
    if (resp.ok()) {
        let str = resp.getData().asString();
        // après traitement, écrire dans state ; lu dans render
    }
});

Console

print(...) et console.log(...) sont équivalents (héritage NTE, à utiliser librement). L’API Console s’aligne sur les usages du Web, sans les méthodes de type table / profile :

console.log / warn / error / debug(...) (debug ne sort qu’en mode debug) · console.count(label="default") / countReset(label) (compteurs indépendants par étiquette) · console.time(label) / timeLog(label) / timeEnd(label) (chronomètres indépendants par étiquette). L’interpolation par substituants n’est pas prise en charge — les template literals suffisent.

Données MTR

MTR.ClientConfig (préférences du joueur)

isChatAnnouncementEnabled() · isTtsAnnouncementEnabled() · shouldHideTranslucentParts() · getLanguageDisplay() (NORMAL / CJK_ONLY / NON_CJK_ONLY) · getDynamicTextureResolution() (0–8) · getVehicleOscillationMultiplier() (multipliez par 10 pour un pourcentage) · getDefaultRail3D() · isCustomFontEnabled().

MTR.Data (données connues du client)

MTR 4 ne synchronise que les données proches — ne rien trouver au loin n’a rien d’étonnant, et bien des fonctions retournent null :

GroupeFonctions
Stations / dépôtsfindStation(pos) · getStation(id) · getKnownStations() ; findDepot(pos) · getDepot(id) · getKnownDepots()
LignesgetRoute(id) · getKnownRoutes() · getKnownRoutesPassingPlatform(platformId)
VéhiculesgetVehicle(vehicleId) · getPlayerMountedVehicle() · getKnownVehicles() · isPlayerMounted(id) · getVehicleMountDetail(): MountDetail (ridingCarIndex(): int, pos(): Vector3f relative au centre de la voiture — amont v2.3.0-prerelease.3)
AscenseursgetLift(id) · getPlayerMountedLift() · getKnownLifts() · getLiftFloors(tscLift): List<Floor> (les étages d’un ascenseur TSC — amont v2.3.0-prerelease.3)
RailsgetRailFromPath(pathData) · getKnownRails() · isRailBlocked(hexId) · getKnownBlockedRails() · getBlockedSignalColors(hexId) · getConnectedRails(pathData, front, back, excludeSelf = false) / getConnectedRails(pos) (les rails connectés à une extrémité de chemin / à la position d’un nœud de rail — amont v2.3.0-prerelease.3)
Quais / voies de garagegetPlatform(id) · getKnownPlatforms() · findNearbyPlatforms(pos, radius) ; getSiding(id) · getKnownSidings() · findNearbySidings(pos, radius)
ArrivéesgetArrivals(platformId | platformIds[]): ArrivalEntries — le même objet que pids.arrivals() des scripts PIDS

MTRClientData est une référence directe à la classe de données interne de MTR — un dernier recours : aucune promesse de stabilité, le contenu peut changer d’une version à l’autre.

Environnement Minecraft

MinecraftClient

worldIsRaining() · worldIsThundering() · worldIsRainingAt(pos) · worldDayTime() · blockLightAt(pos) · skyLightAt(pos) · lightAt(pos) (valeur empaquetée pour le rendu) · lightLevelAt(pos) · renderDistance() · localPlayer() · gamePaused() (la simulation TSC ne s’arrête pas avec la pause !) · narrate(msg) · displayMessage(msg, actionBar) (accepte aussi VanillaText) · spawnParticleInWorld(id, pos, velocity, alwaysSpawn=false) · getScoreboardScore(objective, player) · getWorldPlayers() · getCurrentWorldId() · getCameraMode() · getRedstoneLevel(pos) · getWorldBlockState(pos, stateName).

VanillaText (texte enrichi vanilla)

Construit les composants de texte vanilla du chat / de la barre d’action : literal(str) · translatable(key, ...) · append(other) · withBold() · withItalic() · withFont(id) · withColor(rgb | name) · clickToCopyText(str) · clickToOpenURL(url) · withHoverText(str | VanillaText) · getString() (retourne le résultat localisé).

VoxelShape (contours de bloc)

Pour les collisions / contours personnalisés des décorations : empty() · fullCube() · create(minX, minY, minZ, maxX, maxY, maxZ, facing?) (l’unité 16 = un bloc) · combine(other) ; à utiliser avec ctx.setOutlineShape(...) / ctx.setCollisionShape(...).

ItemStack / PlayerEntity

ItemStack : itemId() · translationId() · empty() · count(). PlayerEntity (en général issu de MinecraftClient.localPlayer() ou des événements) : uuid() · pos() / blockPos() / smoothPos() / velocity() · pitch() / yaw() / bodyYaw() · playerName() / displayName() · hasPermissionLevel(level) (information côté client, à ne pas prendre au sérieux) · mainHandItem() / offHandItem() / activeItem() / isHoldingItem(id) · isSneaking() / isSprinting() / isSwimming() / isCreative() / isSpectator().

Classes utilitaires

DataReader (décodage unifié)

Resources.read, Files.read et Networking.fetch le retournent tous — le décodeur d’une séquence d’octets :

asString(): String? (UTF-8) · asBufferedImage(): BufferedImage? · asFont(): Font? (TTF/OTF ; l’implémentation dépose un fichier dans le répertoire temporaire — en cas de disque saturé, nettoyez les résidus préfixés +~JF) · asByteArray(): byte[] · openInputStream(callback) (ferme le flux automatiquement) · asInputStream() (à fermer vous-même). Un échec de décodage retourne null et signale l’erreur dans la console.

Autres utilitaires

ClasseL’essentiel
Timingelapsed() (secondes de jeu écoulées, y compris en pause) · delta() (secondes depuis le dernier render — la base pour cadrer les animations sur le framerate) · currentTimeMillis() · nanoTime()
TextUtildécoupe le format de nommage 中文|English||附加 de MTR : getCjkParts / getNonCjkParts / getExtraParts / getNonExtraParts / getNonCjkAndExtraParts / isCjk / cycleString(src[, tick])
StateTrackersuivi des transitions d’état (pour éviter « redéclencher à chaque frame dès que la condition est remplie ») : setState(value): boolean (vrai uniquement en cas de changement) · stateNow() / stateLast() / stateNowDuration() / stateNowFirst() · changedTo(v) / changedFromTo(old, v) ; une instance par objet, à conserver dans state
CycleTrackercarrousel cadencé dans le temps : new CycleTracker(["route", 5, "next", 5]) + tick() · stateNow() / stateLast() / stateNowDuration() / stateNowFirst()
RateLimitbridage de cadence : new RateLimit(intervalSec) + if (rl.shouldUpdate()) { ... } ; resetCoolDown() fait arriver l’échéance immédiatement
Javaaide à l’interopérabilité Java : Java.newArray(class, length | dims), Java.toArray(class, list) — certaines méthodes AWT exigent de vrais tableaux Java

Fonctionnalités des scripts

include (inclusion entre scripts)

include(Resources.id("mtrsteamloco:scripts/display_helper.js"));  // chemin absolu
include("./util/common.js");                                     // relatif au script courant

Charge et exécute un autre fichier JS pendant la phase d’analyse (accepte un chemin relatif sous forme de chaîne, ou un Identifier).

Références croisées entre entrées de script

Une entrée de script qu’aucun contenu du même pack ne référence est refusée au chargement par défaut (pour prévenir un scriptId oublié) ; ajoutez "forceLoad": true à l’entrée pour la charger de force — utile pour partager une entrée de script entre packs, ou pour qu’une entrée MTR 3 emprunte une déclaration partagée MTR 4 ; attention à l’ordre de chargement des packs (le déclarant doit être chargé en premier).

Classes de compatibilité ANTE

SoundHelper (lecture de sons façon ANTE), TickableSound, GlobalRegister, ComponentUtil (utilitaires de composants de texte vanilla) et le asJavaArray(list, class) global sont disponibles depuis v2.3, avec des signatures identiques à ANTE, pour faciliter la migration du contenu ANTE.


Ensuite : Types de scripts JS — les API dédiées aux véhicules / décorations / ascenseurs / PIDS ; Extensions Yanyang — les capacités que cette branche ajoute par-dessus JS.