API

몹

사용자 정의 몹은 게임 속 몹의 몸(모델, 애니메이션, 크기, 움직이는 방식)을 사용하고, 그 위에 당신의 텍스처를 입히고, 당신의 능력치, 행동, 전리품을 더합니다. 나머지 콘텐츠처럼 속성 목록으로 선언합니다.

몹 선언하기

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] } ]
}
속성 값 기본값
body 게임 속 몹의 id: minecraft:zombie, minecraft:wolf, minecraft:cow… 필수
texture 몸의 모델 위에 입히는 텍스처 경로: entity/ghost는 모드의 textures/entity/ghost.png 몸의 원래 모습
model 나만의 3D 모델: entity/robot은 모드의 models/entity/robot.json(아래 참고) 몸의 모델
size 블록 단위의 [width, height]: 충돌하는 범위와 클릭되는 범위(아래 참고) 몸의 값
health 체력 몸의 값
speed 걷는 속도(좀비는 0.23, 늑대는 0.3) 몸의 값
attack 근접 공격 피해 몸의 값
follow_range 몇 블록 떨어진 대상까지 감지하는지 몸의 값
behaviour 가장 중요한 것부터 순서대로 놓은 행동 목록(아래 참고) 몸의 행동
targets 우선순위대로 정한 공격 대상(아래 참고) 없음
loot [{ item, count, chance }, …], 블록과 같습니다. 각 아이템은 따로 추첨됩니다 없음
spawns 저절로 나타나는 바이옴, 가중치와 그룹 크기 포함 (아래) 저절로 나타나지 않음
breed_item 두 마리를 번식시키는 아이템 (아래) 번식하지 않음
tame_item 길들이는 아이템 (아래) 길들일 수 없음
rideable true이면 플레이어가 탈 수 있음 (아래) false

행동

목록의 순서가 곧 우선순위입니다. 두 행동이 동시에 하려 하면 앞에 있는 것이 이깁니다. 각 행동은 이름으로, 주요 설정을 담은 { 이름: 숫자 }로, 또는 모든 설정을 담은 맵으로 적습니다.

행동 하는 일 설정
"swim" 물 위에 떠 있습니다.
"look_around" 할 일이 없을 때 주위를 둘러봅니다.
"wander", { wander: 0.8 } 이리저리 돌아다닙니다. speed, 기본값 1
"look_at_players", { look_at_players: 10 } 근처 플레이어를 바라봅니다. range(블록 단위), 기본값 8
"melee_attack", { melee_attack: 1.2 } 대상을 쫓아가 때립니다. speed, 기본값 1
"panic", { panic: 1.5 } 피해를 입으면 도망칩니다. speed, 기본값 1.25
{ avoid: "minecraft:wolf", distance: 8, speed: 1.2 } 그 몹을 피합니다. distance(블록 단위), speed
{ follow: "minecraft:wheat", speed: 1 } 그 아이템을 든 사람을 따라갑니다. speed
{ ranged_attack: "minecraft:snowball", interval: 20, range: 14, damage: 3 } 목표를 향해 투사체를 쏩니다 (아래). projectile, interval, range, speed, power, damage
"breed", { breed: 1 } 먹이를 먹으면 같은 종류와 번식합니다. speed
"follow_parent", { follow_parent: 1.1 } 새끼가 부모 곁에 머뭅니다. speed
{ follow_owner: 1.2, distance: 8 } 길들여진 몹이 주인을 따라다닙니다. speed, distance(블록 수)
{ fly_around: 1 } 날아다닙니다. 나는 몸(앵무새, 벌, 알레이)용입니다. speed
{ can_start: …, tick: … } 직접 작성한 코드 (아래). can_start, tick, keep_going, moves

속도 숫자는 몹의 기본 속도에 곱해집니다. { wander: 0.8 }은 걷는 속도보다 조금 느리게 돌아다닙니다.

공격 대상

targets는 누구를 공격할지 우선순위가 높은 순서대로 정합니다. "hurt_by"는 자신에게 피해를 준 대상이고, 엔티티 id는 그 종류 중 가장 가까운 엔티티입니다(플레이어는 "minecraft:player", 돼지는 "minecraft:pig"). 실제로 공격하려면 "melee_attack"처럼 공격을 수행하는 행동이 필요합니다.

