====== 블록 추가하기 ======
블록을 추가하는 방법은 [[tutorial:items|아이템을 추가]]하는 것과 비슷합니다. 클래스를 생성해서 블록의 인스턴스를 만들고, ''Registry.BLOCK''에 블록을 레지스터 하시면 됩니다. 그리고 블록의 생김새를 위해 블록 택스쳐와 블록 모델을 추가해야 합니다. 블록 모델 구성의 자세한 정보는 [[https://minecraft.gamepedia.com/Model|마인크레프트 위키 모델 페이지]]를 참조하세요.
===== 블록 인스턴스 만들기 =====
''Block''의 인스턴스를 먼저 만듭니다. 이 ''Block'' 인스턴스는 어디에나 위치할 수 있습니다. 하지만 우리는 ''ModInitializer''의 맨 위에 위치시킬 것 입니다. ''Block''의 생성자는 블록의 속성을 설정할 수 있는 ''AbstractBlock.Settings''의 인스턴스를 요구로 합니다. 패브릭은 ''FabricBlockSettings'' 빌더 클래스에 더 많은 사용 가능한 옵션을 제공합니다.
public class ExampleMod implements ModInitializer {
/* 우리의 커스텀 블록 인스턴스를 선언하고 초기화합니다.
우리는 블록 재질을 곡괭이로 효율적으로 부술 수 있는 `METAL`로 설정할 것 입니다.
`strength`는 블록의 경도와 저항 두개를 모두 설정합니다.
경도는 블록이 부수는 데 걸리는 시간을 결정하며, 저항은 블록이 폭발에 얼마나 강한지를 결정합니다.
돌의 경도는 1.5f, 저항은 6.0f인 반면 흑요석의 경도는 50.0f, 저항은 1200.0f입니다.
당신은 모든 바닐라 블록을 `Blocks` 클래스에서 확인하시고 코드에 참조할 수 있습니다.
*/
public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.of(Material.METAL).strength(4.0f));
@Override
public void onInitialize() {
}
}
==== 블록 등록하기 ====
블록은 ''Registry.BLOCK'' 저장소에 등록되어야 합니다. //Registry.register//를 적절한 파라미터에 맞게 실행하세요.
public class ExampleMod implements ModInitializer {
public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.of(Material.METAL).strength(4.0f));
@Override
public void onInitialize() {
Registry.register(Registry.BLOCK, new Identifier("tutorial", "example_block"), EXAMPLE_BLOCK);
}
}
당신의 커스텀 블록은 아이템으로 아직 접근할 수 없을 것입니다. 하지만 게임 내에서는 ''/setblock tutorial:example_block''을 통해 확인할 수 있습니다.
==== 블록 아이템 등록하기 ====
대부분의 경우에는 당신은 아이템을 통해 당신의 블록을 설치하게 하고 싶을 것 입니다. 이 것을 위해 당신은 Registry.ITEM 저장소에 그 블록에 맞는 BlockItem을 등록해야합니다. 저장소에 등록된 블록 아이템의 이름은 주로 블록의 저장소 이름과 같습니다.
public class ExampleMod implements ModInitializer {
public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.of(Material.METAL).strength(4.0f));
@Override
public void onInitialize() {
Registry.register(Registry.BLOCK, new Identifier("tutorial", "example_block"), EXAMPLE_BLOCK);
Registry.register(Registry.ITEM, new Identifier("tutorial", "example_block"), new BlockItem(EXAMPLE_BLOCK, new FabricItemSettings().group(ItemGroup.MISC)));
}
}
===== 블록에게 시각적 요소 부여하기 =====
현재까지는 당신의 블록은 게임 내에서 보라색과 검은색의 체크 무늬로 표시될 것입니다. 마인크래프트는 블록의 에셋을 로딩하는 중 문제가 발생했을 때 이렇게 표시합니다. 이 문제의 전체 내용은 클라이언트를 실행할 때 출력되는 로그에서 확인할 수 있습니다.
당신은 블록에게 시각적 요소를 부여하기 위해 다음의 파일이 필요합니다
* 블록 상태 파일
* 블록 모델 파일
* 텍스쳐
* 만약 블록 아이템이 있을 경우, 아이템 모델 파일
해당 파일들은 다음 위치에 위치되어야 합니다:
블록 상태: src/main/resources/assets/tutorial/blockstates/example_block.json
블록 모델: src/main/resources/assets/tutorial/models/block/example_block.json
아이템 모델: src/main/resources/assets/tutorial/models/item/example_block.json
텍스쳐: src/main/resources/assets/tutorial/textures/block/example_block.png
블록 상태 파일은 블록의 블록 상태(blockstate)에 따라 어떤 블록 모델을 사용할지 결정합니다. 우리의 블록은 상태라고 할 게 딱히 없으니 우리는 블록 상태 파일을 다음과 같이 작성할 수 있을 것입니다.
''""''.
{
"variants": {
"": { "model": "tutorial:block/example_block" }
}
}
블록 모델 파일은 당신의 블록의 모양과 텍스쳐를 결정합니다. 우리의 모델은 모든 면에 같은 텍스쳐를 적용하는 ''block/cube_all''을 부모로 삼을 것 입니다. 따라서 블록 모델 파일은 다음과 같이 작성할 수 있습니다.
{
"parent": "block/cube_all",
"textures": {
"all": "tutorial:block/example_block"
}
}
대부분의 경우에는 블록 아이템을 블록과 똑같이 보이길 원할 것입니다. 그렇다면 당신은 블록 모델을 부모로 삼는 아이템 모델을 다음과 같이 작성하면 됩니다.
{
"parent": "tutorial:block/example_block"
}
이제 마인크래프트를 켜고 블록의 시각적인 요소를 확인해보세요!
===== 블록 드랍 설정하기 =====
블록이 부숴졌을 때 아이템이 떨어지게 하고 싶으면, //루트 테이블//이 필요로 합니다. 당신의 블록이 부숴졌을 때 아이템을 떨어트리는 루트 테이블을 다음과 같이 작성할 수 있습니다.
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "tutorial:example_block"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}
===== 커스텀 블록 클래스 만들기 =====
The above approach works well for simple items but falls short when you want a block with //unique// mechanics. We'll create a //separate// class that extends ''Block'' to do this. The class needs a constructor that takes in an ''AbstractBlock.Settings'' argument:
public class ExampleBlock extends Block {
public ExampleBlock(Settings settings) {
super(settings);
}
}
You can override methods in the block class for custom functionality. Here's an implementation of the ''onUse'' method, which is called when you right-click the block. We check if the interaction is occurring on the server, and then send the player a message saying, //"Hello, world!"//
public class ExampleBlock extends Block {
public ExampleBlock(Settings settings) {
super(settings);
}
@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
if (!world.isClient) {
player.sendMessage(new LiteralText("Hello, world!"), false);
}
return ActionResult.SUCCESS;
}
}
To use your custom block class, replace //new Block// with //new ExampleBlock//:
public class ExampleMod implements ModInitializer {
public static final ExampleBlock EXAMPLE_BLOCK = new ExampleBlock(Block.Settings.of(Material.STONE).hardness(4.0f));
@Override
public void onInitialize() {
Registry.register(Registry.BLOCK, new Identifier("tutorial", "example_block"), EXAMPLE_BLOCK);
Registry.register(Registry.ITEM, new Identifier("tutorial", "example_block"), new BlockItem(EXAMPLE_BLOCK, new Item.Settings().group(ItemGroup.MISC)));
}
}
==== Custom VoxelShape ====
When using block models that do not //entirely// fill the block (eg. Anvil, Slab, Stairs), adjacent blocks hide their faces:
{{:tutorial:voxelshape_wrong.png?200|}}
To fix this, we have to define the ''VoxelShape'' of the new block:
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, ShapeContext context) {
return VoxelShapes.cuboid(0f, 0f, 0f, 1f, 1.0f, 0.5f);
}
Note that the //collision shape// of the block defaults to the outline shape if it is not specified.
{{:tutorial:voxelshape_fixed.png?200|}}
===== Next Steps =====
[[tutorial:blockstate|Adding simple state to a block, like ints and booleans]].
[[tutorial:blockentity|Giving blocks a block entity so they can have advanced state like inventories]]. Also needed for many things like GUI and custom block rendering.