Implement NPC SpeechController

This commit is contained in:
Jeremy Schroeder 2012-12-22 08:23:52 -05:00
parent c4cfd02b1a
commit 1baa5c0f01
6 changed files with 1034 additions and 871 deletions

View File

@ -1,351 +1,363 @@
package net.citizensnpcs;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.CitizensPlugin;
import net.citizensnpcs.api.event.CitizensDisableEvent;
import net.citizensnpcs.api.event.CitizensEnableEvent;
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.scripting.EventRegistrar;
import net.citizensnpcs.api.scripting.ObjectProvider;
import net.citizensnpcs.api.scripting.ScriptCompiler;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitFactory;
import net.citizensnpcs.command.CommandContext;
import net.citizensnpcs.command.CommandManager;
import net.citizensnpcs.command.CommandManager.CommandInfo;
import net.citizensnpcs.command.Injector;
import net.citizensnpcs.command.RequirementsProcessor;
import net.citizensnpcs.command.command.AdminCommands;
import net.citizensnpcs.command.command.EditorCommands;
import net.citizensnpcs.command.command.HelpCommands;
import net.citizensnpcs.command.command.NPCCommands;
import net.citizensnpcs.command.command.ScriptCommands;
import net.citizensnpcs.command.command.TemplateCommands;
import net.citizensnpcs.command.command.TraitCommands;
import net.citizensnpcs.command.command.WaypointCommands;
import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.npc.CitizensNPCRegistry;
import net.citizensnpcs.npc.CitizensTraitFactory;
import net.citizensnpcs.npc.NPCSelector;
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.StringHelper;
import net.citizensnpcs.util.Util;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import com.google.common.collect.Iterables;
import com.google.common.io.Files;
import com.google.common.io.InputSupplier;
public class Citizens extends JavaPlugin implements CitizensPlugin {
private final CommandManager commands = new CommandManager();
private boolean compatible;
private Settings config;
private CitizensNPCRegistry npcRegistry;
private NPCDataStore saves;
private NPCSelector selector;
private CitizensTraitFactory traitFactory;
private void despawnNPCs() {
Iterator<NPC> itr = npcRegistry.iterator();
while (itr.hasNext()) {
NPC npc = itr.next();
try {
npc.despawn();
for (Trait trait : npc.getTraits())
trait.onRemove();
} catch (Throwable e) {
e.printStackTrace();
// ensure that all entities are despawned
}
itr.remove();
}
}
public void test() {
getDataFolder().mkdirs();
final InputStream dllResource = getResource("path/to/dll");
try {
Files.copy(new InputSupplier<InputStream>() {
@Override
public InputStream getInput() throws IOException {
return dllResource;
}
}, new File(getDataFolder(), "name.dll"));
} catch (IOException e) {
e.printStackTrace();
}
// code here
new File(getDataFolder(), "name.dll").delete();
}
private void enableSubPlugins() {
File root = new File(getDataFolder(), Setting.SUBPLUGIN_FOLDER.asString());
if (!root.exists() || !root.isDirectory())
return;
File[] files = root.listFiles();
for (File file : files) {
Plugin plugin;
try {
plugin = Bukkit.getPluginManager().loadPlugin(file);
} catch (Exception e) {
continue;
}
if (plugin == null)
continue;
// code beneath modified from CraftServer
try {
Messaging.logTr(Messages.LOADING_SUB_PLUGIN, plugin.getDescription().getFullName());
plugin.onLoad();
} catch (Throwable ex) {
Messaging.severeTr(Messages.ERROR_INITALISING_SUB_PLUGIN, ex.getMessage(), plugin
.getDescription().getFullName());
ex.printStackTrace();
}
}
NMS.loadPlugins();
}
public CommandInfo getCommandInfo(String rootCommand, String modifier) {
return commands.getCommand(rootCommand, modifier);
}
public Iterable<CommandInfo> getCommands(String base) {
return commands.getCommands(base);
}
@Override
public NPCRegistry getNPCRegistry() {
return npcRegistry;
}
public NPCSelector getNPCSelector() {
return selector;
}
@Override
public File getScriptFolder() {
return new File(getDataFolder(), "scripts");
}
@Override
public TraitFactory getTraitFactory() {
return traitFactory;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String cmdName, String[] args) {
String modifier = args.length > 0 ? args[0] : "";
if (!commands.hasCommand(command, modifier) && !modifier.isEmpty()) {
return suggestClosestModifier(sender, command.getName(), modifier);
}
NPC npc = selector == null ? null : selector.getSelected(sender);
// TODO: change the args supplied to a context style system for
// flexibility (ie. adding more context in the future without
// changing everything)
Object[] methodArgs = { sender, npc };
return commands.executeSafe(command, args, sender, methodArgs);
}
@Override
public void onDisable() {
Bukkit.getPluginManager().callEvent(new CitizensDisableEvent());
Editor.leaveAll();
CitizensAPI.shutdown();
// Don't bother with this part if MC versions are not compatible
if (compatible) {
saves.storeAll(npcRegistry);
saves.saveToDiskImmediate();
despawnNPCs();
npcRegistry = null;
}
}
@Override
public void onEnable() {
CitizensAPI.setImplementation(this);
// Disable if the server is not using the compatible Minecraft version
String mcVersion = Util.getMinecraftVersion();
compatible = mcVersion.startsWith(COMPATIBLE_MC_VERSION);
if (!compatible) {
Messaging.severeTr(Messages.CITIZENS_INCOMPATIBLE, getDescription().getVersion(), mcVersion);
getServer().getPluginManager().disablePlugin(this);
return;
}
config = new Settings(getDataFolder());
registerScriptHelpers();
saves = NPCDataStore.create(getDataFolder());
if (saves == null) {
Messaging.severeTr(Messages.FAILED_LOAD_SAVES);
getServer().getPluginManager().disablePlugin(this);
return;
}
npcRegistry = new CitizensNPCRegistry(saves);
traitFactory = new CitizensTraitFactory();
selector = new NPCSelector(this);
getServer().getPluginManager().registerEvents(new EventListen(), this);
if (Setting.NPC_COST.asDouble() > 0)
setupEconomy();
registerCommands();
enableSubPlugins();
// Setup NPCs after all plugins have been enabled (allows for multiworld
// support and for NPCs to properly register external settings)
if (getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
@Override
public void run() {
saves.loadInto(npcRegistry);
startMetrics();
scheduleSaveTask(Setting.SAVE_TASK_DELAY.asInt());
Bukkit.getPluginManager().callEvent(new CitizensEnableEvent());
}
}, 1) == -1) {
Messaging.severeTr(Messages.LOAD_TASK_NOT_SCHEDULED);
getServer().getPluginManager().disablePlugin(this);
}
}
@Override
public void onImplementationChanged() {
Messaging.severeTr(Messages.CITIZENS_IMPLEMENTATION_DISABLED);
Bukkit.getPluginManager().disablePlugin(this);
}
public void registerCommandClass(Class<?> clazz) {
try {
commands.register(clazz);
} catch (Throwable ex) {
Messaging.logTr(Messages.CITIZENS_INVALID_COMMAND_CLASS);
ex.printStackTrace();
}
}
private void registerCommands() {
commands.setInjector(new Injector(this));
commands.registerAnnotationProcessor(new RequirementsProcessor());
// Register command classes
commands.register(AdminCommands.class);
commands.register(EditorCommands.class);
commands.register(HelpCommands.class);
commands.register(NPCCommands.class);
commands.register(ScriptCommands.class);
commands.register(TemplateCommands.class);
commands.register(TraitCommands.class);
commands.register(WaypointCommands.class);
}
private void registerScriptHelpers() {
ScriptCompiler compiler = CitizensAPI.getScriptCompiler();
compiler.registerGlobalContextProvider(new EventRegistrar(this));
compiler.registerGlobalContextProvider(new ObjectProvider("plugin", this));
}
public void reload() throws NPCLoadException {
Editor.leaveAll();
config.reload();
despawnNPCs();
saves.loadInto(npcRegistry);
getServer().getPluginManager().callEvent(new CitizensReloadEvent());
}
private void scheduleSaveTask(int delay) {
Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
@Override
public void run() {
storeNPCs();
saves.saveToDisk();
}
});
}
private void setupEconomy() {
try {
RegisteredServiceProvider<Economy> provider = Bukkit.getServicesManager().getRegistration(
Economy.class);
if (provider != null && provider.getProvider() != null) {
Economy economy = provider.getProvider();
Bukkit.getPluginManager().registerEvents(new PaymentListener(economy), this);
}
} catch (NoClassDefFoundError e) {
Messaging.logTr(Messages.ERROR_LOADING_ECONOMY);
}
}
private void startMetrics() {
try {
Metrics metrics = new Metrics(Citizens.this);
if (metrics.isOptOut())
return;
metrics.addCustomData(new Metrics.Plotter("Total NPCs") {
@Override
public int getValue() {
if (npcRegistry == null)
return 0;
return Iterables.size(npcRegistry);
}
});
traitFactory.addPlotters(metrics.createGraph("traits"));
saves.addPlotters(metrics.createGraph("Storage type"));
metrics.start();
} catch (IOException e) {
Messaging.logTr(Messages.METRICS_ERROR_NOTIFICATION, e.getMessage());
}
}
public void storeNPCs() {
if (saves == null)
return;
for (NPC npc : npcRegistry)
saves.store(npc);
}
public void storeNPCs(CommandContext args) {
storeNPCs();
boolean async = args.hasFlag('a');
if (async)
saves.saveToDisk();
else
saves.saveToDiskImmediate();
}
private boolean suggestClosestModifier(CommandSender sender, String command, String modifier) {
String closest = commands.getClosestCommandModifier(command, modifier);
if (!closest.isEmpty()) {
sender.sendMessage(ChatColor.GRAY + Messaging.tr(Messages.UNKNOWN_COMMAND));
sender.sendMessage(StringHelper.wrap(" /") + command + " " + StringHelper.wrap(closest));
return true;
}
return false;
}
private static final String COMPATIBLE_MC_VERSION = "1.4";
package net.citizensnpcs;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.CitizensPlugin;
import net.citizensnpcs.api.ai.speech.SpeechFactory;
import net.citizensnpcs.api.event.CitizensDisableEvent;
import net.citizensnpcs.api.event.CitizensEnableEvent;
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.scripting.EventRegistrar;
import net.citizensnpcs.api.scripting.ObjectProvider;
import net.citizensnpcs.api.scripting.ScriptCompiler;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitFactory;
import net.citizensnpcs.command.CommandContext;
import net.citizensnpcs.command.CommandManager;
import net.citizensnpcs.command.CommandManager.CommandInfo;
import net.citizensnpcs.command.Injector;
import net.citizensnpcs.command.RequirementsProcessor;
import net.citizensnpcs.command.command.AdminCommands;
import net.citizensnpcs.command.command.EditorCommands;
import net.citizensnpcs.command.command.HelpCommands;
import net.citizensnpcs.command.command.NPCCommands;
import net.citizensnpcs.command.command.ScriptCommands;
import net.citizensnpcs.command.command.TemplateCommands;
import net.citizensnpcs.command.command.TraitCommands;
import net.citizensnpcs.command.command.WaypointCommands;
import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.npc.CitizensNPCRegistry;
import net.citizensnpcs.npc.CitizensTraitFactory;
import net.citizensnpcs.npc.NPCSelector;
import net.citizensnpcs.npc.ai.speech.Chat;
import net.citizensnpcs.npc.ai.speech.CitizensSpeechFactory;
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.StringHelper;
import net.citizensnpcs.util.Util;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import com.google.common.collect.Iterables;
import com.google.common.io.Files;
import com.google.common.io.InputSupplier;
public class Citizens extends JavaPlugin implements CitizensPlugin {
private final CommandManager commands = new CommandManager();
private boolean compatible;
private Settings config;
private CitizensNPCRegistry npcRegistry;
private NPCDataStore saves;
private NPCSelector selector;
private CitizensTraitFactory traitFactory;
private CitizensSpeechFactory speechFactory;
private void despawnNPCs() {
Iterator<NPC> itr = npcRegistry.iterator();
while (itr.hasNext()) {
NPC npc = itr.next();
try {
npc.despawn();
for (Trait trait : npc.getTraits())
trait.onRemove();
} catch (Throwable e) {
e.printStackTrace();
// ensure that all entities are despawned
}
itr.remove();
}
}
public void test() {
getDataFolder().mkdirs();
final InputStream dllResource = getResource("path/to/dll");
try {
Files.copy(new InputSupplier<InputStream>() {
@Override
public InputStream getInput() throws IOException {
return dllResource;
}
}, new File(getDataFolder(), "name.dll"));
} catch (IOException e) {
e.printStackTrace();
}
// code here
new File(getDataFolder(), "name.dll").delete();
}
private void enableSubPlugins() {
File root = new File(getDataFolder(), Setting.SUBPLUGIN_FOLDER.asString());
if (!root.exists() || !root.isDirectory())
return;
File[] files = root.listFiles();
for (File file : files) {
Plugin plugin;
try {
plugin = Bukkit.getPluginManager().loadPlugin(file);
} catch (Exception e) {
continue;
}
if (plugin == null)
continue;
// code beneath modified from CraftServer
try {
Messaging.logTr(Messages.LOADING_SUB_PLUGIN, plugin.getDescription().getFullName());
plugin.onLoad();
} catch (Throwable ex) {
Messaging.severeTr(Messages.ERROR_INITALISING_SUB_PLUGIN, ex.getMessage(), plugin
.getDescription().getFullName());
ex.printStackTrace();
}
}
NMS.loadPlugins();
}
public CommandInfo getCommandInfo(String rootCommand, String modifier) {
return commands.getCommand(rootCommand, modifier);
}
public Iterable<CommandInfo> getCommands(String base) {
return commands.getCommands(base);
}
@Override
public NPCRegistry getNPCRegistry() {
return npcRegistry;
}
public NPCSelector getNPCSelector() {
return selector;
}
@Override
public File getScriptFolder() {
return new File(getDataFolder(), "scripts");
}
@Override
public TraitFactory getTraitFactory() {
return traitFactory;
}
@Override
public SpeechFactory getSpeechFactory() {
return speechFactory;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String cmdName, String[] args) {
String modifier = args.length > 0 ? args[0] : "";
if (!commands.hasCommand(command, modifier) && !modifier.isEmpty()) {
return suggestClosestModifier(sender, command.getName(), modifier);
}
NPC npc = selector == null ? null : selector.getSelected(sender);
// TODO: change the args supplied to a context style system for
// flexibility (ie. adding more context in the future without
// changing everything)
Object[] methodArgs = { sender, npc };
return commands.executeSafe(command, args, sender, methodArgs);
}
@Override
public void onDisable() {
Bukkit.getPluginManager().callEvent(new CitizensDisableEvent());
Editor.leaveAll();
CitizensAPI.shutdown();
// Don't bother with this part if MC versions are not compatible
if (compatible) {
saves.storeAll(npcRegistry);
saves.saveToDiskImmediate();
despawnNPCs();
npcRegistry = null;
}
}
@Override
public void onEnable() {
CitizensAPI.setImplementation(this);
// Disable if the server is not using the compatible Minecraft version
String mcVersion = Util.getMinecraftVersion();
compatible = mcVersion.startsWith(COMPATIBLE_MC_VERSION);
if (!compatible) {
Messaging.severeTr(Messages.CITIZENS_INCOMPATIBLE, getDescription().getVersion(), mcVersion);
getServer().getPluginManager().disablePlugin(this);
return;
}
config = new Settings(getDataFolder());
registerScriptHelpers();
saves = NPCDataStore.create(getDataFolder());
if (saves == null) {
Messaging.severeTr(Messages.FAILED_LOAD_SAVES);
getServer().getPluginManager().disablePlugin(this);
return;
}
npcRegistry = new CitizensNPCRegistry(saves);
traitFactory = new CitizensTraitFactory();
selector = new NPCSelector(this);
speechFactory = new CitizensSpeechFactory();
speechFactory.register(Chat.class, "chat");
getServer().getPluginManager().registerEvents(new EventListen(), this);
if (Setting.NPC_COST.asDouble() > 0)
setupEconomy();
registerCommands();
enableSubPlugins();
// Setup NPCs after all plugins have been enabled (allows for multiworld
// support and for NPCs to properly register external settings)
if (getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
@Override
public void run() {
saves.loadInto(npcRegistry);
startMetrics();
scheduleSaveTask(Setting.SAVE_TASK_DELAY.asInt());
Bukkit.getPluginManager().callEvent(new CitizensEnableEvent());
}
}, 1) == -1) {
Messaging.severeTr(Messages.LOAD_TASK_NOT_SCHEDULED);
getServer().getPluginManager().disablePlugin(this);
}
}
@Override
public void onImplementationChanged() {
Messaging.severeTr(Messages.CITIZENS_IMPLEMENTATION_DISABLED);
Bukkit.getPluginManager().disablePlugin(this);
}
public void registerCommandClass(Class<?> clazz) {
try {
commands.register(clazz);
} catch (Throwable ex) {
Messaging.logTr(Messages.CITIZENS_INVALID_COMMAND_CLASS);
ex.printStackTrace();
}
}
private void registerCommands() {
commands.setInjector(new Injector(this));
commands.registerAnnotationProcessor(new RequirementsProcessor());
// Register command classes
commands.register(AdminCommands.class);
commands.register(EditorCommands.class);
commands.register(HelpCommands.class);
commands.register(NPCCommands.class);
commands.register(ScriptCommands.class);
commands.register(TemplateCommands.class);
commands.register(TraitCommands.class);
commands.register(WaypointCommands.class);
}
private void registerScriptHelpers() {
ScriptCompiler compiler = CitizensAPI.getScriptCompiler();
compiler.registerGlobalContextProvider(new EventRegistrar(this));
compiler.registerGlobalContextProvider(new ObjectProvider("plugin", this));
}
public void reload() throws NPCLoadException {
Editor.leaveAll();
config.reload();
despawnNPCs();
saves.loadInto(npcRegistry);
getServer().getPluginManager().callEvent(new CitizensReloadEvent());
}
private void scheduleSaveTask(int delay) {
Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
@Override
public void run() {
storeNPCs();
saves.saveToDisk();
}
});
}
private void setupEconomy() {
try {
RegisteredServiceProvider<Economy> provider = Bukkit.getServicesManager().getRegistration(
Economy.class);
if (provider != null && provider.getProvider() != null) {
Economy economy = provider.getProvider();
Bukkit.getPluginManager().registerEvents(new PaymentListener(economy), this);
}
} catch (NoClassDefFoundError e) {
Messaging.logTr(Messages.ERROR_LOADING_ECONOMY);
}
}
private void startMetrics() {
try {
Metrics metrics = new Metrics(Citizens.this);
if (metrics.isOptOut())
return;
metrics.addCustomData(new Metrics.Plotter("Total NPCs") {
@Override
public int getValue() {
if (npcRegistry == null)
return 0;
return Iterables.size(npcRegistry);
}
});
traitFactory.addPlotters(metrics.createGraph("traits"));
saves.addPlotters(metrics.createGraph("Storage type"));
metrics.start();
} catch (IOException e) {
Messaging.logTr(Messages.METRICS_ERROR_NOTIFICATION, e.getMessage());
}
}
public void storeNPCs() {
if (saves == null)
return;
for (NPC npc : npcRegistry)
saves.store(npc);
}
public void storeNPCs(CommandContext args) {
storeNPCs();
boolean async = args.hasFlag('a');
if (async)
saves.saveToDisk();
else
saves.saveToDiskImmediate();
}
private boolean suggestClosestModifier(CommandSender sender, String command, String modifier) {
String closest = commands.getClosestCommandModifier(command, modifier);
if (!closest.isEmpty()) {
sender.sendMessage(ChatColor.GRAY + Messaging.tr(Messages.UNKNOWN_COMMAND));
sender.sendMessage(StringHelper.wrap(" /") + command + " " + StringHelper.wrap(closest));
return true;
}
return false;
}
private static final String COMPATIBLE_MC_VERSION = "1.4";
}

