Хостинг серверов Minecraft playvds.com
  1. Вы находитесь в русском сообществе Bukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на русский язык плагины наших собратьев из других стран.
    Скрыть объявление

Помогите Как сделать, чтобы моб передвигался вместе с игроком?

Тема в разделе "Разработка плагинов для новичков", создана пользователем MrTrojan, 10 янв 2016.

  1. Автор темы
    MrTrojan

    MrTrojan Активный участник Пользователь

    Баллы:
    98
    Skype:
    mrtrojan.ru
    Имя в Minecraft:
    MrTrojan
    Сабж в названии собственно.
     
  2. Хостинг MineCraft
    <
  3. Автор темы
    MrTrojan

    MrTrojan Активный участник Пользователь

    Баллы:
    98
    Skype:
    mrtrojan.ru
    Имя в Minecraft:
    MrTrojan
    Ну с посадкой на игрока вариант сразу не подходит.

    Вот только как?
     
  4. Shockwave

    Shockwave Старожил Пользователь

    Баллы:
    103
    Как я понял, добавлять к вектору моба значения таким образом направляя в сторону игрока или что то вроде того.
     
  5. aceJKE

    aceJKE Старожил Пользователь

    Баллы:
    123
  6. Автор темы
    MrTrojan

    MrTrojan Активный участник Пользователь

    Баллы:
    98
    Skype:
    mrtrojan.ru
    Имя в Minecraft:
    MrTrojan
    К сожалению с английским дело обстоят плохо.
     
  7. aceJKE

    aceJKE Старожил Пользователь

    Баллы:
    123
    По просьбе многих людей, вот пример кода, который позволяет контролировать перемещение LivingEntity к tile(По-моему tile это те энтити, которые обновляются каждый тик). Я настоятельно рекомендую вам сперва прочитать урок сделанный Jacek что бы знать как создать обычное существо. ПОСЛЕ прочтения того урока и его усвоения, конкретно - понимание того как происходит наследование существ, вы можете продолжить читать этот урок.

    Во-первых нам нужно создать PathfinderGoal, которые будет указывать на конкретную tile. Мы не будем писть всю реализацию PathfinderGoal, а переопределим только те методы, которые отвечают за навигацию существа. Глядя на PathfinderGoalRandomStroll.java (это простейший "искатель путей", что я нашел) вы можете наблюдать метод a(), который используется для валидации пути и c() для реализации перемещения. После просмотра этого кода мы можем создать нашу собственную цель перемещения, переопределив PathfinderGoal. Я назвал свой переопредленный класс PathfinderGoalWalktoTile и перекрыл в нем два важнейших метода (a и c).

    Код:
    public class PathfinderGoalWalktoTile extends PathfinderGoal {
        @Override
        public boolean a() {
            //Выполняем валидацию
        }
    
        @Override
        public void c(){
            //Выполняем перемещение
        }
    }

    Теперь я собираюсь скопировать большую часть кода из другого Pathfinder'а (искателя пути/цели) и настрить его в соответствии со своими потребностями, добавив конструктор и переименованием нескольких переменных.


    Код:
    public class PathfinderGoalWalktoTile extends PathfinderGoal {
    
        float speed;
        private EntityCreature entitycreature;
     
        public PathfinderGoalWalktoTile(EntityCreature entitycreature, float speed) {
            this.speed = speed;
            this.entitycreature = entitycreature;
        }
    
        @Override
        public boolean a() {
            if (this.entitycreature.aI() >= 100) {
                return false;
            } else if (<shoudwalk?>) {
                return true;
            } else {
                return false;
            }
        }
    
        @Override
        public void c(){
            this.entitycreature.getNavigation().a(x, y, z, speed);
        }
    }
    Переменные x, y и z можно заменить на нужные вам цифры или брать текущие координаты из другого класса.

    Теперь у нас есть PathfinderGoal и мы можем добавить ему цель используя рефлексию. Вы должны будете получить первоначальные PathfinderGoal существа из NMS (net.minecraft.server) кода, которые вы можете найти здесь. Я использовал PathfinderGoal зомби, из урока Jacek.

    Код:
    public class BloodMoonEntityZombie extends net.minecraft.server.EntityZombie {
    
        public BloodMoonEntityZombie(World world) {
            super(world);
            try {
                Field gsa = net.minecraft.server.v1_5_R2.PathfinderGoalSelector.class.getDeclaredField("a");
                gsa.setAccessible(true);
                gsa.set(this.goalSelector, new UnsafeList());
                gsa.set(this.targetSelector, new UnsafeList());
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
    
            this.goalSelector.a(0, new PathfinderGoalFloat(this));
            this.goalSelector.a(1, new PathfinderGoalBreakDoor(this));
            this.goalSelector.a(1, new PathfinderGoalWalktoTile(this, (float) this.bw));//this.bw можно заменить на свою скорость
            this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, EntityHuman.class, this.bI, false));
            this.goalSelector.a(3, new PathfinderGoalMeleeAttack(this, EntityVillager.class, this.bI, true));
            this.goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, this.bI));
            this.goalSelector.a(5, new PathfinderGoalMoveThroughVillage(this, this.bI, false));
            this.goalSelector.a(6, new PathfinderGoalRandomStroll(this, this.bI));
            this.goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F));
            this.goalSelector.a(7, new PathfinderGoalRandomLookaround(this));
            this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, true));
            this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityHuman.class, 16.0F, 0, true));
            this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityVillager.class, 16.0F, 0, false));
        }
    }

    Если вы хотите удалить такую черту зомби, как ломание дверей, то вы можете просто удалить эту строку из кода. Я надеюсь, что помог вам. Если вы обнаружите какие-либо ошибки в том коде, не стесняйтесь исправлять их. Я еще только осваиваю NMS.

    Немного криво, но зато бесплатно.
     
    Последнее редактирование: 11 янв 2016
  8. Автор темы
    MrTrojan

    MrTrojan Активный участник Пользователь

    Баллы:
    98
    Skype:
    mrtrojan.ru
    Имя в Minecraft:
    MrTrojan
    Ну что ж спасибо огромное :)
     
  9. OsipXD

    OsipXD Старожил Пользователь

    Баллы:
    173
    Skype:
    osip.fatkullin
    Имя в Minecraft:
    OsipXD
    Нужно чтобы моб преследовал игрока или копировал его движения?
     
  10. Автор темы
    MrTrojan

    MrTrojan Активный участник Пользователь

    Баллы:
    98
    Skype:
    mrtrojan.ru
    Имя в Minecraft:
    MrTrojan
    Ну есть игрок и моб, игрок передвигается и моб должен пойти за ним же, как питомец.
     
  11. OsipXD

    OsipXD Старожил Пользователь

    Баллы:
    173
    Skype:
    osip.fatkullin
    Имя в Minecraft:
    OsipXD
    Тогда проще сделать просто чтобы у моба как цель задавался игрок. То есть алгоритм такой: игрок передвигается, у моба задается его новое местоположение как цель.
    Но т.к. Creature#setTarget(org.bukkit.entity.LivingEntity) у меня просто не работал, я сделал так:

    Ловим событие передвижения игрока:
    Код:
    public void onPlayerMove(PlayerMoveEvent event) {
        Player player = event.getPlayer();
    
        if (/* Необходимые вам проверки */) {
            LivingEntity pet = /* Получаем питомца */;
            // Я делал это так: (InventoryWrapper и InventoryManager - мои классы)
            //InventoryWrapper inventoryWrapper = InventoryManager.get(player);
            //LivingEntity pet = inventoryWrapper.getPet();
    
            EntityUtils.goToPlayer(player, pet);
        }
    }
    EntityUtils.java
    Код:
    public static void goToPlayer(final Player player, final LivingEntity entity) {
        // Всякие проверки
        if (!player.isOnline() || entity.isDead()) {
            return;
        }
    
        Location target = player.getLocation();
        if (target.distance(entity.getLocation()) > 20) {
            // Тут телепортируем Entity к игроку, т.к. пет слишком далеко, чтобы следовать за ним
            entity.teleport(target);
            // или entity.teleport(target, PlayerTeleportEvent.TeleportCause.PLUGIN);
            return;
        }
    
        Class<?> entityInsentientClass = MinecraftReflection.getMinecraftClass("EntityInsentient");
        Class<?> navigationAbstractClass = MinecraftReflection.getMinecraftClass("NavigationAbstract");
    
        try {
            Object insentient  = entityInsentientClass.cast(MinecraftReflection.getCraftEntityClass().getDeclaredMethod("getHandle").invoke(entity));
            Object navigation = entityInsentientClass.getDeclaredMethod("getNavigation").invoke(insentient);
            navigationAbstractClass.getDeclaredMethod("a", double.class, double.class, double.class, double.class)
                        .invoke(navigation, target.getX(), target.getY(), target.getZ(), 1.75D);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
    Стоит отметить, что MinecraftReflection это класс из ProtocolLib. Можно конечно сделать просто на рефлексиях без зависимости от ProtocolLib но это будет дольше и стоит ли. Еще можно сделать без рефлексий, но с привязкой к определенным версиям. Если интересуют какие-то из этих вариантов, напишу подробнее.[DOUBLEPOST=1453116851,1453112902][/DOUBLEPOST]P.S. К сожалению вариант @aceJKE привязан к определенной версии майна, что вызовет некоторые трудности при переходе на новые версии.
     
    Последнее редактирование: 18 янв 2016

Поделиться этой страницей