Table of Contents

Добавление блока

Добавление блоков в ваш мод следует аналогичному процессу, описанному в добавлении предметов. Вы можете создать экземпляр Block или пользовательский класс, а затем зарегистрировать его в разделе Registry.BLOCK. Вам также необходимо предоставить текстуру и файл модели/состояний блока для создания визуальных эффектов вашего блока. Для получения дополнительной информации о формате блочной модели просмотрите Страницу википедии Minecraft о моделях (англ.).

Создание блока

Начните с создания экземпляра Block. Он может храниться в любом месте, но мы начнем с верхней части вашего ModInitializer. Для конструктора Block требуется экземпляр AbstractBlock.Settings, который представляет собой конструктор для настройки свойств блока. Fabric предоставляет класс-конструктор FabricBlockSettings с большим количеством доступных опций.

  1. public class ExampleMod implements ModInitializer {
  2.  
  3. /* Объявляем и инициализируем наш пользовательский экземпляр блока.
  4.   Мы устанавливаем для нашего материала значение `METAL`, для эффективного разрушения которого требуется кирка.
  5.  
  6.   `strength` устанавливает как твердость, так и сопротивление блока на одно и то же значение.
  7.   Твердость определяет, сколько времени требуется блоку для разрушения, а сопротивление определяет, насколько прочен блок против повреждений от взрыва (например, взрывов).
  8.   Камень имеет твердость 1,5f и сопротивление 6,0f, в то время как обсидиан имеет твердость 50,0 f и сопротивление 1200,0 f.
  9.  
  10.  
  11.   Вы можете найти статистику всех блоков ванилы в классе `Blocks`, где вы также можете ссылаться на другие блоки.
  12.   */
  13. public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.of(Material.METAL).strength(4.0f));
  14.  
  15. @Override
  16. public void onInitialize() {
  17.  
  18. }
  19. }

Регистрация вашего блока

Блоки должны быть зарегистрированы в реестре Registry.BLOCK. Вызовите Registry.register и передайте соответствующие аргументы. Вы можете либо зарегистрировать блок в методе onInitialize либо непосредственно при создании экземпляра блока в статическом контексте, так как метод register также возвращает экземпляр блока.

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

Ваш блок пока не будет доступен как предмет, но его можно увидеть в игре, используя команду /setblock tutorial:example_block.

Регистрация предмета для вашего блока

В большинстве случаев вы хотите иметь возможность разместить свой блок с помощью элемента. Для этого вам необходимо зарегистрировать соответствующий BlockItem в реестре элементов. Вы можете сделать это, зарегистрировав экземпляр BlockItem в разделе Registry.ITEM. Имя предмета в реестре обычно должно совпадать с именем реестра блока.

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

Предоставление визуальных эффектов вашего блока

На этом этапе ваш новый блок появится в игре в виде фиолетово-черного шахматного рисунка. Это способ Minecraft показать вам, что что-то пошло не так при загрузке ресурсов блока (или визуальных элементов). Полный список проблем будет напечатан в ваших логах при запуске вашего клиента. Вам понадобятся эти файлы, чтобы придать вашему блоку визуальные эффекты:

Файлы должны быть расположены здесь:

Состояние блока: 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 определяет, какую модель должен использовать блок, в зависимости от его состояния блока. У нашего блока нет никаких потенциальных состояний, поэтому мы пишем так: “”.

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

Файл модели блока определяет форму и текстуру вашего блока. Наша модель будет иметь block/cube_allв качестве родительского элемента, который применяет текстуру all ко всем сторонам блока.

src/main/resources/assets/tutorial/models/block/example_block.json
{
  "parent": "block/cube_all",
  "textures": {
    "all": "tutorial:block/example_block"
  }
}

В большинстве случаев вы захотите, чтобы блок выглядел одинаково в форме предмета. Вы можете создать модель предмета, которая имеет файл модели блока в качестве родительского элемента, что делает его похожим на блок:

src/main/resources/assets/tutorial/models/item/example_block.json
{
  "parent": "tutorial:block/example_block"
}

Загрузите Minecraft, и у вашего блока должны быть визуальные эффекты!

Настройка выпадения блока

