Создание модификаций с помощью Forge/1.7+/Дополнительные уроки

Здесь представлены основные уроки по созданию модификаций с помощью Forge/1.7+. Остальную информацию по данной теме смотрите в соответствующей статье.

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

Собственно у нас есть некоторые предметы, блоки, а возможно даже кнопки, существа и надписи из нашего мода, называющиеся в инвентаре примерно так: `item.block.name`

Естественно это нас не устраивает, и это можно исправить, даже не внося изменений в код!

Итак, приступим. Слева, в `src/main/resources`

создайте пакет `assets.mybestmod.lang`

Понятно, что mybestmod — это краткое имя мода(или modid), указанное в @Mod. Теперь где угодно создайте файл(создайте текстовой, а затем измените расширение) en_US.lang (где будут написаны английские название блоков, предметов и т. д.) и пропишите в нём то, что вы видите вместо названия в инвентаре (в случае нашего первого блока — tile.bestblockever.name), затем равно, и прямо за ним — ваше локализированное название, например: «Best Block EvAR!». То есть должно получиться:

```
tile.bestblockever.name=Best Block EvAR!
```

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

```
tile.bestblockever.name=Самый лучший блок!! =P
```

Теперь оба этих файла можете перетащить в заранее созданную `assets.mybestmod.lang`

При переносе выберите Copy files.

Чтобы локализировать вкладки в режиме творчество добавьте такой код:

```
itemGroup.tabTutorial=Локализированое имя
```

`tabTutorial`

— Название вашей вкладки

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

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

Скорее всего в игре русское название будет выглядеть вопросами! Это всё из-за кодировки. Исправить это можно зайдя в eclipse вкладку window\preferences\general и просто нажмите на workspace и внизу найдите text file encoding и поставьте на other и там выберите UTF-8. Всё! теперь у нас нормальный русский язык!

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

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

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

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

напишите «`return Item.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», а с другой — «ТИТ».

## Собственная вкладка в Творческом режиме

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

```
public static CreativeTabs tabTutorial = new TabTutorial("ModID");
```

«ModID» заменяем на любое число. Рекомендую ID больше 11 (12 ID сразу на следующей странице творческого инвентаря).

Потом создайте класс TutorialTab. Если всё правильно, то ваш класс будет иметь `extends CreativeTabs`

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

```
public TabTutorial(String lable) {
super(lable);
}
@Override
public Item getTabIconItem()
{
return Item.getItemFromBlock(Blocks.grass);
}
```

Теперь заходите в игру. Вы увидите свою вкладку во втором списке вкладок, её «символом» будет блок дёрна. Если вам хочется, чтобы «символом» был предмет, то вместо `Blocks.`

напишите `Items.предмет`

. Если вы хотите, чтобы «символом» был ваш блок или предмет, то напишите `BestMod.bestBlockEver`

. `BestMod`

— главный файл вашего мода. `bestBlockEver`

— ваш блок/предмет.

Для того что бы добавить что либо из вашего мода в собственную вкладку пишем:

```
this.setCreativeTab(НазваниеГлавногоКласса.НазваниеВашейВкладки);
```

## Обновление 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-файл с кодом `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 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).

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

на `super(BaseMyBestMod.NEWMAT);`

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

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

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

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

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

```
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(BaseMyBestMod.bestblockever), 1, 10, 3));
```

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

`(ChestGenHooks.DUNGEON_CHEST)`

— Вместо`DUNGEON_CHEST`

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

— Требуемый блок/предмет. В скобках указывается любая переменная типа 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=ВашПароль
```

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