블록
블록 선언
BlockHandle block = mod.content().block("copper_bricks", BlockDefinition.builder()
.strength(2.0f, 6.0f)
.requiresCorrectTool()
.sound(BlockSound.COPPER)
.item(ItemDefinition.builder().creativeTab(CreativeTab.BUILDING_BLOCKS).build())
.build());
| 빌더 메서드 | 뜻 |
|---|---|
strength(hardness, explosionResistance) | 단단함과 폭발 저항 |
requiresCorrectTool() | 맞는 도구로 캐야 아이템이 드롭됨(도구 태그는 데이터 팩이나 addToTag로 지정) |
sound(BlockSound) | STONE, WOOD, GRAVEL, GRASS, METAL, GLASS, WOOL, SAND, COPPER, AMETHYST |
lightLevel(int) / lightLevel(state -> …) | 빛 세기, 또는 상태별 빛 세기 |
friction(float) | 미끄러움 |
noCollision(), noOcclusion() | 충돌 없음 / 빛과 시야를 가리지 않음 |
behavior(BlockBehavior) | 동작 콜백 |
item(ItemDefinition) / noItem() | 같은 ID의 블록 아이템 정의 / 블록 아이템 없음 |
properties(...), facesPlayerWhenPlaced(...) | 상태 속성 |
randomTicks() | 무작위 틱 받기(onRandomTick) |
blockEntity(BlockEntityDefinition) | 블록 엔티티. 블록 엔티티와 메뉴 |
창작 탭은 CreativeTab의 BUILDING_BLOCKS, COLORED_BLOCKS, NATURAL_BLOCKS, FUNCTIONAL_BLOCKS, REDSTONE_BLOCKS, TOOLS_AND_UTILITIES, COMBAT, FOOD_AND_DRINKS, INGREDIENTS, SPAWN_EGGS 중에서 고르며, 탭 끝에 추가됩니다. 모드 전용 탭은 태그와 창작 탭에서 설명합니다.
동작 콜백
BlockBehavior의 메서드에는 모두 기본 구현이 있으므로 필요한 것만 재정의하면 됩니다.
| 메서드 | 호출 시점 |
|---|---|
onUse(BlockUse use) | 플레이어가 블록을 사용할 때(use.world(), use.pos(), use.player()) |
onSteppedOn(world, pos, entity) | 엔티티가 블록 위를 밟을 때 |
onPlaced(world, pos, placer) | 블록이 놓일 때 |
onRandomTick(world, pos) | 무작위 틱이 발생할 때(randomTicks() 필요) |
onNeighborChanged(world, pos) | 이웃 블록이 바뀔 때 |
onUse가 PASS를 반환하면 게임의 기본 동작이 그대로 실행됩니다.
블록 상태 속성
static final BlockProperty.DirectionProperty FACING = BlockProperty.horizontalFacing("facing");
static final BlockProperty.BooleanProperty POWERED = BlockProperty.bool("powered");
BlockDefinition.builder()
.facesPlayerWhenPlaced(FACING) // 놓을 때 플레이어 쪽을 보게 함
.properties(POWERED)
.randomTicks() // BlockBehavior.onRandomTick
.build();
world.stateAt(pos).get(POWERED);
world.setProperty(pos, POWERED, true);
- 속성 종류:
bool,integer(min, max),horizontalFacing,direction,choice(name, values...)가 있습니다. 기본값은withDefault(...)로 바꿉니다. - 기본 상태: 각 속성의 기본값을 모은 것이 기본 상태가 됩니다.
- blockstate 파일:
"facing=north,powered=false"처럼 바닐라 형식으로 모델을 고릅니다. - 바닐라 블록 읽기: 이름과 타입이 같은 속성이면 게임 블록의 상태도 읽을 수 있습니다(예: 화로의
facing). 먼저stateAt(pos).has(property)로 확인하세요. - 블록에 없는 속성을 바꾸려 하면
IllegalArgumentException이 발생합니다.
이름 속성
static final BlockProperty.ChoiceProperty COLOR = BlockProperty.choice("color", "red", "green", "blue"); // 첫 값이 기본값
- 블록 상태 파일에서는
color=blue처럼 씁니다. - 이름이 같은 게임 속성(계단의
half, 통나무의axis등)도 문자열로 읽고 바꿀 수 있습니다. - 허용되지 않은 값을 쓰면
IllegalArgumentException이 발생합니다.
상태별 빛
static final BlockProperty.BooleanProperty LIT = BlockProperty.bool("lit");
mod.content().block("lamp", BlockDefinition.builder()
.properties(COLOR, LIT)
.lightLevel(state -> state.get(LIT) ? 15 : 0) // 상태마다 빛 세기
.behavior(new BlockBehavior() {
@Override
public InteractionResult onUse(BlockUse use) {
if (!use.world().isClientSide()) {
use.world().setProperty(use.pos(), LIT, true);
}
return InteractionResult.SUCCESS;
}
})
.build());
lightLevel(state -> …)는 블록이 만들어질 때 상태마다 한 번 계산합니다. 결과는 WorldView.emittedLight(pos)로 확인할 수 있습니다. 별도의 빛 공급자 API는 없습니다.
모양과 충돌
반 블록, 기둥, 관처럼 꽉 차지 않은 블록은 shape로 모양을 지정합니다. 단위는 픽셀이며, 한 블록은 각 축이 0..16입니다. 블록 모델 요소의 from/to와 같은 단위입니다.
// 반 칸 높이: 엔티티가 y + 0.5에 서고, 윤곽선도 반 칸
mod.content().block("stone_step", BlockDefinition.builder()
.shape(BlockShape.box(0, 0, 0, 16, 8, 16))
.build());
// 받침대와 기둥, 그리고 바라보는 방향에 따라 돌린 손잡이
static final BlockProperty.DirectionProperty FACING = BlockProperty.horizontalFacing("facing");
static final BlockShape HANDLE = BlockShape.box(6, 10, 0, 10, 12, 4); // 북쪽을 볼 때 모양
mod.content().block("lever_post", BlockDefinition.builder()
.properties(FACING)
.facesPlayerWhenPlaced(FACING)
.shape(state -> BlockShape.box(0, 0, 0, 16, 2, 16)
.or(BlockShape.box(6, 2, 6, 10, 16, 10))
.or(HANDLE.facing(state.get(FACING))))
.collisionShape(BlockShape.box(0, 0, 0, 16, 2, 16).or(BlockShape.box(6, 2, 6, 10, 16, 10)))
.build());
| 메서드 | 뜻 |
|---|---|
shape(BlockShape), shape(state -> …) | 플레이어가 겨누는 윤곽선이자 충돌 모양 |
collisionShape(…) | 충돌 모양만 다를 때 |
BlockShape.box(…), or(…) | 상자 하나, 합치기 |
BlockShape.facing(direction) | 북쪽을 보는 모양을 그 방향으로 돌림 |
BlockShape.FULL, BlockShape.EMPTY | 꽉 찬 블록, 모양 없음 |
- 상태별 모양은 게임이 시작할 때 상태마다 한 번 계산합니다. 함수가 예외를 던지거나
null을 돌려주면POLY-CONTENT-006오류가 납니다. - 게임은 모양이 덮는 이웃 면만 숨깁니다. 블록 모델은 자동으로 바뀌지 않으므로 모델을 모양에 맞게 직접 그려야 합니다. 반 블록이라면
"parent": "minecraft:block/slab"을 사용하세요. noCollision()을 지정하면collisionShape와 관계없이 충돌하지 않습니다.
블록 상태 파일 예
assets/my_mod/blockstates/lamp.json
{
"variants": {
"lit=false": {"model": "my_mod:block/lamp_off"},
"lit=true": {"model": "my_mod:block/lamp_on"}
}
}
블록 상태 번호
모드 블록의 상태도 게임의 블록 상태 번호 표에 들어갑니다. 덕분에 모드 블록의 변경 사항을 클라이언트로 보낼 수 있습니다(초기 버전에서 연결이 끊기던 문제를 고쳤습니다).