From 108e9d24c41f0b02b9738db1d2b7c4e619cab988 Mon Sep 17 00:00:00 2001 From: FrozenCow Date: Tue, 24 May 2011 02:13:43 +0200 Subject: [PATCH] Changed the way templates and world-configuration are handled. --- configuration.txt | 16 +- .../dynmap/ClientConfigurationComponent.java | 8 +- .../java/org/dynmap/ConfigurationNode.java | 30 ++++ src/main/java/org/dynmap/DynmapPlugin.java | 156 ++++++++---------- src/main/java/org/dynmap/DynmapWorld.java | 1 + .../dynmap/JsonFileClientUpdateComponent.java | 8 +- src/main/java/org/dynmap/MapManager.java | 95 +++++------ .../handlers/ClientConfigurationHandler.java | 8 + 8 files changed, 174 insertions(+), 148 deletions(-) diff --git a/configuration.txt b/configuration.txt index b21cbae8..35d0ada2 100644 --- a/configuration.txt +++ b/configuration.txt @@ -111,9 +111,10 @@ defaultworld: world # template world - this is used for worlds that exist but aren't defined in the worlds section. # Also, it supplies the "maps" section for worlds lacking a maps section, and the "center" # for worlds lacking a "center" section. -template: +templates: # Template for normal world normal: + enabled: true center: x: 0 y: 64 @@ -151,6 +152,7 @@ template: maximumheight: 127 # Nether world template nether: + enabled: true center: x: 0 y: 64 @@ -169,18 +171,18 @@ template: prefix: nt maximumheight: 127 colorscheme: default -# This list of worlds will be hidden - they will not be automatically initialized by templates -hiddenworlds: - - MyHiddenWorld - - AnotherHiddenWorld # The maptypes Dynmap will use to render. worlds: # Worlds can be handled by templates, based on world type - # To override, provide name and title here. Any other sections that are provided will - # be used instead of the template's value (center, maps). + # You can override the properties of the template by specifying them in this section + # for example 'Title: "My Awesome World"' #- name: world # title: "World" + # Use 'enabled: false' to disable a certain world. + # enabled: false + # Use 'template: mycustomtemplate' to use the properties specified in the template 'mycustomtemplate' to this world. Default it is set to the environment-name (normal or nether). + # template: mycustomtemplate # Rest of comes from template - uncomment to tailor for world specifically # center: # x: 0 diff --git a/src/main/java/org/dynmap/ClientConfigurationComponent.java b/src/main/java/org/dynmap/ClientConfigurationComponent.java index f5ae1361..195859e1 100644 --- a/src/main/java/org/dynmap/ClientConfigurationComponent.java +++ b/src/main/java/org/dynmap/ClientConfigurationComponent.java @@ -19,9 +19,12 @@ public class ClientConfigurationComponent extends Component { s(t, "joinmessage", c.getString("joinmessage", "%playername% joined")); s(t, "quitmessage", c.getString("quitmessage", "%playername% quit")); s(t, "spammessage", c.getString("spammessage", "You may only chat once every %interval% seconds.")); + s(t, "defaultzoom", c.getInteger("defaultzoom", 0)); - for(ConfigurationNode wn : plugin.configuration.getNodes("worlds")) { - DynmapWorld world = plugin.mapManager.getWorld(wn.getString("name")); + DynmapWorld defaultWorld = null; + for(DynmapWorld world : plugin.mapManager.getWorlds()) { + if (defaultWorld == null) defaultWorld = world; + ConfigurationNode wn = world.configuration; JSONObject wo = new JSONObject(); s(wo, "name", wn.getString("name")); s(wo, "title", wn.getString("title")); @@ -34,6 +37,7 @@ public class ClientConfigurationComponent extends Component { mt.buildClientConfiguration(wo); } } + s(t, "defaultworld", c.getString("defaultworld", defaultWorld == null ? "world" : defaultWorld.world.getName())); } }); } diff --git a/src/main/java/org/dynmap/ConfigurationNode.java b/src/main/java/org/dynmap/ConfigurationNode.java index 315b9fbf..eb50106c 100644 --- a/src/main/java/org/dynmap/ConfigurationNode.java +++ b/src/main/java/org/dynmap/ConfigurationNode.java @@ -10,6 +10,11 @@ import java.util.Set; public class ConfigurationNode implements Map { public Map entries; + + public ConfigurationNode() { + entries = new HashMap(); + } + public ConfigurationNode(org.bukkit.util.config.ConfigurationNode node) { entries = new HashMap(); for(String key : node.getKeys(null)) { @@ -18,6 +23,9 @@ public class ConfigurationNode implements Map { } public ConfigurationNode(Map map) { + if (map == null) { + throw new IllegalArgumentException(); + } entries = map; } @@ -152,6 +160,28 @@ public class ConfigurationNode implements Map { return nodes; } + public void extend(Map other) { + if (other != null) + extendMap(this, other); + } + + private final static void extendMap(Map left, Map right) { + ConfigurationNode original = new ConfigurationNode(left); + for(Map.Entry entry : right.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof Map) { + ConfigurationNode subnode = original.getNode(key); + if (subnode == null) { + original.put(key, subnode = new ConfigurationNode()); + } + extendMap(subnode, (Map)value); + } else { + original.put(key, value); + } + } + } + public T createInstance(Class[] constructorParameters, Object[] constructorArguments) { String typeName = getString("class"); try { diff --git a/src/main/java/org/dynmap/DynmapPlugin.java b/src/main/java/org/dynmap/DynmapPlugin.java index 7ce47c0f..c16f789a 100644 --- a/src/main/java/org/dynmap/DynmapPlugin.java +++ b/src/main/java/org/dynmap/DynmapPlugin.java @@ -74,8 +74,6 @@ public class DynmapPlugin extends JavaPlugin { org.bukkit.util.config.Configuration bukkitConfiguration = new org.bukkit.util.config.Configuration(new File(this.getDataFolder(), "configuration.txt")); bukkitConfiguration.load(); configuration = new ConfigurationNode(bukkitConfiguration); - - processWorldTemplates(configuration); loadDebuggers(); @@ -150,20 +148,24 @@ public class DynmapPlugin extends JavaPlugin { @Override public void onDisable() { - int componentCount = componentManager.components.size(); - for(Component component : componentManager.components) { - component.dispose(); + if (componentManager != null) { + int componentCount = componentManager.components.size(); + for(Component component : componentManager.components) { + component.dispose(); + } + componentManager.clear(); + Log.info("Unloaded " + componentCount + " components."); } - componentManager.clear(); - Log.info("Unloaded " + componentCount + " components."); - mapManager.stopRendering(); + if (mapManager != null) { + mapManager.stopRendering(); + } if (webServer != null) { webServer.shutdown(); webServer = null; } - + Debug.clearDebuggers(); } @@ -344,10 +346,7 @@ public class DynmapPlugin extends JavaPlugin { } } else if (c.equals("reload") && checkPlayerPermission(sender, "reload")) { sender.sendMessage("Reloading Dynmap..."); - is_reload = true; - onDisable(); - onEnable(); - is_reload = false; + reload(); sender.sendMessage("Dynmap reloaded"); return true; } @@ -365,86 +364,67 @@ public class DynmapPlugin extends JavaPlugin { } return true; } - /* Prepare for sky worlds... */ - private static final String[] templateworldtypes = { "normal", "nether" }; - private static final Environment[] templateworldenv = { Environment.NORMAL, Environment.NETHER }; - - private void processWorldTemplates(ConfigurationNode node) { - ConfigurationNode template = node.getNode("template"); - if(template == null) - return; - List worlds = node.getNodes("worlds"); - boolean worldsupdated = false; - /* Initialize even if no worlds section */ - if(worlds == null) { - worlds = new ArrayList(); - worldsupdated = true; - } - List hiddenworlds = node.getStrings("hiddenworlds", Collections.EMPTY_LIST); - /* Iternate by world type - so that order in templateworldtypes drives our default order */ - for(int wtype = 0; wtype < templateworldtypes.length; wtype++) { - ConfigurationNode typetemplate = template.getNode(templateworldtypes[wtype]); - if(typetemplate == null) - continue; - for(World w : getServer().getWorlds()) { /* Roll through worlds */ - String wn = w.getName(); - /* Skip processing on hidden worlds */ - if(hiddenworlds.contains(wn)) - continue; - /* Find node for this world, if any */ - ConfigurationNode world = null; - int index; - for(index = 0; index < worlds.size(); index++) { - ConfigurationNode ww = worlds.get(index); - if(wn.equals(ww.getString("name", ""))) { - world = ww; - break; - } - } - /* Check type of world - skip if not right for current template */ - if(w.getEnvironment() != templateworldenv[wtype]) - continue; - /* World not found - need to use template */ - if(world == null) { - ConfigurationNode newworldnode = new ConfigurationNode(new HashMap(typetemplate)); /* Copy it */ - newworldnode.put("name", w.getName()); - newworldnode.put("title", w.getName()); - worlds.add(newworldnode); - worldsupdated = true; - Log.info("World '" + w.getName() + "' configuration inherited from template"); - } - else { /* Else, definition is there, but may be incomplete */ - boolean wupd = false; - List tempmaps = typetemplate.getList("maps"); - if((tempmaps != null) && (world.get("maps") == null)) { /* World with no maps section */ - world.put("maps", tempmaps); - Log.info("World '" + w.getName() + "' configuration inherited maps from template"); - wupd = true; - } - ConfigurationNode tempcenter = typetemplate.getNode("center"); - if((tempcenter != null) && (world.get("center") == null)) { /* World with no center */ - world.put("center", new ConfigurationNode(new HashMap(tempcenter))); - Log.info("World '" + w.getName() + "' configuration inherited center from template"); - wupd = true; - } - if(world.getString("title", null) == null) { - world.put("title", w.getName()); - wupd = true; - } - if(wupd) { - worldsupdated = true; - worlds.set(index, world); - } - } + public ConfigurationNode getWorldConfiguration(World world) { + ConfigurationNode finalConfiguration = new ConfigurationNode(); + finalConfiguration.put("name", world.getName()); + finalConfiguration.put("title", world.getName()); + + ConfigurationNode worldConfiguration = getWorldConfigurationNode(world.getName()); + + // Get the template. + ConfigurationNode templateConfiguration = null; + if (worldConfiguration != null) { + String templateName = worldConfiguration.getString("template"); + if (templateName != null) { + templateConfiguration = getTemplateConfigurationNode(templateName); } } - if(worldsupdated) { - node.put("worlds", worlds); + + // Template not found, using default template. + if (templateConfiguration == null) { + templateConfiguration = getDefaultTemplateConfigurationNode(world); } + + // Merge the finalConfiguration, templateConfiguration and worldConfiguration. + finalConfiguration.extend(templateConfiguration); + finalConfiguration.extend(worldConfiguration); + + Log.info("Configuration of world " + world.getName()); + for(Map.Entry e : finalConfiguration.entrySet()) { + Log.info(e.getKey() + ": " + e.getValue()); + } + + return finalConfiguration; } - public boolean isReload() { - return is_reload; + private ConfigurationNode getDefaultTemplateConfigurationNode(World world) { + Environment environment = world.getEnvironment(); + String environmentName = environment.name().toLowerCase(); + Log.info("Using environment as template: " + environmentName); + return getTemplateConfigurationNode(environmentName); + } + + private ConfigurationNode getWorldConfigurationNode(String worldName) { + for(ConfigurationNode worldNode : configuration.getNodes("worlds")) { + if (worldName.equals(worldNode.getString("name"))) { + return worldNode; + } + } + return new ConfigurationNode(); + } + + private ConfigurationNode getTemplateConfigurationNode(String templateName) { + ConfigurationNode templatesNode = configuration.getNode("templates"); + if (templatesNode != null) { + return templatesNode.getNode(templateName); + } + return null; + } + + public void reload() { + PluginManager pluginManager = getServer().getPluginManager(); + pluginManager.disablePlugin(this); + pluginManager.enablePlugin(this); } } diff --git a/src/main/java/org/dynmap/DynmapWorld.java b/src/main/java/org/dynmap/DynmapWorld.java index a02bc434..0973c4e9 100644 --- a/src/main/java/org/dynmap/DynmapWorld.java +++ b/src/main/java/org/dynmap/DynmapWorld.java @@ -9,4 +9,5 @@ public class DynmapWorld { public World world; public List maps = new ArrayList(); public UpdateQueue updates = new UpdateQueue(); + public ConfigurationNode configuration; } diff --git a/src/main/java/org/dynmap/JsonFileClientUpdateComponent.java b/src/main/java/org/dynmap/JsonFileClientUpdateComponent.java index a4dd7adc..45257702 100644 --- a/src/main/java/org/dynmap/JsonFileClientUpdateComponent.java +++ b/src/main/java/org/dynmap/JsonFileClientUpdateComponent.java @@ -57,6 +57,12 @@ public class JsonFileClientUpdateComponent extends ClientUpdateComponent { writeConfiguration(); } }); + plugin.events.addListener("worldactivated", new Event.Listener() { + @Override + public void triggered(DynmapWorld t) { + writeConfiguration(); + } + }); } protected File getStandaloneFile(String filename) { @@ -87,7 +93,7 @@ public class JsonFileClientUpdateComponent extends ClientUpdateComponent { protected void writeUpdates() { File outputFile; //Handles Updates - for (DynmapWorld dynmapWorld : plugin.mapManager.worlds.values()) { + for (DynmapWorld dynmapWorld : plugin.mapManager.getWorlds()) { World world = dynmapWorld.world; JSONObject update = new JSONObject(); diff --git a/src/main/java/org/dynmap/MapManager.java b/src/main/java/org/dynmap/MapManager.java index 76548902..e89a5389 100644 --- a/src/main/java/org/dynmap/MapManager.java +++ b/src/main/java/org/dynmap/MapManager.java @@ -1,9 +1,12 @@ package org.dynmap; import java.io.File; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; +import java.util.List; import java.util.Map; import org.bukkit.Chunk; @@ -17,8 +20,8 @@ public class MapManager { public AsynchronousQueue tileQueue; public AsynchronousQueue writeQueue; - public Map worlds = new HashMap(); - public Map inactiveworlds = new HashMap(); + public List worlds = new ArrayList(); + public Map worldsLookup = new HashMap(); private BukkitScheduler scheduler; private DynmapPlugin plug_in; private double timeslice_interval = 0.0; @@ -35,13 +38,14 @@ public class MapManager { } public DynmapWorld getWorld(String name) { - DynmapWorld world = worlds.get(name); - if(world == null) { - world = inactiveworlds.get(name); - } + DynmapWorld world = worldsLookup.get(name); return world; } + public Collection getWorlds() { + return worlds; + } + private class FullWorldRenderState implements Runnable { DynmapWorld world; /* Which world are we rendering */ Location loc; /* Start location */ @@ -64,7 +68,7 @@ public class MapManager { /* Single tile render - used for incremental renders */ FullWorldRenderState(MapTile t) { - world = worlds.get(t.getWorld().getName()); + world = getWorld(t.getWorld().getName()); tile0 = t; } @@ -136,7 +140,7 @@ public class MapManager { } public MapManager(DynmapPlugin plugin, ConfigurationNode configuration) { - + plug_in = plugin; mapman = this; this.tileQueue = new AsynchronousQueue(new Handler() { @@ -157,42 +161,18 @@ public class MapManager { timeslice_interval = configuration.getDouble("timesliceinterval", 0.5); - for(ConfigurationNode worldConfiguration : configuration.getNodes("worlds")) { - String worldName = worldConfiguration.getString("name"); - DynmapWorld world = new DynmapWorld(); - - Event.Listener invalitateListener = new Event.Listener() { - @Override - public void triggered(MapTile t) { - invalidateTile(t); - } - }; - - Log.info("Loading maps of world '" + worldName + "'..."); - for(MapType map : worldConfiguration.createInstances("maps", new Class[0], new Object[0])) { - map.onTileInvalidated.addListener(invalitateListener); - world.maps.add(map); - } - Log.info("Loaded " + world.maps.size() + " maps of world '" + worldName + "'."); - - inactiveworlds.put(worldName, world); - - World bukkitWorld = plugin.getServer().getWorld(worldName); - if (bukkitWorld != null) - activateWorld(bukkitWorld); - } - scheduler = plugin.getServer().getScheduler(); - plug_in = plugin; tileQueue.start(); writeQueue.start(); + + for (World world : plug_in.getServer().getWorlds()) { + activateWorld(world); + } } - - void renderFullWorld(Location l) { - DynmapWorld world = worlds.get(l.getWorld().getName()); + DynmapWorld world = getWorld(l.getWorld().getName()); if (world == null) { Log.severe("Could not render: world '" + l.getWorld().getName() + "' not defined in configuration."); return; @@ -211,21 +191,36 @@ public class MapManager { } public void activateWorld(World w) { - DynmapWorld world = inactiveworlds.get(w.getName()); - if (world == null) { - world = worlds.get(w.getName()); - } else { - inactiveworlds.remove(w.getName()); + ConfigurationNode worldConfiguration = plug_in.getWorldConfiguration(w); + if (!worldConfiguration.getBoolean("enabled", false)) { + Log.info("World '" + w.getName() + "' disabled"); + return; } - if (world != null) { - world.world = w; - worlds.put(w.getName(), world); - Log.info("Activated world '" + w.getName() + "' in Dynmap."); + String worldName = w.getName(); + + Event.Listener invalitateListener = new Event.Listener() { + @Override + public void triggered(MapTile t) { + invalidateTile(t); + } + }; + + DynmapWorld dynmapWorld = new DynmapWorld(); + dynmapWorld.world = w; + dynmapWorld.configuration = worldConfiguration; + Log.info("Loading maps of world '" + worldName + "'..."); + for(MapType map : worldConfiguration.createInstances("maps", new Class[0], new Object[0])) { + map.onTileInvalidated.addListener(invalitateListener); + dynmapWorld.maps.add(map); } + Log.info("Loaded " + dynmapWorld.maps.size() + " maps of world '" + worldName + "'."); + worlds.add(dynmapWorld); + worldsLookup.put(w.getName(), dynmapWorld); + plug_in.events.trigger("worldactivated", dynmapWorld); } public int touch(Location l) { - DynmapWorld world = worlds.get(l.getWorld().getName()); + DynmapWorld world = getWorld(l.getWorld().getName()); if (world == null) return 0; int invalidates = 0; @@ -276,7 +271,7 @@ public class MapManager { } public void pushUpdate(Object update) { - for(DynmapWorld world : worlds.values()) { + for(DynmapWorld world : getWorlds()) { world.updates.pushUpdate(update); } } @@ -286,12 +281,12 @@ public class MapManager { } public void pushUpdate(String worldName, Object update) { - DynmapWorld world = worlds.get(worldName); + DynmapWorld world = getWorld(worldName); world.updates.pushUpdate(update); } public Object[] getWorldUpdates(String worldName, long since) { - DynmapWorld world = worlds.get(worldName); + DynmapWorld world = getWorld(worldName); if (world == null) return new Object[0]; return world.updates.getUpdatedObjects(since); diff --git a/src/main/java/org/dynmap/web/handlers/ClientConfigurationHandler.java b/src/main/java/org/dynmap/web/handlers/ClientConfigurationHandler.java index 84d1d790..daad5b86 100644 --- a/src/main/java/org/dynmap/web/handlers/ClientConfigurationHandler.java +++ b/src/main/java/org/dynmap/web/handlers/ClientConfigurationHandler.java @@ -5,6 +5,8 @@ import java.util.Date; import java.util.Map; import org.dynmap.DynmapPlugin; +import org.dynmap.DynmapWorld; +import org.dynmap.Event; import org.dynmap.web.HttpHandler; import org.dynmap.web.HttpRequest; import org.dynmap.web.HttpResponse; @@ -16,6 +18,12 @@ public class ClientConfigurationHandler implements HttpHandler { private byte[] cachedConfiguration = null; public ClientConfigurationHandler(DynmapPlugin plugin) { this.plugin = plugin; + plugin.events.addListener("worldactivated", new Event.Listener() { + @Override + public void triggered(DynmapWorld t) { + cachedConfiguration = null; + } + }); } @Override public void handle(String path, HttpRequest request, HttpResponse response) throws Exception {