IExtendedEntityProperties или "Как создать ману" [Часть 1]

IExtendedEntityProperties или "Как создать ману" [Часть 1]

В этом уроке я расскажу о том, как добавлять переменные к объекту с помощью Forge IExtendEntityProperties.
Что вам потребуется:
- Прямые руки
- Знание комбинаций Ctrl + C и Ctrl + V
- ПК со средой разработки и установленными компонентами для моддинга (y)
- Знать, как настраивать и использовать Forge Events
- Готовность внимательно прочитать

Преступим..
Шаг 1. Создайте класс, который реализует IExtendedEntityProperties
Т.к. мы создаем переменную для ИГРОКА, т.е. EntityPlayer, то назовем класс ExtendedPlayer
Java:
public class ExtendedPlayer implements IExtendedEntityProperties
{
    /*
   Тут мы создаем константу EXT_PROP_NAME для этого класса.
   ВНИМАНИЕ! Для каждого IExtendedEntityProperties нужна своя уникальная константа!
   Вы делаете это ив верхней части каждого класса, поскольку константа позволяет
очень легко организовать и избежать опечаток.

     Обратите внимание, что один объект может иметь несколько расширенных свойств, поэтому каждое
свойство должно иметь уникальное имя. Попытайтесь придумать что-то еще
     уникальным, чем пример тут.
    */
    public final static String EXT_PROP_NAME = "ExtendedPlayer";
/*
Создадим пустую переменную игрока, в которую будем как раз и задавать его,
*/
        private final EntityPlayer player;
/*
Также добавим пустой метод инита, пустой т.к. пока он нам не пригодится, а нужен т.к. мы используем интерфейс.
*/
        @Override
        public void init(Entity entity, World world) {        
        }
/*
Объявим переменные, которые нам нужны еще.
Мы делаем ману, поэтому нам нужна "Текущая мана" (currentMana) и "Максимальная мана" (maxMana)
*/
    private int currentMana, maxMana;

    /*
    По умолчанию конструктор не принимает аргументы, но я вставлю Entity, что бы
    инициализировать вышеупомянутую переменную 'player'
    */
    public ExtendedPlayer(EntityPlayer player)
    {
        this.player = player;
        /*
        Задаем максимальное кол-во маны.
        Так же мы задаем его "Начальным", что бы при первом появлении маны у игрока
        сразу был "Максимум"
        */
        this.currentMana = this.maxMana = 50;
    }

    /**
     Используется для регистрации этих полей для игрока во время события
     EntityConstructing.
     Используется ради удобства.
     */
    public static final void register(EntityPlayer player)
    {
        player.registerExtendedProperties(ExtendedPlayer.EXT_PROP_NAME, new ExtendedPlayer(player));
    }

    /*
     Возвращает свойства ExtendedPlayer для игрока.
     Используется ради удобства.
     */
    public static final ExtendedPlayer get(EntityPlayer player)
    {
        return (ExtendedPlayer) player.getExtendedProperties(EXT_PROP_NAME);
    }

    // Сохранение данных в NBT, для сохранения переменных.
    @Override
    public void saveNBTData(NBTTagCompound compound)
    {
        // Создаем новый состав тегов
        NBTTagCompound properties = new NBTTagCompound();

        // Нам нужно 2 тега. Используемая и Максимальная мана.
        properties.setInteger("CurrentMana", this.currentMana);
        properties.setInteger("MaxMana", this.maxMana);

        // Добавляем наш тег в тег Имени игрока.
       //Что бы при использовании маны у 1 игрока, она не использовалась у всех игроков на сервере.
         compound.setTag(EXT_PROP_NAME, properties);

    }

   // Загружаем сохраненные данные
    @Override
    public void loadNBTData(NBTTagCompound compound)
    {
      // Здесь мы получаем уникальное соединение тегов, которое мы установили для этого класса
        NBTTagCompound properties = (NBTTagCompound) compound.getTag(EXT_PROP_NAME);
       // Получите наши данные из нашего тега
        this.currentMana = properties.getInteger("CurrentMana");
        this.maxMana = properties.getInteger("MaxMana");
        // Что бы узнать, что это работает, мы сделаем вывод в консоль:
        System.out.println("[TUT PROPS] Mana from NBT: " + this.currentMana + "/" + this.maxMana);
    }

