Создание модификаций с помощью Forge/1.6+

**Здесь находятся инструкции по созданию модификаций, работающие для версии 1.6+**

## Подготовка среды и настройка

Данное руководство написано для работы со средой Eclipse под Windows.

### Java

Minecraft написан на языке программирования Java. Он же (причём с расширенным инструментарием, а не просто среда выполнения) нужен для разработки модов. Чтобы установить Java с инструментарием (JDK), проделайте следующие шаги:

- Найдите в интернете что-нибудь по запросу «JDK 8 скачать»
- Скачайте JDK 8 и запустите его, чтобы установить.

В моём случае я скачал JDK 1.8.241. 1.8 и 8 — это одно и то же.

При первой установке **JDK** откройте `⊞ Win` + `PauseBreak`->Дополнительные параметры->Переменные среды и проверьте содержимое. Там должны существовать две переменные (если их нет, то их нужно создать вручную):

**JAVA_HOME**: «`C:\Program Files\Java\jdk1.8.0_241`

» (по умолчанию; у вас может быть другая версия jdk или путь установки)**Path**: «`C:\Program Files\Java\jdk1.8.0_241\bin`

» (по умолчанию; у вас может быть другая версия jdk или путь установки)

### Среда программирования

Писать программы можно и в блокноте, но это неудобно — никакие ошибки в синтаксисе не будут подчёркиваться, нельзя добавить библиотеки и так далее.

Для работы с Java применяются две среды программирования — это Eclipse IDE и Intellij IDEA. Первая среда легковеснее и бесплатна, а также обладает продвинутой подсветкой синтаксиса «из коробки». Вторая лучше «чувствует контекст», но её полноценная версия платная, а количество цветов для подсветки синтаксиса ограничено, если не скачать плагин. Касательно платности: для разработки модов сойдёт и бесплатная версия Intellij IDEA.

### Среда разработки

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

Minecraft 1.6.4 — версия, вышедшая практически 10 лет назад. С тех пор практически весь инструментарий, при помощи которого создавались моды на эту версию, устарел и перестал работать. Тем не менее, один способ создавать моды на момент 2024 года всё ещё есть.

Первым делом, скачайте репозиторий. Он скачается в виде архива. Распакуйте его; вас интересует папка «h-voldeloom-1.6.4» и её содержимое. Если коротко, Voldeloom — это механизм, заменяющий Forge с ForgeGradle. Он реализует не самый лучший, зато рабочий подход к запуску мода в среде.

Всё содержимое папки вы можете переместить в любое место на диске. Например, это может быть D:\Modding. Если вы всё сделали правильно, в этой папке после переноса файлов вы увидите:

- gradle;
- gradlew;
- gradlew.bat;
- gradle.properties;
- ...и другие файлы и папки.

Эта папка и является папкой среды для 1.6.4. Папки для более старых версий, кстати, работают так же.

### Настройка Eclipse

После установки и запуска Eclipse вам нужно будет выбрать среду разработки, в которой будут содержаться исходники вашей модификации и исходники Minecraft.

Открываем сверху слева File->Import->Gradle->Existing Gradle project. Выбираем там папку, в которой находятся файлы Voldeloom (как мы договорились ранее, это может быть D:\Modding). Спустя некоторое время проект импортируется. Далее вам следует проконтролировать, чтобы Eclipse использовал верную версию JDK и имел нужный уровень трактовки синтаксиса. Трактовка синтаксиса (Compiler) нужна для того, чтобы случайно не использовать самые новые возможности языка, которые будут непоняты древней версией 1.6.4.

После импорта проекта слева появится раздел, называющийся так же, как называется папка, где распакован Voldeloom. Кликаем по разделу ПКМ->Properties->Java Compiler. Устанавливаем там значение «Compiler… level» **1.6** вместо стоящего там по умолчанию 11, а если поле заблокировано, то предварительно ставим галочку на «Enable project…» и снимаем с «Use compilance…»

Теперь нам нужно привязать запуск Voldeloom к среде, чтобы было удобнее разрабатывать и тестировать мод. Для этого ищем вверху зелёный кружочек с белым треугольником, что означает запуск. Нажимаем не на него, а на чёрный треугольник сразу рядом с ним (справа). Далее:

