diff --git a/configuration.txt b/configuration.txt index ba469013..2859a65e 100644 --- a/configuration.txt +++ b/configuration.txt @@ -2,6 +2,13 @@ components: - class: org.dynmap.ClientConfigurationComponent + + - class: org.dynmap.InternalClientUpdateComponent + sendhealth: true + #- class: org.dynmap.JsonFileClientUpdateComponent + # sendhealth: true + # interval: 1 + - class: org.dynmap.SimpleWebChatComponent #- class: org.dynmap.herochat.HeroWebChatComponent # # Control which HeroChat channel messages from web are directed to @@ -11,6 +18,7 @@ components: # - Global # #- Trade # #- Haggle + - class: org.dynmap.ClientComponent type: chat - class: org.dynmap.ClientComponent @@ -23,7 +31,7 @@ components: - class: org.dynmap.ClientComponent type: playermarkers showplayerfaces: true - showplayerhealth: false + showplayerhealth: true #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent diff --git a/src/main/java/org/dynmap/Client.java b/src/main/java/org/dynmap/Client.java index 4a82ec08..03e7df03 100644 --- a/src/main/java/org/dynmap/Client.java +++ b/src/main/java/org/dynmap/Client.java @@ -1,41 +1,29 @@ package org.dynmap; +import java.io.IOException; +import java.io.Writer; + import org.bukkit.ChatColor; +import org.json.simple.JSONAware; +import org.json.simple.JSONStreamAware; public class Client { - public static class Update { - public long timestamp; - public long servertime; - public boolean hasStorm; - public boolean isThundering; - public Player[] players; - public Object[] updates; - } + public static class Update implements JSONAware, JSONStreamAware { + public long timestamp = System.currentTimeMillis(); - public static class Player { - public String type = "player"; - public String name; - public String world; - public double x, y, z; - public int health; - public String account; + @Override + public String toJSONString() { + return org.dynmap.web.Json.stringifyJson(this); + } - public Player(String name, String world, double x, double y, double z, int health, String account) { - this.name = ChatColor.stripColor(name); - this.world = world; - this.x = x; - this.y = y; - this.z = z; - this.health = health; - this.account = account; + @Override + public void writeJSONString(Writer w) throws IOException { + // TODO: This isn't the best... + w.write(toJSONString()); } } - public static class Stamped { - public long timestamp = System.currentTimeMillis(); - } - - public static class ChatMessage extends Stamped { + public static class ChatMessage extends Update { public String type = "chat"; public String source; public String playerName; @@ -51,7 +39,7 @@ public class Client { } } - public static class PlayerJoinMessage extends Stamped { + public static class PlayerJoinMessage extends Update { public String type = "playerjoin"; public String playerName; public String account; @@ -61,7 +49,7 @@ public class Client { } } - public static class PlayerQuitMessage extends Stamped { + public static class PlayerQuitMessage extends Update { public String type = "playerquit"; public String playerName; public String account; @@ -71,7 +59,7 @@ public class Client { } } - public static class Tile extends Stamped { + public static class Tile extends Update { public String type = "tile"; public String name; diff --git a/src/main/java/org/dynmap/ClientUpdateComponent.java b/src/main/java/org/dynmap/ClientUpdateComponent.java new file mode 100644 index 00000000..ce9743e6 --- /dev/null +++ b/src/main/java/org/dynmap/ClientUpdateComponent.java @@ -0,0 +1,58 @@ +package org.dynmap; + +import static org.dynmap.JSONUtils.a; +import static org.dynmap.JSONUtils.s; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +public class ClientUpdateComponent extends Component { + public ClientUpdateComponent(final DynmapPlugin plugin, ConfigurationNode configuration) { + super(plugin, configuration); + plugin.events.addListener("buildclientupdate", new Event.Listener() { + @Override + public void triggered(ClientUpdateEvent e) { + buildClientUpdate(e); + } + }); + } + + protected void buildClientUpdate(ClientUpdateEvent e) { + World world = e.world.world; + JSONObject u = e.update; + long since = e.timestamp; + String worldName = world.getName(); + + s(u, "servertime", world.getTime() % 24000); + s(u, "hasStorm", world.hasStorm()); + s(u, "isThundering", world.isThundering()); + + s(u, "players", new JSONArray()); + Player[] players = plugin.playerList.getVisiblePlayers(); + for(int i=0;i triggers = configuration.getStrings("render-triggers", new ArrayList()); @@ -121,11 +112,15 @@ public class DynmapPlugin extends JavaPlugin { registerEvents(); - startWebserver(); + if (!configuration.getBoolean("disable-webserver", false)) { + startWebserver(); + } /* Print version info */ PluginDescriptionFile pdfFile = this.getDescription(); Log.info("version " + pdfFile.getVersion() + " is enabled" ); + + events.trigger("initialized", null); } public void loadWebserver() { @@ -145,7 +140,6 @@ public class DynmapPlugin extends JavaPlugin { webServer = new HttpServer(bindAddress, port); webServer.handlers.put("/", new FilesystemHandler(getFile(configuration.getString("webpath", "web")))); webServer.handlers.put("/tiles/", new FilesystemHandler(tilesDirectory)); - webServer.handlers.put("/up/", new ClientUpdateHandler(this, configuration.getBoolean("health-in-json", false))); webServer.handlers.put("/up/configuration", new ClientConfigurationHandler(this)); if (configuration.getBoolean("allowwebchat", false)) { @@ -388,27 +382,6 @@ public class DynmapPlugin extends JavaPlugin { return true; } - private void jsonConfig() { - File outputFile; - JSONObject clientConfiguration = new JSONObject(); - events.trigger("buildclientconfiguration", clientConfiguration); - File webpath = new File(configuration.getString("webpath", "web"), "standalone/dynmap_config.json"); - if (webpath.isAbsolute()) - outputFile = webpath; - else - outputFile = new File(getDataFolder(), webpath.toString()); - - try { - FileOutputStream fos = new FileOutputStream(outputFile); - fos.write(clientConfiguration.toJSONString().getBytes()); - fos.close(); - } catch (FileNotFoundException ex) { - Log.severe("Exception while writing JSON-configuration-file.", ex); - } catch (IOException ioe) { - Log.severe("Exception while writing JSON-configuration-file.", ioe); - } - } - public void webChat(String name, String message) { mapManager.pushUpdate(new Client.ChatMessage("web", null, name, message, null)); Log.info("[WEB]" + name + ": " + message); diff --git a/src/main/java/org/dynmap/InternalClientUpdateComponent.java b/src/main/java/org/dynmap/InternalClientUpdateComponent.java new file mode 100644 index 00000000..d571aeef --- /dev/null +++ b/src/main/java/org/dynmap/InternalClientUpdateComponent.java @@ -0,0 +1,12 @@ +package org.dynmap; + +import org.dynmap.web.handlers.ClientUpdateHandler; + +public class InternalClientUpdateComponent extends ClientUpdateComponent { + + public InternalClientUpdateComponent(DynmapPlugin plugin, ConfigurationNode configuration) { + super(plugin, configuration); + plugin.webServer.handlers.put("/up/", new ClientUpdateHandler(plugin)); + } + +} diff --git a/src/main/java/org/dynmap/JsonFileClientUpdateComponent.java b/src/main/java/org/dynmap/JsonFileClientUpdateComponent.java new file mode 100644 index 00000000..ef2d4d7f --- /dev/null +++ b/src/main/java/org/dynmap/JsonFileClientUpdateComponent.java @@ -0,0 +1,141 @@ +package org.dynmap; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.util.Iterator; +import java.util.Timer; +import java.util.TimerTask; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.dynmap.web.Json; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import static org.dynmap.JSONUtils.*; + + +public class JsonFileClientUpdateComponent extends ClientUpdateComponent { + protected TimerTask task; + protected Timer timer; + protected long jsonInterval; + protected long lastTimestamp = 0; + protected JSONParser parser = new JSONParser(); + public JsonFileClientUpdateComponent(final DynmapPlugin plugin, ConfigurationNode configuration) { + super(plugin, configuration); + jsonInterval = (long)(configuration.getFloat("interval", 1) * 1000); + task = new TimerTask() { + @Override + public void run() { + writeUpdates(); + } + }; + timer = new Timer(); + timer.scheduleAtFixedRate(task, jsonInterval, jsonInterval); + plugin.events.addListener("buildclientconfiguration", new Event.Listener() { + @Override + public void triggered(JSONObject t) { + s(t, "jsonfile", true); + } + }); + plugin.events.addListener("initialized", new Event.Listener() { + @Override + public void triggered(Object t) { + writeConfiguration(); + } + }); + } + + protected void writeConfiguration() { + File outputFile; + JSONObject clientConfiguration = new JSONObject(); + plugin.events.trigger("buildclientconfiguration", clientConfiguration); + File webpath = new File(plugin.configuration.getString("webpath", "web"), "standalone/dynmap_config.json"); + if (webpath.isAbsolute()) + outputFile = webpath; + else + outputFile = new File(plugin.getDataFolder(), webpath.toString()); + + try { + FileOutputStream fos = new FileOutputStream(outputFile); + fos.write(clientConfiguration.toJSONString().getBytes()); + fos.close(); + } catch (FileNotFoundException ex) { + Log.severe("Exception while writing JSON-configuration-file.", ex); + } catch (IOException ioe) { + Log.severe("Exception while writing JSON-configuration-file.", ioe); + } + } + + protected void writeUpdates() { + long current = System.currentTimeMillis(); + File outputFile; + + //Handles Updates + for (DynmapWorld dynmapWorld : plugin.mapManager.worlds.values()) { + World world = dynmapWorld.world; + current = System.currentTimeMillis(); + + JSONObject update = new JSONObject(); + update.put("timestamp", current); + ClientUpdateEvent clientUpdate = new ClientUpdateEvent(current, dynmapWorld, update); + plugin.events.trigger("buildclientupdate", clientUpdate); + + File webWorldPath = new File(this.configuration.getString("webpath", "web"), "standalone/dynmap_" + world.getName() + ".json"); + if (webWorldPath.isAbsolute()) + outputFile = webWorldPath; + else { + outputFile = new File(plugin.getDataFolder(), webWorldPath.toString()); + } + try { + FileOutputStream fos = new FileOutputStream(outputFile); + fos.write(Json.stringifyJson(update).getBytes()); + fos.close(); + } catch (FileNotFoundException ex) { + Log.severe("Exception while writing JSON-file.", ex); + } catch (IOException ioe) { + Log.severe("Exception while writing JSON-file.", ioe); + } + plugin.events.trigger("clientupdatewritten", clientUpdate); + } + lastTimestamp = System.currentTimeMillis(); + + plugin.events.trigger("clientupdateswritten", null); + } + + protected void handleWebChat() { + File webPath = new File(configuration.getString("webpath", "web")); + if (!webPath.isAbsolute()) { + webPath = new File(plugin.getDataFolder(), webPath.toString()); + } + File webchatFile = new File(webPath, "standalone/dynmap_webchat.json"); + + if (webchatFile.exists() && lastTimestamp != 0) { + JSONArray jsonMsgs = null; + try { + FileReader inputFileReader = new FileReader(webchatFile); + jsonMsgs = (JSONArray) parser.parse(inputFileReader); + inputFileReader.close(); + } catch (IOException ex) { + Log.severe("Exception while reading JSON-file.", ex); + } catch (ParseException ex) { + Log.severe("Exception while parsing JSON-file.", ex); + } + + if (jsonMsgs != null) { + Iterator iter = jsonMsgs.iterator(); + while (iter.hasNext()) { + JSONObject o = (JSONObject) iter.next(); + if (Long.parseLong(String.valueOf(o.get("timestamp"))) >= (lastTimestamp)) { + plugin.webChat(String.valueOf(o.get("name")), String.valueOf(o.get("message"))); + } + } + } + } + } +} diff --git a/src/main/java/org/dynmap/JsonTimerTask.java b/src/main/java/org/dynmap/JsonTimerTask.java deleted file mode 100644 index bc1dd83e..00000000 --- a/src/main/java/org/dynmap/JsonTimerTask.java +++ /dev/null @@ -1,123 +0,0 @@ -package org.dynmap; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.IOException; -import java.util.Iterator; -import java.util.Map; -import java.util.TimerTask; - -import org.bukkit.Location; -import org.bukkit.Server; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.dynmap.web.Json; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; - -class JsonTimerTask extends TimerTask { - private final DynmapPlugin plugin; - private Server server; - private MapManager mapManager; - private ConfigurationNode configuration; - private ConfigurationNode regions; - private static final JSONParser parser = new JSONParser(); - private long lastTimestamp = 0; - - public JsonTimerTask(DynmapPlugin instance, ConfigurationNode config) { - this.plugin = instance; - this.server = this.plugin.getServer(); - this.mapManager = this.plugin.getMapManager(); - this.configuration = config; - } - - public void run() { - long jsonInterval = configuration.getInteger("jsonfile-interval", 1) * 1000; - long current = System.currentTimeMillis(); - File outputFile; - boolean showHealth = configuration.getBoolean("health-in-json", false); - - //Handles Reading WebChat - if (configuration.getNode("web").getBoolean("allowwebchat", false)) { - File webChatPath = new File(this.configuration.getString("webpath", "web"), "standalone/dynmap_webchat.json"); - if (webChatPath.isAbsolute()) - outputFile = webChatPath; - else { - outputFile = new File(plugin.getDataFolder(), webChatPath.toString()); - } - if (webChatPath.exists() && lastTimestamp != 0) { - JSONArray jsonMsgs = null; - try { - FileReader inputFileReader = new FileReader(webChatPath); - jsonMsgs = (JSONArray) parser.parse(inputFileReader); - inputFileReader.close(); - } catch (IOException ex) { - Log.severe("Exception while reading JSON-file.", ex); - } catch (ParseException ex) { - Log.severe("Exception while parsing JSON-file.", ex); - } - - if (jsonMsgs != null) { - Iterator iter = jsonMsgs.iterator(); - while (iter.hasNext()) { - JSONObject o = (JSONObject) iter.next(); - if (Long.parseLong(String.valueOf(o.get("timestamp"))) >= (lastTimestamp)) { - plugin.webChat(String.valueOf(o.get("name")), String.valueOf(o.get("message"))); - } - } - } - } - } - - //Handles Updates - for (DynmapWorld dynmapWorld : plugin.mapManager.worlds.values()) { - World world = dynmapWorld.world; - current = System.currentTimeMillis(); - - Client.Update update = new Client.Update(); - WorldUpdate worldUpdate = new WorldUpdate(dynmapWorld, update); - plugin.events.trigger("buildingupdate", worldUpdate); - update.timestamp = current; - update.servertime = world.getTime() % 24000; - update.hasStorm = world.hasStorm(); - update.isThundering = world.isThundering(); - - Player[] players = plugin.playerList.getVisiblePlayers(); - update.players = new Client.Player[players.length]; - for (int i = 0; i < players.length; i++) { - Player p = players[i]; - Location pl = p.getLocation(); - update.players[i] = new Client.Player(p.getDisplayName(), pl.getWorld().getName(), pl.getX(), pl.getY(), pl.getZ(), showHealth?p.getHealth():-1, - p.getName()); - } - - update.updates = mapManager.getWorldUpdates(world.getName(), current - (jsonInterval + 10000)); - - plugin.events.trigger("buildupdate", worldUpdate); - - File webWorldPath = new File(this.configuration.getString("webpath", "web"), "standalone/dynmap_" + world.getName() + ".json"); - if (webWorldPath.isAbsolute()) - outputFile = webWorldPath; - else { - outputFile = new File(plugin.getDataFolder(), webWorldPath.toString()); - } - try { - FileOutputStream fos = new FileOutputStream(outputFile); - fos.write(Json.stringifyJson(update).getBytes()); - fos.close(); - } catch (FileNotFoundException ex) { - Log.severe("Exception while writing JSON-file.", ex); - } catch (IOException ioe) { - Log.severe("Exception while writing JSON-file.", ioe); - } - plugin.events.trigger("updatewritten", worldUpdate); - } - lastTimestamp = System.currentTimeMillis(); - - plugin.events.trigger("updateswritten", null); - } -} diff --git a/src/main/java/org/dynmap/WorldUpdate.java b/src/main/java/org/dynmap/WorldUpdate.java deleted file mode 100644 index 947bd40d..00000000 --- a/src/main/java/org/dynmap/WorldUpdate.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.dynmap; - -public class WorldUpdate { - public DynmapWorld world; - public Client.Update update; - - public WorldUpdate(DynmapWorld world, Client.Update update) { - this.world = world; - this.update = update; - } -} diff --git a/src/main/java/org/dynmap/regions/RegionsComponent.java b/src/main/java/org/dynmap/regions/RegionsComponent.java index bd21d5d2..823ea7f5 100644 --- a/src/main/java/org/dynmap/regions/RegionsComponent.java +++ b/src/main/java/org/dynmap/regions/RegionsComponent.java @@ -8,11 +8,11 @@ import java.util.Map; import org.bukkit.World; import org.dynmap.ClientComponent; +import org.dynmap.ClientUpdateEvent; import org.dynmap.ConfigurationNode; import org.dynmap.DynmapPlugin; import org.dynmap.Event; import org.dynmap.Log; -import org.dynmap.WorldUpdate; import org.dynmap.web.Json; public class RegionsComponent extends ClientComponent { @@ -27,15 +27,15 @@ public class RegionsComponent extends ClientComponent { // For external webserver. //Parse region file for multi world style if (configuration.getBoolean("useworldpath", false)) { - plugin.events.addListener("updatewritten", new Event.Listener() { + plugin.events.addListener("clientupdatewritten", new Event.Listener() { @Override - public void triggered(WorldUpdate t) { + public void triggered(ClientUpdateEvent t) { World world = t.world.world; parseRegionFile(world.getName() + "/" + configuration.getString("filename", "regions.yml"), configuration.getString("filename", "regions.yml").replace(".", "_" + world.getName() + ".yml")); } }); } else { - plugin.events.addListener("updateswritten", new Event.Listener() { + plugin.events.addListener("clientupdateswritten", new Event.Listener() { @Override public void triggered(Object t) { parseRegionFile(configuration.getString("filename", "regions.yml"), configuration.getString("filename", "regions.yml")); diff --git a/src/main/java/org/dynmap/web/handlers/ClientUpdateHandler.java b/src/main/java/org/dynmap/web/handlers/ClientUpdateHandler.java index 329336d3..950c7859 100644 --- a/src/main/java/org/dynmap/web/handlers/ClientUpdateHandler.java +++ b/src/main/java/org/dynmap/web/handlers/ClientUpdateHandler.java @@ -11,7 +11,9 @@ import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.util.config.Configuration; import org.dynmap.Client; +import org.dynmap.ClientUpdateEvent; import org.dynmap.DynmapPlugin; +import org.dynmap.DynmapWorld; import org.dynmap.MapManager; import org.dynmap.PlayerList; import org.dynmap.web.HttpField; @@ -26,11 +28,9 @@ import static org.dynmap.JSONUtils.*; public class ClientUpdateHandler implements HttpHandler { private DynmapPlugin plugin; - private boolean showHealth; - - public ClientUpdateHandler(DynmapPlugin plugin, boolean showHealth) { + + public ClientUpdateHandler(DynmapPlugin plugin) { this.plugin = plugin; - this.showHealth = showHealth; } Pattern updatePathPattern = Pattern.compile("world/([^/]+)/([0-9]*)"); @@ -48,12 +48,11 @@ public class ClientUpdateHandler implements HttpHandler { String worldName = match.group(1); String timeKey = match.group(2); - World world = plugin.getServer().getWorld(worldName); - if (world == null) { + DynmapWorld dynmapWorld = plugin.mapManager.getWorld(worldName); + if (dynmapWorld == null || dynmapWorld.world == null) { response.status = WorldNotFound; return; } - long current = System.currentTimeMillis(); long since = 0; @@ -65,42 +64,8 @@ public class ClientUpdateHandler implements HttpHandler { } JSONObject u = new JSONObject(); - //plugin.events.trigger("buildclientupdate", update); s(u, "timestamp", current); - s(u, "servertime", world.getTime() % 24000); - s(u, "hasStorm", world.hasStorm()); - s(u, "isThundering", world.isThundering()); - - s(u, "players", new JSONArray()); - Player[] players = plugin.playerList.getVisiblePlayers(); - for(int i=0;i