Simplification part 1 - remove characters

This commit is contained in:
fullwall 2012-07-09 16:46:53 +08:00
parent e3d553e0d7
commit 43f7cbc4a5
58 changed files with 795 additions and 1015 deletions

View File

@ -12,7 +12,6 @@ import net.citizensnpcs.api.event.CitizensReloadEvent;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.npc.NPCRegistry;
import net.citizensnpcs.api.npc.character.CharacterManager;
import net.citizensnpcs.api.scripting.EventRegistrar;
import net.citizensnpcs.api.scripting.ObjectProvider;
import net.citizensnpcs.api.scripting.ScriptCompiler;
@ -35,7 +34,6 @@ import net.citizensnpcs.command.exception.ServerCommandException;
import net.citizensnpcs.command.exception.UnhandledCommandException;
import net.citizensnpcs.command.exception.WrappedCommandException;
import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.npc.CitizensCharacterManager;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.CitizensNPCRegistry;
import net.citizensnpcs.npc.CitizensTraitManager;
@ -55,7 +53,6 @@ import org.bukkit.plugin.java.JavaPlugin;
import com.google.common.collect.Iterables;
public class Citizens extends JavaPlugin implements CitizensPlugin {
private final CitizensCharacterManager characterManager = new CitizensCharacterManager();
private final CommandManager commands = new CommandManager();
private boolean compatible;
private Settings config;
@ -63,11 +60,15 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
private CitizensNPCRegistry npcRegistry;
private Storage saves; // TODO: refactor this, it's used in too many places
private NPCSelector selector;
private TraitManager traitManager;
private CitizensTraitManager traitManager;
@Override
public CharacterManager getCharacterManager() {
return characterManager;
private void despawnNPCs() {
Iterator<NPC> itr = npcRegistry.iterator();
while (itr.hasNext()) {
NPC npc = itr.next();
itr.remove();
npc.despawn();
}
}
public Iterable<net.citizensnpcs.command.Command> getCommands(String base) {
@ -170,7 +171,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
setupStorage();
npcRegistry = new CitizensNPCRegistry(saves);
traitManager = new CitizensTraitManager(this);
traitManager = new CitizensTraitManager();
selector = new NPCSelector(this);
CitizensAPI.setImplementation(this);
@ -203,7 +204,8 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
return Iterables.size(npcRegistry);
}
});
characterManager.addPlotters(metrics);
traitManager.addPlotters(metrics.createGraph("traits"));
metrics.start();
Messaging.log("Metrics started.");
} catch (IOException e) {
@ -251,15 +253,6 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
getServer().getPluginManager().callEvent(new CitizensReloadEvent());
}
private void despawnNPCs() {
Iterator<NPC> itr = npcRegistry.iterator();
while (itr.hasNext()) {
NPC npc = itr.next();
itr.remove();
npc.despawn();
}
}
public void save() {
for (NPC npc : npcRegistry)
((CitizensNPC) npc).save(saves.getKey("npc." + npc.getId()));
@ -287,7 +280,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
continue;
}
}
NPC npc = npcRegistry.createNPC(type, id, key.getString("name"), null);
NPC npc = npcRegistry.createNPC(type, id, key.getString("name"));
((CitizensNPC) npc).load(key);
++created;

View File

