Changed the way templates and world-configuration are handled.

This commit is contained in:
FrozenCow 2011-05-24 02:13:43 +02:00
parent de0ad58344
commit 108e9d24c4
8 changed files with 174 additions and 148 deletions

View File

@ -111,9 +111,10 @@ defaultworld: world
# template world - this is used for worlds that exist but aren't defined in the worlds section. # 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" # Also, it supplies the "maps" section for worlds lacking a maps section, and the "center"
# for worlds lacking a "center" section. # for worlds lacking a "center" section.
template: templates:
# Template for normal world # Template for normal world
normal: normal:
enabled: true
center: center:
x: 0 x: 0
y: 64 y: 64
@ -151,6 +152,7 @@ template:
maximumheight: 127 maximumheight: 127
# Nether world template # Nether world template
nether: nether:
enabled: true
center: center:
x: 0 x: 0
y: 64 y: 64
@ -169,18 +171,18 @@ template:
prefix: nt prefix: nt
maximumheight: 127 maximumheight: 127
colorscheme: default 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. # The maptypes Dynmap will use to render.
worlds: worlds:
# Worlds can be handled by templates, based on world type # Worlds can be handled by templates, based on world type
# To override, provide name and title here. Any other sections that are provided will # You can override the properties of the template by specifying them in this section
# be used instead of the template's value (center, maps). # for example 'Title: "My Awesome World"'
#- name: world #- name: world
# title: "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 # Rest of comes from template - uncomment to tailor for world specifically
# center: # center:
# x: 0 # x: 0

View File

@ -19,9 +19,12 @@ public class ClientConfigurationComponent extends Component {
s(t, "joinmessage", c.getString("joinmessage", "%playername% joined")); s(t, "joinmessage", c.getString("joinmessage", "%playername% joined"));
s(t, "quitmessage", c.getString("quitmessage", "%playername% quit")); s(t, "quitmessage", c.getString("quitmessage", "%playername% quit"));
s(t, "spammessage", c.getString("spammessage", "You may only chat once every %interval% seconds.")); 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 defaultWorld = null;
DynmapWorld world = plugin.mapManager.getWorld(wn.getString("name")); for(DynmapWorld world : plugin.mapManager.getWorlds()) {
if (defaultWorld == null) defaultWorld = world;
ConfigurationNode wn = world.configuration;
JSONObject wo = new JSONObject(); JSONObject wo = new JSONObject();
s(wo, "name", wn.getString("name")); s(wo, "name", wn.getString("name"));
s(wo, "title", wn.getString("title")); s(wo, "title", wn.getString("title"));
@ -34,6 +37,7 @@ public class ClientConfigurationComponent extends Component {
mt.buildClientConfiguration(wo); mt.buildClientConfiguration(wo);
} }
} }
s(t, "defaultworld", c.getString("defaultworld", defaultWorld == null ? "world" : defaultWorld.world.getName()));
} }
}); });
} }

View File

