forked from MTSR/mapserver
Add support for realtime APercy Airutils-based planes
This commit is contained in:
parent
2c4ee1d130
commit
84253939c4
@ -89,6 +89,7 @@ func ParseConfig(filename string) (*Config, error) {
|
||||
Minecart: false,
|
||||
Locator: false,
|
||||
Signs: true,
|
||||
MapserverAirutils: true,
|
||||
}
|
||||
|
||||
mapblockaccessor := MapBlockAccessorConfig{
|
||||
|
@ -61,6 +61,7 @@ type MapObjectConfig struct {
|
||||
Minecart bool `json:"minecart"`
|
||||
Locator bool `json:"locator"`
|
||||
Signs bool `json:"signs"`
|
||||
MapserverAirutils bool `json:"mapserver_airutils"`
|
||||
}
|
||||
|
||||
type WebApiConfig struct {
|
||||
|
@ -59,7 +59,8 @@
|
||||
"trainsignal": true,
|
||||
"minecart": false,
|
||||
"locator": false,
|
||||
"signs": true
|
||||
"signs": true,
|
||||
"mapserver_airutils": true
|
||||
},
|
||||
"mapblockaccessor": {
|
||||
"expiretime": "15s",
|
||||
|
@ -8,6 +8,7 @@ you get more realtime-data from within your minetest-world:
|
||||
|
||||
* Current players with their positions
|
||||
* Current time and max lag
|
||||
* Planes using the [Airutils library](https://github.com/APercy/airutils) by APercy, if installed
|
||||
|
||||
You can use the `mapserver-mod` either passive or active:
|
||||
* *Passive* Makes some additional markers available (POI, Labels, etc)
|
||||
|
@ -22,6 +22,7 @@ import BorderOverlay from './overlays/BorderOverlay.js';
|
||||
import TrainOverlay from './overlays/TrainOverlay.js';
|
||||
import TrainsignalOverlay from './overlays/TrainsignalOverlay.js';
|
||||
import SignOverlay from './overlays/SignOverlay.js';
|
||||
import AirUtilsPlanesOverlay from "./overlays/AirUtilsPlanesOverlay.js";
|
||||
|
||||
export default function(cfg, map, overlays, wsChannel){
|
||||
|
||||
@ -199,4 +200,11 @@ export default function(cfg, map, overlays, wsChannel){
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.mapobjects.mapserver_airutils) {
|
||||
overlays.Planes = new AirUtilsPlanesOverlay();
|
||||
if (isDefault("mapserver_airutils")) {
|
||||
map.addLayer(overlays.Planes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
165
public/js/map/overlays/AirUtilsPlanesOverlay.js
Normal file
165
public/js/map/overlays/AirUtilsPlanesOverlay.js
Normal file
@ -0,0 +1,165 @@
|
||||
import wsChannel from '../../WebSocketChannel.js';
|
||||
import layerMgr from '../../LayerManager.js';
|
||||
|
||||
let planes = [];
|
||||
|
||||
let icons = {
|
||||
"default": {
|
||||
url: "pics/airutils_planes/supercub.png",
|
||||
size: 48
|
||||
},
|
||||
"hidroplane:hidro": {
|
||||
url: "pics/airutils_planes/hidro.png",
|
||||
size: 48
|
||||
},
|
||||
"supercub:supercub": {
|
||||
url: "pics/airutils_planes/supercub.png",
|
||||
size: 48
|
||||
},
|
||||
"pa28:pa28": {
|
||||
url: "pics/airutils_planes/pa28.png",
|
||||
size: 64
|
||||
},
|
||||
"trike:trike": {
|
||||
url: "pics/airutils_planes/trike.png",
|
||||
size: 40
|
||||
},
|
||||
"ju52:ju52": {
|
||||
url: "pics/airutils_planes/ju52.png",
|
||||
size: 72
|
||||
},
|
||||
"steampunk_blimp:blimp": {
|
||||
url: "pics/airutils_planes/blimp.png",
|
||||
size: 96
|
||||
},
|
||||
};
|
||||
|
||||
// listening for realtime updates
|
||||
wsChannel.addListener("minetest-info", function(info) {
|
||||
planes = info.airutils_planes || [];
|
||||
});
|
||||
|
||||
export default L.LayerGroup.extend({
|
||||
initialize: function() {
|
||||
L.LayerGroup.prototype.initialize.call(this);
|
||||
|
||||
this.currentObjects = {}; // id => marker
|
||||
|
||||
this.reDraw = this.reDraw.bind(this);
|
||||
this.onMinetestUpdate = this.onMinetestUpdate.bind(this);
|
||||
},
|
||||
|
||||
createPopup: function(plane) {
|
||||
let name = plane.name;
|
||||
if (!name) name = plane.entity.substring(plane.entity.indexOf(":")+1);
|
||||
|
||||
let html = "<b>" + name + "</b><br>";
|
||||
html += "<hr>";
|
||||
html += "<b>Owner:</b> " + plane.owner + "<br>";
|
||||
html += "<b>Pilot:</b> " + (plane.driver ? plane.driver : "-") + "<br>";
|
||||
html += "<b>Passengers:</b> " + (plane.passenger ? plane.passenger : "-") + "<br>";
|
||||
return html;
|
||||
},
|
||||
|
||||
createMarker: function(plane) {
|
||||
let marker = L.marker([plane.pos.z, plane.pos.x], {icon: this.getIcon(plane)});
|
||||
|
||||
marker.bindPopup(this.createPopup(plane));
|
||||
|
||||
return marker;
|
||||
},
|
||||
|
||||
getIcon: function(plane) {
|
||||
let icon = icons[plane.entity];
|
||||
if (!icon) icon = icons.default;
|
||||
return L.divIcon({
|
||||
html: `<div style="display:inline-block;width:${icon.size}px;height:${icon.size}px;transform:rotate(${plane.yaw*-1}rad);mask:url(${icon.url}) center/contain;-webkit-mask:url(${icon.url}) center/contain;background:${plane.color}">
|
||||
<img src="${icon.url}" style="width:${icon.size}px;height:${icon.size}px;filter:saturate(0%);mix-blend-mode:multiply;" alt="${plane.name}">
|
||||
</div>`,
|
||||
className: '', // don't use leaflet default of a white block
|
||||
iconSize: [icon.size, icon.size],
|
||||
iconAnchor: [icon.size/2, icon.size/2],
|
||||
popupAnchor: [0, -(icon.size/2)]
|
||||
});
|
||||
},
|
||||
|
||||
isInCurrentLayer: function(plane) {
|
||||
let mapLayer = layerMgr.getCurrentLayer();
|
||||
|
||||
return (
|
||||
plane.pos.y >= (mapLayer.from*16) &&
|
||||
plane.pos.y <= ((mapLayer.to*16) + 15)
|
||||
);
|
||||
},
|
||||
|
||||
onMinetestUpdate: function(/*info*/) {
|
||||
|
||||
planes.forEach(plane => {
|
||||
let isInLayer = this.isInCurrentLayer(plane);
|
||||
|
||||
if (!isInLayer) {
|
||||
if (this.currentObjects[plane.id]) {
|
||||
//player is displayed and not on the layer anymore
|
||||
//Remove the marker and reference
|
||||
this.currentObjects[plane.id].remove();
|
||||
delete this.currentObjects[plane.id];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.currentObjects[plane.id]) {
|
||||
//marker exists
|
||||
let marker = this.currentObjects[plane.id];
|
||||
marker.setLatLng([plane.pos.z, plane.pos.x]);
|
||||
marker.setIcon(this.getIcon(plane));
|
||||
marker.setPopupContent(this.createPopup(plane));
|
||||
} else {
|
||||
//marker does not exist
|
||||
let marker = this.createMarker(plane);
|
||||
marker.addTo(this);
|
||||
|
||||
this.currentObjects[plane.id] = marker;
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(this.currentObjects).forEach(existingId => {
|
||||
let planeIsActive = planes.find(function(p) {
|
||||
return p.id == existingId;
|
||||
});
|
||||
|
||||
if (!planeIsActive) {
|
||||
//player
|
||||
this.currentObjects[existingId].remove();
|
||||
delete this.currentObjects[existingId];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
reDraw: function() {
|
||||
this.currentObjects = {};
|
||||
this.clearLayers();
|
||||
|
||||
planes.forEach(plane => {
|
||||
if (!this.isInCurrentLayer(plane)) {
|
||||
//not in current layer
|
||||
return;
|
||||
}
|
||||
|
||||
let marker = this.createMarker(plane);
|
||||
marker.addTo(this);
|
||||
this.currentObjects[plane.id] = marker;
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
onAdd: function(/*map*/) {
|
||||
wsChannel.addListener("minetest-info", this.onMinetestUpdate);
|
||||
this.reDraw();
|
||||
},
|
||||
|
||||
onRemove: function(/*map*/) {
|
||||
this.clearLayers();
|
||||
wsChannel.removeListener("minetest-info", this.onMinetestUpdate);
|
||||
}
|
||||
});
|
BIN
public/pics/airutils_planes/blimp.png
Normal file
BIN
public/pics/airutils_planes/blimp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
BIN
public/pics/airutils_planes/hidro.png
Normal file
BIN
public/pics/airutils_planes/hidro.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
public/pics/airutils_planes/ju52.png
Normal file
BIN
public/pics/airutils_planes/ju52.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
public/pics/airutils_planes/pa28.png
Normal file
BIN
public/pics/airutils_planes/pa28.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
public/pics/airutils_planes/supercub.png
Normal file
BIN
public/pics/airutils_planes/supercub.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
BIN
public/pics/airutils_planes/trike.png
Normal file
BIN
public/pics/airutils_planes/trike.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
@ -53,14 +53,27 @@ type Player struct {
|
||||
//TODO: stamina, skin, etc
|
||||
}
|
||||
|
||||
type AirUtilsPlane struct {
|
||||
Id string `json:"id"`
|
||||
Entity string `json:"entity"`
|
||||
Name string `json:"name"`
|
||||
Pos GenericPos `json:"pos"`
|
||||
Owner string `json:"owner"`
|
||||
Driver string `json:"driver"`
|
||||
Passenger string `json:"passenger"`
|
||||
Color string `json:"color"`
|
||||
Yaw float64 `json:"yaw"`
|
||||
}
|
||||
|
||||
type MinetestInfo struct {
|
||||
MaxLag float64 `json:"max_lag"`
|
||||
Players []*Player `json:"players"`
|
||||
Trains []*Train `json:"trains"`
|
||||
Signals []*Signal `json:"signals"`
|
||||
Minecarts []*Minecart `json:"minecarts"`
|
||||
Time float64 `json:"time"`
|
||||
Uptime float64 `json:"uptime"`
|
||||
MaxLag float64 `json:"max_lag"`
|
||||
Players []*Player `json:"players"`
|
||||
Trains []*Train `json:"trains"`
|
||||
Signals []*Signal `json:"signals"`
|
||||
Minecarts []*Minecart `json:"minecarts"`
|
||||
AirUtilsPlanes []*AirUtilsPlane `json:"airutils_planes"`
|
||||
Time float64 `json:"time"`
|
||||
Uptime float64 `json:"uptime"`
|
||||
}
|
||||
|
||||
var LastStats *MinetestInfo
|
||||
|
Loading…
Reference in New Issue
Block a user