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

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

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

Сначала подготовим среду для работы с кодом Minecraft.

### Скачивание и Установка Forge

Собственно, для создания модификаций нужен Forge. Скачать его можно здесь. Лучше скачивать рекомендованную версию Mdk или Src. Ну и под вашу версию игры. У меня это 1.9.4/1.10. Теперь создайте любую папку там, где вам удобно (в примере это «C:\Users\jgj96\Desktop\Modding»), в ней будет находиться Forge и модификация. В эту папку распакуйте содержимое архива с Forge. Вы увидите следующее:

Далее я вам советую создать файл gradlew build.bat. С помощью этого файла мы сможем собрать (скомпилировать) нашу модификацию в jar файл. Когда вы его создали вы кликаем по нему `ПКМ` и выбираете ИЗМЕНИТЬ. И прописываете вот этот код:

```
gradlew.bat build
```

И сохраняете. Всё теперь вы сможете собрать вашу модификацию. Но об этом поподробнее я расскажу в следующем уроке

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

Теперь нам нужно скачать и установить Forge, который при установке также произведет декомпиляцию кода Minecraft, чтобы сразу можно было начать создание модификаций. Для этого необходим JDK. Скачать его можно здесь. Затем вам нужно выполнить команду `gradlew.bat setupDecompWorkspace eclipse`

или `gradlew.bat setupDevWorkspace eclipse`

(замените `eclipse`

на `idea`

, если вы используете IntelliJ IDEA). Чтобы выполнить эту команду, необходимо нажать сочетание клавиш Shift+ПКМ в этой папке и нажать «Открыть окно команд». Далее в строке прописываете `gradlew setupDecompWorkspace eclipse`


Если вы являетесь пользователем операционной системы Linux, нужно прописать следующие строки в терминале: `cd <путь>/<папка с Forge>`

и `./gradlew setupDecompWorkspace eclipse --refresh-dependencies`

.

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

Перед выполнением команды проверьте, чтобы у вас в win+PauseBreak->Дополнительные параметры->Переменные среды: в JAVA_HOME был указан путь к папке «C:\Program Files\Java\jdk1.7.0_79» и в Path был указан путь к bin-папке java после точки с запятой «…;C:\Program Files\Java\jdk1.7.0_79\bin». Тогда всё благополучно заработает.

Чтобы выполнить команду, можно создать в папке .bat-файл с выбранной вами командой (но обычно он там уже есть) и запустить его. Также вместо всего этого можно запустить командную строку в этой папке (например, нажать `⇧ Shift` + `ПКМ` по этой папке и выбрать «Открыть окно команд») и выполнить выбранную команду.

Если процесс занял некоторое время, то всё прошло хорошо. Этот процесс примерно занимает 8—16 минут. Установка произведена. Последнее время иногда у некоторых появляются ошибки при запуске .bat-файла, и процесс не идёт. Решение заключается в настройке VPN, так как по неизвестной причине без VPN сайт, на который ссылается установка, недоступен.

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

Нужно настроить Eclipse для работы с Minecraft. Первым делом зайдите в него. Он предложит выбрать рабочую директорию (Workspace). Введите туда путь к папке «eclipse» в папке(Путь к папке должен содержать только английские буквы), куда вы распаковали содержимое Forge и поставьте галочку для того чтоб окно больше не появлялось. В примере это `«C:\Users\jgj96\Desktop\Modding\eclipse»`

. Если всё прошло успешно, то слева в Eclipse вы увидите раскрывающееся меню *Minecraft*, а снизу не увидите красных ошибок.

### Настройка IntelliJ IDEA

После того, как Forge скомпилирован и установлен, Вам необходимо запустить `IntelliJ IDEA`

. В появившемся окне нажимаем 'Import Project' и выбираем в папке `D:\Modding`

файл `build.gradle`

. В появившемся окне вам предложат выбрать способ компиляции (рекомендуется оставить значение `Use default gradle wrapper.`

) В строчке ниже выберите ваш `JAVA_HOME`

. В пункте «Формат проекта» нужно обязательно выбрать «.ipr (file based)». В противном случае, вам придется подключать все библиотеки и настраивать запуск самостоятельно. После всего этого нажмите OK. Ждите, пока сборка скомпилируется.

В случае, если ваша `IntelliJ IDEA`

установлена правильно и она различает формат `*.ipr`

, вы можете просто дважды нажать по файлу `<НазваниеПроекта>.ipr`

в директории вашего `MCP. IDEA`

всё сделает за вас.

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

## Уроки

### Урок 1. Директория

Теперь вы можете приступать к созданию своей первой модификации.

Заранее придумайте название своей модификации (например, `TestMod`

). Перейдём к тому, где должна быть модификация в структуре классов Minecraft. Существует некоторый этикет, как оформлять код и всё, что с ним связано. Раскройте проект Minecraft, далее `src/main/java`

. В `src/main/java`

лежит всё, что относится к коду Minecraft. Как вы видите, там есть подпапки (или пакеты) типа `net.minecraft.client`

[1] и так далее. В Java пакетах принято структурировать пакеты так: `domain.product`

или `domain.company.product`

, то есть первое — домен (com, net, ru), далее название компании (если вы единственный разработчик — ваш ник) и название продукта (модификации), или же название компании опускается.[2][3] Minecraft, Minecraft Forge и FML имеют первый вариант структурирования пакета. То есть, если ваш никнейм, например, name, а название вашей модификации — `TestMod`

, то нажмите на `src/main/java`

`ПКМ` и выберите New → package. В поле «Name» наберите «com.name.testmod» с учётом регистра. Это создаст директорию, в которой вы и будете работать с модификацией. Всё, далее можете приступать непосредственно к его созданию.



### Урок 2. Главные классы (Main, Reference, Proxy)

Итак, можно приступить к созданию модификации. Но перед этим в правом углу где написано `Package Explorer`

. Смотрим чуть-чуть ниже и видим пакет типа `com.example.examplemod`

. Его удаляем, так как он нам не понадобиться. Если хотите знать, что это, то это тестовая модификация.

**Создание класса Main.**

Сейчас мы создадим базу (основу) модификации, где в будущем у вас будет хранится (блоки, предметы, мобы, всякие эвенты) и так далее. Для начала мы создадим папку `main`

в которой будет хранится главный класс нашей модификации и назовём его `Main`

.

Нажмите `ПКМ` на директории модификации (com.name.testmod) и выберите New → Package, и в поле Name введите название папки. В нашем случаи это `main`

. Далее просто нажмите Finish. Всё, у вас теперь есть папка `main.`

Потом так же нажимаем `ПКМ` на директории модификации (com.name.testmod.main) выбираем New → Class и называем его `Main.`


Приступим к написанию кода. Запишем ВНЕ тела, то есть над строчкой `public class... `

[4] класса следующую строчку:

@Mod(modid = Reference.MODID, name = Reference.NAME, version = Reference.VERSION)

Вы написали, что из класса Reference мы берём ID нашей модификации `Reference.MODID`

, далее берём из класса Reference имя модификации `Reference.NAME`

и указываем версию модификации тоже из класса Reference `Reference.VERSION`

. Но давайте разберёмся что это за класс Reference.

Этот класс был создан для того чтобы хранить всю самую основную информацию о модификации (имя, версия, Id, поддерживаемые версии, прокси и так далее). Но если вы хотите использовать своё имя для этого класса, да пожалуйста.

**Создание класса Reference.**

