Making a Villager follow you

Discussion in 'Spigot Plugin Development' started by TheDiamondWorm, Jun 4, 2015.

  1. I have been trying to find a simple way to make peaceful mobs (such as villagers) follow a player. But, every method I have found so far is faulty. Either the NMS is outdated and is incompatible with 1.8, the method just no longer works, or the mob will follow you, but when you change worlds/teleport long distances, errors will be thrown and the mob will not be taken with you.

    This is the only method that works:

    Code (Java):
        public void petFollow(final Player player, final Entity pet,
                final double speed) {
            new BukkitRunnable() {
                public void run() {
                    if ((!pet.isValid() || (!player.isOnline()))) {
                        this.cancel();
                    }
                    net.minecraft.server.v1_8_R1.Entity pett = ((CraftEntity) pet)
                            .getHandle();
                    ((EntityInsentient) pett).getNavigation().a(2);
                    Object petf = ((CraftEntity) pet).getHandle();
                    Location targetLocation = player.getLocation();
                    PathEntity path;
                    path = ((EntityInsentient) petf).getNavigation().a(
                            targetLocation.getX() + 1, targetLocation.getY(),
                            targetLocation.getZ() + 1);
                    if (path != null) {
                        ((EntityInsentient) petf).getNavigation().a(path, 1.0D);
                        ((EntityInsentient) petf).getNavigation().a(2.0D);
                    }
                    int distance = (int) Bukkit.getPlayer(player.getName())
                            .getLocation().distance(pet.getLocation());
                    if (distance > 10 && !pet.isDead() && player.isOnGround()) {
                        pet.teleport(player.getLocation());
                    }
                    AttributeInstance attributes = ((EntityInsentient) ((CraftEntity) pet)
                            .getHandle()).getAttributeInstance(GenericAttributes.d);
                    attributes.setValue(speed);
                }
            }.runTaskTimer(this, 0L, 20L);
        }
    But, this isn't compatible with world changes/long-distance teleportations.

    Does anyone know of other methods to do this?
     
  2. Use PlayerChangedWorldEvent (or similar to that, I don't remember the exact name) and/or PlayerTeleportEvent (maybe EntityTeleportEvent) and teleport the Entity next to the Player.
     
    • Like Like x 1
  3. Code (Text):
    if (distance > 10 && !pet.isDead() && player.isOnGround()) {
                        pet.teleport(player.getLocation());
                    }
    Why don't you just add
    OR pet world != player world?
     
    • Like Like x 1
  4. Thanks guys. So, the world problem now fixed.

    Teleportation seems to work for for short distances such as 50-100 blocks, but if I am at 1000, 5, 1000 and teleport to 3000, 5, 3000, the pet will not be taken with me.

    I can use this method, but is this really a good way of doing it? I feel as though checking for their pet in a radius may not be the best way..

    Code (Java):
    @EventHandler
    public void teleportWithPet(PlayerTeleportEvent e) {
    Player p = e.getPlayer();
            for (Entity ent : p.getNearbyEntities(50, 50, 50)) {
                if (ent instanceof Villager) {
                    if (ent.getCustomName().equalsIgnoreCase(
                            ChatColor.translateAlternateColorCodes(
                                    '&',
                                    getConfig().getString("nameTag").replace(
                                            "%player%", p.getName())))) {
    ent.teleport(p.getLocation());
    }
    }}
     
  5. It's propably because the pet will propably be unloaded. I don't know if this can happen when you have it in a variable though.
    In this case it would actually be better to do it on the PlayerTeleportEvent
     
  6. Yup, check the code I just edited into my post, I was wondering if that's the best approach to take.
     
  7. Why don't you just link the villager to the player? Like in a hashmap or something.
    It would clean up your code sooo much.
     

  8. Great idea, I am now storing the name of the player in the config with the pets UUID:
    Code (Text):
    The_Diamond_Worm: 34d0a90a-c8bc-421a-a664-ab1048877050
     
    (Player name because this storage is pretty short term, and I am storing in the config to try to keep pet info over reloads/restarts).

    But, another problem I have now is upon plugin reload, server reload, or server restart, the pet stops following the player.
     
    #8 TheDiamondWorm, Jun 4, 2015
    Last edited: Jun 4, 2015
  9. Yeah, you have to despawn it on player leave and respawn it on player join. Btw. as I learned recently its best to despawn the pet on player teleport and respawn it near the player one tick after the teleport. Else it can happen that the pet will be invisible (=unloaded).
     
    • Useful Useful x 1
  10. How can I load/unload the same pet without killing the old one and just spawning a new one?