Игрок невидим - мобы не трогают

15
0
Недавно задался целью улучшить работу невидимости. Знаем, что когда игрок невидим - враждебные мобы по прежнему видят игрока и бегут его атаковать.

Чтобы это исправить, можно было бы обойтись и простым событием LivingSetAttackTargetEvent, но к сожалению, это событие действует лишь на мобов с AI, да и то, вроде не на всех. В гугле не нашел стоящей информации, поэтому пришлось познакомиться с рефлексией. И о чудо - у меня получилось написать код, который действует на всех ванильных мобов и даже на мобов из модов (за всех не ручаюсь). Посему, делюсь им ниже (версия 1.7.10):

Java:
// LivingSetAttackTargetEvent - Невидим для мобов с AI...
@SubscribeEvent
public void onLivingSetAttackTargetEvent(LivingSetAttackTargetEvent event)
{
    if( event.target instanceof EntityLivingBase )
    {
        // Если цель под действием зелья невидимости
        if( event.target.isPotionActive(Potion.invisibility) )
        {
            // Очищаем цель, метод 1
            event.entityLiving.setRevengeTarget(null);

            if( event.entityLiving instanceof EntityLiving )
            {
                // Очищаем цель, метод 2
                ((EntityLiving) event.entityLiving).setAttackTarget(null);
            }

            // ... лишние методы лишними не бывают...
        }
    }
}

// resetAttackingTarget - Ощищаем цель для атаки у всех остальных мобов, исполняется каждый раз, когда моб обновляется
@SubscribeEvent
public void resetAttackingTarget(LivingUpdateEvent event)
{
    // Очищаем attackTarget у мобов, наследующих EntityLiving
    resetAttackingTargetByReflection(event.entityLiving, "attackTarget", EntityLiving.class);

    // Очищаем entityToAttack у мобов, наследующих EntityCreature
    resetAttackingTargetByReflection(event.entityLiving, "entityToAttack", EntityCreature.class);

    // Очищаем entityLivingToAttack у мобов, наследующих EntityLivingBase
    resetAttackingTargetByReflection(event.entityLiving, "entityLivingToAttack", EntityLivingBase.class);
}

// resetAttackingTargetByReflection - привет, Рефлексия
private static boolean resetAttackingTargetByReflection(EntityLivingBase entityLiving, String fieldName, Class<?> searchInClass)
{
    try
    {
        // Ищем у моба необходимый класс
        Class<?> entityLivingClass = entityLiving.getClass();
        while( entityLivingClass != searchInClass )
        {
            entityLivingClass = entityLivingClass.getSuperclass();

            if( entityLivingClass == Entity.class || entityLivingClass == Object.class || entityLivingClass == null )
            {
                entityLivingClass = null;
                break;
            }
        }

        if( entityLivingClass != null ) // Нашли
        {
            // Ищем переменную, где хранится цель для атаки (эти переменные имеют private)
            Field field = entityLivingClass.getDeclaredField(fieldName);

            if( field != null )
            {
                // Разрешаем изменение переменной
                field.setAccessible(true);

                // Получаем цель атаки
                Object attackedEntity = field.get( entityLiving );

                // И проверяем её на существование
                if( attackedEntity instanceof EntityLivingBase )
                {
                    // Если цель под действием зелья невидимости
                    if( ((EntityLivingBase) attackedEntity).isPotionActive(Potion.invisibility) )
                    {
                        // Очищаем цель
                        field.set(entityLiving, null);
                        return true;
                    }
                }
            }
        }
    }
    // Конечный код не вызывал никаких ошибок, но на всякий пожарный...
    catch (Exception e) { System.out.println(e); }

    return false;
}

Результат:
2017-11-28_23.54.19.png
 

CumingSoon

Местный стендапер
1,634
12
269
Поаккуратнее с рефлексией, значения лучше кэшировать, чтобы не дергать очень часто. А рефлексия медленная
 

CMTV

Основатель
Администратор
1,304
4
601
Игрок невидимый, а ифрит вместе с пауком как-то недобро поглядывают на него... Тогда уж надо и lookAt (или как это там называется) блочить :)
 
Последнее редактирование:
лол, мое достижение добавили
эмм... Мне всегда казалось, что мобы невидимого игрока не атакуют...
 
  • Like
Реакции: CMTV

CMTV

Основатель
Администратор
1,304
4
601
В 1.12+ не атакуют. Возможно, в 1.7.10 атакуют...
 
Спасибо... Но как я получил уведомление от этого сообщения?
 

CMTV

Основатель
Администратор
1,304
4
601
Если ты ответил в теме, то ты автоматически на нее подписываешься. Отписаться можно с помощью кнопки "Прекратить отслеживание" справа сверху.
 
Жаль, что у меня такой кнопки нет, но оно само как-то прекратило отслеживание(y)
 
Последнее редактирование:
Сверху