Войти или зарегистрироваться

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

MrTrojan

Активный участник
Пользователь
Баллы
98
Имя в Minecraft
BlackTrojan
Сабж в названии собственно.
 
Ну можно, посадить его на игрока ;) Правда тогда не моб будет передвигаться, а игрок его тащить.
А можно каждый тик синхронизировать движения.
 
Ну можно, посадить его на игрока ;) Правда тогда не моб будет передвигаться, а игрок его тащить.
А можно каждый тик синхронизировать движения.
Ну с посадкой на игрока вариант сразу не подходит.

Вот только как?
 
Ну с посадкой на игрока вариант сразу не подходит.

Вот только как?
А можно каждый тик синхронизировать движения.
Как я понял, добавлять к вектору моба значения таким образом направляя в сторону игрока или что то вроде того.
 
Как я понял, добавлять к вектору моба значения таким образом направляя в сторону игрока или что то вроде того.
Если каждый тик - то можно его просто телепортировать.

Что в итоге нужно получить?
 
К сожалению с английским дело обстоят плохо.

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

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

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

    @Override
    public void c(){
        //Выполняем перемещение
    }
}

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


Java:
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.

Java:
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.

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

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

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

    @Override
    public void c(){
        //Выполняем перемещение
    }
}

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


Java:
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.

Java:
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.

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

Ловим событие передвижения игрока:
Java:
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
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 но это будет дольше и стоит ли. Еще можно сделать без рефлексий, но с привязкой к определенным версиям. Если интересуют какие-то из этих вариантов, напишу подробнее.
P.S. К сожалению вариант @aceJKE привязан к определенной версии майна, что вызовет некоторые трудности при переходе на новые версии.
 
Последнее редактирование:
Назад
Верх