    /*
   Делаем геттер и ссетер.
  Для потребления/пополнения маны.
     */

    /**
     Возвращает true, если количество маны было потреблено или false
     если текущая маны игрока недостаточна
     */
    public boolean consumeMana(int amount)
    {
        // У игрока достаточно маны?
        boolean sufficient = amount <= this.currentMana;
        // Потребляется в любом случае; Если необходимой маны меньше, чем есть у игрока,
        // то мана сбрасывается на "0".
        this.currentMana -= (amount < this.currentMana ? amount : this.currentMana);
        //Если у игрока достаточно маны:
        return sufficient;
    }

    /**
     * Метод, "сбрасывающий" до максимума нашу ману.
     */
    public void replenishMana()
    {
        this.currentMana = this.maxMana;
    }
}

Шаг 2. Регистрируем ExtendedPlayer в вашем EventHandler
Java:
/ *
Чтобы получить доступ к нашим вновь созданным расширенным свойствам игрока, нам нужно
зарегистрируйте их для каждого экземпляра EntityPlayer. Это просто означает, что мы
создавая новый экземпляр класса, чтобы мы могли получить к нему доступ.
Регистрация IExtendedEntityProperties выполняется в событии EntityConstructing.
*/
public class TutEventHandler{
// Для 1.6.4: @ForgeSubscribe
@SubscribeEventpublic
void onEntityConstructing(EntityConstructing event){
/* Обязательно проверьте, является ли создаваемый объект правильным типом для
расширенных свойств, которые вы собираетесь добавить! Нулевая проверка может быть не нужна*/
if (event.entity instanceof EntityPlayer && ExtendedPlayer.get((EntityPlayer) event.entity) == null)
// Таким образом, расширенные свойства регистрируются с использованием нашего удобного метода
earlierExtendedPlayer.register((EntityPlayer) event.entity);
// Это вызовет конструктор, а также вызовет метод init ()
// для автоматического вызова
// Если вы не сделали два удобных метода раньше, ваш код будет
// намного уродливее:
if (event.entity instanceof EntityPlayer && event.entity.getExtendedProperties(ExtendedPlayer.EXT_PROP_NAME) == null)
event.entity.registerExtendedProperties(ExtendedPlayer.EXT_PROP_NAME, new ExtendedPlayer((EntityPlayer) event.entity));
}
}

В основном - все сделано. Теперь мы создадим предмет, который будет использовать эту ману.
Шаг 3. Создание предмета для использования маны.
Java:
public class ItemUseMana extends Item
{
    public ItemUseMana() {
        super();
    }

    @Override
    public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer player)
        {
        if (!world.isRemote)
        {
            /*
            Что бы код не был длинным, мы создадим локальную переменную
             */
            ExtendedPlayer props = ExtendedPlayer.get(player);
    
             /* Здесь мы будем использовать метод, который мы сделали, чтобы увидеть,
имеет ли игрок достаточно маны, чтобы что-то сделать мы будем печатать что-то на консоль
для отладки.
ВНИМАНИЕ!!! Тут Выполняются все действия, которые вы хотите сделать предметом, "Если у вас достаточно маны". Я же тут ТОЛЬКО вывожу в консоль, мол, "Да, у него достаточно маны" и снимаем 15 маны за использования :D
             */
            if (props.consumeMana(15))
            {
                System.out.println("[Мана Пульятель] Да, маны достаточно!");
            }
/*
Если маны недостоаточно, то мы пишем в консоль "НетУ маны, сорян" и откатываем ее до максимума.
*/
            else
            {
                System.out.println("[Мана Пульятель] Маны не достаточно.");
                props.replenishMana();
            }
        }

        return itemstack;
    }
