mirror of
https://github.com/webbukkit/dynmap.git
synced 2024-12-25 10:07:37 +01:00
Added multiworld update support along with client-side support.
This commit is contained in:
parent
5b0171c459
commit
100f3e0590
@ -47,3 +47,12 @@ web:
|
|||||||
- type: KzedMapType
|
- type: KzedMapType
|
||||||
name: cavemap
|
name: cavemap
|
||||||
prefix: ct
|
prefix: ct
|
||||||
|
|
||||||
|
# The name of the world shown when opening Dynmap's page.
|
||||||
|
defaultworld: world
|
||||||
|
|
||||||
|
# The worlds shown in the menu.
|
||||||
|
shownworlds:
|
||||||
|
- world
|
||||||
|
- nether
|
||||||
|
- world_bad
|
||||||
|
@ -66,6 +66,6 @@ public class DynmapPlayerListener extends PlayerListener {
|
|||||||
* Relevant event details
|
* Relevant event details
|
||||||
*/
|
*/
|
||||||
public void onPlayerChat(PlayerChatEvent event) {
|
public void onPlayerChat(PlayerChatEvent event) {
|
||||||
mgr.updateQueue.pushUpdate(new Client.ChatMessage(event.getPlayer().getName(), event.getMessage()));
|
mgr.pushUpdate(new Client.ChatMessage(event.getPlayer().getName(), event.getMessage()));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,14 +21,16 @@ public class MapManager {
|
|||||||
|
|
||||||
private MapType[] mapTypes;
|
private MapType[] mapTypes;
|
||||||
public AsynchronousQueue<MapTile> tileQueue;
|
public AsynchronousQueue<MapTile> tileQueue;
|
||||||
public UpdateQueue updateQueue;
|
|
||||||
|
public Map<String, UpdateQueue> worldUpdateQueues = new HashMap<String, UpdateQueue>();
|
||||||
|
public ArrayList<String> worlds = new ArrayList<String>();
|
||||||
|
|
||||||
public PlayerList playerList;
|
public PlayerList playerList;
|
||||||
|
|
||||||
/* lock for our data structures */
|
/* lock for our data structures */
|
||||||
public static final Object lock = new Object();
|
public static final Object lock = new Object();
|
||||||
|
|
||||||
public MapManager(ConfigurationNode configuration) {
|
public MapManager(ConfigurationNode configuration) {
|
||||||
this.updateQueue = new UpdateQueue();
|
|
||||||
this.tileQueue = new AsynchronousQueue<MapTile>(new Handler<MapTile>() {
|
this.tileQueue = new AsynchronousQueue<MapTile>(new Handler<MapTile>() {
|
||||||
@Override
|
@Override
|
||||||
public void handle(MapTile t) {
|
public void handle(MapTile t) {
|
||||||
@ -81,7 +83,6 @@ public class MapManager {
|
|||||||
if (render(tile)) {
|
if (render(tile)) {
|
||||||
found.remove(tile);
|
found.remove(tile);
|
||||||
rendered.add(tile);
|
rendered.add(tile);
|
||||||
updateQueue.pushUpdate(new Client.Tile(tile.getFilename()));
|
|
||||||
for (MapTile adjTile : map.getAdjecentTiles(tile)) {
|
for (MapTile adjTile : map.getAdjecentTiles(tile)) {
|
||||||
if (!found.contains(adjTile) && !rendered.contains(adjTile)) {
|
if (!found.contains(adjTile) && !rendered.contains(adjTile)) {
|
||||||
found.add(adjTile);
|
found.add(adjTile);
|
||||||
@ -157,7 +158,9 @@ public class MapManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean render(MapTile tile) {
|
public boolean render(MapTile tile) {
|
||||||
return tile.getMap().render(tile, getTileFile(tile));
|
boolean result = tile.getMap().render(tile, getTileFile(tile));
|
||||||
|
pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename()));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -172,4 +175,31 @@ public class MapManager {
|
|||||||
}
|
}
|
||||||
return new File(worldTileDirectory, tile.getFilename());
|
return new File(worldTileDirectory, tile.getFilename());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void pushUpdate(Object update) {
|
||||||
|
for(int i=0;i<worlds.size();i++) {
|
||||||
|
UpdateQueue queue = worldUpdateQueues.get(worlds.get(i));
|
||||||
|
queue.pushUpdate(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pushUpdate(World world, Object update) {
|
||||||
|
pushUpdate(world.getName(), update);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pushUpdate(String world, Object update) {
|
||||||
|
UpdateQueue updateQueue = worldUpdateQueues.get(world);
|
||||||
|
if (updateQueue == null) {
|
||||||
|
worldUpdateQueues.put(world, updateQueue = new UpdateQueue());
|
||||||
|
worlds.add(world);
|
||||||
|
}
|
||||||
|
updateQueue.pushUpdate(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getWorldUpdates(String worldName, long since) {
|
||||||
|
UpdateQueue queue = worldUpdateQueues.get(worldName);
|
||||||
|
if (queue == null)
|
||||||
|
return new Object[0];
|
||||||
|
return queue.getUpdatedObjects(since);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import java.util.HashSet;
|
|||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class PlayerList {
|
public class PlayerList {
|
||||||
@ -68,6 +69,21 @@ public class PlayerList {
|
|||||||
hide(playerName);
|
hide(playerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Clean this up... one day
|
||||||
|
public Player[] getVisiblePlayers(String worldName) {
|
||||||
|
ArrayList<Player> visiblePlayers = new ArrayList<Player>();
|
||||||
|
Player[] onlinePlayers = server.getOnlinePlayers();
|
||||||
|
for (int i = 0; i < onlinePlayers.length; i++) {
|
||||||
|
Player p = onlinePlayers[i];
|
||||||
|
if (p.getWorld().getName().equals(worldName) && !hiddenPlayerNames.contains(p.getName())) {
|
||||||
|
visiblePlayers.add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Player[] result = new Player[visiblePlayers.size()];
|
||||||
|
visiblePlayers.toArray(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public Player[] getVisiblePlayers() {
|
public Player[] getVisiblePlayers() {
|
||||||
ArrayList<Player> visiblePlayers = new ArrayList<Player>();
|
ArrayList<Player> visiblePlayers = new ArrayList<Player>();
|
||||||
Player[] onlinePlayers = server.getOnlinePlayers();
|
Player[] onlinePlayers = server.getOnlinePlayers();
|
||||||
|
@ -11,7 +11,7 @@ public class UpdateQueue {
|
|||||||
|
|
||||||
private static final int maxUpdateAge = 120000;
|
private static final int maxUpdateAge = 120000;
|
||||||
|
|
||||||
public void pushUpdate(Object obj) {
|
public synchronized void pushUpdate(Object obj) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
long deadline = now - maxUpdateAge;
|
long deadline = now - maxUpdateAge;
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
@ -27,7 +27,7 @@ public class UpdateQueue {
|
|||||||
|
|
||||||
private ArrayList<Object> tmpupdates = new ArrayList<Object>();
|
private ArrayList<Object> tmpupdates = new ArrayList<Object>();
|
||||||
|
|
||||||
public Object[] getUpdatedObjects(long since) {
|
public synchronized Object[] getUpdatedObjects(long since) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
long deadline = now - maxUpdateAge;
|
long deadline = now - maxUpdateAge;
|
||||||
Object[] updates;
|
Object[] updates;
|
||||||
|
@ -15,11 +15,9 @@ import java.util.logging.Logger;
|
|||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.dynmap.DynmapChunk;
|
import org.dynmap.DynmapChunk;
|
||||||
import org.dynmap.MapManager;
|
|
||||||
import org.dynmap.MapTile;
|
import org.dynmap.MapTile;
|
||||||
import org.dynmap.MapType;
|
import org.dynmap.MapType;
|
||||||
import org.dynmap.debug.Debug;
|
import org.dynmap.debug.Debug;
|
||||||
import org.dynmap.debug.Debugger;
|
|
||||||
|
|
||||||
public class KzedMap extends MapType {
|
public class KzedMap extends MapType {
|
||||||
protected static final Logger log = Logger.getLogger("Minecraft");
|
protected static final Logger log = Logger.getLogger("Minecraft");
|
||||||
|
@ -2,6 +2,9 @@ package org.dynmap.web.handlers;
|
|||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -24,14 +27,24 @@ public class ClientUpdateHandler implements HttpHandler {
|
|||||||
this.world = world;
|
this.world = world;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pattern updatePathPattern = Pattern.compile("world/([a-zA-Z0-9_]+)/([0-9]*)");
|
||||||
@Override
|
@Override
|
||||||
public void handle(String path, HttpRequest request, HttpResponse response) throws Exception {
|
public void handle(String path, HttpRequest request, HttpResponse response) throws Exception {
|
||||||
|
|
||||||
|
Matcher match = updatePathPattern.matcher(path);
|
||||||
|
|
||||||
|
if (!match.matches())
|
||||||
|
return;
|
||||||
|
|
||||||
|
String worldName = match.group(1);
|
||||||
|
String timeKey = match.group(2);
|
||||||
|
|
||||||
long current = System.currentTimeMillis();
|
long current = System.currentTimeMillis();
|
||||||
long cutoff = 0;
|
long since = 0;
|
||||||
|
|
||||||
if (path.length() > 0) {
|
if (path.length() > 0) {
|
||||||
try {
|
try {
|
||||||
cutoff = Long.parseLong(path);
|
since = Long.parseLong(timeKey);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,14 +54,15 @@ public class ClientUpdateHandler implements HttpHandler {
|
|||||||
update.servertime = world.getTime() % 24000;
|
update.servertime = world.getTime() % 24000;
|
||||||
|
|
||||||
|
|
||||||
Player[] players = playerList.getVisiblePlayers();
|
Player[] players = playerList.getVisiblePlayers(worldName);
|
||||||
update.players = new Client.Player[players.length];
|
update.players = new Client.Player[players.length];
|
||||||
for(int i=0;i<players.length;i++) {
|
for(int i=0;i<players.length;i++) {
|
||||||
Player p = players[i];
|
Player p = players[i];
|
||||||
update.players[i] = new Client.Player(p.getName(), p.getLocation().getX(), p.getLocation().getY(), p.getLocation().getZ());
|
update.players[i] = new Client.Player(p.getName(), p.getLocation().getX(), p.getLocation().getY(), p.getLocation().getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
update.updates = mapManager.updateQueue.getUpdatedObjects(cutoff);
|
update.updates = mapManager.getWorldUpdates(worldName, since);
|
||||||
|
|
||||||
|
|
||||||
byte[] bytes = Json.stringifyJson(update).getBytes();
|
byte[] bytes = Json.stringifyJson(update).getBytes();
|
||||||
|
|
||||||
|
49
web/map.js
49
web/map.js
@ -91,6 +91,7 @@ DynMap.prototype = {
|
|||||||
$.each(me.options.shownmaps, function(index, mapentry) {
|
$.each(me.options.shownmaps, function(index, mapentry) {
|
||||||
me.options.maps[mapentry.name] = maptypes[mapentry.type](mapentry);
|
me.options.maps[mapentry.name] = maptypes[mapentry.type](mapentry);
|
||||||
});
|
});
|
||||||
|
me.world = me.options.defaultworld;
|
||||||
},
|
},
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
@ -131,11 +132,48 @@ DynMap.prototype = {
|
|||||||
.addClass('sidebar')
|
.addClass('sidebar')
|
||||||
.appendTo(container);
|
.appendTo(container);
|
||||||
|
|
||||||
|
// The world list.
|
||||||
|
var worldlist = me.worldlist = $('<div/>')
|
||||||
|
.addClass('worldlist')
|
||||||
|
.appendTo(sidebar);
|
||||||
|
|
||||||
|
$.each(me.options.shownworlds, function(index, name) {
|
||||||
|
var worldButton;
|
||||||
|
$('<div/>')
|
||||||
|
.addClass('worldrow')
|
||||||
|
.append(worldButton = $('<input/>')
|
||||||
|
.addClass('worldbutton')
|
||||||
|
.addClass('world_' + name)
|
||||||
|
.attr({
|
||||||
|
type: 'radio',
|
||||||
|
name: 'world',
|
||||||
|
value: name
|
||||||
|
})
|
||||||
|
.attr('checked', me.options.defaultworld == name ? 'checked' : null)
|
||||||
|
)
|
||||||
|
.append($('<label/>')
|
||||||
|
.attr('for', 'worldbutton_' + name)
|
||||||
|
.text(name)
|
||||||
|
)
|
||||||
|
.click(function() {
|
||||||
|
$('.worldbutton', worldlist).removeAttr('checked');
|
||||||
|
map.setMapTypeId('none');
|
||||||
|
me.world = name;
|
||||||
|
// Another workaround for GMaps not being able to reload tiles.
|
||||||
|
window.setTimeout(function() {
|
||||||
|
map.setMapTypeId(me.options.defaultmap);
|
||||||
|
}, 1);
|
||||||
|
worldButton.attr('checked', 'checked');
|
||||||
|
})
|
||||||
|
.data('world', name)
|
||||||
|
.appendTo(worldlist);
|
||||||
|
});
|
||||||
|
|
||||||
// The map list.
|
// The map list.
|
||||||
var maplist = me.maplist = $('<div/>')
|
var maplist = me.maplist = $('<div/>')
|
||||||
.addClass('maplist')
|
.addClass('maplist')
|
||||||
.appendTo(sidebar);
|
.appendTo(sidebar);
|
||||||
|
|
||||||
$.each(me.options.maps, function(name, mapType){
|
$.each(me.options.maps, function(name, mapType){
|
||||||
mapType.dynmap = me;
|
mapType.dynmap = me;
|
||||||
map.mapTypes.set(name, mapType);
|
map.mapTypes.set(name, mapType);
|
||||||
@ -144,11 +182,12 @@ DynMap.prototype = {
|
|||||||
$('<div/>')
|
$('<div/>')
|
||||||
.addClass('maprow')
|
.addClass('maprow')
|
||||||
.append(mapButton = $('<input/>')
|
.append(mapButton = $('<input/>')
|
||||||
|
.addClass('mapbutton')
|
||||||
.addClass('maptype_' + name)
|
.addClass('maptype_' + name)
|
||||||
.attr({
|
.attr({
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
name: 'map',
|
name: 'map',
|
||||||
id: 'maptypebutton_' + name
|
value: name
|
||||||
})
|
})
|
||||||
.attr('checked', me.options.defaultmap == name ? 'checked' : null)
|
.attr('checked', me.options.defaultmap == name ? 'checked' : null)
|
||||||
)
|
)
|
||||||
@ -199,7 +238,7 @@ DynMap.prototype = {
|
|||||||
// TODO: is there a better place for this?
|
// TODO: is there a better place for this?
|
||||||
this.cleanPopups();
|
this.cleanPopups();
|
||||||
|
|
||||||
$.getJSON(me.options.updateUrl + me.lasttimestamp, function(update) {
|
$.getJSON(me.options.updateUrl + "world/" + me.world + "/" + me.lasttimestamp, function(update) {
|
||||||
me.alertbox.hide();
|
me.alertbox.hide();
|
||||||
|
|
||||||
me.lasttimestamp = update.timestamp;
|
me.lasttimestamp = update.timestamp;
|
||||||
@ -415,9 +454,9 @@ DynMap.prototype = {
|
|||||||
var tile = me.registeredTiles[tileName];
|
var tile = me.registeredTiles[tileName];
|
||||||
|
|
||||||
if(tile) {
|
if(tile) {
|
||||||
return me.options.tileUrl + tileName + '.png?' + tile.lastseen;
|
return me.options.tileUrl + me.world + '/' + tileName + '.png?' + tile.lastseen;
|
||||||
} else {
|
} else {
|
||||||
return me.options.tileUrl + tileName + '.png?0';
|
return me.options.tileUrl + me.world + '/' + tileName + '.png?0';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
registerTile: function(mapType, tileName, tile) {
|
registerTile: function(mapType, tileName, tile) {
|
||||||
|
Loading…
Reference in New Issue
Block a user