Нет описания правки |
Allblox14482 (обс. | вклад) (разделение, оформление, иллюстрирование) |
||
Строка 1: | Строка 1: | ||
− | {{К разъединению|[[Создание модификаций с помощью Forge/1.7+/Основные уроки|/Основные уроки]], [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки|/Дополнительные уроки]] <br>а здесь оставить «Подготовку среды» и обзорный список уроков|Большой объём страницы ({{REVISIONSIZE}}).<br>Структура текста допускает разделение.}} |
||
'''Здесь находятся инструкции по созданию модификаций, работающие для версии 1.7+''' |
'''Здесь находятся инструкции по созданию модификаций, работающие для версии 1.7+''' |
||
Строка 25: | Строка 24: | ||
Выполнение команды займёт какое-то время, после чего должно появиться сообщение рода Build Successful. |
Выполнение команды займёт какое-то время, после чего должно появиться сообщение рода Build Successful. |
||
+ | |||
+ | [[Файл:Команда setupDecompWorkspace eclipse.png|320px|thumb|center|Пример результата выполнения команды:<br><code>gradlew.bat setupDecompWorkspace eclipse</code>]] |
||
Если же появляется какая-либо ошибка: |
Если же появляется какая-либо ошибка: |
||
Строка 34: | Строка 35: | ||
=== Настройка Eclipse === |
=== Настройка Eclipse === |
||
− | [[Файл:Eclipse после установки.png|250px|thumb|right|Интерфейс Eclipse после правильной установки.]] |
||
Нужно настроить Eclipse для работы с Minecraft. Первым делом зайдите в него. Он предложит выбрать рабочую директорию (Workspace). Введите туда путь к папке «eclipse» в папке (Путь к папке должен содержать только английские буквы), куда вы распаковали содержимое Forge и поставьте галочку для того чтоб окно больше не появлялось. В примере это «D:\MCModding\eclipse». Если всё прошло успешно, то слева в Eclipse вы увидите раскрывающееся меню Minecraft, а снизу не увидите красных ошибок. |
Нужно настроить Eclipse для работы с Minecraft. Первым делом зайдите в него. Он предложит выбрать рабочую директорию (Workspace). Введите туда путь к папке «eclipse» в папке (Путь к папке должен содержать только английские буквы), куда вы распаковали содержимое Forge и поставьте галочку для того чтоб окно больше не появлялось. В примере это «D:\MCModding\eclipse». Если всё прошло успешно, то слева в Eclipse вы увидите раскрывающееся меню Minecraft, а снизу не увидите красных ошибок. |
||
+ | [[Файл:Eclipse после установки.png|420px|thumb|center|Интерфейс Eclipse после правильной установки.]] |
||
− | {{-}} |
||
=== Настройка IntelliJ IDEA === |
=== Настройка IntelliJ IDEA === |
||
− | + | Если вместо Eclipse Вы решили использовать IntelliJ IDEA, то после того, как Forge скомпилирован и установлен, необходимо запустить IDEA, и в появившемся окне нажать 'Import Project'. После чего выбираем в папке «D:\MCModding» файл build.gradle. В появившемся окне Вам предложат выбрать способ компиляции (рекомендуется оставить значение Use default gradle wrapper.) В строчке ниже выберите Ваш JAVA_HOME. В пункте «Формат проекта» нужно обязательно выбрать «.ipr (file based)». В противном случае, придётся подключать все библиотеки и настраивать запуск самостоятельно. После всего этого нажмите OK. Ждите, пока сборка скомпилируется. |
|
В случае, если ваша IntelliJ IDEA установлена правильно и она различает формат *.ipr, вы можете просто дважды нажать по файлу <НазваниеПроекта>.ipr в директории вашего MCP. IDEA все сделает за вас. |
В случае, если ваша IntelliJ IDEA установлена правильно и она различает формат *.ipr, вы можете просто дважды нажать по файлу <НазваниеПроекта>.ipr в директории вашего MCP. IDEA все сделает за вас. |
||
− | + | Поздравляем! Вы успешно настроили среду для того, чтобы начать писать моды на ней. |
|
== Основные уроки == |
== Основные уроки == |
||
+ | {{Main|Создание модификаций с помощью Forge/1.7+/Основные уроки}} |
||
− | |||
− | + | # [[Создание модификаций с помощью Forge/1.7+/Основные уроки#Урок 1. Директория Eclipse (Установка среды)|Директория Eclipse (Установка среды)]] |
|
+ | # [[Создание модификаций с помощью Forge/1.7+/Основные уроки#Урок 2. Главный класс|Главный класс]] |
||
− | Теперь вы можете приступать к созданию своего первого мода. |
||
+ | # [[Создание модификаций с помощью Forge/1.7+/Основные уроки#Урок 3. Блок|Блок]] |
||
− | |||
+ | # [[Создание модификаций с помощью Forge/1.7+/Основные уроки#Урок 4. Предмет|Предмет]] |
||
− | Заранее придумайте название своего мода (например, MyBestMod). Перейдём к тому, где должен быть мод в структуре классов Minecraft. Существует некоторый этикет, как оформлять код и всё, что с ним связано. Раскройте проект Minecraft, далее <code>src/main/java</code>. В <code>src/main/java</code> лежит всё, что относится к коду Minecraft. Как вы видите, там есть подпапки (или пакеты) типа net.minecraft.client<ref>В Java директории указываются не слешами, как в Windows, а точками. То есть «net.minecraft.client» — это когда папка «client» лежит в папке «minecraft», которая лежит в папке «net».</ref> и так далее. В Java пакетах принято структурировать пакеты так: <code>domain.product</code> или <code>domain.company.product</code>, то есть первое — домен (com, net, ru), далее название компании (если вы единственный разработчик — ваш ник) и название продукта (мода), или же название компании опускается.<ref>[http://www.oracle.com/technetwork/java/codeconventions-135099.html Документация Oracle]</ref><ref>[[wikipedia:Java package#Package naming conventions|Статья «Java package» на английской Википедии]]</ref> Minecraft, Minecraft Forge и FML имеют первый вариант структурирования пакета. То есть, если ваш никнейм, например, platon, а название вашего мода — My Best Mod, то нажмите на src/main/java {{Кнопка|ПКМ}} и выберите New → package. В поле «Name» наберите «com.platon.mybestmod» с учётом регистра. Это создаст директорию, в которой вы и будете работать с модом. Всё, далее можете приступать непосредственно к его созданию. |
||
+ | # [[Создание модификаций с помощью Forge/1.7+/Основные уроки#Урок 5. Крафт|Крафт]] |
||
− | |||
+ | # [[Создание модификаций с помощью Forge/1.7+/Основные уроки#Урок 6. Компиляция|Компиляция]] |
||
− | === Урок 2. Главный класс === |
||
+ | # [[Создание модификаций с помощью Forge/1.7+/Основные уроки#Урок 7. Генерация|Генерация]] |
||
− | Итак, можно приступить к созданию мода. Создадим его основу. |
||
+ | # [[Создание модификаций с помощью Forge/1.7+/Основные уроки#Урок 8. Прокси и инстанция|Прокси и инстанция]] |
||
− | |||
+ | # [[Создание модификаций с помощью Forge/1.7+/Основные уроки#Урок 9. Моб|Моб]] |
||
− | Нажмите {{Кнопка|ПКМ}} на директории мода (com.platon.mybestmod) и выберите New → Class, и в поле Name введите название класса. Это главный класс мода, поэтому пусть это будет указано. Например, одно из возможных названий — «BaseMyBestMod». Обратите внимание, что каждое слово написано с большой буквы (естественно, именно так делать необязательно, но общепринятым считается именно этот вариант). Далее просто нажмите Finish. Всё, у вас теперь есть главный класс мода. |
||
− | |||
− | Приступим к написанию кода. Запишем ВНЕ тела, то есть над строчкой <code>public class... </code><ref>Любое тело в Java обозначается фигурными скобками и обозначает внутренности некоторой подпрограммы. Например, <code>public class BaseMyBestMod {</code>} указывает, что это класс, а в скобках написано, что он делает.</ref> класса следующую строчку: |
||
− | <syntaxhighlight lang="Java">@Mod (modid = "mybestmod", name="My Best Mod", version = "1.0")</syntaxhighlight> |
||
− | |||
− | Вы написали, что ваша модификация называется «My Best Mod» и имеет версию 1.0. Но Eclipse сообщает об ошибке, так как ему неизвестно, что значит @Mod. Нужно импортировать соответствующий класс, для этого после строчки с указанием пакета (<code>package platon.mods.mybestmod;</code>) напишите следующую строчку: |
||
− | <syntaxhighlight lang="Java">import cpw.mods.fml.common.Mod;</syntaxhighlight> |
||
− | После этого сообщение об ошибке должно исчезнуть. |
||
− | |||
− | Далее уже в теле (в фигурных скобках) пишем: |
||
− | |||
− | <syntaxhighlight lang="Java">@EventHandler |
||
− | public void preLoad(FMLPreInitializationEvent event) |
||
− | { |
||
− | |||
− | }</syntaxhighlight> |
||
− | Опять ошибка. Как вы поняли, ему опять не хватает импортированных классов. Почти всегда можно автоматически их импортировать, если Eclipse знает или догадывается, где их искать<ref>В Eclipse встроена функция автоматической организации импортируемых классов ({{Кнопка|Ctrl+Shift+O}}).</ref>. |
||
− | |||
− | Вот и всё. Основа мода готова. Можете запустить Minecraft (Зеленая кнопка сверху → Client) и увидеть в списке модов свой мод. По крайней мере для того, чтобы приступить к созданию первого блока. |
||
− | |||
− | === Урок 3. Блок === |
||
− | Приступим к созданию своего первого собственного блока. |
||
− | |||
− | В самом начале тела Класса (После первой фигурной скобки если вы ещё не поняли) пишем: |
||
− | <syntaxhighlight lang="Java">public static Block bestblockever;</syntaxhighlight> |
||
− | |||
− | Public значит, что объект bestblockever (такое кодовое имя мы дали блоку) может быть вызван откуда угодно. Static, что он статичный, а Block значит тип объекта. А вот описание объекта Block надо импортировать, так как в нашем классе этого не указано. Для этого нажмем по ошибке и выберите импорт из net.minecraft.block, а не откуда либо ещё. В случаях с множественными вариантами импорта {{Кнопка|Ctrl-Shift-O}} лучше не нажимать. Всё, ошибка исчезла. |
||
− | |||
− | Теперь укажем, где про блок будет написано более подробно. В теле метода preLoad() напишем строчку: |
||
− | <syntaxhighlight lang="Java">bestblockever = new BlockBestBlockEver();</syntaxhighlight> |
||
− | |||
− | Эта строка говорит, что про объект bestblockever будет написано в классе BlockBestBlockEver. И он выдаёт ошибку. Естественно, ведь никакого класса BlockBestBlockEver не существует. Его легко создать, нажав по ошибке и выбрав Create Class… Далее нажмите Finish. |
||
− | |||
− | Вы перейдете сразу в созданный вами класс. Сразу после названия класса перед фигурной скобкой допишите extends Block. Первую ошибку исправьте, импортировав недостающий класс Block (net.minecraft.block). Вторую ошибку вы видите, потому что созданный класс — наследник класса Block в котором написано что такое блок. И не хватает аргументов которые нужно дать тому классу, чтобы ваш блок был особенным. материал, прочность и т. д. Поэтому просто исправьте ошибку первым способом, он сам её исправит, дописав немного. Строку с двумя слешами, комментарий, можно стереть<ref>В Java если строчка написана после двух слешей, то она воспринимается не как код, а как комментарий. Также можно заключить несколько строк в комментарий, закрыв их в конструкцию <code>/*Закомментированный текст*/</code></ref>. |
||
− | |||
− | В скобках у объекта, где написаны аргументы, которые должны быть посланы снаружи уберите аргумент Material par1Material. Мы пошлем его отсюда, а не снаружи класса. Теперь в следующей строчке в скобках у super() замените «par1Material» на «Material.rock», или после точки сами выберите нужный вам материал.(Не забудьте про импорт) То есть мы посылаем в суперкласс Block что материал блока камень. То есть блок как камень: на звук как камень, ломается с тем же звуком и т. д. Список доступных материалов можно посмотреть через точку после Material. |
||
− | |||
− | Итак, давайте поработаем над характеристиками блока. Это можно сделать из главного класса, указывая их через точку после <code>bestblockever = new BlockBestBlockEver();</code> (до точки с запятой). Но можно и отсюда. Для этого пишите их в теле этого объекта после «this.» «this.» также можно не писать. |
||
− | |||
− | Основные характеристики: |
||
− | |||
− | <syntaxhighlight lang="Java">this.setBlockName("bestblockever"); |
||
− | // Без этой строчки у блока не будет внутриигрового (нелокализированного) имени, он просто будет называться «null». |
||
− | |||
− | this.setCreativeTab(CreativeTabs.tabBlock);// |
||
− | // Указывает в какой вкладке будет находиться блок в креативе (доступные также можно посмотреть через точку от CreativeTabs). Не забудьте про импорт. |
||
− | |||
− | this.setHardness(15F); |
||
− | // Устанавливает прочность, то есть как долго блок будет ломаться. |
||
− | |||
− | this.setResistance(10F); |
||
− | // Устанавливает взрывоустойчивость блока. |
||
− | |||
− | this.setHarvestLevel("pickaxe", 3); |
||
− | // Устанавливает, киркой какого уровня можно сломать. Например, алмазная = 3. |
||
− | </syntaxhighlight> |
||
− | |||
− | Также можно установить будет ли блок [[свет]]иться. Чем больше число, тем светлее. Вместо 0 пишете уровень света, создаваемого блоком, умноженное на 10. Таким образом нужно вставить туда значение от 0 до 150 (150 означает уровень света 15, максимальное значение). |
||
− | |||
− | <syntaxhighlight lang="Java">this.setLightLevel(0F);</syntaxhighlight> |
||
− | |||
− | Теперь давайте добавим текстуру блоку. Она может быть любой, но размером 16×16 или 32х32 пикселей. Например можно создать картинку, написать в ней «Б» и уменьшить до 16×16 пикселей и чуть-чуть подредактировать. Можете скачать эту: [[Файл:Пример текстуры(Туториал Forge).png]] Желательно, чтоб название было как у блока, а расширение обязательно .png |
||
− | |||
− | Так, текстура есть, теперь пропишем её в код. Следующее пропишите всё в том же методе блока. |
||
− | <syntaxhighlight lang="Java">this.setBlockTextureName("mybestmod:BlockBestBlockEver");</syntaxhighlight> |
||
− | |||
− | Давайте немного разберемся насчёт «mybestmod:BlockBestBlockEver». Должно быть написано «краткое название мода: название файла», но название без .png. '''ВАЖНО! Для пользователей IntelliJ IDEA''' — ide автоматически склеивает названия папок как ей вздумается, но чтобы работало подключение ресурсов физическая структура папок должна быть строго такой: assets/mymod/textures/blocks — то есть это отдельные папки! Если создавать через New -> Directory и указать «assets.mymod» — она НЕ создаст отдельные подпапки и работать не будет! |
||
− | |||
− | Теперь поместим текстуру в проект. Слева в окне директорий проекта выберите <code>src/main/resources</code> и нажмите правой кнопкой и создайте директорию.(New → package) Назовите так: assets.краткое название мода.textures.blocks (assets.mybestmod.textures.blocks). Теперь мышкой перетяните текстуру из windows в эту директорию. В окне выберите «Copy files». |
||
− | |||
− | Теперь нужно зарегистрировать блок. Перейдите в главный класс и в самом конце метода preLoad допишите |
||
− | <syntaxhighlight lang="Java">GameRegistry.registerBlock(bestblockever, "bestblockever");</syntaxhighlight> |
||
− | |||
− | Это должно зарегистрировать блок в Forge. |
||
− | |||
− | И последнее: мы не указали, как будет называться блок в игре. |
||
− | Локализация описана в [[#Локализация названий в игре|этом]] доп. уроке. |
||
− | |||
− | Ну вот и всё, блок создан. Теперь необходимо проверить его работоспособность. Запускайте Minecraft с вашим модом! Но сначала сохраните оба класса ({{Кнопка|Ctrl-S}}). Для запуска нужно нажать сверху зелёный круг с треугольником (или {{Кнопка|Ctrl-F11}}). После запуска посмотрите, есть ли ваш мод в окне моды (в главном меню), создайте новый мир в режиме креатив и найдите свой блок в креатив-инвентаре во вкладке блоки. Если он там есть, берется, ставится и ломается, то поздравляю: мод, добавляющий блок, создан! |
||
− | |||
− | === Урок 4. Предмет === |
||
− | Ну вот мы и создали блок. Но ведь в игре присутствуют не только блоки, но и предметы. Такие как еда, инструменты, в общем всё подряд, что обычно нельзя поставить на землю. Давайте создадим такой предмет. Для примера возьмём кирку. |
||
− | |||
− | Перейдем в главный класс мода. До метода preLoad() сразу после <code>public static Block bestblockever;</code> допишите: |
||
− | <syntaxhighlight lang="Java">public static Item bestpickaxe;</syntaxhighlight> |
||
− | |||
− | Тем самым мы создадим переменную типа Item с кодовым названием кирки. |
||
− | |||
− | В методе preLoad() для удобства отступите одну строку от того что уже написано, и пишите туда следующее: (Я сразу напишу всё, что нужно, многие элементы описания предмета совпадают с описанием блока, особой разницы нет) |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | bestpickaxe = new BestPickAxe().setUnlocalizedName("bestpickaxe"); |
||
− | GameRegistry.registerItem(bestpickaxe, "bestpickaxe"); |
||
− | </syntaxhighlight> |
||
− | |||
− | Итак, мы создали кирку, дали ей нелокализированное имя<ref>С помощью <code>.setUnlocalizedName("bestpickaxe")</code> мы сразу передали методу BestPickAxe информацию, вместо того чтоб в нём писать <code>this.setUnlocalizedName("bestpickaxe")</code> По сути можно все такие аргументы послать через точку.</ref> и зарегистрировали в Forge. Щелкнув по ошибке создадим класс этой кирки. Класс создан, но Eclipse не знает, что мы хотим создать — еду или инструмент, поэтому сделаем этот класс наследником класса, где написано про инструмент или еду или что хотите, главное, что про предмет, а не блок. В строчке <code>public class BestPickAxe{</code> после BestPickAxe допишите <code>extends ItemPickaxe</code> и импортируйте этот самый ItemPickaxe. |
||
− | |||
− | Немного об ItemPickaxe: '''pickaxe''' — это кирка по-английски, и, соответственно, <code>extends ItemPickaxe</code> говорит о том, что мы «продолжаем» или дополняем класс ItemPickaxe, в котором указаны все базовые характеристики и функции, такого Item’а или предмета, как кирка. Таким образом можно продолжать любой класс, в зависимости от того, какой предмет нужен. То есть, если нужна еда, то мы продолжаем класс ItemFood, если броня, то ItemArmor, а если свой особенный предмет, то просто Item. Не забывайте: вы всегда можете посмотреть список возможных продолжений того, что вы пишете.<ref>Когда вы вводите какой-то путь к методу, переменной и т. п. через точку, после ввода точки вы всегда видите возможные продолжения, пользуйтесь этим, чтобы сократить время написания кода, или если не знаете точно, что вам нужно (ориентируйтесь по тому, что посылается в метод и что он возвращает). Если список исчез, всегда, даже когда нет точки, вы можете посмотреть список доступных продолжений, нажав {{Кнопка|Ctrl+Пробел}}</ref> |
||
− | |||
− | Теперь, не обращая внимания на появившуюся ошибку вставьте в тело это: |
||
− | <syntaxhighlight lang="Java"> |
||
− | protected BestPickAxe() { |
||
− | super(ToolMaterial.EMERALD); |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | Тогда ошибка исчезнет. Строка <code>super(ToolMaterial.EMERALD);</code> говорит о том, что пошлёт в супер-класс информацию о том, что кирка обладает свойствами алмазной кирки. Ну и также допишем после этой строчки |
||
− | |||
− | <syntaxhighlight lang="Java">this.setCreativeTab(CreativeTabs.tabTools);</syntaxhighlight> |
||
− | |||
− | тем самым добавив кирку в раздел инструменты в режиме «[[Творчество]]». |
||
− | |||
− | Почти готово. осталось только добавить текстуру, давайте модифицируем текстуру из Minecraft. Зайдите в папку c Minecraft\versions\1.7.2, там откройте jar-файл c помощью архиватора, в архиве перейдите в assets\items и там найдите какую-нибудь текстуру кирки, извлеките на рабочий стол. Файлы текстур НЕЛЬЗЯ редактировать обычным Paint’ом, так как текстура должна быть кое-где прозрачной, если вы не хотите конечно идеально квадратную кирку. В общем отредактируйте текстуру как угодно, главное чтоб была 16×16. Назовите текстуру BestPickAxe.png Теперь создайте в проекте директорию с текстурами предметов. Для этого {{Кнопка|ПКМ}} по src → New → package а в названии напишите <code>assets.mybestmod.textures.items</code> и туда мышью с раб. стола перенесите готовую текстуру и нажмите ОК. Теперь скажем предмету где его текстура. Пропишите следующее всё в том же методе кирки. |
||
− | |||
− | <syntaxhighlight lang="Java">this.setTextureName("mybestmod:BestPickAxe");</syntaxhighlight> |
||
− | |||
− | И можно запускать для проверки. |
||
− | |||
− | Собственно вот мы и создали первый предмет — инструмент — кирку, которая по свойствам, как алмазная. В [[#Свой материал для инструмента|этом]] доп. уроке вы можете посмотреть, как создать инструмент с особыми свойствами. |
||
− | |||
− | === Урок 5. Крафт === |
||
− | Если Вы создаёте модификацию исключительно для добавления/удаления рецептов уже существующих вещей, то следует также рассмотреть вариант использования MineTweaker. |
||
− | Собственно, у нас есть блок и предмет. Мы можем их держать в руках, а блок даже ставить. Но а если мы хотим достать их, играя в режиме Выживания? Тогда блок или предмет можно только найти или скрафтить. Добавить крафт очень просто. Предположим, рецепт блока должен быть следующим: |
||
− | |||
− | {{Крафт |
||
− | |A1= Железный слиток |B1= Железный слиток|C1= Железный слиток |
||
− | |A2= Гравий|B2= Обсидиан |C2= Гравий |
||
− | |A3= Железный слиток|B3= Железный слиток|C3= Железный слиток |
||
− | }} |
||
− | |||
− | Тогда я запишу вот это в тело метода preLoad главного класса '''после''' строки регистрации блока в Forge: |
||
− | <syntaxhighlight lang="Java"> |
||
− | GameRegistry.addRecipe(new ItemStack(BaseMyBestMod.bestblockever, 1), |
||
− | |||
− | new Object[]{ |
||
− | |||
− | "###", "XYX", "###", |
||
− | |||
− | ('X'), Blocks.gravel, |
||
− | ('#'), Items.iron_ingot, |
||
− | ('Y'), Blocks.obsidian |
||
− | |||
− | } |
||
− | |||
− | ); |
||
− | </syntaxhighlight> |
||
− | <!-- Не забудьте ничего импортировать. Что? --> |
||
− | |||
− | Давайте разберем, что тут написано: Итак с помощью GameRegistry мы добавляем новый рецепт, new itemStack значит, что создастся новая стопка с предметом bestblockever который объявлен в классе BaseMyBestMod в количестве одной штуки (вместо 1 можно вписать любое число до 64). А далее уже записана сетка крафта. Как мы помним в верстаке мы видим всего 9 клеток, здесь первая строка верстака это «###», вторая строка — это «XYX», ну и последняя — «###». Понятней будет, если посмотреть вот так: |
||
− | "###" |
||
− | "XYX" |
||
− | "###" |
||
− | |||
− | Каждый предмет в крафте обозначается своим личным знаком (любым). Далее это записано как <code>('X'), Blocks.gravel</code> То есть это означает, что X — это гравий, который является блоком. Соответственно знак # — это слиток железа (который является предметом, а не блоком), а Y — это блок обсидиана. Если нужно, чтоб в ячейке крафта ничего не лежало, то вместо знака пишется пробел (Например " # " значит что посередине будет слиток железа, а по бокам ничего). |
||
− | |||
− | Добавить рецепт крафта можно не только вашему блоку или предмету. Можно вписывать вместо <code>BaseMyBestMod.bestblockever</code> или <code>Blocks.obsidian</code> что угодно, главное что бы после точки была указана зарегистрированная переменная типа Block или Item. А до точки — это просто путь к этой переменной. |
||
− | |||
− | Если хотите создать крафт, который можно произвести в инвентаре, вместо «###», «XYX», «###» используйте «AA», «BC» соответственно. |
||
− | |||
− | Бесформенный крафт (то есть крафт, в котором можно располагать ингредиенты как угодно) опишите так: |
||
− | <syntaxhighlight lang="Java">GameRegistry.addShapelessRecipe(new ItemStack(Blocks.grass, 4), new Object[] {Blocks.gravel, Blocks.gravel, Items.arrow});</syntaxhighlight> |
||
− | То есть если вы положите в верстак/инвентарь 2 блока гравия и стрелу, то получите 4 блока Земли, покрытой травой. |
||
− | |||
− | Если у блока/предмета есть несколько видов (например: дубовые, еловые, березовые доски и т. д.), то указав просто например: <code>Blocks.Planks</code> в крафте можно будет использовать любые доски! Что бы это исправить вместо <code>Block.Planks</code> напишем <code>new ItemStack(Blocks.planks, 1, 0)</code> |
||
− | |||
− | Первое число всегда 1. Изменяем только второе число. 0 — это дубовые доски, 1 — еловые доски и т. д. [[Нумерация данных|(см. ID)]] |
||
− | <syntaxhighlight lang="Java"> |
||
− | GameRegistry.addRecipe(new ItemStack(MuchBlocks.MyBlockS, 1), |
||
− | new Object[]{ " I ", "IPI", " I ", |
||
− | ('I'), Items.iron_ingot, ('P'), new ItemStack(Blocks.planks, 1, 0)} |
||
− | ); |
||
− | </syntaxhighlight> |
||
− | |||
− | Так же в игре, как мы знаем, присутствует переплавка одних предметов/блоков в другие. Рецепт такой переплавки создаётся всего одной строкой, которую нужно писать после регистрации блока bestblockever: |
||
− | |||
− | <syntaxhighlight lang="Java">GameRegistry.addSmelting(bestblockever, new ItemStack(Blocks.diamond_block, 2), 1.0F);</syntaxhighlight> |
||
− | |||
− | Но теперь разберём. Итак, первой в скобках указана переменная типа Block (также можно Item), в данном случае это наш блок, затем идет переменная типа ItemStack, которая создаётся сразу же. У этой переменной уточняется, что создастся стак с блоком или предметом, в данном случае алмазным блоком, в количестве 2. Ну и последняя переменная отвечает за количество опыта, получаемого при переплавке. |
||
− | |||
− | Собственно, всё. |
||
− | |||
− | === Урок 6. Компиляция === |
||
− | Что же, вы написали мод, он работает, но вы хотите чтобы он работал и просто на Minecraft. Давайте наконец его скомпилируем! |
||
− | |||
− | Компилировать мод очень просто, запустите файл gradlew.bat с командой build. Или другими словами создайте bat-файл (или измените оставшийся) с кодом: |
||
− | gradlew.bat build |
||
− | |||
− | и запустите его. После автоматического закрытия консоли мод скомпилирован и находится в папке build/libs. |
||
− | Если для компиляции мода требуется подключение дополнительных jar библиотек, то необходимо в корневой папке проекта (MCModding) создать папку libs и поместить все необходимые файлы в неё. |
||
− | |||
− | Теперь немного о том, что получилось. У нас есть файл с расширением jar, а в нём наш мод, и собственно, можно кидать его в папку mods и пользоваться, но нужно отметить что в этом jar-архиве есть папка META-INF, которая запрещает что-либо из него удалять (Если что .jar можно открывать любым архиватором). Так же следует обратить внимание на то что компилятор автоматически вставит в архив всё, что вы «напрограммировали» и там будут весь код и все ресурсы от модов над которыми вы работаете. Если для вас это неприемлемо, просто удалите лишние пути из архива (например platon.mods.megamod, если работаете с mybestmod и т. п.). Так же можно со спокойной совестью удалить META-INF и вообще всё разрахивировать и упаковать в zip-архив, он также будет работать. |
||
− | |||
− | Так же немного о build.gradle Вы можете его модифицировать так, чтобы jar-файл автоматически назывался как надо. Откройте его любым текстовым редактором. Вы можете изменить следующие строки, как захотите, например так: |
||
− | version = "1.0" |
||
− | group= "com.platon.mybestmod" |
||
− | archivesBaseName = "My Best Mod" |
||
− | |||
− | Сохраните файл. Таким образом вы получите при компиляции файл My Best Mod-1.0.jar |
||
− | |||
− | === Урок 7. Генерация === |
||
− | Теперь мы сделаем так, чтобы теперь какой-либо блок, аналогично рудам, генерировался в обычном мире, в [[Нижний мир|нижнем мире]] или в [[Край|краю]]. Теперь в главном классе (BaseMyBestMod) после регистрации блока в Forge регистрируем новую переменную: |
||
− | |||
− | <syntaxhighlight lang="Java">public static BestBlockGenerator bestblockgenerator = new BestBlockGenerator();</syntaxhighlight> |
||
− | |||
− | и исправляем ошибку, создав нужный класс. Естественно, вместо BestBlockGenerator вы можете использовать любое название. Далее в методе <code>preLoad()</code> в любом месте после регистрации блока, который хотите генерировать, добавьте такой код: |
||
− | <syntaxhighlight lang="Java">GameRegistry.registerWorldGenerator(bestblockgenerator, 0);</syntaxhighlight> |
||
− | |||
− | Тем самым вы зарегистрируете ваш генератор. Число «0» обозначает каким по счёту будет загружаться генератор (0 — первым, 1 — вторым и т. д.). |
||
− | |||
− | Теперь в созданном классе после <code>public class BestBlockGenerator</code> добавьте <code>implements IWorldGenerator</code> и в тело класса добавьте это: |
||
− | |||
− | {{Спойлер|<small><syntaxhighlight lang="Java"> |
||
− | @Override |
||
− | public void generate(Random rand, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider) { |
||
− | |||
− | generateOverworld(rand, chunkX, chunkZ, world); |
||
− | generateNether(rand, chunkX, chunkZ, world); |
||
− | generateEnd(rand, chunkX, chunkZ, world); |
||
− | |||
− | } |
||
− | |||
− | private void generateOverworld(Random rand, int chunkX, int chunkZ, World world) { |
||
− | |||
− | generateOverworld(world, rand, chunkX * 16, chunkZ * 16); |
||
− | |||
− | } |
||
− | |||
− | private void generateNether(Random rand, int chunkX, int chunkZ, World world) { |
||
− | |||
− | generateNether(world, rand, chunkX * 16, chunkZ * 16); |
||
− | |||
− | } |
||
− | |||
− | private void generateEnd(Random rand, int chunkX, int chunkZ, World world) { |
||
− | |||
− | generateEnd(world, rand, chunkX * 16, chunkZ * 16); |
||
− | |||
− | } |
||
− | |||
− | public void generateOverworld(World world, Random rand, int blockXPos, int blockZPos) { |
||
− | |||
− | addOreSpawn(BaseMyBestMod.bestblockever, Blocks.stone, world, rand, blockXPos, blockZPos, 16, 16, 1, 2, 1, 1, 10, 5, 6); |
||
− | |||
− | } |
||
− | |||
− | public void generateNether(World world, Random rand, int blockXPos, int blockZPos) { |
||
− | |||
− | addOreSpawn(BaseMyBestMod.bestblockever, Blocks.netherrack, world, rand, blockXPos, blockZPos, 16, 16, 1, 2, 1, 1, 10, 5, 6); |
||
− | |||
− | } |
||
− | |||
− | public void generateEnd(World world, Random rand, int blockXPos, int blockZPos) { |
||
− | |||
− | addOreSpawn(BaseMyBestMod.bestblockever, Blocks.end_stone, world, rand, blockXPos, blockZPos, 16, 16, 1, 2, 1, 1, 10, 5, 6); |
||
− | |||
− | } |
||
− | |||
− | /** |
||
− | * Добавляет генерацию руды в Minecraft. Просто воспользуйтесь этим методом для регистрации генерируемых руд. |
||
− | |||
− | * @param block Блок, который хотите генерировать |
||
− | * @param block replace Блок, рядом с которым хотите генерировать |
||
− | * @param world Мир (не измерение), в котором этот блок должен генерироваться |
||
− | * @param random Случайное число для получения координат генерации блока |
||
− | * @param blockXPos Число для того, чтобы было пустое место по координатам X для метода генерации (использует кварцевая руда) |
||
− | * @param blockZPos Число для того, чтобы было пустое место по координатам Z для метода генерации (использует кварцевая руда) |
||
− | * @param maxX Число, которое настроит максимальную X координату для генерации руды на оси X на чанк |
||
− | * @param maxZ Число, которое настроит максимальную Z координату для генерации руды на оси Z на чанк |
||
− | * @param minVeinSize Минимальное число блоков руды в одной жиле |
||
− | * @param maxVeinSize Максимальное число блоков руды в одной жиле |
||
− | * @param minVeinsPerChunk Минимальное число жил в чанке |
||
− | * @param maxVeinsPerChunk Максимальное число жил в чанке |
||
− | * @param chancesToSpawn Шанс генерации блоков на чанк в процентах |
||
− | * @param minY Минимальная координата Y на которой руда может сгенерироваться |
||
− | * @param maxY Максимальная координата Y на которой руда может сгенерироваться |
||
− | **/ |
||
− | |||
− | public static void addOreSpawn(Block ore, Block replace, World world, Random rand, int blockXPos, int blockZPos, int maxX, int maxZ, |
||
− | int minVeinSize, int maxVeinSize, int minVeinsPerChunk, int maxVeinsPerChunk, int chanceToSpawn, int minY, int maxY) { |
||
− | if (rand.nextInt(101) < (100 - chanceToSpawn)) return; |
||
− | int veins = rand.nextInt(maxVeinsPerChunk - minVeinsPerChunk + 1) + minVeinsPerChunk; |
||
− | for (int i = 0; i < veins; i++) { |
||
− | int posX = blockXPos + rand.nextInt(maxX); |
||
− | int posY = minY + rand.nextInt(maxY - minY); |
||
− | int posZ = blockZPos + rand.nextInt(maxZ); |
||
− | (new WorldGenMinable(ore, minVeinSize + rand.nextInt(maxVeinSize - minVeinSize + 1), |
||
− | replace)).generate(world, rand, posX, posY, posZ); |
||
− | } |
||
− | } |
||
− | </syntaxhighlight></small>}} |
||
− | |||
− | Описание параметров метода addOreSpawn() можно увидеть (чтобы разобраться в них), наведя курсор на его название. Эту информацию мы привязали к методу, благодаря javadoc-комментарию<ref>[[ruwiki:Javadoc|Javadoc-комментарии]] оставляются над методом, классом, переменной и т. д. для того, чтобы описать назначения класса, метода и т. д. Обособляется конструкцией /**Javadoc-комментарий*/</ref>. |
||
− | |||
− | Теперь можно запускать и смотреть результаты. |
||
− | |||
− | <gallery mode="packed"> |
||
− | Генерация руды в аду.png |
||
− | Генерация собственносозданной руды.png |
||
− | Генерация руды в крае.png |
||
− | </gallery> |
||
− | |||
− | === Урок 8. Прокси и инстанция === |
||
− | Прокси и инстанция (экземпляр) нужны для создания мобов, регистрация собственных рендеров, звуков и др. Для создания инстанции добавьте в главный файл мода следующий код: |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | @Instance("mybestmod") |
||
− | public static MyBestMod instance; |
||
− | </syntaxhighlight> |
||
− | |||
− | Также, если вы хотите сократить число импортов, то вместо <code>@Instance</code> сделайте <code>@Mod.Instance</code>, от этого ничего не изменится. '''Инстанция''' — или '''экземпляр''' — это ссылка на ваш мод, которую использует Forge. Если вы не создали её сами, то Forge создаёт её для вас, но в этом случае вы не сможете взаимодействовать с ней, поэтому рекомендовано создать её самому. |
||
− | |||
− | Теперь следует сделать прокси. '''Прокси''' фильтрует контент на то, что должно быть для сервера, а что для клиента. Сервер хранит данные о мире, в то время как клиент рендерит мир. Для создания прокси создайте два класса: ClientProxy для клиента и CommonProxy для сервера. Суперклассом ClientProxy должен быть CommonProxy. Теперь регистрация прокси. Просто добавьте следующий код в главный класс мода: |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | @SidedProxy(clientSide = "ваш.пакет.ClientProxy", serverSide = "ваш.пакет.CommonProxy") |
||
− | public static CommonProxy proxy; |
||
− | </syntaxhighlight> |
||
− | |||
− | Прокси и инстанция готовы. |
||
− | |||
− | === Урок 9. Моб === |
||
− | Можно приступать к созданию [[моб]]а. В примере будет создание враждебного моба, со скином игрока. Начните с главного файла мода. Для удобства регистрации мобов, в примере будет создан отдельный метод: |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | public static void registerEntity(Class entityClass, String name, int primaryColor, int secondaryColor) |
||
− | { |
||
− | int entityID = EntityRegistry.findGlobalUniqueEntityId(); |
||
− | long seed = name.hashCode(); |
||
− | |||
− | EntityRegistry.registerGlobalEntityID(entityClass, name, entityID); |
||
− | EntityRegistry.registerModEntity(entityClass, name, entityID, instance, 64, 1, true); //эта строка не нужна(зачем она?) |
||
− | EntityList.entityEggs.put(Integer.valueOf(entityID), new EntityList.EntityEggInfo(entityID, primaryColor, secondaryColor)); |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | Цвета для [[Яйца призывания|яиц призывания]] вы можете посмотреть [[ruwiki:Википедия:Таблица цветов|здесь]], только когда выберете цвет, замените «#» на «0x». Переменная <code>primaryColor</code> назначает цвет фона яйца, а переменная <code>secondaryColor</code> за цвет пупырышек. |
||
− | |||
− | Теперь в метод preLoad добавьте следующий код: |
||
− | |||
− | <syntaxhighlight lang="Java">registerEntity(MyBestEntity.class, "myBestEntity", 0x00FFFF, 0x00008B);</syntaxhighlight> |
||
− | |||
− | Разбор: |
||
− | {| class = "wikitable" style="text-aligh:center" |
||
− | !Параметр |
||
− | !Описание |
||
− | |- |
||
− | |MyBestEntity.class |
||
− | |Класс моба. |
||
− | |- |
||
− | |«myBestEntity» |
||
− | |ID моба |
||
− | |- |
||
− | |0x00FFFF |
||
− | |Цвет фона яйца |
||
− | |- |
||
− | |0x00008B |
||
− | |Цвет пупырышек яйца. |
||
− | |} |
||
− | Теперь создайте класс моба и добавьте туда следующий код: |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | public class MyBestEntity extends EntityMob |
||
− | { |
||
− | public EntityTest(World par1World) |
||
− | { |
||
− | super(par1World); |
||
− | } |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | В примере суперклассом класса моба является класс «EntityMob», предназначенный для враждебных мобов. Также существуют классы «EntityCreature», «EntityAnimal», «EntityLiving» и другие. |
||
− | |||
− | Теперь модель, текстура и рендер. В класс CommonProxy добавьте следующий код: |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | public void registerRenderers() |
||
− | { |
||
− | // Здесь ничего, так как сервер не рендерит графику или существ! |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | Далее в класс ClientProxy добавьте следующий код: |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | @Override |
||
− | public void registerRenderers() |
||
− | { |
||
− | RenderingRegistry.registerEntityRenderingHandler(MyBestEnity.class, new RenderMyBestEntity(new ModelBiped(), 0.5F)); |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | * Метод <code>registerEntityRenderingHandler</code> говорит Minecraft, как рендерить существо. |
||
− | * <code>MyBestEntity.class</code> — класс моба. |
||
− | * <code>RenderMyBestEntity</code> — класс рендера моба, который использует модель <code>ModelBiped</code>. |
||
− | * <code>ModelBiped</code> — базовая модель игрока. |
||
− | * <code>0.5F</code> — размер тени. |
||
− | |||
− | Теперь надо вызвать созданный метод в главном файле мода. Просто добавьте этот код: |
||
− | |||
− | <syntaxhighlight lang="Java">proxy.registerRenderers();</syntaxhighlight> |
||
− | |||
− | Далее создайте класс RenderВашМоб. В нашем случае это «RenderMyBestEntity». Его суперклассом должен быть класс «RenderBiped». В класс добавьте следующий код: |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | private static final ResourceLocation textureLocation = new ResourceLocation("textures/entity/steve.png"); |
||
− | |||
− | public RenderTest(ModelBiped model, float shadowSize) |
||
− | { |
||
− | super(model, shadowSize); |
||
− | } |
||
− | |||
− | @Override |
||
− | protected ResourceLocation getEntityTexture(Entity par1Entity) |
||
− | { |
||
− | return textureLocation; |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | Вместо <code>textures/entity/steve.png</code> поставьте <code>"IDмода:textures/entity/вашМоб.png"</code>, то есть в примере будет <code>"MyBestMod:textures/entity/myBestEntity.png"</code>. После этого в папке <code>assests/idмода/textures</code> создайте папку <code>entity</code> и туда скопируйте текстуру моба. |
||
− | |||
− | Для локализации яйца моба добавьте в файл локализации следующий код: |
||
− | |||
− | <syntaxhighlight lang="Java">entity.myBestEntity.name=My Best Entity</syntaxhighlight> |
||
− | |||
− | Теперь зайдите в игру. Во вкладке «Разное» будет яйцо. |
||
− | |||
− | Моб закончен. |
||
== Дополнительные уроки == |
== Дополнительные уроки == |
||
+ | {{Main|Создание модификаций с помощью Forge/1.7+/Дополнительные уроки}} |
||
− | |||
− | + | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Локализация названий в игре|Локализация названий в игре]] |
|
+ | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Дроп определённого предмета при разрушении блока|Дроп определённого предмета при разрушении блока]] |
||
− | Собственно у нас есть некоторые предметы, блоки, а возможно даже кнопки, существа и надписи из нашего мода, называющиеся в инвентаре примерно так: <code>item.block.name</code> Естественно это нас не устраивает, и это можно исправить, даже не внося изменений в код! |
||
+ | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Разносторонняя текстура блока|Разносторонняя текстура блока]] |
||
− | |||
+ | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Собственная вкладка в Творческом режиме|Собственная вкладка в Творческом режиме]] |
||
− | Итак, приступим. Слева, в <code>src/main/resources</code> создайте пакет <code>assets.mybestmod.lang</code> Понятно, что mybestmod — это краткое имя мода(или modid), указанное в @Mod. Теперь где угодно создайте файл(создайте текстовой, а затем измените расширение) en_US.lang (где будут написаны английские название блоков, предметов и т. д.) и пропишите в нём то, что вы видите вместо названия в инвентаре (в случае нашего первого блока — tile.bestblockever.name), затем равно, и прямо за ним — ваше локализированное название, например: «Best Block EvAR!». То есть должно получиться: |
||
+ | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Обновление Forge|Обновление Forge]] |
||
− | <syntaxhighlight lang="Java">tile.bestblockever.name=Best Block EvAR!</syntaxhighlight> |
||
+ | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Обновление ForgeGradle|Обновление ForgeGradle]] |
||
− | |||
+ | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Свой материал для инструмента|Свой материал для инструмента]] |
||
− | Теперь скопируйте файл, и назовите копию ru_RU.lang (собственно русский перевод). Внутри него измените название на русское, например |
||
+ | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Создание брони|Создание брони]] |
||
− | <syntaxhighlight lang="Java">tile.bestblockever.name=Самый лучший блок!! =P</syntaxhighlight> |
||
+ | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Свой материал для брони|Свой материал для брони]] |
||
− | Теперь оба этих файла можете перетащить в заранее созданную <code>assets.mybestmod.lang</code> При переносе выберите Copy files. |
||
+ | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Генерация предметов в контейнерах натуральных структур|Генерация предметов в контейнерах натуральных структур]] |
||
− | |||
+ | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Атрибуты для моба|Атрибуты для моба]] |
||
− | Чтобы локализировать вкладки в режиме творчество добавьте такой код: |
||
+ | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Интеллект для моба|Интеллект для моба]] |
||
− | <syntaxhighlight lang="Java">itemGroup.tabTutorial=Локализированое имя</syntaxhighlight> |
||
+ | # [[Создание модификаций с помощью Forge/1.7+/Дополнительные уроки#Свой скин при моддинге|Свой скин при моддинге]] |
||
− | |||
− | <code>tabTutorial</code> — Название вашей вкладки |
||
− | |||
− | Вот и всё! Локализация завершена, теперь в игре будут отображаться выбранные вами названия. |
||
− | |||
− | Подобных названий можно вписывать сколько угодно, главное в столбик. |
||
− | |||
− | Скорее всего в игре русское название будет выглядеть вопросами! Это всё из-за кодировки. Исправить это можно зайдя в eclipse вкладку window\preferences\general и просто нажмите на workspace и внизу найдите text file encoding и поставьте на other и там выберите UTF-8. Всё! теперь у нас нормальный русский язык! |
||
− | |||
− | === Дроп определённого предмета при разрушении блока === |
||
− | Всё очень просто. В конец класса созданного вами блока (перед последней фигурной скобкой) вставьте это: |
||
− | <syntaxhighlight lang="Java"> |
||
− | @Override |
||
− | public Item getItemDropped(int par1, Random par2Random, int par3) |
||
− | { |
||
− | return Items.diamond; |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | То есть теперь при разрушении вашего блока из него выпадет алмаз. Вы можете написать, чтоб выпадало что угодно. Просто вместо |
||
− | <code>return Items.diamond;</code> напишите «<code>return Items.getItemFromBlock(Blocks.);</code>» (для блоков) или «<code>return Items.;</code>» (для предметов), а после ввода вами точки выпадет список возможных предметов или блоков. |
||
− | |||
− | Если хотите, чтоб выпадал не один предмет, а несколько, просто вставьте сразу после предыдущих строк |
||
− | <syntaxhighlight lang="Java"> |
||
− | @Override |
||
− | public int quantityDropped(Random par1Random) |
||
− | { |
||
− | return 20; |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | Тогда при разрушении выпадет 20 выбранных вами предметов или блоков. |
||
− | Всё очень легко и просто! |
||
− | |||
− | === Разносторонняя текстура блока === |
||
− | Я буду использовать следующие текстуры: |
||
− | [[Файл:Нижняя часть блока.jpg|Нижняя сторона]] [[Файл:Верхняя часть блока.jpg|Верхняя сторона]] [[Файл:Северная часть блока.jpg|Северная часть]] [[Файл:Южная часть блока.jpg|Южная часть]] [[Файл:Западная часть блока.jpg|Западная часть]] [[Файл:Восточная часть блока.jpg|Восточная часть]] |
||
− | |||
− | Для этого, добавьте такой код в тело класса: |
||
− | |||
− | <syntaxhighlight lang="Java">public IIcon[] icons = new IIcon[6];</syntaxhighlight> |
||
− | |||
− | И такой после конструктора класса: |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | @Override |
||
− | public void registerBlockIcons(IIconRegister reg) { |
||
− | for (int i = 0; i < 6; i ++) { |
||
− | this.icons[i] = reg.registerIcon(this.textureName + "_" + i); |
||
− | } |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | Теперь в папку <code>assets/ID мода/resources/textures/blocks/</code> добавьте файлы с таким именем: <code><То, что вы указали в скобках в конструкторе класса, в методе this.setBlockTextureName()>_<код стороны блока></code> |
||
− | |||
− | И ещё такой код: |
||
− | <syntaxhighlight lang="Java"> |
||
− | @Override |
||
− | public IIcon getIcon(int side, int meta) { |
||
− | return this.icons[side]; |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | В игре блок будет выглядеть так: |
||
− | |||
− | <gallery mode="packed"> |
||
− | Блок с разностороней текстурой в игре.jpg |
||
− | Блок с Разносторонней текстурой (Вид сзади).jpg |
||
− | </gallery> |
||
− | |||
− | Важно то, что текстура северной и восточной (2 и 5) части блока отображается зеркально. Если вы не поняли, то поставьте [[ТНТ|блок ТНТ]] и посмотрите на части, где написано TNT. С одной стороны написано «TNT», а с другой — «ТИТ». |
||
− | |||
− | === Собственная вкладка в Творческом режиме === |
||
− | Для этого добавьте такой код в тело класса: |
||
− | |||
− | <syntaxhighlight lang="Java">public static CreativeTabs tabTutorial = new TabTutorial("ModID");</syntaxhighlight> |
||
− | |||
− | «ModID» заменяем на любое число. Рекомендую ID больше 11 (12 ID сразу на следующей странице творческого инвентаря). |
||
− | |||
− | Потом создайте класс TutorialTab. Если всё правильно, то ваш класс будет иметь <code>extends CreativeTabs</code> до первой фигурной скобки. Теперь добавьте этот метод в ново-созданный класс: |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | public TabTutorial(String lable) { |
||
− | super(lable); |
||
− | } |
||
− | |||
− | @Override |
||
− | public Item getTabIconItem() |
||
− | { |
||
− | return Item.getItemFromBlock(Blocks.grass); |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | Теперь заходите в игру. Вы увидите свою вкладку во втором списке вкладок, её «символом» будет блок [[Трава|травы]]. Если вам хочется, чтобы «символом» был предмет, то вместо <code>Blocks.</code> напишите <code>Items.предмет</code> . Если вы хотите, чтобы «символом» был ваш блок или предмет, то напишите <code>BestMod.bestBlockEver</code> . <code>BestMod</code> — главный файл вашего мода. <code>bestBlockEver</code> — ваш блок/предмет. |
||
− | |||
− | Для того что бы добавить что либо из вашего мода в собственную вкладку пишем: |
||
− | <syntaxhighlight lang="Java">this.setCreativeTab(НазваниеГлавногоКласса.НазваниеВашейВкладки);</syntaxhighlight> |
||
− | [[Файл:Собственная вкладка в креативе.png|150px|right]] |
||
− | |||
− | === Обновление Forge === |
||
− | Чтобы обновить версию Forge, на который вы создаёте моды, необязательно всё перекачивать. |
||
− | |||
− | Достаточно просто изменить build.gradle Так что если хотите обновить Forge откройте его любым редактором и найдите строчку |
||
− | version = "1.7.2-10.12.0.998" |
||
− | Там будет написана версия Forge, которая у вас сейчас, соответственно вам нужно всего лишь изменить значение на новое. Измените его на версию, до которой хотите обновить Forge (например на 1.7.2-10.12.0.1012) и сохраните файл. Далее запустите gradlew.bat с командой eclipse (то есть запустить bat-файл с кодом <code>gradlew.bat eclipse</code>) и после завершения его работы ваша версия Forge обновлена! |
||
− | |||
− | === Обновление ForgeGradle === |
||
− | Forge отделён от ForgeGradle, поэтому если вы попытаетесь обновиться на версию Forge, которая использует более новой ForgeGradle, вы получите ошибки. Вот таблица версия Forge, и какие версии ForgeGradle он использует. |
||
− | {| class="wikitable" |
||
− | ! ForgeGradle |
||
− | ! Forge |
||
− | |- |
||
− | | - || 959<, 965 |
||
− | |- |
||
− | | 1.0 || 960-964 |
||
− | |- |
||
− | | 1.1 || 967-1047 |
||
− | |- |
||
− | | 1.2 || 1048+ |
||
− | |} |
||
− | Удалите папку '''.gradle''', которая находится в папке, куда вы разархивировали Forge. |
||
− | Теперь, откройте файл '''build.gradle''' (который находится там же). Найдите такую строку: |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | dependencies { |
||
− | classpath 'net.minecraftforge.gradle:ForgeGradle:1.x-SNAPSHOT' |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | В '''1.x-SNAPSHOT''', поменяйте '''1.x''' на нужную версию ForgeGradle. Сохраните файл и откройте командную строку. Повторно введите команды, которые вы использовали при установке Forge. ForgeGradle обновит все нужные файлы. |
||
− | |||
− | === Свой материал для инструмента === |
||
− | Допустим вы хотите, чтобы ваш инструмент обладал свойствами не железной/алмазной кирок из майнкрафта, а собственными. |
||
− | |||
− | Тогда где-нибудь(вы можете где угодно написать эту строку, главное, чтоб можно было вызвать.), например в главном классе вне каких либо методов (то есть можно перед последней фигурной скобкой) напишите: |
||
− | public static final ToolMaterial NEWMAT = EnumHelper.addToolMaterial("NEWMAT", 2, 564, 5.0F, 4.0F, 50); |
||
− | Не забудьте про импорт. Давайте разберемся: static означает, что переменная NEWMAT типа ToolMaterial доступна из других классов. Затем приравнивается значению, которое и даст вашей кирке определённые свойства. Теперь об аргументах, перечисленных через запятую: |
||
− | # Название материала |
||
− | # На сколько кирка крута от 0 до 3, то есть какие блоки может ломать(1 — эквивалент каменной, 3 — алмазной). |
||
− | # Максимальное количество сломанных блоков (у алмазной — 1561, каменной — 131). |
||
− | # Скорость добычи (у золотой — 12, у алмазной — 8, деревянной — 2). |
||
− | # Урон, наносимый существам (у деревянной/золотой — 0, железной — 2, алмазной — 3). |
||
− | # Зачаровываемость, то есть какой шанс хороших чар (у золотой — 22, алмазной — 10, железной — 14). |
||
− | |||
− | Теперь можно придать какому-нибудь инструменту эти свойства, для этого в инструменте (например в нашей кирке) измените <code>super(ToolMaterial.EMERALD);</code> на <code>super(BaseMyBestMod.NEWMAT);</code> В таком случае вы отправляете в супер-класс инструмента информацию о том, что свойства описаны переменной NEWMAT типа ToolMaterial, которая описана в классе BaseMyBestMod (или любой другой класс, где она написана). |
||
− | |||
− | Вот и всё, свойства инструмента изменены. |
||
− | |||
− | === Создание брони === |
||
− | Создание брони немного отличается от создания обычных предметов, точнее имеет свои особенности. Приступим. |
||
− | |||
− | Мы не будем создавать для каждого предмета свой отдельный класс, а создадим один универсальный, который опишет сразу шлем, нагрудник, штаны и ботинки. |
||
− | Начнём с регистрации переменных. |
||
− | <syntaxhighlight lang="Java"> |
||
− | public static Item bestarmorhelmet; |
||
− | public static Item bestarmorplate; |
||
− | public static Item bestarmorpants; |
||
− | public static Item bestarmorboots; |
||
− | </syntaxhighlight> |
||
− | |||
− | Шлем, нагрудник, штаны и ботинки соответственно. Теперь описываем эти переменные с помощью универсального класса. Естественно внутри метода preLoad() |
||
− | <syntaxhighlight lang="Java"> |
||
− | bestarmorhelmet = new BestArmor(0, 0).setUnlocalizedName("bestarmorhelmet").setTextureName("mybestmod:BestArmorHelmet"); |
||
− | bestarmorplate = new BestArmor(0, 1).setUnlocalizedName("bestarmorplate").setTextureName("mybestmod:BestArmorPlate"); |
||
− | bestarmorpants = new BestArmor(0, 2).setUnlocalizedName("bestarmorpants").setTextureName("mybestmod:BestArmorPants"); |
||
− | bestarmorboots = new BestArmor(0, 3).setUnlocalizedName("bestarmorboots").setTextureName("mybestmod:BestArmorBoots"); |
||
− | </syntaxhighlight> |
||
− | |||
− | Здесь, вроде, всё знакомо, мы даём нелокализированное имя каждому из предметов, а также текстуру. Но здесь мы посылаем ещё и две цифры в метод BestArmor. Вторая цифра отвечает за тип брони (0 — шлем, 3 — ботинки), назначение первой неясно, но в данном случае она роли не играет. Далее тоже ничего нового, просто зарегистрируем эти предметы в Forge. Сделать это нужно после описания переменных. |
||
− | <syntaxhighlight lang="Java"> |
||
− | GameRegistry.registerItem(bestarmorhelmet, "bestarmorhelmet"); |
||
− | GameRegistry.registerItem(bestarmorplate, "bestarmorplate"); |
||
− | GameRegistry.registerItem(bestarmorpants, "bestarmorpants"); |
||
− | GameRegistry.registerItem(bestarmorboots, "bestarmorboots"); |
||
− | </syntaxhighlight> |
||
− | |||
− | С главным классом работа окончена. |
||
− | |||
− | Теперь щелкаем по одной из ошибок и создаём новый класс BestArmor. Теперь «продолжаем» класс ItemArmor, то есть пишем <code>extends ItemArmor</code> после названия класса. Теперь в тело класса вставляем следующее: |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | private String texturePath = "mybestmod:textures/model/armor/"; |
||
− | |||
− | public BestArmor(int id, int armorType) { |
||
− | super(ArmorMaterial.DIAMOND, id, armorType); |
||
− | this.setCreativeTab(CreativeTabs.tabCombat); |
||
− | this.setMaxStackSize(1); |
||
− | this.setTextureName(); |
||
− | } |
||
− | |||
− | public void setTextureName () |
||
− | { |
||
− | if(armorType == 0||armorType == 1||armorType == 3){ |
||
− | this.texturePath += "MyBestArmor_" + 1 + ".png"; |
||
− | } |
||
− | else { |
||
− | this.texturePath += "MyBestArmor_" + 2 + ".png"; |
||
− | } |
||
− | } |
||
− | |||
− | @Override |
||
− | public String getArmorTexture(ItemStack itemstack, Entity entity, int slot, String type){ |
||
− | return this.texturePath; |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | Что ж, давайте разбираться. |
||
− | |||
− | Первая переменная, просто обозначает начало пути к текстуре брони. Все нужные текстуры можно спокойно извлечь из майнкрафта и отредактировать по желанию. Вот мои отредактированные текстуры: |
||
− | |||
− | [[Файл:MyBestArmor_1.png]] [[Файл:MyBestArmor_2.png]] [[Файл:BestArmorHelmet.png]] [[Файл:BestArmorPlate.png]] [[Файл:BestArmorPants.png]] [[Файл:BestArmorBoots.png]] |
||
− | |||
− | Текстуры предметов помещаются туда же, где и текстура кирки. А вот две текстуры самой брони нужно поместить в другую папку. Поэтому создайте её: нажмите ПКМ по <code>src/main/resources</code> и выберите New — Package и назовите его <code>assets.mybestmod.textures.model.armor</code> и уже туда перетащите две оставшиеся текстуры. |
||
− | |||
− | Давайте дальше разбираться с кодом: следующим идёт метод BestArmor(), в который мы посылаем из главного класса параметры id и armorType. Напомню: от armorType зависит, какая это часть брони. В нём мы посылаем информацию о том, какой материал брони. Я написал, что броня будет аналогична алмазной, но можно создать [[#Свой материал для брони|свой материал для брони]] и вписать его. Далее мы настраиваем вкладку в креативе. Потом мы ограничиваем максимальное количество данного предмета в одной стопке до одного, чтобы броня не «стакалась». В конце концов мы вызываем созданный нами метод setTextureName() |
||
− | |||
− | В этом нашем собственном методе происходит проверка, какая часть брони вызвала этот класс. И, если это был шлем, нагрудник или ботинки, то используется первая текстура, а если поножи, то вторая. Мы прибавляем к изначальному пути брони нужное окончание, чтобы в определённом случае грузилась одна текстура, а в другом — вторая. |
||
− | |||
− | Последний же метод перезаписывает метод супер-класса и указывает Майнкрафту, что должна грузиться текстура по пути texturePath, который предварительно был отредактирован во втором методе. |
||
− | |||
− | Теперь можно запускать игру и убивать мобов в новых блестящих доспехах! |
||
− | |||
− | === Свой материал для брони === |
||
− | Почти не отличается от создания собственного материала для инструмента. |
||
− | |||
− | В главном классе в любом месте, но вне каких-либо методов пишем: |
||
− | static ArmorMaterial BESTMAT = EnumHelper.addArmorMaterial("BESTMAT", 100, new int[] {3, 8, 6, 3}, 30); |
||
− | Затем импортируем ArmorMaterial. Теперь разберём: |
||
− | # BESTMAT — название материала. |
||
− | # 100 — прочность (железо — 15, алмазы — 33). |
||
− | # 3 — защита шлема. |
||
− | # 8 — защита нагрудника. |
||
− | # 6 — защита штанов. |
||
− | # 3 — защита ботинок. |
||
− | # 30 — зачаровываемость. |
||
− | |||
− | Вот и все. Теперь можно использовать этот материал для брони, например заменив <code>ArmorMaterial.DIAMOND</code> на <code>BaseMyBestMod.BESTMAT</code> |
||
− | |||
− | === Генерация предметов в контейнерах натуральных структур === |
||
− | Итак, вы можете сделать так, чтобы ваш, или любой другой предмет/блок генерировался в сундуках сокровищницы. Для этого в методе preLoad() в главном классе вставьте следующее: |
||
− | <syntaxhighlight lang="Java"> |
||
− | ChestGenHooks.addItem(ChestGenHooks.DUNGEON_CHEST, |
||
− | new WeightedRandomChestContent(new ItemStack(BaseMyBestMod.bestblockever), 1, 10, 3)); |
||
− | </syntaxhighlight> |
||
− | Разберемся в параметрах: |
||
− | # <code>(ChestGenHooks.DUNGEON_CHEST)</code> — Вместо <code>DUNGEON_CHEST</code> выберете одно из возможных мест генерации в выпадающем списке. |
||
− | # <code>(BaseMyBestMod.bestblockever)</code> — Требуемый блок/предмет. В скобках указывается любая переменная типа Block или Item. |
||
− | # <code>(1)</code> — Минимальное генерируемое количество. |
||
− | # <code>(10)</code> — Максимальное генерируемое количество. |
||
− | # <code>(3)</code> — Шанс генерации. |
||
− | |||
− | === Атрибуты для моба === |
||
− | Если вы уже проверили моба, то заметили, что он двигается очень медленно. Чтобы исправить это и изменить атрибуты для моба, добавьте в его класс следующий код: <br> |
||
− | <syntaxhighlight lang="Java"> |
||
− | @Override |
||
− | protected void applyEntityAttributes() |
||
− | { |
||
− | super.applyEntityAttributes(); |
||
− | this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(20.0D); |
||
− | this.getEntityAttribute(SharedMonsterAttributes.followRange).setBaseValue(32.0D); |
||
− | this.getEntityAttribute(SharedMonsterAttributes.knockbackResistance).setBaseValue(0.0D); |
||
− | this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setBaseValue(0.25D); |
||
− | this.getEntityAttribute(SharedMonsterAttributes.attackDamage).setBaseValue(2.0D); |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | Разъяснение: |
||
− | {| class = "wikitable" style="text-aligh:left" |
||
− | !Параметр |
||
− | !Описание |
||
− | |- |
||
− | |maxHealth |
||
− | |Максимальное здоровье |
||
− | |- |
||
− | |followRange |
||
− | |Дистанция, на которой моб будет преследовать кого-либо |
||
− | |- |
||
− | |knockbackResistance |
||
− | |Сопротивление к отбрасыванию |
||
− | |- |
||
− | |movementSpeed |
||
− | |Скорость движения |
||
− | |- |
||
− | |attackDamage |
||
− | |Сила атаки |
||
− | |} |
||
− | Атрибуты установлены. |
||
− | |||
− | === Интеллект для моба === |
||
− | Теперь моб будет просто двигаться, но ничего не делать. Для того, чтобы добавить ему интеллект создайте в класс моба следующий код: |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | public boolean isAIEnabled() |
||
− | { |
||
− | return true; |
||
− | } |
||
− | </syntaxhighlight> |
||
− | |||
− | Теперь в конструктор класса добавьте следующий код: |
||
− | <syntaxhighlight lang="Java"> |
||
− | this.tasks.addTask(1, new EntityAISwimming(this)); |
||
− | this.tasks.addTask(2, new EntityAIAttackOnCollide(this, EntityPlayer.class, 1.2D, false)); |
||
− | this.tasks.addTask(3, new EntityAIWander(this, 1.0D)); |
||
− | this.tasks.addTask(4, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F)); |
||
− | this.tasks.addTask(5, new EntityAILookIdle(this)); |
||
− | |||
− | this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); |
||
− | this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 0, true)); |
||
− | </syntaxhighlight> |
||
− | |||
− | Первый аргумент метода «addTask» — приоритет назначения интеллекта, второй — сам интеллект. В примере используются следующие интеллекты: «Swimming», «AttackOnCollid», «Wander», «WatchClosest», «LookIdle», «HurtByTarget» и «NearestAttackableTarget». Разъяснение: |
||
− | |||
− | {| class = "wikitable" style="text-aligh:left" |
||
− | !Интеллект |
||
− | !Описание |
||
− | |- |
||
− | |Swimming |
||
− | |Может ли существо плавать? |
||
− | |- |
||
− | |AttackOnCollid |
||
− | |Базовый тип атаки, который используют [[зомби]] и [[паук]]и. |
||
− | |- |
||
− | |Wander |
||
− | |Существо будет ходить вокруг, когда никого не атакует. |
||
− | |- |
||
− | |WatchClosest |
||
− | |Ищет назначенное существо на заданном расстоянии. |
||
− | |- |
||
− | |LookIdle |
||
− | |Существо будет осматриваться, просто стоя. |
||
− | |- |
||
− | |HurtByTarget |
||
− | |Сделает целью какого-либо моба, который его ударил. |
||
− | |- |
||
− | |NearestAttackableTarget |
||
− | |Ищет любое существо, которое подходит по второму параметру. |
||
− | |} |
||
− | |||
− | Интеллект установлен. |
||
− | |||
− | === Свой скин при моддинге === |
||
− | '''Внимание!''' Этот способ работает только на лицензионной версии Minecraft. |
||
− | |||
− | Чтобы при создании мода вы видели свой скин, вместо стандартного скина Steve, нужно прописать 2 строчки в аргументы запуска. |
||
− | |||
− | <syntaxhighlight lang="Java"> |
||
− | --username=ВашЛогин |
||
− | --password=ВашПароль |
||
− | </syntaxhighlight> |
||
− | После этого, при заходе в игру вы будете видеть свой скин. |
||
== Примечания == |
== Примечания == |
Версия от 18:52, 13 июня 2019
Здесь находятся инструкции по созданию модификаций, работающие для версии 1.7+
Подготовка среды и настройка
Сначала подготовим среду для работы с кодом Minecraft.
Forge
Собственно, для создания модов нужен Forge. Скачать его можно здесь с пометкой Mdk или с пометкой Src (для версий 1.8/1.7). Теперь создайте любую папку там, где вам удобно (в примере это «D:\MCModding»), в ней будет находиться Forge и мод. В эту папку распакуйте содержимое архива с Forge. Вы увидите следующее:
Среда разработки
Теперь нам нужно установить Forge, который при установке также произведёт декомпиляцию и деобфускацию кода Minecraft, чтобы сразу можно было начать создание модов. Для этого необходимо установить Java Development Kit (JDK), скачав с официального сайта Oracle.
Затем необходимо выполнить одну из следующих команд (замените eclipse
на idea
, если вы используете IntelliJ IDEA):
gradlew.bat setupDecompWorkspace eclipse
илиgradlew.bat setupDevWorkspace eclipse
Первая предпочтительней, так как в отличие от второй команды, подготавливает рабочее пространство с возможностью просмотра исходного кода Minecraft во время разработки. То есть вы всегда сможете посмотреть, как работает генерация мира, анимация движений, применение эффектов и т. д. Таким образом можно создавать моды, не опираясь на руководства, которых может и не быть на конкретную цель.
Если вы являетесь пользователем операционной системы Linux, нужно прописать следующие строки в терминале:
cd <путь>/<папка с Forge>
и./gradlew setupDecompWorkspace eclipse --refresh-dependencies
Чтобы выполнить команду, можно создать в папке .bat-файл с выбранной вами командой (но обычно он там уже есть) и запустить его. Также вместо всего этого можно запустить командную строку в этой папке (например, нажать ⇧ Shift + ПКМ по этой папке и выбрать «Открыть окно команд») и выполнить выбранную команду.
Выполнение команды займёт какое-то время, после чего должно появиться сообщение рода Build Successful.
Если же появляется какая-либо ошибка:
- Проверьте, чтобы у вас в ⊞ Win + PauseBreak->Дополнительные параметры->Переменные среды: в JAVA_HOME указан путь к папке c JDK (по-умолчанию: «C:\Program Files\Java\jdk1.7.0_79») и в Path был указан путь к bin-папке JDK после точки с запятой (по-умолчанию: «
…;C:\Program Files\Java\jdk1.7.0_79\bin
»). - Включите VPN, так как в редких случаях ссылки, необходимые скрипту, могут быть недоступны.
- Установите Java другой версии, не удаляя предыдущую.
- Установите другую версию JDK, не забыв, соответственно, поменять пути JAVA_HOME и Path.
Настройка Eclipse
Нужно настроить Eclipse для работы с Minecraft. Первым делом зайдите в него. Он предложит выбрать рабочую директорию (Workspace). Введите туда путь к папке «eclipse» в папке (Путь к папке должен содержать только английские буквы), куда вы распаковали содержимое Forge и поставьте галочку для того чтоб окно больше не появлялось. В примере это «D:\MCModding\eclipse». Если всё прошло успешно, то слева в Eclipse вы увидите раскрывающееся меню Minecraft, а снизу не увидите красных ошибок.
Настройка IntelliJ IDEA
Если вместо Eclipse Вы решили использовать IntelliJ IDEA, то после того, как Forge скомпилирован и установлен, необходимо запустить IDEA, и в появившемся окне нажать 'Import Project'. После чего выбираем в папке «D:\MCModding» файл build.gradle. В появившемся окне Вам предложат выбрать способ компиляции (рекомендуется оставить значение Use default gradle wrapper.) В строчке ниже выберите Ваш JAVA_HOME. В пункте «Формат проекта» нужно обязательно выбрать «.ipr (file based)». В противном случае, придётся подключать все библиотеки и настраивать запуск самостоятельно. После всего этого нажмите OK. Ждите, пока сборка скомпилируется.
В случае, если ваша IntelliJ IDEA установлена правильно и она различает формат *.ipr, вы можете просто дважды нажать по файлу <НазваниеПроекта>.ipr в директории вашего MCP. IDEA все сделает за вас.
Поздравляем! Вы успешно настроили среду для того, чтобы начать писать моды на ней.
Основные уроки
- Директория Eclipse (Установка среды)
- Главный класс
- Блок
- Предмет
- Крафт
- Компиляция
- Генерация
- Прокси и инстанция
- Моб
Дополнительные уроки
- Локализация названий в игре
- Дроп определённого предмета при разрушении блока
- Разносторонняя текстура блока
- Собственная вкладка в Творческом режиме
- Обновление Forge
- Обновление ForgeGradle
- Свой материал для инструмента
- Создание брони
- Свой материал для брони
- Генерация предметов в контейнерах натуральных структур
- Атрибуты для моба
- Интеллект для моба
- Свой скин при моддинге