NPE with getNavigation in EntityInsentient (NMS)

Discussion in 'Spigot Plugin Development' started by jedk1, May 14, 2016.

  1. Hey, so recently I've been playing around with NMS to set an entity on a path to walk to a location, using whats in this thread: https://www.spigotmc.org/threads/entity-walk-to-location.78916/

    This is the code I've got using ReflectionUtils by DarkBlade on bukkit forums:
    Code (Text):
    package com.jedk1.horses.util;

    import java.lang.reflect.Method;

    import org.bukkit.Location;
    import org.bukkit.entity.LivingEntity;
    import org.bukkit.scheduler.BukkitRunnable;

    import com.jedk1.horses.Horses;
    import com.jedk1.horses.util.ReflectionUtils.PackageType;

    public class PathUtil {
     
        private static boolean initialised = false;
        private static Method getHandle;
        private static Method getNavigation;
        private static Method getPath;
        private static Method setPath;
     
        static {
            try {
                getHandle = ReflectionUtils.getMethod("CraftLivingEntity", PackageType.CRAFTBUKKIT_ENTITY, "getHandle");
                getNavigation = ReflectionUtils.getMethod("EntityInsentient", PackageType.MINECRAFT_SERVER, "getNavigation");
                getPath = ReflectionUtils.getMethod("NavigationAbstract", PackageType.MINECRAFT_SERVER, "a", Double.class, Double.class, Double.class);
                setPath = ReflectionUtils.getMethod("NavigationAbstract", PackageType.MINECRAFT_SERVER, "a", PackageType.MINECRAFT_SERVER.getClass("PathEntity"), Double.class);
                initialised = true;
            } catch (ReflectiveOperationException  e) {
                e.printStackTrace();
                Horses.log.warning("Cannot initialise PathUtil.");
                initialised = false;
            }
        }
     
        public static boolean isInitialised(){
            return initialised;
        }
     
        /**
         * Set the {@link Location} where you want the {@link LivingEntity} to go.
         * @param entity The {@link LivingEntity} you want to modify the path of.
         * @param target The {@link Location} where you want the {@link LivingEntity} to go.
         * @param speed Double value of speed the {@link LivingEntity} should travel at.
         */
        public static void setPath(final LivingEntity entity, final Location target, final double speed) {
            if (!isInitialised()) {
                return;
            }
            if (entity == null || target == null) {
                return;
            }
            if (entity.getWorld() != target.getWorld()) {
                return;
            }
            if (!target.getChunk().isLoaded()) {
                target.getChunk().load();
            }
            new BukkitRunnable() {
                @Override
                public void run() {
                    try {
                        Object entityliving = getHandle.invoke(entity);
                        Class<?> entityinsentient_clazz = PackageType.MINECRAFT_SERVER.getClass("EntityInsentient");
                        if (entityinsentient_clazz.isInstance(entityliving)) {
                            Object entityinsentient = entityinsentient_clazz.cast(entityliving);
                            if (entityinsentient == null) {
                                return;
                            }
                            Object navigation = getNavigation.invoke(entityinsentient);
                            if (navigation == null) {
                                return;
                            }
                            Object pathentity = getPath.invoke(navigation, target.getX(), target.getY(), target.getZ());
                            if (pathentity == null) {
                                return;
                            }
                            setPath.invoke(navigation, pathentity, speed);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }.runTaskAsynchronously(Horses.plugin);
        }
    }
     
    (Running this async makes no difference, I was just doing it to reduce lag on the main thread)

    However, every now and again, I get an NPE which crashes the entire server:
    Code (Text):
    [17:00:50] [Craft Scheduler Thread - 396/WARN]: java.lang.reflect.InvocationTargetException
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at sun.reflect.GeneratedMethodAccessor271.invoke(Unknown Source)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at java.lang.reflect.Method.invoke(Unknown Source)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at com.jedk1.horses.util.PathUtil$1.run(PathUtil.java:74)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at org.bukkit.craftbukkit.v1_8_R3.scheduler.CraftTask.run(CraftTask.java:71)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at org.bukkit.craftbukkit.v1_8_R3.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:53)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at java.lang.Thread.run(Unknown Source)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]: Caused by: java.lang.NullPointerException
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at net.minecraft.server.v1_8_R3.Path.b(Path.java:91)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at net.minecraft.server.v1_8_R3.Path.c(Path.java:38)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at net.minecraft.server.v1_8_R3.Pathfinder.a(SourceFile:56)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at net.minecraft.server.v1_8_R3.Pathfinder.a(SourceFile:37)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at net.minecraft.server.v1_8_R3.Pathfinder.a(SourceFile:27)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at net.minecraft.server.v1_8_R3.NavigationAbstract.a(SourceFile:71)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     at net.minecraft.server.v1_8_R3.NavigationAbstract.a(SourceFile:56)
    [17:00:50] [Craft Scheduler Thread - 396/WARN]:     ... 9 more
    [17:00:50] [Server thread/ERROR]: Encountered an unexpected exception
    net.minecraft.server.v1_8_R3.ReportedException: Ticking entity
        at net.minecraft.server.v1_8_R3.MinecraftServer.B(MinecraftServer.java:797) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.DedicatedServer.B(DedicatedServer.java:374) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.MinecraftServer.A(MinecraftServer.java:654) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:557) [spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at java.lang.Thread.run(Unknown Source) [?:1.7.0_51]
    Caused by: java.lang.NullPointerException
        at net.minecraft.server.v1_8_R3.Path.b(Path.java:91) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.Path.c(Path.java:38) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.Pathfinder.a(SourceFile:56) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.Pathfinder.a(SourceFile:37) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.Pathfinder.a(SourceFile:22) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.NavigationAbstract.a(SourceFile:97) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.NavigationAbstract.a(SourceFile:103) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.EntityCreature.ca(EntityCreature.java:94) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.EntityInsentient.t_(EntityInsentient.java:195) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.EntityHorse.t_(EntityHorse.java:755) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.World.entityJoinedWorld(World.java:1607) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.World.g(World.java:1582) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.World.tickEntities(World.java:1425) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.WorldServer.tickEntities(WorldServer.java:597) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.MinecraftServer.B(MinecraftServer.java:786) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        ... 4 more
    [17:00:50] [Server thread/ERROR]:     Cause of unexpected exception was
    java.lang.NullPointerException
        at net.minecraft.server.v1_8_R3.Path.b(Path.java:91) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.Path.c(Path.java:38) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.Pathfinder.a(SourceFile:56) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.Pathfinder.a(SourceFile:37) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.Pathfinder.a(SourceFile:22) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.NavigationAbstract.a(SourceFile:97) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.NavigationAbstract.a(SourceFile:103) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.EntityCreature.ca(EntityCreature.java:94) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.EntityInsentient.t_(EntityInsentient.java:195) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.EntityHorse.t_(EntityHorse.java:755) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.World.entityJoinedWorld(World.java:1607) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.World.g(World.java:1582) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.World.tickEntities(World.java:1425) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.WorldServer.tickEntities(WorldServer.java:597) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.MinecraftServer.B(MinecraftServer.java:786) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.DedicatedServer.B(DedicatedServer.java:374) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.MinecraftServer.A(MinecraftServer.java:654) ~[spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:557) [spigot_1.8.8.jar:git-Spigot-db6de12-930a59c]
        at java.lang.Thread.run(Unknown Source) [?:1.7.0_51]
    NPE at : "Object pathentity = getPath.invoke(navigation, target.getX(), target.getY(), target.getZ());"

    Now, I've tried many things, but I can't work it out. Is this just minecrafts code being a bit shit and not good at catching errors, or is it something I've done? Any help is appreciated.
     
    #1 jedk1, May 14, 2016
    Last edited: May 14, 2016