From 1baa5c0f01295f2193918c0244c5893407c00d34 Mon Sep 17 00:00:00 2001 From: Jeremy Schroeder Date: Sat, 22 Dec 2012 08:23:52 -0500 Subject: [PATCH] Implement NPC SpeechController --- src/main/java/net/citizensnpcs/Citizens.java | 712 +++++++++--------- src/main/java/net/citizensnpcs/Settings.java | 290 +++---- .../net/citizensnpcs/npc/CitizensNPC.java | 490 ++++++------ .../npc/CitizensTraitFactory.java | 272 +++---- .../net/citizensnpcs/npc/ai/speech/Chat.java | 90 +++ .../npc/ai/speech/CitizensSpeechFactory.java | 51 ++ 6 files changed, 1034 insertions(+), 871 deletions(-) create mode 100644 src/main/java/net/citizensnpcs/npc/ai/speech/Chat.java create mode 100644 src/main/java/net/citizensnpcs/npc/ai/speech/CitizensSpeechFactory.java diff --git a/src/main/java/net/citizensnpcs/Citizens.java b/src/main/java/net/citizensnpcs/Citizens.java index 523056e79..55271ef08 100644 --- a/src/main/java/net/citizensnpcs/Citizens.java +++ b/src/main/java/net/citizensnpcs/Citizens.java @@ -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 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() { - @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 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 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 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() { + @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 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 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"; + } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/Settings.java b/src/main/java/net/citizensnpcs/Settings.java index 4377ca9ad..0bf6f4dc7 100644 --- a/src/main/java/net/citizensnpcs/Settings.java +++ b/src/main/java/net/citizensnpcs/Settings.java @@ -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", "[]: "), - 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 !") { - @Override - public void loadFromKey(DataKey root) { - List list = new ArrayList(); - for (DataKey key : root.getRelative("npc.default.text").getSubKeys()) - list.add(key.getString("")); - value = list; - } - }, - HIGHLIGHT_COLOUR("general.color-scheme.message-highlight", ""), - 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", ""), - 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", "You selected !"), - 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 asList() { - if (!(value instanceof List)) { - value = Lists.newArrayList(value); - } - return (List) 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", "[]: "), + CHAT_FORMAT_TO_TARGET("npc.chat.format.to-target", "[] -> You: "), + CHAT_FORMAT_TO_BYSTANDERS("npc.chat.prefix.to-bystanders", "[] -> []: "), + CHAT_FORMAT_WITH_TARGETS_TO_TARGET("npc.chat.format.with-target-to-target", "[] -> []: "), + CHAT_FORMAT_WITH_TARGETS_TO_BYSTANDERS("npc.chat.format.with-target-to-bystanders", "[] -> []: "), + 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", ",||& |& 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 !") { + @Override + public void loadFromKey(DataKey root) { + List list = new ArrayList(); + for (DataKey key : root.getRelative("npc.default.text").getSubKeys()) + list.add(key.getString("")); + value = list; + } + }, + HIGHLIGHT_COLOUR("general.color-scheme.message-highlight", ""), + 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", ""), + 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", "You selected !"), + 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 asList() { + if (!(value instanceof List)) { + value = Lists.newArrayList(value); + } + return (List) 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); + } + } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/CitizensNPC.java b/src/main/java/net/citizensnpcs/npc/CitizensNPC.java index e9b1801f5..7db7e68f8 100644 --- a/src/main/java/net/citizensnpcs/npc/CitizensNPC.java +++ b/src/main/java/net/citizensnpcs/npc/CitizensNPC.java @@ -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 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 keys = traitNames.isEmpty() ? root.getRelative("traits").getSubKeys() : Iterables - .transform(Splitter.on(',').split(traitNames), new Function() { - @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 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 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 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 keys = traitNames.isEmpty() ? root.getRelative("traits").getSubKeys() : Iterables + .transform(Splitter.on(',').split(traitNames), new Function() { + @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 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 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"; } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/CitizensTraitFactory.java b/src/main/java/net/citizensnpcs/npc/CitizensTraitFactory.java index 6a052095d..e405ad1d2 100644 --- a/src/main/java/net/citizensnpcs/npc/CitizensTraitFactory.java +++ b/src/main/java/net/citizensnpcs/npc/CitizensTraitFactory.java @@ -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> 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> entry : registered.entrySet()) { - if (INTERNAL_TRAITS.contains(entry.getKey())) - continue; - final Class 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 create(Class trait) { - try { - return trait.newInstance(); - } catch (Exception ex) { - ex.printStackTrace(); - return null; - } - } - - @Override - public T getTrait(Class clazz) { - if (!registered.containsValue(clazz)) - return null; - return create(clazz); - } - - @Override - @SuppressWarnings("unchecked") - public T getTrait(String name) { - Class clazz = registered.get(name); - if (clazz == null) - return null; - return (T) create(clazz); - } - - @Override - public Class 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 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> 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> entry : registered.entrySet()) { + if (INTERNAL_TRAITS.contains(entry.getKey())) + continue; + final Class 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 create(Class trait) { + try { + return trait.newInstance(); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } + + @Override + public T getTrait(Class clazz) { + if (!registered.containsValue(clazz)) + return null; + return create(clazz); + } + + @Override + @SuppressWarnings("unchecked") + public T getTrait(String name) { + Class clazz = registered.get(name); + if (clazz == null) + return null; + return (T) create(clazz); + } + + @Override + public Class 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 INTERNAL_TRAITS = Sets.newHashSet(); } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/ai/speech/Chat.java b/src/main/java/net/citizensnpcs/npc/ai/speech/Chat.java new file mode 100644 index 000000000..5b42cb394 --- /dev/null +++ b/src/main/java/net/citizensnpcs/npc/ai/speech/Chat.java @@ -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", "[]: "), + CHAT_FORMAT_TO_TARGET("npc.chat.format.to-target", "[] -> You: "), + CHAT_FORMAT_TO_BYSTANDERS("npc.chat.prefix.to-bystanders", "[] -> []: "), + CHAT_FORMAT_WITH_TARGETS_TO_BYSTANDERS("npc.chat.format.with-target-to-bystanders", "[] -> []: "), + 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", ",||& |& 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.getName()).replace("", 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.getName()).replace("", 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.getName()).replace("", tongue.getRecipients().get(0).getName()).replace("", tongue.getContents()); + talkToBystanders(npc, bystanderText, tongue); + return; + } + + else { // Multiple recipients + // Set up text + String text = Setting.CHAT_FORMAT_TO_TARGET.asString().replace("", npc.getName()).replace("", 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.getName()).replace("", tongue.getRecipients().get(0).getName()).replace("", 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 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; + } + +} diff --git a/src/main/java/net/citizensnpcs/npc/ai/speech/CitizensSpeechFactory.java b/src/main/java/net/citizensnpcs/npc/ai/speech/CitizensSpeechFactory.java new file mode 100644 index 000000000..9564045d7 --- /dev/null +++ b/src/main/java/net/citizensnpcs/npc/ai/speech/CitizensSpeechFactory.java @@ -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> registered = Collections.emptyMap(); + + @Override + public void register(Class clazz, String name) { + registered.put(name, clazz); + } + + @Override + public String getVocalChordName(Class clazz) { + for (Entry> 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 clazz) { + try { + return clazz.newInstance(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return null; + } + +}