mirror of
https://github.com/encounter/dynmap.git
synced 2026-03-30 11:08:39 -07:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 13e829cda0 | |||
| 455b5d3b3e | |||
| 8abf596ba6 | |||
| 1beb4fa466 | |||
| e47b4dc49f | |||
| 3ff0b85ef7 | |||
| 99ae8a8f3b | |||
| 18b36f96fe | |||
| 36d1a7676e | |||
| f14e097c54 | |||
| 4de18ac700 | |||
| 98f03c588e | |||
| 5ee5fee232 | |||
| c2047fe7c4 | |||
| 34093874bc | |||
| 676f6c5a3e | |||
| 9ea9e347ea | |||
| 75efba1425 |
+25
@@ -0,0 +1,25 @@
|
||||
# Eclipse stuff
|
||||
/.classpath
|
||||
/.project
|
||||
/.settings
|
||||
|
||||
# netbeans
|
||||
/nbproject
|
||||
|
||||
# we use maven!
|
||||
/build.xml
|
||||
|
||||
# maven
|
||||
/target
|
||||
|
||||
# vim
|
||||
.*.sw[a-p]
|
||||
|
||||
# various other potential build files
|
||||
/build
|
||||
/bin
|
||||
/dist
|
||||
/manifest.mf
|
||||
|
||||
# Mac filesystem dust
|
||||
/.DS_Store
|
||||
Regular → Executable
+30
-1
@@ -13,4 +13,33 @@ webpath: web
|
||||
webserver-bindaddress: 0.0.0.0
|
||||
|
||||
# The TCP-port the webserver will listen on.
|
||||
webserver-port: 8123
|
||||
webserver-port: 8123
|
||||
|
||||
# The maptypes Dynmap will use to render.
|
||||
maps:
|
||||
- class: org.dynmap.kzedmap.KzedMap
|
||||
renderers:
|
||||
- class: org.dynmap.kzedmap.DefaultTileRenderer
|
||||
prefix: t
|
||||
- class: org.dynmap.kzedmap.CaveTileRenderer
|
||||
prefix: ct
|
||||
|
||||
web:
|
||||
# Interval the browser should poll for updates.
|
||||
updaterate: 2000
|
||||
|
||||
showchatballoons: true
|
||||
showplayerfacesonmap: true
|
||||
showplayerfacesinmenu: true
|
||||
|
||||
# The name of the map shown when opening Dynmap's page (must be in menu).
|
||||
defaultmap: defaultmap
|
||||
|
||||
# The maps shown in the menu.
|
||||
shownmaps:
|
||||
- type: KzedMapType
|
||||
name: defaultmap
|
||||
prefix: t
|
||||
- type: KzedMapType
|
||||
name: cavemap
|
||||
prefix: ct
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.dynmap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.bukkit.event.player.PlayerChatEvent;
|
||||
|
||||
public class ChatQueue {
|
||||
|
||||
public class ChatMessage
|
||||
{
|
||||
public long time;
|
||||
public String playerName;
|
||||
public String message;
|
||||
|
||||
public ChatMessage(PlayerChatEvent event)
|
||||
{
|
||||
time = System.currentTimeMillis();
|
||||
playerName = event.getPlayer().getName();
|
||||
message = event.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/* a list of recent chat message */
|
||||
private LinkedList<ChatMessage> messageQueue;
|
||||
|
||||
/* remember up to this old chat messages (ms) */
|
||||
private static final int maxChatAge = 120000;
|
||||
|
||||
public ChatQueue() {
|
||||
messageQueue = new LinkedList<ChatMessage>();
|
||||
}
|
||||
|
||||
/* put a chat message in the queue */
|
||||
public void pushChatMessage(PlayerChatEvent event)
|
||||
{
|
||||
synchronized(MapManager.lock) {
|
||||
messageQueue.add(new ChatMessage(event));
|
||||
}
|
||||
}
|
||||
|
||||
public ChatMessage[] getChatMessages(long cutoff) {
|
||||
|
||||
ArrayList<ChatMessage> queue = new ArrayList<ChatMessage>();
|
||||
ArrayList<ChatMessage> updateList = new ArrayList<ChatMessage>();
|
||||
queue.addAll(messageQueue);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
long deadline = now - maxChatAge;
|
||||
|
||||
synchronized(MapManager.lock) {
|
||||
|
||||
for (ChatMessage message : queue)
|
||||
{
|
||||
if (message.time < deadline)
|
||||
{
|
||||
messageQueue.remove(message);
|
||||
}
|
||||
else if (message.time >= cutoff)
|
||||
{
|
||||
updateList.add(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
ChatMessage[] messages = new ChatMessage[updateList.size()];
|
||||
updateList.toArray(messages);
|
||||
return messages;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@ public class DynmapPlayerListener extends PlayerListener {
|
||||
@Override
|
||||
public void onPlayerCommand(PlayerChatEvent event) {
|
||||
String[] split = event.getMessage().split(" ");
|
||||
if (split[0].equalsIgnoreCase("/map")) {
|
||||
if (split[0].equalsIgnoreCase("/dynmap")) {
|
||||
if (split.length > 1) {
|
||||
if (split[1].equals("render")) {
|
||||
Player player = event.getPlayer();
|
||||
@@ -38,4 +38,14 @@ public class DynmapPlayerListener extends PlayerListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a player sends a chat message
|
||||
*
|
||||
* @param event Relevant event details
|
||||
*/
|
||||
public void onPlayerChat(PlayerChatEvent event)
|
||||
{
|
||||
mgr.addChatEvent(event);
|
||||
}
|
||||
}
|
||||
@@ -12,19 +12,20 @@ import org.bukkit.plugin.*;
|
||||
import org.bukkit.plugin.java.*;
|
||||
import org.bukkit.util.config.Configuration;
|
||||
import org.dynmap.debug.BukkitPlayerDebugger;
|
||||
import org.dynmap.web.WebServer;
|
||||
|
||||
public class DynmapPlugin extends JavaPlugin {
|
||||
|
||||
protected static final Logger log = Logger.getLogger("Minecraft");
|
||||
|
||||
private WebServer webserver = null;
|
||||
private MapManager mgr = null;
|
||||
private WebServer webServer = null;
|
||||
private MapManager mapManager = null;
|
||||
private PlayerList playerList;
|
||||
|
||||
private BukkitPlayerDebugger debugger = new BukkitPlayerDebugger(this);
|
||||
|
||||
public static File dataRoot;
|
||||
|
||||
|
||||
public DynmapPlugin(PluginLoader pluginLoader, Server instance, PluginDescriptionFile desc, File folder, File plugin, ClassLoader cLoader) {
|
||||
super(pluginLoader, instance, desc, folder, plugin, cLoader);
|
||||
dataRoot = folder;
|
||||
@@ -33,6 +34,14 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
public World getWorld() {
|
||||
return getServer().getWorlds()[0];
|
||||
}
|
||||
|
||||
public MapManager getMapManager() {
|
||||
return mapManager;
|
||||
}
|
||||
|
||||
public WebServer getWebServer() {
|
||||
return webServer;
|
||||
}
|
||||
|
||||
public void onEnable() {
|
||||
Configuration configuration = new Configuration(new File(this.getDataFolder(), "configuration.txt"));
|
||||
@@ -42,11 +51,11 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
playerList = new PlayerList(getServer());
|
||||
playerList.load();
|
||||
|
||||
mgr = new MapManager(getWorld(), debugger, configuration);
|
||||
mgr.startManager();
|
||||
mapManager = new MapManager(getWorld(), debugger, configuration);
|
||||
mapManager.startManager();
|
||||
|
||||
try {
|
||||
webserver = new WebServer(mgr, getServer(), playerList, debugger, configuration);
|
||||
webServer = new WebServer(mapManager, getWorld(), playerList, debugger, configuration);
|
||||
} catch(IOException e) {
|
||||
log.info("position failed to start WebServer (IOException)");
|
||||
}
|
||||
@@ -55,21 +64,22 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
}
|
||||
|
||||
public void onDisable() {
|
||||
mgr.stopManager();
|
||||
mapManager.stopManager();
|
||||
|
||||
if(webserver != null) {
|
||||
webserver.shutdown();
|
||||
webserver = null;
|
||||
if(webServer != null) {
|
||||
webServer.shutdown();
|
||||
webServer = null;
|
||||
}
|
||||
debugger.disable();
|
||||
}
|
||||
|
||||
public void registerEvents() {
|
||||
BlockListener blockListener = new DynmapBlockListener(mgr);
|
||||
BlockListener blockListener = new DynmapBlockListener(mapManager);
|
||||
getServer().getPluginManager().registerEvent(Event.Type.BLOCK_PLACED, blockListener, Priority.Normal, this);
|
||||
getServer().getPluginManager().registerEvent(Event.Type.BLOCK_DAMAGED, blockListener, Priority.Normal, this);
|
||||
|
||||
getServer().getPluginManager().registerEvent(Event.Type.PLAYER_COMMAND, new DynmapPlayerListener(mgr, playerList), Priority.Normal, this);
|
||||
getServer().getPluginManager().registerEvent(Event.Type.PLAYER_COMMAND, new DynmapPlayerListener(mapManager, playerList), Priority.Normal, this);
|
||||
getServer().getPluginManager().registerEvent(Event.Type.PLAYER_CHAT, new DynmapPlayerListener(mapManager, playerList), Priority.Normal, this);
|
||||
//getServer().getPluginManager().registerEvent(Event.Type.BLOCK_DESTROYED, listener, Priority.Normal, this);
|
||||
/* etc.getLoader().addListener(PluginLoader.Hook.COMMAND, listener, this, PluginListener.Priority.MEDIUM);
|
||||
etc.getLoader().addListener(PluginLoader.Hook.BLOCK_CREATED, listener, this, PluginListener.Priority.MEDIUM);
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
package org.dynmap;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.player.PlayerChatEvent;
|
||||
import org.bukkit.util.config.ConfigurationNode;
|
||||
import org.dynmap.debug.Debugger;
|
||||
import org.dynmap.kzedmap.KzedMap;
|
||||
|
||||
public class MapManager extends Thread {
|
||||
protected static final Logger log = Logger.getLogger("Minecraft");
|
||||
|
||||
private World world;
|
||||
private Debugger debugger;
|
||||
private MapType map;
|
||||
private MapType[] maps;
|
||||
public StaleQueue staleQueue;
|
||||
public ChatQueue chatQueue;
|
||||
public PlayerList playerList;
|
||||
|
||||
/* lock for our data structures */
|
||||
@@ -44,20 +49,50 @@ public class MapManager extends Thread {
|
||||
debugger.debug(msg);
|
||||
}
|
||||
|
||||
private static File combinePaths(File parent, String path) { return combinePaths(parent, new File(path)); }
|
||||
|
||||
private static File combinePaths(File parent, File path) {
|
||||
if (path.isAbsolute()) return path;
|
||||
return new File(parent, path.getPath());
|
||||
}
|
||||
|
||||
public MapManager(World world, Debugger debugger, ConfigurationNode configuration)
|
||||
{
|
||||
this.world = world;
|
||||
this.debugger = debugger;
|
||||
this.staleQueue = new StaleQueue();
|
||||
this.chatQueue = new ChatQueue();
|
||||
|
||||
tileDirectory = new File(DynmapPlugin.dataRoot, configuration.getString("tilespath", "web/tiles"));
|
||||
webDirectory = new File(DynmapPlugin.dataRoot, configuration.getString("webpath", "web"));
|
||||
tileDirectory = combinePaths(DynmapPlugin.dataRoot, configuration.getString("tilespath", "web/tiles"));
|
||||
webDirectory = combinePaths(DynmapPlugin.dataRoot, configuration.getString("webpath", "web"));
|
||||
renderWait = (int)(configuration.getDouble("renderinterval", 0.5) * 1000);
|
||||
|
||||
if (!tileDirectory.isDirectory())
|
||||
tileDirectory.mkdirs();
|
||||
|
||||
map = new KzedMap(this, world, debugger, configuration);
|
||||
maps = loadMapTypes(configuration);
|
||||
}
|
||||
|
||||
private MapType[] loadMapTypes(ConfigurationNode configuration) {
|
||||
List<?> configuredMaps = (List<?>)configuration.getProperty("maps");
|
||||
ArrayList<MapType> mapTypes = new ArrayList<MapType>();
|
||||
for(Object configuredMapObj : configuredMaps) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> configuredMap = (Map<String, Object>)configuredMapObj;
|
||||
String typeName = (String)configuredMap.get("class");
|
||||
log.info("Loading map '" + typeName.toString() + "'...");
|
||||
Class<?> mapTypeClass = Class.forName(typeName);
|
||||
Constructor<?> constructor = mapTypeClass.getConstructor(MapManager.class, World.class, Debugger.class, Map.class);
|
||||
MapType mapType = (MapType)constructor.newInstance(this, world, debugger, configuredMap);
|
||||
mapTypes.add(mapType);
|
||||
} catch (Exception e) {
|
||||
debugger.error("Error loading map", e);
|
||||
}
|
||||
}
|
||||
MapType[] result = new MapType[mapTypes.size()];
|
||||
mapTypes.toArray(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* initialize and start map manager */
|
||||
@@ -132,11 +167,18 @@ public class MapManager extends Thread {
|
||||
}
|
||||
|
||||
public void touch(int x, int y, int z) {
|
||||
map.touch(new Location(world, x, y, z));
|
||||
for (int i = 0; i < maps.length; i++) {
|
||||
maps[i].touch(new Location(world, x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
public void invalidateTile(MapTile tile) {
|
||||
debugger.debug("invalidating tile " + tile.getName());
|
||||
staleQueue.pushStaleTile(tile);
|
||||
}
|
||||
|
||||
public void addChatEvent(PlayerChatEvent event)
|
||||
{
|
||||
chatQueue.pushChatMessage(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ public class BukkitPlayerDebugger implements Debugger {
|
||||
public synchronized void enable() {
|
||||
plugin.getServer().getPluginManager().registerEvent(Event.Type.PLAYER_COMMAND, new CommandListener(), Priority.Normal, plugin);
|
||||
plugin.getServer().getPluginManager().registerEvent(Event.Type.PLAYER_QUIT, new CommandListener(), Priority.Normal, plugin);
|
||||
log.info("Debugger enabled, use: " + debugCommand);
|
||||
}
|
||||
|
||||
public synchronized void disable() {
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package org.dynmap.kzedmap;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import java.util.Map;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.util.config.ConfigurationNode;
|
||||
import org.dynmap.debug.Debugger;
|
||||
|
||||
public class CaveTileRenderer extends DefaultTileRenderer {
|
||||
|
||||
public CaveTileRenderer(String name, Debugger debugger, ConfigurationNode configuration) {
|
||||
super(name, debugger, configuration);
|
||||
public CaveTileRenderer(Debugger debugger, Map<String, Object> configuration) {
|
||||
super(debugger, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,11 +5,11 @@ import java.awt.image.BufferedImage;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.util.config.ConfigurationNode;
|
||||
import org.dynmap.debug.Debugger;
|
||||
|
||||
public class DefaultTileRenderer implements MapTileRenderer {
|
||||
@@ -20,9 +20,9 @@ public class DefaultTileRenderer implements MapTileRenderer {
|
||||
return name;
|
||||
}
|
||||
|
||||
public DefaultTileRenderer(String name, Debugger debugger, ConfigurationNode configuration) {
|
||||
this.name = name;
|
||||
public DefaultTileRenderer(Debugger debugger, Map<String, Object> configuration) {
|
||||
this.debugger = debugger;
|
||||
name = (String)configuration.get("prefix");
|
||||
}
|
||||
|
||||
public void render(KzedMapTile tile, String path) {
|
||||
|
||||
@@ -4,18 +4,24 @@ import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.util.config.ConfigurationNode;
|
||||
import org.dynmap.MapType;
|
||||
import org.dynmap.MapManager;
|
||||
import org.dynmap.MapTile;
|
||||
import org.dynmap.MapType;
|
||||
import org.dynmap.debug.Debugger;
|
||||
|
||||
public class KzedMap extends MapType {
|
||||
protected static final Logger log = Logger.getLogger("Minecraft");
|
||||
|
||||
/* dimensions of a map tile */
|
||||
public static final int tileWidth = 128;
|
||||
public static final int tileHeight = 128;
|
||||
@@ -34,18 +40,38 @@ public class KzedMap extends MapType {
|
||||
MapTileRenderer[] renderers;
|
||||
ZoomedTileRenderer zoomrenderer;
|
||||
|
||||
public KzedMap(MapManager manager, World world, Debugger debugger, ConfigurationNode configuration) {
|
||||
public KzedMap(MapManager manager, World world, Debugger debugger, Map<String, Object> configuration) {
|
||||
super(manager, world, debugger);
|
||||
if (colors == null) {
|
||||
colors = loadColorSet("colors.txt");
|
||||
}
|
||||
renderers = new MapTileRenderer[] {
|
||||
new DefaultTileRenderer("t", debugger, configuration),
|
||||
new CaveTileRenderer("ct", debugger, configuration),
|
||||
};
|
||||
|
||||
renderers = loadRenderers(configuration);
|
||||
zoomrenderer = new ZoomedTileRenderer(debugger, configuration);
|
||||
}
|
||||
|
||||
private MapTileRenderer[] loadRenderers(Map<String, Object> configuration) {
|
||||
List<?> configuredRenderers = (List<?>)configuration.get("renderers");
|
||||
ArrayList<MapTileRenderer> renderers = new ArrayList<MapTileRenderer>();
|
||||
for(Object configuredRendererObj : configuredRenderers) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> configuredRenderer = (Map<String, Object>)configuredRendererObj;
|
||||
String typeName = (String)configuredRenderer.get("class");
|
||||
log.info("Loading renderer '" + typeName.toString() + "'...");
|
||||
Class<?> mapTypeClass = Class.forName(typeName);
|
||||
Constructor<?> constructor = mapTypeClass.getConstructor(Debugger.class, Map.class);
|
||||
MapTileRenderer mapTileRenderer = (MapTileRenderer)constructor.newInstance(getDebugger(), configuredRenderer);
|
||||
renderers.add(mapTileRenderer);
|
||||
} catch (Exception e) {
|
||||
getDebugger().error("Error loading renderer", e);
|
||||
}
|
||||
}
|
||||
MapTileRenderer[] result = new MapTileRenderer[renderers.size()];
|
||||
renderers.toArray(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touch(Location l) {
|
||||
int x = l.getBlockX();
|
||||
|
||||
@@ -5,16 +5,14 @@ import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.bukkit.util.config.ConfigurationNode;
|
||||
import org.dynmap.debug.Debugger;
|
||||
|
||||
public class ZoomedTileRenderer {
|
||||
protected Debugger debugger;
|
||||
|
||||
public ZoomedTileRenderer(Debugger debugger, ConfigurationNode configuration) {
|
||||
public ZoomedTileRenderer(Debugger debugger, Map<String, Object> configuration) {
|
||||
this.debugger = debugger;
|
||||
}
|
||||
|
||||
|
||||
+11
-7
@@ -1,4 +1,4 @@
|
||||
package org.dynmap;
|
||||
package org.dynmap.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
@@ -6,8 +6,10 @@ import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.util.config.ConfigurationNode;
|
||||
import org.dynmap.MapManager;
|
||||
import org.dynmap.PlayerList;
|
||||
import org.dynmap.debug.Debugger;
|
||||
|
||||
public class WebServer extends Thread {
|
||||
@@ -21,14 +23,16 @@ public class WebServer extends Thread {
|
||||
private boolean running = false;
|
||||
|
||||
private MapManager mgr;
|
||||
private Server server;
|
||||
private World world;
|
||||
private PlayerList playerList;
|
||||
private ConfigurationNode configuration;
|
||||
|
||||
public WebServer(MapManager mgr, Server server, PlayerList playerList, Debugger debugger, ConfigurationNode configuration) throws IOException
|
||||
public WebServer(MapManager mgr, World world, PlayerList playerList, Debugger debugger, ConfigurationNode configuration) throws IOException
|
||||
{
|
||||
this.mgr = mgr;
|
||||
this.server = server;
|
||||
this.world = world;
|
||||
this.playerList = playerList;
|
||||
this.configuration = configuration;
|
||||
this.debugger = debugger;
|
||||
|
||||
String bindAddress = configuration.getString("webserver-bindaddress", "0.0.0.0");
|
||||
@@ -37,7 +41,7 @@ public class WebServer extends Thread {
|
||||
sock = new ServerSocket(port, 5, bindAddress.equals("0.0.0.0") ? null : InetAddress.getByName(bindAddress));
|
||||
running = true;
|
||||
start();
|
||||
debugger.debug("WebServer started on " + bindAddress + ":" + port);
|
||||
log.info("Dynmap WebServer started on " + bindAddress + ":" + port);
|
||||
}
|
||||
|
||||
public void run()
|
||||
@@ -46,7 +50,7 @@ public class WebServer extends Thread {
|
||||
while (running) {
|
||||
try {
|
||||
Socket socket = sock.accept();
|
||||
WebServerRequest requestThread = new WebServerRequest(socket, mgr, server, playerList, debugger);
|
||||
WebServerRequest requestThread = new WebServerRequest(socket, mgr, world, playerList, configuration, debugger);
|
||||
requestThread.start();
|
||||
}
|
||||
catch (IOException e) {
|
||||
+89
-20
@@ -1,4 +1,4 @@
|
||||
package org.dynmap;
|
||||
package org.dynmap.web;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
@@ -8,13 +8,20 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.config.ConfigurationNode;
|
||||
import org.dynmap.ChatQueue;
|
||||
import org.dynmap.MapManager;
|
||||
import org.dynmap.PlayerList;
|
||||
import org.dynmap.TileUpdate;
|
||||
import org.dynmap.debug.Debugger;
|
||||
|
||||
public class WebServerRequest extends Thread {
|
||||
@@ -23,16 +30,18 @@ public class WebServerRequest extends Thread {
|
||||
private Debugger debugger;
|
||||
private Socket socket;
|
||||
private MapManager mgr;
|
||||
private Server server;
|
||||
private World world;
|
||||
private PlayerList playerList;
|
||||
private ConfigurationNode configuration;
|
||||
|
||||
public WebServerRequest(Socket socket, MapManager mgr, Server server, PlayerList playerList, Debugger debugger)
|
||||
public WebServerRequest(Socket socket, MapManager mgr, World world, PlayerList playerList, ConfigurationNode configuration, Debugger debugger)
|
||||
{
|
||||
this.debugger = debugger;
|
||||
this.socket = socket;
|
||||
this.mgr = mgr;
|
||||
this.server = server;
|
||||
this.world = world;
|
||||
this.playerList = playerList;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
private static void writeHttpHeader(BufferedOutputStream out, int statusCode, String statusText) throws IOException {
|
||||
@@ -57,11 +66,12 @@ public class WebServerRequest extends Thread {
|
||||
|
||||
public void run()
|
||||
{
|
||||
InputStream reader = null;
|
||||
BufferedReader in = null;
|
||||
BufferedOutputStream out = null;
|
||||
try {
|
||||
socket.setSoTimeout(30000);
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());
|
||||
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
out = new BufferedOutputStream(socket.getOutputStream());
|
||||
|
||||
String request = in.readLine();
|
||||
if (request == null || !request.startsWith("GET ") || !(request.endsWith(" HTTP/1.0") || request.endsWith("HTTP/1.1"))) {
|
||||
@@ -73,7 +83,9 @@ public class WebServerRequest extends Thread {
|
||||
|
||||
String path = request.substring(4, request.length() - 9);
|
||||
debugger.debug("request: " + path);
|
||||
if (path.startsWith("/up/")) {
|
||||
if (path.equals("/up/configuration")) {
|
||||
handleConfiguration(out);
|
||||
} else if (path.startsWith("/up/")) {
|
||||
handleUp(out, path.substring(3));
|
||||
} else if (path.startsWith("/tiles/")) {
|
||||
handleMapToDirectory(out, path.substring(6), mgr.tileDirectory);
|
||||
@@ -84,20 +96,73 @@ public class WebServerRequest extends Thread {
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
}
|
||||
catch (Exception anye) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
if (out != null) { try { out.close(); } catch (Exception anye) { } }
|
||||
if (in != null) { try { in.close(); } catch (Exception anye) { } }
|
||||
}
|
||||
catch(Exception ex) {
|
||||
if (out != null) { try { out.close(); } catch (Exception anye) { } }
|
||||
if (in != null) { try { in.close(); } catch (Exception anye) { } }
|
||||
debugger.error("Exception on WebRequest-thread: " + ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public String stringifyJson(Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
} else if (o instanceof Boolean) {
|
||||
return ((Boolean)o) ? "true" : "false";
|
||||
} else if (o instanceof String) {
|
||||
return "\"" + o + "\"";
|
||||
} else if (o instanceof Integer || o instanceof Long || o instanceof Float || o instanceof Double) {
|
||||
return o.toString();
|
||||
} else if (o instanceof LinkedHashMap<?, ?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
LinkedHashMap<String, Object> m = (LinkedHashMap<String, Object>)o;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{");
|
||||
boolean first = true;
|
||||
for (String key : m.keySet()) {
|
||||
if (first) first = false;
|
||||
else sb.append(",");
|
||||
|
||||
sb.append(stringifyJson(key));
|
||||
sb.append(": ");
|
||||
sb.append(stringifyJson(m.get(key)));
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
} else if (o instanceof ArrayList<?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<Object> l = (ArrayList<Object>)o;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int count = 0;
|
||||
for(int i=0;i<l.size();i++) {
|
||||
sb.append(count++ == 0 ? "[" : ",");
|
||||
sb.append(stringifyJson(l.get(i)));
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
} else {
|
||||
return "undefined";
|
||||
}
|
||||
}
|
||||
|
||||
public void handleConfiguration(BufferedOutputStream out) throws IOException {
|
||||
|
||||
String s = stringifyJson(configuration.getProperty("web"));
|
||||
|
||||
byte[] bytes = s.getBytes();
|
||||
String dateStr = new Date().toString();
|
||||
writeHttpHeader(out, 200, "OK");
|
||||
writeHeaderField(out, "Date", dateStr);
|
||||
writeHeaderField(out, "Content-Type", "text/plain");
|
||||
writeHeaderField(out, "Expires", "Thu, 01 Dec 1994 16:00:00 GMT");
|
||||
writeHeaderField(out, "Last-modified", dateStr);
|
||||
writeHeaderField(out, "Content-Length", Integer.toString(bytes.length));
|
||||
writeEndOfHeaders(out);
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
public void handleUp(BufferedOutputStream out, String path) throws IOException {
|
||||
int current = (int) (System.currentTimeMillis() / 1000);
|
||||
long cutoff = 0;
|
||||
@@ -110,8 +175,7 @@ public class WebServerRequest extends Thread {
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
long relativeTime = server.getTime() % 24000;
|
||||
long relativeTime = world.getTime() % 24000;
|
||||
sb.append(current + " " + relativeTime + "\n");
|
||||
|
||||
Player[] players = playerList.getVisiblePlayers();
|
||||
@@ -123,8 +187,13 @@ public class WebServerRequest extends Thread {
|
||||
for(TileUpdate tu : tileUpdates) {
|
||||
sb.append("tile " + tu.tile.getName() + "\n");
|
||||
}
|
||||
|
||||
ChatQueue.ChatMessage[] messages = mgr.chatQueue.getChatMessages(cutoff);
|
||||
for(ChatQueue.ChatMessage cu : messages) {
|
||||
sb.append("chat " + cu.playerName + " " + cu.message + "\n");
|
||||
}
|
||||
|
||||
debugger.debug("Sending " + players.length + " players and " + tileUpdates.length + " tile-updates. " + path + ";" + cutoff);
|
||||
debugger.debug("Sending " + players.length + " players, " + tileUpdates.length + " tile-updates, and " + messages.length + " chats. "+ path + ";" + cutoff);
|
||||
|
||||
byte[] bytes = sb.toString().getBytes();
|
||||
|
||||
+1
-10
@@ -1,16 +1,7 @@
|
||||
var config = {
|
||||
tileUrl: 'tiles/',
|
||||
updateUrl: 'up/', // For Apache and lighttpd
|
||||
// updateUrl: 'up/default.aspx?lasttimestamp=', // For IIS
|
||||
updateRate: 2000, // Seconds the map should poll for updates. (Seconds) * 1000. The default is 2000 (every 2 seconds).
|
||||
showPortraitsOnMap: true,
|
||||
showPortraitsInPlayerList: true,
|
||||
showPlayerNameOnMap: false,
|
||||
defaultMap: 'defaultmap',
|
||||
maps: {
|
||||
'defaultmap': new DefaultMapType(),
|
||||
'cavemap': new CaveMapType()
|
||||
},
|
||||
// updateUrl: 'up.aspx?path=', // For IIS
|
||||
tileWidth: 128,
|
||||
tileHeight: 128
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
+2
-16
@@ -26,7 +26,7 @@ KzedProjection.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function KzedMapType() {}
|
||||
function KzedMapType(configuration) { $.extend(this, configuration); }
|
||||
KzedMapType.prototype = $.extend(new DynMapType(), {
|
||||
constructor: KzedMapType,
|
||||
projection: new KzedProjection(),
|
||||
@@ -113,18 +113,4 @@ KzedMapType.prototype = $.extend(new DynMapType(), {
|
||||
}
|
||||
return tile.get(0);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function DefaultMapType(){}
|
||||
DefaultMapType.prototype = $.extend(new KzedMapType(), {
|
||||
prefix: 't'
|
||||
});
|
||||
|
||||
|
||||
|
||||
function CaveMapType(){}
|
||||
CaveMapType.prototype = $.extend(new KzedMapType(), {
|
||||
prefix: 'ct'
|
||||
});
|
||||
|
||||
});
|
||||
+112
-21
@@ -68,15 +68,29 @@ MinecraftClock.prototype = {
|
||||
};
|
||||
|
||||
function DynMap(options) {
|
||||
this.options = options;
|
||||
this.initialize();
|
||||
var me = this;
|
||||
me.options = options;
|
||||
$.getJSON(me.options.updateUrl + 'configuration', function(configuration) {
|
||||
me.configure(configuration);
|
||||
me.initialize();
|
||||
})
|
||||
}
|
||||
DynMap.prototype = {
|
||||
registeredTiles: new Array(),
|
||||
clock: null,
|
||||
markers: new Array(),
|
||||
chatPopups: new Array(),
|
||||
lasttimestamp: '0',
|
||||
followingPlayer: '',
|
||||
configure: function(configuration) {
|
||||
var me = this;
|
||||
$.extend(me.options, configuration);
|
||||
if (!me.options.maps) me.options.maps = {};
|
||||
$.each(me.options.shownmaps, function(index, mapentry) {
|
||||
var mapconstructor = eval(mapentry.type);
|
||||
me.options.maps[mapentry.name] = new mapconstructor(mapentry);
|
||||
});
|
||||
},
|
||||
initialize: function() {
|
||||
var me = this;
|
||||
|
||||
@@ -97,7 +111,7 @@ DynMap.prototype = {
|
||||
scaleControl: false,
|
||||
mapTypeControl: false,
|
||||
streetViewControl: false,
|
||||
backgroundColor: '#000'
|
||||
backgroundColor: 'none'
|
||||
});
|
||||
|
||||
google.maps.event.addListener(map, 'dragstart', function(mEvent) {
|
||||
@@ -135,7 +149,7 @@ DynMap.prototype = {
|
||||
name: 'map',
|
||||
id: 'maptypebutton_' + name
|
||||
})
|
||||
.attr('checked', me.options.defaultMap == name ? 'checked' : null)
|
||||
.attr('checked', me.options.defaultmap == name ? 'checked' : null)
|
||||
)
|
||||
.append($('<label/>')
|
||||
.attr('for', 'maptypebutton_' + name)
|
||||
@@ -149,7 +163,7 @@ DynMap.prototype = {
|
||||
.data('maptype', mapType)
|
||||
.appendTo(maplist);
|
||||
});
|
||||
map.setMapTypeId(me.options.defaultMap);
|
||||
map.setMapTypeId(me.options.defaultmap);
|
||||
|
||||
// The Player List
|
||||
var playerlist = me.playerlist = $('<div/>')
|
||||
@@ -176,10 +190,14 @@ DynMap.prototype = {
|
||||
.addClass('alertbox')
|
||||
.appendTo(container);
|
||||
|
||||
setTimeout(function() { me.update(); }, me.options.updateRate);
|
||||
setTimeout(function() { me.update(); }, me.options.updaterate);
|
||||
},
|
||||
update: function() {
|
||||
var me = this;
|
||||
|
||||
// TODO: is there a better place for this?
|
||||
this.cleanPopups();
|
||||
|
||||
$.ajax({
|
||||
url: me.options.updateUrl + me.lasttimestamp,
|
||||
success: function(res) {
|
||||
@@ -210,7 +228,23 @@ DynMap.prototype = {
|
||||
tile: function() {
|
||||
me.onTileUpdated(row.name);
|
||||
}
|
||||
}, function() {
|
||||
, chat: function() {
|
||||
if (!me.options.showchatballoons)
|
||||
return;
|
||||
var chats = line.split(' ');
|
||||
var message = '';
|
||||
for (var chatIndex = 2; chatIndex < chats.length; chatIndex++)
|
||||
{
|
||||
if (chatIndex > 2) message = message + " ";
|
||||
message = message + chats[chatIndex];
|
||||
}
|
||||
if (message.length > 0)
|
||||
{
|
||||
me.onPlayerChat(row.name, message);
|
||||
}
|
||||
}
|
||||
},
|
||||
function() {
|
||||
var mi = {
|
||||
id: row.type + '_' + row.name,
|
||||
text: row.name,
|
||||
@@ -234,16 +268,70 @@ DynMap.prototype = {
|
||||
delete me.markers[m];
|
||||
}
|
||||
}
|
||||
setTimeout(function() { me.update(); }, me.options.updateRate);
|
||||
setTimeout(function() { me.update(); }, me.options.updaterate);
|
||||
},
|
||||
error: function(request, statusText, ex) {
|
||||
me.alertbox
|
||||
.text('Could not update map')
|
||||
.show();
|
||||
setTimeout(function() { me.update(); }, me.options.updateRate);
|
||||
setTimeout(function() { me.update(); }, me.options.updaterate);
|
||||
}
|
||||
});
|
||||
},
|
||||
cleanPopups: function() {
|
||||
var POPUP_LIFE = 8000;
|
||||
var d = new Date();
|
||||
var now = d.getTime();
|
||||
for (var popupIndex in this.chatPopups)
|
||||
{
|
||||
var popup = this.chatPopups[popupIndex];
|
||||
if (now - popup.popupTime > POPUP_LIFE)
|
||||
{
|
||||
popup.infoWindow.close();
|
||||
popup.infoWindow = null;
|
||||
delete this.chatPopups[popupIndex];
|
||||
}
|
||||
}
|
||||
},
|
||||
onPlayerChat: function(playerName, message) {
|
||||
var me = this;
|
||||
var markers = me.markers;
|
||||
var chatPopups = this.chatPopups;
|
||||
var map = me.map;
|
||||
var mid = "player_" + playerName;
|
||||
var playerMarker = markers[mid];
|
||||
if (playerMarker)
|
||||
{
|
||||
var popup = chatPopups[playerName];
|
||||
if (!popup)
|
||||
popup = { lines: [ message ] };
|
||||
else
|
||||
popup.lines[popup.lines.length] = message;
|
||||
|
||||
var MAX_LINES = 5;
|
||||
if (popup.lines.length > MAX_LINES)
|
||||
{
|
||||
popup.lines = popup.lines.slice(1);
|
||||
}
|
||||
htmlMessage = '<div id="content"><b>' + playerName + "</b><br/><br/>"
|
||||
for (var line in popup.lines)
|
||||
{
|
||||
htmlMessage = htmlMessage + popup.lines[line] + "<br/>";
|
||||
}
|
||||
htmlMessage = htmlMessage + "</div>"
|
||||
var now = new Date();
|
||||
popup.popupTime = now.getTime();
|
||||
if (!popup.infoWindow) {
|
||||
popup.infoWindow = new google.maps.InfoWindow({
|
||||
content: htmlMessage
|
||||
});
|
||||
} else {
|
||||
popup.infoWindow.setContent(htmlMessage);
|
||||
}
|
||||
popup.infoWindow.open(map, playerMarker);
|
||||
this.chatPopups[playerName] = popup;
|
||||
}
|
||||
},
|
||||
onTileUpdated: function(tileName) {
|
||||
var me = this;
|
||||
var tile = this.registeredTiles[tileName];
|
||||
@@ -281,13 +369,14 @@ DynMap.prototype = {
|
||||
.append($('<span/>')
|
||||
.addClass('playerName')
|
||||
.text(mi.text))
|
||||
|
||||
getMinecraftHead(mi.text, 32, function(head) {
|
||||
$(head)
|
||||
.addClass('playerIcon')
|
||||
.prependTo(div);
|
||||
playerImage.remove();
|
||||
});
|
||||
if (me.options.showplayerfacesonmap) {
|
||||
getMinecraftHead(mi.text, 32, function(head) {
|
||||
$(head)
|
||||
.addClass('playerIcon')
|
||||
.prependTo(div);
|
||||
playerImage.remove();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
var marker = new CustomMarker(mi.position, map, contentfun, mi);
|
||||
@@ -316,11 +405,13 @@ DynMap.prototype = {
|
||||
.click(function(e) { map.panTo(markers[mi.id].getPosition()); })
|
||||
);
|
||||
|
||||
getMinecraftHead(mi.text, 16, function(head) {
|
||||
marker.playerRow.icon = $(head)
|
||||
.addClass('playerIcon')
|
||||
.appendTo(marker.playerIconContainer);
|
||||
});
|
||||
if (me.options.showplayerfacesinmenu) {
|
||||
getMinecraftHead(mi.text, 16, function(head) {
|
||||
marker.playerRow.icon = $(head)
|
||||
.addClass('playerIcon')
|
||||
.appendTo(marker.playerIconContainer);
|
||||
});
|
||||
}
|
||||
|
||||
me.playerlist.append(marker.playerRow);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ body { height: 100%; margin: 0px; padding: 0px ; background-color: #000; }
|
||||
|
||||
.map {
|
||||
width: 100%; height: 100%;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
|
||||
+15
-15
@@ -1,16 +1,16 @@
|
||||
<%@ Page Language="C#" %>
|
||||
<script runat="server" language="C#">
|
||||
public void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
string path = Request.Params["path"];
|
||||
System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create("http://localhost:8123/" + path);
|
||||
System.Net.WebResponse response = request.GetResponse();
|
||||
System.IO.Stream responseStream = response.GetResponseStream();
|
||||
System.IO.StreamReader reader = new System.IO.StreamReader(responseStream);
|
||||
Response.ContentType = response.ContentType;
|
||||
Response.Write(reader.ReadToEnd());
|
||||
reader.Close();
|
||||
responseStream.Close();
|
||||
response.Close();
|
||||
}
|
||||
<%@ Page Language="C#" %>
|
||||
<script runat="server" language="C#">
|
||||
public void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
string path = Request.Params["path"];
|
||||
System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create("http://localhost:8123/up/" + path);
|
||||
System.Net.WebResponse response = request.GetResponse();
|
||||
System.IO.Stream responseStream = response.GetResponseStream();
|
||||
System.IO.StreamReader reader = new System.IO.StreamReader(responseStream);
|
||||
Response.ContentType = response.ContentType;
|
||||
Response.Write(reader.ReadToEnd());
|
||||
reader.Close();
|
||||
responseStream.Close();
|
||||
response.Close();
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user