Чтобы заставить ваш блок отбрасывать предметы при разрыве, вам понадобится таблица выпадений. Следующий файл приведет к тому, что ваш блок удалит соответствующую форму предмета при разрыве:

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

В minecraft 1.17 произошли изменения для разбивания блоков. Теперь, чтобы определить инструменты сбора урожая и уровни сбора урожая, нам нужно использовать теги. Читайте о тегах здесь: Теги. Теги, к которым нам нужно добавить блок, следующие:

Инструмент для сбора урожая: src/main/resources/data/minecraft/tags/blocks/mineable/<tooltype>.json, где 'tooltype' может быть любым из: 'axe', 'pickaxe', 'shovel' или 'hoe'
Уровень сбора урожая: src/main/resources/data/minecraft/tags/blocks/needs_<tier>_tool.json, где 'tier' может быть любым из: 'stone', 'iron' или 'diamond'
src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json
{
  "replace": false,
  "values": [
    "example:example_block"
  ]
}
src/main/resources/data/minecraft/tags/blocks/needs_stone_tool.json
{
  "replace": false,
  "values": [
    "example:example_block"
  ]
}

Чтобы теги уровня сбора урожая (needs_stone_tool, needs_iron_tool и needs_diamond_tool) вступили в силу, добавьте requiresTool() в FabricToolSettings в объявлении блока:

  1. public static final Block EXAMPLE_BLOCK = new ExampleBlock(FabricBlockSettings.of(Material.METAL).strength(4.0f).requiresTool());

Создание пользовательского класса блоков

Описанный выше подход хорошо работает для простых блоков, но не подходит, когда вам нужен блок с уникальной механикой. Для этого мы создадим отдельный класс, который расширяет Block . Классу нужен конструктор, который принимает аргумент AbstractBlock.Settings:

  1. public class ExampleBlock extends Block {
  2.  
  3. public ExampleBlock(Settings settings) {
  4. super(settings);
  5. }
  6. }

Вы можете переопределять методы в классе блока для пользовательских функций. Вот реализация метода onUse, который вызывается, когда вы щелкаете правой кнопкой мыши по блоку. Мы проверяем, происходит ли взаимодействие на сервере, а затем отправляем игроку сообщение со словами: “Hello, world!”

  1. public class ExampleBlock extends Block {
  2.  
  3. public ExampleBlock(Settings settings) {
  4. super(settings);
  5. }
  6.  
  7. @Override
  8. public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
  9. if (!world.isClient) {
  10. player.sendMessage(new LiteralText("Hello, world!"), false);
  11. }
  12.  
  13. return ActionResult.SUCCESS;
  14. }
  15. }

Чтобы использовать свой пользовательский класс блоков, замените new Block на new ExampleBlock:

  1. public class ExampleMod implements ModInitializer {
  2.  
  3. public static final ExampleBlock EXAMPLE_BLOCK = new ExampleBlock(FabricBlockSettings.of(Material.STONE).hardness(4.0f));
  4.  
  5. @Override
  6. public void onInitialize() {
  7. Registry.register(Registry.BLOCK, new Identifier("tutorial", "example_block"), EXAMPLE_BLOCK);
  8. Registry.register(Registry.ITEM, new Identifier("tutorial", "example_block"), new BlockItem(EXAMPLE_BLOCK, new Item.Settings().group(ItemGroup.MISC)));
  9. }
  10. }

VoxelShape

При использовании моделей блока, которые не полностью заполняют блок (например: Наковальня, Плита, Лестница), у соседних блоков пропадают стороны:

Чтобы исправить это, мы должны определить VoxelShape нового блока:

 @Override
 public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, ShapeContext context) {
     return VoxelShapes.cuboid(0f, 0f, 0f, 1f, 1.0f, 0.5f);
 }

Обратите внимание, что форма столкновения блока по умолчанию имеет форму контура, если она не указана.

Следующие шаги

Добавление простого состояния блока, например целых чисел и логических значений.

Предоставление блокам сущности, чтобы они могли иметь расширенное состояние, подобное инвентарю. Также необходим для многих вещей, таких как графический интерфейс и рендеринг пользовательских блоков.