@ -10,6 +10,11 @@ import java.util.Set;
public class ConfigurationNode implements Map<String, Object> { public class ConfigurationNode implements Map<String, Object> {
public Map<String, Object> entries; public Map<String, Object> entries;
public ConfigurationNode() {
entries = new HashMap<String, Object>();
}
public ConfigurationNode(org.bukkit.util.config.ConfigurationNode node) { public ConfigurationNode(org.bukkit.util.config.ConfigurationNode node) {
entries = new HashMap<String, Object>(); entries = new HashMap<String, Object>();
for(String key : node.getKeys(null)) { for(String key : node.getKeys(null)) {
@ -18,6 +23,9 @@ public class ConfigurationNode implements Map<String, Object> {
} }
public ConfigurationNode(Map<String, Object> map) { public ConfigurationNode(Map<String, Object> map) {
if (map == null) {
throw new IllegalArgumentException();
}
entries = map; entries = map;
} }
@ -152,6 +160,28 @@ public class ConfigurationNode implements Map<String, Object> {
return nodes; return nodes;
} }
public void extend(Map<String, Object> other) {
if (other != null)
extendMap(this, other);
}
private final static void extendMap(Map<String, Object> left, Map<String, Object> right) {
ConfigurationNode original = new ConfigurationNode(left);
for(Map.Entry<String, Object> 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<String, Object>)value);
} else {
original.put(key, value);
}
}
}
public <T> T createInstance(Class<?>[] constructorParameters, Object[] constructorArguments) { public <T> T createInstance(Class<?>[] constructorParameters, Object[] constructorArguments) {
String typeName = getString("class"); String typeName = getString("class");
try { try {

View File

@ -75,8 +75,6 @@ public class DynmapPlugin extends JavaPlugin {
bukkitConfiguration.load(); bukkitConfiguration.load();
configuration = new ConfigurationNode(bukkitConfiguration); configuration = new ConfigurationNode(bukkitConfiguration);
processWorldTemplates(configuration);
loadDebuggers(); loadDebuggers();
tilesDirectory = getFile(configuration.getString("tilespath", "web/tiles")); tilesDirectory = getFile(configuration.getString("tilespath", "web/tiles"));
@ -150,14 +148,18 @@ public class DynmapPlugin extends JavaPlugin {
@Override @Override
public void onDisable() { public void onDisable() {
if (componentManager != null) {
int componentCount = componentManager.components.size(); int componentCount = componentManager.components.size();
for(Component component : componentManager.components) { for(Component component : componentManager.components) {
component.dispose(); component.dispose();
} }
componentManager.clear(); componentManager.clear();
Log.info("Unloaded " + componentCount + " components."); Log.info("Unloaded " + componentCount + " components.");
}
if (mapManager != null) {
mapManager.stopRendering(); mapManager.stopRendering();
}
if (webServer != null) { if (webServer != null) {
webServer.shutdown(); webServer.shutdown();
@ -344,10 +346,7 @@ public class DynmapPlugin extends JavaPlugin {
} }
} else if (c.equals("reload") && checkPlayerPermission(sender, "reload")) { } else if (c.equals("reload") && checkPlayerPermission(sender, "reload")) {
sender.sendMessage("Reloading Dynmap..."); sender.sendMessage("Reloading Dynmap...");
is_reload = true; reload();
onDisable();
onEnable();
is_reload = false;
sender.sendMessage("Dynmap reloaded"); sender.sendMessage("Dynmap reloaded");
return true; return true;
} }
@ -365,86 +364,67 @@ public class DynmapPlugin extends JavaPlugin {
} }
return true; 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) { public ConfigurationNode getWorldConfiguration(World world) {
ConfigurationNode template = node.getNode("template"); ConfigurationNode finalConfiguration = new ConfigurationNode();
if(template == null) finalConfiguration.put("name", world.getName());
return; finalConfiguration.put("title", world.getName());
List<ConfigurationNode> worlds = node.getNodes("worlds");
boolean worldsupdated = false;
/* Initialize even if no worlds section */
if(worlds == null) {
worlds = new ArrayList<ConfigurationNode>();
worldsupdated = true;
}
List<String> hiddenworlds = node.getStrings("hiddenworlds", Collections.EMPTY_LIST);
/* Iternate by world type - so that order in templateworldtypes drives our default order */ ConfigurationNode worldConfiguration = getWorldConfigurationNode(world.getName());
for(int wtype = 0; wtype < templateworldtypes.length; wtype++) {
ConfigurationNode typetemplate = template.getNode(templateworldtypes[wtype]); // Get the template.
if(typetemplate == null) ConfigurationNode templateConfiguration = null;
continue; if (worldConfiguration != null) {
for(World w : getServer().getWorlds()) { /* Roll through worlds */ String templateName = worldConfiguration.getString("template");
String wn = w.getName(); if (templateName != null) {
/* Skip processing on hidden worlds */ templateConfiguration = getTemplateConfigurationNode(templateName);
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<String,Object>(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<ConfigurationNode> 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<String,Object>(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);
}
}
}
}
if(worldsupdated) {
node.put("worlds", worlds);
} }
} }
public boolean isReload() { // Template not found, using default template.
return is_reload; 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<String, Object> e : finalConfiguration.entrySet()) {
Log.info(e.getKey() + ": " + e.getValue());
}
return finalConfiguration;
}
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);
} }
} }

View File