- Жмём Run Configurations -> Gradle Task.
- Белый листик сверху слева. Создаётся новый task.
- Жмём на новый task. Открываются его свойства.
- Жмём кнопку Add. Добавляется поле, на которое можно нажать и отредактировать его.
- Вводим runClient.
- Ниже жмём кнопку Workspace и выбираем там название вашей папки, куда был распакован Voldeloom.
- Сохраняем всё на Apply.

Фактически, среда готова. Запуск игры, либо модифицированной вами игры, осуществляется через зелёный кружочек с белым треугольником, рядом с которым мы создавали Run Configuration.

В процессе могут возникнуть ошибки, вот самые частые из них и методы их решения:

**Проблема**: Нет папки исходников src/main/java и папки src/main/resources.**Решение**: создать эти папки руками внутри того места, где у вас распакован Voldeloom, после чего указать эти папки в среде. Это делается примерно там же, где мы выставляли Compiler, но только ПКМ->Properties->Java Build Path->Вкладка Source->Add folder.**Проблема**: отсутствует JDK.**Решение**: указать вашу JDK рядом с тем местом, где мы меняли Compiler, только ПКМ->Properties->Java Build Path->Вкладка Libraries->Add Library->JRE System Library. Там можно выбрать JDK из списка, либо добавить в список новую, которую вы скачали в самом начале.**Проблема**: Игра запустилась без мода, хотя исходника нет.**Решение**: запустить игру снова. При первом запуске происходит предварительная настройка среды без создания продукта (мода), который мог бы подгрузиться в среде.

## Образцы исходного кода

Нет ничего лучше, чем разобрать чужой исходный код простого мода и на его базе попробовать создать что-то своё.

- Мод «The Rings of Power» — маленький мод, добавляющий колечки с эффектами на тик и ПКМ. Портирован на версию 1.6.4 в мае 2023 года
- Мод «Legendary Item» — маленький мод, добавляющий оружие без крафта. Портирован на версию 1.6.4 в мае 2023 года
- Мод «Dirt Tools and Armor» — маленький мод, добавляющий инструменты и броню с крафтом. Портирован на версию 1.6.4 в феврале 2024 года

## Основные уроки

### Урок 1. Создаём пустой мод

Теперь, когда вы разобрались со средой, можно приступать к подготовке вашего мод-пакета.

Откройте ваш раздел в Eclipse (теперь будем так называть раздел в Eclipse, в котором мы настраивали Compiler). В самом его начале будет пакет src/main/java.

Если вы заглядывали в образец исходного кода по первой ссылке, то знаете, что внутри «src/main/java» находится папка trop, а в ней различные файлы. Это главный файл, с которого начинается мод, и зависимые от него файлы. В данном случае, главный файл — это TROP.java.

Главный файл отличается от остальных тем, что у него есть аннотация:

@Mod(modid = "trop", useMetadata = true)

Здесь указан идентификатор мода — trop, а сама аннотация говорит Forge’у, что это мод и что его надо загрузить.

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

@Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { ... } @Mod.EventHandler public void onInit(FMLInitializationEvent event) { ... }

Первее происходит пре-инициализация, позже — инициализация. Ещё есть пост-инициализация. Все эти стадии нужны для того, чтобы определить какие-то данные перед тем, как они понадобятся в последующих шагах.

Мод с таким кодом уже вполне запускается, просто не добавляет никакого контента.

### Урок 2. Традиции и совместимость

Продолжаем рассматривать пример мода TROP. Здесь в пре-инициализации видим такую строчку, как

TROPConfig.preInit(event);

Minecraft 1.6.4 — последняя версия, где у предметов есть жёстко прописанные идентификаторы. Если встречается два мода с одинаковыми идентификаторами предметов, они будут несовместимы. Чтобы этого не произошло, каждый разработчик делает в своём моде конфигурацию, при помощи которой игрок может отредактировать идентификаторы и устранить несовместимость. Это не обязательно, но так принято делать.

