// ===============================================================================================
// Constants
var REGIONSIZE = 512;
var CHUNKSIZE = 16;
var TILESIZE = 128;
var MAXZOOM = 4;
var BAG_COLS = 8;
var BAG_ROWS = 4;
var BELT_COLS = 8;
var INV_ITEM_WIDTH = 58;
var INV_ITEM_HEIGHT = 40;
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);
// TileLayer w/ TMS=true fix for zoomlevel >= 8
tileLayer._getWrapTileNum = function () {
return L.point(0, 0);
};
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);
}
}
}
// ===============================================================================================
// 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
//
// MouseCoords:
//
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) (0)" : playersOfflineMarkerGroup,
"Players (online) (0)" : playersOnlineMarkerGroup,
"Region files": regionLayer,
};
L.control.layers(baseLayers, overlays, {
collapsed: false
}).addTo(map);
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(../itemicons/" + 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(../itemicons/" + 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("
");
for (var x = 0; x < BAG_COLS; x++) {
$("#bagRow"+y).append(
"" +
"" +
" | ");
}
}
$("#beltTable").append("
");
for (var x = 0; x < BELT_COLS; x++) {
$("#beltRow0").append(
"" +
"" +
" | ");
}
// ===============================================================================================
// 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 + "
" +
"Show inventory"
);
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)) {
var name = playersMappingList[steamid].name;
} else {
var name = "unknown"
}
r.bindPopup("Owner: " + name + " ("+steamid+")
Position: " + val.x + " / " + val.y + " / " + val.z);
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;
})
.fail(function(jqxhr, textStatus, error) {
console.log("Error fetching map information");
})
.always(function() {
initMap();
});