Allow markers to be right clicked to update editing slot

This commit is contained in:
fullwall 2012-09-28 18:10:17 +08:00
parent 1f6e568838
commit 96f3c48805
3 changed files with 234 additions and 215 deletions

View File

@ -9,12 +9,12 @@ public class EntityEnderCrystalMarker extends EntityEnderCrystal {
super(world);
}
@Override
public void h_() {
}
@Override
public boolean damageEntity(DamageSource damagesource, int i) {
return false;
}
@Override
public void h_() {
}
}

View File

@ -30,8 +30,10 @@ 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.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.metadata.FixedMetadataValue;
import com.google.common.base.Function;
import com.google.common.collect.Iterators;
@ -44,188 +46,8 @@ public class LinearWaypointProvider implements WaypointProvider {
private final List<Waypoint> waypoints = Lists.newArrayList();
@Override
public Editor createEditor(final Player player) {
return new Editor() {
boolean editing = true;
int editingSlot = waypoints.size() - 1;
Map<Waypoint, Entity> waypointEntities = Maps.newHashMap();
private boolean showPath;
@Override
public void begin() {
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;
Messaging.send(player, ChatColor.AQUA + "Exited the linear waypoint editor.");
editing = false;
if (!showPath)
return;
destroyWaypointMarkers();
}
private String formatLoc(Location location) {
return String.format("<e>%d<a>, <e>%d<a>, <e>%d<a>", location.getBlockX(),
location.getBlockY(), location.getBlockZ());
}
private Location getPreviousWaypoint(int fromSlot) {
if (waypoints.size() <= 1)
return null;
fromSlot--;
if (fromSlot < 0)
fromSlot = waypoints.size() - 1;
return waypoints.get(fromSlot).getLocation();
}
@EventHandler
public void onNPCDespawn(NPCDespawnEvent event) {
if (event.getNPC().equals(npc))
Editor.leave(player);
}
@EventHandler
public void onNPCRemove(NPCRemoveEvent event) {
if (event.getNPC().equals(npc))
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)
return;
if (event.getPlayer().getWorld() != npc.getBukkitEntity().getWorld())
return;
if (event.getAction() == Action.LEFT_CLICK_BLOCK
|| event.getAction() == Action.LEFT_CLICK_AIR) {
if (event.getClickedBlock() == null)
return;
event.setCancelled(true);
Location at = event.getClickedBlock().getLocation();
Location prev = getPreviousWaypoint(editingSlot);
if (prev != null) {
double distance = at.distanceSquared(prev);
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(Math.sqrt(distance), ChatColor.RED),
StringHelper.wrap(Math.sqrt(maxDistance), ChatColor.RED));
return;
}
}
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,
String.format("<e>Added<a> a waypoint at (" + formatLoc(at)
+ ") (<e>%d<a>, <e>%d<a>)", editingSlot + 1, waypoints.size()));
} else if (waypoints.size() > 0) {
event.setCancelled(true);
editingSlot = Math.min(0, Math.max(waypoints.size() - 1, 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(),
editingSlot + 1));
}
currentGoal.onProviderChanged();
}
@EventHandler
public void onPlayerItemHeldChange(PlayerItemHeldEvent event) {
if (!event.getPlayer().equals(player) || waypoints.size() == 0)
return;
int previousSlot = event.getPreviousSlot(), newSlot = event.getNewSlot();
// handle wrap-arounds
if (previousSlot == 0 && newSlot == LARGEST_SLOT) {
editingSlot--;
} else if (previousSlot == LARGEST_SLOT && newSlot == 0) {
editingSlot++;
} else {
int diff = newSlot - previousSlot;
if (Math.abs(diff) != 1)
return; // the player isn't scrolling
editingSlot += diff > 0 ? 1 : -1;
}
if (editingSlot >= waypoints.size())
editingSlot = 0;
if (editingSlot < 0)
editingSlot = waypoints.size() - 1;
Messaging.send(player, "<a>Editing slot set to " + StringHelper.wrap(editingSlot) + " ("
+ 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;
};
public Editor createEditor(Player player) {
return new LinearWaypointEditor(player);
}
@Override
@ -276,6 +98,203 @@ public class LinearWaypointProvider implements WaypointProvider {
currentGoal.setPaused(paused);
}
private final class LinearWaypointEditor extends Editor {
private final Player player;
boolean editing = true;
int editingSlot = waypoints.size() - 1;
private boolean showPath;
Map<Waypoint, Entity> waypointMarkers = Maps.newHashMap();
private static final int LARGEST_SLOT = 8;
private LinearWaypointEditor(Player player) {
this.player = player;
}
@Override
public void begin() {
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(int index, Waypoint waypoint) {
Entity entity = spawnMarker(player.getWorld(), waypoint.getLocation().add(0, 1, 0));
if (entity == null)
return;
entity.setMetadata("waypointindex", new FixedMetadataValue(CitizensAPI.getPlugin(), index));
waypointMarkers.put(waypoint, entity);
}
private void createWaypointMarkers() {
for (int i = 0; i < waypoints.size(); i++)
createWaypointMarker(i, waypoints.get(i));
}
private void destroyWaypointMarkers() {
for (Entity entity : waypointMarkers.values())
entity.remove();
waypointMarkers.clear();
}
@Override
public void end() {
if (!editing)
return;
Messaging.send(player, ChatColor.AQUA + "Exited the linear waypoint editor.");
editing = false;
if (!showPath)
return;
destroyWaypointMarkers();
}
private String formatLoc(Location location) {
return String.format("<e>%d<a>, <e>%d<a>, <e>%d<a>", location.getBlockX(), location.getBlockY(),
location.getBlockZ());
}
private Location getPreviousWaypoint(int fromSlot) {
if (waypoints.size() <= 1)
return null;
fromSlot--;
if (fromSlot < 0)
fromSlot = waypoints.size() - 1;
return waypoints.get(fromSlot).getLocation();
}
@EventHandler
public void onNPCDespawn(NPCDespawnEvent event) {
if (event.getNPC().equals(npc))
Editor.leave(player);
}
@EventHandler
public void onNPCRemove(NPCRemoveEvent event) {
if (event.getNPC().equals(npc))
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);
}
@EventHandler(ignoreCancelled = true)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if (!player.equals(event.getPlayer()) || !showPath)
return;
if (!event.getRightClicked().hasMetadata("waypointindex"))
return;
editingSlot = event.getRightClicked().getMetadata("waypointindex").get(0).asInt();
Messaging.sendF(player, ChatColor.GREEN + "Editing slot set to %s.",
StringHelper.wrap(editingSlot));
}
@EventHandler(ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) {
if (!event.getPlayer().equals(player) || event.getAction() == Action.PHYSICAL)
return;
if (event.getPlayer().getWorld() != npc.getBukkitEntity().getWorld())
return;
if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_AIR) {
if (event.getClickedBlock() == null)
return;
event.setCancelled(true);
Location at = event.getClickedBlock().getLocation();
Location prev = getPreviousWaypoint(editingSlot);
if (prev != null) {
double distance = at.distanceSquared(prev);
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(Math.sqrt(distance), ChatColor.RED),
StringHelper.wrap(Math.sqrt(maxDistance), ChatColor.RED));
return;
}
}
Waypoint element = new Waypoint(at);
waypoints.add(Math.max(0, editingSlot), element);
if (showPath)
createWaypointMarker(editingSlot, element);
editingSlot = Math.min(editingSlot + 1, waypoints.size());
Messaging.send(
player,
String.format("<e>Added<a> a waypoint at (" + formatLoc(at)
+ ") (<e>%d<a>, <e>%d<a>)", editingSlot + 1, waypoints.size()));
} else if (waypoints.size() > 0) {
event.setCancelled(true);
editingSlot = Math.min(0, Math.max(waypoints.size() - 1, 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(), editingSlot + 1));
}
currentGoal.onProviderChanged();
}
@EventHandler
public void onPlayerItemHeldChange(PlayerItemHeldEvent event) {
if (!event.getPlayer().equals(player) || waypoints.size() == 0)
return;
int previousSlot = event.getPreviousSlot(), newSlot = event.getNewSlot();
// handle wrap-arounds
if (previousSlot == 0 && newSlot == LARGEST_SLOT) {
editingSlot--;
} else if (previousSlot == LARGEST_SLOT && newSlot == 0) {
editingSlot++;
} else {
int diff = newSlot - previousSlot;
if (Math.abs(diff) != 1)
return; // the player isn't scrolling
editingSlot += diff > 0 ? 1 : -1;
}
if (editingSlot >= waypoints.size())
editingSlot = 0;
if (editingSlot < 0)
editingSlot = waypoints.size() - 1;
Messaging.send(player, "<a>Editing slot set to " + StringHelper.wrap(editingSlot) + " ("
+ formatLoc(waypoints.get(editingSlot).getLocation()) + ").");
}
private void removeWaypointMarker(Waypoint waypoint) {
Entity entity = waypointMarkers.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 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 class LinearWaypointGoal implements Goal {
private Location currentDestination;
private Iterator<Location> itr;

View File

@ -31,8 +31,8 @@ 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 final Map<Class<? extends Entity>, Constructor<? extends Entity>> ENTITY_CONSTRUCTOR_CACHE = new WeakHashMap<Class<? extends Entity>, Constructor<? extends Entity>>();
private static Map<Integer, Class<? extends Entity>> ENTITY_INT_TO_CLASS;
private static Field GOAL_FIELD;
private static Field LAND_SPEED_MODIFIER_FIELD;
@ -58,6 +58,18 @@ public class NMS {
}
}
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;
}
private static Field getField(Class<?> clazz, String field) {
Field f = null;
try {
@ -116,6 +128,22 @@ public class NMS {
}
}
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();
}
public static void stopNetworkThreads(NetworkManager manager) {
if (THREAD_STOPPER == null)
return;
@ -187,32 +215,4 @@ 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;
}
}