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

В этой статье описывается создание модификаций на основе Minecraft Forge с использованием Eclipse для версий Minecraft с 1.12.

## Установка Forge Gradle

Для начала работы, создайте папку с названием вашей модификации избегая кириллицы. Если ваш мод имеет название из двух слов, желательно называть папку без пробелов, к примеру Tutorial-Mod или TutorialMod. Далее перейдите на официальный сайт Forge и скачайте версию с пометкой MDK (Modder Development Kit). Из загруженного архива извлеките папку gradle и файл build.gradle в папку модификации, остальные файлы сохранены для совместимости и/или дополнительных функций и для начала не понадобятся. Далее импортируйте в Eclipse проект как Existing Gradle Project указав папку модификации. Затем в колонке Gradle tasks поочерёдно выполните * setupDecompWorkspace* из набора

**forgegradle**и

*из набора*

**eclipse****ide**(Для пользователей

**IntelliJ IDEA**task

*), и обновите среду (ПКМ по проекту и Refresh). Теперь можно удалить два файла с расширением .launch, так как для тестовых запусков мы будем использовать задачи Gradle. Для настройки папок ресурсов создайте в папке проекта два каталога:*

**genIntelliJRuns****src\main\java**и

**src\main\resources**после чего выделите их и по ПКМ найдите пункт Build Patch и нажмите Us as source folder.

**Не забудьте!** Далее, все связанное с Java кодом мы будем делать в каталоге **src\main\java**, а остальное в **src\main\resources**.

**Примечание!** Для установки потребуется компьютер с минимальным объёмом ОЗУ от 4Гб! Если у вас недостаточно ОЗУ, добавьте необходимый объём из файла подкачки, но такой метод работает лишь на 64-битных системах.



## Создание модификации

#### build.gradle

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

```
buildscript {
repositories {
jcenter()
maven {
url = "http://files.minecraftforge.net/maven"
}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
version = "версия_модификации" //Обычно согласно версии major.minor.patch
group = "пакет_главного_класса" //Обычно в стиле домен.автор.идентификатор_модификации
archivesBaseName = "идентификатор_модификации" //Без пробелов и только в нижнем регистре
sourceCompatibility = targetCompatibility = '1.8'
compileJava {
sourceCompatibility = targetCompatibility = '1.8'
}
minecraft {
version = "1.12.2-14.23.5.2768"
runDir = "run"
mappings = "snapshot_20171003"
}
dependencies {
}
processResources {
inputs.property "версия_модификации", project.version
inputs.property "1.12.2", project.minecraft.version
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
expand 'version':project.version, 'mcversion':project.minecraft.version
}
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
}
}
runClient {
args "--username=НикнеймАвтора"
jvmArgs "-Xms2G", "-Xmx2G", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseG1GC", "-XX:G1NewSizePercent=20", "-XX:G1ReservePercent=20", "-XX:MaxGCPauseMillis=50", "-XX:G1HeapRegionSize=32M"
}
runServer {
jvmArgs "-Xmx2G", "-Xmx2G"
}
```

Если вы используете **IntelliJ IDEA**, то в конец build.gradle дополнительно добавьте это:

```
apply plugin: 'idea'
idea {
module {
inheritOutputDirs = true
}
}
subprojects {
apply plugin: 'idea'
}
task prepareAssets(type: Copy) {
group = 'build'
from project.file('src/main/resources')
into project.file('build/classes/java/main')
}
classes.dependsOn(prepareAssets)
```



#### pack.mcmeta

Этот файл нужен для корректной работы игры с ресурсами модификации, такими как локализации, модели, рецепты, таблицы добычи и так далее. Заполняется следующим образом:

```
{
"pack": {
"pack_format": 3,
"description": "Описание вашего мода"
}
}
```

#### mcmod.info

Этот файл задаёт более подробную информацию о модификации и заполняется следующим образом:

```
[{
"modid": "Идентификатор модификации",
"name": "Название",
"description": "Описание",
"version": "${version}",
"mcversion": "${mcversion}",
"logoFile": "Путь к логотипу",
"url": "Сайт модификации",
"authorList": ["Автор"],
"credits": "Благодарности кому либо"
}]
```

#### Класс модификации

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

```
@Mod(modid = "идентификатор", name = "название", version = "${version}", dependencies = "required-after:forge@[минимальная версия forge,)", useMetadata = true)
public class TutorialMod {
}
```

## Блок

### Класс блока

Для создания блока создайте класс с названием блока в стиле **TutorialBlock** в пакете **патч.blocks** и заполните его следующим образом:

```
public class TutorialBlock extends Block {
public TutorialBlock() {
super(Material.Материал); //Задает звук ходьбы, к примеру Rock или Glass
this.setCreativeTab(CreativeTabs.ВкладкаТворчества); //К примеру BuildingBlocks
this.setHardness(прочность_блока); //К примеру 3.0F как у руд
this.setResistance(взрывоустойчивость_блока); //К примеру 15.0F как у руд
this.setHarvestLevel("инструмент", уровень); //К примеру pickaxe и 0 как деревянная кирка
this.setRegistryName("идентификатор_блока"); //Используется для подключения моделей и в команде /give
this.setUnlocalizedName("ключ_локализации"); //Можно использовать идентификатор блока
}
}
```

