diff --git a/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/NMSImpl.java b/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/NMSImpl.java index 0cf81e888..d7d4d6ce3 100644 --- a/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/NMSImpl.java +++ b/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/NMSImpl.java @@ -43,6 +43,7 @@ import org.bukkit.util.Vector; import com.google.common.base.Function; import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfileRepository; @@ -177,6 +178,7 @@ import net.minecraft.server.v1_10_R1.NetworkManager; import net.minecraft.server.v1_10_R1.Packet; import net.minecraft.server.v1_10_R1.PacketPlayOutEntityTeleport; import net.minecraft.server.v1_10_R1.PacketPlayOutPlayerInfo; +import net.minecraft.server.v1_10_R1.PathEntity; import net.minecraft.server.v1_10_R1.PathPoint; import net.minecraft.server.v1_10_R1.PathfinderGoalSelector; import net.minecraft.server.v1_10_R1.ReportedException; @@ -381,9 +383,39 @@ public class NMSImpl implements NMSBridge { return NMSImpl.getHandle(entity).P; } + @Override + public MCNavigator getTargetNavigator(org.bukkit.entity.Entity entity, Iterable dest, + final NavigatorParameters params) { + final PathEntity path = new PathEntity( + Iterables.toArray(Iterables.transform(dest, new Function() { + @Override + public PathPoint apply(Vector input) { + return new PathPoint(input.getBlockX(), input.getBlockY(), input.getBlockZ()); + } + }), PathPoint.class)); + return getTargetNavigator(entity, params, new Function() { + @Override + public Void apply(NavigationAbstract input) { + input.a(path, params.speed()); + return null; + } + }); + } + @Override public MCNavigator getTargetNavigator(final org.bukkit.entity.Entity entity, final Location dest, final NavigatorParameters params) { + return getTargetNavigator(entity, params, new Function() { + @Override + public Void apply(NavigationAbstract input) { + input.a(dest.getX(), dest.getY(), dest.getZ(), params.speed()); + return null; + } + }); + } + + private MCNavigator getTargetNavigator(final org.bukkit.entity.Entity entity, final NavigatorParameters params, + final Function function) { net.minecraft.server.v1_10_R1.Entity raw = getHandle(entity); raw.onGround = true; // not sure of a better way around this - if onGround is false, then @@ -394,7 +426,7 @@ public class NMSImpl implements NMSBridge { if (raw instanceof EntityHorse) { raw.width = Math.min(0.99f, oldWidth); } - navigation.a(dest.getX(), dest.getY(), dest.getZ(), params.speed()); + function.apply(navigation); raw.width = oldWidth; // minecraft requires that an entity fit onto both blocks if width >= 1f, but we'd // prefer to make it just fit on 1 so hack around it a bit. final CancelReason initial; @@ -426,7 +458,7 @@ public class NMSImpl implements NMSBridge { public boolean update() { if (params.speed() != lastSpeed) { Messaging.debug("Repathfinding " + ((NPCHolder) entity).getNPC().getId() + " due to speed change"); - navigation.a(dest.getX(), dest.getY(), dest.getZ(), params.speed()); + function.apply(navigation); lastSpeed = params.speed(); } navigation.a(params.speed()); @@ -1295,6 +1327,7 @@ public class NMSImpl implements NMSBridge { private static Field PATHFINDING_RANGE = NMS.getField(NavigationAbstract.class, "f"); private static final Field RABBIT_FIELD = NMS.getField(EntityRabbit.class, "bx"); private static final Random RANDOM = Util.getFastRandom(); + private static Field SKULL_PROFILE_FIELD; private static Field TRACKED_ENTITY_SET = NMS.getField(EntityTracker.class, "c"); diff --git a/src/main/java/net/citizensnpcs/npc/ai/AStarNavigationStrategy.java b/src/main/java/net/citizensnpcs/npc/ai/AStarNavigationStrategy.java index d17892c4b..f39c07598 100644 --- a/src/main/java/net/citizensnpcs/npc/ai/AStarNavigationStrategy.java +++ b/src/main/java/net/citizensnpcs/npc/ai/AStarNavigationStrategy.java @@ -1,9 +1,13 @@ package net.citizensnpcs.npc.ai; +import java.util.List; + import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.util.Vector; +import com.google.common.collect.Lists; + import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.api.ai.AbstractPathStrategy; import net.citizensnpcs.api.ai.NavigatorParameters; @@ -24,6 +28,15 @@ public class AStarNavigationStrategy extends AbstractPathStrategy { private Path plan; private Vector vector; + public AStarNavigationStrategy(NPC npc, Iterable path, NavigatorParameters params) { + super(TargetType.LOCATION); + List list = Lists.newArrayList(path); + this.params = params; + this.destination = list.get(list.size() - 1).toLocation(npc.getStoredLocation().getWorld()); + this.npc = npc; + setPlan(new Path(list)); + } + public AStarNavigationStrategy(NPC npc, Location dest, NavigatorParameters params) { super(TargetType.LOCATION); this.params = params; @@ -31,17 +44,9 @@ public class AStarNavigationStrategy extends AbstractPathStrategy { this.npc = npc; Location location = npc.getEntity().getLocation(); VectorGoal goal = new VectorGoal(dest, (float) params.pathDistanceMargin()); - plan = ASTAR.runFully(goal, + setPlan(ASTAR.runFully(goal, new VectorNode(goal, location, new ChunkBlockSource(location, params.range()), params.examiners()), - 50000); - if (plan == null || plan.isComplete()) { - setCancelReason(CancelReason.STUCK); - } else { - vector = plan.getCurrentVector(); - if (Setting.DEBUG_PATHFINDING.asBoolean()) { - plan.debug(); - } - } + 50000)); } @Override @@ -54,6 +59,18 @@ public class AStarNavigationStrategy extends AbstractPathStrategy { return destination; } + public void setPlan(Path path) { + this.plan = path; + if (plan == null || plan.isComplete()) { + setCancelReason(CancelReason.STUCK); + } else { + vector = plan.getCurrentVector(); + if (Setting.DEBUG_PATHFINDING.asBoolean()) { + plan.debug(); + } + } + } + @Override public void stop() { if (plan != null && Setting.DEBUG_PATHFINDING.asBoolean()) { @@ -95,6 +112,5 @@ public class AStarNavigationStrategy extends AbstractPathStrategy { } private static final AStarMachine ASTAR = AStarMachine.createWithDefaultStorage(); - private static final Location NPC_LOCATION = new Location(null, 0, 0, 0); } diff --git a/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java b/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java index e38151593..aa7bbdfa7 100644 --- a/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java +++ b/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java @@ -12,6 +12,8 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.util.Vector; +import com.google.common.collect.Iterables; + import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.api.ai.EntityTarget; import net.citizensnpcs.api.ai.Navigator; @@ -199,6 +201,27 @@ public class CitizensNavigator implements Navigator, Runnable { switchStrategyTo(newStrategy); } + @Override + public void setTarget(Iterable path) { + if (!npc.isSpawned()) + throw new IllegalStateException("npc is not spawned"); + if (path == null || Iterables.size(path) == 0) { + cancelNavigation(); + return; + } + switchParams(); + updatePathfindingRange(); + PathStrategy newStrategy; + if (npc.isFlyable()) { + newStrategy = new FlyingAStarNavigationStrategy(npc, path, localParams); + } else if (localParams.useNewPathfinder() || !(npc.getEntity() instanceof LivingEntity)) { + newStrategy = new AStarNavigationStrategy(npc, path, localParams); + } else { + newStrategy = new MCNavigationStrategy(npc, path, localParams); + } + switchStrategyTo(newStrategy); + } + @Override public void setTarget(Location target) { if (!npc.isSpawned()) @@ -357,5 +380,6 @@ public class CitizensNavigator implements Navigator, Runnable { } private static final Location STATIONARY_LOCATION = new Location(null, 0, 0, 0); + private static int UNINITIALISED_SPEED = Integer.MIN_VALUE; } diff --git a/src/main/java/net/citizensnpcs/npc/ai/FlyingAStarNavigationStrategy.java b/src/main/java/net/citizensnpcs/npc/ai/FlyingAStarNavigationStrategy.java index 2d51be62e..0226fac69 100644 --- a/src/main/java/net/citizensnpcs/npc/ai/FlyingAStarNavigationStrategy.java +++ b/src/main/java/net/citizensnpcs/npc/ai/FlyingAStarNavigationStrategy.java @@ -1,10 +1,14 @@ package net.citizensnpcs.npc.ai; +import java.util.List; + import org.bukkit.Location; import org.bukkit.entity.EntityType; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.util.Vector; +import com.google.common.collect.Lists; + import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.api.ai.AbstractPathStrategy; import net.citizensnpcs.api.ai.NavigatorParameters; @@ -27,6 +31,15 @@ public class FlyingAStarNavigationStrategy extends AbstractPathStrategy { private final Location target; private Vector vector; + public FlyingAStarNavigationStrategy(NPC npc, Iterable path, NavigatorParameters params) { + super(TargetType.LOCATION); + List list = Lists.newArrayList(path); + this.target = list.get(list.size() - 1).toLocation(npc.getStoredLocation().getWorld()); + this.parameters = params; + this.npc = npc; + setPlan(new Path(list)); + } + public FlyingAStarNavigationStrategy(final NPC npc, Location dest, NavigatorParameters params) { super(TargetType.LOCATION); this.target = dest; @@ -44,17 +57,9 @@ public class FlyingAStarNavigationStrategy extends AbstractPathStrategy { if (!found) { params.examiner(new FlyingBlockExaminer()); } - plan = ASTAR.runFully(goal, + setPlan(ASTAR.runFully(goal, new VectorNode(goal, location, new ChunkBlockSource(location, params.range()), params.examiners()), - 50000); - if (plan == null || plan.isComplete()) { - setCancelReason(CancelReason.STUCK); - } else { - vector = plan.getCurrentVector(); - if (Setting.DEBUG_PATHFINDING.asBoolean()) { - plan.debug(); - } - } + 50000)); } @Override @@ -67,6 +72,18 @@ public class FlyingAStarNavigationStrategy extends AbstractPathStrategy { return target; } + public void setPlan(Path path) { + this.plan = path; + if (plan == null || plan.isComplete()) { + setCancelReason(CancelReason.STUCK); + } else { + vector = plan.getCurrentVector(); + if (Setting.DEBUG_PATHFINDING.asBoolean()) { + plan.debug(); + } + } + } + @Override public void stop() { if (plan != null && Setting.DEBUG_PATHFINDING.asBoolean()) { @@ -124,6 +141,5 @@ public class FlyingAStarNavigationStrategy extends AbstractPathStrategy { } private static final AStarMachine ASTAR = AStarMachine.createWithDefaultStorage(); - private static final Location NPC_LOCATION = new Location(null, 0, 0, 0); } diff --git a/src/main/java/net/citizensnpcs/npc/ai/MCNavigationStrategy.java b/src/main/java/net/citizensnpcs/npc/ai/MCNavigationStrategy.java index 0a90b0f97..487eee564 100644 --- a/src/main/java/net/citizensnpcs/npc/ai/MCNavigationStrategy.java +++ b/src/main/java/net/citizensnpcs/npc/ai/MCNavigationStrategy.java @@ -1,9 +1,13 @@ package net.citizensnpcs.npc.ai; +import java.util.List; + import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.util.Vector; +import com.google.common.collect.Lists; + import net.citizensnpcs.api.ai.AbstractPathStrategy; import net.citizensnpcs.api.ai.NavigatorParameters; import net.citizensnpcs.api.ai.TargetType; @@ -17,6 +21,15 @@ public class MCNavigationStrategy extends AbstractPathStrategy { private final NavigatorParameters parameters; private final Location target; + MCNavigationStrategy(final NPC npc, Iterable path, NavigatorParameters params) { + super(TargetType.LOCATION); + List list = Lists.newArrayList(path); + this.target = list.get(list.size() - 1).toLocation(npc.getStoredLocation().getWorld()); + this.parameters = params; + handle = npc.getEntity(); + this.navigator = NMS.getTargetNavigator(npc.getEntity(), list, params); + } + MCNavigationStrategy(final NPC npc, Location dest, NavigatorParameters params) { super(TargetType.LOCATION); this.target = dest; diff --git a/src/main/java/net/citizensnpcs/util/NMS.java b/src/main/java/net/citizensnpcs/util/NMS.java index 4e8a948ee..c6dcbfb5e 100644 --- a/src/main/java/net/citizensnpcs/util/NMS.java +++ b/src/main/java/net/citizensnpcs/util/NMS.java @@ -15,6 +15,7 @@ import org.bukkit.entity.Tameable; import org.bukkit.entity.Wither; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.util.Vector; import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfileRepository; @@ -106,6 +107,10 @@ public class NMS { return BRIDGE.getStepHeight(entity); } + public static MCNavigator getTargetNavigator(Entity entity, Iterable dest, NavigatorParameters params) { + return BRIDGE.getTargetNavigator(entity, dest, params); + } + public static MCNavigator getTargetNavigator(Entity entity, Location dest, NavigatorParameters params) { return BRIDGE.getTargetNavigator(entity, dest, params); } diff --git a/src/main/java/net/citizensnpcs/util/NMSBridge.java b/src/main/java/net/citizensnpcs/util/NMSBridge.java index de5c97481..5282b12ea 100644 --- a/src/main/java/net/citizensnpcs/util/NMSBridge.java +++ b/src/main/java/net/citizensnpcs/util/NMSBridge.java @@ -15,6 +15,7 @@ import org.bukkit.entity.Tameable; import org.bukkit.entity.Wither; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.util.Vector; import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfileRepository; @@ -58,6 +59,8 @@ public interface NMSBridge { public TargetNavigator getTargetNavigator(Entity handle, Entity target, NavigatorParameters parameters); + public MCNavigator getTargetNavigator(Entity entity, Iterable dest, NavigatorParameters params); + public MCNavigator getTargetNavigator(Entity entity, Location dest, NavigatorParameters params); public Entity getVehicle(Entity entity);