View File

@ -1,142 +1,150 @@
package net.citizensnpcs;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.api.util.Storage;
import net.citizensnpcs.api.util.YamlStorage;
import com.google.common.collect.Lists;
public class Settings {
private final Storage config;
private final DataKey root;
public Settings(File folder) {
config = new YamlStorage(new File(folder, "config.yml"), "Citizens Configuration");
root = config.getKey("");
config.load();
for (Setting setting : Setting.values()) {
if (!root.keyExists(setting.path)) {
setting.setAtKey(root);
} else
setting.loadFromKey(root);
}
save();
}
public void reload() {
config.load();
for (Setting setting : Setting.values())
if (root.keyExists(setting.path))
setting.loadFromKey(root);
save();
}
public void save() {
config.save();
}
public enum Setting {
CHAT_PREFIX("npc.chat.prefix", "[<npc>]: "),
DATABASE_DRIVER("storage.database.driver", ""),
DATABASE_PASSWORD("storage.database.password", ""),
DATABASE_URL("storage.database.url", ""),
DATABASE_USERNAME("storage.database.username", ""),
DEBUG_MODE("general.debug-mode", false),
DEFAULT_LOOK_CLOSE("npc.default.look-close.enabled", false),
DEFAULT_LOOK_CLOSE_RANGE("npc.default.look-close.range", 5),
DEFAULT_NPC_LIMIT("npc.limits.default-limit", 10),
DEFAULT_PATHFINDING_RANGE("npc.default.pathfinding.range", 25F),
DEFAULT_RANDOM_TALKER("npc.default.random-talker", true),
DEFAULT_REALISTIC_LOOKING("npc.default.realistic-looking", false),
DEFAULT_STATIONARY_TICKS("npc.default.stationary-ticks", -1),
DEFAULT_TALK_CLOSE("npc.default.talk-close.enabled", false),
DEFAULT_TALK_CLOSE_RANGE("npc.default.talk-close.range", 5),
DEFAULT_TEXT("npc.default.text.0", "Hi, I'm <npc>!") {
@Override
public void loadFromKey(DataKey root) {
List<String> list = new ArrayList<String>();
for (DataKey key : root.getRelative("npc.default.text").getSubKeys())
list.add(key.getString(""));
value = list;
}
},
HIGHLIGHT_COLOUR("general.color-scheme.message-highlight", "<e>"),
KEEP_CHUNKS_LOADED("npc.chunks.always-keep-loaded", false),
LOCALE("general.translation.locale", ""),
MAX_NPC_LIMIT_CHECKS("npc.limits.max-permission-checks", 100),
MAX_SPEED("npc.limits.max-speed", 100),
MESSAGE_COLOUR("general.color-scheme.message", "<a>"),
NPC_COST("economy.npc.cost", 100D),
QUICK_SELECT("npc.selection.quick-select", false),
REMOVE_PLAYERS_FROM_PLAYER_LIST("npc.player.remove-from-list", true),
SAVE_TASK_DELAY("storage.save-task.delay", 20 * 60 * 60),
SELECTION_ITEM("npc.selection.item", "280"),
SELECTION_MESSAGE("npc.selection.message", "<b>You selected <a><npc><b>!"),
SERVER_OWNS_NPCS("npc.server-ownership", false),
STORAGE_FILE("storage.file", "saves.yml"),
STORAGE_TYPE("storage.type", "yaml"),
SUBPLUGIN_FOLDER("subplugins.folder", "plugins"),
TALK_CLOSE_MAXIMUM_COOLDOWN("npc.text.max-talk-cooldown", 60),
TALK_CLOSE_MINIMUM_COOLDOWN("npc.text.min-talk-cooldown", 30),
TALK_ITEM("npc.text.talk-item", "340"),
USE_NEW_PATHFINDER("npc.pathfinding.use-new-finder", false);
protected String path;
protected Object value;
Setting(String path, Object value) {
this.path = path;
this.value = value;
}
public boolean asBoolean() {
return (Boolean) value;
}
public double asDouble() {
return ((Number) value).doubleValue();
}
public float asFloat() {
return ((Number) value).floatValue();
}
public int asInt() {
if (value instanceof String) {
return Integer.parseInt(value.toString());
}
return ((Number) value).intValue();
}
@SuppressWarnings("unchecked")
public List<String> asList() {
if (!(value instanceof List)) {
value = Lists.newArrayList(value);
}
return (List<String>) value;
}
public long asLong() {
return ((Number) value).longValue();
}
public String asString() {
return value.toString();
}
protected void loadFromKey(DataKey root) {
value = root.getRaw(path);
}
protected void setAtKey(DataKey root) {
root.setRaw(path, value);
}
}
package net.citizensnpcs;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.api.util.Storage;
import net.citizensnpcs.api.util.YamlStorage;
import com.google.common.collect.Lists;
public class Settings {
private final Storage config;
private final DataKey root;
public Settings(File folder) {
config = new YamlStorage(new File(folder, "config.yml"), "Citizens Configuration");
root = config.getKey("");
config.load();
for (Setting setting : Setting.values()) {
if (!root.keyExists(setting.path)) {
setting.setAtKey(root);
} else
setting.loadFromKey(root);
}
save();
}
public void reload() {
config.load();
for (Setting setting : Setting.values())
if (root.keyExists(setting.path))
setting.loadFromKey(root);
save();
}
public void save() {
config.save();
}
public enum Setting {
CHAT_FORMAT("npc.chat.format.no-targets", "[<npc>]: <text>"),
CHAT_FORMAT_TO_TARGET("npc.chat.format.to-target", "[<npc>] -> You: <text>"),
CHAT_FORMAT_TO_BYSTANDERS("npc.chat.prefix.to-bystanders", "[<npc>] -> [<target>]: <text>"),
CHAT_FORMAT_WITH_TARGETS_TO_TARGET("npc.chat.format.with-target-to-target", "[<npc>] -> [<targets>]: <text>"),
CHAT_FORMAT_WITH_TARGETS_TO_BYSTANDERS("npc.chat.format.with-target-to-bystanders", "[<npc>] -> [<target>]: <text>"),
CHAT_RANGE("npc.chat.options.range", 5),
CHAT_BYSTANDERS_HEAR_TARGETED_CHAT("npc.chat.options.bystanders-hear-targeted-chat", true),
CHAT_MAX_NUMBER_OF_TARGETS("npc.chat.options.max-number-of-targets-to-show", 3),
CHAT_MULTIPLE_TARGETS_FORMAT("npc.chat.options.multiple-targets-format", "<target>,|<target>|& <target>|& others"),
DATABASE_DRIVER("storage.database.driver", ""),
DATABASE_PASSWORD("storage.database.password", ""),
DATABASE_URL("storage.database.url", ""),
DATABASE_USERNAME("storage.database.username", ""),
DEBUG_MODE("general.debug-mode", false),
DEFAULT_LOOK_CLOSE("npc.default.look-close.enabled", false),
DEFAULT_LOOK_CLOSE_RANGE("npc.default.look-close.range", 5),
DEFAULT_NPC_LIMIT("npc.limits.default-limit", 10),
DEFAULT_PATHFINDING_RANGE("npc.default.pathfinding.range", 25F),
DEFAULT_RANDOM_TALKER("npc.default.random-talker", true),
DEFAULT_REALISTIC_LOOKING("npc.default.realistic-looking", false),
DEFAULT_STATIONARY_TICKS("npc.default.stationary-ticks", -1),
DEFAULT_TALK_CLOSE("npc.default.talk-close.enabled", false),
DEFAULT_TALK_CLOSE_RANGE("npc.default.talk-close.range", 5),
DEFAULT_TEXT("npc.default.text.0", "Hi, I'm <npc>!") {
@Override
public void loadFromKey(DataKey root) {
List<String> list = new ArrayList<String>();
for (DataKey key : root.getRelative("npc.default.text").getSubKeys())
list.add(key.getString(""));
value = list;
}
},
HIGHLIGHT_COLOUR("general.color-scheme.message-highlight", "<e>"),
KEEP_CHUNKS_LOADED("npc.chunks.always-keep-loaded", false),
LOCALE("general.translation.locale", ""),
MAX_NPC_LIMIT_CHECKS("npc.limits.max-permission-checks", 100),
MAX_SPEED("npc.limits.max-speed", 100),
MESSAGE_COLOUR("general.color-scheme.message", "<a>"),
NPC_COST("economy.npc.cost", 100D),
QUICK_SELECT("npc.selection.quick-select", false),
REMOVE_PLAYERS_FROM_PLAYER_LIST("npc.player.remove-from-list", true),
SAVE_TASK_DELAY("storage.save-task.delay", 20 * 60 * 60),
SELECTION_ITEM("npc.selection.item", "280"),
SELECTION_MESSAGE("npc.selection.message", "<b>You selected <a><npc><b>!"),
SERVER_OWNS_NPCS("npc.server-ownership", false),
STORAGE_FILE("storage.file", "saves.yml"),
STORAGE_TYPE("storage.type", "yaml"),
SUBPLUGIN_FOLDER("subplugins.folder", "plugins"),
TALK_CLOSE_MAXIMUM_COOLDOWN("npc.text.max-talk-cooldown", 60),
TALK_CLOSE_MINIMUM_COOLDOWN("npc.text.min-talk-cooldown", 30),
TALK_ITEM("npc.text.talk-item", "340"),
USE_NEW_PATHFINDER("npc.pathfinding.use-new-finder", false);
protected String path;
protected Object value;
Setting(String path, Object value) {
this.path = path;
this.value = value;
}
public boolean asBoolean() {
return (Boolean) value;
}
public double asDouble() {
return ((Number) value).doubleValue();
}
public float asFloat() {
return ((Number) value).floatValue();
}
public int asInt() {
if (value instanceof String) {
return Integer.parseInt(value.toString());
}
return ((Number) value).intValue();
}
@SuppressWarnings("unchecked")
public List<String> asList() {
if (!(value instanceof List)) {
value = Lists.newArrayList(value);
}
return (List<String>) value;
}
public long asLong() {
return ((Number) value).longValue();
}
public String asString() {
return value.toString();
}
protected void loadFromKey(DataKey root) {
value = root.getRaw(path);
}
protected void setAtKey(DataKey root) {
root.setRaw(path, value);
}
}
}

View File

@ -1,246 +1,246 @@
package net.citizensnpcs.npc;
import java.util.List;
import javax.annotation.Nullable;
import net.citizensnpcs.EventListen;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.ai.Navigator;
import net.citizensnpcs.api.event.DespawnReason;
import net.citizensnpcs.api.event.NPCDespawnEvent;
import net.citizensnpcs.api.event.NPCSpawnEvent;
import net.citizensnpcs.api.npc.AbstractNPC;
import net.citizensnpcs.api.persistence.PersistenceLoader;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.trait.Spawned;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.npc.ai.CitizensNavigator;
import net.citizensnpcs.trait.CurrentLocation;
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
import net.minecraft.server.v1_4_5.EntityLiving;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_4_5.entity.CraftLivingEntity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.metadata.FixedMetadataValue;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
public class CitizensNPC extends AbstractNPC {
private EntityController entityController;
private final CitizensNavigator navigator = new CitizensNavigator(this);
private final List<String> removedTraits = Lists.newArrayList();
public CitizensNPC(int id, String name, EntityController entityController) {
super(id, name);
Preconditions.checkNotNull(entityController);
this.entityController = entityController;
}
@Override
public boolean despawn(DespawnReason reason) {
if (!isSpawned())
return false;
NPCDespawnEvent event = new NPCDespawnEvent(this, reason);
if (reason == DespawnReason.CHUNK_UNLOAD)
event.setCancelled(Setting.KEEP_CHUNKS_LOADED.asBoolean());
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
getBukkitEntity().getLocation().getChunk();
// ensure that we are in a loaded chunk.
return false;
}
boolean keepSelected = getTrait(Spawned.class).shouldSpawn();
if (!keepSelected)
data().remove("selectors");
for (Trait trait : traits.values())
trait.onDespawn();
entityController.remove();
return true;
}
@Override
public LivingEntity getBukkitEntity() {
return entityController.getBukkitEntity();
}
@Deprecated
public EntityLiving getHandle() {
return ((CraftLivingEntity) getBukkitEntity()).getHandle();
}
@Override
public Navigator getNavigator() {
return navigator;
}
@Override
public boolean isSpawned() {
return getBukkitEntity() != null;
}
public void load(final DataKey root) {
metadata.loadFrom(root.getRelative("metadata"));
// Load traits
String traitNames = root.getString("traitnames");
Iterable<DataKey> keys = traitNames.isEmpty() ? root.getRelative("traits").getSubKeys() : Iterables
.transform(Splitter.on(',').split(traitNames), new Function<String, DataKey>() {
@Override
public DataKey apply(@Nullable String input) {
return root.getRelative("traits." + input);
}
});
for (DataKey traitKey : keys) {
if (traitKey.keyExists("enabled") && !traitKey.getBoolean("enabled"))
continue;
Class<? extends Trait> clazz = CitizensAPI.getTraitFactory().getTraitClass(traitKey.name());
Trait trait;
if (hasTrait(clazz)) {
trait = getTrait(clazz);
} else {
trait = CitizensAPI.getTraitFactory().getTrait(clazz);
if (trait == null) {
Messaging.severeTr(Messages.SKIPPING_BROKEN_TRAIT, traitKey.name(), getId());
continue;
}
addTrait(trait);
}
loadTrait(trait, traitKey);
}
// Spawn the NPC
CurrentLocation spawnLocation = getTrait(CurrentLocation.class);
if (getTrait(Spawned.class).shouldSpawn() && spawnLocation.getLocation() != null)
spawn(spawnLocation.getLocation());
navigator.load(root.getRelative("navigator"));
}
private void loadTrait(Trait trait, DataKey traitKey) {
try {
trait.load(traitKey);
PersistenceLoader.load(trait, traitKey);
} catch (Throwable ex) {
Messaging.logTr(Messages.TRAIT_LOAD_FAILED, traitKey.name(), getId());
}
}
@Override
public void removeTrait(Class<? extends Trait> clazz) {
Trait present = traits.get(clazz);
if (present != null)
removedTraits.add(present.getName());
super.removeTrait(clazz);
}
private void removeTraitData(DataKey root) {
for (String name : removedTraits) {
root.removeKey("traits." + name);
}
removedTraits.clear();
}
public void save(DataKey root) {
root.setString("name", getFullName());
metadata.saveTo(root.getRelative("metadata"));
navigator.save(root.getRelative("navigator"));
// Save all existing traits
StringBuilder traitNames = new StringBuilder();
for (Trait trait : traits.values()) {
DataKey traitKey = root.getRelative("traits." + trait.getName());
trait.save(traitKey);
PersistenceLoader.save(trait, traitKey);
removedTraits.remove(trait.getName());
traitNames.append(trait.getName() + ",");
}
if (traitNames.length() > 0) {
root.setString("traitnames", traitNames.substring(0, traitNames.length() - 1));
}
removeTraitData(root);
}
public void setEntityController(EntityController newController) {
Preconditions.checkNotNull(newController);
boolean wasSpawned = isSpawned();
Location prev = null;
if (wasSpawned) {
prev = getBukkitEntity().getLocation();
despawn();
}
entityController = newController;
if (wasSpawned)
spawn(prev);
}
@Override
public boolean spawn(Location at) {
Preconditions.checkNotNull(at, "location cannot be null");
if (isSpawned())
return false;
entityController.spawn(at, this);
EntityLiving mcEntity = getHandle();
boolean couldSpawn = !Util.isLoaded(at) ? false : mcEntity.world.addEntity(mcEntity,
SpawnReason.CUSTOM);
if (!couldSpawn) {
// we need to wait for a chunk load before trying to spawn
mcEntity = null;
EventListen.addForRespawn(at, getId());
return true;
}
NPCSpawnEvent spawnEvent = new NPCSpawnEvent(this, at);
Bukkit.getPluginManager().callEvent(spawnEvent);
if (spawnEvent.isCancelled()) {
mcEntity = null;
return false;
}
NMS.setHeadYaw(mcEntity, at.getYaw());
getBukkitEntity().setMetadata(NPC_METADATA_MARKER,
new FixedMetadataValue(CitizensAPI.getPlugin(), true));
// Set the spawned state
getTrait(CurrentLocation.class).setLocation(at);
getTrait(Spawned.class).setSpawned(true);
navigator.onSpawn();
// Modify NPC using traits after the entity has been created
for (Trait trait : traits.values())
trait.onSpawn();
getBukkitEntity().setRemoveWhenFarAway(false);
return true;
}
@Override
public void update() {
try {
super.update();
if (isSpawned()) {
NMS.trySwim(getBukkitEntity());
navigator.run();
}
} catch (Exception ex) {
Messaging.logTr(Messages.EXCEPTION_UPDATING_NPC, getId(), ex.getMessage());
ex.printStackTrace();
}
}
private static final String NPC_METADATA_MARKER = "NPC";
package net.citizensnpcs.npc;
import java.util.List;
import javax.annotation.Nullable;
import net.citizensnpcs.EventListen;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.ai.Navigator;
import net.citizensnpcs.api.event.DespawnReason;
import net.citizensnpcs.api.event.NPCDespawnEvent;
import net.citizensnpcs.api.event.NPCSpawnEvent;
import net.citizensnpcs.api.npc.AbstractNPC;
import net.citizensnpcs.api.persistence.PersistenceLoader;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.trait.Spawned;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.npc.ai.CitizensNavigator;
import net.citizensnpcs.trait.CurrentLocation;
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
import net.minecraft.server.v1_4_5.EntityLiving;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_4_5.entity.CraftLivingEntity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.metadata.FixedMetadataValue;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
public class CitizensNPC extends AbstractNPC {
private EntityController entityController;
private final CitizensNavigator navigator = new CitizensNavigator(this);
private final List<String> removedTraits = Lists.newArrayList();
public CitizensNPC(int id, String name, EntityController entityController) {
super(id, name);
Preconditions.checkNotNull(entityController);
this.entityController = entityController;
}
@Override
public boolean despawn(DespawnReason reason) {
if (!isSpawned())
return false;
NPCDespawnEvent event = new NPCDespawnEvent(this, reason);
if (reason == DespawnReason.CHUNK_UNLOAD)
event.setCancelled(Setting.KEEP_CHUNKS_LOADED.asBoolean());
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
getBukkitEntity().getLocation().getChunk();
// ensure that we are in a loaded chunk.
return false;
}
boolean keepSelected = getTrait(Spawned.class).shouldSpawn();
if (!keepSelected)
data().remove("selectors");
for (Trait trait : traits.values())
trait.onDespawn();
entityController.remove();
return true;
}
@Override
public LivingEntity getBukkitEntity() {
return entityController.getBukkitEntity();
}
@Deprecated
public EntityLiving getHandle() {
return ((CraftLivingEntity) getBukkitEntity()).getHandle();
}
@Override
public Navigator getNavigator() {
return navigator;
}
@Override
public boolean isSpawned() {
return getBukkitEntity() != null;
}
public void load(final DataKey root) {
metadata.loadFrom(root.getRelative("metadata"));
// Load traits
String traitNames = root.getString("traitnames");
Iterable<DataKey> keys = traitNames.isEmpty() ? root.getRelative("traits").getSubKeys() : Iterables
.transform(Splitter.on(',').split(traitNames), new Function<String, DataKey>() {
@Override
public DataKey apply(@Nullable String input) {
return root.getRelative("traits." + input);
}
});
for (DataKey traitKey : keys) {
if (traitKey.keyExists("enabled") && !traitKey.getBoolean("enabled"))
continue;
Class<? extends Trait> clazz = CitizensAPI.getTraitFactory().getTraitClass(traitKey.name());
Trait trait;
if (hasTrait(clazz)) {
trait = getTrait(clazz);
} else {
trait = CitizensAPI.getTraitFactory().getTrait(clazz);
if (trait == null) {
Messaging.severeTr(Messages.SKIPPING_BROKEN_TRAIT, traitKey.name(), getId());
continue;
}
addTrait(trait);
}
loadTrait(trait, traitKey);
}
// Spawn the NPC
CurrentLocation spawnLocation = getTrait(CurrentLocation.class);
if (getTrait(Spawned.class).shouldSpawn() && spawnLocation.getLocation() != null)
spawn(spawnLocation.getLocation());
navigator.load(root.getRelative("navigator"));
}
private void loadTrait(Trait trait, DataKey traitKey) {
try {
trait.load(traitKey);
PersistenceLoader.load(trait, traitKey);
} catch (Throwable ex) {
Messaging.logTr(Messages.TRAIT_LOAD_FAILED, traitKey.name(), getId());
}
}
@Override
public void removeTrait(Class<? extends Trait> clazz) {
Trait present = traits.get(clazz);
if (present != null)
removedTraits.add(present.getName());
super.removeTrait(clazz);
}
private void removeTraitData(DataKey root) {
for (String name : removedTraits) {
root.removeKey("traits." + name);
}
removedTraits.clear();
}
public void save(DataKey root) {
root.setString("name", getFullName());
metadata.saveTo(root.getRelative("metadata"));
navigator.save(root.getRelative("navigator"));
// Save all existing traits
StringBuilder traitNames = new StringBuilder();
for (Trait trait : traits.values()) {
DataKey traitKey = root.getRelative("traits." + trait.getName());
trait.save(traitKey);
PersistenceLoader.save(trait, traitKey);
removedTraits.remove(trait.getName());
traitNames.append(trait.getName() + ",");
}
if (traitNames.length() > 0) {
root.setString("traitnames", traitNames.substring(0, traitNames.length() - 1));
}
removeTraitData(root);
}
public void setEntityController(EntityController newController) {
Preconditions.checkNotNull(newController);
boolean wasSpawned = isSpawned();
Location prev = null;
if (wasSpawned) {
prev = getBukkitEntity().getLocation();
despawn();
}
entityController = newController;
if (wasSpawned)
spawn(prev);
}
@Override
public boolean spawn(Location at) {
Preconditions.checkNotNull(at, "location cannot be null");
if (isSpawned())
return false;
entityController.spawn(at, this);
EntityLiving mcEntity = getHandle();
boolean couldSpawn = !Util.isLoaded(at) ? false : mcEntity.world.addEntity(mcEntity,
SpawnReason.CUSTOM);
if (!couldSpawn) {
// we need to wait for a chunk load before trying to spawn
mcEntity = null;
EventListen.addForRespawn(at, getId());
return true;
}
NPCSpawnEvent spawnEvent = new NPCSpawnEvent(this, at);
Bukkit.getPluginManager().callEvent(spawnEvent);
if (spawnEvent.isCancelled()) {
mcEntity = null;
return false;
}
NMS.setHeadYaw(mcEntity, at.getYaw());
getBukkitEntity().setMetadata(NPC_METADATA_MARKER,
new FixedMetadataValue(CitizensAPI.getPlugin(), true));
// Set the spawned state
getTrait(CurrentLocation.class).setLocation(at);
getTrait(Spawned.class).setSpawned(true);
navigator.onSpawn();
// Modify NPC using traits after the entity has been created
for (Trait trait : traits.values())
trait.onSpawn();
getBukkitEntity().setRemoveWhenFarAway(false);
return true;
}
@Override
public void update() {
try {
super.update();
if (isSpawned()) {
NMS.trySwim(getBukkitEntity());
navigator.run();
}
} catch (Exception ex) {
Messaging.logTr(Messages.EXCEPTION_UPDATING_NPC, getId(), ex.getMessage());
ex.printStackTrace();
}
}
private static final String NPC_METADATA_MARKER = "NPC";
}

