API

Créatures

Une créature personnalisée utilise le corps d’une créature du jeu (son modèle, ses animations, sa taille et sa façon de se déplacer) avec ta texture peinte par-dessus, tes statistiques, ton comportement et ton butin. Tu la déclares comme le reste de ton contenu : une liste de propriétés.

Déclarer une créature

content/creatures.craftCraftScript
creature "ghost" {
    body: "minecraft:zombie"
    texture: "entity/ghost"
    health: 40
    speed: 0.3
    attack: 4
    behaviour: ["swim", "melee_attack", { wander: 0.8 }, { look_at_players: 10 }, "look_around"]
    targets: ["hurt_by", "minecraft:pig"]
    loot: [ { item: "ghostmod:ecto", count: [1, 2] } ]
}
Propriété Valeurs Par défaut
body id d’une créature du jeu : minecraft:zombie, minecraft:wolf, minecraft:cow… obligatoire
texture chemin de la texture, peinte sur le modèle du corps : entity/ghost est le fichier textures/entity/ghost.png du mod l’apparence du corps
model ton propre modèle 3D : entity/robot est le fichier models/entity/robot.json du mod (voir plus bas) le modèle du corps
size [largeur, hauteur] en blocs : ce avec quoi elle entre en collision et où on peut cliquer dessus (plus bas) celle du corps
health points de vie ceux du corps
speed vitesse de marche (un zombie se déplace à 0.23, un loup à 0.3) celle du corps
attack dégâts d’attaque au corps à corps ceux du corps
follow_range à combien de blocs elle détecte ses cibles celle du corps
behaviour liste de comportements, du plus au moins important (voir plus bas) le comportement du corps
targets qui elle attaque, par ordre de priorité (voir plus bas) personne
loot [{ item, count, chance }, …], comme pour les blocs : chaque objet est tiré séparément rien
spawns biomes où elle apparaît seule, avec poids et taille de groupe (ci-dessous) n’apparaît pas seule
breed_item objet qui fait se reproduire deux d’entre elles (ci-dessous) ne se reproduit pas
tame_item objet qui l’apprivoise (ci-dessous) ne peut pas être apprivoisée
rideable true permet aux joueurs de la monter (ci-dessous) false

Comportements

La liste fixe la priorité : quand deux comportements veulent agir en même temps, le premier l’emporte. Écris chacun sous forme de nom, de { nom: nombre } pour son réglage principal, ou de map avec tous ses réglages.

Comportement Ce qu’il fait Réglages
"swim" Reste à la surface de l’eau.
"look_around" Regarde autour d’elle quand elle ne fait rien.
"wander", { wander: 0.8 } Se promène au hasard. speed, 1 par défaut
"look_at_players", { look_at_players: 10 } Regarde les joueurs proches. range en blocs, 8 par défaut
"melee_attack", { melee_attack: 1.2 } Poursuit sa cible et la frappe. speed, 1 par défaut
"panic", { panic: 1.5 } S’enfuit quand elle subit des dégâts. speed, 1.25 par défaut
{ avoid: "minecraft:wolf", distance: 8, speed: 1.2 } Se tient à l’écart de cette créature. distance en blocs, speed
{ follow: "minecraft:wheat", speed: 1 } Suit celui qui tient cet objet. speed
{ ranged_attack: "minecraft:snowball", interval: 20, range: 14, damage: 3 } Tire un projectile sur sa cible (ci-dessous). projectile, interval, range, speed, power, damage
"breed", { breed: 1 } Se reproduit avec une autre de son espèce une fois nourrie. speed
"follow_parent", { follow_parent: 1.1 } Un petit reste près de son parent. speed
{ follow_owner: 1.2, distance: 8 } Une créature apprivoisée suit son maître. speed, distance en blocs
{ fly_around: 1 } Vole çà et là ; pour les corps volants (perroquet, abeille, allay). speed
{ can_start: …, tick: … } Ton propre code (ci-dessous). can_start, tick, keep_going, moves

Les nombres de vitesse multiplient la vitesse de base de la créature : { wander: 0.8 } se promène un peu plus lentement qu’elle ne marche.

Cibles

targets dit qui elle attaque, de la priorité la plus haute à la plus basse. "hurt_by" est celui qui lui inflige des dégâts ; un id d’entité désigne l’entité de ce type la plus proche ("minecraft:player" pour les joueurs, "minecraft:pig" pour les cochons). Pour que l’attaque ait lieu, la créature a besoin d’un comportement qui l’effectue, comme "melee_attack".

