Move Entity creation logic into EntityController, add /npc type, reduce Location object churn

This commit is contained in:
fullwall 2012-12-08 20:08:58 +08:00
parent 4473b2e57e
commit e998d2a78c
58 changed files with 1153 additions and 1035 deletions

View File

@ -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 + ","

View File

@ -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<Graph> graphs = Collections.synchronizedSet(new HashSet<Graph>());
/**
* 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<Graph> graphs = Collections.synchronizedSet(new HashSet<Graph>());
/**
* 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;
}
}
/**
* <p>
* 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:
* </p>
* <code>
* StringBuffer data = new StringBuffer();
* data.append(encode("guid")).append('=').append(encode(guid));
* encodeDataPair(data, "version", description.getVersion());
* </code>
*
* @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");
}
/**
* <p>
* 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:
* </p>
* <code>
* StringBuffer data = new StringBuffer();
* data.append(encode("guid")).append('=').append(encode(guid));
* encodeDataPair(data, "version", description.getVersion());
* </code>
*
* @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));
}
}

View File

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

View File

@ -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)",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<NPC> npcs = new ByIdArray<NPC>();
private final NPCDataStore saves;
private final Map<EntityType, Class<? extends CitizensNPC>> types = new EnumMap<EntityType, Class<? extends CitizensNPC>>(
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<? extends CitizensNPC> 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

View File

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

View File

@ -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<EntityType, Class<? extends EntityController>> TYPES = Maps
.newEnumMap(EntityType.class);
public static EntityController createForType(EntityType type) {
Class<? extends EntityController> 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);
}
}

View File

@ -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<Class<?>, Constructor<?>> CONSTRUCTOR_CACHE = Maps.newHashMap();
private static Constructor<?> getConstructor(Class<?> clazz) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<Entity> nearby = npc.getBukkitEntity().getNearbyEntities(range, range, range);
final Location npcLocation = npc.getBukkitEntity().getLocation();
npc.getBukkitEntity().getLocation(npcLocation);
Collections.sort(nearby, new Comparator<Entity>() {
@Override
public int compare(Entity o1, Entity o2) {

View File

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

View File

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

View File

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

View File

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