Давайте создадим папку `reference`

и в этой папке создадим класс `Reference.`

Вы можете спросить «А зачем мы создаём отдельные папки, а не создаём классы в основой?» А для того чтобы не путаться. Потому что, когда у вас большую модификацию создавать всё в одной папке будет неудобно.

С этим разобрались. Теперь в классe `Reference`

в теле `public static Reference {}`

в фигурных скобках пишем вот этот код:

```
public static final String MODID = "tm";
public static final String NAME = "Test Mod";
public static final String VERSION = "0.1";
```

`public`

значит что этот (обьект, предмет, параметр) можно вызвать откуда угодно, т.е из любой папки или класса, `static`

, что он статичный т.е неподвижный, `final`

означает что: класс, объявленный, объявленный с модификатором 'final' не может иметь подклассов. Дальше думаю понятно, что MODID это ID вашей модификации, NAME имя модификации, а VERSION версия.
Далее мы переходим в класс Main и импортируем не хватающий класс. Просто наводи на красную линию и нажимаем импортировать не хватающий класс, т.е из (com.name.testmod.reference.Reference) класс `Reference`

. Теперь в самом верху у вас добавилась строчка :

```
import com.name.testmod.reference.Reference;
```

Если не получается то просто скопируйте код выше.

Теперь сообщение об ошибке должно исчезнуть.

**Создание инстанции и классов для Proxy.**

Сейчас мы будем создавать прокси и инстанцию. Лучше создавать его в начале чтобы не заморачиваться в будущем, когда они нам понадобятся. Прокси и инстанция (экземпляр) нужны для создания мобов, регистрация собственных рендеров, звуков и др. Для создания инстанции добавьте в главный класс модификации `Main`

и в тело `public class Main{}`

вот этот код:

```
@Instance
public static Main INSTANCE;
@SidedProxy(clientSide = Reference.CLIENTPROXY, serverSide = Reference.COMMONPROXY)
public static CommonProxy proxy;
```

`@Instance`

и `@SidedProxy`

не забудьте импортировать.
`clientSide`

это сторона клиента, а `serverSide`

это сторона сервера. У ваc появляется ошибка так как в классe `Reference`

нет параметров CLIENTPROXY и COMMONPROXY. Значит переходим в класс `Reference`

и в теле `public class Reference{}`

после `public static final String VERSION....`

пишем этот код:

```
public static final String CLIENTPROXY = "com.name.testmod.proxy.ClientProxy";
public static final String COMMONPROXY = "com.name.testmod.proxy.CommonProxy";
```

`com.name.testmod.proxy.ClientProxy`

это расположение класса СlientProxy, а `com.name.testmod.proxy.CommonProxy`

это расположение класса CommonProxy.

Так как у нас этих классов нет мы и создаём. Но сначала не забудьте создать папку `proxy`

. А в ней создаём два класса: `ClientProxy`

и `CommonProxy`

.

Потом переходим в класс ClientProxy и к строчке `public class ClientProxy`

дописываем `extends CommonProxy{}`

. Действие extends в точности совпадает с его переводом, один класс расширяет другой, что является классическим наследованием.

Далее в этом теле пишем вот этот код:

```
public void preInit(FMLPreInitializationEvent event)
{
}
public void init(FMLInitializationEvent event)
{
}
public void postInit(FMLPostInitializationEvent event)
{
}
```

Импортируем не хватающие параметры (если вы забыли они помечены красными волнами).

Давайте разбираться. Загрузка майнкрафта поделена на 3 части: `PreInit`

(Пре-загрузка) , `Init`

(Загрузка), `PostInit`

(Завершающая загрузка). Вы можете использовать первых 2 этапа для загрузки (блоков, предметов, вкладок в креативе). А последний этап вы можете использовать для загрузки (мобов, entity).

С классом `ClientProxy`

мы закончили. Теперь переходим в класс `CommonProxy.`

И в теле `public class CommonProxy{}`

пишем тот же код который предоставлен выше. И не забывайте импортировать не хватающие параметры.

Теперь переходим в главный класс `Main.`

И ниже после `public static CommonProxy.....`

но ещё главном теле пишем:

```
@EventHandler
public static void preInit(FMLPreInitializationEvent event)
{
proxy.preInit(event);
}
@EventHandler
public static void init(FMLInitializationEvent event)
{
proxy.init(event);
}
@EventHandler
public static void postInit(FMLPostInitializationEvent event)
{
proxy.postInit(event);
}
```

Строки `proxy.preInit(event)`

, `proxy.Init(event)`

, `proxy.postInit(event)`

означает то, что мы регистрируем `preInit, Init, postInit`

из папки proxy.

Если у вас остались красные линии, то до импортируйте не хватающие параметры(классы).

Вот и всё. Основа модификации готова. Можете запустить Minecraft (Зеленая кнопка сверху → Client) и увидеть в списке модификаций свою модификацию. Если вы хотите видеть свою полную информацию о вашей модификации, то зайдите в scr → main → resources и найдёте файл `mcmod.info`

. Можете открыть его с помощью обычного блокнота или с помощью NotePad ++. И в `modid`

в место examplemod пишите свой ID модификации, у нас это `tm`

. А все остальные параметры изменяйте сами, под вашу модификацию.

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

