Aller au contenu principal

API de scripting

Les scripts sont des fichiers Rhai (.rhai) qui éditent le projet courant — générer du terrain, peindre des layers, placer des objets — avec un formulaire de paramètres optionnel affiché dans le panneau Scripts.

Structure d'un script

Un script peut définir quatre fonctions ; seule apply est obligatoire.

// Titre et description affichés dans le panneau Scripts (optionnel).
fn meta() {
#{
name: "Mon script",
description: "Ce que fait ce script.",
undo: true, // capture l'historique d'undo (défaut true ; false = plus rapide)
iterative: false, // si true, le panneau affiche un compteur d'itérations (voir plus bas)
}
}

// Formulaire d'entrée (optionnel). Voir « Paramètres ».
fn params() {
[
#{ id: "radius", label: "Rayon", type: "int", min: 1, max: 64, value: 8 },
]
}

// Ports de sortie (optionnel). Voir « Sorties ».
fn outputs() {
[
#{ id: "cells", label: "Cellules", type: "map2d" },
]
}

// Obligatoire. `map` est l'API d'édition, `p` contient les valeurs du formulaire
// par id (plus `p.iteration`, l'index 0-based de la passe en mode itératif).
fn apply(map, p) {
let r = p.radius;
}

Scripts itératifs

Avec iterative: true dans meta(), le panneau Scripts affiche un compteur d'itérations (1..100000) et apply s'exécute autant de fois. p.iteration est l'index 0-based de la passe courante. Entre deux passes, chaque sortie map2d est réinjectée dans l'entrée map2d de même id — un script peut ainsi transporter un état d'une itération à la suivante.

Paramètres

Chaque entrée de params() est un object map. La valeur initiale se met dans value (default est un mot réservé de Rhai).

typeClés en plusp[id] dans apply
intmin, max, valueentier
floatmin, max, valueflottant
boolvaluebooléen
textvaluechaîne
choiceoptions: [...], valuela chaîne de l'option sélectionnée
layerlayer_typeun map #{ kind, index, name }
colorvalue ("#rrggbb" ou [r, g, b])un map #{ r, g, b } (0–255)
map2dune carte 2D de luminance en lecture seule (voir plus bas)

Pour int et float, omettre min/max affiche un champ numérique libre au lieu d'un slider.

layer_type vaut "material", "cover", "biome", "object", "resource", "feature", "combined", "annotation" ou "any". Passez p[id].index aux fonctions d'édition ci-dessous (tous les types sauf matériaux et biomes sont 1-based).