НО! Внимание, если вы не зарегистрировали свой EventHandler, то у вас будет карш!
Поэтому мы зарегистрируем его в нашем главном классе!
Java:
@EventHandler
public void load(FMLInitializationEvent event)
{
    MinecraftForge.EVENT_BUS.register(new TutEventHandler());
}
Кхм, вроде все готово. Но давайте придадим мане хоть какую-то значимость.
Давайте сделаем что-то на подобии "Заклинания", которое будет предотвращать урон при падении с высоты, которой захотим. :з
Шаг 3.1 Заклинание "АтиПадалка"
Java:
// В класс [B]TutEventHandler[/B]
@SubscribeEvent
public void onLivingFallEvent(LivingFallEvent event)
{
    // Мы добавили это только для Игрока, поэтому проверяем "Игрок ли это"
    if (event.entity instanceof EntityPlayer)
    {
        ExtendedPlayer props = ExtendedPlayer.get((EntityPlayer) event.entity);

        // Делаем так, что бы мана и игрока только кончалась, для предотвращения падения.
        if (event.distance > 3.0F && props.getCurrentMana() > 0)
        {
            // Выводим некоторые данные в консоль, что бы наглядно видеть работу
            System.out.println("[EVENT] Fall distance: " + event.distance);
            System.out.println("[EVENT] Current mana: " + props.getCurrentMana());
            // Нам нужно сделать локальную переменную для хранения суммы,
            //чтобы уменьшить расстояние и ману
            float reduceby = props.getCurrentMana() < (event.distance - 3.0F) ? props.getCurrentMana() : (event.distance - 3.0F);
            event.distance -= reduceby;
            // "Сдвигаем" наш параметр до "int", что бы соответствовать конструктору.
            props.consumeMana((int) reduceby);
           // Ну и наша любимая проверка
            System.out.println("[EVENT] Adjusted fall distance: " + event.distance);
        }
    }
}
(Шаг 1.3.2 Создание ГУИ, для отображения кол-ва маны на дисплее - в разработке. Постараюсь добавить на днях)
Результат выполнения наших действий (Включая шаг 1.3.2)
2017-12-03_14.23.01.png

====
Гайд буду дописывать и включать новые "Плюшки",
Если вы захотите.
Если Вас устроил данный Туториал, то поставьте (y). Это мотивирует меня и дает знать, что гайд нужен и его нужно доделывать)
====

Гайд написан на основе дополнительного источника.
Автор
Tenebrius
Просмотры
2,986
Первый выпуск
Обновление
Оценка
4.08 звёзд 12 оценок

Последние рецензии

1.7.10 хоть и вышла из "моды", но гайд пригодился, спасибо. Вторую часть, так понимаю, не дождусь?)
earlierExtendedPlayer.register((EntityPlayer) event.entity);

Думаю что то тут не так?)
Сделай вывод маны на экран в цифрах
Туториал хороший, но в нем очень много недоработок. За то, что туториал на 1.7.10 +
Tenebrius
Tenebrius
Туториал не на 1.7.10+, а на 1.6.4-1.7.10.
"недоработки" я как всегда не узнаю....
Сначала понравилось теперь заметил много косяков и+ не рассказал про синхронизацию, тройка только за пояснения к всё таки рассказаному материалу, и совершенно неупоминул про метод init который необходимо реализовать ибо он абстрактный.
Таких туториалов много. Хоть и нерусских...
Tenebrius
Tenebrius
Ноунеймов много. Хоть и не с ником WhiteWarrior
Полезная тема, очень помог!
Неплохой перевод, но опечаток куча, так что я лучше почитаю оригинал... да и насчёт передачи клиент <-> сервер ни слова. Так что троечка
(github.com/coolAlias/Forge_Tutorials/blob/master/IExtendedEntityPropertiesTutorial.java)
Tenebrius
Tenebrius
Согласен. Но по синхронизацию умолчал, т.к. хочется для начала самому хорошо разобраться, что бы дать комментарий чуть ли не к каждой строке кода)
А что, просто капа на 1.7.10 уже не очень ? Или ее там нормально не сделать?
Tenebrius
Tenebrius
"просто капа"?
Сверху