** Примечание** регистрируемое имя и ключ локализации указывать только в нижнем регистре, используя при надобности нижнее подчёркивание!

### Модель

Модель (которую, например, можно создать здесь) решает то, как наш блок будет выглядеть. Важно знать, что для блоков используется две модели. Одна задает вид блока, поставленного в мире, а вторая, его иконку в инвентаре. Это дает нам возможность сделать блоку отдельную иконку для инвентаря. Сами же модели для блока подключаются к нему как состояния, **normal** для блока в мире и **inventory** для его иконки в инвентаре. Поэтому для начала создадим файл **идентификатор_блока.json** в пакете **assets.идентификатор_мода.blockstates**, который и подключит наши модели.

```
{
"variants": {
"normal": { "model": "идентификатор_мода:идентификатор_блока" }
}
}
```

Теперь подключим модели. Для этого создайте файл **регистрируемое_имя.json** в пакете **assets.идентификатор_мода.models.block** со следующим содержимым:

```
{
"parent": "block/cube_all",
"textures": {
"all": "идентификатор_мода:blocks/идентификатор_блока"
}
}
```

Теперь зададим иконку блока в инвентаре в пакете **assets.идентификатор_модификации.models.block** с именем **идентификатор_блока.json** со следующим содержанием:

```
{
"parent": "идентификатор_мода:block/идентификатор_блока"
}
```



### Регистрация

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

класс `BlocksInit`

:

```
public static Block ВАШ_БЛОК = new BlockИмяБлока();
public static void registerBlocks() {
setRegister(ВАШ_БЛОК);
}
@SideOnly(Side.CLIENT)
public static void registerBlocksRender() {
setRender(ВАШ_БЛОК);
}
private static void setRegister(Block block) {
ForgeRegistries.BLOCKS.register(block);
ForgeRegistries.ITEMS.register(new ItemBlock(block).setRegistryName(block.getRegistryName()));
}
@SideOnly(Side.CLIENT)
private static void setRender(Block block) {
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(Item.getItemFromBlock(block), 0, new ModelResourceLocation(block.getRegistryName(), "inventory"));
}
```

Теперь в главном классе в методе `preInit`

добавьте инструкцию `BlocksInit.registerBlocks`

а в методе `init`

`BlocksInit.registerBlocksRender`

.

## Предмет

### Основное

#### Класс предмета

Для создания предмета создадим класс с именем **TutorialItem**:

```
import net.minecraft.item.Item;
public class TutorialItem extends Item
{
public TutorialItem(String string) //Параметр string будет заполняться в регистраторе
{
this.setUnlocalizedName(string); //Имя предмета если нет файла локализации
this.setRegistryName(string); //Имя в регистре игры, также используется в команде /give
this.maxStackSize(целое число от 1 до 64); //Размер стопки для предмета, по умолчанию 64
this.setCreativeTab(вкладка); //Творческая вкладка, где будет размещен предмет, пример: this.setCreativeTab(CreativeTabs.MISC);
this.setHasSubtypes(true или false); //Используется для обозначения, что у предмета есть подтипы, т.е. метадата
}
}
```

#### Регистрация

Для регистрации предмета создадим класс **ItemsRegister**:

```
public class ItemsRegister
{
public static Item ВАШ_ПРЕДМЕТ = new TutorialItem("item_tutorial");
public static void register()
{
setRegister(ВАШ_ПРЕДМЕТ);
}
@SideOnly(Side.CLIENT)
public static void registerRender()
{
setRender(ВАШ_ПРЕДМЕТ);
}
private static void setRegister(Item item)
{
ForgeRegistries.ITEMS.registerAll(item);
}
@SideOnly(Side.CLIENT)
private static void setRender(Item item)
{
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(item, 0, new ModelResourceLocation(item.getRegistryName(), "inventory"));
}
}
```

В классе CommonProxy, в методе `preInit()`

добавляем строку `ItemsRegister.register();`

, а в методе `init()`

`ItemsRegister.registerRender();`

.

#### Модель

Теперь у нас есть предмет, однако если мы запустим игру и выдадим себе его, то он будет выглядеть как куб с фиолетовыми и черными клетками. Это говорит о том, что игра не нашла модель предмета. Для исправления этой проблемы создаём в папке `src/main/resources/assets/имя_мода/models/item`

файл с расширением .json и пишем в нём следующий текст:

```
{
"parent": "item/generated",
"textures": {
"layer0": "имя_мода:items/имя_текстуры"
}
}
```

Либо

```
{
"parent": "item/handheld",
"textures": {
"layer0": "имя_мода:items/имя_текстуры"
}
}
```

**Примечание:** название файла модели должно совпадать с RegistryName предмета

Второй вариант используется для моделей инструментов и оружия. Однако теперь, когда у нас есть модель для предмета, осталось добавить текстуру по пути `src/main/resources/assets/имя_мода/textures/items`

дав ему имя, идентичное указанному в файле модели.