From 3748ee098f8953c651170535e582d224ac3f987b Mon Sep 17 00:00:00 2001 From: Jeremy Schroeder Date: Fri, 28 Sep 2012 10:25:00 -0400 Subject: [PATCH] Beef up /npc position. Add --save and --load for storing/recalling positions. Example: /npc positions --save position_1 -a ... continue to use -a for making the NPC assume that position. Using /npc position alone will list positions. Using -a alone will neither save nor load, just assume. --- .../command/command/NPCCommands.java | 90 +++++++++++++------ .../net/citizensnpcs/trait/Positions.java | 78 ++++++++++++++++ .../java/net/citizensnpcs/util/Position.java | 43 +++++++++ src/main/java/net/citizensnpcs/util/Util.java | 7 ++ 4 files changed, 192 insertions(+), 26 deletions(-) create mode 100644 src/main/java/net/citizensnpcs/trait/Positions.java create mode 100644 src/main/java/net/citizensnpcs/util/Position.java diff --git a/src/main/java/net/citizensnpcs/command/command/NPCCommands.java b/src/main/java/net/citizensnpcs/command/command/NPCCommands.java index 660c48158..26e888af3 100644 --- a/src/main/java/net/citizensnpcs/command/command/NPCCommands.java +++ b/src/main/java/net/citizensnpcs/command/command/NPCCommands.java @@ -27,10 +27,12 @@ import net.citizensnpcs.trait.Behaviour; import net.citizensnpcs.trait.Controllable; import net.citizensnpcs.trait.CurrentLocation; import net.citizensnpcs.trait.LookClose; +import net.citizensnpcs.trait.Positions; import net.citizensnpcs.trait.Powered; import net.citizensnpcs.trait.VillagerProfession; import net.citizensnpcs.util.Messaging; import net.citizensnpcs.util.Paginator; +import net.citizensnpcs.util.Position; import net.citizensnpcs.util.StringHelper; import net.citizensnpcs.util.Util; import net.minecraft.server.EntityLiving; @@ -453,32 +455,68 @@ public class NPCCommands { + " is now the owner of " + StringHelper.wrap(npc.getName()) + "."); } - @Command( - aliases = { "npc" }, - usage = "position (-a)", - desc = "Changes NPC's head position", - flags = "a", - modifiers = { "position" }, - min = 1, - max = 2, - permission = "npc.position.assume") - @Requirements(selected = true, ownership = true) - public void position(CommandContext args, Player player, NPC npc) throws CommandException { - // Assume Player's position - if (args.hasFlag('a')) { - // Spawn the NPC if it isn't spawned to prevent NPEs - if (!npc.isSpawned()) - npc.spawn(npc.getTrait(CurrentLocation.class).getLocation()); - // Update entity with some NMS magic - EntityLiving handle = ((CraftLivingEntity) npc.getBukkitEntity()).getHandle(); - handle.yaw = player.getLocation().getYaw(); - handle.pitch = player.getLocation().getPitch(); - handle.as = handle.yaw; - return; - } else - Messaging.sendF(player, ChatColor.YELLOW - + "Usage: '/npc position -a' to assume your head position"); - } + @Command( + aliases = { "npc" }, + usage = "position (-a)", + desc = "Changes NPC's head position", + flags = "a", + modifiers = { "position" }, + min = 1, + max = 2, + permission = "npc.position") + @Requirements(selected = true, ownership = true, types = { EntityType.PLAYER }) + public void position(CommandContext args, CommandSender sender, NPC npc) throws CommandException { + + Positions trait = npc.getTrait(Positions.class); + + if (args.hasValueFlag("save")) { + if (args.getFlag("save").matches("[a-zA-Z0-9_\\-]+")) { + if (sender instanceof Player) { + if (trait.addPosition(args.getFlag("save"), ((Player) sender).getLocation())) + Messaging.sendF(sender, ChatColor.RED + "Position added."); + } + else + Messaging.sendF(sender, ChatColor.YELLOW + "This command can only be used by a Player in-game"); + } + else + Messaging.sendF(sender, ChatColor.YELLOW + "Save name can only be one word. Valid characters: A-Z a-z 0-9 - _"); + } + + else if (args.hasValueFlag("load")) { + if (args.getFlag("load").matches("[a-zA-Z0-9_\\-]+")) { + if (trait.getPosition(args.getFlag("load")) != null) + trait.assumePosition(trait.getPosition(args.getFlag("load"))); + else + throw new CommandException("The position '" + args.getFlag("load") + "' does not exist."); + } + else + Messaging.sendF(sender, ChatColor.YELLOW + "Invalid load name."); + } + + else { + Paginator paginator = new Paginator().header("Positions"); + paginator.addLine("Key: ID Name Pitch/Yaw"); + for (int i = 0; i < trait.getPositions().size(); i ++) { + String line = "" + i + " " + trait.getPositions().get(i).name + " " + Double.valueOf(trait.getPositions().get(i).getPitch()) + "/" + Double.valueOf(trait.getPositions().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."); + } + + // Assume Player's position + if (args.hasFlag('a')) { + if (sender instanceof Player) { + trait.assumePosition(new Position(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"); + } + } @Command( aliases = { "npc" }, diff --git a/src/main/java/net/citizensnpcs/trait/Positions.java b/src/main/java/net/citizensnpcs/trait/Positions.java new file mode 100644 index 000000000..3a8ef869e --- /dev/null +++ b/src/main/java/net/citizensnpcs/trait/Positions.java @@ -0,0 +1,78 @@ +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.Position; +import net.citizensnpcs.util.Util; + +public class Positions extends Trait { + private final List positions = new ArrayList(); + + Position currentPosition = null; + + public Positions() { + super("positions"); + } + + @Override + public void load(DataKey key) throws NPCLoadException { + for (DataKey sub : key.getRelative("list").getIntegerSubKeys()) + try { + positions.add(new Position(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? */ } + } + + @Override + public void save(DataKey key) { + for (int i = 0; i < 100; i++) + key.removeKey(String.valueOf(i)); + key.removeKey("list"); + + for (int i = 0; i < positions.size(); i++) + key.setString("list." + String.valueOf(i), positions.get(i).stringValue()); + } + + public List getPositions() { + return positions; + } + + public boolean addPosition(String name, Location location) { + Position newPosition = new Position(name, location.getPitch(), location.getYaw()); + + if (positions.contains(newPosition)) return false; + positions.add(newPosition); + return true; + } + + public boolean removePosition(Position position) { + if (positions.contains(position)) { + positions.remove(position); + return true; + } + else return false; + } + + public Position getPosition(String name) { + for (Position position : positions) + if (position.name.equalsIgnoreCase(name)) return position; + + return null; + } + + public void assumePosition(Position position) { + + if (!npc.isSpawned()) + npc.spawn(npc.getTrait(CurrentLocation.class).getLocation()); + + Util.assumePosition(npc.getBukkitEntity(), position); + } + + +} diff --git a/src/main/java/net/citizensnpcs/util/Position.java b/src/main/java/net/citizensnpcs/util/Position.java new file mode 100644 index 000000000..feea9b31e --- /dev/null +++ b/src/main/java/net/citizensnpcs/util/Position.java @@ -0,0 +1,43 @@ +package net.citizensnpcs.util; + + +/* + * Position object which holds yaw/pitch of the head with a name to identify. + */ + +public class Position { + public final String name; + private final Float yaw; + private final Float pitch; + + public Position(String name, float pitch, float yaw) { + this.yaw = yaw; + this.pitch = pitch; + this.name = name; + } + + @Override + public String toString() { + return "Name: " + name + " Pitch: " + pitch.doubleValue() + " Yaw: " + yaw.doubleValue(); + } + + public String stringValue() { + return name + ";" + pitch + ";" + yaw; + } + + public float getYaw() { + return yaw; + } + + public float getPitch() { + return pitch; + } + + @Override + public boolean equals(Object otherPosition) { + if (otherPosition == null) return false; + if (otherPosition.toString() == this.name) return true; + else return false; + } + +} \ 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 2541204be..17ef11cf9 100644 --- a/src/main/java/net/citizensnpcs/util/Util.java +++ b/src/main/java/net/citizensnpcs/util/Util.java @@ -63,6 +63,13 @@ public class Util { handle.pitch = (float) pitch; handle.as = handle.yaw; } + + public static void assumePosition(Entity entity, Position position) { + EntityLiving handle = ((CraftLivingEntity) entity).getHandle(); + handle.yaw = (float) position.getYaw(); + handle.pitch = (float) position.getPitch(); + handle.as = handle.yaw; + } public static boolean isSettingFulfilled(Player player, Setting setting) { String parts = setting.asString();