API
Creatures
A custom creature uses the body of a game creature (its model, animations, size and way of moving) with your texture painted on top, your stats, your behavior and your loot. You declare it like the rest of your content: a list of properties.
Declare a creature
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] } ]
}| Property | Values | Default |
|---|---|---|
body |
id of a game creature: minecraft:zombie, minecraft:wolf, minecraft:cow… |
required |
texture |
texture path, painted over the body's model: entity/ghost is the mod's textures/entity/ghost.png |
the body's look |
model |
your own 3D model: entity/robot is the mod's models/entity/robot.json (below) |
the body's model |
size |
[width, height] in blocks: what it collides with and where it is clicked (below) |
the body's |
health |
health points | the body's |
speed |
walking speed (a zombie moves at 0.23, a wolf at 0.3) | the body's |
attack |
melee attack damage | the body's |
follow_range |
how many blocks away it detects its targets | the body's |
behaviour |
list of behaviors, from most to least important (below) | the body's behavior |
targets |
who it attacks, in priority order (below) | nobody |
loot |
[{ item, count, chance }, …], same as for blocks: each item is rolled separately |
nothing |
spawns |
biomes where it appears on its own, with weight and group size (below) | it doesn't spawn on its own |
breed_item |
item that makes two of them breed (below) | can't be bred |
tame_item |
item that tames it (below) | can't be tamed |
rideable |
true lets players ride it (below) |
false |
Behaviors
The list is the priority: when two want to act at once, the earlier one wins. Write each one as a name, as { name: number } for its main setting, or as a map with all its settings.
| Behavior | What it does | Settings |
|---|---|---|
"swim" |
Stays afloat in water. | |
"look_around" |
Looks around when idle. | |
"wander", { wander: 0.8 } |
Wanders around. | speed, default 1 |
"look_at_players", { look_at_players: 10 } |
Looks at nearby players. | range in blocks, default 8 |
"melee_attack", { melee_attack: 1.2 } |
Chases and hits its target. | speed, default 1 |
"panic", { panic: 1.5 } |
Runs away when it takes damage. | speed, default 1.25 |
{ avoid: "minecraft:wolf", distance: 8, speed: 1.2 } |
Keeps away from that creature. | distance in blocks, speed |
{ follow: "minecraft:wheat", speed: 1 } |
Follows whoever holds that item. | speed |
{ ranged_attack: "minecraft:snowball", interval: 20, range: 14, damage: 3 } |
Shoots a projectile at its target (below). | projectile, interval, range, speed, power, damage |
"breed", { breed: 1 } |
Breeds with another of its kind once fed. | speed |
"follow_parent", { follow_parent: 1.1 } |
A baby stays close to its parent. | speed |
{ follow_owner: 1.2, distance: 8 } |
A tamed creature follows its owner. | speed, distance in blocks |
{ fly_around: 1 } |
Flies around; for flying bodies (parrot, bee, allay). | speed |
{ can_start: …, tick: … } |
Your own code (below). | can_start, tick, keep_going, moves |
Speed numbers multiply the creature's base speed: { wander: 0.8 } wanders a bit slower than it walks.
Targets
targets says who it attacks, from highest to lowest priority. "hurt_by" is whoever damages it; an entity id is the nearest entity of that kind ("minecraft:player" for players, "minecraft:pig" for pigs). For the attack to happen, the creature needs a behavior that performs it, such as "melee_attack".
Spawn it
command haunt requires "ghostmod.haunt" describe "Summon a ghost where you stand" {
if player == null { return "Players only" }
world().spawn("ghostmod:ghost", player.location)
return "&7A ghost appears…"
}The id is your mod's: ghostmod:ghost. The game command /summon ghostmod:ghost works too.
Appear on their own
Add spawns and the creature shows up in the world by itself, like the game's own creatures.
creature "ghost" {
body: "minecraft:zombie"
spawns: [ { biomes: ["minecraft:dark_forest", "#minecraft:is_forest"], weight: 20, group: [1, 2] } ]
}Each entry lists the biomes where it appears (an id, or a #tag for a whole group of biomes), a weight (how often, compared with the other creatures of that biome: a cow is 8, a zombie 95) and a group size range.
It follows the spawning rules of its body: with a zombie body it appears in the dark, with a cow body on grass in the light. This holds both when the world is generated and later on.
Spawn egg. Every creature also gets a spawn egg, its id plus _spawn_egg (ghost_spawn_egg), in the creative spawn eggs tab. Its texture is the mod's textures/item/ghost_spawn_egg.png if there is one; otherwise it looks like its body's egg.
In Kotlin:
content.creature("ghost") {
body = "minecraft:zombie"
spawn("minecraft:dark_forest", "#minecraft:is_forest", weight = 20, group = 1..2)
}Steer a creature from code
The creatures you declare, and any other mob, are a Creature. From an event, a command or a timer you can give them orders:
| Member | What it does |
|---|---|
target |
Who it is attacking. Read it or set it. |
moveTo(location, speed), move_to |
Walks to a location. The speed multiplies its normal speed. |
stop() |
Stops walking. |
isMoving, is_moving |
Whether it is walking somewhere. |
lookAt(location), look_at |
Turns to look at a location. |
canSee(entity), can_see |
Whether it has a clear line of sight to that entity. |
isBaby |
Whether it is a baby. |
ownerId |
The id of its owner, once tamed. |
tame(player) |
Makes that player its owner. |
isSitting |
Whether it is sitting. |
playAnimation(name), play_animation |
Plays one of its model's animations (see below). |
Every entity has a velocity, a Vector in blocks per tick. Read it or set it to push the entity: entity.velocity = vector(0, 0.6, 0) sends it upwards.
In CraftScript, a typed let narrows an entity to a creature. It is checked when it runs:
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!"
}Behaviours of your own
When the ready-made ones aren't enough, write one with your own code. It goes in the behaviour list like any other, so its position is its priority.
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: asked every few ticks; return whether it should begin.tick: runs every tick while the behaviour is active.keep_going: says whether to carry on. If omitted, it is the same ascan_start.moves:trueby default. A moving behaviour doesn't run together with another moving one; the earlier in the list wins. Usefalsefor behaviours that only look or react.
In Kotlin: Behaviour.Custom(canStart = { … }, tick = { … }, keepGoing = …, moves = true)
Animals: breed, tame, ride and fly
A few properties and behaviours turn a creature into an animal. This one breeds with apples, is tamed with a bone and can be ridden:
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 }]
}- Breed.
breed_itemplus the"breed"behaviour: fed that item, two of the same kind make a baby of that kind. It needs an animal body (cow, wolf, chicken…). Babies use"follow_parent"to stay close to their parents. - Tame.
tame_item: each try works one time in three. The owner is remembered, and a tamed creature never targets its owner. Sneak and use with an empty hand to make it sit or stand up.{ follow_owner: 1.2, distance: 8 }makes it follow its owner. - Ride.
rideable: true: use with an empty hand to climb on (once tamed, only its owner can). Steer it with the movement keys and the mouse; sneak to get off. - Fly.
{ fly_around: 1 }for flying bodies (parrot, bee, allay). Arideablecreature with a flying body climbs when its rider looks up and dives when the rider looks down.
In Kotlin: breedItem = …, tameItem = …, rideable = true and the behaviours Behaviour.Breed(), Behaviour.FollowParent(), Behaviour.FollowOwner(speed, distance) and Behaviour.FlyAround().
Projectiles of your own
Besides the game's projectiles, a mod can declare its own. It has its own damage, gravity and what happens when it lands:
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: damage dealt to what it hits.gravity:falsemakes it fly in a straight line.on_hit:fun(e), called when it lands, with the sameeas thehitevent:e.projectile,e.shooterande.entityore.block.texture: the projectile flies looking like its item, so by default it usestextures/item/<id>.png; settextureto use another.
Use it like any other projectile: world.shoot("mymod:frost_bolt", from, velocity, shooter), or in a creature, { ranged_attack: "mymod:frost_bolt" }. In Kotlin:
content.projectile("frost_bolt") {
damage = 4.0
gravity = false
onHit = { e -> /* … */ }
}Ranged attacks and projectiles
The ranged_attack behaviour makes a creature shoot. It closes in until its target is in range and in sight, then fires.
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
}
}| Setting | Meaning |
|---|---|
ranged_attack |
ranged_attack: the projectile (minecraft:arrow, minecraft:snowball, minecraft:small_fireball, minecraft:wind_charge…). |
interval |
interval: ticks between shots. |
range |
range: distance in blocks from which it shoots. |
speed |
speed: walking speed while it closes in. |
power |
power: how fast the projectile flies. |
damage |
damage: extra damage when it hits. |
To shoot from code, for creatures or for a player's ability, use world().shoot(projectile, from, velocity, shooter, damage).
In Kotlin:
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)The hit event (ProjectileHitEvent) fires when a projectile lands. It has e.projectile, e.shooter and either e.entity or e.block, whichever it hit. Cancel it and the projectile goes through. See Events.
Good to know
- Each body has its limits. Some game creatures lack a stat: a cow has no attack damage. If you set it, it is ignored and Crafting warns in the log.
- Bodies that don't walk. Bodies that can't find a path on their own ignore walking behaviors (wander, chase, panic, follow, avoid); the rest work.
- Without
behaviour, the creature behaves like the body it uses. As soon as you write the list, it only does what is in it. - The model only changes the look. Movement and behavior always come from the body, and so does its size unless you set
size. - A custom creature is a living entity like any other: it receives the
spawn,damageandentity_deathevents, hasdata, and you handle it with what's in The world and players.
In Kotlin
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)
}
}
}Behaviors: Behaviour.Swim, LookAround, Wander(speed), LookAtPlayers(range), MeleeAttack(speed), Panic(speed), Avoid(entity, distance, speed), Follow(item, speed). Targets: TargetRule.HurtBy and TargetRule.Nearest(id). Add loot with drop(item, count, chance), same as for blocks.
Your own 3D model
Add model and the creature is drawn with your model instead of the body's. The body still gives it its size, movement and behavior; the model only changes how it looks.
creature "robot" {
body: "minecraft:pig"
model: "entity/robot"
texture: "entity/robot"
behaviour: ["swim", { wander: 0.8 }, { look_at_players: 10 }]
}The model is the mod's models/entity/robot.json and its texture is textures/entity/robot.png. In Kotlin: creature("robot") { body = "minecraft:pig"; model = "entity/robot"; texture = "entity/robot" }. The format is the same across game versions.
{ "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" } }Sizes are in pixels (16 is one block), with y pointing up from the creature's feet.
- Bone:
name, an optionalparent(it moves with it),pivot(the point it turns around) andcubes. - Cube:
origin(its lowest corner),sizeanduv(where its texture starts in the image). The layout is the usual box one: a cube of width w, height h and depth d uses an area of 2(w+d) by (d+h) pixels. - Animations go per bone, as a name or a list of names:
| Animation | What it does |
|---|---|
look |
Turns where the creature looks; for heads. |
walk, walk_opposite |
Swings while walking; the second in opposite phase, for the other limb. |
idle |
A slight sway. |
spin |
Keeps turning. |
If a model can't be drawn, the creature looks like its body and the log says why.
Size
A creature is as big as its body. When your model is smaller or bigger, set size: [width, height] in blocks so what it collides with and where it is clicked match what players see:
creature "drake" {
body: "minecraft:bee"
model: "entity/drake"
texture: "entity/drake"
size: [1.4, 1.1]
}In Kotlin: size = 1.4 to 1.1.
Keyframed animations
For movement beyond the ready-made animations, add a clips section next to bones and animations:
{ "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] } } } }
} }- Each clip has a
lengthin seconds and, per bone, up to three channels:rotationin degrees,positionin pixels (y up) andscale(a number or[x, y, z]). - The keys are times in seconds. Values blend in a straight line between keys; add
"interpolation": "smooth"to a clip and it passes through its keys on a curve instead. A channel may also be a single value for the whole clip.
| Clip | When it plays |
|---|---|
walk |
Loops while it walks, in step with its feet. |
idle |
Loops while it stands still. |
attack |
Plays as it strikes. |
| Any other name | Plays when code asks: c.play_animation("roar"). Nearby players who have Crafting see it. |
"idle": { "length": 1.2, "interpolation": "smooth", "bones": {
"left_wing": { "rotation": { "0": [0, 0, -20], "0.6": [0, 0, 25], "1.2": [0, 0, -20] } } } }A clip started from code plays over walk, idle and attack instead of replacing them, and they add up: a creature can roar while it walks.
Babies of a creature with its own model are drawn at half size.
Textures
Without a model, the texture has the same layout as the chosen body's (a zombie, a wolf…), so you can start from a template for that body and paint over it. It goes inside the mod, like item and block textures:
| Mod | Where |
|---|---|
| CraftScript (folder) | mods/ghostmod/textures/entity/ghost.png |
| Kotlin or Java | src/main/resources/assets/ghostmod/textures/entity/ghost.png |