diff --git a/src/main/java/net/citizensnpcs/Citizens.java b/src/main/java/net/citizensnpcs/Citizens.java index 6297f7f67..c3a9adc2f 100644 --- a/src/main/java/net/citizensnpcs/Citizens.java +++ b/src/main/java/net/citizensnpcs/Citizens.java @@ -2,8 +2,10 @@ package net.citizensnpcs; import java.io.File; import java.io.IOException; +import java.sql.SQLException; import java.util.Iterator; import java.util.Locale; +import java.util.Map; import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.api.CitizensAPI; @@ -18,14 +20,20 @@ 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.NPCDataStore; import net.citizensnpcs.api.npc.NPCRegistry; +import net.citizensnpcs.api.npc.SimpleNPCDataStore; 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.api.util.DatabaseStorage; import net.citizensnpcs.api.util.Messaging; +import net.citizensnpcs.api.util.NBTStorage; +import net.citizensnpcs.api.util.Storage; import net.citizensnpcs.api.util.Translator; +import net.citizensnpcs.api.util.YamlStorage; import net.citizensnpcs.commands.AdminCommands; import net.citizensnpcs.commands.EditorCommands; import net.citizensnpcs.commands.HelpCommands; @@ -55,6 +63,7 @@ import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; public class Citizens extends JavaPlugin implements CitizensPlugin { private final CommandManager commands = new CommandManager(); @@ -64,8 +73,42 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { private NPCDataStore saves; private NPCSelector selector; private CitizensSpeechFactory speechFactory; + private final Map storedRegistries = Maps.newHashMap(); private CitizensTraitFactory traitFactory; + @Override + public NPCRegistry createAnonymousNPCRegistry(NPCDataStore store) { + return new CitizensNPCRegistry(store); + } + + @Override + public NPCRegistry createNamedNPCRegistry(String name, NPCDataStore store) { + NPCRegistry created = new CitizensNPCRegistry(store); + storedRegistries.put(name, created); + return created; + } + + private NPCDataStore createStorage(File folder) { + Storage saves = null; + String type = Setting.STORAGE_TYPE.asString(); + if (type.equalsIgnoreCase("db") || type.equalsIgnoreCase("database")) { + try { + saves = new DatabaseStorage(Setting.DATABASE_DRIVER.asString(), Setting.DATABASE_URL.asString(), + Setting.DATABASE_USERNAME.asString(), Setting.DATABASE_PASSWORD.asString()); + } catch (SQLException e) { + e.printStackTrace(); + Messaging.logTr(Messages.DATABASE_CONNECTION_FAILED); + } + } else if (type.equalsIgnoreCase("nbt")) { + saves = new NBTStorage(folder + File.separator + Setting.STORAGE_FILE.asString(), "Citizens NPC Storage"); + } + if (saves == null) + saves = new YamlStorage(new File(folder, Setting.STORAGE_FILE.asString()), "Citizens NPC Storage"); + if (!saves.load()) + return null; + return SimpleNPCDataStore.create(saves); + } + private void despawnNPCs() { Iterator itr = npcRegistry.iterator(); while (itr.hasNext()) { @@ -117,6 +160,11 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { return commands.getCommands(base); } + @Override + public NPCRegistry getNamedNPCRegistry(String name) { + return storedRegistries.get(name); + } + @Override public NPCRegistry getNPCRegistry() { return npcRegistry; @@ -187,7 +235,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { } registerScriptHelpers(); - saves = NPCDataStore.create(getDataFolder()); + saves = createStorage(getDataFolder()); if (saves == null) { Messaging.severeTr(Messages.FAILED_LOAD_SAVES); getServer().getPluginManager().disablePlugin(this); @@ -200,7 +248,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { speechFactory = new CitizensSpeechFactory(); speechFactory.register(Chat.class, "chat"); - getServer().getPluginManager().registerEvents(new EventListen(), this); + getServer().getPluginManager().registerEvents(new EventListen(storedRegistries), this); if (Setting.NPC_COST.asDouble() > 0) setupEconomy(); @@ -214,6 +262,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { @Override public void run() { saves.loadInto(npcRegistry); + Messaging.logTr(Messages.NUM_LOADED_NOTIFICATION, Iterables.size(npcRegistry), "?"); startMetrics(); scheduleSaveTask(Setting.SAVE_TASK_DELAY.asInt()); Bukkit.getPluginManager().callEvent(new CitizensEnableEvent()); @@ -267,6 +316,11 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { getServer().getPluginManager().callEvent(new CitizensReloadEvent()); } + @Override + public void removeNamedNPCRegistry(String name) { + storedRegistries.remove(name); + } + private void scheduleSaveTask(int delay) { Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() { @Override @@ -337,7 +391,6 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { } }); traitFactory.addPlotters(metrics.createGraph("traits")); - saves.addPlotters(metrics.createGraph("Storage type")); metrics.start(); } catch (IOException e) { Messaging.logTr(Messages.METRICS_ERROR_NOTIFICATION, e.getMessage()); @@ -371,5 +424,4 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { } private static final String COMPATIBLE_MC_VERSION = "1.4.7"; - } diff --git a/src/main/java/net/citizensnpcs/EventListen.java b/src/main/java/net/citizensnpcs/EventListen.java index ccebcb546..acbf004e5 100644 --- a/src/main/java/net/citizensnpcs/EventListen.java +++ b/src/main/java/net/citizensnpcs/EventListen.java @@ -1,6 +1,7 @@ package net.citizensnpcs; import java.util.List; +import java.util.Map; import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.api.CitizensAPI; @@ -53,11 +54,17 @@ import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Iterables; import com.google.common.collect.ListMultimap; public class EventListen implements Listener { private final NPCRegistry npcRegistry = CitizensAPI.getNPCRegistry(); - private final ListMultimap toRespawn = ArrayListMultimap.create(); + private final ListMultimap toRespawn = ArrayListMultimap.create(); + private final Map registries; + + EventListen(Map registries) { + this.registries = registries; + } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onChunkLoad(ChunkLoadEvent event) { @@ -69,7 +76,7 @@ public class EventListen implements Listener { public void onChunkUnload(ChunkUnloadEvent event) { ChunkCoord coord = toCoord(event.getChunk()); Location location = new Location(null, 0, 0, 0); - for (NPC npc : npcRegistry) { + for (NPC npc : getAllNPCs()) { if (!npc.isSpawned()) continue; location = npc.getBukkitEntity().getLocation(location); @@ -81,13 +88,17 @@ public class EventListen implements Listener { respawnAllFromCoord(coord); return; } - toRespawn.put(coord, npc.getId()); + toRespawn.put(coord, npc); Messaging .debug("Despawned id", npc.getId(), "due to chunk unload at [" + coord.x + "," + coord.z + "]"); } } } + private Iterable getAllNPCs() { + return Iterables. concat(npcRegistry, Iterables.concat(registries.values())); + } + @EventHandler(ignoreCancelled = true) public void onEntityChangedWorld(EntityTeleportEvent event) { if (event.getFrom() == null || event.getTo() == null) @@ -165,7 +176,7 @@ public class EventListen implements Listener { @EventHandler public void onNeedsRespawn(NPCNeedsRespawnEvent event) { - toRespawn.put(toCoord(event.getSpawnLocation()), event.getNPC().getId()); + toRespawn.put(toCoord(event.getSpawnLocation()), event.getNPC()); } @EventHandler(ignoreCancelled = true) @@ -226,7 +237,7 @@ public class EventListen implements Listener { if (!chunk.worldName.equals(event.getWorld().getName()) || !event.getWorld().isChunkLoaded(chunk.x, chunk.z)) continue; - List ids = toRespawn.get(chunk); + List ids = toRespawn.get(chunk); for (int i = 0; i < ids.size(); i++) { spawn(ids.get(i)); Messaging.debug("Spawned", ids.get(0), "due to world " + event.getWorld().getName() + " load"); @@ -237,7 +248,7 @@ public class EventListen implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onWorldUnload(WorldUnloadEvent event) { - for (NPC npc : npcRegistry) { + for (NPC npc : getAllNPCs()) { if (!npc.isSpawned() || !npc.getBukkitEntity().getWorld().equals(event.getWorld())) continue; storeForRespawn(npc); @@ -249,9 +260,9 @@ public class EventListen implements Listener { } private void respawnAllFromCoord(ChunkCoord coord) { - List ids = toRespawn.get(coord); + List ids = toRespawn.get(coord); for (int i = 0; i < ids.size(); i++) { - int id = ids.get(i); + NPC id = ids.get(i); boolean success = spawn(id); if (!success) { Messaging.debug("Couldn't respawn id", id, "during chunk event at [" + coord.x + "," + coord.z + "]"); @@ -262,22 +273,17 @@ public class EventListen implements Listener { } } - private boolean spawn(int id) { - NPC npc = npcRegistry.getById(id); - if (npc == null) { - Messaging.debug("Couldn't despawn unknown NPC id", id); - return false; - } + private boolean spawn(NPC npc) { Location spawn = npc.getTrait(CurrentLocation.class).getLocation(); if (spawn == null) { - Messaging.debug("Couldn't find a spawn location for despawned NPC id", id); + Messaging.debug("Couldn't find a spawn location for despawned NPC id", npc); return false; } return npc.spawn(spawn); } private void storeForRespawn(NPC npc) { - toRespawn.put(toCoord(npc.getBukkitEntity().getLocation()), npc.getId()); + toRespawn.put(toCoord(npc.getBukkitEntity().getLocation()), npc); } private ChunkCoord toCoord(Chunk chunk) { diff --git a/src/main/java/net/citizensnpcs/NPCDataStore.java b/src/main/java/net/citizensnpcs/NPCDataStore.java deleted file mode 100644 index d61396574..000000000 --- a/src/main/java/net/citizensnpcs/NPCDataStore.java +++ /dev/null @@ -1,120 +0,0 @@ -package net.citizensnpcs; - -import java.io.File; -import java.sql.SQLException; - -import net.citizensnpcs.Metrics.Graph; -import net.citizensnpcs.Metrics.Plotter; -import net.citizensnpcs.Settings.Setting; -import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.api.npc.NPCRegistry; -import net.citizensnpcs.api.util.DataKey; -import net.citizensnpcs.api.util.DatabaseStorage; -import net.citizensnpcs.api.util.Messaging; -import net.citizensnpcs.api.util.NBTStorage; -import net.citizensnpcs.api.util.Storage; -import net.citizensnpcs.api.util.YamlStorage; -import net.citizensnpcs.npc.CitizensNPC; -import net.citizensnpcs.npc.CitizensNPCRegistry; -import net.citizensnpcs.util.Messages; -import net.citizensnpcs.util.Util; - -import org.bukkit.entity.EntityType; - -public class NPCDataStore { - private final Storage root; - - private NPCDataStore(Storage saves) { - root = saves; - } - - public void addPlotters(Graph graph) { - graph.addPlotter(new Plotter("Database") { - @Override - public int getValue() { - return root instanceof DatabaseStorage ? 1 : 0; - } - }); - graph.addPlotter(new Plotter("YAML") { - @Override - public int getValue() { - return root instanceof YamlStorage ? 1 : 0; - } - }); - graph.addPlotter(new Plotter("NBT") { - @Override - public int getValue() { - return root instanceof NBTStorage ? 1 : 0; - } - }); - } - - public void loadInto(CitizensNPCRegistry registry) { - int created = 0; - for (DataKey key : root.getKey("npc").getIntegerSubKeys()) { - int id = Integer.parseInt(key.name()); - if (!key.keyExists("name")) { - Messaging.logTr(Messages.LOAD_NAME_NOT_FOUND, id); - continue; - } - String unparsedEntityType = key.getString("traits.type", "PLAYER"); - EntityType type = Util.matchEntityType(unparsedEntityType); - if (type == null) { - Messaging.logTr(Messages.LOAD_UNKNOWN_NPC_TYPE, unparsedEntityType); - continue; - } - NPC npc = registry.createNPC(type, id, key.getString("name")); - ((CitizensNPC) npc).load(key); - - created++; - } - Messaging.logTr(Messages.NUM_LOADED_NOTIFICATION, created, "?"); - } - - public void remove(NPC npc) { - root.getKey("npc").removeKey(Integer.toString(npc.getId())); - } - - public void saveToDisk() { - new Thread() { - @Override - public void run() { - root.save(); - } - }.start(); - } - - public void saveToDiskImmediate() { - root.save(); - } - - public void store(NPC npc) { - ((CitizensNPC) npc).save(root.getKey("npc." + npc.getId())); - } - - public void storeAll(NPCRegistry registry) { - for (NPC npc : registry) - store(npc); - } - - public static NPCDataStore create(File folder) { - Storage saves = null; - String type = Setting.STORAGE_TYPE.asString(); - if (type.equalsIgnoreCase("db") || type.equalsIgnoreCase("database")) { - try { - saves = new DatabaseStorage(Setting.DATABASE_DRIVER.asString(), Setting.DATABASE_URL.asString(), - Setting.DATABASE_USERNAME.asString(), Setting.DATABASE_PASSWORD.asString()); - } catch (SQLException e) { - e.printStackTrace(); - Messaging.logTr(Messages.DATABASE_CONNECTION_FAILED); - } - } else if (type.equalsIgnoreCase("nbt")) { - saves = new NBTStorage(folder + File.separator + Setting.STORAGE_FILE.asString(), "Citizens NPC Storage"); - } - if (saves == null) - saves = new YamlStorage(new File(folder, Setting.STORAGE_FILE.asString()), "Citizens NPC Storage"); - if (!saves.load()) - return null; - return new NPCDataStore(saves); - } -} diff --git a/src/main/java/net/citizensnpcs/Settings.java b/src/main/java/net/citizensnpcs/Settings.java index 65c82b193..b116df8f7 100644 --- a/src/main/java/net/citizensnpcs/Settings.java +++ b/src/main/java/net/citizensnpcs/Settings.java @@ -101,8 +101,8 @@ public class Settings { 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_CLOSE_MAXIMUM_COOLDOWN("npc.text.max-talk-cooldown", 1), + TALK_CLOSE_MINIMUM_COOLDOWN("npc.text.min-talk-cooldown", 1), TALK_ITEM("npc.text.talk-item", "340"), USE_NEW_PATHFINDER("npc.pathfinding.use-new-finder", false); diff --git a/src/main/java/net/citizensnpcs/npc/CitizensNPCRegistry.java b/src/main/java/net/citizensnpcs/npc/CitizensNPCRegistry.java index ffdd3e840..ff822f167 100644 --- a/src/main/java/net/citizensnpcs/npc/CitizensNPCRegistry.java +++ b/src/main/java/net/citizensnpcs/npc/CitizensNPCRegistry.java @@ -2,9 +2,9 @@ package net.citizensnpcs.npc; import java.util.Iterator; -import net.citizensnpcs.NPCDataStore; import net.citizensnpcs.api.event.NPCCreateEvent; import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.api.npc.NPCDataStore; import net.citizensnpcs.api.npc.NPCRegistry; import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.npc.ai.NPCHolder; @@ -26,6 +26,7 @@ public class CitizensNPCRegistry implements NPCRegistry { saves = store; } + @Override public NPC createNPC(EntityType type, int id, String name) { Preconditions.checkNotNull(name, "name cannot be null"); Preconditions.checkNotNull(type, "type cannot be null"); @@ -45,7 +46,8 @@ public class CitizensNPCRegistry implements NPCRegistry { @Override public void deregister(NPC npc) { npcs.remove(npc.getId()); - saves.remove(npc); + if (saves != null) + saves.clearData(npc); npc.despawn(); } @@ -58,7 +60,8 @@ public class CitizensNPCRegistry implements NPCRegistry { npc.despawn(); for (Trait t : npc.getTraits()) t.onRemove(); - saves.remove(npc); + if (saves != null) + saves.clearData(npc); } } diff --git a/src/main/java/net/citizensnpcs/trait/text/Text.java b/src/main/java/net/citizensnpcs/trait/text/Text.java index c68ee3b0a..500ab6f3d 100644 --- a/src/main/java/net/citizensnpcs/trait/text/Text.java +++ b/src/main/java/net/citizensnpcs/trait/text/Text.java @@ -133,8 +133,9 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve // If the cooldown is not expired, do not send text Date cooldown = cooldowns.get(player.getName()); if (cooldown != null) { - if (!new Date().after(cooldown)) + if (!new Date().after(cooldown)) { return; + } cooldowns.remove(player.getName()); } if (!sendText(player))