- Версия(и) Minecraft
- 1.7.10, 1.12.2
Доброго времени суток. На этот раз я буду описывать процесс создания собственных чар. Разобранный пример и другие, более сложные, вы сможете найти на GitHub: 1.7.10 и 1.12.2.
Создание чар
Все чары наследуются от класса Enchantment, который определяет такие основные свойства как редкость чар, допустимые предметы для применения, уровни чар и требуемый опыт. Применение чар к определённым предметам довольно просто настраивать. Соответствующие зачарованные книги создаются автоматически при регистрации чар.
В рамках туториала создадим чары "Безопасное Падение", которые будут накладываться на любые ботинки и убирать урон при падении, но добавим изюминку - ботинки будут терять прочность в зависимости от высоты.
Суперконструктор требует указания редкости идентификатора чар, "веса" чар и типа целевых предметов, на которые эти чары можно накладывать.
Первым идёт идентификатор (id) чар. В суперклассе содержится массив для чар размером в 256 ячеек, но занято не так много. Изучите его, последние ванильные чары имеют id равный 62, хотя разбросаны они беспорядочно.
Рассмотрим второй параметр - вес, влияющий на редкость чар. Чем ниже это значение - тем реже встречаются чары (в столе зачаровывания). Ванильные чары имеют разброс от 1 (Шёлковое Касание) до 10 (Острота, Защита и т.п.).
Класс предметов экипировки, для которых подходят чары, идёт третьим параметром EnumEnchantmentType. Там много доступных вариантов, например
Все эти параметры будут определены в конструкторе при инициализации. Я добавил строковый параметр для имени чар и метод для его указания.
Далее нужно определиться с какими чарами эти чары могут конфликтовать. По умолчанию все чары конфликтуют сами с собой. Что бы ограничить применение других чар на предмет при наличии конфликтных или наоборот используется метод
В этом примере я исключил ванильные чары, влияющие на снижение урона от падения.
Если предполагается что чары имеют несколько уровней, то необходимо переопределить
Что бы задать границы уровней, в которых при зачаровывании можно получить чары нужно переопределить
Так как уровень у чар только один, можно не заморачиваться хитрыми расчётами.
В итоге класс целиком:
Регистрацию чар будем проводить в отдельном классе EnchantmentsRegistry:
Задаём имя, id (я начал со 100), вес и допустимую экипировку. При загрузке класса наши чары инициализируются и суперконструктор Enchantment добавит наши чары в общий массив и создаст соответствующую зачарованную книгу. Для зарузки класса я создал пустой метод
Локализация названия чар:
А использования в команде /enchant для зачаровывания предмета у себя в руке:
Применение эффекта
Для удобства я создал отдельный класс, в котором размещаю удобные статические методы для проверки наличия чар EnchantmentsHelper. Выглядит это так:
По сути происходит запрос на уровень чар с искомым идентификатором на определённом элементе. Если искомых чар нет, то вернётся уровень, равный нулю.
Теперь к эффекту. В данном случае надо отменить урон от падения - для этого есть LivingFallEvent. Поместил я его в отдельный класс (можно и в класс чар) EnchantmentsEvents:
Не забудьте зарегистрировать класс с эвентом:
Вот и всё. Теперь можно и тестировать. В игре возьмите любые ботинки и зачаруйте командой. Если всё получилось - вы получите ботинки с созданными чарами. При падении с надетыми ботинками с этими чарами урон наносится не должен, но прочность ботинок будет снижаться в зависимости от высоты падения.
Книга с чарами будет располагаться во вкладке с бронёй среди остальных. Вы можете наложить эти чары на наковальне. Ну или попытаться получить их на столе зачаровывания. В конце статьи есть послесловие, прочтите его для получения дополнительной информации.
1.12.2
Начинается всё с класса, представляющего чары. Класс чар EnchantmentSafeFall:
Суперконструктор требует указания редкости чар, класса целевых предметов и элементы экипировки, на которые эти чары можно накладывать.
Рассмотрим первый параметр - редкость, представленная перечислением Rarity. Она бывает четырх разновидностей:
Второй - класс предметов экипировки, для которых подходят чары, перечисление EnumEnchantmentType. Там много доступных вариантов, например
Массив допустимых для чар предметов экипировки идёт третьим параметром, ознакомьтесь с содержимым перечисления EntityEquipmentSlot.
Все эти параметры будут определены в конструкторе при инициализации. Я добавил строковый параметр для имени чар и метод для его указания.
Далее нужно определиться с какими чарами эти чары могут конфликтовать. По умолчанию все чары конфликтуют сами с собой. Что бы ограничить применение других чар на предмет при наличии конфликтных или наоборот используется метод
В этом примере я исключил ванильные чары, влияющие на снижение урона от падения.
Если предполагается что чары имеют несколько уровней, то необходимо переопределить
Что бы задать границы уровней, в которых при зачаровывании можно получить чары нужно переопределить
Так как уровень у чар только один, можно не заморачиваться хитрыми расчётами.
В итоге класс целиком:
Регистрацию чар будем проводить в отдельном классе EnchantmentsRegistry:
Задаём имя, редкость, допустимые элементы экипировки и регистрируем через эвент RegistryEvent.Register. Для автоматической подгрузки эвентов ставим аннотацию
Локализация названия чар:
А использования в команде /enchant для зачаровывания предмета у себя в руке:
Применение эффекта
Для удобства я создал отдельный класс, в котором размещаю удобные статические методы для проверки наличия чар EnchantmentsHelper. Выглядит это так:
По сути происходит запрос на уровень искомых чар на определённом элементе. Если искомых чар нет, то вернётся уровень, равный нулю.
Теперь к эффекту. В данном случае надо отменить урон от падения - для этого есть LivingFallEvent. Поместил я его в отдельный класс (можно и в класс чар) EnchantmentsEvents:
Вот и всё. Теперь можно и тестировать. В игре возьмите любые ботинки и зачаруйте командой. Если всё получилось - вы получите ботинки с созданными чарами. При падении с надетыми ботинками с этими чарами урон наносится не должен, но прочность ботинок будет снижаться в зависимости от высоты падения.
Книга с чарами будет располагаться во вкладке с бронёй среди остальных. Вы можете наложить эти чары на наковальне. Ну или попытаться получить их на столе зачаровывания.
Послесловие
Вот как то так это и происходит. Если вам нужно больше информации, то ознакомьтесь с другими примерами в моём репозитории: 1.7.10, 1.12.2. Кроме этих там есть чары переплавки, которые накладываются только на кастомные инструменты и делают интересные вещи, а также чары для кастомного меча, аналогичные "Остроте" с демонстрацией ванильной системы применения чар без эвентов.
Всем спасибо за внимание. Если вам есть что добавить или какие либо вопросы - пишите в обсуждении.
Чары
Зачаровывание предметов является неотъемлемой частью игры. Есть важный момент - чары привязаны только к предмету (NBT ItemStack'а). Хоть это и вполне логично, это серьёзно ограничивает гибкость их применения так как для этого обязательно придётся использовать эвенты (за исключением чар повышения и снижения урона, предлагающих встроенные методы), а каких либо встроенных средств для отслеживания активных чар и их сохранения (относительно сущностей) в игре нет.
Создание чар
Все чары наследуются от класса Enchantment, который определяет такие основные свойства как редкость чар, допустимые предметы для применения, уровни чар и требуемый опыт. Применение чар к определённым предметам довольно просто настраивать. Соответствующие зачарованные книги создаются автоматически при регистрации чар.
В рамках туториала создадим чары "Безопасное Падение", которые будут накладываться на любые ботинки и убирать урон при падении, но добавим изюминку - ботинки будут терять прочность в зависимости от высоты.
1.7.10
Начинается всё с класса, представляющего чары. Класс чар EnchantmentSafeFall:
Java:
public class EnchantmentSafeFall extends Enchantment {
public EnchantmentSafeFall(String enchantmentName, int enchantmentId, int weight, EnumEnchantmentType enchantmentType) {
super(enchantmentId, weight, enchantmentType);
this.setName(enchantmentName);
}
}
Суперконструктор требует указания редкости идентификатора чар, "веса" чар и типа целевых предметов, на которые эти чары можно накладывать.
Первым идёт идентификатор (id) чар. В суперклассе содержится массив для чар размером в 256 ячеек, но занято не так много. Изучите его, последние ванильные чары имеют id равный 62, хотя разбросаны они беспорядочно.
Рассмотрим второй параметр - вес, влияющий на редкость чар. Чем ниже это значение - тем реже встречаются чары (в столе зачаровывания). Ванильные чары имеют разброс от 1 (Шёлковое Касание) до 10 (Острота, Защита и т.п.).
Класс предметов экипировки, для которых подходят чары, идёт третьим параметром EnumEnchantmentType. Там много доступных вариантов, например
all
- чары могут быть наложены на всё, digger
- только на инструменты, armor
- на броню и т.д.Все эти параметры будут определены в конструкторе при инициализации. Я добавил строковый параметр для имени чар и метод для его указания.
Далее нужно определиться с какими чарами эти чары могут конфликтовать. По умолчанию все чары конфликтуют сами с собой. Что бы ограничить применение других чар на предмет при наличии конфликтных или наоборот используется метод
Enchantment#canApplyTogether()
:
Java:
@Override
public boolean canApplyTogether(Enchantment enchantment) {
return super.canApplyTogether(enchantment) && enchantment != Enchantment.featherFalling;
}
В этом примере я исключил ванильные чары, влияющие на снижение урона от падения.
Если предполагается что чары имеют несколько уровней, то необходимо переопределить
Enchantment#getMinLevel()
и Enchantment#getMaxLevel()
. По умолчанию они возвращают значение, равное единице. Наши чары не будут иметь уровней (будет один по умолчанию) и переопределять эти методы нет необходимости.Что бы задать границы уровней, в которых при зачаровывании можно получить чары нужно переопределить
Enchantment#getMinEnchantability()
и Enchantment#getMaxEnchantability()
:
Java:
@Override
public int getMinEnchantability(int enchantmentLevel) {
return 10;
}
@Override
public int getMaxEnchantability(int enchantmentLevel) {
return 20;
}
Так как уровень у чар только один, можно не заморачиваться хитрыми расчётами.
В итоге класс целиком:
Java:
public class EnchantmentSafeFall extends Enchantment {
/*
* Падение не наносит урона. Эффект применяется с помощью эвента в EnchantmentsEvents.
*
*
* Кол-во уровней чар: 1
*
* Уровни опыта для зачаровывания: 10 - 20
*
* Несовместимости: Невесомость.
*
* Целевые предметы: Любые ботинки.
*
* Эффект: Полное исключение урона при падении, но ботинки получают урон равный высоте, с которой упал игрок.
*/
public EnchantmentSafeFall(String enchantmentName, int enchantmentId, int weight, EnumEnchantmentType enchantmentType) {
super(enchantmentId, weight, enchantmentType);
this.setName(enchantmentName);
}
@Override
public boolean canApplyTogether(Enchantment enchantment) {
return super.canApplyTogether(enchantment) && enchantment != Enchantment.featherFalling;
}
@Override
public int getMinEnchantability(int enchantmentLevel) {
return 10;
}
@Override
public int getMaxEnchantability(int enchantmentLevel) {
return 20;
}
}
Регистрацию чар будем проводить в отдельном классе EnchantmentsRegistry:
Java:
public class EnchanmtmentsRegistry {
public static final Enchantment
SAFE_FALL = new EnchantmentSafeFall("safe_fall", 100, 5, EnumEnchantmentType.armor_feet);//Безопасное Падение
public static void register() {}
}
Задаём имя, id (я начал со 100), вес и допустимую экипировку. При загрузке класса наши чары инициализируются и суперконструктор Enchantment добавит наши чары в общий массив и создаст соответствующую зачарованную книгу. Для зарузки класса я создал пустой метод
register()
, который следует вызвать в процессе преинициализации мода:
Java:
@EventHandler
public void preInit(FMLPreInitializationEvent event) {
EnchanmtmentsRegistry.register();
}
Локализация названия чар:
enchantment.safe_fall=Безопасное Падение
А использования в команде /enchant для зачаровывания предмета у себя в руке:
/enchant (ваш ник) 100(id чар)
Применение эффекта
Для удобства я создал отдельный класс, в котором размещаю удобные статические методы для проверки наличия чар EnchantmentsHelper. Выглядит это так:
Java:
public class EnchantmentsHelper {
/*
* Вспомогательный класс для быстрой проверки наличия определённых чар на экипировке игрока.
*/
public static boolean hasSafeFallEnchantment(EntityPlayer player) {
return EnchantmentHelper.getEnchantmentLevel(EnchanmtmentsRegistry.SAFE_FALL.effectId, player.inventory.armorItemInSlot(0)) > 0;
}
}
По сути происходит запрос на уровень чар с искомым идентификатором на определённом элементе. Если искомых чар нет, то вернётся уровень, равный нулю.
Теперь к эффекту. В данном случае надо отменить урон от падения - для этого есть LivingFallEvent. Поместил я его в отдельный класс (можно и в класс чар) EnchantmentsEvents:
Java:
public class EnchantmentsEvents {
/*
* Эвенты для применения эффектов чар.
*/
//Отмена урона при падении и повреждение ботинок для чар Безопасное Падение (EnchantmentSafeFall).
@SubscribeEvent
public void onPlayerFall(LivingFallEvent event) {
if (event.entityLiving instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer) event.entityLiving;
if (EnchantmentsHelper.hasSafeFallEnchantment(player)) {//Проверка на наличие чар "Безопасного Падения".
player.inventory.armorItemInSlot(0).damageItem((int) event.distance, player);//Дамаг по ботинкам в кол-ве равном расстоянию падения.
event.setCanceled(true);//Отмена эвента (урона).
}
}
}
}
Не забудьте зарегистрировать класс с эвентом:
Java:
@EventHandler
public void init(FMLInitializationEvent event) {
MinecraftForge.EVENT_BUS.register(new EnchantmentsEvents());
}
Вот и всё. Теперь можно и тестировать. В игре возьмите любые ботинки и зачаруйте командой. Если всё получилось - вы получите ботинки с созданными чарами. При падении с надетыми ботинками с этими чарами урон наносится не должен, но прочность ботинок будет снижаться в зависимости от высоты падения.
Книга с чарами будет располагаться во вкладке с бронёй среди остальных. Вы можете наложить эти чары на наковальне. Ну или попытаться получить их на столе зачаровывания. В конце статьи есть послесловие, прочтите его для получения дополнительной информации.
1.12.2
Java:
public class EnchantmentSafeFall extends Enchantment {
public EnchantmentSafeFall(String enchantmentName, Rarity rarity, EnumEnchantmentType type, EntityEquipmentSlot... slots) {
super(rarity, type, slots);
this.setEnchantmentName(enchantmentName);
}
private void setEnchantmentName(String enchantmentName) {
this.setRegistryName(EnchantmentsMain.MODID, enchantmentName);
this.setName(enchantmentName);
}
}
Суперконструктор требует указания редкости чар, класса целевых предметов и элементы экипировки, на которые эти чары можно накладывать.
Рассмотрим первый параметр - редкость, представленная перечислением Rarity. Она бывает четырх разновидностей:
COMMON
, UNCOMMON
, RARE
и VERY_RARE
. От редкости зависит вероятность получить эти чары во время зачаровывания.Второй - класс предметов экипировки, для которых подходят чары, перечисление EnumEnchantmentType. Там много доступных вариантов, например
ALL
- чары могут быть наложены на всё, DIGGER
- только на инструменты, ARMOR
- на броню, WEARABLE
- на всё, что можно надеть на голову и т.д.Массив допустимых для чар предметов экипировки идёт третьим параметром, ознакомьтесь с содержимым перечисления EntityEquipmentSlot.
Все эти параметры будут определены в конструкторе при инициализации. Я добавил строковый параметр для имени чар и метод для его указания.
Далее нужно определиться с какими чарами эти чары могут конфликтовать. По умолчанию все чары конфликтуют сами с собой. Что бы ограничить применение других чар на предмет при наличии конфликтных или наоборот используется метод
Enchantment#canApplyTogether()
:
Java:
@Override
public boolean canApplyTogether(Enchantment enchantment) {
return super.canApplyTogether(enchantment) && enchantment != Enchantments.FEATHER_FALLING;
}
В этом примере я исключил ванильные чары, влияющие на снижение урона от падения.
Если предполагается что чары имеют несколько уровней, то необходимо переопределить
Enchantment#getMinLevel()
и Enchantment#getMaxLevel()
. По умолчанию они возвращают значение, равное единице. Наши чары не будут иметь уровней (будет один по умолчанию) и переопределять эти методы нет необходимости.Что бы задать границы уровней, в которых при зачаровывании можно получить чары нужно переопределить
Enchantment#getMinEnchantability()
и Enchantment#getMaxEnchantability()
:
Java:
@Override
public int getMinEnchantability(int enchantmentLevel) {
return 10;
}
@Override
public int getMaxEnchantability(int enchantmentLevel) {
return 20;
}
Так как уровень у чар только один, можно не заморачиваться хитрыми расчётами.
В итоге класс целиком:
Java:
public class EnchantmentSafeFall extends Enchantment {
/*
* Падение не наносит урона. Эффект применяется с помощью эвента в EnchantmentsEvents.
*
*
* Кол-во уровней чар: 1
*
* Уровни опыта для зачаровывания: 10 - 20
*
* Несовместимости: Невесомость, Покоритель глубин и Ледяная Поступь.
*
* Целевые предметы: Любые ботинки.
*
* Эффект: Полное исключение урона при падении, но ботинки получают урон равный высоте, с которой упал игрок.
*/
public EnchantmentSafeFall(String enchantmentName, Rarity rarity, EnumEnchantmentType type, EntityEquipmentSlot... slots) {
super(rarity, type, slots);
this.setEnchantmentName(enchantmentName);
}
private void setEnchantmentName(String enchantmentName) {
this.setRegistryName(EnchantmentsMain.MODID, enchantmentName);
this.setName(enchantmentName);
}
@Override
public boolean canApplyTogether(Enchantment enchantment) {
return super.canApplyTogether(enchantment) && enchantment != Enchantments.FEATHER_FALLING;
}
@Override
public int getMinEnchantability(int enchantmentLevel) {
return 10;
}
@Override
public int getMaxEnchantability(int enchantmentLevel) {
return 20;
}
}
Регистрацию чар будем проводить в отдельном классе EnchantmentsRegistry:
Java:
@Mod.EventBusSubscriber(modid = EnchantmentsMain.MODID)
public class EnchantmentsRegistry {
public static final Enchantment
SAFE_FALL = new EnchantmentSafeFall("safe_fall", Rarity.RARE, EnumEnchantmentType.ARMOR_FEET, new EntityEquipmentSlot[] {EntityEquipmentSlot.FEET});
@SubscribeEvent
public static void registerEnchantments(RegistryEvent.Register<Enchantment> event) {
event.getRegistry().registerAll(
SAFE_FALL
);
}
}
Задаём имя, редкость, допустимые элементы экипировки и регистрируем через эвент RegistryEvent.Register. Для автоматической подгрузки эвентов ставим аннотацию
@Mod.EventBusSubscriber(modid = Main.MODID)
, а метод определяем статическим.Локализация названия чар:
enchantment.safe_fall=Безопасное Падение
А использования в команде /enchant для зачаровывания предмета у себя в руке:
/enchant @s (ваш modid):safe_fall
Применение эффекта
Для удобства я создал отдельный класс, в котором размещаю удобные статические методы для проверки наличия чар EnchantmentsHelper. Выглядит это так:
Java:
public class EnchantmentsHelper {
/*
* Вспомогательный класс для быстрой проверки наличия определённых чар на экипировке игрока.
*/
public static boolean hasSafeFallEnchantment(EntityPlayer player) {
return EnchantmentHelper.getEnchantmentLevel(EnchantmentsRegistry.SAFE_FALL, player.inventory.armorItemInSlot(0)) > 0;
}
}
По сути происходит запрос на уровень искомых чар на определённом элементе. Если искомых чар нет, то вернётся уровень, равный нулю.
Теперь к эффекту. В данном случае надо отменить урон от падения - для этого есть LivingFallEvent. Поместил я его в отдельный класс (можно и в класс чар) EnchantmentsEvents:
Java:
@Mod.EventBusSubscriber(modid = EnchantmentsMain.MODID)
public class EnchantmentsEvents {
/*
* Эвенты для применения эффектов чар.
*/
//Отмена урона при падении и повреждение ботинок для чар Безопасное Падение (EnchantmentSafeFall).
@SubscribeEvent
public static void onPlayerFall(LivingFallEvent event) {
if (event.getEntityLiving() instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer) event.getEntityLiving();
if (EnchantmentsHelper.hasSafeFallEnchantment(player)) {//Проверка на наличие чар "Безопасного Падения".
player.inventory.armorItemInSlot(0).damageItem((int) event.getDistance(), player);//Дамаг по ботинкам в кол-ве равном расстоянию падения.
event.setCanceled(true);//Отмена эвента (и урона).
}
}
}
}
Вот и всё. Теперь можно и тестировать. В игре возьмите любые ботинки и зачаруйте командой. Если всё получилось - вы получите ботинки с созданными чарами. При падении с надетыми ботинками с этими чарами урон наносится не должен, но прочность ботинок будет снижаться в зависимости от высоты падения.
Книга с чарами будет располагаться во вкладке с бронёй среди остальных. Вы можете наложить эти чары на наковальне. Ну или попытаться получить их на столе зачаровывания.
Послесловие
Вот как то так это и происходит. Если вам нужно больше информации, то ознакомьтесь с другими примерами в моём репозитории: 1.7.10, 1.12.2. Кроме этих там есть чары переплавки, которые накладываются только на кастомные инструменты и делают интересные вещи, а также чары для кастомного меча, аналогичные "Остроте" с демонстрацией ванильной системы применения чар без эвентов.
Всем спасибо за внимание. Если вам есть что добавить или какие либо вопросы - пишите в обсуждении.