Привет всем! Где один новый блок, там и ступени, стена, плита и т.д. Так что без лишних слов переходим к коду!
Java часть
Продолжать буду проект из прошлого урока, так как оригинальный блок будет полезен для урока с рецептами, да и в постройках без него никак.
Итак. Сегодня в планах плита, ступени и стена. Текстуру оставим ту же, а вот моделей будет побольше. Так же в этот раз увидим более интересные blockstates файлы, с множеством состояний!
Понятное дело, что писать классы для всех этих блоков самостоятельно мы не будем. Во-первых, к этому мы еще придём, а пока надо руку набивать на том, что уже есть. А во-вторых, зачем делать заново то, что, снова же, создано и хорошо работает? Так что сегодня мы будем использовать не обычный блок, а StairsBlock, SlabBlock и WallBlock. Если знаете английский, то вопросы вообще отпадут.
Для регистрации плиты и стены вообще можно только Block заменить на подходящий класс, а вот ступени еще требуют BlockState блока «родителя».
Так что три новых блока будут иметь такой вид:
1 2 3 |
public static final RegistryObject<Block> STONE_STICK_STAIRS = BLOCKS.register("stone_stick_stairs", () -> new StairsBlock(() -> STONE_STICK_BLOCK.get().getDefaultState(), Block.Properties.create(Material.ROCK).hardnessAndResistance(3.0F, 3.0F).harvestTool(ToolType.PICKAXE))); public static final RegistryObject<Block> STONE_STICK_SLAB = BLOCKS.register("stone_stick_slab", () -> new SlabBlock(Block.Properties.create(Material.ROCK).hardnessAndResistance(3.0F, 3.0F).harvestTool(ToolType.PICKAXE))); public static final RegistryObject<Block> STONE_STICK_WALL = BLOCKS.register("stone_stick_wall", () -> new WallBlock(Block.Properties.create(Material.ROCK).hardnessAndResistance(3.0F, 3.0F).harvestTool(ToolType.PICKAXE))); |
Предметы для этих блоков будут и вовсе идентичны:
1 2 3 |
public static final RegistryObject<Item> STONE_STICK_STAIRS = ITEMS.register("stone_stick_stairs", () -> new BlockItem(ModBlocks.STONE_STICK_STAIRS.get(), new Item.Properties().group(ModItemGroups.MOD_BLOCKS_ITEM_GROUP))); public static final RegistryObject<Item> STONE_STICK_SLAB = ITEMS.register("stone_stick_slab", () -> new BlockItem(ModBlocks.STONE_STICK_SLAB.get(), new Item.Properties().group(ModItemGroups.MOD_BLOCKS_ITEM_GROUP))); public static final RegistryObject<Item> STONE_STICK_WALL = ITEMS.register("stone_stick_wall", () -> new BlockItem(ModBlocks.STONE_STICK_WALL.get(), new Item.Properties().group(ModItemGroups.MOD_BLOCKS_ITEM_GROUP))); |
Собственно, на этом тут с кодом мы закончили.
Теперь ресурсы, но тут уже будет сложнее, так что лучше делать последовательно.
Работа с ресурсами
Начнём с плиты (она проще). У плиты может быть три состояния. Это нижнее, верхнее и двойная плита (по-сути целый блок).
Так что в папке blockstates добавляем файл stone_stick_slab.json и пишем следующее:
1 2 3 4 5 6 7 |
{ "variants": { "type=bottom": { "model": "tutorial_mod_gs:block/stone_stick_slab" }, "type=top": { "model": "tutorial_mod_gs:block/stone_stick_slab_top" }, "type=double": { "model": "tutorial_mod_gs:block/stone_stick_block" } } } |
Как видите: три состояния – три модели. Так будет не везде, у ступеней куда больше состояний при том же количестве моделей, но тут сделали так. Для двойной плиты, кстати, мы используем и вовсе существующую модель целого блока. Как я и говорил ранее – это экономия ресурсов и места, а значит, так и надо.
В папку моделей для блоков добавляем два новых файла (следите, чтобы имена в blockstates и в папке совпадали). У меня это stone_stick_slab.json:
1 2 3 4 5 6 7 8 |
{ "parent": "block/slab", "textures": { "bottom": "tutorial_mod_gs:block/stone_stick_block", "top": "tutorial_mod_gs:block/stone_stick_block", "side": "tutorial_mod_gs:block/stone_stick_block" } } |
И stone_stick_slab_top.json:
1 2 3 4 5 6 7 8 |
{ "parent": "block/slab_top", "textures": { "bottom": "tutorial_mod_gs:block/stone_stick_block", "top": "tutorial_mod_gs:block/stone_stick_block", "side": "tutorial_mod_gs:block/stone_stick_block" } } |
Из названий ясно, что модели будут для нижней и верхней позиции плиты. Текстура везде одна, так и надо. Но, в отличие от обычного сплошного блока – тут есть выбор. Можно указать разные текстуры для верха плиты, отдельную для низа и отдельную для сторон.
Так же нужно добавить модель предмета для отображения плиты в инвентаре. Файл stone_stick_slab.json:
1 2 3 |
{ "parent": "tutorial_mod_gs:block/stone_stick_slab" } |
Не лишним будет добавить нормальное название:
1 |
"block.tutorial_mod_gs.stone_stick_slab": "Ступени из каменных палок", |
И можно запускать!
Ступени
Готовьтесь офигеть, ведь сейчас мы создадим blockstates для ступеней. Файл stone_stick_stairs.json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
{ "variants": { "facing=east,half=bottom,shape=straight": { "model": "tutorial_mod_gs:block/stone_stick_stairs" }, "facing=west,half=bottom,shape=straight": { "model": "tutorial_mod_gs:block/stone_stick_stairs", "y": 180, "uvlock": true }, "facing=south,half=bottom,shape=straight": { "model": "tutorial_mod_gs:block/stone_stick_stairs", "y": 90, "uvlock": true }, "facing=north,half=bottom,shape=straight": { "model": "tutorial_mod_gs:block/stone_stick_stairs", "y": 270, "uvlock": true }, "facing=east,half=bottom,shape=outer_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer" }, "facing=west,half=bottom,shape=outer_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "y": 180, "uvlock": true }, "facing=south,half=bottom,shape=outer_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "y": 90, "uvlock": true }, "facing=north,half=bottom,shape=outer_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "y": 270, "uvlock": true }, "facing=east,half=bottom,shape=outer_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "y": 270, "uvlock": true }, "facing=west,half=bottom,shape=outer_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "y": 90, "uvlock": true }, "facing=south,half=bottom,shape=outer_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer" }, "facing=north,half=bottom,shape=outer_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "y": 180, "uvlock": true }, "facing=east,half=bottom,shape=inner_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner" }, "facing=west,half=bottom,shape=inner_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "y": 180, "uvlock": true }, "facing=south,half=bottom,shape=inner_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "y": 90, "uvlock": true }, "facing=north,half=bottom,shape=inner_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "y": 270, "uvlock": true }, "facing=east,half=bottom,shape=inner_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "y": 270, "uvlock": true }, "facing=west,half=bottom,shape=inner_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "y": 90, "uvlock": true }, "facing=south,half=bottom,shape=inner_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner" }, "facing=north,half=bottom,shape=inner_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "y": 180, "uvlock": true }, "facing=east,half=top,shape=straight": { "model": "tutorial_mod_gs:block/stone_stick_stairs", "x": 180, "uvlock": true }, "facing=west,half=top,shape=straight": { "model": "tutorial_mod_gs:block/stone_stick_stairs", "x": 180, "y": 180, "uvlock": true }, "facing=south,half=top,shape=straight": { "model": "tutorial_mod_gs:block/stone_stick_stairs", "x": 180, "y": 90, "uvlock": true }, "facing=north,half=top,shape=straight": { "model": "tutorial_mod_gs:block/stone_stick_stairs", "x": 180, "y": 270, "uvlock": true }, "facing=east,half=top,shape=outer_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "x": 180, "y": 90, "uvlock": true }, "facing=west,half=top,shape=outer_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "x": 180, "y": 270, "uvlock": true }, "facing=south,half=top,shape=outer_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "x": 180, "y": 180, "uvlock": true }, "facing=north,half=top,shape=outer_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "x": 180, "uvlock": true }, "facing=east,half=top,shape=outer_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "x": 180, "uvlock": true }, "facing=west,half=top,shape=outer_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "x": 180, "y": 180, "uvlock": true }, "facing=south,half=top,shape=outer_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "x": 180, "y": 90, "uvlock": true }, "facing=north,half=top,shape=outer_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_outer", "x": 180, "y": 270, "uvlock": true }, "facing=east,half=top,shape=inner_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "x": 180, "y": 90, "uvlock": true }, "facing=west,half=top,shape=inner_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "x": 180, "y": 270, "uvlock": true }, "facing=south,half=top,shape=inner_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "x": 180, "y": 180, "uvlock": true }, "facing=north,half=top,shape=inner_right": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "x": 180, "uvlock": true }, "facing=east,half=top,shape=inner_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "x": 180, "uvlock": true }, "facing=west,half=top,shape=inner_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "x": 180, "y": 180, "uvlock": true }, "facing=south,half=top,shape=inner_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "x": 180, "y": 90, "uvlock": true }, "facing=north,half=top,shape=inner_left": { "model": "tutorial_mod_gs:block/stone_stick_stairs_inner", "x": 180, "y": 270, "uvlock": true } } } |
Да, как я и говорил, у ступеней есть очень много вариантов поворотов, есть угловые ступени (притом внутренний угол и внешний).
Но при всём этом количестве положений блока нам нужно добавить всего три модели: stone_stick_stairs_inner.json, stone_stick_stairs_outer.json и stone_stick_stairs.json.
И вот их код:
stone_stick_stairs_inner.json:
1 2 3 4 5 6 7 8 |
{ "parent": "block/inner_stairs", "textures": { "bottom": "tutorial_mod_gs:block/stone_stick_block", "top": "tutorial_mod_gs:block/stone_stick_block", "side": "tutorial_mod_gs:block/stone_stick_block" } } |
stone_stick_stairs_outer.json:
1 2 3 4 5 6 7 8 |
{ "parent": "block/outer_stairs", "textures": { "bottom": "tutorial_mod_gs:block/stone_stick_block", "top": "tutorial_mod_gs:block/stone_stick_block", "side": "tutorial_mod_gs:block/stone_stick_block" } } |
stone_stick_stairs.json:
1 2 3 4 5 6 7 8 |
{ "parent": "block/stairs", "textures": { "bottom": "tutorial_mod_gs:block/stone_stick_block", "top": "tutorial_mod_gs:block/stone_stick_block", "side": "tutorial_mod_gs:block/stone_stick_block" } } |
По сути, единственное их отличие – родитель. Текстуру оставил везде одну.
Не забываем добавить модель предмета:
1 2 3 |
{ "parent": "tutorial_mod_gs:block/stone_stick_stairs" } |
И перевод!
Запускаем.
Стена
Этот блок имеет несколько интересных отличий. К примеру его blockstates состоит не из заранее созданных моделей, а из центрального столбика и сторон стены с разными положениями.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{ "multipart": [ { "when": { "up": "true" }, "apply": { "model": "tutorial_mod_gs:block/stone_stick_wall_post" } }, { "when": { "north": "true" }, "apply": { "model": "tutorial_mod_gs:block/stone_stick_wall_side", "uvlock": true } }, { "when": { "east": "true" }, "apply": { "model": "tutorial_mod_gs:block/stone_stick_wall_side", "y": 90, "uvlock": true } }, { "when": { "south": "true" }, "apply": { "model": "tutorial_mod_gs:block/stone_stick_wall_side", "y": 180, "uvlock": true } }, { "when": { "west": "true" }, "apply": { "model": "tutorial_mod_gs:block/stone_stick_wall_side", "y": 270, "uvlock": true } } ] } |
Условия буквально говорят: если на севере есть с чем соединить – ставим стену на севере. Если нужен столбик (к примеру эта часть стены крайняя или сверху есть какой-то блок): добавляем в центре столбик.
Поэтому нам и не нужен десяток разных моделей стены. Она создаёт себя в зависимости от ситуации (multipart).
Но на этом интересности не закончились. Хоть в состояниях указано только две модели – нужно добавить три. Фишка в том, что в инвентаре нет блоков для соединения или вроде того. А значит, что при помощи существующих моделей создать то, что мы видим в сумке, не выйдет. Разработчики решили пойти обходным путём и добавили отдельную модель для инвентаря.
Итак, добавляем: stone_stick_wall_side.json, stone_stick_wall_post.json, stone_stick_wall_inventory.json.
stone_stick_wall_side.json:
1 2 3 4 5 6 |
{ "parent": "block/template_wall_side", "textures": { "wall": "tutorial_mod_gs:block/stone_stick_block" } } |
stone_stick_wall_post.json:
1 2 3 4 5 6 |
{ "parent": "block/template_wall_post", "textures": { "wall": "tutorial_mod_gs:block/stone_stick_block" } } |
stone_stick_wall_inventory.json
1 2 3 4 5 6 |
{ "parent": "block/wall_inventory", "textures": { "wall": "tutorial_mod_gs:block/stone_stick_block" } } |
Делаем модель для предмета stone_stick_wall.json:
1 2 3 |
{ "parent": "tutorial_mod_gs:block/stone_stick_wall_inventory" } |
Можно запускать? Давайте попробуем!
Пробуем ставить…
Ну, я бы сказал, что-то не так работает. Хотя, такой результат тоже вполне ничего 😀
Если добавить какие-то стандартные стены, то можно понять, что ни наши стены, ни другие не хотят дружить с новенькими. При этом в обратную сторону это не работает и новенький так и тянется к другим.
Это еще одна особенность стен. Чтобы стена стала полноправной стеной — нужно добавить её в список стен! В игре есть система тегов, которые определяют определённые взаимодействия в игре. И это один из наглядных примеров подобного.
Чтобы добавить нашу стену в общий список нужно создать папку data, в ней папку minecraft, а уже в ней tags, в ней blocks и уже в blocks добавить файл walls.json. Проще показать путь:
И пишем в файл такой код:
1 2 3 4 5 6 |
{ "replace": false, "values": [ "tutorial_mod_gs:stone_stick_wall" ] } |
Тут мы говорим игре, что, не заменяя изначальный список нужно добавить к нему наш блок. Если вы укажете replace – true, то все стены перестанут быть стенами, а останется только новая. Но зачем?
Пробуем ещё раз:
Изначально изменений не будет, но если заменить пару блоков, то остальные игра обновит автоматически.
На этом, пожалуй, всё. Как видите, сделать свои версии ванильных блоков очень легко. Исходный код ищите тут.
Пингбэк: [1.15.2] Рецепты. Верстак, печь, камнерез, костёр, коптильня – GeekStand
Пингбэк: Создание модов для Minecraft 1.15 – GeekStand