소환하기

commands/haunt.craftCraftScript
command haunt requires "ghostmod.haunt" describe "서 있는 자리에 유령 소환" {
    if player == null { return "플레이어만 사용할 수 있습니다" }
    world().spawn("ghostmod:ghost", player.location)
    return "&7유령이 나타났습니다…"
}

id는 내 모드의 것입니다: ghostmod:ghost. 게임 명령어 /summon ghostmod:ghost도 작동합니다.

저절로 나타나게 하기

spawns를 추가하면 게임의 몹처럼 몹이 월드에 저절로 나타납니다.

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

각 항목에는 나타날 biomes(id, 또는 바이옴 그룹 전체를 뜻하는 #태그), weight(가중치: 그 바이옴의 다른 몹에 비해 얼마나 자주 나타나는지. 소는 8, 좀비는 95), 그리고 group 크기 범위를 적습니다.

몸의 스폰 규칙을 따릅니다. 좀비 몸이면 어두운 곳에, 소 몸이면 밝은 풀밭에 나타납니다. 월드를 생성할 때도, 그 이후에도 마찬가지입니다.

스폰 알. 모든 몹에는 id 뒤에 _spawn_egg를 붙인 스폰 알(ghost_spawn_egg)이 크리에이티브 스폰 알 탭에 생깁니다. 모드에 textures/item/ghost_spawn_egg.png가 있으면 그것이 텍스처가 되고, 없으면 몸의 스폰 알과 같은 모습입니다.

Kotlin에서:

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

코드로 몹 조종하기

선언한 몹과 다른 모든 몹은 Creature입니다. 이벤트, 명령어, 타이머에서 명령을 내릴 수 있습니다.

멤버 하는 일
target 공격 중인 대상. 읽거나 설정할 수 있습니다.
moveTo(location, speed), move_to 지정한 위치까지 걸어갑니다. speed는 평소 속도에 곱해집니다.
stop() 걷기를 멈춥니다.
isMoving, is_moving 어딘가로 걸어가는 중인지 여부.
lookAt(location), look_at 지정한 위치를 바라봅니다.
canSee(entity), can_see 그 엔티티까지 시야가 트여 있는지 여부.
isBaby 새끼인지 여부.
ownerId 길들여진 뒤 주인의 id.
tame(player) 그 플레이어를 주인으로 삼습니다.
isSitting 앉아 있는지 여부.
playAnimation(name), play_animation 모델의 애니메이션 하나를 재생합니다 (아래 참고).

모든 엔티티에는 틱당 블록 수로 나타내는 Vector인 velocity가 있습니다. 읽거나 설정해서 엔티티를 밀어낼 수 있습니다. entity.velocity = vector(0, 0.6, 0)은 위로 쏘아 올립니다.

CraftScript에서는 타입을 붙인 let이 엔티티를 몹으로 좁혀 줍니다. 실행할 때 검사됩니다.

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!"
}

나만의 행동

준비된 행동으로 부족하면 직접 코드로 작성하세요. 다른 행동처럼 behaviour 목록에 넣으며, 위치가 곧 우선순위입니다.

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: 몇 틱마다 호출됩니다. 시작해야 하는지 반환하세요.
  • tick: 행동이 활성인 동안 매 틱 실행됩니다.
  • keep_going: 계속할지 알려 줍니다. 생략하면 can_start와 같습니다.
  • moves: 기본값은 true입니다. 움직이는 행동은 다른 움직이는 행동과 함께 실행되지 않으며, 목록에서 앞에 있는 것이 이깁니다. 보기만 하거나 반응만 하는 행동에는 false를 쓰세요.

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

동물: 번식, 길들이기, 타기, 날기

