diff --git a/src/main/java/net/citizensnpcs/EventListen.java b/src/main/java/net/citizensnpcs/EventListen.java index f10a0a234..4dda9be7a 100644 --- a/src/main/java/net/citizensnpcs/EventListen.java +++ b/src/main/java/net/citizensnpcs/EventListen.java @@ -83,12 +83,14 @@ public class EventListen implements Listener { @EventHandler(ignoreCancelled = true) public void onChunkUnload(ChunkUnloadEvent event) { ChunkCoord coord = toCoord(event.getChunk()); + Location cachedLocation = new Location(null, 0, 0, 0); for (NPC npc : npcRegistry) { if (!npc.isSpawned()) continue; - Location loc = npc.getBukkitEntity().getLocation(); - boolean sameChunkCoordinates = coord.z == loc.getBlockZ() >> 4 && coord.x == loc.getBlockX() >> 4; - if (sameChunkCoordinates && event.getWorld().equals(loc.getWorld())) { + cachedLocation = npc.getBukkitEntity().getLocation(cachedLocation); + boolean sameChunkCoordinates = coord.z == cachedLocation.getBlockZ() >> 4 + && coord.x == cachedLocation.getBlockX() >> 4; + if (sameChunkCoordinates && event.getWorld().equals(cachedLocation.getWorld())) { npc.despawn(DespawnReason.CHUNK_UNLOAD); toRespawn.put(coord, npc.getId()); Messaging.debug("Despawned", npc.getId(), "due to chunk unload at [" + coord.x + "," diff --git a/src/main/java/net/citizensnpcs/Metrics.java b/src/main/java/net/citizensnpcs/Metrics.java index f912a8548..2352d1d6d 100644 --- a/src/main/java/net/citizensnpcs/Metrics.java +++ b/src/main/java/net/citizensnpcs/Metrics.java @@ -69,48 +69,6 @@ import org.bukkit.scheduler.BukkitTask; */ public class Metrics { - /** - * The current revision number - */ - private final static int REVISION = 6; - - /** - * The base url of the metrics domain - */ - private static final String BASE_URL = "http://mcstats.org"; - - /** - * The url used to report a server's status - */ - private static final String REPORT_URL = "/report/%s"; - - /** - * The separator to use for custom data. This MUST NOT change unless you are - * hosting your own version of metrics and want to change it. - */ - private static final String CUSTOM_DATA_SEPARATOR = "~~"; - - /** - * Interval of time to ping (in minutes) - */ - private static final int PING_INTERVAL = 10; - - /** - * The plugin this metrics submits for - */ - private final Plugin plugin; - - /** - * All of the custom graphs to submit to metrics - */ - private final Set graphs = Collections.synchronizedSet(new HashSet()); - - /** - * The default graph, used for addCustomData when you don't want a specific - * graph - */ - private final Graph defaultGraph = new Graph("Default"); - /** * The plugin configuration file */ @@ -121,21 +79,37 @@ public class Metrics { */ private final File configurationFile; - /** - * Unique server id - */ - private final String guid; - /** * Debug mode */ private final boolean debug; + /** + * The default graph, used for addCustomData when you don't want a specific + * graph + */ + private final Graph defaultGraph = new Graph("Default"); + + /** + * All of the custom graphs to submit to metrics + */ + private final Set graphs = Collections.synchronizedSet(new HashSet()); + + /** + * Unique server id + */ + private final String guid; + /** * Lock for synchronization */ private final Object optOutLock = new Object(); + /** + * The plugin this metrics submits for + */ + private final Plugin plugin; + /** * The scheduled task */ @@ -168,6 +142,39 @@ public class Metrics { debug = configuration.getBoolean("debug", false); } + /** + * Adds a custom data plotter to the default graph + * + * @param plotter + * The plotter to use to plot custom data + */ + public void addCustomData(final Plotter plotter) { + if (plotter == null) { + throw new IllegalArgumentException("Plotter cannot be null"); + } + + // Add the plotter to the graph o/ + defaultGraph.addPlotter(plotter); + + // Ensure the default graph is included in the submitted graphs + graphs.add(defaultGraph); + } + + /** + * Add a Graph object to Metrics that represents data for the plugin that + * should be sent to the backend + * + * @param graph + * The name of the graph + */ + public void addGraph(final Graph graph) { + if (graph == null) { + throw new IllegalArgumentException("Graph cannot be null"); + } + + graphs.add(graph); + } + /** * Construct and create a Graph that can be used to separate specific * plotters to their own graphs on the metrics website. Plotters can be @@ -193,154 +200,6 @@ public class Metrics { return graph; } - /** - * Add a Graph object to Metrics that represents data for the plugin that - * should be sent to the backend - * - * @param graph - * The name of the graph - */ - public void addGraph(final Graph graph) { - if (graph == null) { - throw new IllegalArgumentException("Graph cannot be null"); - } - - graphs.add(graph); - } - - /** - * Adds a custom data plotter to the default graph - * - * @param plotter - * The plotter to use to plot custom data - */ - public void addCustomData(final Plotter plotter) { - if (plotter == null) { - throw new IllegalArgumentException("Plotter cannot be null"); - } - - // Add the plotter to the graph o/ - defaultGraph.addPlotter(plotter); - - // Ensure the default graph is included in the submitted graphs - graphs.add(defaultGraph); - } - - /** - * Start measuring statistics. This will immediately create an async - * repeating task as the plugin and send the initial data to the metrics - * backend, and then after that it will post in increments of PING_INTERVAL - * * 1200 ticks. - * - * @return True if statistics measuring is running, otherwise false. - */ - public boolean start() { - synchronized (optOutLock) { - // Did we opt out? - if (isOptOut()) { - return false; - } - - // Is metrics already running? - if (task != null) { - return true; - } - - // Begin hitting the server with glorious data - task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() { - - private boolean firstPost = true; - - @Override - public void run() { - try { - // This has to be synchronized or it can collide with - // the disable method. - synchronized (optOutLock) { - // Disable Task, if it is running and the server - // owner decided to opt-out - if (isOptOut() && task != null) { - task.cancel(); - task = null; - // Tell all plotters to stop gathering - // information. - for (Graph graph : graphs) { - graph.onOptOut(); - } - } - } - - // We use the inverse of firstPost because if it is the - // first time we are posting, - // it is not a interval ping, so it evaluates to FALSE - // Each time thereafter it will evaluate to TRUE, i.e - // PING! - postPlugin(!firstPost); - - // After the first post we set firstPost to false - // Each post thereafter will be a ping - firstPost = false; - } catch (IOException e) { - if (debug) { - Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage()); - } - } - } - }, 0, PING_INTERVAL * 1200); - - return true; - } - } - - /** - * Has the server owner denied plugin metrics? - * - * @return true if metrics should be opted out of it - */ - public boolean isOptOut() { - synchronized (optOutLock) { - try { - // Reload the metrics file - configuration.load(getConfigFile()); - } catch (IOException ex) { - if (debug) { - Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); - } - return true; - } catch (InvalidConfigurationException ex) { - if (debug) { - Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); - } - return true; - } - return configuration.getBoolean("opt-out", false); - } - } - - /** - * Enables metrics for the server by setting "opt-out" to false in the - * config file and starting the metrics task. - * - * @throws IOException - */ - public void enable() throws IOException { - // This has to be synchronized or it can collide with the check in the - // task. - synchronized (optOutLock) { - // Check if the server owner has already set opt-out, if not, set - // it. - if (isOptOut()) { - configuration.set("opt-out", false); - configuration.save(configurationFile); - } - - // Enable Task, if it is not running - if (task == null) { - start(); - } - } - } - /** * Disables metrics for the server by setting "opt-out" to true in the * config file and canceling the metrics task. @@ -366,6 +225,30 @@ public class Metrics { } } + /** + * Enables metrics for the server by setting "opt-out" to false in the + * config file and starting the metrics task. + * + * @throws IOException + */ + public void enable() throws IOException { + // This has to be synchronized or it can collide with the check in the + // task. + synchronized (optOutLock) { + // Check if the server owner has already set opt-out, if not, set + // it. + if (isOptOut()) { + configuration.set("opt-out", false); + configuration.save(configurationFile); + } + + // Enable Task, if it is not running + if (task == null) { + start(); + } + } + } + /** * Gets the File object of the config file that should be used to store data * such as the GUID and opt-out status @@ -385,6 +268,46 @@ public class Metrics { return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml"); } + /** + * Check if mineshafter is present. If it is, we need to bypass it to send + * POST requests + * + * @return true if mineshafter is installed on the server + */ + private boolean isMineshafterPresent() { + try { + Class.forName("mineshafter.MineServer"); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * Has the server owner denied plugin metrics? + * + * @return true if metrics should be opted out of it + */ + public boolean isOptOut() { + synchronized (optOutLock) { + try { + // Reload the metrics file + configuration.load(getConfigFile()); + } catch (IOException ex) { + if (debug) { + Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); + } + return true; + } catch (InvalidConfigurationException ex) { + if (debug) { + Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); + } + return true; + } + return configuration.getBoolean("opt-out", false); + } + } + /** * Generic method that posts a plugin to the metrics website */ @@ -516,54 +439,71 @@ public class Metrics { } /** - * Check if mineshafter is present. If it is, we need to bypass it to send - * POST requests + * Start measuring statistics. This will immediately create an async + * repeating task as the plugin and send the initial data to the metrics + * backend, and then after that it will post in increments of PING_INTERVAL + * * 1200 ticks. * - * @return true if mineshafter is installed on the server + * @return True if statistics measuring is running, otherwise false. */ - private boolean isMineshafterPresent() { - try { - Class.forName("mineshafter.MineServer"); + public boolean start() { + synchronized (optOutLock) { + // Did we opt out? + if (isOptOut()) { + return false; + } + + // Is metrics already running? + if (task != null) { + return true; + } + + // Begin hitting the server with glorious data + task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() { + + private boolean firstPost = true; + + @Override + public void run() { + try { + // This has to be synchronized or it can collide with + // the disable method. + synchronized (optOutLock) { + // Disable Task, if it is running and the server + // owner decided to opt-out + if (isOptOut() && task != null) { + task.cancel(); + task = null; + // Tell all plotters to stop gathering + // information. + for (Graph graph : graphs) { + graph.onOptOut(); + } + } + } + + // We use the inverse of firstPost because if it is the + // first time we are posting, + // it is not a interval ping, so it evaluates to FALSE + // Each time thereafter it will evaluate to TRUE, i.e + // PING! + postPlugin(!firstPost); + + // After the first post we set firstPost to false + // Each post thereafter will be a ping + firstPost = false; + } catch (IOException e) { + if (debug) { + Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage()); + } + } + } + }, 0, PING_INTERVAL * 1200); + return true; - } catch (Exception e) { - return false; } } - /** - *

- * Encode a key/value data pair to be used in a HTTP post request. This - * INCLUDES a & so the first key/value pair MUST be included manually, e.g: - *

- * - * StringBuffer data = new StringBuffer(); - * data.append(encode("guid")).append('=').append(encode(guid)); - * encodeDataPair(data, "version", description.getVersion()); - * - * - * @param buffer - * the stringbuilder to append the data pair onto - * @param key - * the key value - * @param value - * the value - */ - private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) - throws UnsupportedEncodingException { - buffer.append('&').append(encode(key)).append('=').append(encode(value)); - } - - /** - * Encode text as UTF-8 - * - * @param text - * the text to encode - * @return the encoded text, as UTF-8 - */ - private static String encode(final String text) throws UnsupportedEncodingException { - return URLEncoder.encode(text, "UTF-8"); - } - /** * Represents a custom graph on the website */ @@ -584,15 +524,6 @@ public class Metrics { this.name = name; } - /** - * Gets the graph's name - * - * @return the Graph's name - */ - public String getName() { - return name; - } - /** * Add a plotter to the graph, which will be used to plot entries * @@ -603,14 +534,23 @@ public class Metrics { plotters.add(plotter); } + @Override + public boolean equals(final Object object) { + if (!(object instanceof Graph)) { + return false; + } + + final Graph graph = (Graph) object; + return graph.name.equals(name); + } + /** - * Remove a plotter from the graph + * Gets the graph's name * - * @param plotter - * the plotter to remove from the graph + * @return the Graph's name */ - public void removePlotter(final Plotter plotter) { - plotters.remove(plotter); + public String getName() { + return name; } /** @@ -627,16 +567,6 @@ public class Metrics { return name.hashCode(); } - @Override - public boolean equals(final Object object) { - if (!(object instanceof Graph)) { - return false; - } - - final Graph graph = (Graph) object; - return graph.name.equals(name); - } - /** * Called when the server owner decides to opt-out of Metrics while the * server is running. @@ -644,6 +574,16 @@ public class Metrics { protected void onOptOut() { } + /** + * Remove a plotter from the graph + * + * @param plotter + * the plotter to remove from the graph + */ + public void removePlotter(final Plotter plotter) { + plotters.remove(plotter); + } + } /** @@ -674,16 +614,15 @@ public class Metrics { this.name = name; } - /** - * Get the current value for the plotted point. Since this function - * defers to an external function it may or may not return immediately - * thus cannot be guaranteed to be thread friendly or safe. This - * function can be called from any thread so care should be taken when - * accessing resources that need to be synchronized. - * - * @return the current value for the point to be plotted. - */ - public abstract int getValue(); + @Override + public boolean equals(final Object object) { + if (!(object instanceof Plotter)) { + return false; + } + + final Plotter plotter = (Plotter) object; + return plotter.name.equals(name) && plotter.getValue() == getValue(); + } /** * Get the column name for the plotted point @@ -695,26 +634,87 @@ public class Metrics { } /** - * Called after the website graphs have been updated + * Get the current value for the plotted point. Since this function + * defers to an external function it may or may not return immediately + * thus cannot be guaranteed to be thread friendly or safe. This + * function can be called from any thread so care should be taken when + * accessing resources that need to be synchronized. + * + * @return the current value for the point to be plotted. */ - public void reset() { - } + public abstract int getValue(); @Override public int hashCode() { return getColumnName().hashCode(); } - @Override - public boolean equals(final Object object) { - if (!(object instanceof Plotter)) { - return false; - } - - final Plotter plotter = (Plotter) object; - return plotter.name.equals(name) && plotter.getValue() == 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://mcstats.org"; + + /** + * The separator to use for custom data. This MUST NOT change unless you are + * hosting your own version of metrics and want to change it. + */ + private static final String CUSTOM_DATA_SEPARATOR = "~~"; + + /** + * Interval of time to ping (in minutes) + */ + private static final int PING_INTERVAL = 10; + + /** + * The url used to report a server's status + */ + private static final String REPORT_URL = "/report/%s"; + + /** + * The current revision number + */ + private final static int REVISION = 6; + + /** + * Encode text as UTF-8 + * + * @param text + * the text to encode + * @return the encoded text, as UTF-8 + */ + private static String encode(final String text) throws UnsupportedEncodingException { + return URLEncoder.encode(text, "UTF-8"); + } + + /** + *

+ * Encode a key/value data pair to be used in a HTTP post request. This + * INCLUDES a & so the first key/value pair MUST be included manually, e.g: + *

+ * + * StringBuffer data = new StringBuffer(); + * data.append(encode("guid")).append('=').append(encode(guid)); + * encodeDataPair(data, "version", description.getVersion()); + * + * + * @param buffer + * the stringbuilder to append the data pair onto + * @param key + * the key value + * @param value + * the value + */ + private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) + throws UnsupportedEncodingException { + buffer.append('&').append(encode(key)).append('=').append(encode(value)); + } + } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/NPCDataStore.java b/src/main/java/net/citizensnpcs/NPCDataStore.java index e2de85d7a..07001b4a4 100644 --- a/src/main/java/net/citizensnpcs/NPCDataStore.java +++ b/src/main/java/net/citizensnpcs/NPCDataStore.java @@ -94,7 +94,6 @@ public class NPCDataStore { saves = new YamlStorage(new File(folder, Setting.STORAGE_FILE.asString()), "Citizens NPC Storage"); if (!saves.load()) return null; - Messaging.logTr(Messages.SAVE_METHOD_SET_NOTIFICATION, saves.toString()); return new NPCDataStore(saves); } } diff --git a/src/main/java/net/citizensnpcs/command/command/NPCCommands.java b/src/main/java/net/citizensnpcs/command/command/NPCCommands.java index e4b2fc2d0..b80e7069e 100644 --- a/src/main/java/net/citizensnpcs/command/command/NPCCommands.java +++ b/src/main/java/net/citizensnpcs/command/command/NPCCommands.java @@ -24,6 +24,7 @@ import net.citizensnpcs.command.exception.CommandException; import net.citizensnpcs.command.exception.NoPermissionsException; import net.citizensnpcs.command.exception.ServerCommandException; import net.citizensnpcs.npc.CitizensNPC; +import net.citizensnpcs.npc.EntityControllers; import net.citizensnpcs.npc.NPCSelector; import net.citizensnpcs.npc.Template; import net.citizensnpcs.trait.Age; @@ -814,7 +815,12 @@ public class NPCCommands { Messaging.sendErrorTr(sender, Messages.NPC_NAME_TOO_LONG); newName = newName.substring(0, 15); } + Location prev = npc.isSpawned() ? npc.getBukkitEntity().getLocation() : null; + npc.despawn(); npc.setName(newName); + if (prev != null) + npc.spawn(prev); + Messaging.sendTr(sender, Messages.NPC_RENAMED, oldName, newName); } @@ -989,6 +995,22 @@ public class NPCCommands { Messaging.sendTr(sender, Messages.NPC_TELEPORTED, npc.getName()); } + @Command( + aliases = { "npc" }, + usage = "type", + desc = "Sets an NPC's entity type", + modifiers = { "type" }, + min = 2, + max = 2, + permission = "npc.type") + public void type(CommandContext args, CommandSender sender, NPC npc) throws CommandException { + EntityType type = Util.matchEntityType(args.getString(1)); + if (type == null) + throw new CommandException(Messages.INVALID_ENTITY_TYPE, args.getString(1)); + ((CitizensNPC) npc).setEntityController(EntityControllers.createForType(type)); + Messaging.sendTr(sender, Messages.ENTITY_TYPE_SET, npc.getName(), args.getString(1)); + } + @Command( aliases = { "npc" }, usage = "vulnerable (-t)", diff --git a/src/main/java/net/citizensnpcs/editor/EndermanEquipper.java b/src/main/java/net/citizensnpcs/editor/EndermanEquipper.java new file mode 100644 index 000000000..cf43e608b --- /dev/null +++ b/src/main/java/net/citizensnpcs/editor/EndermanEquipper.java @@ -0,0 +1,42 @@ +package net.citizensnpcs.editor; + +import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.api.trait.trait.Equipment; +import net.citizensnpcs.util.Messages; +import net.citizensnpcs.util.Messaging; + +import org.bukkit.Material; +import org.bukkit.entity.Enderman; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.MaterialData; + +public class EndermanEquipper implements Equipper { + @Override + public void equip(Player equipper, NPC npc) { + ItemStack hand = equipper.getItemInHand(); + if (!hand.getType().isBlock()) { + Messaging.sendErrorTr(equipper, Messages.EQUIPMENT_EDITOR_INVALID_BLOCK); + return; + } + + MaterialData carried = ((Enderman) npc.getBukkitEntity()).getCarriedMaterial(); + if (carried.getItemType() == Material.AIR) { + if (hand.getType() == Material.AIR) { + Messaging.sendErrorTr(equipper, Messages.EQUIPMENT_EDITOR_INVALID_BLOCK); + return; + } + } else { + equipper.getWorld() + .dropItemNaturally(npc.getBukkitEntity().getLocation(), carried.toItemStack(1)); + ((Enderman) npc.getBukkitEntity()).setCarriedMaterial(hand.getData()); + } + + ItemStack set = hand.clone(); + if (set.getType() != Material.AIR) { + set.setAmount(1); + hand.setAmount(hand.getAmount() - 1); + } + npc.getTrait(Equipment.class).set(0, set); + } +} diff --git a/src/main/java/net/citizensnpcs/editor/Equipable.java b/src/main/java/net/citizensnpcs/editor/Equipable.java deleted file mode 100644 index 9da2bc045..000000000 --- a/src/main/java/net/citizensnpcs/editor/Equipable.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.citizensnpcs.editor; - -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - -public interface Equipable { - public void equip(Player equipper, ItemStack toEquip); -} \ 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 0a00d85d6..3731ade03 100644 --- a/src/main/java/net/citizensnpcs/editor/EquipmentEditor.java +++ b/src/main/java/net/citizensnpcs/editor/EquipmentEditor.java @@ -1,10 +1,13 @@ package net.citizensnpcs.editor; +import java.util.Map; + import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.util.Messages; import net.citizensnpcs.util.Messaging; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.Event.Result; import org.bukkit.event.EventHandler; @@ -13,6 +16,8 @@ import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; +import com.google.common.collect.Maps; + public class EquipmentEditor extends Editor { private final NPC npc; private final Player player; @@ -40,14 +45,23 @@ public class EquipmentEditor extends Editor { @EventHandler public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { - if (!event.getPlayer().equals(player) + if (!npc.isSpawned() || !event.getPlayer().equals(player) || !npc.equals(CitizensAPI.getNPCRegistry().getNPC(event.getRightClicked()))) return; - if (npc instanceof Equipable) { - ItemStack hand = event.getPlayer().getItemInHand(); - ((Equipable) npc).equip(event.getPlayer(), hand); - event.getPlayer().setItemInHand(hand.getAmount() > 0 ? hand : null); - } + Equipper equipper = EQUIPPERS.get(npc.getBukkitEntity().getType()); + if (equipper == null) + return; + ItemStack hand = event.getPlayer().getItemInHand(); + equipper.equip(event.getPlayer(), npc); + event.getPlayer().setItemInHand(hand.getAmount() > 0 ? hand : null); + } + + private static final Map EQUIPPERS = Maps.newEnumMap(EntityType.class); + static { + EQUIPPERS.put(EntityType.PIG, new PigEquipper()); + EQUIPPERS.put(EntityType.PLAYER, new HumanEquipper()); + EQUIPPERS.put(EntityType.SHEEP, new SheepEquipper()); + EQUIPPERS.put(EntityType.ENDERMAN, new EndermanEquipper()); } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/editor/Equipper.java b/src/main/java/net/citizensnpcs/editor/Equipper.java new file mode 100644 index 000000000..f24ff64ba --- /dev/null +++ b/src/main/java/net/citizensnpcs/editor/Equipper.java @@ -0,0 +1,9 @@ +package net.citizensnpcs.editor; + +import net.citizensnpcs.api.npc.NPC; + +import org.bukkit.entity.Player; + +public interface Equipper { + public void equip(Player equipper, NPC toEquip); +} \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/editor/HumanEquipper.java b/src/main/java/net/citizensnpcs/editor/HumanEquipper.java new file mode 100644 index 000000000..0cd2262dd --- /dev/null +++ b/src/main/java/net/citizensnpcs/editor/HumanEquipper.java @@ -0,0 +1,84 @@ +package net.citizensnpcs.editor; + +import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.api.trait.trait.Equipment; +import net.citizensnpcs.util.Messages; +import net.citizensnpcs.util.Messaging; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class HumanEquipper implements Equipper { + + @Override + public void equip(Player equipper, NPC toEquip) { + ItemStack hand = equipper.getItemInHand(); + Equipment trait = toEquip.getTrait(Equipment.class); + int slot = 0; + Material type = hand == null ? Material.AIR : hand.getType(); + // First, determine the slot to edit + switch (type) { + case SKULL_ITEM: + case PUMPKIN: + case JACK_O_LANTERN: + case LEATHER_HELMET: + case CHAINMAIL_HELMET: + case GOLD_HELMET: + case IRON_HELMET: + case DIAMOND_HELMET: + if (!equipper.isSneaking()) + slot = 1; + break; + case LEATHER_CHESTPLATE: + case CHAINMAIL_CHESTPLATE: + case GOLD_CHESTPLATE: + case IRON_CHESTPLATE: + case DIAMOND_CHESTPLATE: + if (!equipper.isSneaking()) + slot = 2; + break; + case LEATHER_LEGGINGS: + case CHAINMAIL_LEGGINGS: + case GOLD_LEGGINGS: + case IRON_LEGGINGS: + case DIAMOND_LEGGINGS: + if (!equipper.isSneaking()) + slot = 3; + break; + case LEATHER_BOOTS: + case CHAINMAIL_BOOTS: + case GOLD_BOOTS: + case IRON_BOOTS: + case DIAMOND_BOOTS: + if (!equipper.isSneaking()) + slot = 4; + break; + case AIR: + for (int i = 0; i < 5; i++) { + if (trait.get(i) != null && trait.get(i).getType() != Material.AIR) { + equipper.getWorld().dropItemNaturally(toEquip.getBukkitEntity().getLocation(), + trait.get(i)); + trait.set(i, null); + } + } + Messaging.sendTr(equipper, Messages.EQUIPMENT_EDITOR_ALL_ITEMS_REMOVED, toEquip.getName()); + break; + default: + break; + } + // Drop any previous equipment on the ground + ItemStack equippedItem = trait.get(slot); + if (equippedItem != null && equippedItem.getType() != Material.AIR) + equipper.getWorld().dropItemNaturally(toEquip.getBukkitEntity().getLocation(), equippedItem); + + // Now edit the equipment based on the slot + if (type != Material.AIR) { + // Set the proper slot with one of the item + ItemStack clone = hand.clone(); + clone.setAmount(1); + trait.set(slot, clone); + hand.setAmount(hand.getAmount() - 1); + } + } +} diff --git a/src/main/java/net/citizensnpcs/editor/PigEquipper.java b/src/main/java/net/citizensnpcs/editor/PigEquipper.java new file mode 100644 index 000000000..0509a5216 --- /dev/null +++ b/src/main/java/net/citizensnpcs/editor/PigEquipper.java @@ -0,0 +1,30 @@ +package net.citizensnpcs.editor; + +import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.trait.Saddle; +import net.citizensnpcs.util.Messages; +import net.citizensnpcs.util.Messaging; + +import org.bukkit.Material; +import org.bukkit.entity.Pig; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class PigEquipper implements Equipper { + @Override + public void equip(Player equipper, NPC toEquip) { + ItemStack hand = equipper.getItemInHand(); + Pig pig = (Pig) toEquip.getBukkitEntity(); + if (hand.getType() == Material.SADDLE) { + if (!pig.hasSaddle()) { + toEquip.getTrait(Saddle.class).toggle(); + hand.setAmount(0); + Messaging.sendTr(equipper, Messages.SADDLED_SET, toEquip.getName()); + } + } else if (pig.hasSaddle()) { + equipper.getWorld().dropItemNaturally(pig.getLocation(), new ItemStack(Material.SADDLE, 1)); + toEquip.getTrait(Saddle.class).toggle(); + Messaging.sendTr(equipper, Messages.SADDLED_STOPPED, toEquip.getName()); + } + } +} diff --git a/src/main/java/net/citizensnpcs/editor/SheepEquipper.java b/src/main/java/net/citizensnpcs/editor/SheepEquipper.java new file mode 100644 index 000000000..578d28d60 --- /dev/null +++ b/src/main/java/net/citizensnpcs/editor/SheepEquipper.java @@ -0,0 +1,38 @@ +package net.citizensnpcs.editor; + +import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.trait.Sheared; +import net.citizensnpcs.trait.WoolColor; +import net.citizensnpcs.util.Messages; +import net.citizensnpcs.util.Messaging; + +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.entity.Sheep; +import org.bukkit.inventory.ItemStack; + +public class SheepEquipper implements Equipper { + @Override + public void equip(Player equipper, NPC toEquip) { + ItemStack hand = equipper.getItemInHand(); + Sheep sheep = (Sheep) toEquip.getBukkitEntity(); + if (hand.getType() == Material.SHEARS) { + Messaging.sendTr(equipper, toEquip.getTrait(Sheared.class).toggle() ? Messages.SHEARED_SET + : Messages.SHEARED_STOPPED, toEquip.getName()); + } else if (hand.getType() == Material.INK_SACK) { + if (sheep.getColor() == DyeColor.getByData((byte) (15 - hand.getData().getData()))) + return; + + DyeColor color = DyeColor.getByData((byte) (15 - hand.getData().getData())); + toEquip.getTrait(WoolColor.class).setColor(color); + Messaging.sendTr(equipper, Messages.EQUIPMENT_EDITOR_SHEEP_COLOURED, toEquip.getName(), color + .name().toLowerCase().replace("_", " ")); + + hand.setAmount(hand.getAmount() - 1); + } else { + toEquip.getTrait(WoolColor.class).setColor(DyeColor.WHITE); + Messaging.sendTr(equipper, Messages.EQUIPMENT_EDITOR_SHEEP_COLOURED, toEquip.getName(), "white"); + } + } +} diff --git a/src/main/java/net/citizensnpcs/npc/AbstractEntityController.java b/src/main/java/net/citizensnpcs/npc/AbstractEntityController.java new file mode 100644 index 000000000..b3041b065 --- /dev/null +++ b/src/main/java/net/citizensnpcs/npc/AbstractEntityController.java @@ -0,0 +1,30 @@ +package net.citizensnpcs.npc; + +import net.citizensnpcs.api.npc.NPC; + +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; + +public abstract class AbstractEntityController implements EntityController { + private LivingEntity bukkitEntity; + + protected abstract LivingEntity createEntity(Location at, NPC npc); + + @Override + public LivingEntity getBukkitEntity() { + return bukkitEntity; + } + + @Override + public void remove() { + if (bukkitEntity == null) + return; + bukkitEntity.remove(); + bukkitEntity = null; + } + + @Override + public void spawn(Location at, NPC npc) { + bukkitEntity = createEntity(at, npc); + } +} \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/CitizensNPC.java b/src/main/java/net/citizensnpcs/npc/CitizensNPC.java index 7b11176ec..e7bf6753a 100644 --- a/src/main/java/net/citizensnpcs/npc/CitizensNPC.java +++ b/src/main/java/net/citizensnpcs/npc/CitizensNPC.java @@ -25,29 +25,30 @@ import net.citizensnpcs.util.NMS; import net.citizensnpcs.util.Util; import net.minecraft.server.v1_4_5.EntityLiving; -import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_4_5.entity.CraftLivingEntity; import org.bukkit.entity.LivingEntity; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.metadata.FixedMetadataValue; import com.google.common.base.Function; +import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -public abstract class CitizensNPC extends AbstractNPC { - protected EntityLiving mcEntity; +public class CitizensNPC extends AbstractNPC { + private EntityController entityController; private final CitizensNavigator navigator = new CitizensNavigator(this); private final List removedTraits = Lists.newArrayList(); - protected CitizensNPC(int id, String name) { + public CitizensNPC(int id, String name, EntityController entityController) { super(id, name); + Preconditions.checkNotNull(entityController); + this.entityController = entityController; } - protected abstract EntityLiving createHandle(Location loc); - @Override public boolean despawn(DespawnReason reason) { if (!isSpawned()) @@ -67,21 +68,19 @@ public abstract class CitizensNPC extends AbstractNPC { data().remove("selectors"); for (Trait trait : traits.values()) trait.onDespawn(); - getBukkitEntity().remove(); - mcEntity = null; + entityController.remove(); return true; } @Override public LivingEntity getBukkitEntity() { - if (mcEntity == null) - return null; - return (LivingEntity) mcEntity.getBukkitEntity(); + return entityController.getBukkitEntity(); } + @Deprecated public EntityLiving getHandle() { - return mcEntity; + return ((CraftLivingEntity) getBukkitEntity()).getHandle(); } @Override @@ -91,7 +90,7 @@ public abstract class CitizensNPC extends AbstractNPC { @Override public boolean isSpawned() { - return mcEntity != null; + return getBukkitEntity() != null; } public void load(final DataKey root) { @@ -177,35 +176,49 @@ public abstract class CitizensNPC extends AbstractNPC { removeTraitData(root); } + public void setEntityController(EntityController newController) { + Preconditions.checkNotNull(newController); + boolean wasSpawned = isSpawned(); + Location prev = null; + if (wasSpawned) { + prev = getBukkitEntity().getLocation(); + despawn(); + } + entityController = newController; + if (wasSpawned) + spawn(prev); + } + @Override - public boolean spawn(Location loc) { - Validate.notNull(loc, "location cannot be null"); + public boolean spawn(Location at) { + Preconditions.checkNotNull(at, "location cannot be null"); if (isSpawned()) return false; - mcEntity = createHandle(loc); - boolean couldSpawn = !Util.isLoaded(loc) ? false : mcEntity.world.addEntity(mcEntity, + entityController.spawn(at, this); + EntityLiving mcEntity = getHandle(); + boolean couldSpawn = !Util.isLoaded(at) ? false : mcEntity.world.addEntity(mcEntity, SpawnReason.CUSTOM); if (!couldSpawn) { // we need to wait for a chunk load before trying to spawn mcEntity = null; - EventListen.addForRespawn(loc, getId()); + EventListen.addForRespawn(at, getId()); return true; } - NPCSpawnEvent spawnEvent = new NPCSpawnEvent(this, loc); + NPCSpawnEvent spawnEvent = new NPCSpawnEvent(this, at); Bukkit.getPluginManager().callEvent(spawnEvent); if (spawnEvent.isCancelled()) { mcEntity = null; return false; } - NMS.setHeadYaw(mcEntity, loc.getYaw()); + NMS.setHeadYaw(mcEntity, at.getYaw()); getBukkitEntity().setMetadata(NPC_METADATA_MARKER, new FixedMetadataValue(CitizensAPI.getPlugin(), true)); // Set the spawned state - getTrait(CurrentLocation.class).setLocation(loc); + getTrait(CurrentLocation.class).setLocation(at); getTrait(Spawned.class).setSpawned(true); navigator.onSpawn(); diff --git a/src/main/java/net/citizensnpcs/npc/CitizensNPCRegistry.java b/src/main/java/net/citizensnpcs/npc/CitizensNPCRegistry.java index e3cb37186..8c9cc489b 100644 --- a/src/main/java/net/citizensnpcs/npc/CitizensNPCRegistry.java +++ b/src/main/java/net/citizensnpcs/npc/CitizensNPCRegistry.java @@ -1,43 +1,12 @@ package net.citizensnpcs.npc; -import java.util.EnumMap; import java.util.Iterator; -import java.util.Map; import net.citizensnpcs.NPCDataStore; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPCRegistry; import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.npc.ai.NPCHolder; -import net.citizensnpcs.npc.entity.CitizensBatNPC; -import net.citizensnpcs.npc.entity.CitizensBlazeNPC; -import net.citizensnpcs.npc.entity.CitizensCaveSpiderNPC; -import net.citizensnpcs.npc.entity.CitizensChickenNPC; -import net.citizensnpcs.npc.entity.CitizensCowNPC; -import net.citizensnpcs.npc.entity.CitizensCreeperNPC; -import net.citizensnpcs.npc.entity.CitizensEnderDragonNPC; -import net.citizensnpcs.npc.entity.CitizensEndermanNPC; -import net.citizensnpcs.npc.entity.CitizensGhastNPC; -import net.citizensnpcs.npc.entity.CitizensGiantNPC; -import net.citizensnpcs.npc.entity.CitizensHumanNPC; -import net.citizensnpcs.npc.entity.CitizensIronGolemNPC; -import net.citizensnpcs.npc.entity.CitizensMagmaCubeNPC; -import net.citizensnpcs.npc.entity.CitizensMushroomCowNPC; -import net.citizensnpcs.npc.entity.CitizensOcelotNPC; -import net.citizensnpcs.npc.entity.CitizensPigNPC; -import net.citizensnpcs.npc.entity.CitizensPigZombieNPC; -import net.citizensnpcs.npc.entity.CitizensSheepNPC; -import net.citizensnpcs.npc.entity.CitizensSilverfishNPC; -import net.citizensnpcs.npc.entity.CitizensSkeletonNPC; -import net.citizensnpcs.npc.entity.CitizensSlimeNPC; -import net.citizensnpcs.npc.entity.CitizensSnowmanNPC; -import net.citizensnpcs.npc.entity.CitizensSpiderNPC; -import net.citizensnpcs.npc.entity.CitizensSquidNPC; -import net.citizensnpcs.npc.entity.CitizensVillagerNPC; -import net.citizensnpcs.npc.entity.CitizensWitchNPC; -import net.citizensnpcs.npc.entity.CitizensWitherNPC; -import net.citizensnpcs.npc.entity.CitizensWolfNPC; -import net.citizensnpcs.npc.entity.CitizensZombieNPC; import net.citizensnpcs.util.ByIdArray; import org.bukkit.craftbukkit.v1_4_5.entity.CraftEntity; @@ -47,41 +16,9 @@ import org.bukkit.entity.EntityType; public class CitizensNPCRegistry implements NPCRegistry { private final ByIdArray npcs = new ByIdArray(); private final NPCDataStore saves; - private final Map> types = new EnumMap>( - EntityType.class); public CitizensNPCRegistry(NPCDataStore store) { saves = store; - - types.put(EntityType.BAT, CitizensBatNPC.class); - types.put(EntityType.BLAZE, CitizensBlazeNPC.class); - types.put(EntityType.CAVE_SPIDER, CitizensCaveSpiderNPC.class); - types.put(EntityType.CHICKEN, CitizensChickenNPC.class); - types.put(EntityType.COW, CitizensCowNPC.class); - types.put(EntityType.CREEPER, CitizensCreeperNPC.class); - types.put(EntityType.ENDER_DRAGON, CitizensEnderDragonNPC.class); - types.put(EntityType.ENDERMAN, CitizensEndermanNPC.class); - types.put(EntityType.GHAST, CitizensGhastNPC.class); - types.put(EntityType.GIANT, CitizensGiantNPC.class); - types.put(EntityType.IRON_GOLEM, CitizensIronGolemNPC.class); - types.put(EntityType.MAGMA_CUBE, CitizensMagmaCubeNPC.class); - types.put(EntityType.MUSHROOM_COW, CitizensMushroomCowNPC.class); - types.put(EntityType.OCELOT, CitizensOcelotNPC.class); - types.put(EntityType.PIG, CitizensPigNPC.class); - types.put(EntityType.PIG_ZOMBIE, CitizensPigZombieNPC.class); - types.put(EntityType.PLAYER, CitizensHumanNPC.class); - types.put(EntityType.SHEEP, CitizensSheepNPC.class); - types.put(EntityType.SILVERFISH, CitizensSilverfishNPC.class); - types.put(EntityType.SKELETON, CitizensSkeletonNPC.class); - types.put(EntityType.SLIME, CitizensSlimeNPC.class); - types.put(EntityType.SNOWMAN, CitizensSnowmanNPC.class); - types.put(EntityType.SPIDER, CitizensSpiderNPC.class); - types.put(EntityType.SQUID, CitizensSquidNPC.class); - types.put(EntityType.VILLAGER, CitizensVillagerNPC.class); - types.put(EntityType.WOLF, CitizensWolfNPC.class); - types.put(EntityType.WITCH, CitizensWitchNPC.class); - types.put(EntityType.WITHER, CitizensWitherNPC.class); - types.put(EntityType.ZOMBIE, CitizensZombieNPC.class); } public NPC createNPC(EntityType type, int id, String name) { @@ -134,17 +71,7 @@ public class CitizensNPCRegistry implements NPCRegistry { } private CitizensNPC getByType(EntityType type, int id, String name) { - Class npcClass = types.get(type); - if (npcClass == null) - throw new IllegalArgumentException("Invalid EntityType: " + type); - try { - return npcClass.getConstructor(int.class, String.class).newInstance(id, name); - } catch (Throwable ex) { - if (ex.getCause() != null) - ex = ex.getCause(); - ex.printStackTrace(); - return null; - } + return new CitizensNPC(id, name, EntityControllers.createForType(type)); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/EntityController.java b/src/main/java/net/citizensnpcs/npc/EntityController.java new file mode 100644 index 000000000..28c2f6194 --- /dev/null +++ b/src/main/java/net/citizensnpcs/npc/EntityController.java @@ -0,0 +1,14 @@ +package net.citizensnpcs.npc; + +import net.citizensnpcs.api.npc.NPC; + +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; + +public interface EntityController { + LivingEntity getBukkitEntity(); + + void remove(); + + void spawn(Location at, NPC npc); +} diff --git a/src/main/java/net/citizensnpcs/npc/EntityControllers.java b/src/main/java/net/citizensnpcs/npc/EntityControllers.java new file mode 100644 index 000000000..30ad62aef --- /dev/null +++ b/src/main/java/net/citizensnpcs/npc/EntityControllers.java @@ -0,0 +1,88 @@ +package net.citizensnpcs.npc; + +import java.util.Map; + +import net.citizensnpcs.npc.entity.BatController; +import net.citizensnpcs.npc.entity.BlazeController; +import net.citizensnpcs.npc.entity.CaveSpiderController; +import net.citizensnpcs.npc.entity.ChickenController; +import net.citizensnpcs.npc.entity.CowController; +import net.citizensnpcs.npc.entity.CreeperController; +import net.citizensnpcs.npc.entity.EnderDragonController; +import net.citizensnpcs.npc.entity.EndermanController; +import net.citizensnpcs.npc.entity.GhastController; +import net.citizensnpcs.npc.entity.GiantController; +import net.citizensnpcs.npc.entity.HumanController; +import net.citizensnpcs.npc.entity.IronGolemController; +import net.citizensnpcs.npc.entity.MagmaCubeController; +import net.citizensnpcs.npc.entity.MushroomCowController; +import net.citizensnpcs.npc.entity.OcelotController; +import net.citizensnpcs.npc.entity.PigController; +import net.citizensnpcs.npc.entity.PigZombieController; +import net.citizensnpcs.npc.entity.SheepController; +import net.citizensnpcs.npc.entity.SilverfishController; +import net.citizensnpcs.npc.entity.SkeletonController; +import net.citizensnpcs.npc.entity.SlimeController; +import net.citizensnpcs.npc.entity.SnowmanController; +import net.citizensnpcs.npc.entity.SpiderController; +import net.citizensnpcs.npc.entity.SquidController; +import net.citizensnpcs.npc.entity.VillagerController; +import net.citizensnpcs.npc.entity.WitchController; +import net.citizensnpcs.npc.entity.WitherController; +import net.citizensnpcs.npc.entity.WolfController; +import net.citizensnpcs.npc.entity.ZombieController; + +import org.bukkit.entity.EntityType; + +import com.google.common.collect.Maps; + +public class EntityControllers { + + private static final Map> TYPES = Maps + .newEnumMap(EntityType.class); + public static EntityController createForType(EntityType type) { + Class controllerClass = TYPES.get(type); + if (controllerClass == null) + throw new IllegalArgumentException("Invalid EntityType: " + type); + try { + return controllerClass.newInstance(); + } catch (Throwable ex) { + if (ex.getCause() != null) + ex = ex.getCause(); + ex.printStackTrace(); + return null; + } + } + + static { + TYPES.put(EntityType.BAT, BatController.class); + TYPES.put(EntityType.BLAZE, BlazeController.class); + TYPES.put(EntityType.CAVE_SPIDER, CaveSpiderController.class); + TYPES.put(EntityType.CHICKEN, ChickenController.class); + TYPES.put(EntityType.COW, CowController.class); + TYPES.put(EntityType.CREEPER, CreeperController.class); + TYPES.put(EntityType.ENDER_DRAGON, EnderDragonController.class); + TYPES.put(EntityType.ENDERMAN, EndermanController.class); + TYPES.put(EntityType.GHAST, GhastController.class); + TYPES.put(EntityType.GIANT, GiantController.class); + TYPES.put(EntityType.IRON_GOLEM, IronGolemController.class); + TYPES.put(EntityType.MAGMA_CUBE, MagmaCubeController.class); + TYPES.put(EntityType.MUSHROOM_COW, MushroomCowController.class); + TYPES.put(EntityType.OCELOT, OcelotController.class); + TYPES.put(EntityType.PIG, PigController.class); + TYPES.put(EntityType.PIG_ZOMBIE, PigZombieController.class); + TYPES.put(EntityType.PLAYER, HumanController.class); + TYPES.put(EntityType.SHEEP, SheepController.class); + TYPES.put(EntityType.SILVERFISH, SilverfishController.class); + TYPES.put(EntityType.SKELETON, SkeletonController.class); + TYPES.put(EntityType.SLIME, SlimeController.class); + TYPES.put(EntityType.SNOWMAN, SnowmanController.class); + TYPES.put(EntityType.SPIDER, SpiderController.class); + TYPES.put(EntityType.SQUID, SquidController.class); + TYPES.put(EntityType.VILLAGER, VillagerController.class); + TYPES.put(EntityType.WOLF, WolfController.class); + TYPES.put(EntityType.WITCH, WitchController.class); + TYPES.put(EntityType.WITHER, WitherController.class); + TYPES.put(EntityType.ZOMBIE, ZombieController.class); + } +} diff --git a/src/main/java/net/citizensnpcs/npc/CitizensMobNPC.java b/src/main/java/net/citizensnpcs/npc/MobEntityController.java similarity index 70% rename from src/main/java/net/citizensnpcs/npc/CitizensMobNPC.java rename to src/main/java/net/citizensnpcs/npc/MobEntityController.java index effe961f1..29a782155 100644 --- a/src/main/java/net/citizensnpcs/npc/CitizensMobNPC.java +++ b/src/main/java/net/citizensnpcs/npc/MobEntityController.java @@ -1,7 +1,6 @@ package net.citizensnpcs.npc; import java.lang.reflect.Constructor; -import java.util.Arrays; import java.util.Map; import net.citizensnpcs.api.npc.NPC; @@ -12,42 +11,40 @@ import net.minecraft.server.v1_4_5.World; import org.bukkit.Location; import org.bukkit.block.BlockFace; import org.bukkit.craftbukkit.v1_4_5.CraftWorld; +import org.bukkit.entity.LivingEntity; import com.google.common.collect.Maps; -public abstract class CitizensMobNPC extends CitizensNPC { +public abstract class MobEntityController extends AbstractEntityController { private final Constructor constructor; - protected CitizensMobNPC(int id, String name, Class clazz) { - super(id, name); + protected MobEntityController(Class clazz) { this.constructor = getConstructor(clazz); NMS.registerEntityClass(clazz); } + @Override + protected LivingEntity createEntity(Location at, NPC npc) { + EntityLiving entity = createEntityFromClass(((CraftWorld) at.getWorld()).getHandle(), npc); + entity.setPositionRotation(at.getX(), at.getY(), at.getZ(), at.getYaw(), at.getPitch()); + + // entity.onGround isn't updated right away - we approximate here so + // that things like pathfinding still work *immediately* after spawn. + org.bukkit.Material beneath = at.getBlock().getRelative(BlockFace.DOWN).getType(); + if (beneath.isBlock()) + entity.onGround = true; + return (LivingEntity) entity.getBukkitEntity(); + } + private EntityLiving createEntityFromClass(Object... args) { try { - Object[] newArgs = Arrays.copyOf(args, args.length + 1); - newArgs[args.length] = this; - return (EntityLiving) constructor.newInstance(newArgs); + return (EntityLiving) constructor.newInstance(args); } catch (Exception ex) { ex.printStackTrace(); return null; } } - @Override - protected EntityLiving createHandle(Location loc) { - EntityLiving entity = createEntityFromClass(((CraftWorld) loc.getWorld()).getHandle()); - entity.setPositionRotation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); - - // entity.onGround isn't updated right away - we approximate here so - // that things like pathfinding still work *immediately* after spawn. - org.bukkit.Material beneath = loc.getBlock().getRelative(BlockFace.DOWN).getType(); - if (beneath.isBlock()) - entity.onGround = true; - return entity; - } - private static final Map, Constructor> CONSTRUCTOR_CACHE = Maps.newHashMap(); private static Constructor getConstructor(Class clazz) { diff --git a/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java b/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java index 7635e5dc1..f36e94972 100644 --- a/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java +++ b/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java @@ -32,6 +32,8 @@ public class CitizensNavigator implements Navigator, Runnable { private int lastX, lastY, lastZ; private NavigatorParameters localParams = defaultParams; private final CitizensNPC npc; + private final Location stationaryLocation = new Location(null, 0, 0, 0); + private int stationaryTicks; public CitizensNavigator(CitizensNPC npc) { @@ -211,19 +213,19 @@ public class CitizensNavigator implements Navigator, Runnable { private boolean updateStationaryStatus() { if (localParams.stationaryTicks() < 0) return false; - Location handle = npc.getBukkitEntity().getLocation(); - if (lastX == handle.getBlockX() && lastY == handle.getBlockY() && lastZ == handle.getBlockZ()) { + npc.getBukkitEntity().getLocation(stationaryLocation); + if (lastX == stationaryLocation.getBlockX() && lastY == stationaryLocation.getBlockY() + && lastZ == stationaryLocation.getBlockZ()) { if (++stationaryTicks >= localParams.stationaryTicks()) { stopNavigating(CancelReason.STUCK); return true; } } else stationaryTicks = 0; - lastX = handle.getBlockX(); - lastY = handle.getBlockY(); - lastZ = handle.getBlockZ(); + lastX = stationaryLocation.getBlockX(); + lastY = stationaryLocation.getBlockY(); + lastZ = stationaryLocation.getBlockZ(); return false; } - private static int UNINITIALISED_SPEED = Integer.MIN_VALUE; } diff --git a/src/main/java/net/citizensnpcs/npc/ai/MCTargetStrategy.java b/src/main/java/net/citizensnpcs/npc/ai/MCTargetStrategy.java index 0a1d758ee..e650d17d6 100644 --- a/src/main/java/net/citizensnpcs/npc/ai/MCTargetStrategy.java +++ b/src/main/java/net/citizensnpcs/npc/ai/MCTargetStrategy.java @@ -22,8 +22,12 @@ public class MCTargetStrategy implements PathStrategy, EntityTarget { private CancelReason cancelReason; private final EntityLiving handle, target; private final Navigation navigation; + private final Location npcLocation = new Location(null, 0, 0, 0); + private final NavigatorParameters parameters; + private final Location targetLocation = new Location(null, 0, 0, 0); + public MCTargetStrategy(NPC handle, LivingEntity target, boolean aggro, NavigatorParameters params) { this.handle = ((CraftLivingEntity) handle.getBukkitEntity()).getHandle(); this.target = ((CraftLivingEntity) target).getHandle(); @@ -38,14 +42,14 @@ public class MCTargetStrategy implements PathStrategy, EntityTarget { && (handle.boundingBox.e > target.boundingBox.b && handle.boundingBox.b < target.boundingBox.e) && distanceSquared() <= ATTACK_DISTANCE && hasLineOfSight(); } - @Override public void clearCancelReason() { cancelReason = null; } private double distanceSquared() { - return handle.getBukkitEntity().getLocation().distanceSquared(target.getBukkitEntity().getLocation()); + return handle.getBukkitEntity().getLocation(npcLocation) + .distanceSquared(target.getBukkitEntity().getLocation(targetLocation)); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensBatNPC.java b/src/main/java/net/citizensnpcs/npc/entity/BatController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensBatNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/BatController.java index 25aee1136..535941b95 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensBatNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/BatController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,9 +17,9 @@ import org.bukkit.entity.Bat; import org.bukkit.entity.Entity; import org.bukkit.util.Vector; -public class CitizensBatNPC extends CitizensMobNPC { - public CitizensBatNPC(int id, String name) { - super(id, name, EntityBatNPC.class); +public class BatController extends MobEntityController { + public BatController() { + super(EntityBatNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensBlazeNPC.java b/src/main/java/net/citizensnpcs/npc/entity/BlazeController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensBlazeNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/BlazeController.java index ff336393c..9a5fac144 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensBlazeNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/BlazeController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Blaze; import org.bukkit.entity.Entity; import org.bukkit.util.Vector; -public class CitizensBlazeNPC extends CitizensMobNPC { - - public CitizensBlazeNPC(int id, String name) { - super(id, name, EntityBlazeNPC.class); +public class BlazeController extends MobEntityController { + public BlazeController() { + super(EntityBlazeNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensCaveSpiderNPC.java b/src/main/java/net/citizensnpcs/npc/entity/CaveSpiderController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensCaveSpiderNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/CaveSpiderController.java index 00a3aec91..9cd81b98b 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensCaveSpiderNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/CaveSpiderController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,9 +17,9 @@ import org.bukkit.entity.CaveSpider; import org.bukkit.entity.Entity; import org.bukkit.util.Vector; -public class CitizensCaveSpiderNPC extends CitizensMobNPC { - public CitizensCaveSpiderNPC(int id, String name) { - super(id, name, EntityCaveSpiderNPC.class); +public class CaveSpiderController extends MobEntityController { + public CaveSpiderController() { + super(EntityCaveSpiderNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensChickenNPC.java b/src/main/java/net/citizensnpcs/npc/entity/ChickenController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensChickenNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/ChickenController.java index bc2465c62..085c6624a 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensChickenNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/ChickenController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,9 +17,9 @@ import org.bukkit.entity.Chicken; import org.bukkit.entity.Entity; import org.bukkit.util.Vector; -public class CitizensChickenNPC extends CitizensMobNPC { - public CitizensChickenNPC(int id, String name) { - super(id, name, EntityChickenNPC.class); +public class ChickenController extends MobEntityController { + public ChickenController() { + super(EntityChickenNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensEndermanNPC.java b/src/main/java/net/citizensnpcs/npc/entity/CitizensEndermanNPC.java deleted file mode 100644 index e9767e5fb..000000000 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensEndermanNPC.java +++ /dev/null @@ -1,164 +0,0 @@ -package net.citizensnpcs.npc.entity; - -import net.citizensnpcs.api.event.NPCPushEvent; -import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.api.trait.trait.Equipment; -import net.citizensnpcs.editor.Equipable; -import net.citizensnpcs.npc.CitizensMobNPC; -import net.citizensnpcs.npc.CitizensNPC; -import net.citizensnpcs.npc.ai.NPCHolder; -import net.citizensnpcs.util.Messages; -import net.citizensnpcs.util.Messaging; -import net.citizensnpcs.util.NMS; -import net.citizensnpcs.util.Util; -import net.minecraft.server.v1_4_5.EntityEnderman; -import net.minecraft.server.v1_4_5.World; - -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_4_5.CraftServer; -import org.bukkit.craftbukkit.v1_4_5.entity.CraftEnderman; -import org.bukkit.entity.Enderman; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.material.MaterialData; -import org.bukkit.util.Vector; - -public class CitizensEndermanNPC extends CitizensMobNPC implements Equipable { - public CitizensEndermanNPC(int id, String name) { - super(id, name, EntityEndermanNPC.class); - } - - @Override - public void equip(Player equipper, ItemStack hand) { - if (!hand.getType().isBlock()) { - Messaging.sendErrorTr(equipper, Messages.EQUIPMENT_EDITOR_INVALID_BLOCK); - return; - } - - MaterialData carried = getBukkitEntity().getCarriedMaterial(); - if (carried.getItemType() == Material.AIR) { - if (hand.getType() == Material.AIR) { - Messaging.sendErrorTr(equipper, Messages.EQUIPMENT_EDITOR_INVALID_BLOCK); - return; - } - } else { - equipper.getWorld().dropItemNaturally(getBukkitEntity().getLocation(), carried.toItemStack(1)); - getBukkitEntity().setCarriedMaterial(hand.getData()); - } - - ItemStack set = hand.clone(); - if (set.getType() != Material.AIR) { - set.setAmount(1); - hand.setAmount(hand.getAmount() - 1); - } - getTrait(Equipment.class).set(0, set); - } - - @Override - public Enderman getBukkitEntity() { - return (Enderman) super.getBukkitEntity(); - } - - public static class EndermanNPC extends CraftEnderman implements NPCHolder { - private final CitizensNPC npc; - - public EndermanNPC(EntityEndermanNPC entity) { - super((CraftServer) Bukkit.getServer(), entity); - this.npc = entity.npc; - } - - @Override - public NPC getNPC() { - return npc; - } - } - - public static class EntityEndermanNPC extends EntityEnderman implements NPCHolder { - private final CitizensNPC npc; - - public EntityEndermanNPC(World world) { - this(world, null); - } - - public EntityEndermanNPC(World world, NPC npc) { - super(world); - this.npc = (CitizensNPC) npc; - if (npc != null) { - NMS.clearGoals(goalSelector, targetSelector); - - } - } - - @Override - public void bl() { - super.bl(); - if (npc != null) - npc.update(); - } - - @Override - public void bn() { - if (npc == null) - super.bn(); - else { - NMS.updateAI(this); - npc.update(); - } - } - - @Override - public void c() { - if (npc == null) - super.c(); - else { - NMS.updateAI(this); - npc.update(); - } - } - - @Override - public void collide(net.minecraft.server.v1_4_5.Entity entity) { - // this method is called by both the entities involved - cancelling - // it will not stop the NPC from moving. - super.collide(entity); - if (npc != null) - Util.callCollisionEvent(npc, entity); - } - - @Override - public void g(double x, double y, double z) { - if (npc == null) { - super.g(x, y, z); - return; - } - if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) { - if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) - super.g(x, y, z); - return; - } - Vector vector = new Vector(x, y, z); - NPCPushEvent event = Util.callPushEvent(npc, vector); - if (!event.isCancelled()) { - vector = event.getCollisionVector(); - super.g(vector.getX(), vector.getY(), vector.getZ()); - } - // when another entity collides, this method is called to push the - // NPC so we prevent it from doing anything if the event is - // cancelled. - } - - @Override - public Entity getBukkitEntity() { - if (bukkitEntity == null && npc != null) - bukkitEntity = new EndermanNPC(this); - return super.getBukkitEntity(); - } - - @Override - public NPC getNPC() { - return npc; - } - } -} \ 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 deleted file mode 100644 index 0e99ea35b..000000000 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensHumanNPC.java +++ /dev/null @@ -1,147 +0,0 @@ -package net.citizensnpcs.npc.entity; - -import net.citizensnpcs.Settings.Setting; -import net.citizensnpcs.api.CitizensAPI; -import net.citizensnpcs.api.trait.trait.Equipment; -import net.citizensnpcs.editor.Equipable; -import net.citizensnpcs.npc.CitizensNPC; -import net.citizensnpcs.util.Messages; -import net.citizensnpcs.util.Messaging; -import net.citizensnpcs.util.NMS; -import net.citizensnpcs.util.StringHelper; -import net.citizensnpcs.util.Util; -import net.minecraft.server.v1_4_5.EntityLiving; -import net.minecraft.server.v1_4_5.ItemInWorldManager; -import net.minecraft.server.v1_4_5.WorldServer; - -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_4_5.CraftWorld; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - -public class CitizensHumanNPC extends CitizensNPC implements Equipable { - public CitizensHumanNPC(int id, String name) { - super(id, name); - } - - @Override - protected EntityLiving createHandle(final Location loc) { - WorldServer ws = ((CraftWorld) loc.getWorld()).getHandle(); - final EntityHumanNPC handle = new EntityHumanNPC(ws.getServer().getServer(), ws, - StringHelper.parseColors(getFullName()), new ItemInWorldManager(ws), this); - handle.getBukkitEntity().teleport(loc); - Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() { - @Override - public void run() { - boolean removeFromPlayerList = Setting.REMOVE_PLAYERS_FROM_PLAYER_LIST.asBoolean(); - NMS.addOrRemoveFromPlayerList(getBukkitEntity(), - data().get("removefromplayerlist", removeFromPlayerList)); - } - }, 1); - handle.getBukkitEntity().setSleepingIgnored(true); - return handle; - } - - @Override - public void equip(Player equipper, ItemStack hand) { - Equipment trait = getTrait(Equipment.class); - int slot = 0; - Material type = hand == null ? Material.AIR : hand.getType(); - // First, determine the slot to edit - switch (type) { - case SKULL_ITEM: - case PUMPKIN: - case JACK_O_LANTERN: - case LEATHER_HELMET: - case CHAINMAIL_HELMET: - case GOLD_HELMET: - case IRON_HELMET: - case DIAMOND_HELMET: - if (!equipper.isSneaking()) - slot = 1; - break; - case LEATHER_CHESTPLATE: - case CHAINMAIL_CHESTPLATE: - case GOLD_CHESTPLATE: - case IRON_CHESTPLATE: - case DIAMOND_CHESTPLATE: - if (!equipper.isSneaking()) - slot = 2; - break; - case LEATHER_LEGGINGS: - case CHAINMAIL_LEGGINGS: - case GOLD_LEGGINGS: - case IRON_LEGGINGS: - case DIAMOND_LEGGINGS: - if (!equipper.isSneaking()) - slot = 3; - break; - case LEATHER_BOOTS: - case CHAINMAIL_BOOTS: - case GOLD_BOOTS: - case IRON_BOOTS: - case DIAMOND_BOOTS: - if (!equipper.isSneaking()) - slot = 4; - break; - case AIR: - for (int i = 0; i < 5; i++) { - if (trait.get(i) != null && trait.get(i).getType() != Material.AIR) { - equipper.getWorld().dropItemNaturally(getBukkitEntity().getLocation(), trait.get(i)); - trait.set(i, null); - } - } - Messaging.sendTr(equipper, Messages.EQUIPMENT_EDITOR_ALL_ITEMS_REMOVED, getName()); - break; - default: - break; - } - // Drop any previous equipment on the ground - ItemStack equippedItem = trait.get(slot); - if (equippedItem != null && equippedItem.getType() != Material.AIR) - equipper.getWorld().dropItemNaturally(getBukkitEntity().getLocation(), equippedItem); - - // Now edit the equipment based on the slot - if (type != Material.AIR) { - // Set the proper slot with one of the item - ItemStack clone = hand.clone(); - clone.setAmount(1); - trait.set(slot, clone); - - hand.setAmount(hand.getAmount() - 1); - } - } - - @Override - public Player getBukkitEntity() { - if (getHandle() == null) - return null; - return getHandle().getBukkitEntity(); - } - - @Override - public EntityHumanNPC getHandle() { - return (EntityHumanNPC) mcEntity; - } - - @Override - public void setName(String name) { - super.setName(name); - Location prev = getBukkitEntity().getLocation(); - despawn(); - spawn(prev); - } - - @Override - public void update() { - super.update(); - if (isSpawned() && Util.isLoaded(getBukkitEntity().getLocation())) { - if (!getNavigator().isNavigating() && !NMS.inWater(mcEntity)) - mcEntity.move(0, -0.2, 0); - // gravity. also works around an entity.onGround not updating issue - // (onGround is normally updated by the client) - } - } -} \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensSheepNPC.java b/src/main/java/net/citizensnpcs/npc/entity/CitizensSheepNPC.java deleted file mode 100644 index 1595312f0..000000000 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensSheepNPC.java +++ /dev/null @@ -1,140 +0,0 @@ -package net.citizensnpcs.npc.entity; - -import net.citizensnpcs.api.event.NPCPushEvent; -import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.editor.Equipable; -import net.citizensnpcs.npc.CitizensMobNPC; -import net.citizensnpcs.npc.CitizensNPC; -import net.citizensnpcs.npc.ai.NPCHolder; -import net.citizensnpcs.trait.Sheared; -import net.citizensnpcs.trait.WoolColor; -import net.citizensnpcs.util.Messages; -import net.citizensnpcs.util.Messaging; -import net.citizensnpcs.util.NMS; -import net.citizensnpcs.util.Util; -import net.minecraft.server.v1_4_5.EntitySheep; -import net.minecraft.server.v1_4_5.World; - -import org.bukkit.Bukkit; -import org.bukkit.DyeColor; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_4_5.CraftServer; -import org.bukkit.craftbukkit.v1_4_5.entity.CraftSheep; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.entity.Sheep; -import org.bukkit.inventory.ItemStack; -import org.bukkit.util.Vector; - -public class CitizensSheepNPC extends CitizensMobNPC implements Equipable { - public CitizensSheepNPC(int id, String name) { - super(id, name, EntitySheepNPC.class); - } - - @Override - public void equip(Player equipper, ItemStack hand) { - if (hand.getType() == Material.SHEARS) { - Messaging.sendTr(equipper, getTrait(Sheared.class).toggle() ? Messages.SHEARED_SET - : Messages.SHEARED_STOPPED, getName()); - } else if (hand.getType() == Material.INK_SACK) { - if (getBukkitEntity().getColor() == DyeColor.getByData((byte) (15 - hand.getData().getData()))) - return; - - DyeColor color = DyeColor.getByData((byte) (15 - hand.getData().getData())); - getTrait(WoolColor.class).setColor(color); - Messaging.sendTr(equipper, Messages.EQUIPMENT_EDITOR_SHEEP_COLOURED, getName(), color.name() - .toLowerCase().replace("_", " ")); - - hand.setAmount(hand.getAmount() - 1); - } else { - getTrait(WoolColor.class).setColor(DyeColor.WHITE); - Messaging.sendTr(equipper, Messages.EQUIPMENT_EDITOR_SHEEP_COLOURED, getName(), "white"); - } - } - - @Override - public Sheep getBukkitEntity() { - return (Sheep) super.getBukkitEntity(); - } - - public static class EntitySheepNPC extends EntitySheep implements NPCHolder { - private final CitizensNPC npc; - - public EntitySheepNPC(World world) { - this(world, null); - } - - public EntitySheepNPC(World world, NPC npc) { - super(world); - this.npc = (CitizensNPC) npc; - if (npc != null) { - NMS.clearGoals(goalSelector, targetSelector); - - } - } - - @Override - public void bl() { - super.bl(); - if (npc != null) - npc.update(); - } - - @Override - public void collide(net.minecraft.server.v1_4_5.Entity entity) { - // this method is called by both the entities involved - cancelling - // it will not stop the NPC from moving. - super.collide(entity); - if (npc != null) - Util.callCollisionEvent(npc, entity); - } - - @Override - public void g(double x, double y, double z) { - if (npc == null) { - super.g(x, y, z); - return; - } - if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) { - if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) - super.g(x, y, z); - return; - } - Vector vector = new Vector(x, y, z); - NPCPushEvent event = Util.callPushEvent(npc, vector); - if (!event.isCancelled()) { - vector = event.getCollisionVector(); - super.g(vector.getX(), vector.getY(), vector.getZ()); - } - // when another entity collides, this method is called to push the - // NPC so we prevent it from doing anything if the event is - // cancelled. - } - - @Override - public Entity getBukkitEntity() { - if (bukkitEntity == null && npc != null) - bukkitEntity = new SheepNPC(this); - return super.getBukkitEntity(); - } - - @Override - public NPC getNPC() { - return npc; - } - } - - public static class SheepNPC extends CraftSheep implements NPCHolder { - private final CitizensNPC npc; - - public SheepNPC(EntitySheepNPC entity) { - super((CraftServer) Bukkit.getServer(), entity); - this.npc = entity.npc; - } - - @Override - public NPC getNPC() { - return npc; - } - } -} \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensCowNPC.java b/src/main/java/net/citizensnpcs/npc/entity/CowController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensCowNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/CowController.java index 6adab418a..0c9793372 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensCowNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/CowController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Cow; import org.bukkit.entity.Entity; import org.bukkit.util.Vector; -public class CitizensCowNPC extends CitizensMobNPC { - - public CitizensCowNPC(int id, String name) { - super(id, name, EntityCowNPC.class); +public class CowController extends MobEntityController { + public CowController() { + super(EntityCowNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensCreeperNPC.java b/src/main/java/net/citizensnpcs/npc/entity/CreeperController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensCreeperNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/CreeperController.java index 8b1a33360..6056f5cfc 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensCreeperNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/CreeperController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -18,10 +18,9 @@ import org.bukkit.entity.Creeper; import org.bukkit.entity.Entity; import org.bukkit.util.Vector; -public class CitizensCreeperNPC extends CitizensMobNPC { - - public CitizensCreeperNPC(int id, String name) { - super(id, name, EntityCreeperNPC.class); +public class CreeperController extends MobEntityController { + public CreeperController() { + super(EntityCreeperNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensEnderDragonNPC.java b/src/main/java/net/citizensnpcs/npc/entity/EnderDragonController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensEnderDragonNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/EnderDragonController.java index 9e0388df1..73a607bb2 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensEnderDragonNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/EnderDragonController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.EnderDragon; import org.bukkit.entity.Entity; import org.bukkit.util.Vector; -public class CitizensEnderDragonNPC extends CitizensMobNPC { - - public CitizensEnderDragonNPC(int id, String name) { - super(id, name, EntityEnderDragonNPC.class); +public class EnderDragonController extends MobEntityController { + public EnderDragonController() { + super(EntityEnderDragonNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/EndermanController.java b/src/main/java/net/citizensnpcs/npc/entity/EndermanController.java new file mode 100644 index 000000000..f765a4c73 --- /dev/null +++ b/src/main/java/net/citizensnpcs/npc/entity/EndermanController.java @@ -0,0 +1,130 @@ +package net.citizensnpcs.npc.entity; + +import net.citizensnpcs.api.event.NPCPushEvent; +import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.npc.MobEntityController; +import net.citizensnpcs.npc.CitizensNPC; +import net.citizensnpcs.npc.ai.NPCHolder; +import net.citizensnpcs.util.NMS; +import net.citizensnpcs.util.Util; +import net.minecraft.server.v1_4_5.EntityEnderman; +import net.minecraft.server.v1_4_5.World; + +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_4_5.CraftServer; +import org.bukkit.craftbukkit.v1_4_5.entity.CraftEnderman; +import org.bukkit.entity.Enderman; +import org.bukkit.entity.Entity; +import org.bukkit.util.Vector; + +public class EndermanController extends MobEntityController { + public EndermanController() { + super(EntityEndermanNPC.class); + } + + @Override + public Enderman getBukkitEntity() { + return (Enderman) super.getBukkitEntity(); + } + + public static class EndermanNPC extends CraftEnderman implements NPCHolder { + private final CitizensNPC npc; + + public EndermanNPC(EntityEndermanNPC entity) { + super((CraftServer) Bukkit.getServer(), entity); + this.npc = entity.npc; + } + + @Override + public NPC getNPC() { + return npc; + } + } + + public static class EntityEndermanNPC extends EntityEnderman implements NPCHolder { + private final CitizensNPC npc; + + public EntityEndermanNPC(World world) { + this(world, null); + } + + public EntityEndermanNPC(World world, NPC npc) { + super(world); + this.npc = (CitizensNPC) npc; + if (npc != null) { + NMS.clearGoals(goalSelector, targetSelector); + + } + } + + @Override + public void bl() { + super.bl(); + if (npc != null) + npc.update(); + } + + @Override + public void bn() { + if (npc == null) + super.bn(); + else { + NMS.updateAI(this); + npc.update(); + } + } + + @Override + public void c() { + if (npc == null) + super.c(); + else { + NMS.updateAI(this); + npc.update(); + } + } + + @Override + public void collide(net.minecraft.server.v1_4_5.Entity entity) { + // this method is called by both the entities involved - cancelling + // it will not stop the NPC from moving. + super.collide(entity); + if (npc != null) + Util.callCollisionEvent(npc, entity); + } + + @Override + public void g(double x, double y, double z) { + if (npc == null) { + super.g(x, y, z); + return; + } + if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) { + if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) + super.g(x, y, z); + return; + } + Vector vector = new Vector(x, y, z); + NPCPushEvent event = Util.callPushEvent(npc, vector); + if (!event.isCancelled()) { + vector = event.getCollisionVector(); + super.g(vector.getX(), vector.getY(), vector.getZ()); + } + // when another entity collides, this method is called to push the + // NPC so we prevent it from doing anything if the event is + // cancelled. + } + + @Override + public Entity getBukkitEntity() { + if (bukkitEntity == null && npc != null) + bukkitEntity = new EndermanNPC(this); + return super.getBukkitEntity(); + } + + @Override + public NPC getNPC() { + return npc; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/entity/EntityHumanNPC.java b/src/main/java/net/citizensnpcs/npc/entity/EntityHumanNPC.java index 484353327..50273ae7a 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/EntityHumanNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/EntityHumanNPC.java @@ -24,6 +24,7 @@ import net.minecraft.server.v1_4_5.Packet5EntityEquipment; import net.minecraft.server.v1_4_5.World; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.craftbukkit.v1_4_5.CraftServer; import org.bukkit.craftbukkit.v1_4_5.entity.CraftPlayer; import org.bukkit.metadata.MetadataValue; @@ -31,7 +32,9 @@ import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; public class EntityHumanNPC extends EntityPlayer implements NPCHolder { + private final Location loadedLocation = new Location(null, 0, 0, 0); private final CitizensNPC npc; + private final net.minecraft.server.v1_4_5.ItemStack[] previousEquipment = { null, null, null, null, null }; public EntityHumanNPC(MinecraftServer minecraftServer, World world, String string, @@ -125,6 +128,13 @@ public class EntityHumanNPC extends EntityPlayer implements NPCHolder { if (npc == null) return; + if (getBukkitEntity() != null && Util.isLoaded(getBukkitEntity().getLocation(loadedLocation))) { + if (!npc.getNavigator().isNavigating() && !NMS.inWater(this)) + move(0, -0.2, 0); + // gravity. also works around an entity.onGround not updating issue + // (onGround is normally updated by the client) + } + updateEquipment(); if (Math.abs(motX) < EPSILON && Math.abs(motY) < EPSILON && Math.abs(motZ) < EPSILON) motX = motY = motZ = 0; diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensGhastNPC.java b/src/main/java/net/citizensnpcs/npc/entity/GhastController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensGhastNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/GhastController.java index 3fca3318e..04892c593 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensGhastNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/GhastController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Ghast; import org.bukkit.util.Vector; -public class CitizensGhastNPC extends CitizensMobNPC { - - public CitizensGhastNPC(int id, String name) { - super(id, name, EntityGhastNPC.class); +public class GhastController extends MobEntityController { + public GhastController() { + super(EntityGhastNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensGiantNPC.java b/src/main/java/net/citizensnpcs/npc/entity/GiantController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensGiantNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/GiantController.java index 7356b77b9..18e3cfc70 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensGiantNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/GiantController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Giant; import org.bukkit.util.Vector; -public class CitizensGiantNPC extends CitizensMobNPC { - - public CitizensGiantNPC(int id, String name) { - super(id, name, EntityGiantNPC.class); +public class GiantController extends MobEntityController { + public GiantController() { + super(EntityGiantNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/HumanController.java b/src/main/java/net/citizensnpcs/npc/entity/HumanController.java new file mode 100644 index 000000000..f919bed4c --- /dev/null +++ b/src/main/java/net/citizensnpcs/npc/entity/HumanController.java @@ -0,0 +1,41 @@ +package net.citizensnpcs.npc.entity; + +import net.citizensnpcs.Settings.Setting; +import net.citizensnpcs.api.CitizensAPI; +import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.npc.AbstractEntityController; +import net.citizensnpcs.util.NMS; +import net.citizensnpcs.util.StringHelper; +import net.minecraft.server.v1_4_5.ItemInWorldManager; +import net.minecraft.server.v1_4_5.WorldServer; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_4_5.CraftWorld; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +public class HumanController extends AbstractEntityController { + @Override + protected LivingEntity createEntity(final Location at, final NPC npc) { + WorldServer ws = ((CraftWorld) at.getWorld()).getHandle(); + final EntityHumanNPC handle = new EntityHumanNPC(ws.getServer().getServer(), ws, + StringHelper.parseColors(npc.getFullName()), new ItemInWorldManager(ws), npc); + handle.getBukkitEntity().teleport(at); + Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() { + @Override + public void run() { + boolean removeFromPlayerList = Setting.REMOVE_PLAYERS_FROM_PLAYER_LIST.asBoolean(); + NMS.addOrRemoveFromPlayerList(getBukkitEntity(), + npc.data().get("removefromplayerlist", removeFromPlayerList)); + } + }, 1); + handle.getBukkitEntity().setSleepingIgnored(true); + return handle.getBukkitEntity(); + } + + @Override + public Player getBukkitEntity() { + return (Player) super.getBukkitEntity(); + } +} \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensIronGolemNPC.java b/src/main/java/net/citizensnpcs/npc/entity/IronGolemController.java similarity index 93% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensIronGolemNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/IronGolemController.java index cd7b21fbf..f0c68abb7 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensIronGolemNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/IronGolemController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.IronGolem; import org.bukkit.util.Vector; -public class CitizensIronGolemNPC extends CitizensMobNPC { - - public CitizensIronGolemNPC(int id, String name) { - super(id, name, EntityIronGolemNPC.class); +public class IronGolemController extends MobEntityController { + public IronGolemController() { + super(EntityIronGolemNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensMagmaCubeNPC.java b/src/main/java/net/citizensnpcs/npc/entity/MagmaCubeController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensMagmaCubeNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/MagmaCubeController.java index e51aff90a..bfc1f3779 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensMagmaCubeNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/MagmaCubeController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.MagmaCube; import org.bukkit.util.Vector; -public class CitizensMagmaCubeNPC extends CitizensMobNPC { - - public CitizensMagmaCubeNPC(int id, String name) { - super(id, name, EntityMagmaCubeNPC.class); +public class MagmaCubeController extends MobEntityController { + public MagmaCubeController() { + super(EntityMagmaCubeNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensMushroomCowNPC.java b/src/main/java/net/citizensnpcs/npc/entity/MushroomCowController.java similarity index 93% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensMushroomCowNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/MushroomCowController.java index ba27654d5..bb003db91 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensMushroomCowNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/MushroomCowController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,10 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.MushroomCow; import org.bukkit.util.Vector; -public class CitizensMushroomCowNPC extends CitizensMobNPC { +public class MushroomCowController extends MobEntityController { - public CitizensMushroomCowNPC(int id, String name) { - super(id, name, EntityMushroomCowNPC.class); + public MushroomCowController() { + super(EntityMushroomCowNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensOcelotNPC.java b/src/main/java/net/citizensnpcs/npc/entity/OcelotController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensOcelotNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/OcelotController.java index 07831ee9c..69ab4c9fc 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensOcelotNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/OcelotController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Ocelot; import org.bukkit.util.Vector; -public class CitizensOcelotNPC extends CitizensMobNPC { - - public CitizensOcelotNPC(int id, String name) { - super(id, name, EntityOcelotNPC.class); +public class OcelotController extends MobEntityController { + public OcelotController() { + super(EntityOcelotNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensPigNPC.java b/src/main/java/net/citizensnpcs/npc/entity/PigController.java similarity index 74% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensPigNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/PigController.java index 52b9cd955..254a98052 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensPigNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/PigController.java @@ -2,13 +2,9 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.editor.Equipable; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; -import net.citizensnpcs.trait.Saddle; -import net.citizensnpcs.util.Messages; -import net.citizensnpcs.util.Messaging; import net.citizensnpcs.util.NMS; import net.citizensnpcs.util.Util; import net.minecraft.server.v1_4_5.EntityLightning; @@ -16,35 +12,15 @@ import net.minecraft.server.v1_4_5.EntityPig; import net.minecraft.server.v1_4_5.World; import org.bukkit.Bukkit; -import org.bukkit.Material; import org.bukkit.craftbukkit.v1_4_5.CraftServer; import org.bukkit.craftbukkit.v1_4_5.entity.CraftPig; import org.bukkit.entity.Entity; import org.bukkit.entity.Pig; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; -public class CitizensPigNPC extends CitizensMobNPC implements Equipable { - - public CitizensPigNPC(int id, String name) { - super(id, name, EntityPigNPC.class); - } - - @Override - public void equip(Player equipper, ItemStack hand) { - if (hand.getType() == Material.SADDLE) { - if (!getBukkitEntity().hasSaddle()) { - getTrait(Saddle.class).toggle(); - hand.setAmount(0); - Messaging.sendTr(equipper, Messages.SADDLED_SET, getName()); - } - } else if (getBukkitEntity().hasSaddle()) { - equipper.getWorld().dropItemNaturally(getBukkitEntity().getLocation(), - new ItemStack(Material.SADDLE, 1)); - getTrait(Saddle.class).toggle(); - Messaging.sendTr(equipper, Messages.SADDLED_STOPPED, getName()); - } +public class PigController extends MobEntityController { + public PigController() { + super(EntityPigNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensPigZombieNPC.java b/src/main/java/net/citizensnpcs/npc/entity/PigZombieController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensPigZombieNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/PigZombieController.java index 62c1c5a0c..8c62f371a 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensPigZombieNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/PigZombieController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,10 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.PigZombie; import org.bukkit.util.Vector; -public class CitizensPigZombieNPC extends CitizensMobNPC { +public class PigZombieController extends MobEntityController { - public CitizensPigZombieNPC(int id, String name) { - super(id, name, EntityPigZombieNPC.class); + public PigZombieController() { + super(EntityPigZombieNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/SheepController.java b/src/main/java/net/citizensnpcs/npc/entity/SheepController.java new file mode 100644 index 000000000..de20f4ff7 --- /dev/null +++ b/src/main/java/net/citizensnpcs/npc/entity/SheepController.java @@ -0,0 +1,110 @@ +package net.citizensnpcs.npc.entity; + +import net.citizensnpcs.api.event.NPCPushEvent; +import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.npc.MobEntityController; +import net.citizensnpcs.npc.CitizensNPC; +import net.citizensnpcs.npc.ai.NPCHolder; +import net.citizensnpcs.util.NMS; +import net.citizensnpcs.util.Util; +import net.minecraft.server.v1_4_5.EntitySheep; +import net.minecraft.server.v1_4_5.World; + +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_4_5.CraftServer; +import org.bukkit.craftbukkit.v1_4_5.entity.CraftSheep; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Sheep; +import org.bukkit.util.Vector; + +public class SheepController extends MobEntityController { + public SheepController() { + super(EntitySheepNPC.class); + } + + @Override + public Sheep getBukkitEntity() { + return (Sheep) super.getBukkitEntity(); + } + + public static class EntitySheepNPC extends EntitySheep implements NPCHolder { + private final CitizensNPC npc; + + public EntitySheepNPC(World world) { + this(world, null); + } + + public EntitySheepNPC(World world, NPC npc) { + super(world); + this.npc = (CitizensNPC) npc; + if (npc != null) { + NMS.clearGoals(goalSelector, targetSelector); + + } + } + + @Override + public void bl() { + super.bl(); + if (npc != null) + npc.update(); + } + + @Override + public void collide(net.minecraft.server.v1_4_5.Entity entity) { + // this method is called by both the entities involved - cancelling + // it will not stop the NPC from moving. + super.collide(entity); + if (npc != null) + Util.callCollisionEvent(npc, entity); + } + + @Override + public void g(double x, double y, double z) { + if (npc == null) { + super.g(x, y, z); + return; + } + if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) { + if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) + super.g(x, y, z); + return; + } + Vector vector = new Vector(x, y, z); + NPCPushEvent event = Util.callPushEvent(npc, vector); + if (!event.isCancelled()) { + vector = event.getCollisionVector(); + super.g(vector.getX(), vector.getY(), vector.getZ()); + } + // when another entity collides, this method is called to push the + // NPC so we prevent it from doing anything if the event is + // cancelled. + } + + @Override + public Entity getBukkitEntity() { + if (bukkitEntity == null && npc != null) + bukkitEntity = new SheepNPC(this); + return super.getBukkitEntity(); + } + + @Override + public NPC getNPC() { + return npc; + } + } + + public static class SheepNPC extends CraftSheep implements NPCHolder { + private final CitizensNPC npc; + + public SheepNPC(EntitySheepNPC entity) { + super((CraftServer) Bukkit.getServer(), entity); + this.npc = entity.npc; + } + + @Override + public NPC getNPC() { + return npc; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensSilverfishNPC.java b/src/main/java/net/citizensnpcs/npc/entity/SilverfishController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensSilverfishNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/SilverfishController.java index f26352498..07b0343eb 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensSilverfishNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/SilverfishController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Silverfish; import org.bukkit.util.Vector; -public class CitizensSilverfishNPC extends CitizensMobNPC { - - public CitizensSilverfishNPC(int id, String name) { - super(id, name, EntitySilverfishNPC.class); +public class SilverfishController extends MobEntityController { + public SilverfishController() { + super(EntitySilverfishNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensSkeletonNPC.java b/src/main/java/net/citizensnpcs/npc/entity/SkeletonController.java similarity index 93% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensSkeletonNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/SkeletonController.java index d5924e04a..db08cb6c9 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensSkeletonNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/SkeletonController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Skeleton; import org.bukkit.util.Vector; -public class CitizensSkeletonNPC extends CitizensMobNPC { - - public CitizensSkeletonNPC(int id, String name) { - super(id, name, EntitySkeletonNPC.class); +public class SkeletonController extends MobEntityController { + public SkeletonController() { + super(EntitySkeletonNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensSlimeNPC.java b/src/main/java/net/citizensnpcs/npc/entity/SlimeController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensSlimeNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/SlimeController.java index 640822adb..9e2d259f4 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensSlimeNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/SlimeController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,10 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Slime; import org.bukkit.util.Vector; -public class CitizensSlimeNPC extends CitizensMobNPC { +public class SlimeController extends MobEntityController { - public CitizensSlimeNPC(int id, String name) { - super(id, name, EntitySlimeNPC.class); + public SlimeController() { + super(EntitySlimeNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensSnowmanNPC.java b/src/main/java/net/citizensnpcs/npc/entity/SnowmanController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensSnowmanNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/SnowmanController.java index 13f54a216..4bcf2d9dc 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensSnowmanNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/SnowmanController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Snowman; import org.bukkit.util.Vector; -public class CitizensSnowmanNPC extends CitizensMobNPC { - - public CitizensSnowmanNPC(int id, String name) { - super(id, name, EntitySnowmanNPC.class); +public class SnowmanController extends MobEntityController { + public SnowmanController() { + super(EntitySnowmanNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensSpiderNPC.java b/src/main/java/net/citizensnpcs/npc/entity/SpiderController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensSpiderNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/SpiderController.java index 291505fa0..b7a3114dd 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensSpiderNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/SpiderController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,9 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Spider; import org.bukkit.util.Vector; -public class CitizensSpiderNPC extends CitizensMobNPC { - public CitizensSpiderNPC(int id, String name) { - super(id, name, EntitySpiderNPC.class); +public class SpiderController extends MobEntityController { + public SpiderController() { + super(EntitySpiderNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensSquidNPC.java b/src/main/java/net/citizensnpcs/npc/entity/SquidController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensSquidNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/SquidController.java index f18e77863..135f4e604 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensSquidNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/SquidController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Squid; import org.bukkit.util.Vector; -public class CitizensSquidNPC extends CitizensMobNPC { - - public CitizensSquidNPC(int id, String name) { - super(id, name, EntitySquidNPC.class); +public class SquidController extends MobEntityController { + public SquidController() { + super(EntitySquidNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensVillagerNPC.java b/src/main/java/net/citizensnpcs/npc/entity/VillagerController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensVillagerNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/VillagerController.java index 80a6b80c0..b2c4eff42 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensVillagerNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/VillagerController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -18,10 +18,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Villager; import org.bukkit.util.Vector; -public class CitizensVillagerNPC extends CitizensMobNPC { - - public CitizensVillagerNPC(int id, String name) { - super(id, name, EntityVillagerNPC.class); +public class VillagerController extends MobEntityController { + public VillagerController() { + super(EntityVillagerNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensWitchNPC.java b/src/main/java/net/citizensnpcs/npc/entity/WitchController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensWitchNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/WitchController.java index e79709d40..6e57860ee 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensWitchNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/WitchController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,9 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Witch; import org.bukkit.util.Vector; -public class CitizensWitchNPC extends CitizensMobNPC { - public CitizensWitchNPC(int id, String name) { - super(id, name, EntityWitchNPC.class); +public class WitchController extends MobEntityController { + public WitchController() { + super(EntityWitchNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensWitherNPC.java b/src/main/java/net/citizensnpcs/npc/entity/WitherController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensWitherNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/WitherController.java index 5c495b96b..29003c1f5 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensWitherNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/WitherController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,9 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Wither; import org.bukkit.util.Vector; -public class CitizensWitherNPC extends CitizensMobNPC { - public CitizensWitherNPC(int id, String name) { - super(id, name, EntityWitherNPC.class); +public class WitherController extends MobEntityController { + public WitherController() { + super(EntityWitherNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensWolfNPC.java b/src/main/java/net/citizensnpcs/npc/entity/WolfController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensWolfNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/WolfController.java index c418a3630..256f8cb5f 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensWolfNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/WolfController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Wolf; import org.bukkit.util.Vector; -public class CitizensWolfNPC extends CitizensMobNPC { - - public CitizensWolfNPC(int id, String name) { - super(id, name, EntityWolfNPC.class); +public class WolfController extends MobEntityController { + public WolfController() { + super(EntityWolfNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/npc/entity/CitizensZombieNPC.java b/src/main/java/net/citizensnpcs/npc/entity/ZombieController.java similarity index 94% rename from src/main/java/net/citizensnpcs/npc/entity/CitizensZombieNPC.java rename to src/main/java/net/citizensnpcs/npc/entity/ZombieController.java index 970c4731b..a76be5cd4 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/CitizensZombieNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/ZombieController.java @@ -2,7 +2,7 @@ package net.citizensnpcs.npc.entity; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.npc.CitizensMobNPC; +import net.citizensnpcs.npc.MobEntityController; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -17,10 +17,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Zombie; import org.bukkit.util.Vector; -public class CitizensZombieNPC extends CitizensMobNPC { - - public CitizensZombieNPC(int id, String name) { - super(id, name, EntityZombieNPC.class); +public class ZombieController extends MobEntityController { + public ZombieController() { + super(EntityZombieNPC.class); } @Override diff --git a/src/main/java/net/citizensnpcs/trait/CurrentLocation.java b/src/main/java/net/citizensnpcs/trait/CurrentLocation.java index f3b1a2dd6..bbe40dc87 100644 --- a/src/main/java/net/citizensnpcs/trait/CurrentLocation.java +++ b/src/main/java/net/citizensnpcs/trait/CurrentLocation.java @@ -7,31 +7,29 @@ import org.bukkit.Location; public class CurrentLocation extends Trait { @Persist(value = "", required = true) - private Location loc; + private Location location = new Location(null, 0, 0, 0); public CurrentLocation() { super("location"); } public Location getLocation() { - if (loc != null && loc.getWorld() == null) - return null; - return loc; + return location.getWorld() == null ? null : location; } @Override public void run() { if (!npc.isSpawned()) return; - loc = npc.getBukkitEntity().getLocation(); + location = npc.getBukkitEntity().getLocation(location); } public void setLocation(Location loc) { - this.loc = loc; + this.location = loc; } @Override public String toString() { - return "CurrentLocation{" + loc + "}"; + return "CurrentLocation{" + location + "}"; } } \ 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 e27adfa9f..b00a03afb 100644 --- a/src/main/java/net/citizensnpcs/trait/LookClose.java +++ b/src/main/java/net/citizensnpcs/trait/LookClose.java @@ -21,7 +21,9 @@ import org.bukkit.entity.Player; public class LookClose extends Trait implements Toggleable, CommandConfigurable { private boolean enabled = Setting.DEFAULT_LOOK_CLOSE.asBoolean(); private Player lookingAt; + private final Location npcLocation = new Location(null, 0, 0, 0); private double range = Setting.DEFAULT_LOOK_CLOSE_RANGE.asDouble(); + private boolean realisticLooking = Setting.DEFAULT_REALISTIC_LOOKING.asBoolean(); public LookClose() { @@ -41,7 +43,7 @@ public class LookClose extends Trait implements Toggleable, CommandConfigurable private void findNewTarget() { List nearby = npc.getBukkitEntity().getNearbyEntities(range, range, range); - final Location npcLocation = npc.getBukkitEntity().getLocation(); + npc.getBukkitEntity().getLocation(npcLocation); Collections.sort(nearby, new Comparator() { @Override public int compare(Entity o1, Entity o2) { diff --git a/src/main/java/net/citizensnpcs/util/Messages.java b/src/main/java/net/citizensnpcs/util/Messages.java index 5ad7b08ec..be156d9f4 100644 --- a/src/main/java/net/citizensnpcs/util/Messages.java +++ b/src/main/java/net/citizensnpcs/util/Messages.java @@ -50,6 +50,7 @@ public class Messages { public static final String CURRENT_WAYPOINT_PROVIDER = "citizens.waypoints.current-provider"; public static final String DATABASE_CONNECTION_FAILED = "citizens.notifications.database-connection-failed"; public static final String DELAY_TRIGGER_PROMPT = "citizens.editors.waypoints.triggers.delay.prompt"; + public static final String ENTITY_TYPE_SET = "citizens.commands.npc.type.set"; public static final String EQUIPMENT_EDITOR_ALL_ITEMS_REMOVED = "citizens.editors.equipment.all-items-removed"; public static final String EQUIPMENT_EDITOR_BEGIN = "citizens.editors.equipment.begin"; public static final String EQUIPMENT_EDITOR_END = "citizens.editors.equipment.end"; @@ -78,6 +79,7 @@ public class Messages { public static final String INVALID_AGE = "citizens.commands.npc.age.invalid-age"; public static final String INVALID_ANCHOR_NAME = "citizens.commands.npc.anchor.invalid-name"; public static final String INVALID_ANIMATION = "citizens.editors.waypoints.triggers.animation.invalid-animation"; + public static final String INVALID_ENTITY_TYPE = "citizens.commands.npc.type.invalid"; public static final String INVALID_POSE_NAME = "citizens.commands.npc.pose.invalid-name"; public static final String INVALID_PROFESSION = "citizens.commands.npc.profession.invalid-profession"; public static final String INVALID_SKELETON_TYPE = "citizens.commands.npc.skeletontype.invalid-type"; @@ -140,7 +142,6 @@ public class Messages { public static final String REMOVED_FROM_PLAYERLIST = "citizens.commands.npc.playerlist.removed"; public static final String SADDLED_SET = "citizens.editors.equipment.saddled-set"; public static final String SADDLED_STOPPED = "citizens.editors.equipment.saddled-stopped"; - public static final String SAVE_METHOD_SET_NOTIFICATION = "citizens.notifications.save-method-set"; public static final String SCRIPT_COMPILED = "citizens.commands.script.compiled"; public static final String SCRIPT_COMPILING = "citizens.commands.script.compiling"; public static final String SCRIPT_FILE_MISSING = "citizens.commands.script.file-missing"; diff --git a/src/main/java/net/citizensnpcs/util/StringHelper.java b/src/main/java/net/citizensnpcs/util/StringHelper.java index dba6d0080..70b5f8fc2 100644 --- a/src/main/java/net/citizensnpcs/util/StringHelper.java +++ b/src/main/java/net/citizensnpcs/util/StringHelper.java @@ -14,8 +14,8 @@ 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)))); + return capitalize.length() == 0 ? "" : Character.toUpperCase(capitalize.charAt(0)) + + capitalize.substring(1, capitalize.length()); } public static int getLevenshteinDistance(String s, String t) { diff --git a/src/main/java/net/citizensnpcs/util/Util.java b/src/main/java/net/citizensnpcs/util/Util.java index dbd62b16b..7407f26e1 100644 --- a/src/main/java/net/citizensnpcs/util/Util.java +++ b/src/main/java/net/citizensnpcs/util/Util.java @@ -27,6 +27,10 @@ public class Util { private Util() { } + private static final Location atLocation = new Location(null, 0, 0, 0); + + private static final Location fromLocation = new Location(null, 0, 0, 0); + private static Class RNG_CLASS = null; public static void assumePose(org.bukkit.entity.Entity entity, float yaw, float pitch) { @@ -49,11 +53,16 @@ public class Util { public static void faceEntity(Entity from, Entity at) { if (from.getWorld() != at.getWorld()) return; - Location loc = from.getLocation(); - - double xDiff = at.getLocation().getX() - loc.getX(); - double yDiff = at.getLocation().getY() - loc.getY(); - double zDiff = at.getLocation().getZ() - loc.getZ(); + double xDiff, yDiff, zDiff; + synchronized (fromLocation) { + from.getLocation(fromLocation); + synchronized (atLocation) { + at.getLocation(atLocation); + xDiff = atLocation.getX() - fromLocation.getX(); + yDiff = atLocation.getY() - fromLocation.getY(); + zDiff = atLocation.getZ() - fromLocation.getZ(); + } + } double distanceXZ = Math.sqrt(xDiff * xDiff + zDiff * zDiff); double distanceY = Math.sqrt(distanceXZ * distanceXZ + yDiff * yDiff); diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties index 4b0dc1fd8..0e0c2144d 100644 --- a/src/main/resources/messages_en.properties +++ b/src/main/resources/messages_en.properties @@ -78,6 +78,8 @@ citizens.commands.npc.speed.modifier-above-limit=Speed is above the limit. citizens.commands.npc.speed.set=NPC speed modifier set to [[{0}]]. citizens.commands.npc.tp.teleported=You teleported to [[{0}]]. citizens.commands.npc.tphere.teleported=[[{0}]] was teleported to your location. +citizens.commands.npc.type.set=[[{0}]]''s type set to [[{1}]]. +citizens.commands.npc.type.invalid=[[{0}]] is not a valid type. citizens.commands.npc.vulnerable.set=[[{0}]] is now vulnerable. citizens.commands.npc.vulnerable.stopped=[[{0}]] is no longer vulnerable. citizens.commands.page-missing=The page [[{0}]] does not exist. @@ -190,7 +192,6 @@ citizens.notifications.npc-not-found=No NPC could be found. citizens.notifications.npcs-loaded=Loaded {0} NPCs. citizens.notifications.reloaded=Citizens reloaded. citizens.notifications.reloading=Reloading Citizens... -citizens.notifications.save-method-set=Save method set to {0}. citizens.notifications.saved=Citizens saved. citizens.notifications.saving=Saving Citizens... citizens.notifications.skipping-broken-trait=Skipped broken or missing trait {0} while loading ID {1}. Has the name changed?