source: binary-improvements/webserver/js/map.js@ 325

Last change on this file since 325 was 320, checked in by alloc, 6 years ago

Fixed #152: XSS attacks

File size: 16.2 KB
Line 
1var mapinfo = {
2 regionsize: 512,
3 chunksize: 16,
4 tilesize: 128,
5 maxzoom: 4
6}
7
8function InitMap() {
9 // ===============================================================================================
10 // 7dtd coordinate transformations
11
12 SDTD_Projection = {
13 project: function (latlng) {
14 return new L.Point(
15 (latlng.lat) / Math.pow(2, mapinfo.maxzoom),
16 (latlng.lng) / Math.pow(2, mapinfo.maxzoom) );
17 },
18
19 unproject: function (point) {
20 return new L.LatLng(
21 point.x * Math.pow(2, mapinfo.maxzoom),
22 point.y * Math.pow(2, mapinfo.maxzoom) );
23 }
24 };
25
26 SDTD_CRS = L.extend({}, L.CRS.Simple, {
27 projection: SDTD_Projection,
28 transformation: new L.Transformation(1, 0, -1, 0),
29
30 scale: function (zoom) {
31 return Math.pow(2, zoom);
32 }
33 });
34
35 // ===============================================================================================
36 // Map and basic tile layers
37
38 map = L.map('tab_map', {
39 zoomControl: false, // Added by Zoomslider
40 zoomsliderControl: true,
41 attributionControl: false,
42 crs: SDTD_CRS
43 }).setView([0, 0], Math.max(0, mapinfo.maxzoom - 5));
44
45
46 var initTime = new Date().getTime();
47 var tileLayer = GetSdtdTileLayer (mapinfo, initTime);
48 var tileLayerMiniMap = GetSdtdTileLayer (mapinfo, initTime, true);
49
50 // player icon
51 var playerIcon = L.icon({
52 iconUrl: '/static/leaflet/images/marker-survivor.png',
53 iconRetinaUrl: '/static/leaflet/images/marker-survivor-2x.png',
54 iconSize: [25, 48],
55 iconAnchor: [12, 24],
56 popupAnchor: [0, -20]
57 });
58
59 // hostile icon
60 var hostileIcon = L.icon({
61 iconUrl: '/static/leaflet/images/marker-zombie.png',
62 iconRetinaUrl: '/static/leaflet/images/marker-zombie-2x.png',
63 iconSize: [25, 33],
64 iconAnchor: [12, 16],
65 popupAnchor: [0, -10]
66 });
67
68 // animal icon
69 var animalIcon = L.icon({
70 iconUrl: '/static/leaflet/images/marker-animal.png',
71 iconRetinaUrl: '/static/leaflet/images/marker-animal-2x.png',
72 iconSize: [25, 26],
73 iconAnchor: [12, 13],
74 popupAnchor: [0, -10]
75 });
76
77
78
79 // ===============================================================================================
80 // Overlays and controls
81
82 var playersOnlineMarkerGroup = L.markerClusterGroup({
83 maxClusterRadius: function(zoom) { return zoom == mapinfo.maxzoom ? 10 : 50; }
84 });
85 var playersOfflineMarkerGroup = L.markerClusterGroup({
86 maxClusterRadius: function(zoom) { return zoom == mapinfo.maxzoom ? 10 : 50; }
87 });
88 var hostilesMarkerGroup = L.markerClusterGroup({
89 maxClusterRadius: function(zoom) { return zoom == mapinfo.maxzoom ? 10 : 50; }
90 });
91 var animalsMarkerGroup = L.markerClusterGroup({
92 maxClusterRadius: function(zoom) { return zoom == mapinfo.maxzoom ? 10 : 50; }
93 });
94
95 var densityMismatchMarkerGroupAir = L.markerClusterGroup({
96 maxClusterRadius: function(zoom) { return zoom == mapinfo.maxzoom ? 10 : 50; }
97 });
98 var densityMismatchMarkerGroupTerrain = L.markerClusterGroup({
99 maxClusterRadius: function(zoom) { return zoom == mapinfo.maxzoom ? 10 : 50; }
100 });
101 var densityMismatchMarkerGroupNonTerrain = L.markerClusterGroup({
102 maxClusterRadius: function(zoom) { return zoom == mapinfo.maxzoom ? 10 : 50; }
103 });
104
105
106 var layerControl = L.control.layers({
107 //"Map": tileLayer
108 }, null, {
109 collapsed: false
110 }
111 );
112
113 var layerCount = 0;
114
115
116 tileLayer.addTo(map);
117
118 new L.Control.Coordinates({}).addTo(map);
119
120 new L.Control.ReloadTiles({
121 autoreload_enable: true,
122 autoreload_minInterval: 30,
123 autoreload_interval: 120,
124 autoreload_defaultOn: false,
125 layers: [tileLayer, tileLayerMiniMap]
126 }).addTo(map);
127
128 layerControl.addOverlay (GetRegionLayer (mapinfo), "Region files");
129 layerCount++;
130
131 var miniMap = new L.Control.MiniMap(tileLayerMiniMap, {
132 zoomLevelOffset: -6,
133 toggleDisplay: true
134 }).addTo(map);
135
136 var measure = L.control.measure({
137 units: {
138 sdtdMeters: {
139 factor: 0.00001,
140 display: 'XMeters',
141 decimals: 0
142 },
143 sdtdSqMeters: {
144 factor: 0.000000001,
145 display: 'XSqMeters',
146 decimals: 0
147 }
148 },
149 primaryLengthUnit: "sdtdMeters",
150 primaryAreaUnit: "sdtdSqMeters",
151 //activeColor: "#ABE67E",
152 //completedColor: "#C8F2BE",
153 position: "bottomleft"
154 });
155 //measure.addTo(map);
156
157 new L.Control.GameTime({}).addTo(map);
158
159 if (HasPermission ("webapi.getlandclaims")) {
160 layerControl.addOverlay (GetLandClaimsLayer (map, mapinfo), "Land claims");
161 layerCount++;
162 }
163
164 if (HasPermission ("webapi.gethostilelocation")) {
165 layerControl.addOverlay (hostilesMarkerGroup, "Hostiles (<span id='mapControlHostileCount'>0</span>)");
166 layerCount++;
167 }
168
169 if (HasPermission ("webapi.getanimalslocation")) {
170 layerControl.addOverlay (animalsMarkerGroup, "Animals (<span id='mapControlAnimalsCount'>0</span>)");
171 layerCount++;
172 }
173
174 if (HasPermission ("webapi.getplayerslocation")) {
175 layerControl.addOverlay (playersOfflineMarkerGroup, "Players (offline) (<span id='mapControlOfflineCount'>0</span>)");
176 layerControl.addOverlay (playersOnlineMarkerGroup, "Players (online) (<span id='mapControlOnlineCount'>0</span>)");
177 layerCount++;
178 }
179
180 if (layerCount > 0) {
181 layerControl.addTo(map);
182 }
183
184
185
186
187 var hostilesMappingList = {};
188 var animalsMappingList = {};
189 var playersMappingList = {};
190
191
192
193 // ===============================================================================================
194 // Player markers
195
196 $(".leaflet-popup-pane").on('click.action', '.inventoryButton', function(event) {
197 ShowInventoryDialog ($(this).data('steamid'));
198 });
199
200 var updatingMarkers = false;
201
202
203 var setPlayerMarkers = function(data) {
204 var onlineIds = [];
205 updatingMarkers = true;
206 $.each( data, function( key, val ) {
207 var marker;
208 if (playersMappingList.hasOwnProperty(val.steamid)) {
209 marker = playersMappingList[val.steamid].currentPosMarker;
210 } else {
211 marker = L.marker([val.position.x, val.position.z], {icon: playerIcon}).bindPopup(
212 "Player: " + $("<div>").text(val.name).html() +
213 (HasPermission ("webapi.getplayerinventory") ?
214 "<br/><a class='inventoryButton' data-steamid='"+val.steamid+"'>Show inventory</a>"
215 : "")
216 );
217 marker.on("move", function ( e ) {
218 if ( this.isPopupOpen () ) {
219 map.flyTo (e.latlng, map.getZoom ());
220 }
221 });
222 playersMappingList[val.steamid] = { online: !val.online };
223 }
224
225 if (val.online) {
226 onlineIds.push (val.steamid);
227 }
228
229 oldpos = marker.getLatLng ();
230 if ( playersMappingList[val.steamid].online != val.online ) {
231 if (playersMappingList[val.steamid].online) {
232 playersOnlineMarkerGroup.removeLayer(marker);
233 playersOfflineMarkerGroup.addLayer(marker);
234 } else {
235 playersOfflineMarkerGroup.removeLayer(marker);
236 playersOnlineMarkerGroup.addLayer(marker);
237 }
238 }
239 if ( oldpos.lat != val.position.x || oldpos.lng != val.position.z ) {
240 marker.setLatLng([val.position.x, val.position.z]);
241 if (val.online) {
242 marker.setOpacity(1.0);
243 } else {
244 marker.setOpacity(0.5);
245 }
246 }
247
248 val.currentPosMarker = marker;
249 playersMappingList[val.steamid] = val;
250 });
251
252 var online = 0;
253 var offline = 0;
254 $.each ( playersMappingList, function ( key, val ) {
255 if ( val.online && onlineIds.indexOf (key) < 0 ) {
256 var marker = val.currentPosMarker;
257 playersOnlineMarkerGroup.removeLayer(marker);
258 playersOfflineMarkerGroup.addLayer(marker);
259 val.online = false;
260 }
261 if (val.online) {
262 online++;
263 } else {
264 offline++;
265 }
266 });
267
268 updatingMarkers = false;
269
270 $( "#mapControlOnlineCount" ).text( online );
271 $( "#mapControlOfflineCount" ).text( offline );
272 }
273
274 var updatePlayerTimeout;
275 var playerUpdateCount = -1;
276 var updatePlayerEvent = function() {
277 playerUpdateCount++;
278
279 $.getJSON( "../api/getplayerslocation" + ((playerUpdateCount % 15) == 0 ? "?offline=true" : ""))
280 .done(setPlayerMarkers)
281 .fail(function(jqxhr, textStatus, error) {
282 console.log("Error fetching players list");
283 })
284 .always(function() {
285 updatePlayerTimeout = window.setTimeout(updatePlayerEvent, 4000);
286 });
287 }
288
289 tabs.on ("tabbedcontenttabopened", function (event, data) {
290 if (data.newTab === "#tab_map") {
291 if (HasPermission ("webapi.getplayerslocation")) {
292 updatePlayerEvent ();
293 }
294 } else {
295 window.clearTimeout (updatePlayerTimeout);
296 }
297 });
298
299 if (tabs.tabbedContent ("isTabOpen", "tab_map")) {
300 if (HasPermission ("webapi.getplayerslocation")) {
301 updatePlayerEvent ();
302 }
303 }
304
305
306
307
308 // ===============================================================================================
309 // Hostiles markers
310
311 var setHostileMarkers = function(data) {
312 updatingMarkersHostile = true;
313
314 var hostileCount = 0;
315
316 hostilesMarkerGroup.clearLayers();
317
318 $.each( data, function( key, val ) {
319 var marker;
320 if (hostilesMappingList.hasOwnProperty(val.id)) {
321 marker = hostilesMappingList[val.id].currentPosMarker;
322 } else {
323 marker = L.marker([val.position.x, val.position.z], {icon: hostileIcon}).bindPopup(
324 "Hostile: " + val.name
325 );
326 //hostilesMappingList[val.id] = { };
327 hostilesMarkerGroup.addLayer(marker);
328 }
329
330 var bAbort = false;
331
332 oldpos = marker.getLatLng ();
333
334 //if ( oldpos.lat != val.position.x || oldpos.lng != val.position.z ) {
335 // hostilesMarkerGroup.removeLayer(marker);
336 marker.setLatLng([val.position.x, val.position.z]);
337 marker.setOpacity(1.0);
338 hostilesMarkerGroup.addLayer(marker);
339 //}
340
341 val.currentPosMarker = marker;
342 hostilesMappingList[val.id] = val;
343
344 hostileCount++;
345 });
346
347 $( "#mapControlHostileCount" ).text( hostileCount );
348
349 updatingMarkersHostile = false;
350 }
351
352 var updateHostileTimeout;
353 var updateHostileEvent = function() {
354 $.getJSON( "../api/gethostilelocation")
355 .done(setHostileMarkers)
356 .fail(function(jqxhr, textStatus, error) {
357 console.log("Error fetching hostile list");
358 })
359 .always(function() {
360 updateHostileTimeout = window.setTimeout(updateHostileEvent, 4000);
361 });
362 }
363
364 tabs.on ("tabbedcontenttabopened", function (event, data) {
365 if (data.newTab === "#tab_map") {
366 if (HasPermission ("webapi.gethostilelocation")) {
367 updateHostileEvent ();
368 }
369 } else {
370 window.clearTimeout (updateHostileTimeout);
371 }
372 });
373
374 if (tabs.tabbedContent ("isTabOpen", "tab_map")) {
375 if (HasPermission ("webapi.gethostilelocation")) {
376 updateHostileEvent ();
377 }
378 }
379
380
381
382 // ===============================================================================================
383 // Animals markers
384
385 var setAnimalMarkers = function(data) {
386 updatingMarkersAnimals = true;
387
388 var animalsCount = 0;
389
390 animalsMarkerGroup.clearLayers();
391
392 $.each( data, function( key, val ) {
393 var marker;
394 if (animalsMappingList.hasOwnProperty(val.id)) {
395 marker = animalsMappingList[val.id].currentPosMarker;
396 } else {
397 marker = L.marker([val.position.x, val.position.z], {icon: animalIcon}).bindPopup(
398 "Animal: " + val.name
399 );
400 //animalsMappingList[val.id] = { };
401 animalsMarkerGroup.addLayer(marker);
402 }
403
404 var bAbort = false;
405
406 oldpos = marker.getLatLng ();
407
408 //if ( oldpos.lat != val.position.x || oldpos.lng != val.position.z ) {
409 // animalsMarkerGroup.removeLayer(marker);
410 marker.setLatLng([val.position.x, val.position.z]);
411 marker.setOpacity(1.0);
412 animalsMarkerGroup.addLayer(marker);
413 //}
414
415 val.currentPosMarker = marker;
416 animalsMappingList[val.id] = val;
417
418 animalsCount++;
419 });
420
421 $( "#mapControlAnimalsCount" ).text( animalsCount );
422
423 updatingMarkersAnimals = false;
424 }
425
426 var updateAnimalsTimeout;
427 var updateAnimalsEvent = function() {
428 $.getJSON( "../api/getanimalslocation")
429 .done(setAnimalMarkers)
430 .fail(function(jqxhr, textStatus, error) {
431 console.log("Error fetching animals list");
432 })
433 .always(function() {
434 updateAnimalsTimeout = window.setTimeout(updateAnimalsEvent, 4000);
435 });
436 }
437
438 tabs.on ("tabbedcontenttabopened", function (event, data) {
439 if (data.newTab === "#tab_map") {
440 if (HasPermission ("webapi.getanimalslocation")) {
441 updateAnimalsEvent ();
442 }
443 } else {
444 window.clearTimeout (updateAnimalsTimeout);
445 }
446 });
447
448 if (tabs.tabbedContent ("isTabOpen", "tab_map")) {
449 if (HasPermission ("webapi.getanimalslocation")) {
450 updateAnimalsEvent ();
451 }
452 }
453
454
455
456
457
458
459
460
461
462 // ===============================================================================================
463 // Density markers
464
465 var setDensityMarkers = function(data) {
466 var densityCountAir = 0;
467 var densityCountTerrain = 0;
468 var densityCountNonTerrain = 0;
469
470 densityMismatchMarkerGroupAir.clearLayers();
471 densityMismatchMarkerGroupTerrain.clearLayers();
472 densityMismatchMarkerGroupNonTerrain.clearLayers();
473
474
475 var downloadCsv = true;
476 var downloadJson = false;
477
478 if (downloadJson) {
479 var jsonAir = [];
480 var jsonTerrain = [];
481 var jsonNonTerrain = [];
482 }
483 if (downloadCsv) {
484 var csvAir = "x;y;z;Density;IsTerrain;BvType\r\n";
485 var csvTerrain = "x;y;z;Density;IsTerrain;BvType\r\n";
486 var csvNonTerrain = "x;y;z;Density;IsTerrain;BvType\r\n";
487 }
488
489 $.each( data, function( key, val ) {
490 if (val.bvtype == 0) {
491 marker = L.marker([val.x, val.z]).bindPopup(
492 "Density Mismatch: <br>Position: " + val.x + " " + val.y + " " + val.z + "<br>Density: " + val.density + "<br>isTerrain: " + val.terrain + "<br>bv.type: " + val.bvtype
493 );
494 densityMismatchMarkerGroupAir.addLayer(marker);
495 densityCountAir++;
496 if (downloadJson) {
497 jsonAir.push (val);
498 }
499 if (downloadCsv) {
500 csvAir += val.x + ";" + val.y + ";" + val.z + ";" + val.density + ";" + val.terrain + ";" + val.bvtype + "\r\n";
501 }
502 } else if (val.terrain) {
503 marker = L.marker([val.x, val.z]).bindPopup(
504 "Density Mismatch: <br>Position: " + val.x + " " + val.y + " " + val.z + "<br>Density: " + val.density + "<br>isTerrain: " + val.terrain + "<br>bv.type: " + val.bvtype
505 );
506 densityMismatchMarkerGroupTerrain.addLayer(marker);
507 densityCountTerrain++;
508 if (downloadJson) {
509 jsonTerrain.push (val);
510 }
511 if (downloadCsv) {
512 csvTerrain += val.x + ";" + val.y + ";" + val.z + ";" + val.density + ";" + val.terrain + ";" + val.bvtype + "\r\n";
513 }
514 } else {
515 marker = L.marker([val.x, val.z]).bindPopup(
516 "Density Mismatch: <br>Position: " + val.x + " " + val.y + " " + val.z + "<br>Density: " + val.density + "<br>isTerrain: " + val.terrain + "<br>bv.type: " + val.bvtype
517 );
518 densityMismatchMarkerGroupNonTerrain.addLayer(marker);
519 densityCountNonTerrain++;
520 if (downloadJson) {
521 jsonNonTerrain.push (val);
522 }
523 if (downloadCsv) {
524 csvNonTerrain += val.x + ";" + val.y + ";" + val.z + ";" + val.density + ";" + val.terrain + ";" + val.bvtype + "\r\n";
525 }
526 }
527 });
528
529 layerControl.addOverlay (densityMismatchMarkerGroupAir, "Density Mismatches Air (<span id='mapControlDensityCountAir'>0</span>)");
530 layerControl.addOverlay (densityMismatchMarkerGroupTerrain, "Density Mismatches Terrain (<span id='mapControlDensityCountTerrain'>0</span>)");
531 layerControl.addOverlay (densityMismatchMarkerGroupNonTerrain, "Density Mismatches NonTerrain (<span id='mapControlDensityCountNonTerrain'>0</span>)");
532
533 $( "#mapControlDensityCountAir" ).text( densityCountAir );
534 $( "#mapControlDensityCountTerrain" ).text( densityCountTerrain );
535 $( "#mapControlDensityCountNonTerrain" ).text( densityCountNonTerrain );
536
537 if (downloadJson) {
538 download ("air-negative-density.json", JSON.stringify(jsonAir, null, '\t'));
539 download ("terrain-positive-density.json", JSON.stringify(jsonTerrain, null, '\t'));
540 download ("nonterrain-negative-density.json", JSON.stringify(jsonNonTerrain, null, '\t'));
541 }
542 if (downloadCsv) {
543 download ("air-negative-density.csv", csvAir);
544 download ("terrain-positive-density.csv", csvTerrain);
545 download ("nonterrain-negative-density.csv", csvNonTerrain);
546 }
547
548 function download(filename, text) {
549 var element = document.createElement('a');
550 var file = new Blob([text], {type: 'text/plain'});
551 element.href = URL.createObjectURL(file);
552 element.download = filename;
553
554 element.style.display = 'none';
555 document.body.appendChild(element);
556
557 element.click();
558
559 document.body.removeChild(element);
560 }
561 }
562
563 $.getJSON("densitymismatch.json")
564 .done(setDensityMarkers)
565 .fail(function(jqxhr, textStatus, error) {
566 console.log("Error fetching density mismatch list");
567 });
568
569}
570
571
572
573
574
575function StartMapModule () {
576 $.getJSON( "../map/mapinfo.json")
577 .done(function(data) {
578 mapinfo.tilesize = data.blockSize;
579 mapinfo.maxzoom = data.maxZoom;
580 })
581 .fail(function(jqxhr, textStatus, error) {
582 console.log ("Error fetching map information");
583 })
584 .always(function() {
585 InitMap ();
586 });
587}
588
589
Note: See TracBrowser for help on using the repository browser.