몇 가지 속성과 행동으로 몹을 동물로 만들 수 있습니다. 이 몹은 사과로 번식하고, 뼈로 길들일 수 있으며, 탈 수 있습니다.

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 }]
}
  • 번식. breed_item과 행동 "breed": 그 아이템을 먹이면 같은 종류 두 마리가 그 종류의 새끼를 낳습니다. 동물 몸(소, 늑대, 닭 등)이 필요합니다. 새끼는 "follow_parent"로 부모 곁에 머뭅니다.
  • 길들이기. tame_item: 세 번 시도하면 한 번 성공합니다. 주인이 기억되고, 길들여진 몹은 주인을 절대 공격 대상으로 삼지 않습니다. 웅크린 채 빈손으로 사용하면 앉거나 일어납니다. { follow_owner: 1.2, distance: 8 }은 주인을 따라다니게 합니다.
  • 타기. rideable: true: 빈손으로 사용해 올라탑니다(길들인 뒤에는 주인만 가능). 이동 키와 마우스로 조종하고, 웅크리면 내립니다.
  • 날기. 나는 몸(앵무새, 벌, 알레이)에는 { fly_around: 1 }. rideable인 나는 몸의 몹은 탄 사람이 위를 보면 올라가고 아래를 보면 내려갑니다.

Kotlin에서: breedItem = …, tameItem = …, rideable = true, 그리고 행동 Behaviour.Breed(), Behaviour.FollowParent(), Behaviour.FollowOwner(speed, distance), Behaviour.FlyAround().

나만의 투사체

게임의 투사체 외에도 모드가 자체 투사체를 선언할 수 있습니다. 피해, 중력, 어딘가에 맞았을 때의 동작을 직접 정합니다.

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: 맞은 대상에게 주는 피해.
  • gravity: false면 직선으로 날아갑니다.
  • on_hit: fun(e). 맞았을 때 호출되며, hit 이벤트와 같은 e를 받습니다: e.projectile, e.shooter, 그리고 e.entity 또는 e.block.
  • texture: 투사체는 그 아이템의 모습으로 날아가므로 기본적으로 textures/item/<id>.png를 씁니다. 다른 것을 쓰려면 texture를 지정하세요.

다른 투사체처럼 사용합니다: world.shoot("mymod:frost_bolt", from, velocity, shooter), 몹에서는 { ranged_attack: "mymod:frost_bolt" }. Kotlin에서:

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

원거리 공격과 투사체

행동 ranged_attack은 몹이 투사체를 쏘게 합니다. 목표가 사거리 안에 들어오고 시야에 보일 때까지 다가간 뒤 발사합니다.

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
    }
}
설정 의미
ranged_attack ranged_attack: 투사체(minecraft:arrow, minecraft:snowball, minecraft:small_fireball, minecraft:wind_charge 등).
interval interval: 발사 사이의 틱 수.
range range: 쏘기 시작하는 거리(블록).
speed speed: 다가갈 때의 걷기 속도.
power power: 투사체가 날아가는 속도.
damage damage: 명중 시 추가 피해.

코드에서 쏘려면(몹이든 플레이어의 능력이든) world().shoot(projectile, from, velocity, shooter, damage)를 사용하세요.

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)

hit 이벤트(ProjectileHitEvent)는 투사체가 무언가에 맞았을 때 발생합니다. e.projectile, e.shooter, 그리고 맞은 대상에 따라 e.entity 또는 e.block이 있습니다. 취소하면 투사체가 그대로 통과합니다. 이벤트를 참고하세요.

알아 두면 좋은 점

  • 몸마다 한계가 있습니다. 어떤 몹은 특정 능력치가 없습니다. 예를 들어 소에는 공격 피해가 없습니다. 이를 설정하면 무시되고 Crafting이 로그에 경고합니다.
  • 걷지 않는 몸. 스스로 경로를 찾지 못하는 몸은 걷는 행동(돌아다니기, 쫓기, 도망치기, 따라가기, 피하기)을 무시하고, 나머지는 작동합니다.
  • behaviour가 없으면 몹은 사용하는 몸처럼 행동합니다. 목록을 적는 순간, 목록에 있는 것만 합니다.
  • 모델은 겉모습만 바꿉니다. 움직임과 행동은 언제나 몸의 것이고, 크기도 size를 지정하지 않으면 몸의 것입니다.
  • 사용자 정의 몹은 다른 것과 똑같은 생명체 엔티티입니다. spawn, damage, entity_death 이벤트를 받고, data를 가지며, 월드와 플레이어에 있는 기능으로 다룹니다.

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)
        }
    }
}