Un input map2d s'alimente via le node Script de l'éditeur nodal (branchez n'importe quel champ scalaire sur son port) ; lancé depuis le panneau Scripts, il contient les contraintes de l'outil (1 là où la cellule les satisfait, 0 ailleurs).

Une valeur map2d expose :

FonctionDescription
m.width(), m.height()dimensions (width() == 0 = aucune carte fournie)
m.get(x, z)valeur de la cellule (0.0 hors bornes)
m.set(x, z, v)fixe la valeur (flottant ou entier)
m.neighbor_count(seuil)nouvelle map2d où chaque cellule contient le nombre de ses 8 voisins dont la valeur est >= seuil
m.neighbor_count_equal(valeur)nouvelle map2d comptant les 8 voisins dont la valeur égale valeur
m.neighbor_count_equal(valeur, wrap)idem, avec wrap = true pour des bords toroïdaux (les bords se recollent)
new_map2d(w, h)fonction libre créant une carte remplie de zéros

Sorties

outputs() déclare des ports de sortie (même forme d'object map que params(), avec type "map2d", "color" ou "material"). On les écrit dans apply :

FonctionDescription
map.set_output(id, map2d)écrit une sortie map2d
map.set_output_color(id, r, g, b)écrit une sortie couleur (0–255)
map.set_output_material(id, index)écrit une sortie index de matériau

Les sorties alimentent les ports de sortie du node Script dans l'éditeur nodal, et pilotent la boucle de feedback itérative (voir « Scripts itératifs »).

Node Script

Dans l'éditeur nodal, le node Script expose les inputs d'un script directement dans le graphe : les inputs int, float, color, map2d et layer de type material deviennent des ports d'entrée nommés (avec un widget intégré tant qu'ils ne sont pas connectés) ; les autres formes s'éditent dans le node. Le node n'est jamais évalué par l'aperçu en direct ni par Appliquer à la map — le script ne s'exécute que depuis le bouton du node.

L'API map

Les coordonnées sont x (ouest→est) et z (nord→sud), origine en 0,0. Les coordonnées hors-bornes sont ignorées.

Dimensions & bornes

FonctionRenvoie
map.width()largeur de la map en cellules
map.height()hauteur de la map en cellules
map.water_level()niveau d'eau global
map.min_height()hauteur minimale autorisée
map.max_height()hauteur maximale autorisée

Hauteurs

Les hauteurs sont des f64 (précision sous-bloc), bornées à [min_height, max_height].

FonctionDescription
map.get_height(x, z)hauteur de la cellule
map.set_height(x, z, h)fixe la hauteur
map.add_height(x, z, dh)ajoute dh à la hauteur
map.slope(x, z)pente locale en degrés

Matériau de surface

Index 0-based dans la palette des matériaux.

FonctionDescription
map.get_surface(x, z)index du matériau
map.set_surface(x, z, mat)fixe l'index du matériau
map.set_surface_mask(mask, mat_on)peint toute la surface depuis une map2d : cellule >= 0.5mat_on, sinon 0
map.set_surface_mask(mask, mat_on, mat_off)idem, avec un matériau mat_off explicite pour les cellules < 0.5
map.set_surface_mask(mask, mat_on, x0, z0, x1, z1)ne peint que le rectangle [x0..=x1, z0..=z1]

Un seul appel set_surface_mask prend un seul verrou pour toute la map, bien plus rapide qu'une boucle de set_surface par cellule.

Sélection

Expose la sélection active de l'outil pour qu'un script puisse restreindre son travail à la zone sélectionnée sans changer la taille de la map.

FonctionRenvoie
map.has_selection()true si une sélection « uniquement » non vide est active
map.selection_bounds()boîte englobante [x0, z0, x1, z1] (inclusive) ; la map entière si aucune sélection exploitable

Combinez selection_bounds() avec la forme rectangle de set_surface_mask pour ne traiter que la zone active.

Biome

Index 0-based dans la liste des biomes.

FonctionDescription
map.get_biome(x, z)index du biome
map.set_biome(x, z, id)fixe l'index du biome

Couvertures (ground covers)

1-based, empilables, alpha 0..=255 (défaut 255).

FonctionDescription
map.add_cover(x, z, id)ajoute une couverture (alpha 255)
map.add_cover(x, z, id, alpha)ajoute une couverture avec alpha
map.remove_cover(x, z, id)retire une couverture

Object layers

1-based, empilables ; mêmes signatures que les covers.

FonctionDescription
map.add_object(x, z, id)ajoute un objet (alpha 255)
map.add_object(x, z, id, alpha)ajoute un objet avec alpha
map.remove_object(x, z, id)retire un objet

Ressources

1-based, empilables ; mêmes signatures que les covers.

FonctionDescription
map.add_resource(x, z, id)ajoute une ressource (alpha 255)
map.add_resource(x, z, id, alpha)ajoute une ressource avec alpha
map.remove_resource(x, z, id)retire une ressource

Features

1-based, empilables ; mêmes signatures que les covers.

FonctionDescription
map.add_feature(x, z, id)ajoute une feature (alpha 255)
map.add_feature(x, z, id, alpha)ajoute une feature avec alpha
map.remove_feature(x, z, id)retire une feature

Combined layers

1-based, empilables ; mêmes signatures que les covers.

FonctionDescription
map.add_combined(x, z, id)ajoute un combined layer (alpha 255)
map.add_combined(x, z, id, alpha)ajoute un combined layer avec alpha
map.remove_combined(x, z, id)retire un combined layer

Annotations

1-based, une couleur par cellule (id = index dans les 16 couleurs fixes).

FonctionDescription
map.add_annotation(x, z, id)peint la couleur d'annotation (remplace)
map.remove_annotation(x, z)efface l'annotation de la cellule
map.set_annotation_mask(mask, on)peint depuis un map2d : cellule >= 0.5on, sinon efface
map.set_annotation_mask(mask, on, off)idem, avec une couleur off explicite pour < 0.5 (0 efface)
map.set_annotation_mask(mask, on, off, x0, z0, x1, z1)idem, borné au rectangle [x0..=x1, z0..=z1]
map.set_annotation_ids(states, x0, z0)stampe des ids d'annotation par cellule : chaque cellule de states peint l'id round(valeur) (0 efface) en (x0+lx, z0+lz)

Eau par cellule

FonctionDescription
map.get_water(x, z)niveau d'eau local (retombe sur le global)
map.set_water(x, z, level)fixe le niveau d'eau local
map.clear_water(x, z)retire l'eau locale

Recherche par nom

Renvoie l'index d'une entrée de palette, ou -1 si introuvable. Les index de covers et objets sont 1-based, comme add_*/remove_*.

FonctionRenvoie
map.material_index(name)index matériau 0-based
map.cover_index(name)index couverture 1-based
map.biome_index(name)index biome 0-based
map.object_index(name)index objet 1-based
map.resource_index(name)index ressource 1-based
map.feature_index(name)index feature 1-based
map.combined_index(name)index combined layer 1-based
map.annotation_index(name)index couleur d'annotation 1-based

Comptes de palette

map.material_count(), map.cover_count(), map.biome_count(), map.object_count(), map.resource_count(), map.feature_count(), map.combined_count(), map.annotation_count().

Matériau le plus proche

map.nearest_material(r, g, b) renvoie l'index de palette du matériau le plus proche (distance CIELAB) de la couleur sRGB donnée, ou -1 si la palette est vide. Comme le node « Bloc le plus proche », la couleur d'un matériau est la moyenne pondérée des couleurs de texture de ses blocs (repli sur la couleur d'aperçu si aucune texture n'est résolvable).

map.nearest_block_material(r, g, b) cherche parmi tous les blocs full-cube vanilla (comme le node Bloc le plus proche), réutilise ou crée l'entrée de palette correspondante et renvoie son index (-1 si la table des couleurs de blocs est indisponible ou si la palette est pleine).

Progression & annulation

FonctionDescription
map.report_progress(current, total, message)met à jour la barre de progression
map.is_cancelled()true si l'utilisateur a annulé

print(...) et debug(...) sont écrits dans le journal de l'application.

Exemple

Surélever un cône de terrain et peindre sa surface, avec une entrée de rayon :

fn meta() {
#{ name: "Surélever un cône", description: "Surélève un cône et peint de la pierre." }
}

fn params() {
[
#{ id: "radius", label: "Rayon", type: "int", min: 1, max: 128, value: 32 },
#{ id: "peak", label: "Hauteur du sommet", type: "float", min: 0.0, max: 256.0, value: 64.0 },
]
}

fn apply(map, p) {
let r = p.radius;
let cx = map.width() / 2;
let cz = map.height() / 2;
let stone = map.material_index("minecraft:stone");

for dz in -r..=r {
if map.is_cancelled() { return; }
map.report_progress(dz + r, 2 * r, "Surélévation du terrain...");
for dx in -r..=r {
let dist = ((dx * dx + dz * dz) as float).sqrt();
if dist <= r {
map.add_height(cx + dx, cz + dz, p.peak * (1.0 - dist / r));
if stone >= 0 { map.set_surface(cx + dx, cz + dz, stone); }
}
}
}
}