Fix some bugs with waypoints, add waypoint markers

This commit is contained in:
fullwall 2012-09-28 17:56:16 +08:00
parent 41ba6b1f64
commit ffaf616b1b
5 changed files with 147 additions and 21 deletions

View File

@ -417,7 +417,7 @@ public class NPCCommands {
}
@Command(aliases = { "npc" }, desc = "Show basic NPC information", max = 0)
public void npc(CommandContext args, CommandSender sender, NPC npc) {
public void npc(CommandContext args, CommandSender sender, final NPC npc) {
Messaging.send(sender, StringHelper.wrapHeader(npc.getName()));
Messaging.send(sender, " <a>ID: <e>" + npc.getId());
Messaging.send(sender, " <a>Type: <e>" + npc.getTrait(MobType.class).getType());

View File

@ -149,15 +149,13 @@ public class CitizensNavigator implements Navigator {
private void stopNavigating(CancelReason reason) {
if (!isNavigating())
return;
if (reason == CancelReason.STUCK) {
if (reason == CancelReason.STUCK && localParams.stuckAction() != null) {
StuckAction action = localParams.stuckAction();
if (action != null) {
boolean shouldContinue = action.run(npc, this);
if (shouldContinue) {
stationaryTicks = 0;
executing.clearCancelReason();
return;
}
boolean shouldContinue = action.run(npc, this);
if (shouldContinue) {
stationaryTicks = 0;
executing.clearCancelReason();
return;
}
}
NavigationCancelEvent event = new NavigationCancelEvent(this, reason);
@ -188,9 +186,9 @@ public class CitizensNavigator implements Navigator {
boolean finished = executing.update();
if (!finished)
return;
if (executing.getCancelReason() != null)
if (executing.getCancelReason() != null) {
stopNavigating(executing.getCancelReason());
else {
} else {
NavigationCompleteEvent event = new NavigationCompleteEvent(this);
PathStrategy old = executing;
Bukkit.getPluginManager().callEvent(event);

View File

@ -0,0 +1,20 @@
package net.citizensnpcs.trait.waypoint;
import net.minecraft.server.DamageSource;
import net.minecraft.server.EntityEnderCrystal;
import net.minecraft.server.World;
public class EntityEnderCrystalMarker extends EntityEnderCrystal {
public EntityEnderCrystalMarker(World world) {
super(world);
}
@Override
public void h_() {
}
@Override
public boolean damageEntity(DamageSource damagesource, int i) {
return false;
}
}

View File

@ -2,6 +2,7 @@ package net.citizensnpcs.trait.waypoint;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
@ -16,20 +17,26 @@ import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.StringHelper;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import com.google.common.base.Function;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public class LinearWaypointProvider implements WaypointProvider {
private LinearWaypointGoal currentGoal;
@ -41,19 +48,32 @@ public class LinearWaypointProvider implements WaypointProvider {
return new Editor() {
boolean editing = true;
int editingSlot = waypoints.size() - 1;
Map<Waypoint, Entity> waypointEntities = Maps.newHashMap();
private boolean showPath;
@Override
public void begin() {
player.sendMessage(ChatColor.AQUA + "Entered the linear waypoint editor!");
Messaging.send(player, ChatColor.AQUA + "Entered the linear waypoint editor!");
Messaging.send(player, "<e>Left click<a> to add a waypoint, <e>right click<a> to remove.");
Messaging.send(player, "<a>Type <e>toggle path<a> to toggle showing entities at waypoints.");
}
private void createWaypointMarker(Waypoint waypoint) {
Entity entity = spawnMarker(player.getWorld(), waypoint.getLocation().add(0, 1, 0));
if (entity == null)
return;
waypointEntities.put(waypoint, entity);
}
@Override
public void end() {
if (!editing)
return;
player.sendMessage(ChatColor.AQUA + "Exited the linear waypoint editor.");
Messaging.send(player, ChatColor.AQUA + "Exited the linear waypoint editor.");
editing = false;
if (!showPath)
return;
destroyWaypointMarkers();
}
private String formatLoc(Location location) {
@ -82,6 +102,44 @@ public class LinearWaypointProvider implements WaypointProvider {
Editor.leave(player);
}
@EventHandler(ignoreCancelled = true)
public void onPlayerChat(AsyncPlayerChatEvent event) {
if (!event.getPlayer().equals(player))
return;
if (!event.getMessage().equalsIgnoreCase("toggle path"))
return;
event.setCancelled(true);
// we need to spawn entities, get back on the main thread.
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() {
@Override
public void run() {
togglePath();
}
}, 1);
}
private void togglePath() {
showPath = !showPath;
if (showPath) {
createWaypointMarkers();
Messaging.sendF(player, "%s waypoint markers.", StringHelper.wrap("Showing"));
} else {
destroyWaypointMarkers();
Messaging.sendF(player, "%s showing waypoint markers.", StringHelper.wrap("Stopped"));
}
}
private void createWaypointMarkers() {
for (Waypoint waypoint : waypoints)
createWaypointMarker(waypoint);
}
private void destroyWaypointMarkers() {
for (Entity entity : waypointEntities.values())
entity.remove();
waypointEntities.clear();
}
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if (!event.getPlayer().equals(player) || event.getAction() == Action.PHYSICAL)
@ -98,18 +156,20 @@ public class LinearWaypointProvider implements WaypointProvider {
if (prev != null) {
double distance = at.distanceSquared(prev);
double maxDistance = npc.getNavigator().getDefaultParameters().range();
maxDistance = Math.pow(maxDistance, 2);
double maxDistance = Math.pow(npc.getNavigator().getDefaultParameters().range(), 2);
if (distance > maxDistance) {
Messaging.sendF(player, ChatColor.RED
+ "Previous waypoint is %s blocks away but the distance limit is %s.",
StringHelper.wrap(distance, ChatColor.RED),
StringHelper.wrap(maxDistance, ChatColor.RED));
StringHelper.wrap(Math.sqrt(distance), ChatColor.RED),
StringHelper.wrap(Math.sqrt(maxDistance), ChatColor.RED));
return;
}
}
waypoints.add(Math.max(0, editingSlot), new Waypoint(at));
Waypoint element = new Waypoint(at);
waypoints.add(Math.max(0, editingSlot), element);
if (showPath)
createWaypointMarker(element);
editingSlot = Math.min(editingSlot + 1, waypoints.size());
Messaging.send(
player,
@ -118,7 +178,9 @@ public class LinearWaypointProvider implements WaypointProvider {
} else if (waypoints.size() > 0) {
event.setCancelled(true);
editingSlot = Math.min(0, Math.max(waypoints.size() - 1, editingSlot));
waypoints.remove(editingSlot);
Waypoint waypoint = waypoints.remove(editingSlot);
if (showPath)
removeWaypointMarker(waypoint);
editingSlot = Math.max(0, editingSlot - 1);
Messaging.send(player, String.format(
"<e>Removed<a> a waypoint (<e>%d<a> remaining) (<e>%d<a>)", waypoints.size(),
@ -151,6 +213,17 @@ public class LinearWaypointProvider implements WaypointProvider {
+ formatLoc(waypoints.get(editingSlot).getLocation()) + ").");
}
private void removeWaypointMarker(Waypoint waypoint) {
Entity entity = waypointEntities.remove(waypoint);
if (entity != null)
entity.remove();
}
private Entity spawnMarker(World world, Location at) {
return NMS.spawnCustomEntity(world, at, EntityEnderCrystalMarker.class,
EntityType.ENDER_CRYSTAL);
}
private static final int LARGEST_SLOT = 8;
};
}
@ -224,7 +297,7 @@ public class LinearWaypointProvider implements WaypointProvider {
@EventHandler
public void onNavigationComplete(NavigationCompleteEvent event) {
if (currentDestination == null || !event.getNavigator().equals(getNavigator()))
if (selector == null || !event.getNavigator().equals(getNavigator()))
return;
selector.finish();
}
@ -243,6 +316,8 @@ public class LinearWaypointProvider implements WaypointProvider {
@Override
public void run(GoalSelector selector) {
if (!getNavigator().isNavigating())
selector.finish();
}
public void setPaused(boolean pause) {
@ -254,8 +329,9 @@ public class LinearWaypointProvider implements WaypointProvider {
@Override
public boolean shouldExecute(GoalSelector selector) {
if (paused || currentDestination != null || !npc.isSpawned() || getNavigator().isNavigating()
|| waypoints.size() == 0)
|| waypoints.size() == 0) {
return false;
}
if (waypoints.size() == 1) {
// avoid pathing to the same point and wasting memory.
Location dest = npc.getBukkitEntity().getLocation();

View File

@ -1,8 +1,10 @@
package net.citizensnpcs.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import net.citizensnpcs.npc.CitizensNPC;
import net.minecraft.server.ControllerLook;
@ -14,6 +16,7 @@ import net.minecraft.server.NetworkManager;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftLivingEntity;
import org.bukkit.entity.EntityType;
@ -28,6 +31,7 @@ public class NMS {
}
private static final float DEFAULT_SPEED = 0.4F;
private static final Map<Class<? extends Entity>, Constructor<? extends Entity>> ENTITY_CONSTRUCTOR_CACHE = new WeakHashMap<Class<? extends Entity>, Constructor<? extends Entity>>();
private static Map<Class<? extends Entity>, Integer> ENTITY_CLASS_TO_INT;
private static Map<Integer, Class<? extends Entity>> ENTITY_INT_TO_CLASS;
private static Field GOAL_FIELD;
@ -183,4 +187,32 @@ public class NMS {
} catch (Exception e) {
}
}
public static org.bukkit.entity.Entity spawnCustomEntity(org.bukkit.World world, Location at,
Class<? extends Entity> clazz, EntityType type) {
World handle = ((CraftWorld) world).getHandle();
Entity entity = null;
try {
Constructor<? extends Entity> constructor = getCustomEntityConstructor(clazz, type);
entity = constructor.newInstance(handle);
} catch (Exception e) {
e.printStackTrace();
return null;
}
handle.addEntity(entity);
entity.setLocation(at.getX(), at.getY(), at.getZ(), at.getYaw(), at.getPitch());
return entity.getBukkitEntity();
}
private static Constructor<? extends Entity> getCustomEntityConstructor(Class<? extends Entity> clazz,
EntityType type) throws SecurityException, NoSuchMethodException {
Constructor<? extends Entity> constructor = ENTITY_CONSTRUCTOR_CACHE.get(clazz);
if (constructor == null) {
constructor = clazz.getConstructor(World.class);
constructor.setAccessible(true);
ENTITY_CLASS_TO_INT.put(clazz, (int) type.getTypeId());
ENTITY_CONSTRUCTOR_CACHE.put(clazz, constructor);
}
return constructor;
}
}