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,
|
Minecart: false,
|
||||||
Locator: false,
|
Locator: false,
|
||||||
Signs: true,
|
Signs: true,
|
||||||
|
MapserverAirutils: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
mapblockaccessor := MapBlockAccessorConfig{
|
mapblockaccessor := MapBlockAccessorConfig{
|
||||||
|
@ -61,6 +61,7 @@ type MapObjectConfig struct {
|
|||||||
Minecart bool `json:"minecart"`
|
Minecart bool `json:"minecart"`
|
||||||
Locator bool `json:"locator"`
|
Locator bool `json:"locator"`
|
||||||
Signs bool `json:"signs"`
|
Signs bool `json:"signs"`
|
||||||
|
MapserverAirutils bool `json:"mapserver_airutils"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebApiConfig struct {
|
type WebApiConfig struct {
|
||||||
|
@ -59,7 +59,8 @@
|
|||||||
"trainsignal": true,
|
"trainsignal": true,
|
||||||
"minecart": false,
|
"minecart": false,
|
||||||
"locator": false,
|
"locator": false,
|
||||||
"signs": true
|
"signs": true,
|
||||||
|
"mapserver_airutils": true
|
||||||
},
|
},
|
||||||
"mapblockaccessor": {
|
"mapblockaccessor": {
|
||||||
"expiretime": "15s",
|
"expiretime": "15s",
|
||||||
|
@ -8,6 +8,7 @@ you get more realtime-data from within your minetest-world:
|
|||||||
|
|
||||||
* Current players with their positions
|
* Current players with their positions
|
||||||
* Current time and max lag
|
* 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:
|
You can use the `mapserver-mod` either passive or active:
|
||||||
* *Passive* Makes some additional markers available (POI, Labels, etc)
|
* *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 TrainOverlay from './overlays/TrainOverlay.js';
|
||||||
import TrainsignalOverlay from './overlays/TrainsignalOverlay.js';
|
import TrainsignalOverlay from './overlays/TrainsignalOverlay.js';
|
||||||
import SignOverlay from './overlays/SignOverlay.js';
|
import SignOverlay from './overlays/SignOverlay.js';
|
||||||
|
import AirUtilsPlanesOverlay from "./overlays/AirUtilsPlanesOverlay.js";
|
||||||
|
|
||||||
export default function(cfg, map, overlays, wsChannel){
|
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
|
//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 {
|
type MinetestInfo struct {
|
||||||
MaxLag float64 `json:"max_lag"`
|
MaxLag float64 `json:"max_lag"`
|
||||||
Players []*Player `json:"players"`
|
Players []*Player `json:"players"`
|
||||||
Trains []*Train `json:"trains"`
|
Trains []*Train `json:"trains"`
|
||||||
Signals []*Signal `json:"signals"`
|
Signals []*Signal `json:"signals"`
|
||||||
Minecarts []*Minecart `json:"minecarts"`
|
Minecarts []*Minecart `json:"minecarts"`
|
||||||
Time float64 `json:"time"`
|
AirUtilsPlanes []*AirUtilsPlane `json:"airutils_planes"`
|
||||||
Uptime float64 `json:"uptime"`
|
Time float64 `json:"time"`
|
||||||
|
Uptime float64 `json:"uptime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var LastStats *MinetestInfo
|
var LastStats *MinetestInfo
|
||||||
|
Loading…
Reference in New Issue
Block a user