View File

@ -1,136 +1,138 @@
package net.citizensnpcs.npc;
import java.util.Map;
import java.util.Set;
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.trait.Equipment;
import net.citizensnpcs.api.trait.trait.Inventory;
import net.citizensnpcs.api.trait.trait.MobType;
import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.api.trait.trait.Spawned;
import net.citizensnpcs.trait.Age;
import net.citizensnpcs.trait.Anchors;
import net.citizensnpcs.trait.Behaviour;
import net.citizensnpcs.trait.Controllable;
import net.citizensnpcs.trait.CurrentLocation;
import net.citizensnpcs.trait.Gravity;
import net.citizensnpcs.trait.LookClose;
import net.citizensnpcs.trait.NPCSkeletonType;
import net.citizensnpcs.trait.Poses;
import net.citizensnpcs.trait.Powered;
import net.citizensnpcs.trait.Saddle;
import net.citizensnpcs.trait.Sheared;
import net.citizensnpcs.trait.SlimeSize;
import net.citizensnpcs.trait.VillagerProfession;
import net.citizensnpcs.trait.WoolColor;
import net.citizensnpcs.trait.ZombieModifier;
import net.citizensnpcs.trait.text.Text;
import net.citizensnpcs.trait.waypoint.Waypoints;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
public class CitizensTraitFactory implements TraitFactory {
private final Map<String, Class<? extends Trait>> registered = Maps.newHashMap();
public CitizensTraitFactory() {
registerTrait(TraitInfo.create(Age.class).withName("age"));
registerTrait(TraitInfo.create(Anchors.class).withName("anchors"));
registerTrait(TraitInfo.create(Behaviour.class).withName("behaviour"));
registerTrait(TraitInfo.create(Controllable.class).withName("controllable"));
registerTrait(TraitInfo.create(Equipment.class).withName("equipment"));
registerTrait(TraitInfo.create(Gravity.class).withName("gravity"));
registerTrait(TraitInfo.create(Inventory.class).withName("inventory"));
registerTrait(TraitInfo.create(CurrentLocation.class).withName("location"));
registerTrait(TraitInfo.create(LookClose.class).withName("lookclose"));
registerTrait(TraitInfo.create(Owner.class).withName("owner"));
registerTrait(TraitInfo.create(Poses.class).withName("poses"));
registerTrait(TraitInfo.create(Powered.class).withName("powered"));
registerTrait(TraitInfo.create(VillagerProfession.class).withName("profession"));
registerTrait(TraitInfo.create(Saddle.class).withName("saddle"));
registerTrait(TraitInfo.create(Sheared.class).withName("sheared"));
registerTrait(TraitInfo.create(NPCSkeletonType.class).withName("skeletontype"));
registerTrait(TraitInfo.create(SlimeSize.class).withName("slimesize"));
registerTrait(TraitInfo.create(Spawned.class).withName("spawned"));
registerTrait(TraitInfo.create(Text.class).withName("text"));
registerTrait(TraitInfo.create(MobType.class).withName("type"));
registerTrait(TraitInfo.create(Waypoints.class).withName("waypoints"));
registerTrait(TraitInfo.create(WoolColor.class).withName("woolcolor"));
registerTrait(TraitInfo.create(ZombieModifier.class).withName("zombiemodifier"));
for (String trait : registered.keySet())
INTERNAL_TRAITS.add(trait);
}
public void addPlotters(Graph graph) {
for (Map.Entry<String, Class<? extends Trait>> entry : registered.entrySet()) {
if (INTERNAL_TRAITS.contains(entry.getKey()))
continue;
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;
}
});
}
}
private <T extends Trait> T create(Class<T> trait) {
try {
return trait.newInstance();
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
@Override
public <T extends Trait> T getTrait(Class<T> clazz) {
if (!registered.containsValue(clazz))
return null;
return create(clazz);
}
@Override
@SuppressWarnings("unchecked")
public <T extends Trait> T getTrait(String name) {
Class<? extends Trait> clazz = registered.get(name);
if (clazz == null)
return null;
return (T) create(clazz);
}
@Override
public Class<? extends Trait> getTraitClass(String name) {
return registered.get(name.toLowerCase());
}
@Override
public boolean isInternalTrait(Trait trait) {
return INTERNAL_TRAITS.contains(trait.getName());
}
@Override
public void registerTrait(TraitInfo info) {
Preconditions.checkNotNull(info, "info cannot be null");
if (registered.containsKey(info))
throw new IllegalArgumentException("trait name already registered");
registered.put(info.getTraitName(), info.getTraitClass());
}
private static final Set<String> INTERNAL_TRAITS = Sets.newHashSet();
package net.citizensnpcs.npc;
import java.util.Map;
import java.util.Set;
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.trait.Equipment;
import net.citizensnpcs.api.trait.trait.Inventory;
import net.citizensnpcs.api.trait.trait.MobType;
import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.api.trait.trait.Spawned;
import net.citizensnpcs.api.trait.trait.Speech;
import net.citizensnpcs.trait.Age;
import net.citizensnpcs.trait.Anchors;
import net.citizensnpcs.trait.Behaviour;
import net.citizensnpcs.trait.Controllable;
import net.citizensnpcs.trait.CurrentLocation;
import net.citizensnpcs.trait.Gravity;
import net.citizensnpcs.trait.LookClose;
import net.citizensnpcs.trait.NPCSkeletonType;
import net.citizensnpcs.trait.Poses;
import net.citizensnpcs.trait.Powered;
import net.citizensnpcs.trait.Saddle;
import net.citizensnpcs.trait.Sheared;
import net.citizensnpcs.trait.SlimeSize;
import net.citizensnpcs.trait.VillagerProfession;
import net.citizensnpcs.trait.WoolColor;
import net.citizensnpcs.trait.ZombieModifier;
import net.citizensnpcs.trait.text.Text;
import net.citizensnpcs.trait.waypoint.Waypoints;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
public class CitizensTraitFactory implements TraitFactory {
private final Map<String, Class<? extends Trait>> registered = Maps.newHashMap();
public CitizensTraitFactory() {
registerTrait(TraitInfo.create(Age.class).withName("age"));
registerTrait(TraitInfo.create(Anchors.class).withName("anchors"));
registerTrait(TraitInfo.create(Behaviour.class).withName("behaviour"));
registerTrait(TraitInfo.create(Controllable.class).withName("controllable"));
registerTrait(TraitInfo.create(Equipment.class).withName("equipment"));
registerTrait(TraitInfo.create(Gravity.class).withName("gravity"));
registerTrait(TraitInfo.create(Inventory.class).withName("inventory"));
registerTrait(TraitInfo.create(CurrentLocation.class).withName("location"));
registerTrait(TraitInfo.create(LookClose.class).withName("lookclose"));
registerTrait(TraitInfo.create(Owner.class).withName("owner"));
registerTrait(TraitInfo.create(Poses.class).withName("poses"));
registerTrait(TraitInfo.create(Powered.class).withName("powered"));
registerTrait(TraitInfo.create(VillagerProfession.class).withName("profession"));
registerTrait(TraitInfo.create(Saddle.class).withName("saddle"));
registerTrait(TraitInfo.create(Sheared.class).withName("sheared"));
registerTrait(TraitInfo.create(NPCSkeletonType.class).withName("skeletontype"));
registerTrait(TraitInfo.create(SlimeSize.class).withName("slimesize"));
registerTrait(TraitInfo.create(Spawned.class).withName("spawned"));
registerTrait(TraitInfo.create(Speech.class).withName("speech"));
registerTrait(TraitInfo.create(Text.class).withName("text"));
registerTrait(TraitInfo.create(MobType.class).withName("type"));
registerTrait(TraitInfo.create(Waypoints.class).withName("waypoints"));
registerTrait(TraitInfo.create(WoolColor.class).withName("woolcolor"));
registerTrait(TraitInfo.create(ZombieModifier.class).withName("zombiemodifier"));
for (String trait : registered.keySet())
INTERNAL_TRAITS.add(trait);
}
public void addPlotters(Graph graph) {
for (Map.Entry<String, Class<? extends Trait>> entry : registered.entrySet()) {
if (INTERNAL_TRAITS.contains(entry.getKey()))
continue;
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;
}
});
}
}
private <T extends Trait> T create(Class<T> trait) {
try {
return trait.newInstance();
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
@Override
public <T extends Trait> T getTrait(Class<T> clazz) {
if (!registered.containsValue(clazz))
return null;
return create(clazz);
}
@Override
@SuppressWarnings("unchecked")
public <T extends Trait> T getTrait(String name) {
Class<? extends Trait> clazz = registered.get(name);
if (clazz == null)
return null;
return (T) create(clazz);
}
@Override
public Class<? extends Trait> getTraitClass(String name) {
return registered.get(name.toLowerCase());
}
@Override
public boolean isInternalTrait(Trait trait) {
return INTERNAL_TRAITS.contains(trait.getName());
}
@Override
public void registerTrait(TraitInfo info) {
Preconditions.checkNotNull(info, "info cannot be null");
if (registered.containsKey(info))
throw new IllegalArgumentException("trait name already registered");
registered.put(info.getTraitName(), info.getTraitClass());
}
private static final Set<String> INTERNAL_TRAITS = Sets.newHashSet();
}

View File

@ -0,0 +1,90 @@
package net.citizensnpcs.npc.ai.speech;
import java.util.List;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.ai.speech.Talkable;
import net.citizensnpcs.api.ai.speech.TalkableEntity;
import net.citizensnpcs.api.ai.speech.Tongue;
import net.citizensnpcs.api.ai.speech.VocalChord;
import net.citizensnpcs.api.npc.NPC;
public class Chat implements VocalChord {
/*
CHAT_FORMAT("npc.chat.format.no-targets", "[<npc>]: <text>"),
CHAT_FORMAT_TO_TARGET("npc.chat.format.to-target", "[<npc>] -> You: <text>"),
CHAT_FORMAT_TO_BYSTANDERS("npc.chat.prefix.to-bystanders", "[<npc>] -> [<target>]: <text>"),
CHAT_FORMAT_WITH_TARGETS_TO_BYSTANDERS("npc.chat.format.with-target-to-bystanders", "[<npc>] -> [<targets>]: <text>"),
CHAT_RANGE("npc.chat.options.range", 5),
CHAT_BYSTANDERS_HEAR_TARGETED_CHAT("npc.chat.options.bystanders-hear-targeted-chat", true),
CHAT_MAX_NUMBER_OF_TARGETS("npc.chat.options.max-number-of-targets-to-show", 2),
CHAT_MULTIPLE_TARGETS_FORMAT("npc.chat.options.multiple-targets-format", "<target>,|<target>|& <target>|& others"),
*/
public final String VOCAL_CHORD_NAME = "chat";
@Override
public void talk(Tongue tongue) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(tongue.getTalker().getEntity());
// If no recipients, chat to the world with CHAT_FORMAT and CHAT_RANGE settings
if (!tongue.isTargeted()) {
String text = Setting.CHAT_FORMAT.asString().replace("<npc>", npc.getName()).replace("<text>", tongue.getContents());
talkToBystanders(npc, text, tongue);
return;
}
// Assumed recipients at this point
else if (tongue.getRecipients().size() <= 1) { // One recipient
String text = Setting.CHAT_FORMAT_TO_TARGET.asString().replace("<npc>", npc.getName()).replace("<text>", tongue.getContents());
tongue.getRecipients().get(0).talkTo(tongue, text, this);
if (!Setting.CHAT_BYSTANDERS_HEAR_TARGETED_CHAT.asBoolean()) return;
String bystanderText = Setting.CHAT_FORMAT_TO_BYSTANDERS.asString().replace("<npc>", npc.getName()).replace("<target>", tongue.getRecipients().get(0).getName()).replace("<text>", tongue.getContents());
talkToBystanders(npc, bystanderText, tongue);
return;
}
else { // Multiple recipients
// Set up text
String text = Setting.CHAT_FORMAT_TO_TARGET.asString().replace("<npc>", npc.getName()).replace("<text>", tongue.getContents());
tongue.getRecipients().get(0).talkTo(tongue, text, this);
if (!Setting.CHAT_BYSTANDERS_HEAR_TARGETED_CHAT.asBoolean()) return;
String bystanders = null;
bystanders = bystanders + "";
String bystanderText = Setting.CHAT_FORMAT_WITH_TARGETS_TO_BYSTANDERS.asString().replace("<npc>", npc.getName()).replace("<targets>", tongue.getRecipients().get(0).getName()).replace("<text>", tongue.getContents());
talkToBystanders(npc, bystanderText, tongue);
// TODO: Finish multiple recipients
}
}
private void talkToBystanders(NPC npc, String text, Tongue tongue) {
// Get list of nearby entities
List<Entity> bystanderEntities = npc.getBukkitEntity().getNearbyEntities(Setting.CHAT_RANGE.asDouble(), Setting.CHAT_RANGE.asDouble(), Setting.CHAT_RANGE.asDouble());
for (Entity bystander : bystanderEntities)
// Continue if a LivingEntity, which is compatible with TalkableEntity
if (bystander instanceof LivingEntity) {
// Exclude Targets
if (tongue.isTargeted()) {
for (Talkable target : tongue.getRecipients())
if (target.getEntity() == bystander) continue;
} else
// Found a nearby LivingEntity, make it Talkable and talkNear it
new TalkableEntity((LivingEntity) bystander).talkNear(tongue, text, this);
}
}
@Override
public String getName() {
return VOCAL_CHORD_NAME;
}
}

View File

@ -0,0 +1,51 @@
package net.citizensnpcs.npc.ai.speech;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import net.citizensnpcs.api.ai.speech.SpeechFactory;
import net.citizensnpcs.api.ai.speech.VocalChord;
public class CitizensSpeechFactory implements SpeechFactory {
Map<String, Class<? extends VocalChord>> registered = Collections.emptyMap();
@Override
public void register(Class<? extends VocalChord> clazz, String name) {
registered.put(name, clazz);
}
@Override
public String getVocalChordName(Class<? extends VocalChord> clazz) {
for (Entry<String, Class<? extends VocalChord>> vocalChord : registered.entrySet())
if (vocalChord.getValue() == clazz) return vocalChord.getKey();
return null;
}
@Override
public VocalChord getVocalChord(String name) {
if (registered.containsKey(name.toLowerCase()))
try {
return registered.get(name.toLowerCase()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
@Override
public VocalChord getVocalChord(Class<? extends VocalChord> clazz) {
try {
return clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}