- 15
- 0
Недавно задался целью улучшить работу невидимости. Знаем, что когда игрок невидим - враждебные мобы по прежнему видят игрока и бегут его атаковать.
Чтобы это исправить, можно было бы обойтись и простым событием LivingSetAttackTargetEvent, но к сожалению, это событие действует лишь на мобов с AI, да и то, вроде не на всех. В гугле не нашел стоящей информации, поэтому пришлось познакомиться с рефлексией. И о чудо - у меня получилось написать код, который действует на всех ванильных мобов и даже на мобов из модов (за всех не ручаюсь). Посему, делюсь им ниже (версия 1.7.10):
Результат:
Чтобы это исправить, можно было бы обойтись и простым событием 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;
}
Результат: