Index: /binary-improvements/webserver/js/index.js
===================================================================
--- /binary-improvements/webserver/js/index.js	(revision 185)
+++ /binary-improvements/webserver/js/index.js	(revision 186)
@@ -14,466 +14,517 @@
 
 
-// ===============================================================================================
-// 7dtd coordinate transformations
-
-SDTD_Projection = {
-	project: function (latlng) {
-		return new L.Point(latlng.lng / 16, latlng.lat / 16);
-	},
-
-	unproject: function (point) {
-		return new L.LatLng(point.y * 16, point.x * 16);
-	}
-};
-
-SDTD_CRS = L.extend({}, L.CRS.Simple, {
-	projection: SDTD_Projection,
-	transformation: new L.Transformation(1, 0, -1, 0),
-
-	scale: function (zoom) {
-		return Math.pow(2, zoom);
-	}
+function initMap() {
+	// ===============================================================================================
+	// 7dtd coordinate transformations
+
+	SDTD_Projection = {
+		project: function (latlng) {
+			return new L.Point(
+				(latlng.lat) / Math.pow(2, MAXZOOM),
+				(latlng.lng) / Math.pow(2, MAXZOOM) );
+		},
+		
+		unproject: function (point) {
+			return new L.LatLng(
+				point.x * Math.pow(2, MAXZOOM),
+				point.y * Math.pow(2, MAXZOOM) );
+		}
+	};
+
+	SDTD_CRS = L.extend({}, L.CRS.Simple, {
+		projection: SDTD_Projection,
+		transformation: new L.Transformation(1, 0, -1, 0),
+
+		scale: function (zoom) {
+			return Math.pow(2, zoom);
+		}
+	});
+
+	var CoordToChunk = function(latlng) {
+		var x = Math.floor(((latlng.lat + 16777216) / CHUNKSIZE) - (16777216 / CHUNKSIZE));
+		var y = Math.floor(((latlng.lng + 16777216) / CHUNKSIZE) - (16777216 / CHUNKSIZE));
+		return L.latLng(x, y);
+	}
+
+	var CoordToRegion = function(latlng) {
+		var x = Math.floor(((latlng.lat + 16777216) / REGIONSIZE) - (16777216 / REGIONSIZE));
+		var y = Math.floor(((latlng.lng + 16777216) / REGIONSIZE) - (16777216 / REGIONSIZE));
+		return L.latLng(x, y);
+	}
+
+	var FormatCoord = function(latlng) {
+		return "" +
+			Math.abs(latlng.lng) + (latlng.lng>=0 ? " N" : " S") + " / " +
+			Math.abs(latlng.lat) + (latlng.lat>=0 ? " E" : " W");
+	}
+
+	var FormatRegionFileName = function(latlng) {
+		return "r." + latlng.lat + "." + latlng.lng + ".7rg";
+	}
+
+
+
+	// ===============================================================================================
+	// Map and basic tile layers
+
+	var tileTime = new Date().getTime();
+
+	map = L.map('map', {
+		zoomControl: false, // Added by Zoomslider
+		zoomsliderControl: true,
+		attributionControl: false,
+		crs: SDTD_CRS
+	}).setView([0, 0], Math.max(0, MAXZOOM-5));
+
+	var tileLayer = L.tileLayer('../map/{z}/{x}/{y}.png?t={time}', {
+		maxZoom:MAXZOOM+1,
+		minZoom: Math.max(0, MAXZOOM-5),
+		maxNativeZoom: MAXZOOM,
+		tileSize: TILESIZE,
+		continuousWorld: true,
+		tms: true,
+		unloadInvisibleTiles: false,
+		time: function() { return tileTime; }
+	}).addTo(map);
+
+	var tileLayerMiniMap = L.tileLayer('../map/{z}/{x}/{y}.png?t={time}', {
+		maxZoom: MAXZOOM,
+		minZoom: 0,
+		maxNativeZoom: MAXZOOM,
+		tileSize: TILESIZE,
+		continuousWorld: true,
+		tms: true,
+		unloadInvisibleTiles: false,
+		time: function() { return tileTime; }
+	});
+
+	var regionLayer = L.tileLayer.canvas({
+		maxZoom: MAXZOOM+1,
+		minZoom: 0,
+		maxNativeZoom: MAXZOOM+1,
+		tileSize: TILESIZE,
+		continuousWorld: true
+	});
+
+	regionLayer.drawTile = function(canvas, tilePoint, zoom) {
+		var blockWorldSize = TILESIZE * Math.pow(2, MAXZOOM-zoom);
+		var tileLeft = tilePoint.x * blockWorldSize;
+		var tileBottom = (-1-tilePoint.y) * blockWorldSize;
+		var blockPos = L.latLng(tileLeft, tileBottom);
+	
+		var ctx = canvas.getContext('2d');
+	
+		ctx.strokeStyle = "lightblue";
+		ctx.fillStyle = "lightblue";
+		ctx.lineWidth = 1;
+		ctx.font="14px Arial";
+	
+		var lineCount = blockWorldSize / REGIONSIZE;
+		if (lineCount >= 1) {
+			var pos = 0;
+			while (pos < TILESIZE) {
+				// Vertical
+				ctx.beginPath();
+				ctx.moveTo(pos, 0);
+				ctx.lineTo(pos, TILESIZE);
+				ctx.stroke();
+			
+				// Horizontal
+				ctx.beginPath();
+				ctx.moveTo(0, pos);
+				ctx.lineTo(TILESIZE, pos);
+				ctx.stroke();
+
+				pos += TILESIZE / lineCount;
+			}
+			ctx.fillText(FormatRegionFileName(CoordToRegion(blockPos)), 4, TILESIZE-5);
+		} else {
+			if ((tileLeft % REGIONSIZE) == 0) {
+				// Vertical
+				ctx.beginPath();
+				ctx.moveTo(0, 0);
+				ctx.lineTo(0, TILESIZE);
+				ctx.stroke();
+			}
+			if ((tileBottom % REGIONSIZE) == 0) {
+				// Horizontal
+				ctx.beginPath();
+				ctx.moveTo(0, TILESIZE);
+				ctx.lineTo(TILESIZE, TILESIZE);
+				ctx.stroke();
+			}
+			if ((tileLeft % REGIONSIZE) == 0 && (tileBottom % REGIONSIZE) == 0) {
+				ctx.fillText(FormatRegionFileName(CoordToRegion(blockPos)), 4, TILESIZE-5);
+			}
+		}
+
+		var pos = tileLeft;
+
+	}
+
+
+	// ===============================================================================================
+	// Reload control
+
+	L.Control.ReloadTiles = L.Control.extend({
+		options: {
+			position: 'bottomleft'
+		},
+
+		onAdd: function (map) {
+			var name = 'control-reloadtiles',
+			    container = L.DomUtil.create('div', name + ' leaflet-bar');
+
+			this._map = map;
+
+			this._reloadbutton = this._createButton(
+				"Reload tiles", "Reload tiles",
+				name + "-btn", container, this._reload, this);
+
+			return container;
+		},
+
+		onRemove: function (map) {
+		},
+
+		_reload: function (e) {
+			tileTime = new Date().getTime();
+			tileLayer.redraw();
+			tileLayerMiniMap.redraw();
+		},
+
+		_createButton: function (html, title, className, container, fn, context) {
+			var link = L.DomUtil.create('a', className, container);
+			link.innerHTML = html;
+			link.href = '#';
+			link.title = title;
+
+			var stop = L.DomEvent.stopPropagation;
+
+			L.DomEvent
+			    .on(link, 'click', stop)
+			    .on(link, 'mousedown', stop)
+			    .on(link, 'dblclick', stop)
+			    .on(link, 'click', L.DomEvent.preventDefault)
+			    .on(link, 'click', fn, context)
+			    .on(link, 'click', this._refocusOnMap, context);
+
+			return link;
+		}
+
+	});
+
+	new L.Control.ReloadTiles({
+	}).addTo(map);
+
+
+	// ===============================================================================================
+	// Coordinates control
+	//	<div id="info">
+	//		MouseCoords: <span id="pos"></span>
+	//	</div>
+
+	L.Control.Coordinates = L.Control.extend({
+		options: {
+			position: 'bottomleft'
+		},
+
+		onAdd: function (map) {
+			var name = 'control-coordinates',
+			    container = L.DomUtil.create('div', name + ' leaflet-bar');
+		
+			container.innerHTML = "- N / - E"
+
+			this._map = map;
+			this._div = container;
+
+			map.on('mousemove', this._onMouseMove, this);
+
+			return container;
+		},
+
+		onRemove: function (map) {
+		},
+	
+		_onMouseMove: function (e) {
+			this._div.innerHTML = FormatCoord(e.latlng);
+		}
+
+
+	});
+
+	new L.Control.Coordinates({
+	}).addTo(map);
+
+
+
+
+	// ===============================================================================================
+	// Overlays and controls
+
+	var playersOnlineMarkerGroup = L.layerGroup();
+	var playersOfflineMarkerGroup = L.markerClusterGroup({
+		maxClusterRadius: function(zoom) { return zoom == MAXZOOM ? 10 : 50; }
+	});
+
+
+	var landClaimsGroup = L.layerGroup();
+	var landClaimsClusterGroup = L.markerClusterGroup({
+		disableClusteringAtZoom: MAXZOOM,
+		singleMarkerMode: true,
+		maxClusterRadius: 50
+	});
+	var landClaimsRectGroup = L.layerGroup();
+	landClaimsGroup.addLayer(landClaimsClusterGroup);
+	landClaimsGroup.addLayer(landClaimsRectGroup);
+	var maxZoomForCluster = 4;
+
+	var baseLayers = {
+		//"Map": tileLayer
+	};
+
+	var overlays = {
+		"Land claims" : landClaimsGroup,
+		"Players (offline) (<span id='mapControlOfflineCount'>0</span>)" : playersOfflineMarkerGroup,
+		"Players (online) (<span id='mapControlOnlineCount'>0</span>)" : playersOnlineMarkerGroup,
+		"Region files": regionLayer,
+	};
+
+	
+	L.control.layers(baseLayers, overlays, {
+		collapsed: false
+	}).addTo(map);
+
+	//map.on('mousemove', function(e) {
+	//	L.DomUtil.get('pos').textContent = FormatCoord(e.latlng);
+	//});
+
+	var miniMap = new L.Control.MiniMap(tileLayerMiniMap, {
+		zoomLevelOffset: -6,
+		toggleDisplay: true
+	}).addTo(map);
+
+
+	var playersMappingList = {};
+
+
+
+	// ===============================================================================================
+	// Inventory dialog
+
+	var showInv = function(steamid) {
+		$.getJSON( "../api/getplayerinventory", { steamid: steamid  })
+		.done(function(data) {
+			$("#invPlayerName").text(playersMappingList[steamid].name);
+			for (var y = 0; y < BAG_ROWS; y++) {
+				for (var x = 0; x < BAG_COLS; x++) {
+					if (data.bag[y*BAG_COLS+x].count > 0) {
+						$("#bagField"+x+"_"+y).attr("style", "background-image: url(itemimages/" + data.bag[y*BAG_COLS+x].name + ".png);");
+						$("#bagFieldText"+x+"_"+y).text(data.bag[y*BAG_COLS+x].count);
+					} else {
+						$("#bagField"+x+"_"+y).attr("style", "background-image: none;");
+						$("#bagFieldText"+x+"_"+y).text("");
+					}
+				}
+			}
+
+			for (var x = 0; x < BELT_COLS; x++) {
+				if (data.belt[x].count > 0) {
+					$("#beltField"+x).attr("style", "background-image: url(itemimages/" + data.belt[x].name + ".png);");
+					$("#beltFieldText"+x).text(data.belt[x].count);
+				} else {
+					$("#beltField"+x).attr("style", "background-image: none;");
+					$("#beltFieldText"+x).text("");
+				}
+			}
+
+			$( "#playerInventoryDialog" ).css("z-index", "1010").dialog({
+				modal: true,
+				width: BAG_COLS*(INV_ITEM_WIDTH+14) + 20,
+				buttons: {
+					Ok: function() {
+						$( this ).dialog( "close" );
+					}
+				}
+			});
+		})
+		.fail(function(jqxhr, textStatus, error) {
+			console.log("Error fetching player inventory");
+		})
+		.always(function() {
+		});
+	};
+
+	for (var y = 0; y < BAG_ROWS; y++) {
+		$("#bagTable").append("<tr id=\"bagRow"+y+"\"></tr>");
+		for (var x = 0; x < BAG_COLS; x++) {
+			$("#bagRow"+y).append(
+				"<td class=\"invField\" id=\"bagField"+x+"_"+y+"\">" +
+				"<span class=\"invFieldText\" id=\"bagFieldText"+x+"_"+y+"\"></span>" +
+				"</td>");
+		}
+	}
+
+	$("#beltTable").append("<tr id=\"beltRow0\"></tr>");
+	for (var x = 0; x < BELT_COLS; x++) {
+		$("#beltRow0").append(
+			"<td class=\"invField\" id=\"beltField"+x+"\">" +
+			"<span class=\"invFieldText\" id=\"beltFieldText"+x+"\"></span>" +
+			"</td>");
+	}
+
+
+
+	// ===============================================================================================
+	// Player markers
+
+	$(".leaflet-popup-pane").on('click.action', '.inventoryButton', function(event) {
+		showInv($(this).data('steamid'));
+	});
+
+	var setPlayerMarkers = function(data) {
+		var online = 0;
+		var offline = 0;
+		$.each( data, function( key, val ) {
+			var marker;
+			if (playersMappingList.hasOwnProperty(val.steamid)) {
+				marker = playersMappingList[val.steamid].currentPosMarker;
+				marker.setLatLng([val.position.x, val.position.z]);
+			} else {
+				marker = L.marker([val.position.x, val.position.z]).bindPopup(
+					"Player: " + val.name + "<br/>" +
+					"<a class='inventoryButton' data-steamid='"+val.steamid+"'>Show inventory</a>"
+				);
+				playersMappingList[val.steamid] = { online: !val.online };
+			}
+			if (playersMappingList[val.steamid].online != val.online) {
+				if (val.online) {
+					marker.setOpacity(1.0);
+					playersOfflineMarkerGroup.removeLayer(marker);
+					playersOnlineMarkerGroup.addLayer(marker);
+				} else {
+					marker.setOpacity(0.5);
+					playersOnlineMarkerGroup.removeLayer(marker);
+					playersOfflineMarkerGroup.addLayer(marker);
+				}
+			}
+			val.currentPosMarker = marker;
+			playersMappingList[val.steamid] = val;
+		
+			if (val.online)
+				online++;
+			else
+				offline++;
+		});
+		$( "#mapControlOnlineCount" ).text( online );
+		$( "#mapControlOfflineCount" ).text( offline );
+	}
+
+	var updatePlayerEvent = function() {
+		$.getJSON( "../api/getplayerslocation")
+		.done(setPlayerMarkers)
+		.fail(function(jqxhr, textStatus, error) {
+			console.log("Error fetching players list");
+		})
+		.always(function() {
+			window.setTimeout(updatePlayerEvent, 2000);
+		});
+	}
+
+	window.setTimeout(updatePlayerEvent, 500);
+
+
+
+	// ===============================================================================================
+	// Land claim markers
+
+	var setLandClaims = function(data) {
+		landClaimsClusterGroup.clearLayers();
+		landClaimsRectGroup.clearLayers();
+	
+		var claimPower = Math.floor(Math.log(data.claimsize) / Math.LN2);
+		var maxClusterZoomUnlimited = MAXZOOM - (claimPower - 3);
+		var maxClusterZoomLimitedMax = Math.min(maxClusterZoomUnlimited, MAXZOOM+1);
+		maxZoomForCluster = Math.max(maxClusterZoomLimitedMax, 0);
+	
+		checkClaimClustering({target: map});
+
+		var sizeHalf = Math.floor(data.claimsize / 2);
+
+		$.each( data.claimowners, function( key, val ) {
+			var steamid = val.steamid;
+			var active = val.claimactive;
+			var color = active ? "#55ff55" : "#ff0000";
+		
+			$.each( val.claims, function( key, val ) {
+				var pos = L.latLng(val.x, val.z);
+				var bounds = L.latLngBounds(L.latLng(val.x - sizeHalf, val.z - sizeHalf), L.latLng(val.x + sizeHalf, val.z + sizeHalf));
+				var r = L.rectangle(bounds, {color: color, weight: 1, opacity: 0.8, fillOpacity: 0.15});
+				var m = L.marker(pos, { clickable: false, keyboard: false, zIndexOffset:-1000, iconSize: [0,0], icon: L.divIcon({className: 'invisIcon', iconSize:[0,0]}) });
+				if (playersMappingList.hasOwnProperty(steamid)) {
+					r.bindPopup("Owner: " + playersMappingList[steamid].name);
+				} else {
+					r.bindPopup("Owner: unknown ("+steamid+")");
+				}
+				landClaimsRectGroup.addLayer(r);
+				landClaimsClusterGroup.addLayer(m);
+			});
+		});
+	}
+
+	var updateClaimsEvent = function() {
+		$.getJSON( "../api/getlandclaims")
+		.done(setLandClaims)
+		.fail(function(jqxhr, textStatus, error) {
+			console.log("Error fetching land claim list");
+		})
+		.always(function() {
+			//updateClaimTimer = window.setTimeout(updateClaimsEvent, 3000);
+		});
+	}
+
+
+
+	// ===============================================================================================
+	// Layer events
+
+	var updateClaimTimer;
+	map.on('overlayadd', function(e) {
+		if (e.layer == landClaimsGroup) {
+			updateClaimsEvent();
+		}
+	});
+
+	map.on('overlayremove', function(e) {
+		if (e.layer == landClaimsGroup) {
+			//window.clearTimeout(updateClaimTimer);
+		}
+	});
+
+	var checkClaimClustering = function(e) {
+		if (e.target._zoom >= maxZoomForCluster) {
+			landClaimsGroup.removeLayer(landClaimsClusterGroup);	
+		} else {
+			landClaimsGroup.addLayer(landClaimsClusterGroup);	
+		}
+	};
+
+	map.on('zoomend', checkClaimClustering);
+
+}
+
+
+
+$.getJSON( "../map/mapinfo.json")
+.done(function(data) {
+	TILESIZE = data.blockSize;
+	MAXZOOM = data.maxZoom;
+	initMap();
+})
+.fail(function(jqxhr, textStatus, error) {
+	console.log("Error fetching map information");
+})
+.always(function() {
+	//updateClaimTimer = window.setTimeout(updateClaimsEvent, 3000);
 });
 
-var CoordToChunk = function(latlng) {
-	var x = Math.floor(((latlng.lng + 16777216) / CHUNKSIZE) - (16777216 / CHUNKSIZE));
-	var y = Math.floor(((latlng.lat + 16777216) / CHUNKSIZE) - (16777216 / CHUNKSIZE));
-	return L.latLng(y, x);
-}
-
-var CoordToRegion = function(latlng) {
-	var x = Math.floor(((latlng.lng + 16777216) / REGIONSIZE) - (16777216 / REGIONSIZE));
-	var y = Math.floor(((latlng.lat + 16777216) / REGIONSIZE) - (16777216 / REGIONSIZE));
-	return L.latLng(y, x);
-}
-
-var FormatCoord = function(latlng) {
-	return Math.abs(latlng.lat)+ (latlng.lat>=0 ? " N" : " S") + " / " + Math.abs(latlng.lng) + (latlng.lng>=0 ? " E" : " W");
-}
-
-var FormatRegionFileName = function(latlng) {
-	return "r." + latlng.lng + "." + latlng.lat + ".7rg";
-}
-
-
-
-// ===============================================================================================
-// Map and basic tile layers
-
-var tileTime = new Date().getTime();
-
-var map = L.map('map', {
-	zoomControl: false, // Added by Zoomslider
-	zoomsliderControl: true,
-	attributionControl: false,
-	crs: SDTD_CRS
-}).setView([0, 0], 0);
-
-var tileLayer = L.tileLayer('../../map/{z}/{x}/{y}.png?t={time}', {
-	maxZoom: MAXZOOM+1,
-	minZoom: 0,
-	maxNativeZoom: MAXZOOM,
-	tileSize: TILESIZE,
-	continuousWorld: true,
-	tms: true,
-	unloadInvisibleTiles: false,
-	time: function() { return tileTime; }
-});
-
-var tileLayerMiniMap = L.tileLayer('../../map/{z}/{x}/{y}.png?t={time}', {
-	maxZoom: MAXZOOM,
-	minZoom: 0,
-	maxNativeZoom: MAXZOOM,
-	tileSize: TILESIZE,
-	continuousWorld: true,
-	tms: true,
-	unloadInvisibleTiles: false,
-	time: function() { return tileTime; }
-});
-
-var regionLayer = L.tileLayer.canvas({
-	maxZoom: MAXZOOM+1,
-	minZoom: 0,
-	maxNativeZoom: MAXZOOM+1,
-	tileSize: TILESIZE,
-	continuousWorld: true
-});
-
-regionLayer.drawTile = function(canvas, tilePoint, zoom) {
-	var blockWorldSize = TILESIZE * Math.pow(2, MAXZOOM-zoom);
-	var tileLeft = tilePoint.x * blockWorldSize;
-	var tileBottom = (-1-tilePoint.y) * blockWorldSize;
-	var blockPos = L.latLng(tileBottom, tileLeft);
-	
-	var ctx = canvas.getContext('2d');
-	
-	ctx.strokeStyle = "lightblue";
-	ctx.fillStyle = "lightblue";
-	ctx.lineWidth = 1;
-	ctx.font="14px Arial";
-	
-	var lineCount = blockWorldSize / REGIONSIZE;
-	if (lineCount >= 1) {
-		var pos = 0;
-		while (pos < TILESIZE) {
-			// Vertical
-			ctx.beginPath();
-			ctx.moveTo(pos, 0);
-			ctx.lineTo(pos, TILESIZE);
-			ctx.stroke();
-			
-			// Horizontal
-			ctx.beginPath();
-			ctx.moveTo(0, pos);
-			ctx.lineTo(TILESIZE, pos);
-			ctx.stroke();
-
-			pos += TILESIZE / lineCount;
-		}
-		ctx.fillText(FormatRegionFileName(CoordToRegion(blockPos)), 4, TILESIZE-5);
-	} else {
-		if ((tileLeft % REGIONSIZE) == 0) {
-			// Vertical
-			ctx.beginPath();
-			ctx.moveTo(0, 0);
-			ctx.lineTo(0, TILESIZE);
-			ctx.stroke();
-		}
-		if ((tileBottom % REGIONSIZE) == 0) {
-			// Horizontal
-			ctx.beginPath();
-			ctx.moveTo(0, TILESIZE);
-			ctx.lineTo(TILESIZE, TILESIZE);
-			ctx.stroke();
-		}
-		if ((tileLeft % REGIONSIZE) == 0 && (tileBottom % REGIONSIZE) == 0) {
-			ctx.fillText(FormatRegionFileName(CoordToRegion(blockPos)), 4, TILESIZE-5);
-		}
-	}
-
-	var pos = tileLeft;
-
-}
-
-
-
-// ===============================================================================================
-// Reload control
-
-L.Control.ReloadTiles = L.Control.extend({
-	options: {
-		position: 'bottomleft'
-	},
-
-	onAdd: function (map) {
-		var name = 'control-reloadtiles',
-		    container = L.DomUtil.create('div', name + ' leaflet-bar');
-
-		this._map = map;
-
-		this._reloadbutton = this._createButton(
-			"Reload tiles", "Reload tiles",
-			name + "-btn", container, this._reload, this);
-
-		return container;
-	},
-
-	onRemove: function (map) {
-	},
-
-	_reload: function (e) {
-		tileTime = new Date().getTime();
-		tileLayer.redraw();
-		tileLayerMiniMap.redraw();
-	},
-
-	_createButton: function (html, title, className, container, fn, context) {
-		var link = L.DomUtil.create('a', className, container);
-		link.innerHTML = html;
-		link.href = '#';
-		link.title = title;
-
-		var stop = L.DomEvent.stopPropagation;
-
-		L.DomEvent
-		    .on(link, 'click', stop)
-		    .on(link, 'mousedown', stop)
-		    .on(link, 'dblclick', stop)
-		    .on(link, 'click', L.DomEvent.preventDefault)
-		    .on(link, 'click', fn, context)
-		    .on(link, 'click', this._refocusOnMap, context);
-
-		return link;
-	}
-
-});
-
-new L.Control.ReloadTiles({
-}).addTo(map);
-
-
-// ===============================================================================================
-// Coordinates control
-//	<div id="info">
-//		MouseCoords: <span id="pos"></span>
-//	</div>
-
-L.Control.Coordinates = L.Control.extend({
-	options: {
-		position: 'bottomleft'
-	},
-
-	onAdd: function (map) {
-		var name = 'control-coordinates',
-		    container = L.DomUtil.create('div', name + ' leaflet-bar');
-		
-		container.innerHTML = "- N / - E"
-
-		this._map = map;
-		this._div = container;
-
-		map.on('mousemove', this._onMouseMove, this);
-
-		return container;
-	},
-
-	onRemove: function (map) {
-	},
-	
-	_onMouseMove: function (e) {
-		this._div.innerHTML = FormatCoord(e.latlng);
-	}
-
-
-});
-
-new L.Control.Coordinates({
-}).addTo(map);
-
-
-
-// ===============================================================================================
-// Overlays and controls
-
-var playersOnlineMarkerGroup = L.layerGroup();
-var playersOfflineMarkerGroup = L.markerClusterGroup({
-	maxClusterRadius: function(zoom) { return zoom == MAXZOOM ? 10 : 50; }
-});
-var landClaimsGroup = L.markerClusterGroup({
-	disableClusteringAtZoom: MAXZOOM,
-	maxClusterRadius: 50
-});
-
-var baseLayers = {
-	//"Map": tileLayer
-};
-
-var overlays = {
-	"Land claims" : landClaimsGroup,
-	"Players (offline) (<span id='mapControlOfflineCount'>0</span>)" : playersOfflineMarkerGroup,
-	"Players (online) (<span id='mapControlOnlineCount'>0</span>)" : playersOnlineMarkerGroup,
-	"Region files": regionLayer,
-};
-
-tileLayer.addTo(map);
-L.control.layers(baseLayers, overlays, {
-	collapsed: false
-}).addTo(map);
-
-//map.on('mousemove', function(e) {
-//	L.DomUtil.get('pos').textContent = FormatCoord(e.latlng);
-//});
-
-var miniMap = new L.Control.MiniMap(tileLayerMiniMap, {
-	toggleDisplay: true
-}).addTo(map);
-
-
-var playersMappingList = {};
-
-
-
-// ===============================================================================================
-// Inventory dialog
-
-var showInv = function(steamid) {
-	$.getJSON( "../api/getplayerinventory", { steamid: steamid  })
-	.done(function(data) {
-		$("#invPlayerName").text(playersMappingList[steamid].name);
-		for (var y = 0; y < BAG_ROWS; y++) {
-			for (var x = 0; x < BAG_COLS; x++) {
-				if (data.bag[y*BAG_COLS+x].count > 0) {
-					$("#bagField"+x+"_"+y).attr("style", "background-image: url(itemimages/" + data.bag[y*BAG_COLS+x].name + ".png);");
-					$("#bagFieldText"+x+"_"+y).text(data.bag[y*BAG_COLS+x].count);
-				} else {
-					$("#bagField"+x+"_"+y).attr("style", "background-image: none;");
-					$("#bagFieldText"+x+"_"+y).text("");
-				}
-			}
-		}
-
-		for (var x = 0; x < BELT_COLS; x++) {
-			if (data.belt[x].count > 0) {
-				$("#beltField"+x).attr("style", "background-image: url(itemimages/" + data.belt[x].name + ".png);");
-				$("#beltFieldText"+x).text(data.belt[x].count);
-			} else {
-				$("#beltField"+x).attr("style", "background-image: none;");
-				$("#beltFieldText"+x).text("");
-			}
-		}
-
-		$( "#playerInventoryDialog" ).css("z-index", "1010").dialog({
-			modal: true,
-			width: BAG_COLS*(INV_ITEM_WIDTH+14) + 20,
-			buttons: {
-				Ok: function() {
-					$( this ).dialog( "close" );
-				}
-			}
-		});
-	})
-	.fail(function(jqxhr, textStatus, error) {
-		console.log("Error fetching player inventory");
-	})
-	.always(function() {
-	});
-};
-
-for (var y = 0; y < BAG_ROWS; y++) {
-	$("#bagTable").append("<tr id=\"bagRow"+y+"\"></tr>");
-	for (var x = 0; x < BAG_COLS; x++) {
-		$("#bagRow"+y).append(
-			"<td class=\"invField\" id=\"bagField"+x+"_"+y+"\">" +
-			"<span class=\"invFieldText\" id=\"bagFieldText"+x+"_"+y+"\"></span>" +
-			"</td>");
-	}
-}
-
-$("#beltTable").append("<tr id=\"beltRow0\"></tr>");
-for (var x = 0; x < BELT_COLS; x++) {
-	$("#beltRow0").append(
-		"<td class=\"invField\" id=\"beltField"+x+"\">" +
-		"<span class=\"invFieldText\" id=\"beltFieldText"+x+"\"></span>" +
-		"</td>");
-}
-
-
-
-// ===============================================================================================
-// Player markers
-
-$(".leaflet-popup-pane").on('click.action', '.inventoryButton', function(event) {
-	showInv($(this).data('steamid'));
-});
-
-var setPlayerMarkers = function(data) {
-	var online = 0;
-	var offline = 0;
-	$.each( data, function( key, val ) {
-		var marker;
-		if (playersMappingList.hasOwnProperty(val.steamid)) {
-			marker = playersMappingList[val.steamid].currentPosMarker;
-			marker.setLatLng([val.position.z, val.position.x]);
-		} else {
-			marker = L.marker([val.position.z, val.position.x]).bindPopup(
-				"Player: " + val.name + "<br/>" +
-				"<a class='inventoryButton' data-steamid='"+val.steamid+"'>Show inventory</a>"
-			);
-			playersMappingList[val.steamid] = { online: !val.online };
-		}
-		if (playersMappingList[val.steamid].online != val.online) {
-			if (val.online) {
-				marker.setOpacity(1.0);
-				playersOfflineMarkerGroup.removeLayer(marker);
-				playersOnlineMarkerGroup.addLayer(marker);
-			} else {
-				marker.setOpacity(0.5);
-				playersOnlineMarkerGroup.removeLayer(marker);
-				playersOfflineMarkerGroup.addLayer(marker);
-			}
-		}
-		val.currentPosMarker = marker;
-		playersMappingList[val.steamid] = val;
-		
-		if (val.online)
-			online++;
-		else
-			offline++;
-	});
-	$( "#mapControlOnlineCount" ).text( online );
-	$( "#mapControlOfflineCount" ).text( offline );
-}
-
-var updatePlayerEvent = function() {
-	$.getJSON( "../api/getplayerslocation")
-	.done(setPlayerMarkers)
-	.fail(function(jqxhr, textStatus, error) {
-		console.log("Error fetching players list");
-	})
-	.always(function() {
-		window.setTimeout(updatePlayerEvent, 2000);
-	});
-}
-
-window.setTimeout(updatePlayerEvent, 500);
-
-
-
-// ===============================================================================================
-// Land claim markers
-
-var setLandClaims = function(data) {
-	landClaimsGroup.clearLayers();
-	var sizeHalf = Math.floor(data.claimsize / 2);
-
-	$.each( data.claimowners, function( key, val ) {
-		var steamid = val.steamid;
-		var active = val.claimactive;
-		var color = active ? "#00ff00" : "#ff0000";
-		
-		$.each( val.claims, function( key, val ) {
-			var pos = L.latLng(val.z, val.x);
-			var bounds = L.latLngBounds(L.latLng(val.z - sizeHalf, val.x - sizeHalf), L.latLng(val.z + sizeHalf, val.x + sizeHalf));
-			var r = L.rectangle(bounds, {color: color, weight: 1});
-			var m = L.marker(pos, { clickable: false, keyboard: false, zIndexOffset:-1000, iconSize: [0,0], icon: L.divIcon({className: 'invisIcon', iconSize:[0,0]}) });
-			if (playersMappingList.hasOwnProperty(steamid)) {
-				r.bindPopup("Owner: " + playersMappingList[steamid].name);
-			} else {
-				r.bindPopup("Owner: unknown ("+steamid+")");
-			}
-			landClaimsGroup.addLayer(r);
-			landClaimsGroup.addLayer(m);
-		});
-	});
-}
-
-var updateClaimsEvent = function() {
-	$.getJSON( "../api/getlandclaims")
-	.done(setLandClaims)
-	.fail(function(jqxhr, textStatus, error) {
-		console.log("Error fetching land claim list");
-	})
-	.always(function() {
-		//updateClaimTimer = window.setTimeout(updateClaimsEvent, 3000);
-	});
-}
-
-
-
-// ===============================================================================================
-// Layer events
-
-var updateClaimTimer;
-map.on('overlayadd', function(e) {
-	if (e.layer == landClaimsGroup) {
-		updateClaimsEvent();
-	}
-});
-
-map.on('overlayremove', function(e) {
-	if (e.layer == landClaimsGroup) {
-		//window.clearTimeout(updateClaimTimer);
-	}
-});
-
-
