Table of Contents

Agregando Bloques

El proceso de agregar bloques a tu mod es similar al proceso de agregar un objeto. Puedes crear una instancia de Block o tu propia clase, y luego puedes registarlo mediante Registries.BLOCK (para versiones 1.19.3 en adelante) o Registry.BLOCK (para versiones 1.19.2 para atrás). También necesitarás proporcionar un archivo de textura y estado de bloque/modelo para darle aspectos visuales a tu bloque. Para mas información sobre sobre el formato de modelo de bloques, visita la página de Modelos de la Wiki de Minecraft.

Creando un Bloque

Empieza creando una instancia de Block. Lo puedes guardar en cualquier lugar, pero empezaremos al principio de tu ModInitializer. El constructor de Block requiere una instancia de AbstractBlock.Settings, el cual es un builder para configurar las propiedades del bloque. Fabric provee una clase builder FabricBlockSettings con mayores opciones.

  1. public class ExampleMod implements ModInitializer {
  2.  
  3. /* Declara e inicialisza una instancia de nuestro bloque personalizado.
  4.   Elegimos `METAL` como el material del bloque.
  5.  
  6.   `strength` determina la dureza y la resistencia del bloque al mismo valor.
  7.   Hardness determine cuanto tarda el bloque en ser minado, y resistance determina la resistencia del bloque contra daño de explosiones.
  8.   La piedra tiene un hardness de 1.5f y una resistencia de 6.0f, mientras que la obsidiana tiene un hardness de 50.0f y un resistance de 1200.0f.
  9.  
  10.   You can find the stats of all vanilla blocks in the class `Blocks`, where you can also reference other blocks.
  11.   */
  12. // public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.of(Material.METAL).strength(4.0f)); // fabric api version <= 0.77.0
  13. public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.create().strength(4.0f));
  14. @Override
  15. public void onInitialize() {
  16.  
  17. }
  18. }

Registrando tu Bloque

Los Bloques deberían ser registrados en el registro de Registries.BLOCK. LlamaRegistry.register pasando los argumentos necesarios. Puedes registrar tu bloque en el método onInitialize o directamente cuando creas la instancia del bloque en el contexto estático, ya que el método register retorna la instancia del bloque. Si estás usando la versión 1.19.2 o menor, porfavor reemplaza Registries.BLOCK con Registry.BLOCK

  1. public class ExampleMod implements ModInitializer {
  2.  
  3. // public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.of(Material.METAL).strength(4.0f)); // fabric api version <= 0.77.0
  4. public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.create().strength(4.0f));
  5.  
  6. @Override
  7. public void onInitialize() {
  8. Registry.register(Registries.BLOCK, new Identifier("tutorial", "example_block"), EXAMPLE_BLOCK);
  9. }
  10. }

Tu Bloque personalizado no será todavía accesible como un item, pero puede ser visto en el juego usando el comando /setblock <position> tutorial:example_block.

Registrando un Item para tu Bloque

En la mayoría de los casos, vas a querer poder usar tu bloque con un item. Para hacer esto, debes registrar un BlockItem correspondiente en el registro de objetos. Puedes hacer esto registrando una instancia de BlockItem en el registro de Registries.ITEM. El nombre del registro del objeto debería ser el mismo que el nombre del registro del bloque.

  1. public class ExampleMod implements ModInitializer {
  2.  
  3. // public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.of(Material.METAL).strength(4.0f)); // fabric api version <= 0.77.0
  4. public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.create().strength(4.0f));
  5.  
  6. @Override
  7. public void onInitialize() {
  8. Registry.register(Registries.BLOCK, new Identifier("tutorial", "example_block"), EXAMPLE_BLOCK);
  9. Registry.register(Registries.ITEM, new Identifier("tutorial", "example_block"), new BlockItem(EXAMPLE_BLOCK, new FabricItemSettings()));
  10. }
  11. }

Dandole Visuales a tus Bloques

A este punto, tu nuevo bloque aparecerá como un un bloque morado y negro con un patrón de cuadrícula. Esta es la manera en que Minecraft nos dice que algo salió mal cuando el juego cargaba los archivos visuales del bloque. Una lista completa de los problemas aparecerá en tus logs cuando corras el cliente. Necesitarás estos archivos para darle visuales a tu bloque:

Los archivos deberían estar aquí:

El archivo blockstate determina que modelo un bloque usará dependiendo de su blockstate. Nuestro bloque no tiene ningún estado, asique rellenamos con “”.

src/main/resources/assets/tutorial/blockstates/example_block.json
{
  "variants": {
    "": { "model": "tutorial:block/example_block" }
  }
}