Давайте приступим к созданию своего первого собственного блока. (сначала дам небольшой совет от меня: «Если у вас что то не получается, не отчаивайтесь потому что вы первый раз пишите свою модификацию. А в первый раз и у меня было столько ошибок ооо…. Вы пересмотрите статью и убедитесь что вы где то не забыли поставить `,`

или `:`

или `;`

или забыли фигурные скобки `{}`

закрыть. Так что я в вас верю! А много сначала не понимать это нормально. Мы же все учимся на своих ошибках»

**Главный класс.**

Чтобы создать блок необходимо создать основной класс блоков. Где будет храниться всё краткая информация о блоках. Значит сначала создаём папку `init`

и в этой папке создавайте класс (можете использовать своё название) `BlocksInit.`

Далее переходите в него и в теле `public class BlocksInit{}`

в фигурных скобках (если вы ещё не поняли) пишите этот код:

```
public static void init()
{
}
public static void register()
{
}
public static void registerRenders()
{
}
```

`Void`

значит что наш (объект, блок, предмет) это пустота.

В теле `init()`

мы будем указывать краткие параметры нашего блока, в теле `register()`

мы будем регистрировать блоки (если мы не зарегистрируем блок, то он просто не появиться в игре), в теле `registerRedner()`

мы будем регистрировать рендеры для нашего блока.

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

Теперь мы можем написать наш блок.

Сначала в теле `public class Blockinit{}`

пишем вот эту строчку:

```
public static Block testblock;
```

Мы написали что мы создаём блок `Block`

и название нашего блока (ну это ещё не основное название) `testblock`

. Не забудьте импортировать `Block`

из `net.minecraft.block.`

Теперь укажем, где про блок будет написано более подробно. Потом в теле `Init()`

пишем вот этот код:

```
testblock = new test_block();
```

Эта строка говорит, что про объект `TestBlock`

будет написано в классе `test_block`

. И он выдаёт ошибку. Естественно, ведь никакого класса `test_block`

не существует. Перед создание класса создадим папку под названием `blocks`

, где будут храниться все классы блоков. Ну в пакете `com.name.testmod`

. Потом создаём уже в папке `blocks`

класс `test_block`

.

Вы перейдете сразу в созданный вами класс. Сразу после названия класса перед фигурной скобкой допишите `extends Block`

, если Eclipse не дописал эту строку сам. Первую ошибку исправьте, импортировав недостающий класс `Block`

(`net.minecraft.block`

). Вторую ошибку вы видите потому, что созданный класс — наследник класса `Block`

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

Так теперь вы наведите на ошибку и вам предлагают создать конструктор. Но у вас их два. Первый это `'add....(Material)'`

, а второй это `'add....(Material,MapColor)'.`

Первая строка значит, что мы в этом конструкторе будем указывать только материал блока, а во второй строке мы будем указывать и материал блока и цвет этого блока на карте. Про цвет блока на карте мы поговорим в дополнительном уроке. Сейчас мы будем использовать первый конструктор `'add....(Material)'`

. Вы создаёте его и у вас должен появиться вот этот код:

```
public test_block(Material materialIn) {
super(materialIn);
// TODO Auto-generated constructor stub
}
```

Строчку `//TODO Auto-..........stub`

можете убрать так как она нам не нужна (это просто подсказка). В строчке `public...()`

в скобках уберите надпись `Material materialIn`

она нам тоже не понадобиться. Далее в строчке `super()`

вместо `materialIn`

пишем `Material.`

и выбираете материал (ROCK, AIR, CAKE, ICE, IRON, CLAY, GLASS, LAVA и т.д) Я выбираю камень поэтому пишу `Material.ROCK`

. Теперь после строчки `super()`

мы будем указывать параметры для нашего блока.

Все параметры указываются через `this.`

после точки идут уже наши параметры (прочность, устойчивость и т.д). А также можно сделать из главного класса, указывая их через точку после `testblock = new test_block();`

(до точки с запятой).

Итак, давайте поработаем над характеристиками блока. Основные эти:

this.setUnlocalizedName("testblock");

Самое важное. Без этой строчки у блока не будет внутриигрового(нелокализированного) имени, он просто будет называться `«tile.null.name».`


this.setCreativeTab(CreativeTabs.BUILDING_BLOCKS);

Которая говорит в какой вкладке будет находиться блок в креативе (доступные также можно посмотреть через точку от CreativeTabs). Не забудьте про импорт.

this.setHardness(15F);

Устанавливает прочность, то есть как долго блок будет ломаться.

this.setResistance(10F);

Устанавливает взрывоустойчивость блока.

this.setHarvestLevel("pickaxe", 3);

Устанавливает, что можно сломать блок киркой алмазного уровня, не ниже.

Также можно установить будет ли блок светиться. Чем больше число, тем светлее (вместо 0 пишете уровень света, создаваемого блоком, умноженное на 10; таким образом нужно вставить туда значение от 0 до 150 (150 означает уровень света 15, максимальное значение)).

this.setLightLevel(0F);

Теперь этот класс можно будет сохранить. Не забывайте про импорт. Сейчас мы будем создавать класс в котором будет указаны все параметры регистрации блока и чтобы мы потом смогли добавить модель и текстуру блоку. В это вникать пока не надо, потому что мы создадим этот класс и больше его трогать не будем. Для начала создайте папку `utils`

в пакете `com.name.testmod`

и уже в этой папке создайте класс и назовите его `BlockRegistry`

(вы можете использовать своё название). Далее в этом классе в теле `public class BlockRegistry{}`

вставьте вот этот код:

```
public static void registerBlock(Block block)
{
GameRegistry.registerBlock(block, block.getUnlocalizedName().substring(5));
}
public static void registerRender(Block block)
{
Item item = Item.getItemFromBlock(block);
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(item, 0, new ModelResourceLocation(Reference.MODID + ":" + item.getUnlocalizedName().substring(5), "inventory"));
}
```

Импортируйте не хватающие параметры (классы) тем самым исправляя все ошибки. Потом вы этот класс сохраняете и всё. Сейчас мы будем регистрировать наш блок в Forge.
Теперь вы переходите в класс `BlocksInit`

и в теле `register() {}`

в фигурных скобках прописываем вот это:

```
BlockRegistry.registerBlock(testblock);
```

В скобках() вы указываете не название класса (где храниться вся информация о блоке) а самое первое название которое мы указали в самом начале `public static Block `

Далее в теле __testblock__;`registerRender() {}`

в фигурных скобках прописываем вот это:

```
BlockRegistry.registerRender(testblock);
```

Теперь переходим в класс `Main`

и теле `preInit() {}`

напишите вот этот код:

```
BlocksInit.init();
```

Эта строка означает, что все блоки которые находятся в классе `BlocksInit`

в теле `init()`

будут загружаться.
Дальше мы в классе `Main`

в теле `Init() {}`

пишем этот код:

```
BlocksInit.register();
BlocksInit.registerRenders();
```

Эти строки означают что все блоки которые зарегистрированы в классе `BlocksInit`

в теле `register();`

будут загружаться.

**Создание модели и текстуры.**

Всё мы зарегистрировали наш блок в Forge. Теперь нам осталось лишь локализировать наш блок, добавить ему модель и текстуру. Давайте начнём с модели. Теперь в проводнике Windows заходим в папку вашего мода и далее переходим по scr → main → resources и там создаём папку `assets`

. Далее в папке `assets`

создаём папку `tm`

. Это ID вашего мода. И в этой папке создайте вот эти папки (blockstates, lang, models, textures)

Заходим в папку `blockstates`

и создаём файл `testblock.json`

, и открывайте его с помощью NotePad ++. И вставьте туда вот это:

```
{
"variants": {
"normal": { "model": "tm:testblock" }
}
}
```

`tm:testblock`

это `id:название модели`

.Теперь переходим к созданию файла модели (потому что у нас его ещё нет). Переходим в папку `models`

и там создаём две папки `item`

и `block`

. Заходим в папку `block`

и создаём файл `testblock.json`

. Далее в нём пишем вот это:

```
{
"parent": "block/cube_all",
"textures": {
"all": "tm:blocks/testblock"
}
}
```

Тут мы пишем уже название текстуры.
Сохраняем и выходим. Теперь заходи в папку `Item`

и опять создаём файл `testblock.json`

. И вписываем в него это:

```
{
"parent": "tm:block/testblock"
}
```

Всё с моделями закончили теперь преступим к текстуре. Переходим в папку `textures`

и создаём папку `blocks`

(как вы уже догадались туда мы будем кидать все текстуры блоков) Я буду использовать свою текстуру блока. Можете её взять . Потом просто перекидайте эту текстуры с название `testblock.png`

в папку `blocks`

и всё текстура и модель готовы! Осталось только локализировать блок.
Заходим снова в eclipse и слева, в `src/main/resources`

и там переходите в пакет `assets.testmod.lang`

Понятно, что `testmod`

— это краткое имя модификации(или modid), указанное в @Mod. Теперь где угодно создайте файл(создайте текстовой, а затем измените расширение) en_US.lang (где будут написаны английские название блоков, предметов и т. д.) и пропишите в нём то, что вы видите вместо названия в инвентаре (в случае нашего первого блока — tile.testblock.name), затем равно, и прямо за ним — ваше локализированное название, например: «My First EVAR BLACKK!!!!». То есть должно получиться:

```
tile.testblock.name=My First EVAR BLACKK!!!
```

Теперь скопируйте файл, и назовите копию ru_RU.lang (собственно русский перевод). Внутри него измените название на русское, например:

```
tile.testblock.name=Мой Первый Блок
```

Всё локализация сделана!

Ну вот и всё, блок создан. И теперь самый волнующий момент. Запускайте Minecraft с вашей модификацией! Но сначала сохраните все классы (`Ctrl-S`). Для запуска нужно нажать сверху зелёный круг с треугольником (или `Ctrl-F11`). После запуска посмотрите, есть ли ваша модификация в окне модификации (в главном меню), создайте новый мир в режиме креатив и найдите свой блок в креатив-инвентаре во вкладке блоки. Если он там есть, берется, ставится и ломается, то поздравляю: модификация добавляющая блок создана!!!

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

Ну вот мы и создали блок. Но ведь в Майнкрафте присутствуют не только блоки, но и предметы. Такие как еда, инструменты, в общем всё подряд, что обычно нельзя поставить на землю. Давайте создадим такой предмет. Начнём с обычного предмета.

**Главный класс.**

Чтобы создать предмет необходимо создать основной класс предметов. Так же как мы делали с блоками. Где будет храниться всё краткая информация о предметах. Значит в пакете `com.name.testmod.init`

создавайте класс (можете использовать своё название) `ItemsInit.`

Далее переходите в него и в теле `public class ItemsInit{}`

в фигурных скобках пишите тот же код который мы писали для блоков:

```
public static void init()
{
}
public static void register()
{
}
public static void registerRenders()
{
}
```

**Создание предмета.**

Теперь мы начинаем писать наш предмет.

Сначала в теле `public class ItemsInit{}`

пишем вот эту строчку:

```
public static Item testitem;
```

Мы написали что мы создаём уже предмет `Item`

и название нашего предмета `testitem`

. Не забудьте импортировать всё. Теперь укажем, где про предмет будет написано более подробно. Потом в теле `Init()`

пишем вот этот код:

```
testitem = new test_item();
```

У нас высветилась ошибка потому что у нас нет класса `test_item`

. Значит создаём папку `items`

в пакете `com.name.testmod`

а в ней класс `test_item`

. Далее в этом классе в теле `public class..`

дописываем `extends Item`

. А дальше так же как с блоком. В этом же теле пишем:

```
public test_item()
{
}
```

И потом в теле `test_item() {}`

так же через параметр `this.`

пишем параметры предмета. Так как это у нас обычный предмет то мы запишем всего два параметра. Это `this.setCreativeTab(CreativeTabs.MATERIALS);`

(повторяю в `CreativesTabs.`

через точку вы можете выбрать свою вкладку в креативе) и `this.setUnlocalizedName("testitem");`

Всё импортируем и сохраняем. Дальше мы создадим класс так же как и для блоков где будут параметры регистрации предмета и чтобы мы потом смогли добавить модель и текстуру предмету.
В пакете `com.name.testmod.utils`

создайте класс и назовите его `ItemRegistry`

. Далее в этом классе в теле `public class ItemRegistry{}`

вставьте вот этот код и импортируйте недостающие классы:

```
public static void registerItem(Item item)
{
GameRegistry.registerItem(item, item.getUnlocalizedName().substring(5));
}
public static void registerRender(Item item)
{
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(item, 0, new ModelResourceLocation(Reference.MODID + ":" + item.getUnlocalizedName().substring(5), "inventory"));
}
```

Сохраняем и закрываем класс. Теперь вы переходите в класс `ItemsInit`

и в теле `register() {}`

в фигурных скобках прописываем вот это:

```
ItemRegistry.registerItem(testitem);
```

Далее в теле `registerRender() {}`

в фигурных скобках прописываем вот это:

```
ItemRegistry.registerRender(testitem);
```

Теперь переходим в класс `Main`

и теле `preInit() {}`

напишите вот этот код:

```
ItemsInit.init();
```

Дальше мы в классе `Main`

в теле `Init() {}`

пишем этот код:

```
ItemsInit.register();
ItemsInit.registerRenders();
```

**Создание модели и текстуры.**
Так, теперь мы так же как и для блока будем создавать модель и текстуру. Переходим уже проводник Windows и в папке нашей модификации идём по scr → main → resources → assets → tm → models → item и в ней создаём файл `testitem.json`

и в нём пишем:

```
{
"parent": "item/generated",
"textures": {
"layer0": "tm:items/testitem"
}
}
```

Потом в папке `textures`

создаём папку `items`

. И в неё кидаем текстуру с названием которое вы указали в `"layer0": "tm:items/testitem"`

. Я буду использовать свою текстуру. Вот она . И конечно же локализация. Значит переходим папку lang где у вас все языки. И в файле `ru_RU`

или `en_US`

пишите вот это:

```
item.testitem.name=Test Item
```

Ну на русском вы пишите это уже в файле `ru_RU`

и собственно его перевод.

Собственно вот мы и создали первый самый обычный предмет. В следующих уроках я расскажу как сделать инструменты, еду, или молоток как из Industrial Craft 2 который сможет раздрабливать предметы.

### Урок 4.1 Инструмент (Кирка, Меч, Топор..)

В этом мини уроке я расскажу как добавить предмет кирку, меч или топор с мотыгой. Будет 2 примера это кирка и меч. Потому что инструменты создаются все почти одинаково. Для начала мы с вами создадим кирку.

В классе `ItemsInit`

в главном теле `ItemsInit{}`

пишем `public static Item testpickaxe;`

и в теле `Init() {}`

пишем `testpickaxe = new test_pickaxe();`

. И создавайте класс `test_pickaxe`

. Советую создать папку `tools`

в пакете `com.name.testmod.items`

, но это уже для удобства (вы можете создать в любом месте)

Далее в строчке где у вас `extend Item`

мы и будем указывать что мы хотим сделать `ItemPickaxe`

(кирка), `ItemAxe`

(топор), `ItemSword`

(меч), `ItemShovel`

(лопата) и `ItemHoe`

(мотыга), а также множества других типов предмета. Я создаю кирку и в место `Item`

пишу `ItemPickaxe`

.

Дальше пишем:

```
public test_pickaxe() {
super(ToolMaterial.IRON);
}
```

`ToolMaterial.`

это материал кирки. Мы указали `IRON`

значит наша кирка будет иметь прочность железной кирки. Можно указать так же (GOLD, DIAMOND, EMERALD, WOOD, STONE). Но я так же покажу как сделать кирку со свой прочностью. А дальше указываем вкладку в креативе `this.setCreativeTab(CreativeTabs.TOOLS);`

и указываем нелокализированное имя предмета `this.setUnlocalizedName("testpickaxe");`

А чтобы сделать кирку со своей прочностью просто напишите это:

```
this.setMaxDamage(1000);
```

`1000`

значит что кирка или топор или мотыга будет иметь прочность 1000.

Потом в главном классе с предметами `ItemsInit`

в теле `register() {}`

пишем `ItemRegistry.registerItem(testpickaxe);`

и в теле registerRender() {} пишем `ItemRegistry.registerRender(testpickaxe);`

тем самым мы зарегистрируем нашу кирку.

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

Ну покажу ещё один пример. Мы создадим меч. В классе `ItemsInit`

в главном теле `ItemsInit{}`

пишем `public static Item testsword;`

и в теле `Init() {}`

пишем `testsword = new test_sword();`

. И создавайте класс `test_sword`

в пакете `com.name.testmod.items.tools`

. В классе `test_sword`

в пишем:

```
public test_sword() {
super(ToolMaterial.GOLD);
}
```

На этот раз я выбрал материал GOLD (золото). Потом мак же указываем вкладку в креативе `this.setCreativeTab(CreativeTabs.COMBAT);`

и указываем нелокализированное имя предмета `this.setUnlocalizedName("testsword");`

. Потом в главном классе с предметами `ItemsInit`

в теле `register() {}`

пишем `ItemRegistry.registerItem(testsword);`

и в теле registerRender() {} пишем `ItemRegistry.registerRender(testsword);`

и так же как кирку мы зарегистрируем меч.

Вот и всё. Надеюсь вам понятно как создавать инструменты. И вы наверно поняли что это не так уж и сложно. Если есть какие то проблемы с текстурой или моделью то перечитайте прошлой урок.

### Урок 4.2 Инструменты с прочностью (Молоток, Нож)

Итак, в этом уроке я расскажу как создать предмет с прочностью, да и ещё чтоб наш нож/молоток умел раздваивать предметы/резать. Прям как в Industrial Craft 2. Заинтересованы тогда давайте приступим.

Сначала как обычно в классе `ItemsInit`

в теле `ItemsInit() {}`

пишем:

```
public static Item knife;
```

И в теле `Init() {}`

пишем:

```
knife = new knife();
```

И сразу давайте зарегистрируем предмет. В теле `register() {}`

пишем `ItemRegistry.registerItem(knife);`

и в теле `registerRender() {}`

пишем `ItemRegistry.registerRender(knife);`

. Когда вы это сделали, то создайте класс `knife`

в пакете `com.name.testname.items.tools`

но вы можете использовать своё месторасположение. Думаю подробно уже объяснять про строение предмета не буду, но только про новые параметры. Значит, просто напишите этот код:

```
public knife()
{
super();
this.setCreativeTab(CreativeTabs.TOOLS);
this.setUnlocalizedName("knife");
this.maxStackSize = 1;
this.setMaxDamage(100);
this.setNoRepair();
}
```

`maxStackSize`

это количество предмета в одном слоте инвентаря. Так как это инструмент поэтому рекомендую указывать 1.
`setNoRepair`

означает что этот инструмент нельзя будет починить. Про импорт не забывайте. И сохраните класс. Теперь мы будет создавать класс в котором будем указывать дополнительные параметры крафта для ножа. Но до этого создайте папку `handlers`

в пакете `com.name.testmod`

. И там создайте класс `HandlersTools`

. Потом в теле `HandlersTools() {}`

просто вставьте этот код:

```
@SubscribeEvent
public void onCrafting(ItemCraftedEvent event) {
final IInventory craftMatrix = null;
for(int i = 0; i < event.craftMatrix.getSizeInventory(); i++) {
if(event.craftMatrix.getStackInSlot(i) != null) {
//Knife
ItemStack item0 = event.craftMatrix.getStackInSlot(i);
if(item0 != null && item0.getItem() ==ItemsInit.knife) {
ItemStack k = new ItemStack(ItemsInit.knife, 2, (item0.getItemDamage() + 1));
if(k.getItemDamage() >= k.getMaxDamage()) {
k.stackSize--;
}
event.craftMatrix.setInventorySlotContents(i, k);
}
```

Давайте разберёмся. `@SubscribeEvent`

это вспомогательная команда. Параметр `onCrafting() {}`

означает что действие будут происходить на верстаке. Я выделил одну часть кода надписью __//Knife__. В этой части кода у нас идёт все действия с определённым предметом. У нас это `knife.`

Если вы ходите добавить такой же другой предмет чтобы он тратил прочность в верстаке, то просто скопируйте часть кода начиная с `ItemStack item0 = event.craftMatrix`

….до `event.craftMatrix.setInventorySlotsContentss(i,k);`

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

```
public class HandlersTools {
@SubscribeEvent
public void onCrafting(ItemCraftedEvent event) {
final IInventory craftMatrix = null;
for(int i = 0; i < event.craftMatrix.getSizeInventory(); i++) {
if(event.craftMatrix.getStackInSlot(i) != null) {
//Knife
ItemStack item0 = event.craftMatrix.getStackInSlot(i);
if(item0 != null && item0.getItem() ==ItemsInit.knife) {
ItemStack k = new ItemStack(ItemsInit.knife, 2, (item0.getItemDamage() + 1));
if(k.getItemDamage() >= k.getMaxDamage()) {
k.stackSize--;
}
event.craftMatrix.setInventorySlotContents(i, k);
}
//Hammer
ItemStack item1 = event.craftMatrix.getStackInSlot(i);
if(item1 != null && item1.getItem() ==ItemsInit.hammer) {
ItemStack k = new ItemStack(ItemsInit.hammer), 2, (item1.getItemDamage() + 1));
if(k.getItemDamage() >= k.getMaxDamage()) {
k.stackSize--;
}
event.craftMatrix.setInventorySlotContents(i, k);
}
```

После строчки `//Hammer`

как вы возможно догадались это второй предмет. Но вам его не обязательно добавлять. Ну если конечно вы не хотите его добавить. Перед сохранением класса не забудьте импортировать недостающие классы.
Теперь нам нужно указать крафт. Про создания базы для крафта смотрите урок 5. Значит в папке craft в классе CraftingRecipes в теле `init() {}`

пишем крафт.

```
GameRegistry.addRecipe(new ItemStack(ItemsInit.testitem, 1),
new Object[]{ " K ", "WWW", "WWW",
('W'), Blocks.WOOL, ('K'), new ItemStack(ItemsInit.knife, 1, OreDictionary.WILDCARD_VALUE)});
```

Как вы поняли или нет к нашему предмету просто добавляется параметр `OreDictionary.WILDCARD_VALUE`

. Теперь переходим в главный класс `Main`

и в теле `init() {}`

пишем вот этот код:

```
MinecraftForge.EVENT_BUS.register(new HandlersTools());
```

Вот и всё. Теперь вам осталось добавить только модель, текстуру и локализировать предмет. Об это подробнее смотрите в уроке 4.

Примерно вот так у вас должно получиться.

### Урок 4.3 Еда/Напитки

В прошлых уроках вы научились создавать предмет, а теперь давайте создадим еду, чтобы наш персонаж был сыт и мог вкусненько поесть. Создадим класс для нашей еды, пусть будет мандарин. (если вы не умеете создавать классы и работать с предметом, то и посмотрите 4 урок.) Значит назовем наш класс `FoodMandarinchik`

(можете назвать по своему). Ну а дальше уже по старинке:

```
public class FoodMandarinchik extends ItemFood
{
public FoodMandarinchik(int amount, float saturation, boolean isWolfFood)
{
super(amount, saturation, isWolfFood);
this.CreativeTab(ваш класс.ваша вкладка)
this.setUnlocalizedName("Mandarinchik");
}
}
```

Появились новые параметры, такие как `amount`

, `saturation`

, `isWolfFood`

.

`isWolfFood`

— отвечает за то, может ли волк есть нашу еду.

`amount`

— отвечает за количество восполняемого голода.

`saturation`

— отвечает за длительность сытости.

Дальше мы заходим в класс `ItemsInit`

и в теле `ItemsInit() {}`

пишем: `public static Item Mandarinchik`

. И в теле `Init() {}`

пишем: `Mandarinchik = new FoodMandarinchik(1, 0.5F, false);`

.

Всё! Вам только осталось локализировать еду, сделать модель и текстуру. Если вы не знаете как это делать смотрите 4 урок.

**Добавление эффекта при съедании.**

Давайте вернёмся к нашему классу еды (`FoodMandarinchik`

) и добавим туда метод `onFoodEaten`

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

```
@Override
protected void onFoodEaten(ItemStack stack, World worldIn, EntityPlayer player)
{
super.onFoodEaten(stack, worldIn, player);
if(player.getFoodStats().getFoodLevel() > 2)
{
player.addPotionEffect(new PotionEffect(Potion.getPotionById(9), 100));
}
}
```

Из кода видно, что если у игрока уровень голода больше 2, то мы добавляем игроку эффект зелья тошноты (id = 9), которое будет длится 5 секунд. Вы можете использовать любые Id эффектов. Все еда с эффектом готова.

**Анимация (Есть/Пить)**

Это вообще легко. Возвращаемся в наш класс еды и пишем:

```
public EnumAction getItemUseAction(ItemStack stack)
{
return EnumAction.DRINK;
}
```

Это анимация питья. (`DRINK`

)

```
public EnumAction getItemUseAction(ItemStack stack)
{
return EnumAction.EAT;
}
```

Это анимация еды. (`EAT`

) .

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

Собственно, у нас есть блок и предмет. Мы можем их держать в руках, а блок даже ставить. Но а если мы хотим достать их, играя в режиме Выживания? Тогда блок или предмет можно только найти или скрафтить.

**Главный класс.**

Но перед тем как мы будем создавать крафты мы создадим в пакете `com.name.testmod.crafts`

класс `CraftingRecipes`

(повторяю, что можно использовать своё название). И в этом классе в теле `CraftingRecipes {}`

пишем маленький код:

```
public static void init()
{
}
```

Тут как вы уже поняли мы будем писать все крафты. Но перед этим мы в главном классе `Main`

должны написать, что эти крафты будут загружаться. Значит в главном классе `Main`

в теле `init() {}`

пишем:

```
CraftingRecipes.init();
```

Главный класс сохраняем. (не забываем импортировать классы) И теперь начинаем добавлять наши крафты. Переходим в класс крафтов у нас это `CraftingRecipes`

.

**Создание крафта.**

Добавить крафт очень просто. Например я хочу скрафтить блок, положив во все верхние и нижние клетки камень, в оставшиеся боковые — гравий, а в середину — железный слиток, тогда я запишу вот это в тело метода `init() {}`

в фигурных скобках запишу вот это:

```
GameRegistry.addRecipe(new ItemStack(BlocksInit.testblock, 1),
new Object[]{ "###", "XYX", "###", ('X'),
Blocks.GRAVEL, ('#'), Items.IRON_INGOT, ('Y'), Blocks.STONE});
```

Давайте разберем, что тут написано: Итак с помощью `GameRegistry`

мы добавляем новый рецепт, `new itemStack`

значит, что создастся новая стопка с предметом `testblock`

который объявлен в классе `BlocksInit`

в количестве одной штуки (вместо 1 можно вписать любое число до 64). А далее уже записана сетка крафта. Как мы помним в верстаке мы видим всего 9 клеток, здесь первая строка верстака это `«###»`

, вторая строка — это `«XYX»`

, ну и последняя — `«###»`

. Понятней будет, если посмотреть вот так:

"###" "XYX" "###"

Каждый предмет в крафте обозначается своим личным знаком(любым). Далее это записано как `('X'), Blocks.GRAVEL`

То есть это означает, что X — это гравий, который является блоком. Соответственно знак `('#')`

— это слиток железа (который является предметом, а не блоком), а `('Y')`

— это блок камня. Если нужно, чтоб в ячейке крафта ничего не лежало, то вместо знака пишется пробел (Например `" # "`

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

Добавить рецепт крафта можно не только вашему блоку или предмету. Можно вписывать вместо `BlocksInit.testblock`

или `Blocks.STONE`

что угодно, главное что бы после точки была указана зарегистрированная переменная типа `Block`

или `Item`

. А до точки — это просто путь к этой переменной.

Если хотите создать крафт, который можно произвести в инвентаре, вместо `«###», «XYX», «###»`

используйте "`AA», «BC»`

соответственно.

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

```
GameRegistry.addShapelessRecipe(new ItemStack(Blocks.GRASS, 4),
new Object[] {Blocks.GRAVEL, Blocks.GRAVEL, Items.ARROW});
```

Не забывайте про импорт.

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

Но можно не писать 2 раза GRAVEL можно просто после `Blocks.GRAVEL`

поставить запятую и указать цифру от 1 до 9.

Если у блока/предмета есть несколько видов (например: дубовые, еловые, березовые доски и т. д.), то указав просто например: `Blocks.PLANKS`

в крафте можно будет использовать любые доски!

Так же в майнкрафте, как мы знаем, присутствует переплавка одних предметов/блоков в другие. Рецепт такой переплавки создаётся всего одной строкой, которую можно писать в любом месте класса `CraftingRecipes`

и тела `init() {}`

:

```
GameRegistry.addSmelting(testblock, new ItemStack(Blocks.diamond_block, 2), 1.0F);
```

Но теперь разберем. Итак, первой в скобочках указана переменная типа `Block`

(также можно `Item`

), в данном случае это наш блок, затем идет переменная типа `ItemStack`

, которая создаётся сразу же. У этой переменной уточняется, что создастся стак с блоком или предметом, в данном случае алмазным блоком, в количестве 2. Ну и последняя переменная отвечает за количество опыта, получаемого при переплавке.

Если у вас есть предмет который имеет прочность и вы хотите чтобы при его использовании (крафте) его прочность уменьшалась(если вы не знаете. что это такое то посмотрите #урок 4.2) то напишите этот код:

```
GameRegistry.addRecipe(new ItemStack(ItemsInit.testitem, 1),
new Object[]{ " K ", "WWW", "WWW",
('W'), Blocks.WOOL, ('K'), new ItemStack(ItemsInit.test_knife, 1, OreDictionary.WILDCARD_VALUE)});
```

Как вы поняли или нет к нашему предмету просто добавляется параметр `OreDictionary.WILDCARD_VALUE`

.

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

### Урок 6. Вкладка в креативе

Ну вот вы написали мод, да? У вас есть блоки, предметы, даже некоторые предметы со своими свойствами. Но вы хотите поместить их куда-то в одно место. Вы хотите создать свою вкладку в креативе, и не знаете как это сделать. Делается всё довольно легко. И сегодня я расскажу как.

**Главный класс.**

Так же, как для блоков и предметов мы сделаем главный класс и для вкладок в креативе. Давайте начнём. В пакете `com.name.testmod.init`

создайте класс `CreativeTabInit`

. И в теле `CreativeTabInit() {}`

пропишите вот этот код:

```
public static void init()
{
}
```

**Создание вкладки.**
Всё мы создали главный класс. Теперь в этом класс в теле `CreativeTabInit {}`

пишем:

```
public static CreativeTabs TabTest;
```

А потом в теле `Init () {}`

:

```
TabTest = new TabTest();
```

Далее создаём класс и заходим в него. И в строке `public class....`

дописываем `extends CreativeTabs`

. И теперь в главном теле пишем этот код:

```
public TabTest()
{
super("TabTest");
}
@Override
public Item getTabIconItem()
{
return Items.STICK;
}
@Override
public String getTranslatedTabLabel()
{
return "My first Tab";
}
```

`getTabIconItem`

указывает какая иконка будет во вкладке. `getTranslatedTabLabel`

какое имя будет у вашей вкладки. Собственно всё, можете сохранять.

**Добавление предмета или блока во вкладку.**

Просто в вашем классе блока или предмета там где строка `this.setCreativeTab(главный класс.ваша вкладка);`

вместо `главный класс`

пишите `CreativeTabInit`

а вместо `ваша вкладка`

пишите `TabTest`

(вашу вкладку). Всё очень просто и легко. Вот вы и добавили свою первую вкладку.

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

Что же, вы написали модификацию, она работает, но вы хотите чтобы он работал и просто на Minecraft. Давайте наконец его скомпилируем!

Компилировать модификацию очень просто.

В самом первом уроке про создание Forge я вам советовал создать файл `gradlew build.bat`

. И повторюсь что так правильнее делать. С помощью этого файла мы сможем собрать (скомпилировать) наша модификация в jar файл. Когда вы его создали вы кликаем по нему `ПКМ` и выбираете ИЗМЕНИТЬ. И прописываете вот этот код:

gradlew.bat build

Теперь запускаем его. После автоматического закрытия консоли модификация скомпилирована и находится в папке build/libs.
Если для компиляции модификации требуется подключение дополнительных jar библиотек, то необходимо в корневой папке проекта (Modding) создать папку `libs`

и поместить все необходимые файлы в неё.

Теперь немного о том, что получилось. У нас есть файл с расширением `jar`

, а в нём наша модификация, и собственно, можно кидать его в папку mods и пользоваться, но нужно отметить что в этом jar-архиве есть папка `META-INF`

, которая запрещает что-либо из него удалять (Если что `.jar`

можно открывать любым архиватором). Так же следует обратить внимание на то что компилятор автоматически вставит в архив всё, что вы «напрограммировали» и там будут весь код и все ресурсы от модификаций над которыми вы работаете. Если для вас это неприемлемо, просто удалите лишние пути из архива (например `name.mod.megatestmod,`

если работаете с `testmod`

и т. п.). Так же можно со спокойной совестью удалить `META-INF`

и вообще всё разархивировать и упаковать в zip-архив, он также будет работать.

Так же немного о `build.gradle`

Вы можете его модифицировать так, чтобы jar-файл автоматически назывался как надо. Откройте его любым текстовым редактором. Вы можете изменить следующие строки, как захотите, например так:

version = "1.0" group= "com.name.testmod" archivesBaseName = "Test Mod"

Сохраните файл. Таким образом вы получите при компиляции файл `Test Mod-1.0.jar`


### Урок 8. Генерация блоков в мире

Теперь мы сделаем так, чтобы теперь какой-либо блок, аналогично рудам, генерировался в обычном мире, в Нижнем мире или в краю. Сейчас мы будем создавать генератор наших руд. Я вам советую перед этим создать в пакете `com.name.testmod`

создать папку `world`

и ещё в ней создать папку `gen`

, а только потом создавать класс `GeneratorOre`

(вы так же можете использовать своё месторасположения). Так уже в классе `GeneratorOre`

в строке `public class GeneratorOre`

дописываем `implements IWorldGenerator`

. Теперь в теле главного класса пишем:

```
//World Generators
private WorldGenerator testore;
```

Тут мы дали понять, что зарегистрировали наш блок в генераторе. И если вы хотите добавить 2 блок в генератор, то просто на следующей строчке пишите например: `private WorldGenerator testore2`

или `private WorldGenerator testore50`

. Для каждого генератора будет использоваться один блок или руда. Продолжаем дальше писать:

```
public GeneratorOre() {
testore = new WorldGenMinable(BlocksInit.myore.getDefaultState(), 8);
}
```

Мы написали что наш генератор `testore`

(может быть любое название) будет генерировать блок `myore`

и максимальное количество руды в жиле будет `8`

. Может быть любое количество. НУ а теперь самое сложное. Пишем этот код:

```
private void runGenerator(WorldGenerator generator, World world, Random rand, int chunk_X, int chunk_Z, int chancesToSpawn, int minHeight, int maxHeight) {
if (minHeight < 0 || maxHeight > 256 || minHeight > maxHeight)
throw new IllegalArgumentException("Illegal Height Arguments for WorldGenerator");
int heightDiff = maxHeight - minHeight + 1;
for (int i = 0; i < chancesToSpawn; i ++) {
int x = chunk_X * 16 + rand.nextInt(16);
int y = minHeight + rand.nextInt(heightDiff);
int z = chunk_Z * 16 + rand.nextInt(16);
generator.generate(world, rand, new BlockPos(x, y, z));
}
}
@Override
public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator,
IChunkProvider chunkProvider) {
switch(world.provider.getDimension()) {
case 0: //OverWorld
this.runGenerator(testore, world, random, chunkX, chunkZ, 13, 50, 150);
case 1: //End
case -1: //Nether
}
}
```

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

```
case 0: //OverWorld
this.runGenerator(testore, world, random, chunkX, chunkZ, 13, 50, 150);
case 1: //End
case -1: //Nether
```

`case 0`

означает, что руда будет генерироваться в нормальном мире (обычном) , `case 1`

то, что руда будет генерироваться в энде, а `case -1`

как вы уже поняли, что в Нижнем мире. Теперь смотрим на строку `this.runGenerator......`

. `testore`

это ваш блок или руда которую мы указывали в самом верху кода (`private WorldGenerator testore;`

), `world`

то что генерация будет происходить в мире, `random`

, то что руда будет генерироваться рандомно, `chunkX`

и `chunkZ`

можно пропустить.
Теперь смотрим на цифры. Первая означает шанс спауна руды/блока. Нормальный шанс спауна это от 5 до 20. Дальше уже будет слишком много. Вторая цифра означает минимальную высоту спауна, а третья цифра максимальную высоту. Если вы с этим разобрались то продолжаем писать. Сейчас мы будем регистрировать генератор. Чтоб он генерировал руду.

```
public static void register() {
GameRegistry.registerWorldGenerator(new GeneratorOre(), 0);
}
```

Цифра 0 означает вес для данного генератора. Тяжелые веса, как правило, опускаются до нижней части списка мировых генераторов (то есть они запускаются позже). Если не поняли о чём речь то просто оставьте 0 и всё. Не забывайте импортировать недостающее классы. И после этого сохраняйте генератор.
Теперь переходим в класс `Main`

и в теле `Init() {}`

пишем:

```
GeneratorOre.register();
```

Всё теперь можно запускать и смотреть результаты.

### Урок 9. Моб

Скоро.

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

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

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

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

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

напишите «`return Items.getItemFromBlock(Blocks.);`

» (для блоков) или «`return Items.;`

» (для предметов), а после ввода вами точки выпадет список возможных предметов или блоков.

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

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

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

### Разносторонняя текстура блока

Я буду использовать следующие текстуры:

Для этого, добавьте такой код в тело класса:

public IIcon[] icons = new IIcon[6];

И такой после конструктора класса:

@Override public void registerBlockIcons(IIconRegister reg) { for (int i = 0; i < 6; i ++) { this.icons[i] = reg.registerIcon(this.textureName + "_" + i); } }

Теперь в папку `assets/ID модификации/resources/textures/blocks/`

добавьте файлы с таким именем: `<То, что вы указали в скобках в конструкторе класса, в методе this.setBlockTextureName()>_<код стороны блока>`


И ещё такой код:

@Override public IIcon getIcon(int side, int meta) { return this.icons[side]; }

В игре блок будет выглядеть так:

Важно то, что текстура северной и восточной (2 и 5) части блока отображается зеркально. Если вы не поняли, то поставьте блок ТНТ и посмотрите на части, где написано TNT. С одной стороны написано «TNT», а с другой — «ТИТ».

### Обновление Forge

Чтобы обновить версию Forge, на который вы создаёте модификации, необязательно всё перекачивать.

Достаточно просто изменить build.gradle Так что если хотите обновить Forge откройте его любым редактором и найдите строчку

version = "1.9.4-10.12.0.998"

Там будет написана версия Forge, которая у вас сейчас, соответственно вам нужно всего лишь изменить значение на новое. Измените его на версию, до которой хотите обновить Forge (например на `1.9.4-10.12.0.1012`

) и сохраните файл. Далее запустите `gradlew.bat`

с командой `eclipse`

(то есть запустить bat-файл с кодом `gradlew.bat eclipse`

) и после завершения его работы ваша версия Forge обновлена!

### Обновление ForgeGradle

Forge отделён от `ForgeGradle`

, поэтому если вы попытаетесь обновиться на версию Forge, которая использует более новой `ForgeGradle`

, вы получите ошибки. Вот таблица версия Forge, и какие версии `ForgeGradle`

он использует.

ForgeGradle | Forge |
---|---|

- | 959<, 965 |

1.0 | 960-964 |

1.1 | 967-1047 |

1.2 | 1048+ |


Удалите папку **.gradle**, которая находится в папке, куда вы разархивировали Forge.
Теперь, откройте файл **build.gradle** (который находится там же). Найдите такую строку:

dependencies { classpath 'net.minecraftforge.gradle:ForgeGradle:1.x-SNAPSHOT' }

В **1.x-SNAPSHOT**, поменяйте **1.x** на нужную версию `ForgeGradle`

. Сохраните файл и откройте командную строку. Повторно введите команды, которые вы использовали при установке Forge. `ForgeGradle`

обновит все нужные файлы.



### Создание брони

Создание брони немного отличается от создания обычных предметов, точнее имеет свои особенности. Приступим.

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

public static Item bestarmorhelmet; public static Item bestarmorplate; public static Item bestarmorpants; public static Item bestarmorboots;

Шлем, нагрудник, штаны и ботинки соответственно. Теперь описываем эти переменные с помощью универсального класса. Естественно внутри метода preLoad()

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");

Здесь вроде всё знакомо, мы даём нелокализированное имя каждому из предметов, а также текстуру. Но здесь мы посылаем ещё и две цифры в метод BestArmor. Вторая цифра отвечает за тип брони (0 — шлем, 3 — ботинки), назначение первой неясно, но в данном случае она роли не играет. Далее тоже ничего нового, просто зарегистрируем эти предметы в Forge. Сделать это нужно после описания переменных.

GameRegistry.registerItem(bestarmorhelmet, "bestarmorhelmet"); GameRegistry.registerItem(bestarmorplate, "bestarmorplate"); GameRegistry.registerItem(bestarmorpants, "bestarmorpants"); GameRegistry.registerItem(bestarmorboots, "bestarmorboots");

С главным классом работа окончена.

Теперь щелкаем по одной из ошибок и создаём новый класс BestArmor. Теперь «продолжаем» класс ItemArmor, то есть пишем `extends ItemArmor`

после названия класса. Теперь в тело класса вставляем следующее:

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; }

Что ж, давайте разбираться.

Первая переменная, просто обозначает начало пути к текстуре брони. Все нужные текстуры можно спокойно извлечь из майнкрафта и отредактировать по желанию. Вот мои отредактированные текстуры:
Текстуры предметов помещаются туда же, где и текстура кирки. А вот две текстуры самой брони нужно поместить в другую папку. Поэтому создайте её: нажмите ПКМ по `src/main/resources`

и выберите New — Package и назовите его `assets.mybestmod.textures.model.armor`

и уже туда перетащите две оставшиеся текстуры.

Давайте дальше разбираться с кодом: следующим идёт метод 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 — зачаровываемость.

Вот и все. Теперь можно использовать этот материал для брони, например заменив `ArmorMaterial.DIAMOND`

на `BaseMyBestMod.BESTMAT`


### Генерация предметов в контейнерах натуральных структур

Итак, вы можете сделать так, чтобы ваш, или любой другой предмет/блок генерировался в сундуках сокровищницы. Для этого в методе preLoad() в главном классе вставьте следующее:

ChestGenHooks.addItem(ChestGenHooks.DUNGEON_CHEST, new WeightedRandomChestContent(new ItemStack(Testmod.testblock), 1, 10, 3));

Разберемся в параметрах:

`(ChestGenHooks.DUNGEON_CHEST)`

— Вместо`DUNGEON_CHEST`

выберете одно из возможных мест генерации в выпадающем списке.`(Testmod.testblock)`

— Требуемый блок/предмет. В скобочках указывается любая переменная типа Block или Item.`(1)`

— Минимальное генерируемое количество.`(10)`

— Максимальное генерируемое количество.`(3)`

— Шанс генерации.

### Атрибуты для моба

Если вы уже проверили моба, то заметили, что он двигается очень медленно. Чтобы исправить это и добавить атрибуты для моба добавьте в класс моба следующий код:


@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); }

