블록을 추가하는 방법은 아이템을 추가하는 것과 비슷합니다. 클래스를 생성해서 블록의 인스턴스를 만들고, Registry.BLOCK
에 블록을 레지스터 하시면 됩니다. 그리고 블록의 생김새를 위해 블록 택스쳐와 블록 모델을 추가해야 합니다. 블록 모델 구성의 자세한 정보는 마인크레프트 위키 모델 페이지를 참조하세요.
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() { } }
당신의 커스텀 블록은 아이템으로 아직 접근할 수 없을 것입니다. 하지만 게임 내에서는 /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() { } }
현재까지는 당신의 블록은 게임 내에서 보라색과 검은색의 체크 무늬로 표시될 것입니다. 마인크래프트는 블록의 에셋을 로딩하는 중 문제가 발생했을 때 이렇게 표시합니다. 이 문제의 전체 내용은 클라이언트를 실행할 때 출력되는 로그에서 확인할 수 있습니다. 당신은 블록에게 시각적 요소를 부여하기 위해 다음의 파일이 필요합니다
해당 파일들은 다음 위치에 위치되어야 합니다:
블록 상태: 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() { } }
When using block models that do not entirely fill the block (eg. Anvil, Slab, Stairs), adjacent blocks hide their faces:
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.
Adding simple state to a block, like ints and booleans.
Giving blocks a block entity so they can have advanced state like inventories. Also needed for many things like GUI and custom block rendering.