행동: Behaviour.Swim, LookAround, Wander(speed), LookAtPlayers(range), MeleeAttack(speed), Panic(speed), Avoid(entity, distance, speed), Follow(item, speed). 공격 대상: TargetRule.HurtBy와 TargetRule.Nearest(id). 전리품은 블록과 마찬가지로 drop(item, count, chance)로 추가합니다.

나만의 3D 모델

model을 추가하면 몹이 몸의 모델 대신 당신의 모델로 그려집니다. 크기, 움직임, 행동은 여전히 몸에서 가져오며, 모델은 겉모습만 바꿉니다.

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

모델은 모드의 models/entity/robot.json이고 텍스처는 textures/entity/robot.png입니다. Kotlin에서는 creature("robot") { body = "minecraft:pig"; model = "entity/robot"; texture = "entity/robot" }. 형식은 게임 버전이 바뀌어도 같습니다.

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" } }

크기는 픽셀 단위(16이 블록 하나)이고, y는 몹의 발에서 위쪽을 가리킵니다.

  • 본(bone): name, 선택 사항인 parent(함께 움직임), pivot(회전의 중심점), cubes.
  • 큐브: origin(가장 낮은 모서리), size, uv(이미지에서 텍스처가 시작되는 위치). 배치는 흔히 쓰는 상자 전개도 방식입니다. 너비 w, 높이 h, 깊이 d인 큐브는 2(w+d) × (d+h) 픽셀의 영역을 사용합니다.
  • 애니메이션은 본마다 이름 하나 또는 이름 목록으로 지정합니다:
애니메이션 하는 일
look 몹이 바라보는 쪽으로 돌립니다. 머리용.
walk, walk_opposite 걸을 때 흔들립니다. 두 번째는 반대 위상으로, 반대편 팔다리용.
idle 살짝 흔들립니다.
spin 계속 돕니다.

모델을 그릴 수 없으면 몹은 몸의 모습으로 나타나고 로그에 이유가 남습니다.

크기

몹은 몸과 같은 크기입니다. 모델이 더 작거나 크다면 size: [width, height]를 블록 단위로 지정해, 충돌하는 범위와 클릭되는 범위를 플레이어에게 보이는 모습에 맞추세요.

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

Kotlin에서: size = 1.4 to 1.1.

키프레임 애니메이션

준비된 애니메이션 이상의 움직임이 필요하면 bones, animations 옆에 clips 섹션을 추가하세요.

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] } } } }
  } }
  • 각 클립에는 초 단위의 length(길이)가 있고, 본마다 최대 세 개의 채널이 있습니다. rotation(도), position(픽셀, y가 위), scale(숫자 또는 [x, y, z])입니다.
  • 키는 초 단위 시간입니다. 키 사이의 값은 직선으로 섞입니다. 클립에 "interpolation": "smooth"를 추가하면 대신 키를 지나는 곡선으로 섞입니다. 채널은 클립 전체에 하나의 값만 둘 수도 있습니다.
클립 재생되는 때
walk 걷는 동안 발걸음에 맞춰 반복됩니다.
idle 가만히 서 있는 동안 반복됩니다.
attack 공격할 때 재생됩니다.
그 밖의 이름 코드가 요청할 때 재생됩니다: c.play_animation("roar"). Crafting을 사용하는 근처 플레이어에게 보입니다.
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] } } } }

코드에서 시작한 클립은 walk, idle, attack을 대체하지 않고 그 위에서 재생되며 서로 더해집니다. 몹이 걸으면서 울부짖을 수 있습니다.

자체 모델을 가진 몹의 새끼는 절반 크기로 그려집니다.

텍스처

모델이 없으면 텍스처는 선택한 몸(좀비, 늑대…)의 것과 같은 배치를 가지므로, 그 몸의 템플릿에서 시작해 위에 그리면 됩니다. 아이템과 블록 텍스처처럼 모드 안에 넣습니다.

모드 위치
CraftScript(폴더) mods/ghostmod/textures/entity/ghost.png
Kotlin 또는 Java src/main/resources/assets/ghostmod/textures/entity/ghost.png