Разъяснение:

Параметр | Описание |
---|---|

maxHealth | Максимальное здоровье |

followRange | Дистанция, на которой моб будет преследовать кого-либо |

knockbackResistance | Сопротивление к отбрасыванию |

movementSpeed | Скорость движения |

attackDamage | Сила атаки |


Атрибуты установлены.

### Интеллект для моба

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

public boolean isAIEnabled() { return true; }

Теперь в конструктор класса добавьте следующий код:

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));

Первый аргумент метода «addTask» — приоритет назначения интеллекта, второй — сам интеллект. В примере используются следующие интеллекты: «Swimming», «AttackOnCollid», «Wander», «WatchClosest», «LookIdle», «HurtByTarget» и «NearestAttackableTarget». Разъяснение:

Интеллект | Описание |
---|---|

Swimming | Может ли существо плавать? |

AttackOnCollid | Базовый тип атаки, который используют зомби и пауки. |

Wander | Существо будет ходить вокруг, когда никого не атакует. |

WatchClosest | Ищет назначенное существо на заданном расстоянии. |

LookIdle | Существо будет осматриваться, просто стоя. |

HurtByTarget | Сделает целью какого-либо моба, который его ударил. |

NearestAttackableTarget | Ищет любое существо, которое подходит по второму параметру. |


Интеллект установлен.

### Свой скин при моддинге

**Внимание!** Этот способ работает только на лицензионной версии MineCraft

Чтобы при создании модификации вы видели свой скин, вместо стандартного скина Steve, нужно прописать 2 строчки в аргументах запуска.

--username=ВашЛогин --password=ВашПароль

После этого, при заходе в игру вы будете видеть свой скин.

## Примечания

- ↑ В Java директории указываются не слешами, как в Windows, а точками. То есть «net.minecraft.client» — это когда папка «client» лежит в папке «minecraft», которая лежит в папке «net».
- ↑ Документация Oracle
- ↑ Статья «Java package» на английской википедии
- ↑ Любое тело в Java обозначается фигурными скобками и обозначает внутренности некоторой подпрограммы. Например,
`public class TestMod {`

} указывает, что это класс, а в скобках написано, что он делает.