diff --git a/src/main/java/net/citizensnpcs/Citizens.java b/src/main/java/net/citizensnpcs/Citizens.java index a1f366154..6c23c0c33 100644 --- a/src/main/java/net/citizensnpcs/Citizens.java +++ b/src/main/java/net/citizensnpcs/Citizens.java @@ -146,7 +146,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { try { commands.execute(split, sender, sender, npc); } catch (ServerCommandException ex) { - Messaging.sendTr(sender, Messages.INGAME_COMMAND); + Messaging.sendTr(sender, Messages.COMMAND_MUST_BE_INGAME); } catch (CommandUsageException ex) { Messaging.sendError(sender, ex.getMessage()); Messaging.sendError(sender, ex.getUsage()); diff --git a/src/main/java/net/citizensnpcs/command/command/NPCCommands.java b/src/main/java/net/citizensnpcs/command/command/NPCCommands.java index 3cef05cdf..f9a019f2c 100644 --- a/src/main/java/net/citizensnpcs/command/command/NPCCommands.java +++ b/src/main/java/net/citizensnpcs/command/command/NPCCommands.java @@ -20,6 +20,7 @@ import net.citizensnpcs.command.CommandContext; import net.citizensnpcs.command.Requirements; import net.citizensnpcs.command.exception.CommandException; import net.citizensnpcs.command.exception.NoPermissionsException; +import net.citizensnpcs.command.exception.ServerCommandException; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.NPCSelector; import net.citizensnpcs.trait.Age; @@ -42,6 +43,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.entity.Ageable; +import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -453,79 +455,67 @@ public class NPCCommands { + " is now the owner of " + StringHelper.wrap(npc.getName()) + "."); } - @Command( - aliases = { "npc" }, - usage = "pose (--save [name]|--load [name]|--remove [name]|--list) (-a)", - desc = "Changes/Saves/Lists NPC's head pose(s)", - flags = "a", - modifiers = { "pose" }, - min = 1, - max = 2, - permission = "npc.pose") - @Requirements(selected = true, ownership = true, types = { EntityType.PLAYER }) - public void position(CommandContext args, CommandSender sender, NPC npc) throws CommandException { + @Command( + aliases = { "npc" }, + usage = "pose (--save [name]|--load [name]|--remove [name]|--list) (-a)", + desc = "Changes/Saves/Lists NPC's head pose(s)", + flags = "a", + modifiers = { "pose" }, + min = 1, + max = 2, + permission = "npc.pose") + @Requirements(selected = true, ownership = true, types = EntityType.PLAYER) + public void pose(CommandContext args, CommandSender sender, NPC npc) throws CommandException { + Poses trait = npc.getTrait(Poses.class); + if (args.hasValueFlag("save")) { + if (args.getFlag("save").isEmpty()) + throw new CommandException("Invalid name."); - Poses trait = npc.getTrait(Poses.class); + if (!(sender instanceof Player)) + throw new ServerCommandException(); - if (args.hasValueFlag("save")) { - if (!args.getFlag("save").isEmpty()) { - if (sender instanceof Player) { - if (trait.addPose(args.getFlag("save"), ((Player) sender).getLocation())) - Messaging.sendF(sender, ChatColor.GREEN + "Pose added."); - else throw new CommandException("The pose '" + args.getFlag("load") + "' already exists."); - } - else - throw new CommandException("This command may be used in-game only."); - } - else - throw new CommandException("Invalid name."); - } + if (trait.addPose(args.getFlag("save"), ((Player) sender).getLocation())) { + Messaging.sendF(sender, ChatColor.GREEN + "Pose added."); + } else + throw new CommandException("The pose '" + args.getFlag("load") + "' already exists."); + } else if (args.hasValueFlag("load")) { + if (args.getFlag("load").isEmpty()) + throw new CommandException("Invalid name."); - else if (args.hasValueFlag("load")) { - if (!args.getFlag("load").isEmpty()) { - if (trait.getPose(args.getFlag("load")) != null) - trait.assumePose(trait.getPose(args.getFlag("load"))); - else - throw new CommandException("The pose '" + args.getFlag("load") + "' does not exist."); - } - else - throw new CommandException("Invalid name."); - } + Pose pose = trait.getPose(args.getFlag("load")); + if (pose == null) + throw new CommandException("The pose '" + args.getFlag("load") + "' does not exist."); + trait.assumePose(pose); + } else if (args.hasValueFlag("remove")) { + if (args.getFlag("remove").isEmpty()) + throw new CommandException("Invalid name."); + if (trait.removePose(trait.getPose(args.getFlag("remove")))) + Messaging.sendF(sender, ChatColor.GREEN + "Position removed."); + else + throw new CommandException("The pose '" + args.getFlag("remove") + "' does not exist."); + } else if (!args.hasFlag('a')) { + Paginator paginator = new Paginator().header("Pose"); + paginator.addLine("Key: ID Name Pitch/Yaw"); + for (int i = 0; i < trait.getPoses().size(); i++) { + String line = "" + i + " " + trait.getPoses().get(i).getName() + " " + + trait.getPoses().get(i).getPitch() + "/" + trait.getPoses().get(i).getYaw(); + paginator.addLine(line); + } - else if (args.hasValueFlag("remove")) { - if (!args.getFlag("remove").isEmpty()) { - if (trait.removePose(trait.getPose(args.getFlag("remove")))) - Messaging.sendF(sender, ChatColor.GREEN + "Position removed."); - else - throw new CommandException("The pose '" + args.getFlag("remove") + "' does not exist."); - } - else - throw new CommandException("Invalid name."); - } - - else if (!args.hasFlag('a')) { - Paginator paginator = new Paginator().header("Pose"); - paginator.addLine("Key: ID Name Pitch/Yaw"); - for (int i = 0; i < trait.getPoses().size(); i ++) { - String line = "" + i + " " + trait.getPoses().get(i).getName() + " " + trait.getPoses().get(i).getPitch() + "/" + trait.getPoses().get(i).getYaw(); - paginator.addLine(line); - } + int page = args.getInteger(1, 1); + if (!paginator.sendPage(sender, page)) + throw new CommandException("The page '" + page + "' does not exist."); + } - int page = args.getInteger(1, 1); - if (!paginator.sendPage(sender, page)) - throw new CommandException("The page '" + page + "' does not exist."); - } - - // Assume Player's pose - if (args.hasFlag('a')) { - if (sender instanceof Player) { - trait.assumePose(new Pose(sender.getName(), ((Player) sender).getLocation().getPitch(), ((Player) sender).getLocation().getYaw())); - return; - } - else - Messaging.sendF(sender, ChatColor.YELLOW + "This command can only be used by a Player in-game"); - } - } + // Assume Player's pose + if (!args.hasFlag('a')) + return; + if (sender instanceof Player) { + Location location = ((Player) sender).getLocation(); + trait.assumePose(new Pose(sender.getName(), location.getPitch(), location.getYaw())); + } else + throw new ServerCommandException(); + } @Command( aliases = { "npc" }, @@ -613,17 +603,31 @@ public class NPCCommands { @Command( aliases = { "npc" }, - usage = "select|sel [id]", + usage = "select|sel [id] (--r range)", desc = "Select a NPC with the given ID", modifiers = { "select", "sel" }, - min = 2, + min = 1, max = 2, permission = "npc.select") @Requirements(ownership = true) public void select(CommandContext args, CommandSender sender, NPC npc) throws CommandException { - NPC toSelect = npcRegistry.getById(args.getInteger(1)); + NPC toSelect = null; + if (args.argsLength() == 0) { + if (!(sender instanceof Player)) + throw new ServerCommandException(); + double range = Math.abs(args.getFlagDouble("r", 10)); + List search = ((Player) sender).getNearbyEntities(range, range, range); + for (Entity possibleNPC : search) { + NPC test = npcRegistry.getNPC(possibleNPC); + if (test == null) + continue; + toSelect = test; + break; + } + } else + toSelect = npcRegistry.getById(args.getInteger(1)); if (toSelect == null || !toSelect.getTrait(Spawned.class).shouldSpawn()) - throw new CommandException("No NPC with the ID '" + args.getInteger(1) + "' is spawned."); + throw new CommandException("No NPC could be found."); if (npc != null && toSelect.getId() == npc.getId()) throw new CommandException("You already have that NPC selected."); selector.select(sender, toSelect); diff --git a/src/main/java/net/citizensnpcs/trait/LookClose.java b/src/main/java/net/citizensnpcs/trait/LookClose.java index 4697ec8ce..6e83b0862 100644 --- a/src/main/java/net/citizensnpcs/trait/LookClose.java +++ b/src/main/java/net/citizensnpcs/trait/LookClose.java @@ -11,6 +11,7 @@ import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.command.CommandConfigurable; import net.citizensnpcs.command.CommandContext; +import net.citizensnpcs.util.NMS; import net.citizensnpcs.util.Util; import org.bukkit.Location; @@ -29,7 +30,7 @@ public class LookClose extends Trait implements Toggleable, CommandConfigurable } private boolean canSeeTarget() { - return realisticLooking ? Util.rayTrace(npc.getBukkitEntity(), lookingAt) : true; + return realisticLooking ? NMS.rayTrace(npc.getBukkitEntity(), lookingAt) : true; } @Override diff --git a/src/main/java/net/citizensnpcs/trait/Poses.java b/src/main/java/net/citizensnpcs/trait/Poses.java index 11cf522ac..811a5d32e 100644 --- a/src/main/java/net/citizensnpcs/trait/Poses.java +++ b/src/main/java/net/citizensnpcs/trait/Poses.java @@ -1,75 +1,73 @@ package net.citizensnpcs.trait; - import java.util.ArrayList; import java.util.List; -import org.bukkit.Location; - import net.citizensnpcs.api.exception.NPCLoadException; import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.api.util.DataKey; +import net.citizensnpcs.util.Messaging; import net.citizensnpcs.util.Pose; import net.citizensnpcs.util.Util; +import org.bukkit.Location; + public class Poses extends Trait { - private final List poses = new ArrayList(); + private final List poses = new ArrayList(); - Pose currentPosition = null; + public Poses() { + super("poses"); + } - public Poses() { - super("poses"); - } + public boolean addPose(String name, Location location) { + Pose newPose = new Pose(name, location.getPitch(), location.getYaw()); + if (poses.contains(newPose)) + return false; + poses.add(newPose); + return true; + } - @Override - public void load(DataKey key) throws NPCLoadException { - for (DataKey sub : key.getRelative("list").getIntegerSubKeys()) - try { - poses.add(new Pose(sub.getString("").split(";")[0], Float.valueOf(sub.getString("").split(";")[1]), Float.valueOf(sub.getString("").split(";")[2]))) ; - } catch(Exception e) { /* Perhaps remove the entry if bad? Warn console? */ } - } + public void assumePose(Pose pose) { + if (!npc.isSpawned()) + npc.spawn(npc.getTrait(CurrentLocation.class).getLocation()); - @Override - public void save(DataKey key) { - key.removeKey("list"); - for (int i = 0; i < poses.size(); i++) - key.setString("list." + String.valueOf(i), poses.get(i).stringValue()); - } + Util.assumePose(npc.getBukkitEntity(), pose); + } - public List getPoses() { - return poses; - } + public Pose getPose(String name) { + for (Pose pose : poses) + if (pose.getName().equalsIgnoreCase(name)) + return pose; + return null; + } - public boolean addPose(String name, Location location) { - Pose newPose = new Pose(name, location.getPitch(), location.getYaw()); + public List getPoses() { + return poses; + } - if (poses.contains(newPose)) return false; - poses.add(newPose); - return true; - } - - public boolean removePose(Pose pose) { - if (poses.contains(pose)) { - poses.remove(pose); - return true; - } - else return false; - } - - public Pose getPose(String name) { - for (Pose pose : poses) - if (pose.getName().equalsIgnoreCase(name)) return pose; - - return null; - } - - public void assumePose(Pose pose) { - - if (!npc.isSpawned()) - npc.spawn(npc.getTrait(CurrentLocation.class).getLocation()); - - Util.assumePose(npc.getBukkitEntity(), pose); - } + @Override + public void load(DataKey key) throws NPCLoadException { + for (DataKey sub : key.getRelative("list").getIntegerSubKeys()) + try { + String[] parts = sub.getString("").split(";"); + poses.add(new Pose(parts[0], Float.valueOf(parts[1]), Float.valueOf(parts[2]))); + } catch (NumberFormatException e) { + Messaging.logF("Skipping pose %s - invalid yaw/pitch (%s).", sub.name(), e.getMessage()); + } + } + public boolean removePose(Pose pose) { + if (poses.contains(pose)) { + poses.remove(pose); + return true; + } + return false; + } + @Override + public void save(DataKey key) { + key.removeKey("list"); + for (int i = 0; i < poses.size(); i++) + key.setString("list." + String.valueOf(i), poses.get(i).stringValue()); + } } diff --git a/src/main/java/net/citizensnpcs/trait/waypoint/LinearWaypointProvider.java b/src/main/java/net/citizensnpcs/trait/waypoint/LinearWaypointProvider.java index b8d79c9e9..e5a34528e 100644 --- a/src/main/java/net/citizensnpcs/trait/waypoint/LinearWaypointProvider.java +++ b/src/main/java/net/citizensnpcs/trait/waypoint/LinearWaypointProvider.java @@ -99,13 +99,11 @@ public class LinearWaypointProvider implements WaypointProvider { } private final class LinearWaypointEditor extends Editor { - private final Player player; boolean editing = true; int editingSlot = waypoints.size() - 1; + private final Player player; private boolean showPath; Map waypointMarkers = Maps.newHashMap(); - private static final int LARGEST_SLOT = 8; - private LinearWaypointEditor(Player player) { this.player = player; } @@ -189,17 +187,6 @@ public class LinearWaypointProvider implements WaypointProvider { }, 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) @@ -249,6 +236,17 @@ public class LinearWaypointProvider implements WaypointProvider { currentGoal.onProviderChanged(); } + @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 public void onPlayerItemHeldChange(PlayerItemHeldEvent event) { if (!event.getPlayer().equals(player) || waypoints.size() == 0) @@ -293,6 +291,8 @@ public class LinearWaypointProvider implements WaypointProvider { Messaging.sendF(player, "%s showing waypoint markers.", StringHelper.wrap("Stopped")); } } + + private static final int LARGEST_SLOT = 8; } private class LinearWaypointGoal implements Goal { diff --git a/src/main/java/net/citizensnpcs/util/Messages.java b/src/main/java/net/citizensnpcs/util/Messages.java index e9ef1124d..6643745f2 100644 --- a/src/main/java/net/citizensnpcs/util/Messages.java +++ b/src/main/java/net/citizensnpcs/util/Messages.java @@ -16,12 +16,12 @@ public enum Messages { CITIZENS_IMPLEMENTATION_DISABLED("citizens.changed-implementation", "Citizens implementation changed, disabling plugin."), COMMAND_INVALID_NUMBER("citizens.commands.invalid-number", "That is not a valid number."), + COMMAND_MUST_BE_INGAME("citizens.commands.must-be-ingame", "You must be ingame to use that command."), COMMAND_REPORT_ERROR("citizens.commands.console-error", "Please report this error: [See console]"), ERROR_INITALISING_SUB_PLUGIN("citizens.sub-plugins.error-on-load", "{0} initializing {1}"), ERROR_LOADING_ECONOMY("citizens.economy.error-loading", "Unable to use economy handling. Has Vault been enabled?"), FAILED_LOAD_SAVES("citizens.saves.load-failed", "Unable to load saves, disabling..."), - INGAME_COMMAND("citizens.commands.must-be-ingame", "You must be ingame to use that command."), LOAD_TASK_NOT_SCHEDULED("citizens.load-task-error", "NPC load task couldn't be scheduled - disabling..."), LOADING_SUB_PLUGIN("citizens.sub-plugins.load", "Loading {0}"), LOCALE_NOTIFICATION("citizens.notifications.locale", "Using locale {0}."), diff --git a/src/main/java/net/citizensnpcs/util/NMS.java b/src/main/java/net/citizensnpcs/util/NMS.java index 3b6b7b62d..d9f2fa379 100644 --- a/src/main/java/net/citizensnpcs/util/NMS.java +++ b/src/main/java/net/citizensnpcs/util/NMS.java @@ -31,6 +31,7 @@ public class NMS { } private static final float DEFAULT_SPEED = 0.4F; + private static Map, Integer> ENTITY_CLASS_TO_INT; private static final Map, Constructor> ENTITY_CONSTRUCTOR_CACHE = new WeakHashMap, Constructor>(); private static Map> ENTITY_INT_TO_CLASS; @@ -41,7 +42,6 @@ public class NMS { private static Field PATHFINDING_RANGE; private static Field SPEED_FIELD; private static Field THREAD_STOPPER; - public static void attack(EntityLiving handle, EntityLiving target) { handle.k(target); } @@ -103,6 +103,17 @@ public class NMS { controllerLook.a(target, 10.0F, handle.bf()); } + public static void look(EntityLiving handle, float yaw, float pitch) { + handle.yaw = handle.as = yaw; + handle.pitch = pitch; + } + + public static boolean rayTrace(LivingEntity entity, LivingEntity entity2) { + EntityLiving from = ((CraftLivingEntity) entity).getHandle(); + EntityLiving to = ((CraftLivingEntity) entity2).getHandle(); + return from.l(to); + } + public static void registerEntityClass(Class clazz) { if (ENTITY_CLASS_TO_INT.containsKey(clazz)) return; diff --git a/src/main/java/net/citizensnpcs/util/Pose.java b/src/main/java/net/citizensnpcs/util/Pose.java index 859c11e1d..c077786d6 100644 --- a/src/main/java/net/citizensnpcs/util/Pose.java +++ b/src/main/java/net/citizensnpcs/util/Pose.java @@ -9,8 +9,8 @@ import org.apache.commons.lang.builder.HashCodeBuilder; public class Pose { private final String name; - private final float yaw; private final float pitch; + private final float yaw; public Pose(String name, float pitch, float yaw) { this.yaw = yaw; @@ -18,34 +18,6 @@ public class Pose { this.name = name; } - @Override - public int hashCode() { - return new HashCodeBuilder(13, 21). - append(name). - toHashCode(); - } - - @Override - public String toString() { - return "Name: " + name + " Pitch: " + pitch + " Yaw: " + yaw; - } - - public String stringValue() { - return name + ";" + pitch + ";" + yaw; - } - - public float getYaw() { - return yaw; - } - - public float getPitch() { - return pitch; - } - - public String getName() { - return name; - } - @Override public boolean equals(Object object) { if (object == null) return false; @@ -58,5 +30,33 @@ public class Pose { append(name, op.getName()). isEquals(); } + + public String getName() { + return name; + } + + public float getPitch() { + return pitch; + } + + public float getYaw() { + return yaw; + } + + @Override + public int hashCode() { + return new HashCodeBuilder(13, 21). + append(name). + toHashCode(); + } + + public String stringValue() { + return name + ";" + pitch + ";" + yaw; + } + + @Override + public String toString() { + return "Name: " + name + " Pitch: " + pitch + " Yaw: " + yaw; + } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/util/Util.java b/src/main/java/net/citizensnpcs/util/Util.java index f4d60f5f3..61c45c34c 100644 --- a/src/main/java/net/citizensnpcs/util/Util.java +++ b/src/main/java/net/citizensnpcs/util/Util.java @@ -16,7 +16,6 @@ import org.bukkit.craftbukkit.entity.CraftLivingEntity; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; -import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.util.Vector; @@ -28,6 +27,11 @@ public class Util { private Util() { } + public static void assumePose(org.bukkit.entity.Entity entity, Pose pose) { + EntityLiving handle = ((CraftLivingEntity) entity).getHandle(); + NMS.look(handle, pose.getYaw(), pose.getPitch()); + } + public static void callCollisionEvent(NPC npc, net.minecraft.server.Entity entity) { if (NPCCollisionEvent.getHandlerList().getRegisteredListeners().length > 0) Bukkit.getPluginManager().callEvent(new NPCCollisionEvent(npc, entity.getBukkitEntity())); @@ -54,21 +58,11 @@ public class Util { double yaw = (Math.acos(xDiff / distanceXZ) * 180 / Math.PI); double pitch = (Math.acos(yDiff / distanceY) * 180 / Math.PI) - 90; - if (zDiff < 0.0) { + if (zDiff < 0.0) yaw = yaw + (Math.abs(180 - yaw) * 2); - } EntityLiving handle = ((CraftLivingEntity) from).getHandle(); - handle.yaw = (float) yaw - 90; - handle.pitch = (float) pitch; - handle.as = handle.yaw; - } - - public static void assumePose(Entity entity, Pose pose) { - EntityLiving handle = ((CraftLivingEntity) entity).getHandle(); - handle.yaw = (float) pose.getYaw(); - handle.pitch = (float) pose.getPitch(); - handle.as = handle.yaw; + NMS.look(handle, (float) yaw - 90, (float) pitch); } public static boolean isSettingFulfilled(Player player, Setting setting) { @@ -96,12 +90,6 @@ public class Util { return type; } - public static boolean rayTrace(LivingEntity entity, LivingEntity entity2) { - EntityLiving from = ((CraftLivingEntity) entity).getHandle(); - EntityLiving to = ((CraftLivingEntity) entity2).getHandle(); - return from.l(to); - } - public static void sendPacketNearby(Location location, Packet packet, double radius) { radius *= radius; final World world = location.getWorld();