Changes to waypoints

This commit is contained in:
fullwall 2012-03-02 18:36:54 +08:00
parent 89197d3acb
commit b26a495aff
32 changed files with 729 additions and 707 deletions

View File

@ -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<Character> 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<Trait> 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<Character> 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<Character> 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";
}

View File

@ -35,8 +35,8 @@ import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
public class EventListen implements Listener {
private final Map<Chunk, List<Integer>> toRespawn = new HashMap<Chunk, List<Integer>>();
private volatile CitizensNPCManager npcManager;
private final Map<Chunk, List<Integer>> toRespawn = new HashMap<Chunk, List<Integer>>();
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<Integer> respawn = new ArrayList<Integer>();
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<Integer> respawn = new ArrayList<Integer>();
respawn.add(npc.getId());
toRespawn.put(loc.getChunk(), respawn);
}
}
}
}

View File

@ -31,15 +31,15 @@ public class Settings {
public enum Setting {
CHAT_PREFIX("npc.chat.prefix", "[<npc>]: "),
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", "<b>You selected <a><npc><b>!"),
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;

View File

@ -18,7 +18,7 @@ public @interface Command {
String[] modifiers() default "";
String usage() default "";
String permission() default "";
String usage() default "";
}

View File

@ -28,8 +28,8 @@ import com.google.common.collect.Maps;
public class CommandContext {
protected String[] args;
protected final Map<String, String> valueFlags = Maps.newHashMap();
protected final Set<Character> flags = new HashSet<Character>();
protected final Map<String, String> 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<Character> getFlags() {
return flags;
}
@ -152,6 +191,10 @@ public class CommandContext {
return index + 1 < args.length ? args[index + 1] : def;
}
public Map<String, String> 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<String, String> 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);
}
}

View File

@ -38,8 +38,6 @@ public class CommandManager {
*/
private final Map<String, Method> commands = new HashMap<String, Method>();
private final Map<String, List<Command>> subCommands = new HashMap<String, List<Command>>();
// Stores the injector used to getInstance.
private Injector injector;
@ -50,6 +48,8 @@ public class CommandManager {
private final Map<Method, ServerCommand> serverCommands = new HashMap<Method, ServerCommand>();
private final Map<String, List<Command>> subCommands = new HashMap<String, List<Command>>();
/*
* 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<Command> getCommands(String command) {
if (subCommands.containsKey(command))
return subCommands.get(command);
List<Command> cmds = new ArrayList<Command>();
for (Entry<String, Method> 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<Command> getCommands(String command) {
if (subCommands.containsKey(command))
return subCommands.get(command);
List<Command> cmds = new ArrayList<Command>();
for (Entry<String, Method> 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);

View File

@ -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;

View File

@ -43,6 +43,24 @@ public class HelpCommands {
throw new CommandException("The page '" + page + "' does not exist.");
}
private List<String> getLines(Player player, String baseCommand) {
// Ensures that commands with multiple modifiers are only added once
Set<Command> cmds = new HashSet<Command>();
List<String> lines = new ArrayList<String>();
for (Command cmd : cmdManager.getCommands(baseCommand)) {
if (cmds.contains(cmd)
|| (!player.hasPermission("citizens.admin") && !player
.hasPermission("citizens." + cmd.permission())))
continue;
lines.add("<7>/<c>" + cmd.aliases()[0] + (cmd.usage().isEmpty() ? "" : " " + cmd.usage()) + " <7>- <e>"
+ 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<String> getLines(Player player, String baseCommand) {
// Ensures that commands with multiple modifiers are only added once
Set<Command> cmds = new HashSet<Command>();
List<String> lines = new ArrayList<String>();
for (Command cmd : cmdManager.getCommands(baseCommand)) {
if (cmds.contains(cmd)
|| (!player.hasPermission("citizens.admin") && !player
.hasPermission("citizens." + cmd.permission())))
continue;
lines.add("<7>/<c>" + cmd.aliases()[0] + (cmd.usage().isEmpty() ? "" : " " + cmd.usage()) + " <7>- <e>"
+ cmd.desc());
if (cmd.modifiers().length > 1)
cmds.add(cmd);
}
return lines;
}
}

View File

@ -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<Character> 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, " <a>ID: <e>" + npc.getId());
Messaging.send(player, " <a>Character: <e>"
+ (npc.getCharacter() != null ? npc.getCharacter().getName() : "None"));
Messaging.send(player, " <a>Type: <e>" + 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, "<a>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, "<a>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, " <a>ID: <e>" + npc.getId());
Messaging.send(player, " <a>Character: <e>"
+ (npc.getCharacter() != null ? npc.getCharacter().getName() : "None"));
Messaging.send(player, " <a>Type: <e>" + 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, "<a>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, "<a>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.");
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -10,12 +10,19 @@ import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
public abstract class Editor implements Listener {
private static final Map<String, Editor> editing = new HashMap<String, Editor>();
public abstract void begin();
public abstract void end();
private static final Map<String, Editor> editing = new HashMap<String, Editor>();
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());
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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<NPC> npcs = new ByIdArray<NPC>();
private final Storage saves;
private final NPCBuilder npcBuilder = new NPCBuilder();
private final ByIdArray<NPC> npcs = new ByIdArray<NPC>();
private final Citizens plugin;
private final Storage saves;
public CitizensNPCManager(Storage saves) {
plugin = (Citizens) Bukkit.getPluginManager().getPlugin("Citizens");

View File

@ -19,12 +19,12 @@ import com.google.common.collect.Lists;
public class CitizensAI implements AI {
private Runnable ai;
private boolean paused;
private final List<WeakReference<NavigationCallback>> callbacks = Lists.newArrayList();
private PathStrategy executing;
private final List<GoalEntry> executingGoals = Lists.newArrayList();
private final List<GoalEntry> 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<WeakReference<NavigationCallback>> itr = callbacks.iterator();
while (itr.hasNext()) {
NavigationCallback next = itr.next().get();

View File

@ -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) {

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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 + "}";

View File

@ -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<Waypoint> itr;
private final Iterable<Waypoint> provider;
public GenericWaypointCallback(Iterable<Waypoint> 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;
}
}

View File

@ -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<Waypoint> {
private final GenericWaypointCallback callback = new GenericWaypointCallback(this);
private final List<Waypoint> 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<Waypoint> 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;
}
}
};
}

View File

@ -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();
}

View File

@ -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<WaypointProvider> providers = DefaultInstanceFactory.create();
public static void registerWaypointProvider(Class<? extends WaypointProvider> clazz, String name) {
providers.register(clazz, name);
}
private static final InstanceFactory<WaypointProvider> providers = DefaultInstanceFactory.create();
static {
providers.register(LinearWaypointProvider.class, "linear");
}

View File

@ -6,12 +6,12 @@ import java.util.Iterator;
import java.util.NoSuchElementException;
public class ByIdArray<T> implements Iterable<T> {
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);

View File

@ -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<Plugin, Set<Plotter>> customData = Collections
.synchronizedMap(new HashMap<Plugin, Set<Plotter>>());
/**
* 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
*

View File

@ -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<? extends CitizensNPC> 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<EntityType, Class<? extends CitizensNPC>> types = new HashMap<EntityType, Class<? extends CitizensNPC>>();
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<? extends CitizensNPC> 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;
}
}

View File

@ -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<String> lines = new ArrayList<String>();
private String header;
private final List<String> lines = new ArrayList<String>();
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;
}

View File

@ -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) {