diff --git a/src/main/java/net/citizensnpcs/Citizens.java b/src/main/java/net/citizensnpcs/Citizens.java index 34db352eb..608918c68 100644 --- a/src/main/java/net/citizensnpcs/Citizens.java +++ b/src/main/java/net/citizensnpcs/Citizens.java @@ -55,33 +55,29 @@ import org.bukkit.plugin.java.JavaPlugin; import com.google.common.collect.Iterators; public class Citizens extends JavaPlugin { - private static final String COMPATIBLE_MC_VERSION = "1.2.2"; - - private volatile CitizensNPCManager npcManager; private final InstanceFactory characterManager = DefaultInstanceFactory.create(); + + private final CommandManager commands = new CommandManager(); + private boolean compatible; + private Settings config; + private volatile CitizensNPCManager npcManager; + private Storage saves; private final InstanceFactory traitManager = DefaultInstanceFactory.create(Owner.class, Spawned.class, LookClose.class, SpawnLocation.class, Inventory.class, MobType.class, Waypoints.class, Equipment.class); - private final CommandManager commands = new CommandManager(); - private Settings config; - private Storage saves; - private boolean compatible; + public InstanceFactory getCharacterManager() { + return characterManager; + } - private boolean suggestClosestModifier(CommandSender sender, String command, String modifier) { - int minDist = Integer.MAX_VALUE; - String closest = ""; - for (String string : commands.getAllCommandModifiers(command)) { - int distance = StringHelper.getLevenshteinDistance(modifier, string); - if (minDist > distance) { - minDist = distance; - closest = string; - } - } - if (!closest.isEmpty()) { - sender.sendMessage(ChatColor.GRAY + "Unknown command. Did you mean:"); - sender.sendMessage(StringHelper.wrap(" /") + command + " " + StringHelper.wrap(closest)); - return true; - } - return false; + public CommandManager getCommandManager() { + return commands; + } + + public CitizensNPCManager getNPCManager() { + return npcManager; + } + + public Storage getStorage() { + return saves; } @Override @@ -212,13 +208,13 @@ public class Citizens extends JavaPlugin { Metrics metrics = new Metrics(); metrics.addCustomData(Citizens.this, new Metrics.Plotter() { @Override - public int getValue() { - return Iterators.size(npcManager.iterator()); + public String getColumnName() { + return "Total NPCs"; } @Override - public String getColumnName() { - return "Total NPCs"; + public int getValue() { + return Iterators.size(npcManager.iterator()); } }); metrics.beginMeasuringPlugin(Citizens.this); @@ -229,11 +225,14 @@ public class Citizens extends JavaPlugin { }.start(); } - public void save() { - config.save(); - for (NPC npc : npcManager) - npc.save(saves.getKey("npc." + npc.getId())); - saves.save(); + private void registerCommands() { + commands.setInjector(new Injector(this)); + + // Register command classes + commands.register(AdminCommands.class); + commands.register(EditorCommands.class); + commands.register(HelpCommands.class); + commands.register(NPCCommands.class); } public void reload() throws NPCLoadException { @@ -247,30 +246,11 @@ public class Citizens extends JavaPlugin { setupNPCs(); } - public CitizensNPCManager getNPCManager() { - return npcManager; - } - - public InstanceFactory getCharacterManager() { - return characterManager; - } - - public CommandManager getCommandManager() { - return commands; - } - - public Storage getStorage() { - return saves; - } - - private void registerCommands() { - commands.setInjector(new Injector(this)); - - // Register command classes - commands.register(AdminCommands.class); - commands.register(EditorCommands.class); - commands.register(HelpCommands.class); - commands.register(NPCCommands.class); + public void save() { + config.save(); + for (NPC npc : npcManager) + npc.save(saves.getKey("npc." + npc.getId())); + saves.save(); } private void setupNPCs() throws NPCLoadException { @@ -294,4 +274,24 @@ public class Citizens extends JavaPlugin { } Messaging.log("Loaded " + created + " NPCs (" + spawned + " spawned)."); } + + private boolean suggestClosestModifier(CommandSender sender, String command, String modifier) { + int minDist = Integer.MAX_VALUE; + String closest = ""; + for (String string : commands.getAllCommandModifiers(command)) { + int distance = StringHelper.getLevenshteinDistance(modifier, string); + if (minDist > distance) { + minDist = distance; + closest = string; + } + } + if (!closest.isEmpty()) { + sender.sendMessage(ChatColor.GRAY + "Unknown command. Did you mean:"); + sender.sendMessage(StringHelper.wrap(" /") + command + " " + StringHelper.wrap(closest)); + return true; + } + return false; + } + + private static final String COMPATIBLE_MC_VERSION = "1.2.2"; } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/EventListen.java b/src/main/java/net/citizensnpcs/EventListen.java index 73cfdcee1..317ab1fca 100644 --- a/src/main/java/net/citizensnpcs/EventListen.java +++ b/src/main/java/net/citizensnpcs/EventListen.java @@ -35,8 +35,8 @@ import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; public class EventListen implements Listener { - private final Map> toRespawn = new HashMap>(); private volatile CitizensNPCManager npcManager; + private final Map> toRespawn = new HashMap>(); public EventListen(CitizensNPCManager npcManager) { this.npcManager = npcManager; @@ -77,40 +77,6 @@ public class EventListen implements Listener { toRespawn.put(event.getChunk(), respawn); } - @EventHandler - public void onWorldLoad(WorldLoadEvent event) { - for (Chunk chunk : toRespawn.keySet()) { - if (event.getWorld().isChunkLoaded(chunk)) { - for (int id : toRespawn.get(chunk)) { - NPC npc = npcManager.getNPC(id); - npc.spawn(npc.getTrait(SpawnLocation.class).getLocation()); - } - toRespawn.remove(chunk); - } - } - } - - @EventHandler - public void onWorldUnload(WorldUnloadEvent event) { - if (event.isCancelled()) - return; - - for (NPC npc : npcManager) { - if (!npc.isSpawned() || !npc.getBukkitEntity().getWorld().equals(event.getWorld())) - continue; - Location loc = npc.getBukkitEntity().getLocation(); - npc.getTrait(SpawnLocation.class).setLocation(loc); - npc.despawn(); - if (toRespawn.containsKey(loc.getChunk())) - toRespawn.get(loc.getChunk()).add(npc.getId()); - else { - List respawn = new ArrayList(); - respawn.add(npc.getId()); - toRespawn.put(loc.getChunk(), respawn); - } - } - } - /* * Entity events */ @@ -152,12 +118,12 @@ public class EventListen implements Listener { npc.getCharacter().onRightClick(npc, player); } - /* - * Player events - */ @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - Editor.leave(event.getPlayer()); + public void onPlayerChangedWorld(PlayerChangedWorldEvent event) { + if (!(((CraftPlayer) event.getPlayer()).getHandle() instanceof EntityHumanNPC)) + return; + + ((CraftServer) Bukkit.getServer()).getHandle().players.remove(((CraftPlayer) event.getPlayer()).getHandle()); } @EventHandler @@ -169,11 +135,45 @@ public class EventListen implements Listener { new EntityTargetEvent(event.getRightClicked(), event.getPlayer(), TargetReason.CUSTOM)); } + /* + * Player events + */ @EventHandler - public void onPlayerChangedWorld(PlayerChangedWorldEvent event) { - if (!(((CraftPlayer) event.getPlayer()).getHandle() instanceof EntityHumanNPC)) + public void onPlayerQuit(PlayerQuitEvent event) { + Editor.leave(event.getPlayer()); + } + + @EventHandler + public void onWorldLoad(WorldLoadEvent event) { + for (Chunk chunk : toRespawn.keySet()) { + if (event.getWorld().isChunkLoaded(chunk)) { + for (int id : toRespawn.get(chunk)) { + NPC npc = npcManager.getNPC(id); + npc.spawn(npc.getTrait(SpawnLocation.class).getLocation()); + } + toRespawn.remove(chunk); + } + } + } + + @EventHandler + public void onWorldUnload(WorldUnloadEvent event) { + if (event.isCancelled()) return; - ((CraftServer) Bukkit.getServer()).getHandle().players.remove(((CraftPlayer) event.getPlayer()).getHandle()); + for (NPC npc : npcManager) { + if (!npc.isSpawned() || !npc.getBukkitEntity().getWorld().equals(event.getWorld())) + continue; + Location loc = npc.getBukkitEntity().getLocation(); + npc.getTrait(SpawnLocation.class).setLocation(loc); + npc.despawn(); + if (toRespawn.containsKey(loc.getChunk())) + toRespawn.get(loc.getChunk()).add(npc.getId()); + else { + List respawn = new ArrayList(); + respawn.add(npc.getId()); + toRespawn.put(loc.getChunk(), respawn); + } + } } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/Settings.java b/src/main/java/net/citizensnpcs/Settings.java index ad7597306..648ae1a89 100644 --- a/src/main/java/net/citizensnpcs/Settings.java +++ b/src/main/java/net/citizensnpcs/Settings.java @@ -31,15 +31,15 @@ public class Settings { public enum Setting { CHAT_PREFIX("npc.chat.prefix", "[]: "), + DATABASE_DRIVER("database.driver", ""), + DATABASE_PASSWORD("database.password", ""), + DATABASE_URL("database.url", ""), + DATABASE_USERNAME("database.username", ""), DEBUG_MODE("general.debug-mode", false), QUICK_SELECT("npc.selection.quick-select", false), SELECTION_ITEM("npc.selection.item", 280), SELECTION_MESSAGE("npc.selection.message", "You selected !"), - USE_DATABASE("use-database", false), - DATABASE_PASSWORD("database.password", ""), - DATABASE_USERNAME("database.username", ""), - DATABASE_URL("database.url", ""), - DATABASE_DRIVER("database.driver", ""); + USE_DATABASE("use-database", false); private String path; private Object value; diff --git a/src/main/java/net/citizensnpcs/command/Command.java b/src/main/java/net/citizensnpcs/command/Command.java index 103e8e601..42d6048ca 100644 --- a/src/main/java/net/citizensnpcs/command/Command.java +++ b/src/main/java/net/citizensnpcs/command/Command.java @@ -18,7 +18,7 @@ public @interface Command { String[] modifiers() default ""; - String usage() default ""; - String permission() default ""; + + String usage() default ""; } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/command/CommandContext.java b/src/main/java/net/citizensnpcs/command/CommandContext.java index 4371f9f46..e81c4a471 100644 --- a/src/main/java/net/citizensnpcs/command/CommandContext.java +++ b/src/main/java/net/citizensnpcs/command/CommandContext.java @@ -28,8 +28,8 @@ import com.google.common.collect.Maps; public class CommandContext { protected String[] args; - protected final Map valueFlags = Maps.newHashMap(); protected final Set flags = new HashSet(); + protected final Map valueFlags = Maps.newHashMap(); public CommandContext(String args) { this(args.split(" ")); @@ -112,6 +112,45 @@ public class CommandContext { return index + 1 < args.length ? Double.parseDouble(args[index + 1]) : def; } + public String getFlag(String ch) { + return valueFlags.get(ch); + } + + public String getFlag(String ch, String def) { + final String value = valueFlags.get(ch); + if (value == null) { + return def; + } + + return value; + } + + public double getFlagDouble(String ch) throws NumberFormatException { + return Double.parseDouble(valueFlags.get(ch)); + } + + public double getFlagDouble(String ch, double def) throws NumberFormatException { + final String value = valueFlags.get(ch); + if (value == null) { + return def; + } + + return Double.parseDouble(value); + } + + public int getFlagInteger(String ch) throws NumberFormatException { + return Integer.parseInt(valueFlags.get(ch)); + } + + public int getFlagInteger(String ch, int def) throws NumberFormatException { + final String value = valueFlags.get(ch); + if (value == null) { + return def; + } + + return Integer.parseInt(value); + } + public Set getFlags() { return flags; } @@ -152,6 +191,10 @@ public class CommandContext { return index + 1 < args.length ? args[index + 1] : def; } + public Map getValueFlags() { + return valueFlags; + } + public boolean hasFlag(char ch) { return flags.contains(ch); } @@ -167,47 +210,4 @@ public class CommandContext { public boolean matches(String command) { return args[0].equalsIgnoreCase(command); } - - public Map getValueFlags() { - return valueFlags; - } - - public String getFlag(String ch) { - return valueFlags.get(ch); - } - - public String getFlag(String ch, String def) { - final String value = valueFlags.get(ch); - if (value == null) { - return def; - } - - return value; - } - - public int getFlagInteger(String ch) throws NumberFormatException { - return Integer.parseInt(valueFlags.get(ch)); - } - - public int getFlagInteger(String ch, int def) throws NumberFormatException { - final String value = valueFlags.get(ch); - if (value == null) { - return def; - } - - return Integer.parseInt(value); - } - - public double getFlagDouble(String ch) throws NumberFormatException { - return Double.parseDouble(valueFlags.get(ch)); - } - - public double getFlagDouble(String ch, double def) throws NumberFormatException { - final String value = valueFlags.get(ch); - if (value == null) { - return def; - } - - return Double.parseDouble(value); - } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/command/CommandManager.java b/src/main/java/net/citizensnpcs/command/CommandManager.java index 860934dc3..76e83748a 100644 --- a/src/main/java/net/citizensnpcs/command/CommandManager.java +++ b/src/main/java/net/citizensnpcs/command/CommandManager.java @@ -38,8 +38,6 @@ public class CommandManager { */ private final Map commands = new HashMap(); - private final Map> subCommands = new HashMap>(); - // Stores the injector used to getInstance. private Injector injector; @@ -50,6 +48,8 @@ public class CommandManager { private final Map serverCommands = new HashMap(); + private final Map> subCommands = new HashMap>(); + /* * Attempt to execute a command. This version takes a separate command name * (for the root command) and then a list of following arguments. @@ -150,6 +150,19 @@ public class CommandManager { return cmds.toArray(new String[cmds.size()]); } + public List getCommands(String command) { + if (subCommands.containsKey(command)) + return subCommands.get(command); + List cmds = new ArrayList(); + for (Entry entry : commands.entrySet()) { + if (!entry.getKey().split(" ")[0].equalsIgnoreCase(command) + || !entry.getValue().isAnnotationPresent(Command.class)) + continue; + cmds.add(entry.getValue().getAnnotation(Command.class)); + } + return cmds; + } + // Get the usage string for a command. private String getUsage(String[] args, Command cmd) { StringBuilder command = new StringBuilder(); @@ -173,19 +186,6 @@ public class CommandManager { || commands.containsKey(command.toLowerCase() + " *"); } - public List getCommands(String command) { - if (subCommands.containsKey(command)) - return subCommands.get(command); - List cmds = new ArrayList(); - for (Entry entry : commands.entrySet()) { - if (!entry.getKey().split(" ")[0].equalsIgnoreCase(command) - || !entry.getValue().isAnnotationPresent(Command.class)) - continue; - cmds.add(entry.getValue().getAnnotation(Command.class)); - } - return cmds; - } - // Returns whether a player has access to a command. private boolean hasPermission(Method method, Player player) { Command cmd = method.getAnnotation(Command.class); diff --git a/src/main/java/net/citizensnpcs/command/Injector.java b/src/main/java/net/citizensnpcs/command/Injector.java index 030d88096..0f456de92 100644 --- a/src/main/java/net/citizensnpcs/command/Injector.java +++ b/src/main/java/net/citizensnpcs/command/Injector.java @@ -7,8 +7,8 @@ import java.util.logging.Level; import net.citizensnpcs.util.Messaging; public class Injector { - private Object[] args; private Class[] argClasses; + private Object[] args; public Injector(Object... args) { this.args = args; diff --git a/src/main/java/net/citizensnpcs/command/command/HelpCommands.java b/src/main/java/net/citizensnpcs/command/command/HelpCommands.java index eed6fc53e..8ef6cf86c 100644 --- a/src/main/java/net/citizensnpcs/command/command/HelpCommands.java +++ b/src/main/java/net/citizensnpcs/command/command/HelpCommands.java @@ -43,6 +43,24 @@ public class HelpCommands { throw new CommandException("The page '" + page + "' does not exist."); } + private List getLines(Player player, String baseCommand) { + // Ensures that commands with multiple modifiers are only added once + Set cmds = new HashSet(); + List lines = new ArrayList(); + for (Command cmd : cmdManager.getCommands(baseCommand)) { + if (cmds.contains(cmd) + || (!player.hasPermission("citizens.admin") && !player + .hasPermission("citizens." + cmd.permission()))) + continue; + + lines.add("<7>/" + cmd.aliases()[0] + (cmd.usage().isEmpty() ? "" : " " + cmd.usage()) + " <7>- " + + cmd.desc()); + if (cmd.modifiers().length > 1) + cmds.add(cmd); + } + return lines; + } + @Command( aliases = { "npc" }, usage = "help (page)", @@ -61,22 +79,4 @@ public class HelpCommands { if (!paginator.sendPage(player, page)) throw new CommandException("The page '" + page + "' does not exist."); } - - private List getLines(Player player, String baseCommand) { - // Ensures that commands with multiple modifiers are only added once - Set cmds = new HashSet(); - List lines = new ArrayList(); - for (Command cmd : cmdManager.getCommands(baseCommand)) { - if (cmds.contains(cmd) - || (!player.hasPermission("citizens.admin") && !player - .hasPermission("citizens." + cmd.permission()))) - continue; - - lines.add("<7>/" + cmd.aliases()[0] + (cmd.usage().isEmpty() ? "" : " " + cmd.usage()) + " <7>- " - + cmd.desc()); - if (cmd.modifiers().length > 1) - cmds.add(cmd); - } - return lines; - } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/command/command/NPCCommands.java b/src/main/java/net/citizensnpcs/command/command/NPCCommands.java index ea633ef29..315077278 100644 --- a/src/main/java/net/citizensnpcs/command/command/NPCCommands.java +++ b/src/main/java/net/citizensnpcs/command/command/NPCCommands.java @@ -30,21 +30,34 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; @Requirements(selected = true, ownership = true) public class NPCCommands { - private final CitizensNPCManager npcManager; private final InstanceFactory characterManager; + private final CitizensNPCManager npcManager; public NPCCommands(Citizens plugin) { npcManager = plugin.getNPCManager(); characterManager = plugin.getCharacterManager(); } - @Command(aliases = { "npc" }, desc = "Show basic NPC information", max = 0) - public void npc(CommandContext args, Player player, NPC npc) { - Messaging.send(player, StringHelper.wrapHeader(npc.getName())); - Messaging.send(player, " ID: " + npc.getId()); - Messaging.send(player, " Character: " - + (npc.getCharacter() != null ? npc.getCharacter().getName() : "None")); - Messaging.send(player, " Type: " + npc.getTrait(MobType.class).getType()); + @Command( + aliases = { "npc" }, + usage = "character [character]", + desc = "Set the character of an NPC", + modifiers = { "character" }, + min = 2, + max = 2) + public void character(CommandContext args, Player player, NPC npc) throws CommandException { + String name = args.getString(1).toLowerCase(); + Character character = characterManager.getInstance(name, npc); + if (character == null) + throw new CommandException("The character '" + args.getString(1) + "' does not exist."); + if (npc.getCharacter() != null && npc.getCharacter().getName().equalsIgnoreCase(character.getName())) + throw new CommandException("The NPC already has the character '" + name + "'."); + if (!player.hasPermission("citizens.npc.character." + character.getName()) + && !player.hasPermission("citizens.npc.character.*") && !player.hasPermission("citizens.admin")) + throw new NoPermissionsException(); + Messaging.send(player, StringHelper.wrap(npc.getName() + "'s") + " character is now '" + + StringHelper.wrap(name) + "'."); + npc.setCharacter(character); } @Command( @@ -112,181 +125,6 @@ public class NPCCommands { Messaging.send(player, ChatColor.GREEN + "You despawned " + StringHelper.wrap(npc.getName()) + "."); } - @Command( - aliases = { "npc" }, - usage = "remove (all)", - desc = "Remove an NPC", - modifiers = { "remove" }, - min = 1, - max = 2) - @Requirements - public void remove(CommandContext args, Player player, NPC npc) throws CommandException { - if (args.argsLength() == 2) { - if (!args.getString(1).equals("all")) - throw new CommandException("Incorrect syntax. /npc remove (all)"); - if (!player.hasPermission("citizens.npc.remove.all") && !player.hasPermission("citizens.admin")) - throw new NoPermissionsException(); - npcManager.removeAll(); - Messaging.send(player, "You permanently removed all NPCs."); - return; - } - if (npc == null) - throw new CommandException("You must have an NPC selected to execute that command."); - if (!npc.getTrait(Owner.class).getOwner().equals(player.getName()) && !player.hasPermission("citizens.admin")) - throw new CommandException("You must be the owner of this NPC to execute that command."); - if (!player.hasPermission("citizens.npc.remove") && !player.hasPermission("citizens.admin")) - throw new NoPermissionsException(); - npc.remove(); - Messaging.send(player, "You permanently removed " + StringHelper.wrap(npc.getName()) + "."); - } - - @Command( - aliases = { "npc" }, - usage = "rename [name]", - desc = "Rename an NPC", - modifiers = { "rename" }, - min = 2, - max = 2, - permission = "npc.rename") - public void rename(CommandContext args, Player player, NPC npc) { - String oldName = npc.getName(); - String newName = args.getString(1); - if (newName.length() > 16) { - Messaging.sendError(player, "NPC names cannot be longer than 16 characters. The name has been shortened."); - newName = newName.substring(0, 15); - } - npc.setName(newName); - Messaging.send(player, ChatColor.GREEN + "You renamed " + StringHelper.wrap(oldName) + " to " - + StringHelper.wrap(newName) + "."); - } - - @Command( - aliases = { "npc" }, - usage = "select [id]", - desc = "Select an NPC with the given ID", - modifiers = { "select" }, - min = 2, - max = 2, - permission = "npc.select") - @Requirements(ownership = true) - public void select(CommandContext args, Player player, NPC npc) throws CommandException { - NPC toSelect = npcManager.getNPC(args.getInteger(1)); - if (toSelect == null || !toSelect.getTrait(Spawned.class).shouldSpawn()) - throw new CommandException("No NPC with the ID '" + args.getInteger(1) + "' is spawned."); - if (npc != null && toSelect.getId() == npc.getId()) - throw new CommandException("You already have that NPC selected."); - npcManager.selectNPC(player, toSelect); - Messaging.sendWithNPC(player, Setting.SELECTION_MESSAGE.asString(), toSelect); - } - - @Command( - aliases = { "npc" }, - usage = "character [character]", - desc = "Set the character of an NPC", - modifiers = { "character" }, - min = 2, - max = 2) - public void character(CommandContext args, Player player, NPC npc) throws CommandException { - String name = args.getString(1).toLowerCase(); - Character character = characterManager.getInstance(name, npc); - if (character == null) - throw new CommandException("The character '" + args.getString(1) + "' does not exist."); - if (npc.getCharacter() != null && npc.getCharacter().getName().equalsIgnoreCase(character.getName())) - throw new CommandException("The NPC already has the character '" + name + "'."); - if (!player.hasPermission("citizens.npc.character." + character.getName()) - && !player.hasPermission("citizens.npc.character.*") && !player.hasPermission("citizens.admin")) - throw new NoPermissionsException(); - Messaging.send(player, StringHelper.wrap(npc.getName() + "'s") + " character is now '" - + StringHelper.wrap(name) + "'."); - npc.setCharacter(character); - } - - @Command( - aliases = { "npc" }, - usage = "owner [name]", - desc = "Set the owner of an NPC", - modifiers = { "owner" }, - min = 2, - max = 2, - permission = "npc.owner") - public void owner(CommandContext args, Player player, NPC npc) throws CommandException { - String name = args.getString(1); - if (npc.getTrait(Owner.class).getOwner().equals(name)) - throw new CommandException("'" + name + "' is already the owner of " + npc.getName() + "."); - npc.getTrait(Owner.class).setOwner(name); - Messaging.send(player, StringHelper.wrap(name) + " is now the owner of " + StringHelper.wrap(npc.getName()) - + "."); - } - - @Command( - aliases = { "npc" }, - usage = "spawn [id]", - desc = "Spawn an existing NPC", - modifiers = { "spawn" }, - min = 2, - max = 2, - permission = "npc.spawn") - @Requirements - public void spawn(CommandContext args, Player player, NPC npc) throws CommandException { - NPC respawn = npcManager.getNPC(args.getInteger(1)); - if (respawn == null) - throw new CommandException("No NPC with the ID '" + args.getInteger(1) + "' exists."); - - if (!respawn.getTrait(Owner.class).getOwner().equals(player.getName())) - throw new CommandException("You must be the owner of this NPC to execute that command."); - - if (respawn.spawn(player.getLocation())) { - npcManager.selectNPC(player, respawn); - Messaging.send(player, ChatColor.GREEN + "You respawned " + StringHelper.wrap(respawn.getName()) - + " at your location."); - } else - throw new CommandException(respawn.getName() + " is already spawned at another location." - + " Use '/npc tphere' to teleport the NPC to your location."); - } - - @Command( - aliases = { "npc" }, - usage = "tphere", - desc = "Teleport an NPC to your location", - modifiers = { "tphere" }, - min = 1, - max = 1, - permission = "npc.tphere") - public void tphere(CommandContext args, Player player, NPC npc) { - // Spawn the NPC if it isn't spawned to prevent NPEs - if (!npc.isSpawned()) - npc.spawn(npc.getTrait(SpawnLocation.class).getLocation()); - npc.getBukkitEntity().teleport(player, TeleportCause.COMMAND); - npc.getTrait(SpawnLocation.class).setLocation(npc.getBukkitEntity().getLocation()); - Messaging.send(player, StringHelper.wrap(npc.getName()) + " was teleported to your location."); - } - - @Command( - aliases = { "npc" }, - usage = "tp", - desc = "Teleport to an NPC", - modifiers = { "tp", "teleport" }, - min = 1, - max = 1, - permission = "npc.tp") - public void tp(CommandContext args, Player player, NPC npc) { - // Spawn the NPC if it isn't spawned to prevent NPEs - if (!npc.isSpawned()) - npc.spawn(npc.getTrait(SpawnLocation.class).getLocation()); - player.teleport(npc.getBukkitEntity(), TeleportCause.COMMAND); - Messaging.send(player, ChatColor.GREEN + "You teleported to " + StringHelper.wrap(npc.getName()) + "."); - } - - @Command(aliases = { "npc" }, usage = "lookclose", desc = "Toggle an NPC's look-close state", modifiers = { - "lookclose", "look", "rotate" }, min = 1, max = 1, permission = "npc.lookclose") - public void lookClose(CommandContext args, Player player, NPC npc) { - LookClose trait = npc.getTrait(LookClose.class); - trait.toggle(); - String msg = StringHelper.wrap(npc.getName()) + " will " - + (trait.shouldLookClose() ? "now rotate" : "no longer rotate"); - Messaging.send(player, msg += " when a player is nearby."); - } - @Command( aliases = { "npc" }, usage = "list (page) ((-a) --owner (owner) --type (type) --char (char))", @@ -358,4 +196,166 @@ public class NPCCommands { if (!paginator.sendPage(player, page)) throw new CommandException("The page '" + page + "' does not exist."); } + + @Command(aliases = { "npc" }, usage = "lookclose", desc = "Toggle an NPC's look-close state", modifiers = { + "lookclose", "look", "rotate" }, min = 1, max = 1, permission = "npc.lookclose") + public void lookClose(CommandContext args, Player player, NPC npc) { + LookClose trait = npc.getTrait(LookClose.class); + trait.toggle(); + String msg = StringHelper.wrap(npc.getName()) + " will " + + (trait.shouldLookClose() ? "now rotate" : "no longer rotate"); + Messaging.send(player, msg += " when a player is nearby."); + } + + @Command(aliases = { "npc" }, desc = "Show basic NPC information", max = 0) + public void npc(CommandContext args, Player player, NPC npc) { + Messaging.send(player, StringHelper.wrapHeader(npc.getName())); + Messaging.send(player, " ID: " + npc.getId()); + Messaging.send(player, " Character: " + + (npc.getCharacter() != null ? npc.getCharacter().getName() : "None")); + Messaging.send(player, " Type: " + npc.getTrait(MobType.class).getType()); + } + + @Command( + aliases = { "npc" }, + usage = "owner [name]", + desc = "Set the owner of an NPC", + modifiers = { "owner" }, + min = 2, + max = 2, + permission = "npc.owner") + public void owner(CommandContext args, Player player, NPC npc) throws CommandException { + String name = args.getString(1); + if (npc.getTrait(Owner.class).getOwner().equals(name)) + throw new CommandException("'" + name + "' is already the owner of " + npc.getName() + "."); + npc.getTrait(Owner.class).setOwner(name); + Messaging.send(player, StringHelper.wrap(name) + " is now the owner of " + StringHelper.wrap(npc.getName()) + + "."); + } + + @Command( + aliases = { "npc" }, + usage = "remove (all)", + desc = "Remove an NPC", + modifiers = { "remove" }, + min = 1, + max = 2) + @Requirements + public void remove(CommandContext args, Player player, NPC npc) throws CommandException { + if (args.argsLength() == 2) { + if (!args.getString(1).equals("all")) + throw new CommandException("Incorrect syntax. /npc remove (all)"); + if (!player.hasPermission("citizens.npc.remove.all") && !player.hasPermission("citizens.admin")) + throw new NoPermissionsException(); + npcManager.removeAll(); + Messaging.send(player, "You permanently removed all NPCs."); + return; + } + if (npc == null) + throw new CommandException("You must have an NPC selected to execute that command."); + if (!npc.getTrait(Owner.class).getOwner().equals(player.getName()) && !player.hasPermission("citizens.admin")) + throw new CommandException("You must be the owner of this NPC to execute that command."); + if (!player.hasPermission("citizens.npc.remove") && !player.hasPermission("citizens.admin")) + throw new NoPermissionsException(); + npc.remove(); + Messaging.send(player, "You permanently removed " + StringHelper.wrap(npc.getName()) + "."); + } + + @Command( + aliases = { "npc" }, + usage = "rename [name]", + desc = "Rename an NPC", + modifiers = { "rename" }, + min = 2, + max = 2, + permission = "npc.rename") + public void rename(CommandContext args, Player player, NPC npc) { + String oldName = npc.getName(); + String newName = args.getString(1); + if (newName.length() > 16) { + Messaging.sendError(player, "NPC names cannot be longer than 16 characters. The name has been shortened."); + newName = newName.substring(0, 15); + } + npc.setName(newName); + Messaging.send(player, ChatColor.GREEN + "You renamed " + StringHelper.wrap(oldName) + " to " + + StringHelper.wrap(newName) + "."); + } + + @Command( + aliases = { "npc" }, + usage = "select [id]", + desc = "Select an NPC with the given ID", + modifiers = { "select" }, + min = 2, + max = 2, + permission = "npc.select") + @Requirements(ownership = true) + public void select(CommandContext args, Player player, NPC npc) throws CommandException { + NPC toSelect = npcManager.getNPC(args.getInteger(1)); + if (toSelect == null || !toSelect.getTrait(Spawned.class).shouldSpawn()) + throw new CommandException("No NPC with the ID '" + args.getInteger(1) + "' is spawned."); + if (npc != null && toSelect.getId() == npc.getId()) + throw new CommandException("You already have that NPC selected."); + npcManager.selectNPC(player, toSelect); + Messaging.sendWithNPC(player, Setting.SELECTION_MESSAGE.asString(), toSelect); + } + + @Command( + aliases = { "npc" }, + usage = "spawn [id]", + desc = "Spawn an existing NPC", + modifiers = { "spawn" }, + min = 2, + max = 2, + permission = "npc.spawn") + @Requirements + public void spawn(CommandContext args, Player player, NPC npc) throws CommandException { + NPC respawn = npcManager.getNPC(args.getInteger(1)); + if (respawn == null) + throw new CommandException("No NPC with the ID '" + args.getInteger(1) + "' exists."); + + if (!respawn.getTrait(Owner.class).getOwner().equals(player.getName())) + throw new CommandException("You must be the owner of this NPC to execute that command."); + + if (respawn.spawn(player.getLocation())) { + npcManager.selectNPC(player, respawn); + Messaging.send(player, ChatColor.GREEN + "You respawned " + StringHelper.wrap(respawn.getName()) + + " at your location."); + } else + throw new CommandException(respawn.getName() + " is already spawned at another location." + + " Use '/npc tphere' to teleport the NPC to your location."); + } + + @Command( + aliases = { "npc" }, + usage = "tp", + desc = "Teleport to an NPC", + modifiers = { "tp", "teleport" }, + min = 1, + max = 1, + permission = "npc.tp") + public void tp(CommandContext args, Player player, NPC npc) { + // Spawn the NPC if it isn't spawned to prevent NPEs + if (!npc.isSpawned()) + npc.spawn(npc.getTrait(SpawnLocation.class).getLocation()); + player.teleport(npc.getBukkitEntity(), TeleportCause.COMMAND); + Messaging.send(player, ChatColor.GREEN + "You teleported to " + StringHelper.wrap(npc.getName()) + "."); + } + + @Command( + aliases = { "npc" }, + usage = "tphere", + desc = "Teleport an NPC to your location", + modifiers = { "tphere" }, + min = 1, + max = 1, + permission = "npc.tphere") + public void tphere(CommandContext args, Player player, NPC npc) { + // Spawn the NPC if it isn't spawned to prevent NPEs + if (!npc.isSpawned()) + npc.spawn(npc.getTrait(SpawnLocation.class).getLocation()); + npc.getBukkitEntity().teleport(player, TeleportCause.COMMAND); + npc.getTrait(SpawnLocation.class).setLocation(npc.getBukkitEntity().getLocation()); + Messaging.send(player, StringHelper.wrap(npc.getName()) + " was teleported to your location."); + } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/command/exception/CommandException.java b/src/main/java/net/citizensnpcs/command/exception/CommandException.java index 0039563ee..b55ff3890 100644 --- a/src/main/java/net/citizensnpcs/command/exception/CommandException.java +++ b/src/main/java/net/citizensnpcs/command/exception/CommandException.java @@ -1,8 +1,6 @@ package net.citizensnpcs.command.exception; public class CommandException extends Exception { - private static final long serialVersionUID = 870638193072101739L; - public CommandException() { super(); } @@ -14,4 +12,6 @@ public class CommandException extends Exception { public CommandException(Throwable t) { super(t); } + + private static final long serialVersionUID = 870638193072101739L; } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/command/exception/CommandUsageException.java b/src/main/java/net/citizensnpcs/command/exception/CommandUsageException.java index 98bda1ca6..7a72de128 100644 --- a/src/main/java/net/citizensnpcs/command/exception/CommandUsageException.java +++ b/src/main/java/net/citizensnpcs/command/exception/CommandUsageException.java @@ -1,8 +1,6 @@ package net.citizensnpcs.command.exception; public class CommandUsageException extends CommandException { - private static final long serialVersionUID = -6761418114414516542L; - protected String usage; public CommandUsageException(String message, String usage) { @@ -13,4 +11,6 @@ public class CommandUsageException extends CommandException { public String getUsage() { return usage; } + + private static final long serialVersionUID = -6761418114414516542L; } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/command/exception/NoPermissionsException.java b/src/main/java/net/citizensnpcs/command/exception/NoPermissionsException.java index ebdccba7b..02f67ac99 100644 --- a/src/main/java/net/citizensnpcs/command/exception/NoPermissionsException.java +++ b/src/main/java/net/citizensnpcs/command/exception/NoPermissionsException.java @@ -1,9 +1,9 @@ package net.citizensnpcs.command.exception; public class NoPermissionsException extends CommandException { - private static final long serialVersionUID = -602374621030168291L; - public NoPermissionsException() { super("You don't have permission to execute that command."); } + + private static final long serialVersionUID = -602374621030168291L; } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/command/exception/RequirementMissingException.java b/src/main/java/net/citizensnpcs/command/exception/RequirementMissingException.java index 43549ce14..3bbc11126 100644 --- a/src/main/java/net/citizensnpcs/command/exception/RequirementMissingException.java +++ b/src/main/java/net/citizensnpcs/command/exception/RequirementMissingException.java @@ -1,9 +1,9 @@ package net.citizensnpcs.command.exception; public class RequirementMissingException extends CommandException { - private static final long serialVersionUID = -4299721983654504028L; - public RequirementMissingException(String message) { super(message); } + + private static final long serialVersionUID = -4299721983654504028L; } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/command/exception/WrappedCommandException.java b/src/main/java/net/citizensnpcs/command/exception/WrappedCommandException.java index 66680bee5..66cabeca4 100644 --- a/src/main/java/net/citizensnpcs/command/exception/WrappedCommandException.java +++ b/src/main/java/net/citizensnpcs/command/exception/WrappedCommandException.java @@ -1,9 +1,9 @@ package net.citizensnpcs.command.exception; public class WrappedCommandException extends CommandException { - private static final long serialVersionUID = -4075721444847778918L; - public WrappedCommandException(Throwable t) { super(t); } + + private static final long serialVersionUID = -4075721444847778918L; } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/editor/Editor.java b/src/main/java/net/citizensnpcs/editor/Editor.java index f16edcf62..0a2039904 100644 --- a/src/main/java/net/citizensnpcs/editor/Editor.java +++ b/src/main/java/net/citizensnpcs/editor/Editor.java @@ -10,12 +10,19 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; public abstract class Editor implements Listener { - private static final Map editing = new HashMap(); - public abstract void begin(); public abstract void end(); + private static final Map editing = new HashMap(); + + private static void enter(Player player, Editor editor) { + editor.begin(); + player.getServer().getPluginManager().registerEvents(editor, + player.getServer().getPluginManager().getPlugin("Citizens")); + editing.put(player.getName(), editor); + } + public static void enterOrLeave(Player player, Editor editor) { Editor edit = editing.get(player.getName()); if (edit == null) @@ -26,6 +33,10 @@ public abstract class Editor implements Listener { Messaging.sendError(player, "You're already in an editor!"); } + public static boolean hasEditor(Player player) { + return editing.containsKey(player.getName()); + } + public static void leave(Player player) { if (!hasEditor(player)) return; @@ -37,15 +48,4 @@ public abstract class Editor implements Listener { public static void leaveAll() { editing.clear(); } - - private static void enter(Player player, Editor editor) { - editor.begin(); - player.getServer().getPluginManager().registerEvents(editor, - player.getServer().getPluginManager().getPlugin("Citizens")); - editing.put(player.getName(), editor); - } - - public static boolean hasEditor(Player player) { - return editing.containsKey(player.getName()); - } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/editor/EquipmentEditor.java b/src/main/java/net/citizensnpcs/editor/EquipmentEditor.java index 4a2b3967c..b1fb9b44b 100644 --- a/src/main/java/net/citizensnpcs/editor/EquipmentEditor.java +++ b/src/main/java/net/citizensnpcs/editor/EquipmentEditor.java @@ -15,9 +15,9 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; public class EquipmentEditor extends Editor { - private final Citizens plugin; - private final Player player; private final NPC npc; + private final Player player; + private final Citizens plugin; public EquipmentEditor(Citizens plugin, Player player, NPC npc) { this.plugin = plugin; diff --git a/src/main/java/net/citizensnpcs/npc/CitizensNPC.java b/src/main/java/net/citizensnpcs/npc/CitizensNPC.java index 051cfbdb3..1d04a9ff1 100644 --- a/src/main/java/net/citizensnpcs/npc/CitizensNPC.java +++ b/src/main/java/net/citizensnpcs/npc/CitizensNPC.java @@ -9,7 +9,6 @@ import net.citizensnpcs.api.trait.trait.Spawned; import net.citizensnpcs.npc.ai.CitizensAI; import net.citizensnpcs.util.Messaging; import net.citizensnpcs.util.StringHelper; - import net.minecraft.server.EntityLiving; import org.bukkit.Bukkit; @@ -19,8 +18,8 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; public abstract class CitizensNPC extends AbstractNPC { - protected final CitizensNPCManager manager; protected final CitizensAI ai = new CitizensAI(this); + protected final CitizensNPCManager manager; protected EntityLiving mcEntity; protected CitizensNPC(CitizensNPCManager manager, int id, String name) { @@ -28,25 +27,19 @@ public abstract class CitizensNPC extends AbstractNPC { this.manager = manager; } + @Override + public void chat(Player player, String message) { + Messaging.sendWithNPC(player, Setting.CHAT_PREFIX.asString() + message, this); + } + @Override public void chat(String message) { for (Player player : Bukkit.getOnlinePlayers()) chat(player, message); } - @Override - public void chat(Player player, String message) { - Messaging.sendWithNPC(player, Setting.CHAT_PREFIX.asString() + message, this); - } - protected abstract EntityLiving createHandle(Location loc); - @Override - public void move(int x, int y, int z) { - if (mcEntity != null) - mcEntity.move(x, y, z); - } - @Override public boolean despawn() { if (!isSpawned()) { @@ -62,6 +55,11 @@ public abstract class CitizensNPC extends AbstractNPC { return true; } + @Override + public CitizensAI getAI() { + return ai; + } + @Override public LivingEntity getBukkitEntity() { return (LivingEntity) getHandle().getBukkitEntity(); @@ -72,8 +70,10 @@ public abstract class CitizensNPC extends AbstractNPC { } @Override - public CitizensAI getAI() { - return ai; + public org.bukkit.inventory.Inventory getInventory() { + Inventory inventory = Bukkit.getServer().createInventory(this, 36, StringHelper.parseColors(getFullName())); + inventory.setContents(getTrait(net.citizensnpcs.api.trait.trait.Inventory.class).getContents()); + return inventory; } @Override @@ -81,6 +81,12 @@ public abstract class CitizensNPC extends AbstractNPC { return getHandle() != null; } + @Override + public void move(int x, int y, int z) { + if (mcEntity != null) + mcEntity.move(x, y, z); + } + @Override public void remove() { manager.remove(this); @@ -88,6 +94,11 @@ public abstract class CitizensNPC extends AbstractNPC { despawn(); } + @Override + public void setName(String name) { + super.setName(name); + } + @Override public boolean spawn(Location loc) { if (isSpawned()) { @@ -111,21 +122,9 @@ public abstract class CitizensNPC extends AbstractNPC { return true; } - @Override - public org.bukkit.inventory.Inventory getInventory() { - Inventory inventory = Bukkit.getServer().createInventory(this, 36, StringHelper.parseColors(getFullName())); - inventory.setContents(getTrait(net.citizensnpcs.api.trait.trait.Inventory.class).getContents()); - return inventory; - } - @Override public void update() { super.update(); ai.update(); } - - @Override - public void setName(String name) { - super.setName(name); - } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/CitizensNPCManager.java b/src/main/java/net/citizensnpcs/npc/CitizensNPCManager.java index 57dc5c641..01ec49f26 100644 --- a/src/main/java/net/citizensnpcs/npc/CitizensNPCManager.java +++ b/src/main/java/net/citizensnpcs/npc/CitizensNPCManager.java @@ -24,10 +24,10 @@ import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.MetadataValue; public class CitizensNPCManager implements NPCManager { - private final Citizens plugin; - private final ByIdArray npcs = new ByIdArray(); - private final Storage saves; private final NPCBuilder npcBuilder = new NPCBuilder(); + private final ByIdArray npcs = new ByIdArray(); + private final Citizens plugin; + private final Storage saves; public CitizensNPCManager(Storage saves) { plugin = (Citizens) Bukkit.getPluginManager().getPlugin("Citizens"); diff --git a/src/main/java/net/citizensnpcs/npc/ai/CitizensAI.java b/src/main/java/net/citizensnpcs/npc/ai/CitizensAI.java index 7ed977f4e..9ff20543c 100644 --- a/src/main/java/net/citizensnpcs/npc/ai/CitizensAI.java +++ b/src/main/java/net/citizensnpcs/npc/ai/CitizensAI.java @@ -19,12 +19,12 @@ import com.google.common.collect.Lists; public class CitizensAI implements AI { private Runnable ai; - private boolean paused; private final List> callbacks = Lists.newArrayList(); private PathStrategy executing; private final List executingGoals = Lists.newArrayList(); private final List goals = Lists.newArrayList(); private final CitizensNPC npc; + private boolean paused; public CitizensAI(CitizensNPC npc) { this.npc = npc; @@ -38,6 +38,11 @@ public class CitizensAI implements AI { Collections.sort(goals); } + @Override + public boolean hasDestination() { + return executing != null; + } + private boolean isGoalAllowable(GoalEntry test) { for (GoalEntry item : goals) { if (item == test) @@ -54,6 +59,10 @@ public class CitizensAI implements AI { return true; } + public void pause() { + paused = true; + } + @Override public void registerNavigationCallback(NavigationCallback callback) { if (!callbacks.contains(callback)) { @@ -62,6 +71,10 @@ public class CitizensAI implements AI { } } + public void resume() { + paused = false; + } + @Override public void setAI(Runnable ai) { this.ai = ai; @@ -109,19 +122,10 @@ public class CitizensAI implements AI { } } - public void pause() { - paused = true; - } - - public void resume() { - paused = false; - } - public void update() { if (paused) return; if (executing != null && executing.update()) { - Messaging.log("finished"); Iterator> itr = callbacks.iterator(); while (itr.hasNext()) { NavigationCallback next = itr.next().get(); diff --git a/src/main/java/net/citizensnpcs/npc/ai/MoveStrategy.java b/src/main/java/net/citizensnpcs/npc/ai/MoveStrategy.java index e2339c772..4b4d7ff8e 100644 --- a/src/main/java/net/citizensnpcs/npc/ai/MoveStrategy.java +++ b/src/main/java/net/citizensnpcs/npc/ai/MoveStrategy.java @@ -13,13 +13,11 @@ import org.bukkit.Location; import org.bukkit.entity.Player; public class MoveStrategy implements PathStrategy { - private static final double JUMP_VELOCITY = 0.49D; + private Float cachedSpeed; - private Float cachedMotion; private final EntityLiving handle; private final PathEntity path; private final Random random = new Random(); - public MoveStrategy(CitizensNPC handle, Location destination) { this.handle = handle.getHandle(); this.path = this.handle.world.a(this.handle, destination.getBlockX(), destination.getBlockY(), @@ -37,14 +35,25 @@ public class MoveStrategy implements PathStrategy { lengthSq *= lengthSq; while (vec3d != null && vec3d.d(handle.locX, vec3d.b, handle.locZ) < lengthSq) { this.path.a(); // Increment path index. - if (this.path.b())// finished. + if (this.path.b()) { // finished. return null; - else - vec3d = this.path.a(handle); + } + vec3d = this.path.a(handle); } return vec3d; } + private float getYawDifference(double diffZ, double diffX) { + float vectorYaw = (float) (Math.atan2(diffZ, diffX) * 180.0D / Math.PI) - 90.0F; + float diffYaw = (vectorYaw - handle.yaw) % 360; + return Math.max(-30F, Math.min(30, diffYaw)); + } + + private void jump() { + if (handle.onGround) + handle.motY = JUMP_VELOCITY; + } + @Override public boolean update() { if (handle.dead) @@ -61,16 +70,16 @@ public class MoveStrategy implements PathStrategy { handle.yaw += getYawDifference(diffZ, diffX); if (vector.b - yHeight > 0.0D) jump(); - if (cachedMotion == null) { + if (cachedSpeed == null) { try { - cachedMotion = MOTION_FIELD.getFloat(handle); + cachedSpeed = SPEED_FIELD.getFloat(handle); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } - handle.e(cachedMotion); + handle.e(cachedSpeed); // handle.walk(); if (handle.positionChanged) @@ -80,21 +89,12 @@ public class MoveStrategy implements PathStrategy { return false; } - private float getYawDifference(double diffZ, double diffX) { - float vectorYaw = (float) (Math.atan2(diffZ, diffX) * 180.0D / Math.PI) - 90.0F; - float diffYaw = (vectorYaw - handle.yaw) % 360; - return Math.max(-30F, Math.min(30, diffYaw)); - } + private static final double JUMP_VELOCITY = 0.49D; - private void jump() { - if (handle.onGround) - handle.motY = JUMP_VELOCITY; - } - - private static Field MOTION_FIELD; + private static Field SPEED_FIELD; static { try { - MOTION_FIELD = EntityLiving.class.getDeclaredField("bb"); + SPEED_FIELD = EntityLiving.class.getDeclaredField("bb"); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { diff --git a/src/main/java/net/citizensnpcs/npc/ai/TargetStrategy.java b/src/main/java/net/citizensnpcs/npc/ai/TargetStrategy.java index 2ccbdf63b..ccdfbc801 100644 --- a/src/main/java/net/citizensnpcs/npc/ai/TargetStrategy.java +++ b/src/main/java/net/citizensnpcs/npc/ai/TargetStrategy.java @@ -9,9 +9,9 @@ import org.bukkit.craftbukkit.entity.CraftLivingEntity; import org.bukkit.entity.LivingEntity; public class TargetStrategy implements PathStrategy { - private final EntityLiving handle, target; private final boolean aggro; private PathStrategy current = null; + private final EntityLiving handle, target; public TargetStrategy(CitizensNPC handle, LivingEntity target, boolean aggro) { this.handle = handle.getHandle(); @@ -19,6 +19,16 @@ public class TargetStrategy implements PathStrategy { this.aggro = aggro; } + private boolean canAttack() { + return handle.attackTicks == 0 + && (handle.boundingBox.e > target.boundingBox.b && handle.boundingBox.b < target.boundingBox.e) + && distanceSquared() <= ATTACK_DISTANCE && handle.h(target); + } + + private double distanceSquared() { + return handle.getBukkitEntity().getLocation().distanceSquared(target.getBukkitEntity().getLocation()); + } + @Override public boolean update() { if (target == null || target.dead) @@ -36,15 +46,5 @@ public class TargetStrategy implements PathStrategy { return false; } - private boolean canAttack() { - return handle.attackTicks == 0 - && (handle.boundingBox.e > target.boundingBox.b && handle.boundingBox.b < target.boundingBox.e) - && distanceSquared() <= ATTACK_DISTANCE && handle.h(target); - } - private static final double ATTACK_DISTANCE = 1.75 * 1.75; - - private double distanceSquared() { - return handle.getBukkitEntity().getLocation().distanceSquared(target.getBukkitEntity().getLocation()); - } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensHumanNPC.java b/src/main/java/net/citizensnpcs/npc/entity/CitizensHumanNPC.java index b104e24f8..dff3bbd93 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensHumanNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/CitizensHumanNPC.java @@ -21,6 +21,16 @@ public class CitizensHumanNPC extends CitizensNPC { super(manager, id, name); } + @Override + protected EntityLiving createHandle(Location loc) { + WorldServer ws = ((CraftWorld) loc.getWorld()).getHandle(); + EntityHumanNPC handle = new EntityHumanNPC(ws.getServer().getServer(), ws, + StringHelper.parseColors(getFullName()), new ItemInWorldManager(ws)); + handle.removeFromPlayerMap(getFullName()); + handle.setPositionRotation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); + return handle; + } + @Override public Player getBukkitEntity() { return (Player) getHandle().getBukkitEntity(); @@ -32,10 +42,8 @@ public class CitizensHumanNPC extends CitizensNPC { } @Override - public void update() { - super.update(); - if (mcEntity == null) - return; + public void load(DataKey key) throws NPCLoadException { + super.load(key); } @Override @@ -47,17 +55,9 @@ public class CitizensHumanNPC extends CitizensNPC { } @Override - protected EntityLiving createHandle(Location loc) { - WorldServer ws = ((CraftWorld) loc.getWorld()).getHandle(); - EntityHumanNPC handle = new EntityHumanNPC(ws.getServer().getServer(), ws, - StringHelper.parseColors(getFullName()), new ItemInWorldManager(ws)); - handle.removeFromPlayerMap(getFullName()); - handle.setPositionRotation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); - return handle; - } - - @Override - public void load(DataKey key) throws NPCLoadException { - super.load(key); + public void update() { + super.update(); + if (mcEntity == null) + return; } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/trait/LookClose.java b/src/main/java/net/citizensnpcs/trait/LookClose.java index a4059d508..00f78aa6b 100644 --- a/src/main/java/net/citizensnpcs/trait/LookClose.java +++ b/src/main/java/net/citizensnpcs/trait/LookClose.java @@ -20,36 +20,6 @@ public class LookClose extends Trait implements Runnable { this.npc = npc; } - @Override - public void load(DataKey key) throws NPCLoadException { - shouldLookClose = key.getBoolean(""); - } - - @Override - public void save(DataKey key) { - key.setBoolean("", shouldLookClose); - } - - @Override - public void run() { - EntityLiving search = null; - CitizensNPC handle = (CitizensNPC) npc; - if ((search = handle.getHandle().world.findNearbyPlayer(handle.getHandle(), 5)) != null && shouldLookClose) - faceEntity(handle, search.getBukkitEntity()); - } - - public void setLookClose(boolean shouldLookClose) { - this.shouldLookClose = shouldLookClose; - } - - public boolean shouldLookClose() { - return shouldLookClose; - } - - public void toggle() { - shouldLookClose = !shouldLookClose; - } - private void faceEntity(CitizensNPC npc, Entity target) { if (npc.getBukkitEntity().getWorld() != target.getWorld()) return; @@ -72,6 +42,36 @@ public class LookClose extends Trait implements Runnable { npc.getHandle().pitch = (float) pitch; } + @Override + public void load(DataKey key) throws NPCLoadException { + shouldLookClose = key.getBoolean(""); + } + + @Override + public void run() { + EntityLiving search = null; + CitizensNPC handle = (CitizensNPC) npc; + if ((search = handle.getHandle().world.findNearbyPlayer(handle.getHandle(), 5)) != null && shouldLookClose) + faceEntity(handle, search.getBukkitEntity()); + } + + @Override + public void save(DataKey key) { + key.setBoolean("", shouldLookClose); + } + + public void setLookClose(boolean shouldLookClose) { + this.shouldLookClose = shouldLookClose; + } + + public boolean shouldLookClose() { + return shouldLookClose; + } + + public void toggle() { + shouldLookClose = !shouldLookClose; + } + @Override public String toString() { return "LookClose{" + shouldLookClose + "}"; diff --git a/src/main/java/net/citizensnpcs/trait/waypoint/GenericWaypointCallback.java b/src/main/java/net/citizensnpcs/trait/waypoint/GenericWaypointCallback.java new file mode 100644 index 000000000..5c0898dfa --- /dev/null +++ b/src/main/java/net/citizensnpcs/trait/waypoint/GenericWaypointCallback.java @@ -0,0 +1,80 @@ +package net.citizensnpcs.trait.waypoint; + +import java.util.Iterator; + +import net.citizensnpcs.api.ai.AI; +import net.citizensnpcs.api.ai.NavigationCallback; + +import org.bukkit.Location; + +public class GenericWaypointCallback extends NavigationCallback { + private Location dest; + private boolean executing; + private Iterator itr; + private final Iterable provider; + + public GenericWaypointCallback(Iterable provider) { + this.provider = provider; + } + + private void ensureItr() { + if (itr == null || !itr.hasNext()) + itr = provider.iterator(); + } + + @Override + public void onAttach(AI ai) { + executing = !ai.hasDestination(); + if (!executing) + return; + if (dest == null) { + ensureItr(); + if (itr.hasNext()) { + dest = itr.next().getLocation(); + } + } + if (dest != null) { + ai.setDestination(dest); + } + } + + @Override + public boolean onCancel(AI ai, PathCancelReason reason) { + if (executing) { + executing = false; + } else { + executing = true; + ensureItr(); + if (dest != null) + ai.setDestination(dest); + else if (itr.hasNext()) { + ai.setDestination(itr.next().getLocation()); + } + } + return false; + } + + @Override + public boolean onCompletion(AI ai) { + if (executing) { // if we're executing, we need to get the next waypoint + if (!itr.hasNext()) { + dest = null; + } else { + dest = itr.next().getLocation(); + } + } else { + executing = true; + // we're free to return to our waypoints! + // if we had a destination, we will return to it. + } + if (dest != null) { + ai.setDestination(dest); + } + return false; + } + + public void onProviderChanged() { + itr = provider.iterator(); + dest = null; + } +} diff --git a/src/main/java/net/citizensnpcs/trait/waypoint/LinearWaypointProvider.java b/src/main/java/net/citizensnpcs/trait/waypoint/LinearWaypointProvider.java index 0fb90b505..e2f495773 100644 --- a/src/main/java/net/citizensnpcs/trait/waypoint/LinearWaypointProvider.java +++ b/src/main/java/net/citizensnpcs/trait/waypoint/LinearWaypointProvider.java @@ -1,8 +1,8 @@ package net.citizensnpcs.trait.waypoint; +import java.util.Iterator; import java.util.List; -import net.citizensnpcs.api.ai.AI; import net.citizensnpcs.api.ai.NavigationCallback; import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.StorageUtils; @@ -17,7 +17,9 @@ import org.bukkit.event.player.PlayerInteractEvent; import com.google.common.collect.Lists; -public class LinearWaypointProvider implements WaypointProvider { +public class LinearWaypointProvider implements WaypointProvider, Iterable { + private final GenericWaypointCallback callback = new GenericWaypointCallback(this); + private final List waypoints = Lists.newArrayList(); @Override @@ -32,12 +34,7 @@ public class LinearWaypointProvider implements WaypointProvider { @Override public void end() { player.sendMessage(ChatColor.GREEN + "Exited linear waypoint editor."); - if (waypoints.size() == 0) - callback.currentIndex = -1; - else if (callback.ai != null && callback.currentIndex == -1) { - callback.currentIndex = 0; - callback.ai.setDestination(waypoints.get(0).getLocation()); - } + callback.onProviderChanged(); } @EventHandler @@ -58,6 +55,16 @@ public class LinearWaypointProvider implements WaypointProvider { }; } + @Override + public NavigationCallback getCallback() { + return callback; + } + + @Override + public Iterator iterator() { + return waypoints.iterator(); + } + @Override public void load(DataKey key) { for (DataKey root : key.getRelative("waypoints").getIntegerSubKeys()) { @@ -72,72 +79,4 @@ public class LinearWaypointProvider implements WaypointProvider { StorageUtils.saveLocation(key.getRelative(Integer.toString(i)), waypoints.get(i).getLocation()); } } - - @Override - public NavigationCallback getCallback() { - return callback; - } - - private final LinearNavigationCallback callback = new LinearNavigationCallback(); - - private class LinearNavigationCallback extends NavigationCallback { - private boolean executing; - private int currentIndex = -1; - private AI ai; - - @Override - public boolean onCancel(AI ai, PathCancelReason reason) { - if (executing) { - executing = false; - } else { - executing = true; - if (currentIndex == -1 && waypoints.size() > 0) - currentIndex = 0; - if (currentIndex != -1) { - ai.setDestination(waypoints.get(currentIndex).getLocation()); - } - } - return false; - } - - @Override - public void onAttach(AI ai) { - this.ai = ai; - executing = false; - currentIndex = -1; - cycle(); - if (currentIndex != -1) { - ai.setDestination(waypoints.get(currentIndex).getLocation()); - } - } - - @Override - public boolean onCompletion(AI ai) { - if (executing) { - cycle(); // if we're executing, we need to get the next index - } else { - executing = true; // we're free to return to our waypoints! - if (currentIndex == -1 && waypoints.size() > 0) - currentIndex = 0; - } - if (currentIndex != -1) { - ai.setDestination(waypoints.get(currentIndex).getLocation()); - } - return false; - } - - // TODO: problem with only 1 waypoint. Waypoint instantly completes, - // possibly causes lag.... - - private void cycle() { - if (waypoints.size() == 0) { - currentIndex = -1; - return; - } - currentIndex++; - if (currentIndex >= waypoints.size()) { - currentIndex = 0; - } - } - }; } diff --git a/src/main/java/net/citizensnpcs/trait/waypoint/WaypointProvider.java b/src/main/java/net/citizensnpcs/trait/waypoint/WaypointProvider.java index f517325ed..487796026 100644 --- a/src/main/java/net/citizensnpcs/trait/waypoint/WaypointProvider.java +++ b/src/main/java/net/citizensnpcs/trait/waypoint/WaypointProvider.java @@ -10,9 +10,9 @@ public interface WaypointProvider { public Editor createEditor(Player player); + public NavigationCallback getCallback(); + public void load(DataKey key); public void save(DataKey key); - - public NavigationCallback getCallback(); } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/trait/waypoint/Waypoints.java b/src/main/java/net/citizensnpcs/trait/waypoint/Waypoints.java index d25f930a5..19a23773d 100644 --- a/src/main/java/net/citizensnpcs/trait/waypoint/Waypoints.java +++ b/src/main/java/net/citizensnpcs/trait/waypoint/Waypoints.java @@ -14,14 +14,18 @@ import org.bukkit.entity.Player; @SaveId("waypoints") public class Waypoints extends Trait { private final NPC npc; - private String providerName; private WaypointProvider provider = new LinearWaypointProvider(); + private String providerName; public Waypoints(NPC npc) { this.npc = npc; npc.getAI().registerNavigationCallback(provider.getCallback()); } + public Editor getEditor(Player player) { + return provider.createEditor(player); + } + @Override public void load(DataKey key) throws NPCLoadException { providerName = key.getString("provider", "linear"); @@ -40,21 +44,17 @@ public class Waypoints extends Trait { key.setString("provider", providerName); } - public Editor getEditor(Player player) { - return provider.createEditor(player); - } - public void setWaypointProvider(WaypointProvider provider, String name) { this.provider = provider; providerName = name; } + private static final InstanceFactory providers = DefaultInstanceFactory.create(); + public static void registerWaypointProvider(Class clazz, String name) { providers.register(clazz, name); } - private static final InstanceFactory providers = DefaultInstanceFactory.create(); - static { providers.register(LinearWaypointProvider.class, "linear"); } diff --git a/src/main/java/net/citizensnpcs/util/ByIdArray.java b/src/main/java/net/citizensnpcs/util/ByIdArray.java index 56c0623ef..183b32cd8 100644 --- a/src/main/java/net/citizensnpcs/util/ByIdArray.java +++ b/src/main/java/net/citizensnpcs/util/ByIdArray.java @@ -6,12 +6,12 @@ import java.util.Iterator; import java.util.NoSuchElementException; public class ByIdArray implements Iterable { - private Object[] elementData; private final int capacity; - private int size; - private int modCount; + private Object[] elementData; private int highest = Integer.MIN_VALUE; private int lowest = Integer.MAX_VALUE; + private int modCount; + private int size; public ByIdArray() { this(65535); diff --git a/src/main/java/net/citizensnpcs/util/Metrics.java b/src/main/java/net/citizensnpcs/util/Metrics.java index 6a09193df..ef994fdc6 100644 --- a/src/main/java/net/citizensnpcs/util/Metrics.java +++ b/src/main/java/net/citizensnpcs/util/Metrics.java @@ -54,71 +54,9 @@ import org.bukkit.plugin.Plugin; public class Metrics { /** - * Interface used to collect custom data for a plugin + * The plugin configuration file */ - public static abstract class Plotter { - - /** - * Get the column name for the plotted point - * - * @return the plotted point's column name - */ - public abstract String getColumnName(); - - /** - * Get the current value for the plotted point - * - * @return - */ - public abstract int getValue(); - - /** - * Called after the website graphs have been updated - */ - public void reset() { - } - - @Override - public int hashCode() { - return getColumnName().hashCode() + getValue(); - } - - @Override - public boolean equals(Object object) { - if (!(object instanceof Plotter)) { - return false; - } - - Plotter plotter = (Plotter) object; - return plotter.getColumnName().equals(getColumnName()) && plotter.getValue() == getValue(); - } - - } - - /** - * The metrics revision number - */ - private final static int REVISION = 4; - - /** - * The base url of the metrics domain - */ - private static final String BASE_URL = "http://metrics.griefcraft.com"; - - /** - * The url used to report a server's status - */ - private static final String REPORT_URL = "/report/%s"; - - /** - * The file where guid and opt out is stored in - */ - private static final String CONFIG_FILE = "plugins/PluginMetrics/config.yml"; - - /** - * Interval of time to ping in minutes - */ - private final static int PING_INTERVAL = 10; + private final YamlConfiguration configuration; /** * A map of the custom data plotters for plugins @@ -126,11 +64,6 @@ public class Metrics { private final Map> customData = Collections .synchronizedMap(new HashMap>()); - /** - * The plugin configuration file - */ - private final YamlConfiguration configuration; - /** * Unique server id */ @@ -199,6 +132,21 @@ public class Metrics { }, PING_INTERVAL * 1200, PING_INTERVAL * 1200); } + /** + * Check if mineshafter is present. If it is, we need to bypass it to send + * POST requests + * + * @return + */ + private boolean isMineshafterPresent() { + try { + Class.forName("mineshafter.MineServer"); + return true; + } catch (Exception e) { + return false; + } + } + /** * Generic method that posts a plugin to the metrics website * @@ -273,20 +221,72 @@ public class Metrics { } /** - * Check if mineshafter is present. If it is, we need to bypass it to send - * POST requests - * - * @return + * Interface used to collect custom data for a plugin */ - private boolean isMineshafterPresent() { - try { - Class.forName("mineshafter.MineServer"); - return true; - } catch (Exception e) { - return false; + public static abstract class Plotter { + + @Override + public boolean equals(Object object) { + if (!(object instanceof Plotter)) { + return false; + } + + Plotter plotter = (Plotter) object; + return plotter.getColumnName().equals(getColumnName()) && plotter.getValue() == getValue(); } + + /** + * Get the column name for the plotted point + * + * @return the plotted point's column name + */ + public abstract String getColumnName(); + + /** + * Get the current value for the plotted point + * + * @return + */ + public abstract int getValue(); + + @Override + public int hashCode() { + return getColumnName().hashCode() + getValue(); + } + + /** + * Called after the website graphs have been updated + */ + public void reset() { + } + } + /** + * The base url of the metrics domain + */ + private static final String BASE_URL = "http://metrics.griefcraft.com"; + + /** + * The file where guid and opt out is stored in + */ + private static final String CONFIG_FILE = "plugins/PluginMetrics/config.yml"; + + /** + * Interval of time to ping in minutes + */ + private final static int PING_INTERVAL = 10; + + /** + * The url used to report a server's status + */ + private static final String REPORT_URL = "/report/%s"; + + /** + * The metrics revision number + */ + private final static int REVISION = 4; + /** * Encode text as UTF-8 * diff --git a/src/main/java/net/citizensnpcs/util/NPCBuilder.java b/src/main/java/net/citizensnpcs/util/NPCBuilder.java index fbe538585..85b768cfe 100644 --- a/src/main/java/net/citizensnpcs/util/NPCBuilder.java +++ b/src/main/java/net/citizensnpcs/util/NPCBuilder.java @@ -35,6 +35,17 @@ import net.citizensnpcs.npc.entity.CitizensZombieNPC; import org.bukkit.entity.EntityType; public class NPCBuilder { + public CitizensNPC getByType(EntityType type, CitizensNPCManager npcManager, int id, String name) { + Class npcClass = types.get(type); + try { + return npcClass.getConstructor(CitizensNPCManager.class, int.class, String.class).newInstance(npcManager, + id, name); + } catch (Exception ex) { + ex.printStackTrace(); + } + return null; + } + private static final Map> types = new HashMap>(); static { @@ -65,15 +76,4 @@ public class NPCBuilder { types.put(EntityType.WOLF, CitizensWolfNPC.class); types.put(EntityType.ZOMBIE, CitizensZombieNPC.class); } - - public CitizensNPC getByType(EntityType type, CitizensNPCManager npcManager, int id, String name) { - Class npcClass = types.get(type); - try { - return npcClass.getConstructor(CitizensNPCManager.class, int.class, String.class).newInstance(npcManager, - id, name); - } catch (Exception ex) { - ex.printStackTrace(); - } - return null; - } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/util/Paginator.java b/src/main/java/net/citizensnpcs/util/Paginator.java index 09c349144..daebac50f 100644 --- a/src/main/java/net/citizensnpcs/util/Paginator.java +++ b/src/main/java/net/citizensnpcs/util/Paginator.java @@ -6,19 +6,13 @@ import java.util.List; import org.bukkit.entity.Player; public class Paginator { - private static final int LINES_PER_PAGE = 9; - - private final List lines = new ArrayList(); private String header; + private final List lines = new ArrayList(); public void addLine(String line) { lines.add(line); } - public void setHeaderText(String header) { - this.header = header; - } - public boolean sendPage(Player player, int page) { int pages = (int) ((lines.size() / LINES_PER_PAGE == 0) ? 1 : Math.ceil((double) lines.size() / LINES_PER_PAGE)); if (page < 0 || page > pages) @@ -35,4 +29,10 @@ public class Paginator { Messaging.send(player, line); return true; } + + public void setHeaderText(String header) { + this.header = header; + } + + private static final int LINES_PER_PAGE = 9; } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/util/StringHelper.java b/src/main/java/net/citizensnpcs/util/StringHelper.java index 92c802f44..2b6513015 100644 --- a/src/main/java/net/citizensnpcs/util/StringHelper.java +++ b/src/main/java/net/citizensnpcs/util/StringHelper.java @@ -4,6 +4,12 @@ import org.bukkit.ChatColor; public class StringHelper { + public static String capitalize(Object string) { + String capitalize = string.toString(); + return capitalize.replaceFirst(String.valueOf(capitalize.charAt(0)), String.valueOf(Character + .toUpperCase(capitalize.charAt(0)))); + } + public static int getLevenshteinDistance(String s, String t) { if (s == null || t == null) throw new IllegalArgumentException("Strings must not be null"); @@ -53,14 +59,6 @@ public class StringHelper { return p[n]; } - public static String wrap(Object string) { - return ChatColor.YELLOW + string.toString() + ChatColor.GREEN; - } - - public static String wrap(Object string, ChatColor after) { - return ChatColor.YELLOW + string.toString() + after; - } - public static String parseColors(Object string) { String parsed = string.toString(); for (ChatColor color : ChatColor.values()) { @@ -69,10 +67,12 @@ public class StringHelper { return parsed; } - public static String capitalize(Object string) { - String capitalize = string.toString(); - return capitalize.replaceFirst(String.valueOf(capitalize.charAt(0)), String.valueOf(Character - .toUpperCase(capitalize.charAt(0)))); + public static String wrap(Object string) { + return ChatColor.YELLOW + string.toString() + ChatColor.GREEN; + } + + public static String wrap(Object string, ChatColor after) { + return ChatColor.YELLOW + string.toString() + after; } public static String wrapHeader(Object string) {