El archivo block model define la forma y la textura de tu bloque. Nuestro modelo tendrá como pariente a block/cube_all', que aplica la textura all a todos los lados del bloque. <code JavaScript src/main/resources/assets/tutorial/models/block/example_block.json> { “parent”: “block/cube_all”, “textures”: { “all”: “tutorial:block/example_block” } } </code> En la mayoría de la casos, querrás que el bloque se vea de la misma manera que un su forma de item. Puedes hacer un modelo de item que tiene que el archivo de block model como pariente, lo cual lo hace aparecer exactamente como el bloque: <code JavaScript src/main/resources/assets/tutorial/models/item/example_block.json> { “parent”: “tutorial:block/example_block” } </code> Load up Minecraft and your block should have visuals! ===== Configurando los Drops del Bloque ===== Para hacer que tu bloque suelte items cuando sea roto, necesitarás un loot table. El siguiente archivo causará que tu bloque suelte su item respectivo cuando sea roto: <code JavaScript src/main/resources/data/tutorial/loot_tables/blocks/example_block.json> { “type”: “minecraft:block”, “pools”: [ { “rolls”: 1, “entries”: [ { “type”: “minecraft:item”, “name”: “tutorial:example_block” } ], “conditions”: [ { “condition”: “minecraft:survives_explosion” } ] } ] } </code> La condición minecraft:survives_explosion significa que, si el bloque es destruído en una explosión con decaimiento (como explosiones de Creeper, no explosiones de TNT), entonces puede que suelte su item. Si esta condición no está, el bloque siempre soltará su item en caso de explosiones con decaimiento. En Minecraft 1.17, hubieron cambios en la manera en que los bloques son destruidos. Ahora, para definir las herramientas de minado y los niveles de minado, utilizamos tags. Lee sobre los Tags en: Tags Tutorial. Los tags que debemos agregar a nuestro bloque son: * Herramientas de mina: src/main/resources/data/minecraft/tags/blocks/mineable/<tooltype>.json, donde<tooltype> puede ser: axe, pickaxe, shovel o hoe * Nivel de minado: src/main/resources/data/minecraft/tags/blocks/needs_<tier>_tool.json, donde <tier> puede ser: stone, iron or diamond (not including netherite) <code JavaScript src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json> { “replace”: false, “values”: [ “tutorial:example_block” ] } </code> <code JavaScript src/main/resources/data/minecraft/tags/blocks/needs_stone_tool.json> { “replace”: false, “values”: [ “tutorial:example_block” ] } </code> Para que los tags de niveles de minado tomen efecto (needs_stone_tool, needs_iron_tool and needs_diamond_tool) agrega requiresTool() al FabricBlockSettings en la declaración del bloque: <code java [enable_line_numbers=“true”]> public static final Block EXAMPLE_BLOCK = new ExampleBlock(FabricBlockSettings.of(Material.METAL).strength(4.0f).requiresTool()); fabric api version ⇐ 0.77.0 public static final Block EXAMPLE_BLOCK = new ExampleBlock(FabricBlockSettings.create().strength(4.0f).requiresTool()); </code> ===== Creando una Clase Personalizada para un Bloque ===== Lo que hicimos arriba funciona bien para bloques simple, pero no es suficiente para hacer un bloque con mecánicas únicas. Crearemos una clase separada que extiende Block para hacer esto. Esta clase necesita un constructor con un parametro de AbstractBlock.Settings: <code java [enable_line_numbers=“true”]> public class ExampleBlock extends Block { public ExampleBlock(Settings settings) { super(settings); } } </code> Puedes sobreescribir métodos en tu clase de bloque para funcionalidad personalizada. Aquí está una implementación del método onUse, el cual es llamada cuando el jugador hace click-derecho en el bloque. Verificamos que la interacción esta ocurriendo en el servidor, y luego enviamos un mensaje diciendo “Hello, world!” <code java [enable_line_numbers=“true”,highlight_lines_extra=“8,9,10,11,12,13,14,15”]> 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(Text.literal(“Hello, world!”), false); } return ActionResult.SUCCESS; } } </code> Para usar tu clase de bloque personalizada, reemplazanew Block con new ExampleBlock: <code java [enable_line_numbers=“true”,highlight_lines_extra=“3”]> public class ExampleMod implements ModInitializer { public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.of(Material.METAL).strength(4.0f)); fabric api version ⇐ 0.77.0 public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.create().strength(4.0f)); @Override public void onInitialize() { Registry.register(Registries.BLOCK, new Identifier(“tutorial”, “example_block”), EXAMPLE_BLOCK); Registry.register(Registries.ITEM, new Identifier(“tutorial”, “example_block”), new BlockItem(EXAMPLE_BLOCK, new Item.Settings())); } } </code> ==== Forma Personalizada ==== Cuando se usan modelos de bloques que no rellenan enteramente el bloque (eg. Yunques, Losas, Escaleras), mientras que su forma voxelizada es completa, las caras opacadas de los bloques adyacentes serán expuestas: Para arreglar esto, debemos definir el VoxelShape de nuestro nuevo bloque: <code java> public class ExampleBlock extends Block { […] @Override public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, ShapeContext context) { return VoxelShapes.cuboid(0f, 0f, 0f, 1f, 1.0f, 0.5f); } } </code> También puedes definir otros tipos de formas para tu bloque. Los tipos de forma incluyen: * outline shape (Forma de contorno): La forma usada por defecto para la mayoría de los tipos de formas. En los mundos, cuando apuntas a la forma, el contorno negro translúcido del bloque es mostrado de acuerdo a esta forma. No debería estar vacía en el mayor de los casos. * collision shape (Forma de colisión): La forma usada para calcular colisiones. Cuando las entidades (incluyendo jugadores) se mueven, sus cajas de colisiones usualmente no puede intersectar la forma de colisiones de bloques. Algunos bloques, cercas y paredes, pueden tener una forma de colisión arriba de un bloque. Algunos bloques, como flores, pueden tener una forma de colisión vacía. Aparte de modificar el método getCollisionShape, también puedes llamar noCollision en FabricBlockSettings cuando creas el bloque. * raycasting shape (Forma de trazado de rayos): La forma usada para calcular raycasting (el proceso que determina a que bloque estas mirando). Usualmente no necesitas especificarlo. * camera collision shape (Forma de colisión de la camara): La forma usada para calcular la posición de la camara en la vista de tercera perona. El bloque de Cristal y Nieve Enpolvada tienen una forma de colisión de camara vacía. ===== Siguientes pasos ===== Agregando un estado simple a un block, como números y boleanos. Dandole entidades de bloques a blcoks para que puedan tener estado avanzado como inventarios. Necesitado también para cosas como interfazes y renderización peronalizada para el bloque. Para hacer tu bloque flamba (que pueda ser quemado por fuego), puedes usar FlammableBlockRegistry''.