@ -1,6 +1,5 @@
package net.citizensnpcs;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.NPCDamageByEntityEvent;
import net.citizensnpcs.api.event.NPCDamageEvent;
@ -11,8 +10,6 @@ import net.citizensnpcs.api.npc.NPCRegistry;
import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.npc.entity.EntityHumanNPC;
import net.citizensnpcs.trait.CurrentLocation;
import net.citizensnpcs.trait.text.Text;
import net.citizensnpcs.util.Util;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
@ -52,7 +49,7 @@ public class EventListen implements Listener {
if (!toRespawn.containsKey(coord))
return;
for (int id : toRespawn.get(coord)) {
NPC npc = npcRegistry.getNPC(id);
NPC npc = npcRegistry.getById(id);
npc.spawn(npc.getTrait(CurrentLocation.class).getLocation());
}
toRespawn.removeAll(coord);
@ -96,11 +93,6 @@ public class EventListen implements Listener {
// Call left-click event
NPCLeftClickEvent leftClickEvent = new NPCLeftClickEvent(npc, damager);
Bukkit.getPluginManager().callEvent(leftClickEvent);
if (leftClickEvent.isCancelled())
return;
if (npc.getCharacter() != null)
npc.getCharacter().onLeftClick(npc, damager);
} else {
Bukkit.getPluginManager().callEvent(new NPCDamageEvent(npc, event));
}
@ -125,15 +117,6 @@ public class EventListen implements Listener {
// Call right-click event
NPCRightClickEvent rightClickEvent = new NPCRightClickEvent(npc, player);
Bukkit.getPluginManager().callEvent(rightClickEvent);
if (rightClickEvent.isCancelled())
return;
// If the NPC isn't a close talker
// TODO: move this into text.class
if (Util.isSettingFulfilled(player, Setting.TALK_ITEM) && !npc.getTrait(Text.class).shouldTalkClose())
npc.getTrait(Text.class).sendText(player);
if (npc.getCharacter() != null)
npc.getCharacter().onRightClick(npc, player);
}
/*
@ -171,7 +154,7 @@ public class EventListen implements Listener {
if (!event.getWorld().isChunkLoaded(chunk.first, chunk.second))
continue;
for (int id : toRespawn.get(chunk)) {
NPC npc = npcRegistry.getNPC(id);
NPC npc = npcRegistry.getById(id);
npc.spawn(npc.getTrait(CurrentLocation.class).getLocation());
}
toRespawn.removeAll(chunk);

View File

@ -67,53 +67,6 @@ import org.bukkit.plugin.PluginDescriptionFile;
*/
public class Metrics {
/**
* The current revision number
*/
private final static int REVISION = 5;
/**
* 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 file where guid and opt out is stored in
*/
private static final String CONFIG_FILE = "plugins/PluginMetrics/config.yml";
/**
* 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
*/
@ -124,6 +77,17 @@ public class Metrics {
*/
private final File configurationFile;
/**
* 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
*/
@ -134,6 +98,11 @@ public class Metrics {
*/
private final Object optOutLock = new Object();
/**
* The plugin this metrics submits for
*/
private final Plugin plugin;
/**
* Id of the scheduled task
*/
@ -164,6 +133,23 @@ public class Metrics {
guid = configuration.getString("guid");
}
/**
* Adds a custom data plotter to the default graph
*
* @param plotter
*/
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);
}
/**
* Construct and create a Graph that can be used to separate specific
* plotters to their own graphs on the metrics website. Plotters can be
@ -189,99 +175,27 @@ public class Metrics {
}
/**
* Adds a custom data plotter to the default graph
* Disables metrics for the server by setting "opt-out" to true in the
* config file and canceling the metrics task.
*
* @param plotter
* @throws IOException
*/
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() {
public void disable() throws IOException {
// This has to be synchronized or it can collide with the check in the
// task.
synchronized (optOutLock) {
// Did we opt out?
if (isOptOut()) {
return false;
// Check if the server owner has already set opt-out, if not, set
// it.
if (!isOptOut()) {
configuration.set("opt-out", true);
configuration.save(configurationFile);
}
// Is metrics already running?
if (taskId >= 0) {
return true;
// Disable Task, if it is running
if (taskId > 0) {
this.plugin.getServer().getScheduler().cancelTask(taskId);
taskId = -1;
}
// Begin hitting the server with glorious data
taskId = plugin.getServer().getScheduler().scheduleAsyncRepeatingTask(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() && taskId > 0) {
plugin.getServer().getScheduler().cancelTask(taskId);
taskId = -1;
}
}
// 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) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
}
}
}, 0, PING_INTERVAL * 1200);
return true;
}
}
/**
* Has the server owner denied plugin metrics?
*
* @return
*/
public boolean isOptOut() {
synchronized (optOutLock) {
try {
// Reload the metrics file
configuration.load(CONFIG_FILE);
} catch (IOException ex) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
return true;
} catch (InvalidConfigurationException ex) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
return true;
}
return configuration.getBoolean("opt-out", false);
}
}
@ -310,27 +224,38 @@ public class Metrics {
}
/**
* Disables metrics for the server by setting "opt-out" to true in the
* config file and canceling the metrics task.
* Check if mineshafter is present. If it is, we need to bypass it to send
* POST requests
*
* @throws IOException
* @return
*/
public void disable() 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", true);
configuration.save(configurationFile);
}
private boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch (Exception e) {
return false;
}
}
// Disable Task, if it is running
if (taskId > 0) {
this.plugin.getServer().getScheduler().cancelTask(taskId);
taskId = -1;
/**
* Has the server owner denied plugin metrics?
*
* @return
*/
public boolean isOptOut() {
synchronized (optOutLock) {
try {
// Reload the metrics file
configuration.load(CONFIG_FILE);
} catch (IOException ex) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
return true;
} catch (InvalidConfigurationException ex) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
return true;
}
return configuration.getBoolean("opt-out", false);
}
}
@ -444,51 +369,64 @@ 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
* @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 (taskId >= 0) {
return true;
}
// Begin hitting the server with glorious data
taskId = plugin.getServer().getScheduler().scheduleAsyncRepeatingTask(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() && taskId > 0) {
plugin.getServer().getScheduler().cancelTask(taskId);
taskId = -1;
}
}
// 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) {
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
* @param key
* @param value
* @return
*/
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
* @return
*/
private static String encode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
/**
* Represents a custom graph on the website
*/
@ -509,15 +447,6 @@ public class Metrics {
this.name = name;
}
/**
* Gets the graph's name
*
* @return
*/
public String getName() {
return name;
}
/**
* Add a plotter to the graph, which will be used to plot entries
*
@ -527,13 +456,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
* @return
*/
public void removePlotter(final Plotter plotter) {
plotters.remove(plotter);
public String getName() {
return name;
}
/**
@ -550,14 +489,13 @@ 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);
/**
* Remove a plotter from the graph
*
* @param plotter
*/
public void removePlotter(final Plotter plotter) {
plotters.remove(plotter);
}
}
@ -588,12 +526,15 @@ public class Metrics {
this.name = name;
}
/**
* Get the current value for the plotted point
*
* @return
*/
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
@ -605,26 +546,85 @@ public class Metrics {
}
/**
* Called after the website graphs have been updated
* Get the current value for the plotted point
*
* @return
*/
public void reset() {
}
public abstract int getValue();
@Override
public int hashCode() {
return getColumnName().hashCode() + 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();
/**
* 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 file where guid and opt out is stored in
*/
private static final String CONFIG_FILE = "plugins/PluginMetrics/config.yml";
/**
* 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 = 5;
/**
* Encode text as UTF-8
*
* @param text
* @return
*/
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
* @param key
* @param value
* @return
*/
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

@ -23,9 +23,9 @@ public class Settings {
for (Setting setting : Setting.values()) {
if (!root.keyExists(setting.path)) {
Messaging.logF("Writing default setting: '%s'", setting.path);
setting.set(root);
setting.setAtKey(root);
} else
setting.load(root);
setting.loadFromKey(root);
}
save();
@ -35,7 +35,7 @@ public class Settings {
config.load();
for (Setting setting : Setting.values())
if (root.keyExists(setting.path))
setting.load(root);
setting.loadFromKey(root);
save();
}
@ -56,7 +56,7 @@ public class Settings {
DEFAULT_TALK_CLOSE("npc.default.talk-close", false),
DEFAULT_TEXT("npc.default.text.0", "Hi, I'm <npc>!") {
@Override
public void load(DataKey root) {
public void loadFromKey(DataKey root) {
List<String> list = new ArrayList<String>();
for (DataKey key : root.getRelative("npc.default.text").getSubKeys())
list.add(key.getString(""));
@ -109,12 +109,12 @@ public class Settings {
return value.toString();
}
protected void set(DataKey root) {
root.setRaw(path, value);
protected void loadFromKey(DataKey root) {
value = root.getRaw(path);
}
protected void load(DataKey root) {
value = root.getRaw(path);
protected void setAtKey(DataKey root) {
root.setRaw(path, value);
}
}
}

View File

@ -198,6 +198,11 @@ public class CommandManager {
|| commands.containsKey(command.toLowerCase() + " *");
}
// Returns whether a player has permission.
private boolean hasPermission(CommandSender sender, String perm) {
return sender.hasPermission("citizens." + perm);
}
// Returns whether a player has access to a command.
private boolean hasPermission(Method method, CommandSender sender) {
Command cmd = method.getAnnotation(Command.class);
@ -207,11 +212,6 @@ public class CommandManager {
return false;
}
// Returns whether a player has permission.
private boolean hasPermission(CommandSender sender, String perm) {
return sender.hasPermission("citizens." + perm);
}
/*
* Register an class that contains commands (denoted by Command. If no
* dependency injector is specified, then the methods of the class will be

View File

@ -8,11 +8,11 @@ import org.bukkit.entity.EntityType;
@Retention(RetentionPolicy.RUNTIME)
public @interface Requirements {
EntityType[] excludedTypes() default { EntityType.UNKNOWN };
boolean ownership() default false;
boolean selected() default false;
EntityType[] types() default { EntityType.UNKNOWN };
EntityType[] excludedTypes() default { EntityType.UNKNOWN };
}

View File

@ -59,24 +59,6 @@ public class HelpCommands {
return lines;
}
@Command(
aliases = { "script" },
usage = "help (page)",
desc = "Script help menu",
modifiers = { "help" },
min = 1,
max = 2,
permission = "script.help")
@Requirements
public void scriptHelp(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
int page = args.argsLength() == 2 ? args.getInteger(1) : 1;
Paginator paginator = new Paginator().header("Script Help");
for (String line : getLines(sender, "script"))
paginator.addLine(line);
if (!paginator.sendPage(sender, page))
throw new CommandException("The page '" + page + "' does not exist.");
}
@Command(
aliases = { "npc" },
usage = "help (page)",
@ -94,4 +76,22 @@ public class HelpCommands {
if (!paginator.sendPage(sender, page))
throw new CommandException("The page '" + page + "' does not exist.");
}
@Command(
aliases = { "script" },
usage = "help (page)",
desc = "Script help menu",
modifiers = { "help" },
min = 1,
max = 2,
permission = "script.help")
@Requirements
public void scriptHelp(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
int page = args.argsLength() == 2 ? args.getInteger(1) : 1;
Paginator paginator = new Paginator().header("Script Help");
for (String line : getLines(sender, "script"))
paginator.addLine(line);
if (!paginator.sendPage(sender, page))
throw new CommandException("The page '" + page + "' does not exist.");
}
}

View File

@ -8,8 +8,7 @@ import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.npc.NPCRegistry;
import net.citizensnpcs.api.npc.character.Character;
import net.citizensnpcs.api.npc.character.CharacterManager;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.trait.MobType;
import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.api.trait.trait.Spawned;
@ -26,15 +25,14 @@ import net.citizensnpcs.trait.CurrentLocation;
import net.citizensnpcs.trait.LookClose;
import net.citizensnpcs.trait.Powered;
import net.citizensnpcs.trait.VillagerProfession;
import net.citizensnpcs.trait.text.Text;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.Paginator;
import net.citizensnpcs.util.StringHelper;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.Location;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Ageable;
import org.bukkit.entity.EntityType;
@ -46,7 +44,6 @@ import com.google.common.base.Splitter;
@Requirements(selected = true, ownership = true)
public class NPCCommands {
private final CharacterManager characterManager = CitizensAPI.getCharacterManager();
private final NPCRegistry npcRegistry;
private final NPCSelector selector;
@ -103,31 +100,19 @@ public class NPCCommands {
@Command(
aliases = { "npc" },
usage = "character [character]",
desc = "Set the character of a NPC",
modifiers = { "character" },
min = 2,
max = 2)
public void character(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
String name = args.getString(1).toLowerCase();
Character character = characterManager.getCharacter(name);
if (character == null)
throw new CommandException("The character '" + args.getString(1) + "' does not exist.");
if (npc.getCharacter() != null && npc.getCharacter().getName().equalsIgnoreCase(character.getName()))
throw new CommandException("The NPC already has the character '" + name + "'.");
if (!sender.hasPermission("citizens.npc.character." + character.getName())
&& !sender.hasPermission("citizens.npc.character.*") && !sender.hasPermission("citizens.admin"))
throw new NoPermissionsException();
EntityType type = EntityType.valueOf(npc.getTrait(MobType.class).getType());
if (!character.getValidTypes().isEmpty() && !character.getValidTypes().contains(type)) {
Messaging.sendError(sender, "This NPC cannot be given the character '" + character.getName() + "'.");
return;
usage = "controllable",
desc = "Toggles whether the NPC can be ridden and controlled",
modifiers = { "controllable" },
min = 1,
max = 1,
permission = "npc.controllable")
public void controllable(CommandContext args, CommandSender sender, NPC npc) {
boolean enabled = npc.getTrait(Controllable.class).toggle();
if (enabled) {
Messaging.send(sender, StringHelper.wrap(npc.getName()) + " can now be controlled.");
} else {
Messaging.send(sender, StringHelper.wrap(npc.getName()) + " can no longer be controlled.");
}
Messaging.send(sender, StringHelper.wrap(npc.getName() + "'s") + " character is now " + StringHelper.wrap(name)
+ ".");
npc.setCharacter(character);
}
@Command(
@ -156,25 +141,7 @@ public class NPCCommands {
}
}
npc = npcRegistry.createNPC(type, name);
String msg = ChatColor.GREEN + "You created " + StringHelper.wrap(npc.getName());
if (args.hasValueFlag("char")) {
String character = args.getFlag("char").toLowerCase();
if (characterManager.getCharacter(character) == null) {
Messaging.sendError(player, "'" + args.getFlag("char") + "' is not a valid character.");
return;
} else {
Character set = characterManager.getCharacter(character);
if (!set.getValidTypes().isEmpty() && !set.getValidTypes().contains(type)) {
Messaging.sendError(player, "The character '" + set.getName() + "' cannot be given the mob type '"
+ type.name().toLowerCase() + "'.");
npc.remove();
return;
}
npc.setCharacter(characterManager.getCharacter(character));
msg += " with the character " + StringHelper.wrap(character);
}
}
msg += " at your location";
String msg = ChatColor.GREEN + "You created " + StringHelper.wrap(npc.getName()) + " at your location";
int age = 0;
if (args.hasFlag('b')) {
@ -195,19 +162,15 @@ public class NPCCommands {
msg += ".";
// Initialize necessary traits
npc.addTrait(Owner.class);
if (!Setting.SERVER_OWNS_NPCS.asBoolean())
npc.getTrait(Owner.class).setOwner(player.getName());
npc.getTrait(MobType.class).setType(type.toString());
npc.addTrait(LookClose.class);
npc.addTrait(Text.class);
npc.spawn(player.getLocation());
// Set age after entity spawns
if (npc.getBukkitEntity() instanceof Ageable)
npc.getTrait(Age.class).setAge(age);
selector.select(player, npc);
Messaging.send(player, msg);
}
@ -267,17 +230,6 @@ public class NPCCommands {
npcs.add(add);
}
}
if (args.hasValueFlag("char")) {
String character = args.getFlag("char");
if (characterManager.getCharacter(character) == null)
throw new CommandException("'" + character + "' is not a valid character.");
for (NPC add : npcRegistry.getNPCs(characterManager.getCharacter(character).getClass())) {
if (!npcs.contains(add))
npcs.add(add);
}
}
}
Paginator paginator = new Paginator().header("NPCs");
@ -308,26 +260,23 @@ public class NPCCommands {
Messaging.send(sender, msg + " when a player is nearby.");
}
@Command(aliases = { "npc" }, desc = "Show basic NPC information", max = 0)
public void npc(CommandContext args, CommandSender sender, NPC npc) {
Messaging.send(sender, StringHelper.wrapHeader(npc.getName()));
Messaging.send(sender, " <a>ID: <e>" + npc.getId());
Messaging.send(sender, " <a>Character: <e>"
+ (npc.getCharacter() != null ? npc.getCharacter().getName() : "None"));
Messaging.send(sender, " <a>Type: <e>" + npc.getTrait(MobType.class).getType());
}
@Command(aliases = { "npc" }, usage = "moveto", desc = "Teleports a NPC to a given location", modifiers = "moveto",
min = 1, max = 1, permission = "npc.moveto")
@Command(
aliases = { "npc" },
usage = "moveto",
desc = "Teleports a NPC to a given location",
modifiers = "moveto",
min = 1,
max = 1,
permission = "npc.moveto")
public void moveto(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
// Spawn the NPC if it isn't spawned to prevent NPEs
if (!npc.isSpawned())
npc.spawn(npc.getTrait(CurrentLocation.class).getLocation());
Location current = npc.getBukkitEntity().getLocation();
Location to = current.clone();
if (args.hasValueFlag("x"))
if (args.hasValueFlag("x"))
to.setX(args.getFlagInteger("x"));
if (args.hasValueFlag("y"))
if (args.hasValueFlag("y"))
to.setY(args.getFlagInteger("y"));
if (args.hasValueFlag("z"))
to.setZ(args.getFlagInteger("z"));
@ -335,16 +284,24 @@ public class NPCCommands {
to.setYaw((float) args.getFlagDouble("yaw"));
if (args.hasValueFlag("pitch"))
to.setPitch((float) args.getFlagDouble("pitch"));
if (args.hasValueFlag("world")){
if (args.hasValueFlag("world")) {
World world = Bukkit.getWorld(args.getFlag("world"));
if (world == null)
throw new CommandException("Given world not found.");
to.setWorld(world);
}
npc.getBukkitEntity().teleport(to, TeleportCause.COMMAND);
Messaging.send(sender, StringHelper.wrap(npc.getName()) + " was teleported to " + to + ".");
}
@Command(aliases = { "npc" }, desc = "Show basic NPC information", max = 0)
public void npc(CommandContext args, CommandSender sender, NPC npc) {
Messaging.send(sender, StringHelper.wrapHeader(npc.getName()));
Messaging.send(sender, " <a>ID: <e>" + npc.getId());
Messaging.send(sender, " <a>Type: <e>" + npc.getTrait(MobType.class).getType());
}
@Command(
aliases = { "npc" },
usage = "owner [name]",
@ -431,7 +388,7 @@ public class NPCCommands {
throw new CommandException("You must be the owner of this NPC to execute that command.");
if (!player.hasPermission("citizens.npc.remove") && !player.hasPermission("citizens.admin"))
throw new NoPermissionsException();
npc.remove();
npc.destroy();
Messaging.send(player, "<a>You permanently removed " + StringHelper.wrap(npc.getName()) + ".");
}
@ -465,7 +422,7 @@ public class NPCCommands {
permission = "npc.select")
@Requirements(ownership = true)
public void select(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
NPC toSelect = npcRegistry.getNPC(args.getInteger(1));
NPC toSelect = npcRegistry.getById(args.getInteger(1));
if (toSelect == null || !toSelect.getTrait(Spawned.class).shouldSpawn())
throw new CommandException("No NPC with the ID '" + args.getInteger(1) + "' is spawned.");
if (npc != null && toSelect.getId() == npc.getId())
@ -484,7 +441,7 @@ public class NPCCommands {
permission = "npc.spawn")
@Requirements
public void spawn(CommandContext args, Player player, NPC npc) throws CommandException {
NPC respawn = npcRegistry.getNPC(args.getInteger(1));
NPC respawn = npcRegistry.getById(args.getInteger(1));
if (respawn == null)
throw new CommandException("No NPC with the ID '" + args.getInteger(1) + "' exists.");
@ -500,23 +457,6 @@ public class NPCCommands {
+ " Use '/npc tphere' to teleport the NPC to your location.");
}
@Command(
aliases = { "npc" },
usage = "controllable",
desc = "Toggles whether the NPC can be ridden and controlled",
modifiers = { "controllable" },
min = 1,
max = 1,
permission = "npc.controllable")
public void controllable(CommandContext args, CommandSender sender, NPC npc) {
boolean enabled = npc.getTrait(Controllable.class).toggle();
if (enabled) {
Messaging.send(sender, StringHelper.wrap(npc.getName()) + " can now be controlled.");
} else {
Messaging.send(sender, StringHelper.wrap(npc.getName()) + " can no longer be controlled.");
}
}
@Command(
aliases = { "npc" },
usage = "tp",
@ -542,4 +482,20 @@ public class NPCCommands {
npc.getBukkitEntity().teleport(player, TeleportCause.COMMAND);
Messaging.send(player, StringHelper.wrap(npc.getName()) + " was teleported to your location.");
}
@Command(
aliases = { "npc" },
usage = "trait [trait name]",
desc = "Adds a trait to the NPC",
modifiers = { "trait" },
min = 2,
max = 2,
permission = "npc.trait")
public void trait(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
Trait trait = CitizensAPI.getTraitManager().getTrait(args.getString(1), npc);
if (trait == null)
throw new CommandException("Trait not found.");
npc.addTrait(trait);
Messaging.sendF(sender, ChatColor.GREEN + "Trait %s added successfully.", StringHelper.wrap(trait.getName()));
}
}

View File

@ -37,6 +37,10 @@ public class ScriptCommands {
if (!file.exists())
throw new CommandException("The file '" + args.getString(1) + "' doesn't exist!");
CitizensAPI.getScriptCompiler().compile(file).withCallback(new CompileCallback() {
@Override
public void onCompileTaskFinished() {
}
@Override
public void onScriptCompiled(ScriptFactory script) {
Script s = script.newInstance();
@ -47,10 +51,6 @@ public class ScriptCommands {
}
Messaging.send(sender, "<a>Done.");
}
@Override
public void onCompileTaskFinished() {
}
}).begin();
sender.sendMessage("Compiling...");
}

View File

@ -1,47 +0,0 @@
package net.citizensnpcs.npc;
import java.util.HashMap;
import java.util.Map;
import net.citizensnpcs.Metrics;
import net.citizensnpcs.Metrics.Graph;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.exception.CharacterException;
import net.citizensnpcs.api.npc.character.Character;
import net.citizensnpcs.api.npc.character.CharacterFactory;
import net.citizensnpcs.api.npc.character.CharacterManager;
import net.citizensnpcs.util.StringHelper;
public class CitizensCharacterManager implements CharacterManager {
private final Map<String, Character> registered = new HashMap<String, Character>();
@Override
public Character getCharacter(String name) {
return registered.get(name);
}
@Override
public void registerCharacter(CharacterFactory factory) {
try {
Character character = factory.create();
registered.put(character.getName(), character); // TODO: this only
// allows singletons
// for characters.
} catch (CharacterException ex) {
ex.printStackTrace();
}
}
public void addPlotters(Metrics metrics) {
Graph graph = metrics.createGraph("Character Type Usage");
for (final Character character : registered.values()) {
graph.addPlotter(new Metrics.Plotter(StringHelper.capitalize(character.getName())) {
@Override
public int getValue() {
return CitizensAPI.getNPCRegistry().getNPCs(character.getClass()).size();
}
});
}
}
}

View File

@ -1,12 +1,10 @@
package net.citizensnpcs.npc;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.NPCDespawnEvent;
import net.citizensnpcs.api.event.NPCSpawnEvent;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.AbstractNPC;
import net.citizensnpcs.api.npc.character.Character;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.trait.Spawned;
import net.citizensnpcs.api.util.DataKey;
@ -20,29 +18,14 @@ import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
public abstract class CitizensNPC extends AbstractNPC {
private final CitizensAI ai = new CitizensAI(this);
protected EntityLiving mcEntity;
private final CitizensTraitManager traitManager;
protected CitizensNPC(int id, String name) {
super(id, name);
traitManager = (CitizensTraitManager) CitizensAPI.getTraitManager();
// TODO: remove this dependency
}
@Override
public void chat(Player player, String message) {
Messaging.sendWithNPC(player, Setting.CHAT_PREFIX.asString() + message, this);
}
@Override
public void chat(String message) {
for (Player player : Bukkit.getOnlinePlayers())
chat(player, message);
}
protected abstract EntityLiving createHandle(Location loc);
@ -57,13 +40,19 @@ public abstract class CitizensNPC extends AbstractNPC {
Bukkit.getPluginManager().callEvent(new NPCDespawnEvent(this));
boolean keepSelected = getTrait(Spawned.class).shouldSpawn();
if (!keepSelected)
removeMetadata("selectors", CitizensAPI.getPlugin());
data().remove("selectors");
getBukkitEntity().remove();
mcEntity = null;
return true;
}
@Override
public void destroy() {
super.destroy();
CitizensAPI.getNPCRegistry().deregister(this);
}
@Override
public CitizensAI getAI() {
return ai;
@ -87,7 +76,7 @@ public abstract class CitizensNPC extends AbstractNPC {
@Override
public Trait getTraitFor(Class<? extends Trait> clazz) {
return traitManager.getTrait(clazz, this);
return CitizensAPI.getTraitManager().getTrait(clazz, this);
}
@Override
@ -96,22 +85,9 @@ public abstract class CitizensNPC extends AbstractNPC {
}
public void load(DataKey root) {
Character character = CitizensAPI.getCharacterManager().getCharacter(root.getString("character"));
// Load the character if it exists
if (character != null) {
try {
character.load(root.getRelative("characters." + character.getName()));
} catch (NPCLoadException e) {
Messaging.severe(String.format("Unable to load character '%s': %s.", character.getName(),
e.getMessage()));
}
setCharacter(character);
}
// Load traits
for (DataKey traitKey : root.getRelative("traits").getSubKeys()) {
Trait trait = traitManager.getTrait(traitKey.name(), this);
Trait trait = CitizensAPI.getTraitManager().getTrait(traitKey.name(), this);
if (trait == null) {
Messaging.severeF("Skipped missing trait '%s' while loading NPC ID: '%d'. Has the name changed?",
traitKey.name(), getId());
@ -119,7 +95,7 @@ public abstract class CitizensNPC extends AbstractNPC {
}
addTrait(trait);
try {
getTrait(trait.getClass()).load(traitKey);
trait.load(traitKey);
} catch (NPCLoadException ex) {
Messaging.logF("The trait '%s' failed to load for NPC ID: '%d'.", traitKey.name(), getId(),
ex.getMessage());
@ -134,32 +110,15 @@ public abstract class CitizensNPC extends AbstractNPC {
}
}
@Override
public void remove() {
super.remove();
CitizensAPI.getNPCRegistry().deregister(this);
}
public void save(DataKey root) {
root.setString("name", getFullName());
// Save the character if it exists
if (getCharacter() != null) {
root.setString("character", getCharacter().getName());
getCharacter().save(root.getRelative("characters." + getCharacter().getName()));
}
// Save all existing traits
for (Trait trait : traits.values()) {
trait.save(root.getRelative("traits." + trait.getName()));
}
}
@Override
public void setName(String name) {
super.setName(name);
}
@Override
public boolean spawn(Location loc) {
Validate.notNull(loc, "location cannot be null");

View File

@ -1,17 +1,13 @@
package net.citizensnpcs.npc;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.npc.NPCRegistry;
import net.citizensnpcs.api.npc.character.Character;
import net.citizensnpcs.api.util.Storage;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.npc.entity.CitizensBlazeNPC;
import net.citizensnpcs.npc.entity.CitizensCaveSpiderNPC;
import net.citizensnpcs.npc.entity.CitizensChickenNPC;
@ -82,67 +78,17 @@ public class CitizensNPCRegistry implements NPCRegistry {
types.put(EntityType.ZOMBIE, CitizensZombieNPC.class);
}
public NPC createNPC(EntityType type, int id, String name, Character character) {
public NPC createNPC(EntityType type, int id, String name) {
CitizensNPC npc = getByType(type, id, name);
if (npc == null)
throw new IllegalStateException("Could not create NPC.");
if (character != null)
npc.setCharacter(character);
npcs.put(npc.getId(), npc);
return npc;
}
@Override
public NPC createNPC(EntityType type, String name) {
return createNPC(type, name, null);
}
@Override
public NPC createNPC(EntityType type, String name, Character character) {
return createNPC(type, generateUniqueId(), name, character);
}
private int generateUniqueId() {
int count = 0;
while (getNPC(count++) != null)
; // TODO: doesn't respect existing save data that might not have
// been loaded. This causes DBs with NPCs that weren't loaded to
// have conflicting primary keys.
return count - 1;
}
@Override
public NPC getNPC(Entity entity) {
Validate.notNull(entity);
net.minecraft.server.Entity handle = ((CraftEntity) entity).getHandle();
return handle instanceof NPCHandle ? ((NPCHandle) handle).getNPC() : null;
}
@Override
public NPC getNPC(int id) {
if (id < 0)
throw new IllegalArgumentException("invalid id");
return npcs.get(id);
}
@Override
public Collection<NPC> getNPCs(Class<? extends Character> character) {
List<NPC> npcs = new ArrayList<NPC>();
for (NPC npc : this) {
if (npc.getCharacter() != null && npc.getCharacter().getClass().equals(character))
npcs.add(npc);
}
return npcs;
}
@Override
public boolean isNPC(Entity entity) {
return getNPC(entity) != null;
}
@Override
public Iterator<NPC> iterator() {
return npcs.iterator();
return createNPC(type, generateUniqueId(), name);
}
@Override
@ -163,6 +109,22 @@ public class CitizensNPCRegistry implements NPCRegistry {
}
}
private int generateUniqueId() {
int count = 0;
while (getById(count++) != null)
; // TODO: doesn't respect existing save data that might not have
// been loaded. This causes DBs with NPCs that weren't loaded to
// have conflicting primary keys.
return count - 1;
}
@Override
public NPC getById(int id) {
if (id < 0)
throw new IllegalArgumentException("invalid id");
return npcs.get(id);
}
private CitizensNPC getByType(EntityType type, int id, String name) {
Class<? extends CitizensNPC> npcClass = types.get(type);
if (npcClass == null)
@ -173,4 +135,21 @@ public class CitizensNPCRegistry implements NPCRegistry {
return null;
}
}
@Override
public NPC getNPC(Entity entity) {
Validate.notNull(entity);
net.minecraft.server.Entity handle = ((CraftEntity) entity).getHandle();
return handle instanceof NPCHolder ? ((NPCHolder) handle).getNPC() : null;
}
@Override
public boolean isNPC(Entity entity) {
return getNPC(entity) != null;
}
@Override
public Iterator<NPC> iterator() {
return npcs.iterator();
}
}

View File

@ -1,13 +1,13 @@
package net.citizensnpcs.npc;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import net.citizensnpcs.Metrics;
import net.citizensnpcs.Metrics.Graph;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitFactory;
import net.citizensnpcs.api.trait.TraitInfo;
import net.citizensnpcs.api.trait.TraitManager;
import net.citizensnpcs.api.trait.trait.Equipment;
import net.citizensnpcs.api.trait.trait.Inventory;
@ -27,57 +27,53 @@ import net.citizensnpcs.trait.WoolColor;
import net.citizensnpcs.trait.text.Text;
import net.citizensnpcs.trait.waypoint.Waypoints;
import org.bukkit.plugin.Plugin;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
public class CitizensTraitManager implements TraitManager {
private final Map<Class<? extends Trait>, Constructor<? extends Trait>> CACHED_CTORS = new HashMap<Class<? extends Trait>, Constructor<? extends Trait>>();
private final Map<Plugin, Map<String, Class<? extends Trait>>> registered = new HashMap<Plugin, Map<String, Class<? extends Trait>>>();
private final Map<String, Class<? extends Trait>> registered = Maps.newHashMap();
// TODO: handle Plugin-setting/names better and avoid cruft. also find a
// way to avoid naming conflicts
public CitizensTraitManager(Plugin plugin) {
registerTrait(new TraitFactory(Age.class).withName("age").withPlugin(plugin));
registerTrait(new TraitFactory(CurrentLocation.class).withName("location").withPlugin(plugin));
registerTrait(new TraitFactory(Equipment.class).withName("equipment").withPlugin(plugin));
registerTrait(new TraitFactory(Inventory.class).withName("inventory").withPlugin(plugin));
registerTrait(new TraitFactory(LookClose.class).withName("lookclose").withPlugin(plugin));
registerTrait(new TraitFactory(MobType.class).withName("type").withPlugin(plugin));
registerTrait(new TraitFactory(Owner.class).withName("owner").withPlugin(plugin));
registerTrait(new TraitFactory(Powered.class).withName("powered").withPlugin(plugin));
registerTrait(new TraitFactory(Saddle.class).withName("saddle").withPlugin(plugin));
registerTrait(new TraitFactory(Sheared.class).withName("sheared").withPlugin(plugin));
registerTrait(new TraitFactory(Spawned.class).withName("spawned").withPlugin(plugin));
registerTrait(new TraitFactory(Text.class).withName("text").withPlugin(plugin));
registerTrait(new TraitFactory(VillagerProfession.class).withName("profession").withPlugin(plugin));
registerTrait(new TraitFactory(Waypoints.class).withName("waypoints").withPlugin(plugin));
registerTrait(new TraitFactory(WoolColor.class).withName("woolcolor").withPlugin(plugin));
registerTrait(new TraitFactory(Controllable.class).withName("controllable").withPlugin(plugin));
registerTrait(new TraitFactory(Behaviour.class).withName("behaviour").withPlugin(plugin));
// TODO: find a way to avoid naming conflicts
public CitizensTraitManager() {
registerTrait(TraitInfo.create(Age.class).withName("age"));
registerTrait(TraitInfo.create(CurrentLocation.class).withName("location"));
registerTrait(TraitInfo.create(Equipment.class).withName("equipment"));
registerTrait(TraitInfo.create(Inventory.class).withName("inventory"));
registerTrait(TraitInfo.create(LookClose.class).withName("lookclose"));
registerTrait(TraitInfo.create(MobType.class).withName("type"));
registerTrait(TraitInfo.create(Owner.class).withName("owner"));
registerTrait(TraitInfo.create(Powered.class).withName("powered"));
registerTrait(TraitInfo.create(Saddle.class).withName("saddle"));
registerTrait(TraitInfo.create(Sheared.class).withName("sheared"));
registerTrait(TraitInfo.create(Spawned.class).withName("spawned"));
registerTrait(TraitInfo.create(Text.class).withName("text"));
registerTrait(TraitInfo.create(VillagerProfession.class).withName("profession"));
registerTrait(TraitInfo.create(Waypoints.class).withName("waypoints"));
registerTrait(TraitInfo.create(WoolColor.class).withName("woolcolor"));
registerTrait(TraitInfo.create(Controllable.class).withName("controllable"));
registerTrait(TraitInfo.create(Behaviour.class).withName("behaviour"));
}
public void addPlotters(Graph graph) {
for (Map.Entry<String, Class<? extends Trait>> entry : registered.entrySet()) {
final Class<? extends Trait> traitClass = entry.getValue();
graph.addPlotter(new Metrics.Plotter(entry.getKey()) {
@Override
public int getValue() {
int numberUsingTrait = 0;
for (NPC npc : CitizensAPI.getNPCRegistry()) {
if (npc.hasTrait(traitClass))
++numberUsingTrait;
}
return numberUsingTrait;
}
});
}
}
@SuppressWarnings("unchecked")
private <T extends Trait> T create(Class<T> trait, NPC npc) {
Constructor<? extends Trait> constructor;
if (!CACHED_CTORS.containsKey(trait)) {
try {
// TODO: replace this fixed constructor with a context class
// which can have extra environment variables.
constructor = trait.getConstructor(NPC.class);
if (constructor == null)
constructor = trait.getConstructor(CitizensNPC.class);
constructor.setAccessible(true);
} catch (Exception ex) {
constructor = null;
}
CACHED_CTORS.put(trait, constructor);
} else
constructor = CACHED_CTORS.get(trait);
try {
if (constructor == null || npc == null)
return trait.newInstance();
return (T) constructor.newInstance(npc);
return trait.newInstance();
} catch (Exception ex) {
ex.printStackTrace();
return null;
@ -85,55 +81,24 @@ public class CitizensTraitManager implements TraitManager {
}
@Override
public <T extends Trait> T getTrait(Class<T> clazz) {
return getTrait(clazz, null);
}
@SuppressWarnings("unchecked")
public <T extends Trait> T getTrait(Class<T> clazz, NPC npc) {
for (Entry<Plugin, Map<String, Class<? extends Trait>>> entry : registered.entrySet()) {
for (Entry<String, Class<? extends Trait>> subEntry : entry.getValue().entrySet()) {
if (!subEntry.getValue().equals(clazz))
continue;
Trait trait = create(subEntry.getValue(), npc);
if (trait == null)
return null;
trait.setPlugin(entry.getKey());
trait.setName(subEntry.getKey());
return (T) trait;
}
}
return null;
if (!registered.containsValue(clazz))
return null;
return create(clazz, npc);
}
@SuppressWarnings("unchecked")
@Override
public <T extends Trait> T getTrait(String name) {
for (Map<String, Class<? extends Trait>> entry : registered.values()) {
if (!entry.containsKey(name))
continue;
return (T) create(entry.get(name), null);
}
return null;
}
@SuppressWarnings("unchecked")
public <T extends Trait> T getTrait(String name, NPC npc) {
for (Map<String, Class<? extends Trait>> entry : registered.values()) {
Class<? extends Trait> clazz = entry.get(name);
if (clazz == null)
continue;
return (T) getTrait(clazz, npc);
}
return null;
Class<? extends Trait> clazz = registered.get(name);
if (clazz == null)
return null;
return (T) create(clazz, npc);
}
@Override
public void registerTrait(TraitFactory factory) {
Map<String, Class<? extends Trait>> map = registered.get(factory.getTraitPlugin());
if (map == null)
map = new HashMap<String, Class<? extends Trait>>();
map.put(factory.getTraitName(), factory.getTraitClass());
registered.put(factory.getTraitPlugin(), map);
public void registerTrait(TraitInfo info) {
Preconditions.checkNotNull(info, "info cannot be null");
registered.put(info.getTraitName(), info.getTraitClass());
}
}

View File

@ -22,15 +22,48 @@ import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.plugin.Plugin;
import com.google.common.collect.Lists;
public class NPCSelector implements Listener {
private final Plugin plugin;
private int consoleSelectedNPC = -1;
private final Plugin plugin;
public NPCSelector(Plugin plugin) {
this.plugin = plugin;
Bukkit.getPluginManager().registerEvents(this, plugin);
}
public NPC getSelected(CommandSender sender) {
if (sender instanceof Player) {
List<MetadataValue> metadata = ((Player) sender).getMetadata("selected");
if (metadata.size() == 0)
return null;
return CitizensAPI.getNPCRegistry().getById(metadata.get(0).asInt());
} else {
if (consoleSelectedNPC == -1)
return null;
return CitizensAPI.getNPCRegistry().getById(consoleSelectedNPC);
}
}
@EventHandler
public void onNPCRemove(NPCRemoveEvent event) {
NPC npc = event.getNPC();
List<String> selectors = npc.data().get("selectors");
if (selectors == null)
return;
for (String value : selectors) {
if (value.equals("console")) {
consoleSelectedNPC = -1;
} else {
Player search = Bukkit.getPlayerExact(value);
if (search != null)
search.removeMetadata("selected", plugin);
}
}
npc.data().remove("selectors");
}
@EventHandler
public void onNPCRightClick(NPCRightClickEvent event) {
Player player = event.getClicker();
@ -48,51 +81,24 @@ public class NPCSelector implements Listener {
}
}
@EventHandler
public void onNPCRemove(NPCRemoveEvent event) {
NPC npc = event.getNPC();
for (MetadataValue value : npc.getMetadata("selectors")) {
if (value.asString().equals("console")) {
consoleSelectedNPC = -1;
} else {
Player search = Bukkit.getPlayerExact(value.asString());
if (search != null)
search.removeMetadata("selected", plugin);
}
}
npc.removeMetadata("selectors", plugin);
}
public void select(CommandSender sender, NPC npc) {
// Remove existing selection if any
List<Object> selectors = npc.data().get("selectors", Lists.newArrayList());
if (sender instanceof Player) {
Player player = (Player) sender;
if (player.hasMetadata("selected"))
player.removeMetadata("selected", plugin);
player.setMetadata("selected", new FixedMetadataValue(plugin, npc.getId()));
npc.setMetadata("selectors", new FixedMetadataValue(plugin, player.getName()));
selectors.add(player.getName());
// Remove editor if the player has one
Editor.leave(player);
} else {
consoleSelectedNPC = npc.getId();
npc.setMetadata("selectors", new FixedMetadataValue(plugin, "console"));
selectors.add("console");
}
Bukkit.getPluginManager().callEvent(new NPCSelectEvent(npc, sender));
}
public NPC getSelected(CommandSender sender) {
if (sender instanceof Player) {
List<MetadataValue> metadata = ((Player) sender).getMetadata("selected");
if (metadata.size() == 0)
return null;
return CitizensAPI.getNPCRegistry().getNPC(metadata.get(0).asInt());
} else {
if (consoleSelectedNPC == -1)
return null;
return CitizensAPI.getNPCRegistry().getNPC(consoleSelectedNPC);
}
}
}

View File

@ -20,9 +20,9 @@ public class CitizensAI implements AI {
private PathStrategy executing;
private final List<GoalEntry> executingGoals = Lists.newArrayList();
private final List<GoalEntry> goals = Lists.newArrayList();
private List<Goal> toRemove = null;
private final CitizensNPC npc;
private boolean paused;
private List<Goal> toRemove = null;
public CitizensAI(CitizensNPC npc) {
this.npc = npc;
@ -89,6 +89,29 @@ public class CitizensAI implements AI {
toRemove.add(goal);
}
private void removeGoals() {
if (toRemove == null)
return;
for (Goal goal : toRemove) {
Iterator<GoalEntry> itr = executingGoals.iterator();
while (itr.hasNext()) {
GoalEntry entry = itr.next();
if (entry.getGoal().equals(goal)) {
entry.getGoal().reset();
itr.remove();
}
}
itr = goals.iterator();
while (itr.hasNext()) {
GoalEntry entry = itr.next();
if (entry.getGoal().equals(goal))
itr.remove();
}
}
toRemove = null;
}
public void resume() {
paused = false;
}
@ -164,29 +187,6 @@ public class CitizensAI implements AI {
}
}
private void removeGoals() {
if (toRemove == null)
return;
for (Goal goal : toRemove) {
Iterator<GoalEntry> itr = executingGoals.iterator();
while (itr.hasNext()) {
GoalEntry entry = itr.next();
if (entry.getGoal().equals(goal)) {
entry.getGoal().reset();
itr.remove();
}
}
itr = goals.iterator();
while (itr.hasNext()) {
GoalEntry entry = itr.next();
if (entry.getGoal().equals(goal))
itr.remove();
}
}
toRemove = null;
}
public static class GoalEntry implements Comparable<GoalEntry> {
private final Goal goal;
private final int priority;
@ -201,19 +201,6 @@ public class CitizensAI implements AI {
return o.priority > priority ? 1 : o.priority < priority ? -1 : 0;
}
public Goal getGoal() {
return goal;
}
public int getPriority() {
return priority;
}
@Override
public int hashCode() {
return 31 + ((goal == null) ? 0 : goal.hashCode());
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
@ -232,5 +219,18 @@ public class CitizensAI implements AI {
}
return true;
}
public Goal getGoal() {
return goal;
}
public int getPriority() {
return priority;
}
@Override
public int hashCode() {
return 31 + ((goal == null) ? 0 : goal.hashCode());
}
}
}

View File

@ -1,7 +0,0 @@
package net.citizensnpcs.npc.ai;
import net.citizensnpcs.api.npc.NPC;
public interface NPCHandle {
public NPC getNPC();
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityBlaze;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensBlazeNPC extends CitizensMobNPC {
return (Blaze) getHandle().getBukkitEntity();
}
public static class EntityBlazeNPC extends EntityBlaze implements NPCHandle {
public static class EntityBlazeNPC extends EntityBlaze implements NPCHolder {
private final CitizensNPC npc;
public EntityBlazeNPC(World world) {

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityCaveSpider;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensCaveSpiderNPC extends CitizensMobNPC {
return (CaveSpider) getHandle().getBukkitEntity();
}
public static class EntityCaveSpiderNPC extends EntityCaveSpider implements NPCHandle {
public static class EntityCaveSpiderNPC extends EntityCaveSpider implements NPCHolder {
private final CitizensNPC npc;
public EntityCaveSpiderNPC(World world, NPC npc) {
@ -31,15 +31,15 @@ public class CitizensCaveSpiderNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityChicken;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensChickenNPC extends CitizensMobNPC {
return (Chicken) getHandle().getBukkitEntity();
}
public static class EntityChickenNPC extends EntityChicken implements NPCHandle {
public static class EntityChickenNPC extends EntityChicken implements NPCHolder {
private final CitizensNPC npc;
public EntityChickenNPC(World world) {
@ -35,16 +35,16 @@ public class CitizensChickenNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityCow;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensCowNPC extends CitizensMobNPC {
return (Cow) getHandle().getBukkitEntity();
}
public static class EntityCowNPC extends EntityCow implements NPCHandle {
public static class EntityCowNPC extends EntityCow implements NPCHolder {
private final CitizensNPC npc;
public EntityCowNPC(World world) {
@ -35,16 +35,16 @@ public class CitizensCowNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityCreeper;
import net.minecraft.server.EntityWeatherLighting;
import net.minecraft.server.PathfinderGoalSelector;
@ -22,7 +22,7 @@ public class CitizensCreeperNPC extends CitizensMobNPC {
return (Creeper) getHandle().getBukkitEntity();
}
public static class EntityCreeperNPC extends EntityCreeper implements NPCHandle {
public static class EntityCreeperNPC extends EntityCreeper implements NPCHolder {
private final CitizensNPC npc;
public EntityCreeperNPC(World world) {
@ -40,16 +40,16 @@ public class CitizensCreeperNPC extends CitizensMobNPC {
public void a(EntityWeatherLighting entityweatherlighting) {
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityEnderDragon;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensEnderDragonNPC extends CitizensMobNPC {
return (EnderDragon) getHandle().getBukkitEntity();
}
public static class EntityEnderDragonNPC extends EntityEnderDragon implements NPCHandle {
public static class EntityEnderDragonNPC extends EntityEnderDragon implements NPCHolder {
private final CitizensNPC npc;
public EntityEnderDragonNPC(World world, NPC npc) {

View File

@ -5,7 +5,7 @@ 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.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.util.Messaging;
import net.minecraft.server.EntityEnderman;
import net.minecraft.server.PathfinderGoalSelector;
@ -59,7 +59,7 @@ public class CitizensEndermanNPC extends CitizensMobNPC implements Equipable {
return (Enderman) getHandle().getBukkitEntity();
}
public static class EntityEndermanNPC extends EntityEnderman implements NPCHandle {
public static class EntityEndermanNPC extends EntityEnderman implements NPCHolder {
private final CitizensNPC npc;
public EntityEndermanNPC(World world) {

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityGhast;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensGhastNPC extends CitizensMobNPC {
return (Ghast) getHandle().getBukkitEntity();
}
public static class EntityGhastNPC extends EntityGhast implements NPCHandle {
public static class EntityGhastNPC extends EntityGhast implements NPCHolder {
private final CitizensNPC npc;
public EntityGhastNPC(World world) {

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityGiantZombie;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensGiantNPC extends CitizensMobNPC {
return (Giant) getHandle().getBukkitEntity();
}
public static class EntityGiantNPC extends EntityGiantZombie implements NPCHandle {
public static class EntityGiantNPC extends EntityGiantZombie implements NPCHolder {
private final CitizensNPC npc;
public EntityGiantNPC(World world, NPC npc) {

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityIronGolem;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensIronGolemNPC extends CitizensMobNPC {
return (IronGolem) getHandle().getBukkitEntity();
}
public static class EntityIronGolemNPC extends EntityIronGolem implements NPCHandle {
public static class EntityIronGolemNPC extends EntityIronGolem implements NPCHolder {
private final CitizensNPC npc;
public EntityIronGolemNPC(World world, NPC npc) {
@ -31,15 +31,15 @@ public class CitizensIronGolemNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityMagmaCube;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensMagmaCubeNPC extends CitizensMobNPC {
return (MagmaCube) getHandle().getBukkitEntity();
}
public static class EntityMagmaCubeNPC extends EntityMagmaCube implements NPCHandle {
public static class EntityMagmaCubeNPC extends EntityMagmaCube implements NPCHolder {
private final CitizensNPC npc;
public EntityMagmaCubeNPC(World world) {

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityMushroomCow;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensMushroomCowNPC extends CitizensMobNPC {
return (MushroomCow) getHandle().getBukkitEntity();
}
public static class EntityMushroomCowNPC extends EntityMushroomCow implements NPCHandle {
public static class EntityMushroomCowNPC extends EntityMushroomCow implements NPCHolder {
private final CitizensNPC npc;
public EntityMushroomCowNPC(World world) {
@ -35,16 +35,16 @@ public class CitizensMushroomCowNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityOcelot;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensOcelotNPC extends CitizensMobNPC {
return (Ocelot) getHandle().getBukkitEntity();
}
public static class EntityOcelotNPC extends EntityOcelot implements NPCHandle {
public static class EntityOcelotNPC extends EntityOcelot implements NPCHolder {
private final CitizensNPC npc;
public EntityOcelotNPC(World world) {
@ -35,16 +35,16 @@ public class CitizensOcelotNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -4,7 +4,7 @@ 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.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.trait.Saddle;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.StringHelper;
@ -48,7 +48,7 @@ public class CitizensPigNPC extends CitizensMobNPC implements Equipable {
return (Pig) getHandle().getBukkitEntity();
}
public static class EntityPigNPC extends EntityPig implements NPCHandle {
public static class EntityPigNPC extends EntityPig implements NPCHolder {
private final CitizensNPC npc;
public EntityPigNPC(World world) {
@ -66,16 +66,16 @@ public class CitizensPigNPC extends CitizensMobNPC implements Equipable {
public void a(EntityWeatherLighting entityweatherlighting) {
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityPigZombie;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensPigZombieNPC extends CitizensMobNPC {
return (PigZombie) getHandle().getBukkitEntity();
}
public static class EntityPigZombieNPC extends EntityPigZombie implements NPCHandle {
public static class EntityPigZombieNPC extends EntityPigZombie implements NPCHolder {
private final CitizensNPC npc;
public EntityPigZombieNPC(World world) {

View File

@ -4,7 +4,7 @@ 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.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.trait.Sheared;
import net.citizensnpcs.trait.WoolColor;
import net.citizensnpcs.util.Messaging;
@ -58,7 +58,7 @@ public class CitizensSheepNPC extends CitizensMobNPC implements Equipable {
return (Sheep) getHandle().getBukkitEntity();
}
public static class EntitySheepNPC extends EntitySheep implements NPCHandle {
public static class EntitySheepNPC extends EntitySheep implements NPCHolder {
private final CitizensNPC npc;
public EntitySheepNPC(World world) {
@ -72,16 +72,16 @@ public class CitizensSheepNPC extends CitizensMobNPC implements Equipable {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntitySilverfish;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensSilverfishNPC extends CitizensMobNPC {
return (Silverfish) getHandle().getBukkitEntity();
}
public static class EntitySilverfishNPC extends EntitySilverfish implements NPCHandle {
public static class EntitySilverfishNPC extends EntitySilverfish implements NPCHolder {
private final CitizensNPC npc;
public EntitySilverfishNPC(World world) {
@ -35,16 +35,16 @@ public class CitizensSilverfishNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntitySkeleton;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensSkeletonNPC extends CitizensMobNPC {
return (Skeleton) getHandle().getBukkitEntity();
}
public static class EntitySkeletonNPC extends EntitySkeleton implements NPCHandle {
public static class EntitySkeletonNPC extends EntitySkeleton implements NPCHolder {
private final CitizensNPC npc;
public EntitySkeletonNPC(World world) {
@ -35,16 +35,16 @@ public class CitizensSkeletonNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntitySlime;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensSlimeNPC extends CitizensMobNPC {
return (Slime) getHandle().getBukkitEntity();
}
public static class EntitySlimeNPC extends EntitySlime implements NPCHandle {
public static class EntitySlimeNPC extends EntitySlime implements NPCHolder {
private final CitizensNPC npc;
public EntitySlimeNPC(World world) {
@ -36,16 +36,16 @@ public class CitizensSlimeNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntitySnowman;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensSnowmanNPC extends CitizensMobNPC {
return (Snowman) getHandle().getBukkitEntity();
}
public static class EntitySnowmanNPC extends EntitySnowman implements NPCHandle {
public static class EntitySnowmanNPC extends EntitySnowman implements NPCHolder {
private final CitizensNPC npc;
public EntitySnowmanNPC(World world, NPC npc) {
@ -31,15 +31,15 @@ public class CitizensSnowmanNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntitySpider;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensSpiderNPC extends CitizensMobNPC {
return (Spider) getHandle().getBukkitEntity();
}
public static class EntitySpiderNPC extends EntitySpider implements NPCHandle {
public static class EntitySpiderNPC extends EntitySpider implements NPCHolder {
private final CitizensNPC npc;
public EntitySpiderNPC(World world) {
@ -35,16 +35,16 @@ public class CitizensSpiderNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntitySquid;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensSquidNPC extends CitizensMobNPC {
return (Squid) getHandle().getBukkitEntity();
}
public static class EntitySquidNPC extends EntitySquid implements NPCHandle {
public static class EntitySquidNPC extends EntitySquid implements NPCHolder {
private final CitizensNPC npc;
public EntitySquidNPC(World world) {

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityVillager;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensVillagerNPC extends CitizensMobNPC {
return (Villager) getHandle().getBukkitEntity();
}
public static class EntityVillagerNPC extends EntityVillager implements NPCHandle {
public static class EntityVillagerNPC extends EntityVillager implements NPCHolder {
private final CitizensNPC npc;
public EntityVillagerNPC(World world) {
@ -35,16 +35,16 @@ public class CitizensVillagerNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityWolf;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensWolfNPC extends CitizensMobNPC {
return (Wolf) getHandle().getBukkitEntity();
}
public static class EntityWolfNPC extends EntityWolf implements NPCHandle {
public static class EntityWolfNPC extends EntityWolf implements NPCHolder {
private final CitizensNPC npc;
public EntityWolfNPC(World world) {
@ -35,16 +35,16 @@ public class CitizensWolfNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.npc.entity;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.minecraft.server.EntityZombie;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
@ -21,7 +21,7 @@ public class CitizensZombieNPC extends CitizensMobNPC {
return (Zombie) getHandle().getBukkitEntity();
}
public static class EntityZombieNPC extends EntityZombie implements NPCHandle {
public static class EntityZombieNPC extends EntityZombie implements NPCHolder {
private final CitizensNPC npc;
public EntityZombieNPC(World world) {
@ -35,16 +35,16 @@ public class CitizensZombieNPC extends CitizensMobNPC {
targetSelector = new PathfinderGoalSelector();
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public void z_() {
super.z_();
if (npc != null)
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
}
}

View File

@ -4,7 +4,7 @@ import java.io.IOException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.npc.network.NPCNetHandler;
import net.citizensnpcs.npc.network.NPCNetworkManager;
import net.citizensnpcs.npc.network.NPCSocket;
@ -16,7 +16,7 @@ import net.minecraft.server.NetHandler;
import net.minecraft.server.NetworkManager;
import net.minecraft.server.World;
public class EntityHumanNPC extends EntityPlayer implements NPCHandle {
public class EntityHumanNPC extends EntityPlayer implements NPCHolder {
private CitizensNPC npc;
public EntityHumanNPC(MinecraftServer minecraftServer, World world, String string,
@ -57,6 +57,11 @@ public class EntityHumanNPC extends EntityPlayer implements NPCHandle {
npc.update();
}
@Override
public NPC getNPC() {
return npc;
}
private void moveOnCurrentHeading() {
getControllerMove().c();
getControllerLook().a();
@ -76,9 +81,4 @@ public class EntityHumanNPC extends EntityPlayer implements NPCHandle {
a(aW, aX);
X = yaw; // TODO: this looks jerky
}
@Override
public NPC getNPC() {
return npc;
}
}

View File

@ -1,7 +1,6 @@
package net.citizensnpcs.trait;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
@ -9,12 +8,11 @@ import org.bukkit.entity.Ageable;
public class Age extends Trait implements Runnable, Toggleable {
private int age = 0;
private boolean locked = true;
private boolean ageable = false;
private final NPC npc;
private boolean locked = true;
public Age(NPC npc) {
this.npc = npc;
public Age() {
super("age");
}
@Override

View File

@ -8,7 +8,6 @@ import java.util.Map.Entry;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.ai.Goal;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.scripting.CompileCallback;
import net.citizensnpcs.api.scripting.ScriptFactory;
import net.citizensnpcs.api.trait.Trait;
@ -31,7 +30,6 @@ public class Behaviour extends Trait {
return new File(rootFolder, arg0);
}
};
private final NPC npc;
private final File rootFolder = new File(CitizensAPI.getScriptFolder(), "behaviours");
private final List<File> scripts = Lists.newArrayList();
{
@ -39,8 +37,8 @@ public class Behaviour extends Trait {
rootFolder.mkdirs();
}
public Behaviour(NPC npc) {
this.npc = npc;
public Behaviour() {
super("behaviour");
}
public void addScripts(Iterable<String> scripts) {

View File

@ -5,10 +5,10 @@ import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.npc.CitizensNPC;
import net.minecraft.server.EntityLiving;
import net.minecraft.server.EntityPlayer;
import org.bukkit.craftbukkit.entity.CraftLivingEntity;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@ -17,18 +17,21 @@ import org.bukkit.event.player.PlayerInteractEvent;
//TODO: reduce reliance on CitizensNPC
public class Controllable extends Trait implements Runnable, Listener, Toggleable {
private final CitizensNPC npc;
private boolean enabled;
public Controllable(NPC npc) {
this.npc = (CitizensNPC) npc;
super("controllable");
}
private EntityLiving getHandle() {
return ((CraftLivingEntity) npc.getBukkitEntity()).getHandle();
}
private void jump() {
boolean allowed = npc.getHandle().onGround;
boolean allowed = getHandle().onGround;
if (!allowed)
return;
npc.getHandle().motY = JUMP_VELOCITY;
getHandle().motY = JUMP_VELOCITY;
// TODO: make jumping work in liquid or make liquids float the npc
}
@ -43,7 +46,7 @@ public class Controllable extends Trait implements Runnable, Listener, Toggleabl
return;
EntityPlayer handle = ((CraftPlayer) event.getPlayer()).getHandle();
Action performed = event.getAction();
if (performed == Action.PHYSICAL || !handle.equals(npc.getHandle().passenger))
if (performed == Action.PHYSICAL || !handle.equals(getHandle().passenger))
return;
if (performed == Action.LEFT_CLICK_AIR || performed == Action.LEFT_CLICK_BLOCK) {
jump();
@ -55,20 +58,20 @@ public class Controllable extends Trait implements Runnable, Listener, Toggleabl
if (!npc.isSpawned() || !event.getNPC().equals(npc))
return;
EntityPlayer handle = ((CraftPlayer) event.getClicker()).getHandle();
if (npc.getHandle().passenger != null) {
if (npc.getHandle().passenger == handle) {
if (getHandle().passenger != null) {
if (getHandle().passenger == handle) {
event.getClicker().leaveVehicle();
}
return;
}
handle.setPassengerOf(npc.getHandle());
handle.setPassengerOf(getHandle());
}
@Override
public void run() {
if (!npc.isSpawned() || npc.getHandle().passenger == null)
if (!npc.isSpawned() || getHandle().passenger == null)
return;
EntityLiving handle = npc.getHandle();
EntityLiving handle = getHandle();
boolean onGround = handle.onGround;
handle.motX += handle.passenger.motX * (onGround ? GROUND_SPEED : AIR_SPEED);
handle.motZ += handle.passenger.motZ * (onGround ? GROUND_SPEED : AIR_SPEED);
@ -79,12 +82,12 @@ public class Controllable extends Trait implements Runnable, Listener, Toggleabl
key.setBoolean("enabled", enabled);
}
private static final double GROUND_SPEED = 4;
private static final double AIR_SPEED = 1.5;
private static final double JUMP_VELOCITY = 0.6;
@Override
public boolean toggle() {
return (enabled = !enabled);
}
private static final double AIR_SPEED = 1.5;
private static final double GROUND_SPEED = 4;
private static final double JUMP_VELOCITY = 0.6;
}

View File

@ -1,7 +1,6 @@
package net.citizensnpcs.trait;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
@ -10,20 +9,15 @@ import org.bukkit.Location;
public class CurrentLocation extends Trait implements Runnable {
private Location loc;
private final NPC npc;
public CurrentLocation(NPC npc) {
this.npc = npc;
public CurrentLocation() {
super("location");
}
public Location getLocation() {
return loc;
}
public void setLocation(Location loc) {
this.loc = loc;
}
@Override
public void load(DataKey key) throws NPCLoadException {
if (Bukkit.getWorld(key.getString("world")) == null)
@ -56,6 +50,10 @@ public class CurrentLocation extends Trait implements Runnable {
key.setDouble("pitch", loc.getPitch());
}
public void setLocation(Location loc) {
this.loc = loc;
}
@Override
public String toString() {
return "CurrentLocation{" + loc + "}";

View File

@ -6,7 +6,6 @@ import java.util.List;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
import net.minecraft.server.EntityLiving;
@ -19,10 +18,9 @@ import org.bukkit.entity.Player;
public class LookClose extends Trait implements Runnable, Toggleable {
private boolean enabled = Setting.DEFAULT_LOOK_CLOSE.asBoolean();
private Player lookingAt;
private final NPC npc;
public LookClose(NPC npc) {
this.npc = npc;
public LookClose() {
super("lookclose");
}
private void faceEntity(Entity from, Entity at) {
@ -49,23 +47,6 @@ public class LookClose extends Trait implements Runnable, Toggleable {
handle.X = handle.yaw;
}
@Override
public void load(DataKey key) throws NPCLoadException {
enabled = key.getBoolean("");
}
@Override
public void run() {
if (!enabled || npc.getAI().hasDestination())
return;
if (hasInvalidTarget()) {
findNewTarget();
}
if (lookingAt != null) {
faceEntity(npc.getBukkitEntity(), lookingAt);
}
}
private void findNewTarget() {
List<Entity> nearby = npc.getBukkitEntity().getNearbyEntities(2.5, 5, 2.5);
Collections.sort(nearby, new Comparator<Entity>() {
@ -96,6 +77,23 @@ public class LookClose extends Trait implements Runnable, Toggleable {
return false;
}
@Override
public void load(DataKey key) throws NPCLoadException {
enabled = key.getBoolean("");
}
@Override
public void run() {
if (!enabled || npc.getAI().hasDestination())
return;
if (hasInvalidTarget()) {
findNewTarget();
}
if (lookingAt != null) {
faceEntity(npc.getBukkitEntity(), lookingAt);
}
}
@Override
public void save(DataKey key) {
key.setBoolean("", enabled);

View File

@ -1,18 +1,16 @@
package net.citizensnpcs.trait;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
import org.bukkit.entity.Creeper;
public class Powered extends Trait implements Toggleable {
private final NPC npc;
private boolean powered;
public Powered(NPC npc) {
this.npc = npc;
public Powered() {
super("powered");
}
@Override

View File

@ -2,7 +2,6 @@ package net.citizensnpcs.trait;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
@ -12,12 +11,11 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractEntityEvent;
public class Saddle extends Trait implements Toggleable, Listener {
private final NPC npc;
private boolean saddle;
private boolean pig;
private boolean saddle;
public Saddle(NPC npc) {
this.npc = npc;
public Saddle() {
super("saddle");
}
@Override

View File

@ -2,7 +2,6 @@ package net.citizensnpcs.trait;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
@ -12,11 +11,10 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerShearEntityEvent;
public class Sheared extends Trait implements Toggleable, Listener {
private final NPC npc;
private boolean sheared;
public Sheared(NPC npc) {
this.npc = npc;
public Sheared() {
super("sheared");
}
@Override

View File

@ -1,7 +1,6 @@
package net.citizensnpcs.trait;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
@ -9,11 +8,10 @@ import org.bukkit.entity.Villager;
import org.bukkit.entity.Villager.Profession;
public class VillagerProfession extends Trait {
private final NPC npc;
private Profession profession = Profession.FARMER;
public VillagerProfession(NPC npc) {
this.npc = npc;
public VillagerProfession() {
super("profession");
}
@Override

View File

@ -2,7 +2,6 @@ package net.citizensnpcs.trait;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
@ -14,11 +13,10 @@ import org.bukkit.event.entity.SheepDyeWoolEvent;
public class WoolColor extends Trait implements Listener {
private DyeColor color = DyeColor.WHITE;
private final NPC npc;
boolean sheep = false;
public WoolColor(NPC npc) {
this.npc = npc;
public WoolColor() {
super("woolcolor");
}
@Override

View File

@ -1,15 +1,16 @@
package net.citizensnpcs.trait.text;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.event.NPCRightClickEvent;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.editor.Editor;
@ -17,6 +18,7 @@ import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.trait.Toggleable;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.Paginator;
import net.citizensnpcs.util.Util;
import net.minecraft.server.EntityHuman;
import net.minecraft.server.EntityLiving;
@ -26,19 +28,20 @@ import org.bukkit.conversations.ConversationAbandonedEvent;
import org.bukkit.conversations.ConversationAbandonedListener;
import org.bukkit.conversations.ConversationFactory;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
public class Text extends Trait implements Runnable, Toggleable, ConversationAbandonedListener {
private final Map<String, Calendar> cooldowns = new HashMap<String, Calendar>();
public class Text extends Trait implements Runnable, Toggleable, Listener, ConversationAbandonedListener {
private final Map<String, Date> cooldowns = new HashMap<String, Date>();
private int currentIndex;
private final NPC npc;
private final Plugin plugin;
private boolean randomTalker = Setting.DEFAULT_RANDOM_TALKER.asBoolean();
private boolean talkClose = Setting.DEFAULT_TALK_CLOSE.asBoolean();
private final List<String> text = new ArrayList<String>();
public Text(NPC npc) {
this.npc = npc;
public Text() {
super("text");
this.plugin = Bukkit.getPluginManager().getPlugin("Citizens");
}
@ -98,6 +101,14 @@ public class Text extends Trait implements Runnable, Toggleable, ConversationAba
populateDefaultText();
}
@EventHandler
public void onRightClick(NPCRightClickEvent event) {
if (!event.getNPC().equals(npc))
return;
if (Util.isSettingFulfilled(event.getClicker(), Setting.TALK_ITEM) && !shouldTalkClose())
sendText(event.getClicker());
}
private void populateDefaultText() {
text.addAll(Setting.DEFAULT_TEXT.asList());
}
@ -116,17 +127,17 @@ public class Text extends Trait implements Runnable, Toggleable, ConversationAba
Player player = (Player) search.getBukkitEntity();
// If the cooldown is not expired, do not send text
if (cooldowns.get(player.getName()) != null) {
if (!Calendar.getInstance().after(cooldowns.get(player.getName())))
if (!new Date().after(cooldowns.get(player.getName())))
return;
cooldowns.remove(player.getName());
}
if (sendText(player)) {
// Add a cooldown if the text was successfully sent
Calendar wait = Calendar.getInstance();
wait.add(
Calendar.SECOND,
(new Random().nextInt(Setting.TALK_CLOSE_MAXIMUM_COOLDOWN.asInt()) + Setting.TALK_CLOSE_MINIMUM_COOLDOWN
.asInt()));
Date wait = new Date();
int secondsDelta = new Random().nextInt(Setting.TALK_CLOSE_MAXIMUM_COOLDOWN.asInt())
+ Setting.TALK_CLOSE_MINIMUM_COOLDOWN.asInt();
long millisecondsDelta = TimeUnit.MILLISECONDS.convert(secondsDelta, TimeUnit.SECONDS);
wait.setTime(wait.getTime() + millisecondsDelta);
cooldowns.put(player.getName(), wait);
}
}
@ -162,7 +173,7 @@ public class Text extends Trait implements Runnable, Toggleable, ConversationAba
currentIndex = 0;
index = currentIndex++;
}
npc.chat(player, text.get(index));
Messaging.sendWithNPC(player, Setting.CHAT_PREFIX.asString() + text.get(index), npc);
return true;
}

View File

@ -11,7 +11,9 @@ public class GenericWaypointCallback extends NavigationCallback {
private AI ai;
private Location dest;
private boolean executing;
boolean hackfix = false;
private Iterator<Waypoint> itr;
private final Iterable<Waypoint> provider;
public GenericWaypointCallback(Iterable<Waypoint> provider) {
@ -40,8 +42,6 @@ public class GenericWaypointCallback extends NavigationCallback {
ai.setDestination(dest);
}
}
boolean hackfix = false;
@Override
public boolean onCancel(AI ai, CancelReason reason) {

View File

@ -34,6 +34,8 @@ public interface WaypointProvider {
*/
public void load(DataKey key);
public void onAttach();
/**
* Saves to the specified {@link DataKey}.
*
@ -41,6 +43,4 @@ public interface WaypointProvider {
* The key to save to
*/
public void save(DataKey key);
public void onAttach();
}

View File

@ -5,7 +5,6 @@ import java.util.Map;
import java.util.Map.Entry;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.editor.Editor;
@ -13,13 +12,11 @@ import net.citizensnpcs.editor.Editor;
import org.bukkit.entity.Player;
public class Waypoints extends Trait {
private final NPC npc;
private WaypointProvider provider = new LinearWaypointProvider();
private String providerName = "linear";
public Waypoints(NPC npc) {
this.npc = npc;
npc.getAI().registerNavigationCallback(provider.getCallback());
public Waypoints() {
super("waypoints");
}
private WaypointProvider create(Class<? extends WaypointProvider> clazz) {
@ -32,11 +29,6 @@ public class Waypoints extends Trait {
}
}
@Override
public void onNPCSpawn() {
npc.getAI().registerNavigationCallback(provider.getCallback());
}
public Editor getEditor(Player player) {
return provider.createEditor(player);
}
@ -56,6 +48,11 @@ public class Waypoints extends Trait {
provider.load(key.getRelative(providerName));
}
@Override
public void onNPCSpawn() {
npc.getAI().registerNavigationCallback(provider.getCallback());
}
@Override
public void save(DataKey key) {
if (provider == null)

View File

@ -22,6 +22,12 @@ public class Messaging {
log(msg);
}
private static String getFormatted(Object[] msg) {
String toFormat = msg[0].toString();
Object[] args = msg.length > 1 ? Arrays.copyOfRange(msg, 1, msg.length) : new Object[] {};
return String.format(toFormat, args);
}
public static void log(Level level, Object... msg) {
Bukkit.getLogger().log(level, "[Citizens] " + SPACE.join(msg));
}
@ -30,12 +36,6 @@ public class Messaging {
log(Level.INFO, msg);
}
private static String getFormatted(Object[] msg) {
String toFormat = msg[0].toString();
Object[] args = msg.length > 1 ? Arrays.copyOfRange(msg, 1, msg.length) : new Object[] {};
return String.format(toFormat, args);
}
public static void logF(Object... msg) {
log(getFormatted(msg));
}
@ -46,12 +46,6 @@ public class Messaging {
sender.sendMessage(joined);
}
public static void sendF(CommandSender sender, Object... msg) {
String joined = getFormatted(msg);
joined = StringHelper.parseColors(joined);
sender.sendMessage(joined);
}
public static void sendError(CommandSender sender, Object... msg) {
send(sender, ChatColor.RED.toString() + SPACE.join(msg));
}
@ -60,6 +54,12 @@ public class Messaging {
sendF(sender, ChatColor.RED.toString() + SPACE.join(msg));
}
public static void sendF(CommandSender sender, Object... msg) {
String joined = getFormatted(msg);
joined = StringHelper.parseColors(joined);
sender.sendMessage(joined);
}
public static void sendWithNPC(CommandSender sender, Object msg, NPC npc) {
String send = msg.toString();

View File

@ -26,6 +26,8 @@ public class Util {
private Util() {
}
private static final Map<Class<?>, Class<?>> primitiveClassMap = Maps.newHashMap();
/**
* Given a set of instantiation parameters, attempts to find a matching
* constructor with the greatest number of matching class parameters and
@ -85,6 +87,17 @@ public class Util {
return null;
}
public static boolean isSettingFulfilled(Player player, Setting setting) {
String parts = setting.asString();
if (parts.contains("*"))
return true;
for (String part : Splitter.on(',').split(parts)) {
if (Material.matchMaterial(part) == player.getItemInHand().getType()) {
return true;
}
}
return false;
}
private static boolean searchInterfaces(Class<?> class1, Class<?> class2) {
for (Class<?> test : class1.getInterfaces())
if (test == class2)
@ -92,7 +105,31 @@ public class Util {
return false;
}
private static final Map<Class<?>, Class<?>> primitiveClassMap = Maps.newHashMap();
public static void sendPacketNearby(Location location, Packet packet, double radius) {
radius *= radius;
final World world = location.getWorld();
for (Player ply : Bukkit.getServer().getOnlinePlayers()) {
if (ply == null || world != ply.getWorld()) {
continue;
}
if (location.distanceSquared(ply.getLocation()) > radius) {
continue;
}
((CraftPlayer) ply).getHandle().netServerHandler.sendPacket(packet);
}
}
public static void sendToOnline(Packet... packets) {
Validate.notNull(packets, "packets cannot be null");
for (Player player : Bukkit.getOnlinePlayers()) {
if (player == null || !player.isOnline())
continue;
for (Packet packet : packets) {
((CraftPlayer) player).getHandle().netServerHandler.sendPacket(packet);
}
}
}
static {
primitiveClassMap.put(Boolean.class, boolean.class);
primitiveClassMap.put(Byte.class, byte.class);
@ -111,41 +148,4 @@ public class Util {
primitiveClassMap.put(float.class, Float.class);
primitiveClassMap.put(double.class, Double.class);
}
public static boolean isSettingFulfilled(Player player, Setting setting) {
String parts = setting.asString();
if (parts.contains("*"))
return true;
for (String part : Splitter.on(',').split(parts)) {
if (Material.matchMaterial(part) == player.getItemInHand().getType()) {
return true;
}
}
return false;
}
public static void sendToOnline(Packet... packets) {
Validate.notNull(packets, "packets cannot be null");
for (Player player : Bukkit.getOnlinePlayers()) {
if (player == null || !player.isOnline())
continue;
for (Packet packet : packets) {
((CraftPlayer) player).getHandle().netServerHandler.sendPacket(packet);
}
}
}
public static void sendPacketNearby(Location location, Packet packet, double radius) {
radius *= radius;
final World world = location.getWorld();
for (Player ply : Bukkit.getServer().getOnlinePlayers()) {
if (ply == null || world != ply.getWorld()) {
continue;
}
if (location.distanceSquared(ply.getLocation()) > radius) {
continue;
}
((CraftPlayer) ply).getHandle().netServerHandler.sendPacket(packet);
}
}
}