@ -9,4 +9,5 @@ public class DynmapWorld {
public World world; public World world;
public List<MapType> maps = new ArrayList<MapType>(); public List<MapType> maps = new ArrayList<MapType>();
public UpdateQueue updates = new UpdateQueue(); public UpdateQueue updates = new UpdateQueue();
public ConfigurationNode configuration;
} }

View File

@ -57,6 +57,12 @@ public class JsonFileClientUpdateComponent extends ClientUpdateComponent {
writeConfiguration(); writeConfiguration();
} }
}); });
plugin.events.addListener("worldactivated", new Event.Listener<DynmapWorld>() {
@Override
public void triggered(DynmapWorld t) {
writeConfiguration();
}
});
} }
protected File getStandaloneFile(String filename) { protected File getStandaloneFile(String filename) {
@ -87,7 +93,7 @@ public class JsonFileClientUpdateComponent extends ClientUpdateComponent {
protected void writeUpdates() { protected void writeUpdates() {
File outputFile; File outputFile;
//Handles Updates //Handles Updates
for (DynmapWorld dynmapWorld : plugin.mapManager.worlds.values()) { for (DynmapWorld dynmapWorld : plugin.mapManager.getWorlds()) {
World world = dynmapWorld.world; World world = dynmapWorld.world;
JSONObject update = new JSONObject(); JSONObject update = new JSONObject();

View File

@ -1,9 +1,12 @@
package org.dynmap; package org.dynmap;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.bukkit.Chunk; import org.bukkit.Chunk;
@ -17,8 +20,8 @@ public class MapManager {
public AsynchronousQueue<MapTile> tileQueue; public AsynchronousQueue<MapTile> tileQueue;
public AsynchronousQueue<ImageWriter> writeQueue; public AsynchronousQueue<ImageWriter> writeQueue;
public Map<String, DynmapWorld> worlds = new HashMap<String, DynmapWorld>(); public List<DynmapWorld> worlds = new ArrayList<DynmapWorld>();
public Map<String, DynmapWorld> inactiveworlds = new HashMap<String, DynmapWorld>(); public Map<String, DynmapWorld> worldsLookup = new HashMap<String, DynmapWorld>();
private BukkitScheduler scheduler; private BukkitScheduler scheduler;
private DynmapPlugin plug_in; private DynmapPlugin plug_in;
private double timeslice_interval = 0.0; private double timeslice_interval = 0.0;
@ -35,13 +38,14 @@ public class MapManager {
} }
public DynmapWorld getWorld(String name) { public DynmapWorld getWorld(String name) {
DynmapWorld world = worlds.get(name); DynmapWorld world = worldsLookup.get(name);
if(world == null) {
world = inactiveworlds.get(name);
}
return world; return world;
} }
public Collection<DynmapWorld> getWorlds() {
return worlds;
}
private class FullWorldRenderState implements Runnable { private class FullWorldRenderState implements Runnable {
DynmapWorld world; /* Which world are we rendering */ DynmapWorld world; /* Which world are we rendering */
Location loc; /* Start location */ Location loc; /* Start location */
@ -64,7 +68,7 @@ public class MapManager {
/* Single tile render - used for incremental renders */ /* Single tile render - used for incremental renders */
FullWorldRenderState(MapTile t) { FullWorldRenderState(MapTile t) {
world = worlds.get(t.getWorld().getName()); world = getWorld(t.getWorld().getName());
tile0 = t; tile0 = t;
} }
@ -136,7 +140,7 @@ public class MapManager {
} }
public MapManager(DynmapPlugin plugin, ConfigurationNode configuration) { public MapManager(DynmapPlugin plugin, ConfigurationNode configuration) {
plug_in = plugin;
mapman = this; mapman = this;
this.tileQueue = new AsynchronousQueue<MapTile>(new Handler<MapTile>() { this.tileQueue = new AsynchronousQueue<MapTile>(new Handler<MapTile>() {
@ -157,42 +161,18 @@ public class MapManager {
timeslice_interval = configuration.getDouble("timesliceinterval", 0.5); timeslice_interval = configuration.getDouble("timesliceinterval", 0.5);
for(ConfigurationNode worldConfiguration : configuration.getNodes("worlds")) {
String worldName = worldConfiguration.getString("name");
DynmapWorld world = new DynmapWorld();
Event.Listener<MapTile> invalitateListener = new Event.Listener<MapTile>() {
@Override
public void triggered(MapTile t) {
invalidateTile(t);
}
};
Log.info("Loading maps of world '" + worldName + "'...");
for(MapType map : worldConfiguration.<MapType>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(); scheduler = plugin.getServer().getScheduler();
plug_in = plugin;
tileQueue.start(); tileQueue.start();
writeQueue.start(); writeQueue.start();
for (World world : plug_in.getServer().getWorlds()) {
activateWorld(world);
}
} }
void renderFullWorld(Location l) { void renderFullWorld(Location l) {
DynmapWorld world = worlds.get(l.getWorld().getName()); DynmapWorld world = getWorld(l.getWorld().getName());
if (world == null) { if (world == null) {
Log.severe("Could not render: world '" + l.getWorld().getName() + "' not defined in configuration."); Log.severe("Could not render: world '" + l.getWorld().getName() + "' not defined in configuration.");
return; return;
@ -211,21 +191,36 @@ public class MapManager {
} }
public void activateWorld(World w) { public void activateWorld(World w) {
DynmapWorld world = inactiveworlds.get(w.getName()); ConfigurationNode worldConfiguration = plug_in.getWorldConfiguration(w);
if (world == null) { if (!worldConfiguration.getBoolean("enabled", false)) {
world = worlds.get(w.getName()); Log.info("World '" + w.getName() + "' disabled");
} else { return;
inactiveworlds.remove(w.getName());
} }
if (world != null) { String worldName = w.getName();
world.world = w;
worlds.put(w.getName(), world); Event.Listener<MapTile> invalitateListener = new Event.Listener<MapTile>() {
Log.info("Activated world '" + w.getName() + "' in Dynmap."); @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.<MapType>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) { public int touch(Location l) {
DynmapWorld world = worlds.get(l.getWorld().getName()); DynmapWorld world = getWorld(l.getWorld().getName());
if (world == null) if (world == null)
return 0; return 0;
int invalidates = 0; int invalidates = 0;
@ -276,7 +271,7 @@ public class MapManager {
} }
public void pushUpdate(Object update) { public void pushUpdate(Object update) {
for(DynmapWorld world : worlds.values()) { for(DynmapWorld world : getWorlds()) {
world.updates.pushUpdate(update); world.updates.pushUpdate(update);
} }
} }
@ -286,12 +281,12 @@ public class MapManager {
} }
public void pushUpdate(String worldName, Object update) { public void pushUpdate(String worldName, Object update) {
DynmapWorld world = worlds.get(worldName); DynmapWorld world = getWorld(worldName);
world.updates.pushUpdate(update); world.updates.pushUpdate(update);
} }
public Object[] getWorldUpdates(String worldName, long since) { public Object[] getWorldUpdates(String worldName, long since) {
DynmapWorld world = worlds.get(worldName); DynmapWorld world = getWorld(worldName);
if (world == null) if (world == null)
return new Object[0]; return new Object[0];
return world.updates.getUpdatedObjects(since); return world.updates.getUpdatedObjects(since);

View File

@ -5,6 +5,8 @@ import java.util.Date;
import java.util.Map; import java.util.Map;
import org.dynmap.DynmapPlugin; import org.dynmap.DynmapPlugin;
import org.dynmap.DynmapWorld;
import org.dynmap.Event;
import org.dynmap.web.HttpHandler; import org.dynmap.web.HttpHandler;
import org.dynmap.web.HttpRequest; import org.dynmap.web.HttpRequest;
import org.dynmap.web.HttpResponse; import org.dynmap.web.HttpResponse;
@ -16,6 +18,12 @@ public class ClientConfigurationHandler implements HttpHandler {
private byte[] cachedConfiguration = null; private byte[] cachedConfiguration = null;
public ClientConfigurationHandler(DynmapPlugin plugin) { public ClientConfigurationHandler(DynmapPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
plugin.events.addListener("worldactivated", new Event.Listener<DynmapWorld>() {
@Override
public void triggered(DynmapWorld t) {
cachedConfiguration = null;
}
});
} }
@Override @Override
public void handle(String path, HttpRequest request, HttpResponse response) throws Exception { public void handle(String path, HttpRequest request, HttpResponse response) throws Exception {