Очевидно, что конфигурация должна происходить до того, как будут объявлены предметы, именно поэтому конфигурация идёт в пре-инициализации — перед всем, что дальше происходит в моде. Все файлы конфигурации выглядят одинаково: набор полей и набор их значений по умолчанию, если не задано иное. Образец файла конфигурации в файле TROPConfig.java.

### Урок 3. Предмет

Чтобы создать предмет, нам нужно его объявление, инициализация и регистрация. Будем рассматривать создание предмета на примере мода TROP.

Для начала в верхней части класса создайте переменную типа Item. Это — объявление.

public static Item ringGreat;

Далее вам потребуется блок описать (проинициализировать). Это мы сделаем в onInit(), там же, где описываются предметы.

ringGreat = new TROPItemRingGreat(TROPConfig.idRingGreat - 256);

Смысл кода: мы описываем переменную, как новый предмет TROPItemRingGreat с идентификатором, который взят из конфигурации.

Посмотрим, что у нас есть в файле TROPItemRingGreat:

public class TROPItemRingGreat extends Item { public TROPItemRingGreat(int id) { super(id); } @Override public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer entity) { entity.addPotionEffect(new PotionEffect(Potion.regeneration.getId(), 3600, 2)); return super.onItemRightClick(itemStack, world, entity); } @Override public void onUpdate(ItemStack itemstack, World world, Entity entity, int par4, boolean par5) { if (entity instanceof EntityPlayer) { ((EntityPlayer) entity).addPotionEffect(new PotionEffect(Potion.invisibility.getId(), 20, 2)); } } }

Если вы не знакомы с основами джавы, то пояснение: «extends» — это наследование. То есть, TROPItemRingGreat наследует свойства от предметов и сам является предметом.

Далее три строчки — это конструктор; один аргумент в скобках, вида int id, должен быть указан в скобках везде, где мы создаём new TROPItemRingGreat(…). Помните, мы указывали в onInit() идентификатор? Вот, он сюда и передался в качестве аргумента.

Далее следует два переопределённых метода. Там мы можем использовать аргументы из описания функции, чтобы применить к ним какие-нибудь другие функции. Наглядно: onItemRightClick. Эта функция срабатывает всегда, когда игрок жмёт ПКМ с предметом в руке. У функции есть такой аргумент, как EntityPlayer entity. Это тот, кто держит предмет в руке.

entity.addPotionEffect(new PotionEffect(Potion.regeneration.getId(), 3600, 2));

Этот фрагмент кода выше накладывает на существо (того, кто держит кольцо в руке и жмёт ПКМ) эффект регенерации 2 уровня на 3600/20 секунд.

Вернёмся к функции onInit() в главном файле. После объявления предмета происходит его регистрация.

register(ringGreat, "ringGreat");

Регистрируем мы при помощи своей собственной функции, которая объявлена в самом низу файла. В качестве аргументом передаём, собственно предмет (то, что регистрируем) и его название.

public static void register(Item item, String field) { String name = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field); item.setTextureName("trop:" + name); item.setUnlocalizedName(name); item.setMaxDamage(0); item.setMaxStackSize(1); item.setCreativeTab(TROPCreativeTabs.tabRing); GameRegistry.registerItem(item, name); }

В этой функции мы превращаем название в такой вид, который обычно используется для наименования предметов в Minecraft (не вотТакой, а вот_такой). мы устанавливаем имя текстуры в папку trop: name, это означает assets/trop/textures/items/name.png. Далее задаём имя для файла перевода, количество прочности (0 = бесконечно), максимальное количество предметов в стаке (1), креативную вкладку (наша созданная вкладка — кольца) и регистрируем предмет.

Фактически, выше мы просто задали кучу свойств на конкретный item, который передали в функцию. Свойств много — полный перечень можно посмотреть, введя item. и смотря, что Eclipse предлагает дописать.

**Важное примечание.** Программирование — это вариативность. Нет разницы, где вы зададите свойства предметам; это можно сделать самыми разными способами:

1. Где-то в зоне инициализации, где происходит работа с нашим предметом.

ringGreat = new TROPItemRingGreat(TROPConfig.idRingGreat - 256); ringGreat.setTextureName("trop:" + name);

2. Прямо на предмете.