La faire apparaître

commands/haunt.craftCraftScript
command haunt requires "ghostmod.haunt" describe "Fait apparaître un fantôme là où tu te trouves" {
    if player == null { return "Réservé aux joueurs" }
    world().spawn("ghostmod:ghost", player.location)
    return "&7Un fantôme apparaît…"
}

L’id est celui de ton mod : ghostmod:ghost. La commande du jeu /summon ghostmod:ghost fonctionne aussi.

Apparaître toutes seules

Ajoute spawns et la créature apparaît d’elle-même dans le monde, comme les créatures du jeu.

content/ghost.craftCraftScript
creature "ghost" {
    body: "minecraft:zombie"
    spawns: [ { biomes: ["minecraft:dark_forest", "#minecraft:is_forest"], weight: 20, group: [1, 2] } ]
}

Chaque entrée indique les biomes où elle apparaît (un id, ou un #tag pour tout un groupe de biomes), un weight (poids : la fréquence, par rapport aux autres créatures de ce biome ; une vache vaut 8, un zombie 95) et une plage de taille de group (groupe).

Elle suit les règles d’apparition de son corps : avec un corps de zombie, elle apparaît dans le noir ; avec un corps de vache, sur l’herbe, à la lumière. Cela vaut à la génération du monde comme après.

Œuf d’apparition. Chaque créature reçoit aussi un œuf d’apparition, son id plus _spawn_egg (ghost_spawn_egg), dans l’onglet créatif des œufs d’apparition. Sa texture est textures/item/ghost_spawn_egg.png du mod s’il existe ; sinon il ressemble à l’œuf de son corps.

En Kotlin :

content/Creatures.ktKotlin
content.creature("ghost") {
    body = "minecraft:zombie"
    spawn("minecraft:dark_forest", "#minecraft:is_forest", weight = 20, group = 1..2)
}

Diriger une créature depuis le code

Les créatures que tu déclares, et tout autre mob, sont une Creature. Depuis un événement, une commande ou un minuteur, tu peux leur donner des ordres :

Membre Ce qu’il fait
target Qui elle attaque. À lire ou à définir.
moveTo(location, speed), move_to Marche jusqu’à une position. La vitesse multiplie sa vitesse normale.
stop() Arrête de marcher.
isMoving, is_moving Si elle se rend quelque part.
lookAt(location), look_at Se tourne pour regarder une position.
canSee(entity), can_see Si elle a une ligne de vue dégagée vers cette entité.
isBaby Si c’est un petit.
ownerId L’id de son maître, une fois apprivoisée.
tame(player) Fait de ce joueur son maître.
isSitting Si elle est assise.
playAnimation(name), play_animation Joue l’une des animations de son modèle (voir ci-dessous).

Toute entité a une velocity, un Vector en blocs par tick. Lis-la ou définis-la pour pousser l’entité : entity.velocity = vector(0, 0.6, 0) la propulse vers le haut.

En CraftScript, un let typé restreint une entité à une créature. C’est vérifié à l’exécution :

commands/pup.craftCraftScript
command pup requires "dogmod.pup" describe "Get a pet dog" {
    if player == null { return "Players only" }
    let dog: Creature = world().spawn("dogmod:dog", player.location)
    dog.tame(player)
    dog.look_at(player.location)
    dog.velocity = vector(0, 0.6, 0)      // a little hop
    return "&7Good dog!"
}

Tes propres comportements

Quand ceux qui existent ne suffisent pas, écris-en un avec ton code. Il va dans la liste behaviour comme les autres : sa position est donc sa priorité.

content/herder.craftCraftScript
creature "herder" {
    body: "minecraft:wolf"
    targets: ["minecraft:pig"]
    behaviour: [
        "swim",
        {
            can_start: fun(c) { return c.target != null && c.can_see(c.target) },
            tick: fun(c) {
                if c.target != null {
                    c.look_at(c.target.location)
                    if !c.is_moving { c.move_to(c.target.location, 1.2) }
                }
            }
        },
        { wander: 1 }
    ]
}
  • can_start : demandé tous les quelques ticks ; renvoie s’il doit commencer.
  • tick : s’exécute à chaque tick tant que le comportement est actif.
  • keep_going : dit s’il doit continuer. Si omis, c’est identique à can_start.
  • moves : true par défaut. Un comportement qui bouge ne s’exécute pas en même temps qu’un autre qui bouge ; celui qui est plus haut dans la liste l’emporte. Utilise false pour ceux qui ne font que regarder ou réagir.

En Kotlin : Behaviour.Custom(canStart = { … }, tick = { … }, keepGoing = …, moves = true)

Animaux : élever, apprivoiser, monter et voler

Quelques propriétés et comportements transforment une créature en animal. Celle-ci se reproduit avec des pommes, s’apprivoise avec un os et peut être montée :

content/mooble.craftCraftScript
creature "mooble" {
    body: "minecraft:cow"
    tame_item: "minecraft:bone"
    breed_item: "minecraft:apple"
    rideable: true
    behaviour: ["swim", { breed: 1 }, { follow_parent: 1.1 }, { follow_owner: 1.2, distance: 8 }, { wander: 0.8 }]
}
  • Élever. breed_item plus le comportement "breed" : nourries avec cet objet, deux créatures de la même espèce donnent un petit de cette espèce. Il faut un corps d’animal (vache, loup, poule…). Les petits utilisent "follow_parent" pour rester près de leurs parents.
  • Apprivoiser. tame_item : chaque essai réussit une fois sur trois. Le maître est mémorisé, et une créature apprivoisée ne cible jamais son maître. Accroupi, utilise à main vide pour la faire s’asseoir ou se lever. { follow_owner: 1.2, distance: 8 } la fait suivre son maître.
  • Monter. rideable: true : utilise à main vide pour grimper (une fois apprivoisée, seul son maître le peut). On la dirige avec les touches de déplacement et la souris ; accroupis-toi pour descendre.
  • Voler. { fly_around: 1 } pour les corps volants (perroquet, abeille, allay). Une créature rideable au corps volant monte quand son cavalier regarde vers le haut et pique quand il regarde vers le bas.

En Kotlin : breedItem = …, tameItem = …, rideable = true et les comportements Behaviour.Breed(), Behaviour.FollowParent(), Behaviour.FollowOwner(speed, distance) et Behaviour.FlyAround().

Tes propres projectiles

En plus de ceux du jeu, un mod peut déclarer ses propres projectiles. Il a ses propres dégâts, sa gravité et ce qui se passe quand il atterrit :

content/frost_bolt.craftCraftScript
projectile "frost_bolt" {
    damage: 4
    gravity: false
    on_hit: fun(e) {
        let at = e.entity?.location ?? e.block?.location
        if at != null { e.projectile.world.spawn_particle("minecraft:snowflake", at.add(0.5, 1, 0.5), 12, 0.4, 0.02) }
    }
}
  • damage : les dégâts infligés à ce qu’il touche.
  • gravity : false le fait voler en ligne droite.
  • on_hit : fun(e), appelée quand il atterrit, avec le même e que l’événement hit : e.projectile, e.shooter et e.entity ou e.block.
  • texture : le projectile vole avec l’apparence de son objet ; par défaut il utilise donc textures/item/<id>.png ; renseigne texture pour en utiliser une autre.

Utilise-le comme n’importe quel autre projectile : world.shoot("mymod:frost_bolt", from, velocity, shooter), ou, dans une créature, { ranged_attack: "mymod:frost_bolt" }. En Kotlin :

content/FrostBolt.ktKotlin
content.projectile("frost_bolt") {
    damage = 4.0
    gravity = false
    onHit = { e -> /* … */ }
}

Attaques à distance et projectiles

Le comportement ranged_attack fait tirer une créature. Elle s’approche jusqu’à ce que sa cible soit à portée et en vue, puis tire.

content/frost_spirit.craftCraftScript
creature "frost_spirit" {
    body: "minecraft:snow_golem"
    behaviour: [{ ranged_attack: "minecraft:snowball", interval: 20, range: 14, damage: 3 }, { wander: 0.6 }]
    targets: ["minecraft:zombie", "hurt_by"]
}

on hit(e) {
    if e.shooter?.type == "frostmod:frost_spirit" && e.entity != null {
        e.entity.velocity = vector(0, 0.2, 0)      // knocked up
    }
}
Réglage Signification
ranged_attack ranged_attack : le projectile (minecraft:arrow, minecraft:snowball, minecraft:small_fireball, minecraft:wind_charge…).
interval interval : ticks entre deux tirs.
range range : distance en blocs à partir de laquelle elle tire.
speed speed : vitesse de marche pendant qu’elle s’approche.
power power : vitesse de vol du projectile.
damage damage : dégâts supplémentaires au toucher.

Pour tirer depuis le code, pour des créatures ou pour la capacité d’un joueur, utilise world().shoot(projectile, from, velocity, shooter, damage).

En Kotlin :

content/FrostSpirit.ktKotlin
creature("frost_spirit") {
    body = "minecraft:snow_golem"
    behaviour(Behaviour.RangedAttack(Identifier.parse("minecraft:snowball"), interval = 20, range = 14.0, damage = 3.0))
    target(TargetRule.Nearest(Identifier.parse("minecraft:zombie")))
}

// From code, e.g. a player's ability:
world.shoot(Identifier.parse("minecraft:small_fireball"), from, Vector(0.0, 0.0, 1.5), shooter = player, damage = 4.0)

L’événement hit (ProjectileHitEvent) se déclenche quand un projectile touche. Il a e.projectile, e.shooter et e.entity ou e.block, selon ce qui a été touché. Annule-le et le projectile traverse. Voir Événements.

Bon à savoir

  • Chaque corps a ses limites. Certaines créatures du jeu n’ont pas toutes les statistiques : une vache n’a pas de dégâts d’attaque. Si tu en définis, ils sont ignorés et Crafting prévient dans le journal.
  • Les corps qui ne marchent pas. Les corps qui ne savent pas trouver un chemin seuls ignorent les comportements de déplacement (wander, poursuite, panic, follow, avoid) ; les autres fonctionnent.
  • Sans behaviour, la créature se comporte comme le corps qu’elle utilise. Dès que tu écris la liste, elle ne fait que ce qu’elle contient.
  • Le modèle ne change que l’apparence. Le déplacement et le comportement viennent toujours du corps, et la taille aussi, sauf si tu définis size.
  • Une créature personnalisée est une entité vivante comme les autres : elle reçoit les événements spawn, damage et entity_death, a des data, et tu la manipules avec ce qui se trouve dans Le monde et les joueurs.

En Kotlin

content/Creatures.ktKotlin
package com.example.rubies.content

object Creatures {
    fun register(content: ContentBuilder) {
        content.creature("ruby_golem") {
            body = "minecraft:zombie"
            texture = "entity/ruby_golem"
            health = 60.0
            speed = 0.25
            attackDamage = 6.0
            behaviour(Behaviour.Swim)
            behaviour(Behaviour.MeleeAttack())
            behaviour(Behaviour.Wander(0.6))
            behaviour(Behaviour.LookAtPlayers(12f))
            behaviour(Behaviour.LookAround)
            target(TargetRule.HurtBy)
            target(TargetRule.Nearest(Identifier.parse("minecraft:player")))
            drop(Items.RUBY, 2..4)
        }
    }
}

Comportements : Behaviour.Swim, LookAround, Wander(speed), LookAtPlayers(range), MeleeAttack(speed), Panic(speed), Avoid(entity, distance, speed), Follow(item, speed). Cibles : TargetRule.HurtBy et TargetRule.Nearest(id). Ajoute du butin avec drop(item, count, chance), comme pour les blocs.

Ton propre modèle 3D

Ajoute model et la créature est dessinée avec ton modèle au lieu de celui du corps. Le corps lui donne toujours sa taille, son déplacement et son comportement ; le modèle ne change que son apparence.

content/robot.craftCraftScript
creature "robot" {
    body: "minecraft:pig"
    model: "entity/robot"
    texture: "entity/robot"
    behaviour: ["swim", { wander: 0.8 }, { look_at_players: 10 }]
}

Le modèle est le fichier models/entity/robot.json du mod et sa texture est textures/entity/robot.png. En Kotlin : creature("robot") { body = "minecraft:pig"; model = "entity/robot"; texture = "entity/robot" }. Le format est le même d’une version du jeu à l’autre.

models/entity/robot.jsonJSON
{ "texture_size": [64, 64],
  "bones": [
    { "name": "body", "pivot": [0, 6, 0], "cubes": [ { "origin": [-5, 6, -3], "size": [10, 10, 6], "uv": [0, 0] } ] },
    { "name": "head", "parent": "body", "pivot": [0, 16, 0], "cubes": [ { "origin": [-4, 16, -4], "size": [8, 8, 8], "uv": [0, 16] } ] },
    { "name": "left_leg", "pivot": [2.5, 6, 0], "cubes": [ { "origin": [1, 0, -1.5], "size": [3, 6, 3], "uv": [32, 0] } ] },
    { "name": "right_leg", "pivot": [-2.5, 6, 0], "cubes": [ { "origin": [-4, 0, -1.5], "size": [3, 6, 3], "uv": [32, 16] } ] }
  ],
  "animations": { "head": "look", "left_leg": "walk", "right_leg": "walk_opposite", "body": "idle" } }

Les tailles sont en pixels (16 correspond à un bloc), avec y qui monte à partir des pieds de la créature.

  • Os : name, un parent facultatif (il bouge avec lui), pivot (le point autour duquel il tourne) et cubes.
  • Cube : origin (son coin le plus bas), size et uv (l’endroit où sa texture commence dans l’image). La disposition est celle des boîtes habituelles : un cube de largeur w, hauteur h et profondeur d utilise une zone de 2(w+d) sur (d+h) pixels.
  • Les animations se placent par os, sous forme d’un nom ou d’une liste de noms :
Animation Ce qu’elle fait
look Se tourne là où regarde la créature ; pour les têtes.
walk, walk_opposite Se balance pendant la marche ; la seconde en opposition de phase, pour l’autre membre.
idle Un léger balancement.
spin Tourne sans arrêt.

Si un modèle ne peut pas être dessiné, la créature ressemble à son corps et le journal explique pourquoi.

Taille

Une créature a la taille de son corps. Quand ton modèle est plus petit ou plus grand, renseigne size: [largeur, hauteur] en blocs pour que ce avec quoi elle entre en collision et l’endroit où l’on clique correspondent à ce que voient les joueurs :

content/drake.craftCraftScript
creature "drake" {
    body: "minecraft:bee"
    model: "entity/drake"
    texture: "entity/drake"
    size: [1.4, 1.1]
}

En Kotlin : size = 1.4 to 1.1.

Animations par images clés

Pour des mouvements au-delà des animations prêtes à l’emploi, ajoute une section clips à côté de bones et animations :

models/entity/robot.jsonJSON
{ "bones": [ … ],
  "animations": { … },
  "clips": {
    "idle": { "length": 2.0, "bones": { "head": { "position": { "0": [0, 0, 0], "1": [0, 0.6, 0], "2": [0, 0, 0] } } } },
    "walk": { "length": 1.0, "bones": { "body": { "rotation": { "0": [0, 0, -6], "0.5": [0, 0, 6], "1": [0, 0, -6] } } } },
    "roar": { "length": 1.5, "bones": {
      "head": { "rotation": { "0": [0, 0, 0], "0.4": [-35, 0, 0], "1.1": [-35, 0, 0], "1.5": [0, 0, 0] },
                "scale": { "0": 1, "0.4": 1.35, "1.1": 1.35, "1.5": 1 } },
      "body": { "position": { "0": [0, 0, 0], "0.3": [0, 4, 0], "0.6": [0, 0, 0] } } } }
  } }
  • Chaque clip a une length (durée) en secondes et, par os, jusqu’à trois canaux : rotation en degrés, position en pixels (y vers le haut) et scale (un nombre ou [x, y, z]).
  • Les clés sont des instants en secondes. Les valeurs se mélangent en ligne droite entre les clés ; ajoute "interpolation": "smooth" à un clip et il passe par ses clés en suivant une courbe. Un canal peut aussi être une seule valeur pour tout le clip.
Clip Quand il se joue
walk Boucle tant qu’elle marche, au rythme de ses pattes.
idle Boucle tant qu’elle reste immobile.
attack Se joue quand elle frappe.
Tout autre nom Se joue quand le code le demande : c.play_animation("roar"). Les joueurs proches qui ont Crafting la voient.
Smooth clipJSON
"idle": { "length": 1.2, "interpolation": "smooth", "bones": {
  "left_wing": { "rotation": { "0": [0, 0, -20], "0.6": [0, 0, 25], "1.2": [0, 0, -20] } } } }

Un clip lancé depuis le code se joue par-dessus walk, idle et attack au lieu de les remplacer, et ils s’additionnent : une créature peut rugir tout en marchant.

Les petits d’une créature avec son propre modèle sont dessinés à moitié taille.

Textures

Sans modèle, la texture a la même disposition que celle du corps choisi (un zombie, un loup…), tu peux donc partir d’un modèle de texture pour ce corps et peindre par-dessus. Elle va dans le mod, comme les textures des objets et des blocs :

Mod Où
CraftScript (dossier) mods/ghostmod/textures/entity/ghost.png
Kotlin ou Java src/main/resources/assets/ghostmod/textures/entity/ghost.png