ringGreat = new TROPItemRingGreat(TROPConfig.idRingGreat - 256).setTextureName("trop:" + name);

3. Внутри конструктора предмета.

public class TROPItemRingGreat extends Item { public TROPItemRingGreat(int id) { super(id); this.setTextureName("trop:" + name); } ...

4. Тот, который мы рассмотрели в исходнике-образце.

Вот уже четыре варианта, как применить свойство к предмету.

Осталось лишь сделать текстуру и перевод для предмета. Ничего сложного в этом нет: скачайте Paint.NET и нарисуйте картинку 16х16, после чего положите её по пути текстур. Выше мы указывали, что он у нас в папке assets/trop/textures/items/name.png

Переводы хранятся в папке assets/trop/lang/lang_CODE.lang.

Теперь запускайте игру. Вы создали свой собственный предмет!

### Урок 4. Блок

Блок создаётся точно так же, как предметы: объявление, инициализация, регистрация. Свойства можно задавать там, где вам удобнее.

Пример класса для блока:

public class TestBlock extends Block { public TestBlock(int id, Material material) { super(id, material); this.setCreativeTab(CreativeTabs.tabBlock); this.setHardness(3.5F); this.setLightValue(0.75F); this.setResistance(500.0F); } }

Свойства в этом примере:

- hardness — это параметр, отвечающий за длительность разрушения блока. Например, у булыжника он равен 2.0F, а у обсидиана 50.0F. Тем самым, чтобы сломать булыжник рукой вам потребуется 10 секунд, а чтобы сломать обсидиан, понадобится уже 250 секунд. Вам ничего не выпадет, но это можно исправить. но об этом в дополнительных уроках.
- lightValue — это параметр, отвечающий за свечение блока.
- resistance — это параметр, который определяет устойчивость к взрывам. Для примера, у обсидиана этот параметр равен 2000.0F.

Регистрация предмета немного отличается от предмета. Нам здесь нужна функция registerBlock, а не registerItem.

GameRegistry.registerBlock(testBlock, name);

Текстуры у блоков лежат по пути assets/trop/textures/blocks/name.png

### Урок 5. Крафт

Собственно, у нас есть блок и предмет. Мы можем их держать в руках, а блок даже ставить. Но этот предмет/блок доступен в творческом режиме. Чтобы его можно было скрафтить, мы должны зарегистрировать рецепт. Это делается очень просто.

Будем рассматривать на примере мода TROP. Допустим, нужно скрафтить кольцо ringGreat, положив по кругу золотые самородки, а по центру — изумруд. Код рецепта (который нужно разместить где-нибудь в инициализации) будет таким:

GameRegistry.addRecipe(new ItemStack(TROP.ringGreat, 1), "XXX", "XYX", "XXX", 'X', Item.goldNugget, 'Y', Item.emerald);

Давайте разберем, что тут написано. Итак, с помощью GameRegistry мы добавляем новый рецепт. new ItemStack означает, что создастся новый стак колец в количестве одной штуки (вместо 1 можно вписать любое число до 64). Далее записана сетка крафта ("XXX", "XYX", "XXX") и её трактовка. Как мы помним, верстак - это поле 3х3, поэтому наша сетка - это три строки по три символа.

Каждый предмет в крафте обозначается своим личным знаком, который может быть любым. Чтобы игра понимала, каким именно блоком или предметом является икс, игрек и так далее, мы должны написать трактовку применённых символов. В коде выше это 'X', Item.goldNugget, 'Y', Item.emerald". Сначала пишем символ, затем - то, чем он является.

Добавить рецепт крафта можно не только вашему блоку или предмету. Для этого просто укажите предмет из самого Minecraft: Item.emerald вместо TROP.ringGreat и так далее.

Если хотите создать крафт, который можно произвести в инвентаре, вместо «XXX», «XYX», «XXX» используйте «XX», «YY» (поле 2х2) соответственно.

Бесформенный крафт (то есть крафт, в котором можно располагать ингредиенты как угодно) опишите так:

GameRegistry.addShapelessRecipe(new ItemStack(Block.grass, 4), Block.gravel, Block.gravel, Item.arrow);

То есть, если вы положите в верстак/инвентарь 2 блока гравия и стрелу, то получите 4 блока травы.

Собственно, всё.

### Урок 6. Компиляция

Ну что ж, мы написали мод. Он работает и всё отлично, но как поиграть с ним вне Eclipse? Где взять файл мода, который мы обычно скачиваем из интернета? Для этого нужно его скомпилировать. При работе с Forge это нужно делать вручную, а при работе с Voldeloom это происходит автоматически — именно скомпилированный мод там запускается по команде runClient.

Таким образом, когда вы закончили разработку мода и запустили его, зайдите в папку, где вы распаковали Voldeloom. Внутри неё пройдите по пути build/libs. Там будет два мода — один будет называться 1.6.4.jar, второй — 1.6.4-dev.jar (имена могут быть другими, но приписка -dev останется). Для игры в обычном лаунчере нужен первый из двух модов. Файл можно вынуть из папки и использовать по назначению.

## Дополнительные уроки

### Дроп определённого предмета при разрушении блока

Всё очень просто. В конец класса созданного вами блока (перед последней фигурной скобкой) вставьте это:

@Override public int idDropped(int par1, Random par2Random, int par3) { return Item.diamond.itemID; }

То есть теперь при разрушении вашего блока из него выпадет алмаз. Вы можете написать, чтобы выпадало что угодно. Просто вместо
`return Item.diamond.itemID;`

напишите «return Block.» или «return Item.», а после ввода вами точки выпадет список возможных предметов или блоков.

Если хотите, чтобы выпадал не один предмет, а несколько, просто вставьте

@Override public int quantityDropped(Random par1Random) { return 20; }

Тогда при разрушении выпадет 20 выбранных вами предметов или блоков.

### Свой материал для инструмента

Допустим вы хотите, чтобы ваш инструмент обладал свойствами не железной/алмазной кирки из *Minecraft*, а собственными.

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

static EnumToolMaterial NEWMAT = EnumHelper.addToolMaterial("NEWMAT", 2, 564, 5.0F, 4.0F, 50);

Не забудьте про импорт. Давайте разберёмся: static означает, что переменная NEWMAT типа EnumToolMaterial доступна из других классов. Затем приравнивается значению, которое и даст вашей кирке определенные свойства. Теперь об аргументах, перечисленных через запятую:

- Название материала
- На сколько кирка мощная, от 0 до 3, то есть какие блоки может ломать (1 — эквивалент каменной, 3 — алмазной).
- Прочность (у алмазной — 1561, каменной — 131).
- Скорость добычи (у золотой — 12, у алмазной — 8, деревянной — 2).
- Урон, наносимый существам (у деревянной/золотой — 0, железной — 2, алмазной — 3).
- Зачаровываемость, то есть какой шанс хороших чар (у золотой — 22, алмазной — 10, железной — 14).

Что ж, теперь можно придать какому-нибудь инструменту эти свойства, для этого в инструменте (например в нашей кирке) измените `super(par1, EnumToolMaterial.EMERALD);`

на `super(par1, BaseMyBestMod.NEWMAT);`

В таком случае вы отправляете в супер-класс инструмента информацию о том, что свойства описаны переменной NEWMAT типа EnumToolMaterial, которая описана в классе BaseMyBestMod (или любой другой класс, где она написана).

Вот и всё, свойства инструмента изменены.

### Локализация названий в игре

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

Это сделать довольно легко. Вы создаёте пакет mybestmod.assets.mybestmod.lang, по нему нажимаете ПКМ, выбираете New -> File. Называете его ru_RU.lang, такую же операцию проделываете с файлами en_US.lang и en_UK.lang. В файле en_US напишите `tile.mybestblockever.name=My best block ever!`

Это код отвечает за название на английском языке. Разберём:
`tile.`

, это обозначение блока, для предмета будет `item.`

, а для вкладки в Творчестве. `itemGroup.`

, дальше название блока/предмета/вкладки `mybestblockever.`

и `name=`

, что обозначает имя. После ** =** пишите имя. В этом файле можно писать много имён, но рекомендовано в столбце. В файле en_UK должно быть написано тоже самое что и в en_US, так как оба эти файла обозначают английский язык. В русском файле соответственно будут русские названия.