Split DynmapMapProvider build methods into their own file
This commit is contained in:
parent
f90b32c41a
commit
8bf0fe04a7
@ -16,28 +16,24 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
HeadQueueEntry,
|
HeadQueueEntry,
|
||||||
LiveAtlasArea, LiveAtlasChat,
|
|
||||||
LiveAtlasCircle, LiveAtlasComponentConfig,
|
|
||||||
LiveAtlasDimension,
|
|
||||||
LiveAtlasLine,
|
|
||||||
LiveAtlasMarker,
|
|
||||||
LiveAtlasMarkerSet,
|
LiveAtlasMarkerSet,
|
||||||
LiveAtlasPlayer, LiveAtlasServerConfig,
|
LiveAtlasPlayer,
|
||||||
LiveAtlasServerDefinition,
|
LiveAtlasServerDefinition,
|
||||||
LiveAtlasServerMessageConfig,
|
|
||||||
LiveAtlasWorldDefinition
|
LiveAtlasWorldDefinition
|
||||||
} from "@/index";
|
} from "@/index";
|
||||||
import {
|
|
||||||
DynmapMarkerSetUpdates, DynmapTileUpdate, DynmapUpdate
|
|
||||||
} from "@/dynmap";
|
|
||||||
import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition";
|
|
||||||
import ChatError from "@/errors/ChatError";
|
import ChatError from "@/errors/ChatError";
|
||||||
import {MutationTypes} from "@/store/mutation-types";
|
import {MutationTypes} from "@/store/mutation-types";
|
||||||
import MapProvider from "@/providers/MapProvider";
|
import MapProvider from "@/providers/MapProvider";
|
||||||
import {ActionTypes} from "@/store/action-types";
|
import {ActionTypes} from "@/store/action-types";
|
||||||
import {endWorldNameRegex, netherWorldNameRegex, titleColoursRegex} from "@/util";
|
import {
|
||||||
import {getPoints} from "@/util/areas";
|
buildAreas,
|
||||||
import {getLinePoints} from "@/util/lines";
|
buildCircles, buildComponents,
|
||||||
|
buildLines,
|
||||||
|
buildMarkers,
|
||||||
|
buildMarkerSet,
|
||||||
|
buildMessagesConfig,
|
||||||
|
buildServerConfig, buildUpdates, buildWorlds
|
||||||
|
} from "@/util/dynmap";
|
||||||
|
|
||||||
export default class DynmapMapProvider extends MapProvider {
|
export default class DynmapMapProvider extends MapProvider {
|
||||||
private configurationAbort?: AbortController = undefined;
|
private configurationAbort?: AbortController = undefined;
|
||||||
@ -53,534 +49,6 @@ export default class DynmapMapProvider extends MapProvider {
|
|||||||
super(config);
|
super(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static buildServerConfig(response: any): LiveAtlasServerConfig {
|
|
||||||
return {
|
|
||||||
defaultMap: response.defaultmap || undefined,
|
|
||||||
defaultWorld: response.defaultworld || undefined,
|
|
||||||
defaultZoom: response.defaultzoom || 0,
|
|
||||||
followMap: response.followmap || undefined,
|
|
||||||
followZoom: response.followzoom,
|
|
||||||
title: response.title.replace(titleColoursRegex, '') || 'Dynmap',
|
|
||||||
expandUI: response.sidebaropened && response.sidebaropened !== 'false', //Sent as a string for some reason
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static buildMessagesConfig(response: any): LiveAtlasServerMessageConfig {
|
|
||||||
return {
|
|
||||||
chatPlayerJoin: response.joinmessage || '',
|
|
||||||
chatPlayerQuit: response.quitmessage || '',
|
|
||||||
chatAnonymousJoin: response['msg-hiddennamejoin'] || '',
|
|
||||||
chatAnonymousQuit: response['msg-hiddennamequit'] || '',
|
|
||||||
chatErrorNotAllowed: response['msg-chatnotallowed'] || '',
|
|
||||||
chatErrorRequiresLogin: response['msg-chatrequireslogin'] || '',
|
|
||||||
chatErrorCooldown: response.spammessage || '',
|
|
||||||
worldsHeading: response['msg-maptypes'] || '',
|
|
||||||
playersHeading: response['msg-players'] ? `${response['msg-players']} ({cur}/{max})` : '',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildWorlds(response: any): Array<LiveAtlasWorldDefinition> {
|
|
||||||
const worlds: Map<string, LiveAtlasWorldDefinition> = new Map<string, LiveAtlasWorldDefinition>();
|
|
||||||
|
|
||||||
//Get all the worlds first so we can handle append_to_world properly
|
|
||||||
(response.worlds || []).forEach((world: any) => {
|
|
||||||
let worldType: LiveAtlasDimension = 'overworld';
|
|
||||||
|
|
||||||
if (netherWorldNameRegex.test(world.name) || (world.name == 'DIM-1')) {
|
|
||||||
worldType = 'nether';
|
|
||||||
} else if (endWorldNameRegex.test(world.name) || (world.name == 'DIM1')) {
|
|
||||||
worldType = 'end';
|
|
||||||
}
|
|
||||||
|
|
||||||
worlds.set(world.name, {
|
|
||||||
name: world.name,
|
|
||||||
displayName: world.title || '',
|
|
||||||
dimension: worldType,
|
|
||||||
protected: world.protected || false,
|
|
||||||
height: world.height || 256,
|
|
||||||
seaLevel: world.sealevel || 64,
|
|
||||||
center: {
|
|
||||||
x: world.center.x || 0,
|
|
||||||
y: world.center.y || 0,
|
|
||||||
z: world.center.z || 0
|
|
||||||
},
|
|
||||||
maps: new Map(),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
(response.worlds || []).forEach((world: any) => {
|
|
||||||
(world.maps || []).forEach((map: any) => {
|
|
||||||
const worldName = map.append_to_world || world.name,
|
|
||||||
w = worlds.get(worldName);
|
|
||||||
|
|
||||||
if(!w) {
|
|
||||||
console.warn(`Ignoring map '${map.name}' associated with non-existent world '${worldName}'`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
w.maps.set(map.name, Object.freeze(new LiveAtlasMapDefinition({
|
|
||||||
world: w, //Ignore append_to_world here otherwise things break
|
|
||||||
background: map.background || '#000000',
|
|
||||||
backgroundDay: map.backgroundday || '#000000',
|
|
||||||
backgroundNight: map.backgroundnight || '#000000',
|
|
||||||
icon: map.icon || undefined,
|
|
||||||
imageFormat: map['image-format'] || 'png',
|
|
||||||
name: map.name || '(Unnamed map)',
|
|
||||||
nightAndDay: map.nightandday || false,
|
|
||||||
prefix: map.prefix || '',
|
|
||||||
protected: map.protected || false,
|
|
||||||
displayName: map.title || '',
|
|
||||||
mapToWorld: map.maptoworld || undefined,
|
|
||||||
worldToMap: map.worldtomap || undefined,
|
|
||||||
nativeZoomLevels: map.mapzoomout || 1,
|
|
||||||
extraZoomLevels: map.mapzoomin || 0
|
|
||||||
})));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return Array.from(worlds.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildComponents(response: any): LiveAtlasComponentConfig {
|
|
||||||
const components: LiveAtlasComponentConfig = {
|
|
||||||
markers: {
|
|
||||||
showLabels: false,
|
|
||||||
},
|
|
||||||
chatBox: undefined,
|
|
||||||
chatBalloons: false,
|
|
||||||
playerMarkers: undefined,
|
|
||||||
coordinatesControl: undefined,
|
|
||||||
layerControl: response.showlayercontrol && response.showlayercontrol !== 'false', //Sent as a string for some reason
|
|
||||||
linkControl: false,
|
|
||||||
clockControl: undefined,
|
|
||||||
logoControls: [],
|
|
||||||
login: response['login-enabled'] || false,
|
|
||||||
};
|
|
||||||
|
|
||||||
(response.components || []).forEach((component: any) => {
|
|
||||||
const type = component.type || "unknown";
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case "markers":
|
|
||||||
components.markers = {
|
|
||||||
showLabels: component.showlabel || false,
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "playermarkers":
|
|
||||||
components.playerMarkers = {
|
|
||||||
grayHiddenPlayers: response.grayplayerswhenhidden || false,
|
|
||||||
hideByDefault: component.hidebydefault || false,
|
|
||||||
layerName: component.label || "Players",
|
|
||||||
layerPriority: component.layerprio || 0,
|
|
||||||
showBodies: component.showplayerbody || false,
|
|
||||||
showSkinFaces: component.showplayerfaces || false,
|
|
||||||
showHealth: component.showplayerhealth || false,
|
|
||||||
smallFaces: component.smallplayerfaces || false,
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "coord":
|
|
||||||
components.coordinatesControl = {
|
|
||||||
showY: !(component.hidey || false),
|
|
||||||
label: component.label || "Location: ",
|
|
||||||
showRegion: component['show-mcr'] || false,
|
|
||||||
showChunk: component['show-chunk'] || false,
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "link":
|
|
||||||
components.linkControl = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "digitalclock":
|
|
||||||
components.clockControl = {
|
|
||||||
showDigitalClock: true,
|
|
||||||
showWeather: false,
|
|
||||||
showTimeOfDay: false,
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "timeofdayclock":
|
|
||||||
components.clockControl = {
|
|
||||||
showTimeOfDay: true,
|
|
||||||
showDigitalClock: component.showdigitalclock || false,
|
|
||||||
showWeather: component.showweather || false,
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "logo":
|
|
||||||
components.logoControls.push({
|
|
||||||
text: component.text || '',
|
|
||||||
url: component.linkurl || undefined,
|
|
||||||
position: component.position.replace('-', '') || 'topleft',
|
|
||||||
image: component.logourl || undefined,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "chat":
|
|
||||||
if (response.allowwebchat) {
|
|
||||||
components.chatSending = {
|
|
||||||
loginRequired: response['webchat-requires-login'] || false,
|
|
||||||
maxLength: response['chatlengthlimit'] || 256,
|
|
||||||
cooldown: response['webchat-interval'] || 5,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "chatbox":
|
|
||||||
components.chatBox = {
|
|
||||||
allowUrlName: component.allowurlname || false,
|
|
||||||
showPlayerFaces: component.showplayerfaces || false,
|
|
||||||
messageLifetime: component.messagettl || Infinity,
|
|
||||||
messageHistory: component.scrollback || Infinity,
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "chatballoon":
|
|
||||||
components.chatBalloons = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return components;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static buildMarkerSet(id: string, data: any): any {
|
|
||||||
return {
|
|
||||||
id,
|
|
||||||
label: data.label || "Unnamed set",
|
|
||||||
hidden: data.hide || false,
|
|
||||||
priority: data.layerprio || 0,
|
|
||||||
showLabels: data.showlabels || undefined,
|
|
||||||
minZoom: typeof data.minzoom !== 'undefined' && data.minzoom > -1 ? data.minzoom : undefined,
|
|
||||||
maxZoom: typeof data.maxzoom !== 'undefined' && data.maxzoom > -1 ? data.maxzoom : undefined,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static buildMarkers(data: any): Map<string, LiveAtlasMarker> {
|
|
||||||
const markers = Object.freeze(new Map()) as Map<string, LiveAtlasMarker>;
|
|
||||||
|
|
||||||
for (const key in data) {
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
markers.set(key, DynmapMapProvider.buildMarker(data[key]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return markers;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static buildMarker(marker: any): LiveAtlasMarker {
|
|
||||||
return {
|
|
||||||
label: marker.label || '',
|
|
||||||
isLabelHTML: marker.markup || false,
|
|
||||||
location: {
|
|
||||||
x: marker.x || 0,
|
|
||||||
y: marker.y || 0,
|
|
||||||
z: marker.z || 0,
|
|
||||||
},
|
|
||||||
dimensions: marker.dim ? marker.dim.split('x') : [16, 16],
|
|
||||||
icon: marker.icon || "default",
|
|
||||||
minZoom: typeof marker.minzoom !== 'undefined' && marker.minzoom > -1 ? marker.minzoom : undefined,
|
|
||||||
maxZoom: typeof marker.maxzoom !== 'undefined' && marker.maxzoom > -1 ? marker.maxzoom : undefined,
|
|
||||||
popupContent: marker.desc || undefined,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static buildAreas(data: any): Map<string, LiveAtlasArea> {
|
|
||||||
const areas = Object.freeze(new Map()) as Map<string, LiveAtlasArea>;
|
|
||||||
|
|
||||||
for (const key in data) {
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
areas.set(key, DynmapMapProvider.buildArea(data[key]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return areas;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static buildArea(area: any): LiveAtlasArea {
|
|
||||||
const opacity = area.fillopacity || 0,
|
|
||||||
x = area.x || [0, 0],
|
|
||||||
y: [number, number] = [area.ybottom || 0, area.ytop || 0],
|
|
||||||
z = area.z || [0, 0];
|
|
||||||
|
|
||||||
return Object.seal({
|
|
||||||
style: {
|
|
||||||
color: area.color || '#ff0000',
|
|
||||||
opacity: area.opacity || 1,
|
|
||||||
weight: area.weight || 1,
|
|
||||||
fillColor: area.fillcolor || '#ff0000',
|
|
||||||
fillOpacity: area.fillopacity || 0,
|
|
||||||
},
|
|
||||||
outline: !opacity,
|
|
||||||
points: getPoints(x, y, z, !opacity),
|
|
||||||
minZoom: typeof area.minzoom !== 'undefined' && area.minzoom > -1 ? area.minzoom : undefined,
|
|
||||||
maxZoom: typeof area.maxzoom !== 'undefined' && area.maxzoom > -1 ? area.maxzoom : undefined,
|
|
||||||
|
|
||||||
isPopupHTML: area.desc ? true : area.markup || false,
|
|
||||||
popupContent: area.desc || area.label || undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static buildLines(data: any): Map<string, LiveAtlasLine> {
|
|
||||||
const lines = Object.freeze(new Map()) as Map<string, LiveAtlasLine>;
|
|
||||||
|
|
||||||
for (const key in data) {
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
lines.set(key, DynmapMapProvider.buildLine(data[key]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static buildLine(line: any): LiveAtlasLine {
|
|
||||||
return Object.seal({
|
|
||||||
style: {
|
|
||||||
color: line.color || '#ff0000',
|
|
||||||
opacity: line.opacity || 1,
|
|
||||||
weight: line.weight || 1,
|
|
||||||
},
|
|
||||||
points: getLinePoints(line.x || [0, 0], line.y || [0, 0], line.z || [0, 0]),
|
|
||||||
minZoom: typeof line.minzoom !== 'undefined' && line.minzoom > -1 ? line.minzoom : undefined,
|
|
||||||
maxZoom: typeof line.maxzoom !== 'undefined' && line.maxzoom > -1 ? line.maxzoom : undefined,
|
|
||||||
|
|
||||||
isPopupHTML: line.desc ? true : line.markup || false,
|
|
||||||
popupContent: line.desc || line.label || undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static buildCircles(data: any): Map<string, LiveAtlasCircle> {
|
|
||||||
const circles = Object.freeze(new Map()) as Map<string, LiveAtlasCircle>;
|
|
||||||
|
|
||||||
for (const key in data) {
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
circles.set(key, DynmapMapProvider.buildCircle(data[key]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return circles;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static buildCircle(circle: any): LiveAtlasCircle {
|
|
||||||
return Object.seal({
|
|
||||||
location: {
|
|
||||||
x: circle.x || 0,
|
|
||||||
y: circle.y || 0,
|
|
||||||
z: circle.z || 0,
|
|
||||||
},
|
|
||||||
radius: [circle.xr || 0, circle.zr || 0],
|
|
||||||
style: {
|
|
||||||
fillColor: circle.fillcolor || '#ff0000',
|
|
||||||
fillOpacity: circle.fillopacity || 0,
|
|
||||||
color: circle.color || '#ff0000',
|
|
||||||
opacity: circle.opacity || 1,
|
|
||||||
weight: circle.weight || 1,
|
|
||||||
},
|
|
||||||
minZoom: typeof circle.minzoom !== 'undefined' && circle.minzoom > -1 ? circle.minzoom : undefined,
|
|
||||||
maxZoom: typeof circle.maxzoom !== 'undefined' && circle.maxzoom > -1 ? circle.maxzoom : undefined,
|
|
||||||
|
|
||||||
isPopupHTML: circle.desc ? true : circle.markup || false,
|
|
||||||
popupContent: circle.desc || circle.label || undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildUpdates(data: Array<any>) {
|
|
||||||
const updates = {
|
|
||||||
markerSets: new Map<string, DynmapMarkerSetUpdates>(),
|
|
||||||
tiles: [] as DynmapTileUpdate[],
|
|
||||||
chat: [] as LiveAtlasChat[],
|
|
||||||
},
|
|
||||||
dropped = {
|
|
||||||
stale: 0,
|
|
||||||
noSet: 0,
|
|
||||||
noId: 0,
|
|
||||||
unknownType: 0,
|
|
||||||
unknownCType: 0,
|
|
||||||
incomplete: 0,
|
|
||||||
notImplemented: 0,
|
|
||||||
},
|
|
||||||
lastUpdate = this.updateTimestamp;
|
|
||||||
|
|
||||||
let accepted = 0;
|
|
||||||
|
|
||||||
for (const entry of data) {
|
|
||||||
switch (entry.type) {
|
|
||||||
case 'component': {
|
|
||||||
if (lastUpdate && entry.timestamp < lastUpdate) {
|
|
||||||
dropped.stale++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entry.id) {
|
|
||||||
dropped.noId++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Set updates don't have a set field, the id is the set
|
|
||||||
const set = entry.msg.startsWith("set") ? entry.id : entry.set;
|
|
||||||
|
|
||||||
if (!set) {
|
|
||||||
dropped.noSet++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.ctype !== 'markers') {
|
|
||||||
dropped.unknownCType++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!updates.markerSets.has(set)) {
|
|
||||||
updates.markerSets.set(set, {
|
|
||||||
areaUpdates: [],
|
|
||||||
markerUpdates: [],
|
|
||||||
lineUpdates: [],
|
|
||||||
circleUpdates: [],
|
|
||||||
removed: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const markerSetUpdates = updates.markerSets.get(set),
|
|
||||||
update: DynmapUpdate = {
|
|
||||||
id: entry.id,
|
|
||||||
removed: entry.msg.endsWith('deleted'),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (entry.msg.startsWith("set")) {
|
|
||||||
markerSetUpdates!.removed = update.removed;
|
|
||||||
markerSetUpdates!.payload = update.removed ? undefined : DynmapMapProvider.buildMarkerSet(set, entry);
|
|
||||||
} else if (entry.msg.startsWith("marker")) {
|
|
||||||
update.payload = update.removed ? undefined : DynmapMapProvider.buildMarker(entry);
|
|
||||||
markerSetUpdates!.markerUpdates.push(Object.freeze(update));
|
|
||||||
} else if (entry.msg.startsWith("area")) {
|
|
||||||
update.payload = update.removed ? undefined : DynmapMapProvider.buildArea(entry);
|
|
||||||
markerSetUpdates!.areaUpdates.push(Object.freeze(update));
|
|
||||||
|
|
||||||
} else if (entry.msg.startsWith("circle")) {
|
|
||||||
update.payload = update.removed ? undefined : DynmapMapProvider.buildCircle(entry);
|
|
||||||
markerSetUpdates!.circleUpdates.push(Object.freeze(update));
|
|
||||||
|
|
||||||
} else if (entry.msg.startsWith("line")) {
|
|
||||||
update.payload = update.removed ? undefined : DynmapMapProvider.buildLine(entry);
|
|
||||||
markerSetUpdates!.lineUpdates.push(Object.freeze(update));
|
|
||||||
}
|
|
||||||
|
|
||||||
accepted++;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'chat':
|
|
||||||
if (!entry.message || !entry.timestamp) {
|
|
||||||
dropped.incomplete++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.timestamp < lastUpdate) {
|
|
||||||
dropped.stale++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.source !== 'player' && entry.source !== 'web') {
|
|
||||||
dropped.notImplemented++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
updates.chat.push({
|
|
||||||
type: 'chat',
|
|
||||||
source: entry.source || undefined,
|
|
||||||
playerAccount: entry.account || undefined,
|
|
||||||
playerName: entry.playerName || undefined,
|
|
||||||
message: entry.message || "",
|
|
||||||
timestamp: entry.timestamp,
|
|
||||||
channel: entry.channel || undefined,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'playerjoin':
|
|
||||||
if (!entry.account || !entry.timestamp) {
|
|
||||||
dropped.incomplete++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.timestamp < lastUpdate) {
|
|
||||||
dropped.stale++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
updates.chat.push({
|
|
||||||
type: 'playerjoin',
|
|
||||||
playerAccount: entry.account,
|
|
||||||
playerName: entry.playerName || "",
|
|
||||||
timestamp: entry.timestamp || undefined,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'playerquit':
|
|
||||||
if (!entry.account || !entry.timestamp) {
|
|
||||||
dropped.incomplete++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.timestamp < lastUpdate) {
|
|
||||||
dropped.stale++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
updates.chat.push({
|
|
||||||
type: 'playerleave',
|
|
||||||
playerAccount: entry.account,
|
|
||||||
playerName: entry.playerName || "",
|
|
||||||
timestamp: entry.timestamp || undefined,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'tile':
|
|
||||||
if (!entry.name || !entry.timestamp) {
|
|
||||||
dropped.incomplete++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastUpdate && entry.timestamp < lastUpdate) {
|
|
||||||
dropped.stale++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
updates.tiles.push({
|
|
||||||
name: entry.name,
|
|
||||||
timestamp: entry.timestamp,
|
|
||||||
});
|
|
||||||
|
|
||||||
accepted++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
dropped.unknownType++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Sort chat by newest first
|
|
||||||
updates.chat = updates.chat.sort((one, two) => {
|
|
||||||
return two.timestamp - one.timestamp;
|
|
||||||
});
|
|
||||||
|
|
||||||
console.debug(`Updates: ${accepted} accepted. Rejected: `, dropped);
|
|
||||||
|
|
||||||
return updates;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getMarkerSets(world: LiveAtlasWorldDefinition): Promise<Map<string, LiveAtlasMarkerSet>> {
|
private async getMarkerSets(world: LiveAtlasWorldDefinition): Promise<Map<string, LiveAtlasMarkerSet>> {
|
||||||
const url = `${this.config.dynmap!.markers}_markers_/marker_${world.name}.json`;
|
const url = `${this.config.dynmap!.markers}_markers_/marker_${world.name}.json`;
|
||||||
|
|
||||||
@ -601,13 +69,13 @@ export default class DynmapMapProvider extends MapProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const set = response.sets[key],
|
const set = response.sets[key],
|
||||||
markers = DynmapMapProvider.buildMarkers(set.markers || {}),
|
markers = buildMarkers(set.markers || {}),
|
||||||
circles = DynmapMapProvider.buildCircles(set.circles || {}),
|
circles = buildCircles(set.circles || {}),
|
||||||
areas = DynmapMapProvider.buildAreas(set.areas || {}),
|
areas = buildAreas(set.areas || {}),
|
||||||
lines = DynmapMapProvider.buildLines(set.lines || {});
|
lines = buildLines(set.lines || {});
|
||||||
|
|
||||||
sets.set(key, {
|
sets.set(key, {
|
||||||
...DynmapMapProvider.buildMarkerSet(key, set),
|
...buildMarkerSet(key, set),
|
||||||
markers,
|
markers,
|
||||||
circles,
|
circles,
|
||||||
areas,
|
areas,
|
||||||
@ -635,16 +103,16 @@ export default class DynmapMapProvider extends MapProvider {
|
|||||||
throw new Error(response.error);
|
throw new Error(response.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = DynmapMapProvider.buildServerConfig(response);
|
const config = buildServerConfig(response);
|
||||||
|
|
||||||
this.updateInterval = response.updaterate || 3000;
|
this.updateInterval = response.updaterate || 3000;
|
||||||
|
|
||||||
this.store.commit(MutationTypes.SET_SERVER_CONFIGURATION, config);
|
this.store.commit(MutationTypes.SET_SERVER_CONFIGURATION, config);
|
||||||
this.store.commit(MutationTypes.SET_SERVER_CONFIGURATION_HASH, response.confighash || 0);
|
this.store.commit(MutationTypes.SET_SERVER_CONFIGURATION_HASH, response.confighash || 0);
|
||||||
this.store.commit(MutationTypes.SET_MAX_PLAYERS, response.maxcount || 0);
|
this.store.commit(MutationTypes.SET_MAX_PLAYERS, response.maxcount || 0);
|
||||||
this.store.commit(MutationTypes.SET_SERVER_MESSAGES, DynmapMapProvider.buildMessagesConfig(response));
|
this.store.commit(MutationTypes.SET_SERVER_MESSAGES, buildMessagesConfig(response));
|
||||||
this.store.commit(MutationTypes.SET_WORLDS, this.buildWorlds(response));
|
this.store.commit(MutationTypes.SET_WORLDS, buildWorlds(response));
|
||||||
this.store.commit(MutationTypes.SET_COMPONENTS, this.buildComponents(response));
|
this.store.commit(MutationTypes.SET_COMPONENTS, buildComponents(response));
|
||||||
this.store.commit(MutationTypes.SET_LOGGED_IN, response.loggedin || false);
|
this.store.commit(MutationTypes.SET_LOGGED_IN, response.loggedin || false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,7 +135,7 @@ export default class DynmapMapProvider extends MapProvider {
|
|||||||
|
|
||||||
const response = await DynmapMapProvider.getJSON(url, this.updateAbort.signal);
|
const response = await DynmapMapProvider.getJSON(url, this.updateAbort.signal);
|
||||||
const players: Set<LiveAtlasPlayer> = new Set(),
|
const players: Set<LiveAtlasPlayer> = new Set(),
|
||||||
updates = this.buildUpdates(response.updates || []),
|
updates = buildUpdates(response.updates || [], this.updateTimestamp),
|
||||||
worldState = {
|
worldState = {
|
||||||
timeOfDay: response.servertime || 0,
|
timeOfDay: response.servertime || 0,
|
||||||
thundering: response.isThundering || false,
|
thundering: response.isThundering || false,
|
||||||
|
557
src/util/dynmap.ts
Normal file
557
src/util/dynmap.ts
Normal file
@ -0,0 +1,557 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 James Lyne
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {DynmapMarkerSetUpdates, DynmapTileUpdate, DynmapUpdate} from "@/dynmap";
|
||||||
|
import {
|
||||||
|
LiveAtlasArea, LiveAtlasChat,
|
||||||
|
LiveAtlasCircle,
|
||||||
|
LiveAtlasComponentConfig, LiveAtlasDimension,
|
||||||
|
LiveAtlasLine,
|
||||||
|
LiveAtlasMarker, LiveAtlasServerConfig, LiveAtlasServerMessageConfig,
|
||||||
|
LiveAtlasWorldDefinition
|
||||||
|
} from "@/index";
|
||||||
|
import {getPoints} from "@/util/areas";
|
||||||
|
import {endWorldNameRegex, netherWorldNameRegex, titleColoursRegex} from "@/util";
|
||||||
|
import {getLinePoints} from "@/util/lines";
|
||||||
|
import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition";
|
||||||
|
|
||||||
|
export function buildServerConfig(response: any): LiveAtlasServerConfig {
|
||||||
|
return {
|
||||||
|
defaultMap: response.defaultmap || undefined,
|
||||||
|
defaultWorld: response.defaultworld || undefined,
|
||||||
|
defaultZoom: response.defaultzoom || 0,
|
||||||
|
followMap: response.followmap || undefined,
|
||||||
|
followZoom: response.followzoom,
|
||||||
|
title: response.title.replace(titleColoursRegex, '') || 'Dynmap',
|
||||||
|
expandUI: response.sidebaropened && response.sidebaropened !== 'false', //Sent as a string for some reason
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildMessagesConfig(response: any): LiveAtlasServerMessageConfig {
|
||||||
|
return {
|
||||||
|
chatPlayerJoin: response.joinmessage || '',
|
||||||
|
chatPlayerQuit: response.quitmessage || '',
|
||||||
|
chatAnonymousJoin: response['msg-hiddennamejoin'] || '',
|
||||||
|
chatAnonymousQuit: response['msg-hiddennamequit'] || '',
|
||||||
|
chatErrorNotAllowed: response['msg-chatnotallowed'] || '',
|
||||||
|
chatErrorRequiresLogin: response['msg-chatrequireslogin'] || '',
|
||||||
|
chatErrorCooldown: response.spammessage || '',
|
||||||
|
worldsHeading: response['msg-maptypes'] || '',
|
||||||
|
playersHeading: response['msg-players'] ? `${response['msg-players']} ({cur}/{max})` : '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildWorlds(response: any): Array<LiveAtlasWorldDefinition> {
|
||||||
|
const worlds: Map<string, LiveAtlasWorldDefinition> = new Map<string, LiveAtlasWorldDefinition>();
|
||||||
|
|
||||||
|
//Get all the worlds first so we can handle append_to_world properly
|
||||||
|
(response.worlds || []).forEach((world: any) => {
|
||||||
|
let worldType: LiveAtlasDimension = 'overworld';
|
||||||
|
|
||||||
|
if (netherWorldNameRegex.test(world.name) || (world.name == 'DIM-1')) {
|
||||||
|
worldType = 'nether';
|
||||||
|
} else if (endWorldNameRegex.test(world.name) || (world.name == 'DIM1')) {
|
||||||
|
worldType = 'end';
|
||||||
|
}
|
||||||
|
|
||||||
|
worlds.set(world.name, {
|
||||||
|
name: world.name,
|
||||||
|
displayName: world.title || '',
|
||||||
|
dimension: worldType,
|
||||||
|
protected: world.protected || false,
|
||||||
|
height: world.height || 256,
|
||||||
|
seaLevel: world.sealevel || 64,
|
||||||
|
center: {
|
||||||
|
x: world.center.x || 0,
|
||||||
|
y: world.center.y || 0,
|
||||||
|
z: world.center.z || 0
|
||||||
|
},
|
||||||
|
maps: new Map(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
(response.worlds || []).forEach((world: any) => {
|
||||||
|
(world.maps || []).forEach((map: any) => {
|
||||||
|
const actualWorld = worlds.get(world.name),
|
||||||
|
assignedWorldName = map.append_to_world || world.name, //handle append_to_world
|
||||||
|
assignedWorld = worlds.get(assignedWorldName);
|
||||||
|
|
||||||
|
if (!assignedWorld || !actualWorld) {
|
||||||
|
console.warn(`Ignoring map '${map.name}' associated with non-existent world '${assignedWorldName}'`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assignedWorld.maps.set(map.name, Object.freeze(new LiveAtlasMapDefinition({
|
||||||
|
world: actualWorld, //Ignore append_to_world here for Dynmap URL parity
|
||||||
|
background: map.background || '#000000',
|
||||||
|
backgroundDay: map.backgroundday || '#000000',
|
||||||
|
backgroundNight: map.backgroundnight || '#000000',
|
||||||
|
icon: map.icon || undefined,
|
||||||
|
imageFormat: map['image-format'] || 'png',
|
||||||
|
name: map.name || '(Unnamed map)',
|
||||||
|
nightAndDay: map.nightandday || false,
|
||||||
|
prefix: map.prefix || '',
|
||||||
|
protected: map.protected || false,
|
||||||
|
displayName: map.title || '',
|
||||||
|
mapToWorld: map.maptoworld || undefined,
|
||||||
|
worldToMap: map.worldtomap || undefined,
|
||||||
|
nativeZoomLevels: map.mapzoomout || 1,
|
||||||
|
extraZoomLevels: map.mapzoomin || 0
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(worlds.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildComponents(response: any): LiveAtlasComponentConfig {
|
||||||
|
const components: LiveAtlasComponentConfig = {
|
||||||
|
markers: {
|
||||||
|
showLabels: false,
|
||||||
|
},
|
||||||
|
chatBox: undefined,
|
||||||
|
chatBalloons: false,
|
||||||
|
playerMarkers: undefined,
|
||||||
|
coordinatesControl: undefined,
|
||||||
|
layerControl: response.showlayercontrol && response.showlayercontrol !== 'false', //Sent as a string for some reason
|
||||||
|
linkControl: false,
|
||||||
|
clockControl: undefined,
|
||||||
|
logoControls: [],
|
||||||
|
login: response['login-enabled'] || false,
|
||||||
|
};
|
||||||
|
|
||||||
|
(response.components || []).forEach((component: any) => {
|
||||||
|
const type = component.type || "unknown";
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case "markers":
|
||||||
|
components.markers = {
|
||||||
|
showLabels: component.showlabel || false,
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "playermarkers":
|
||||||
|
components.playerMarkers = {
|
||||||
|
grayHiddenPlayers: response.grayplayerswhenhidden || false,
|
||||||
|
hideByDefault: component.hidebydefault || false,
|
||||||
|
layerName: component.label || "Players",
|
||||||
|
layerPriority: component.layerprio || 0,
|
||||||
|
showBodies: component.showplayerbody || false,
|
||||||
|
showSkinFaces: component.showplayerfaces || false,
|
||||||
|
showHealth: component.showplayerhealth || false,
|
||||||
|
smallFaces: component.smallplayerfaces || false,
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "coord":
|
||||||
|
components.coordinatesControl = {
|
||||||
|
showY: !(component.hidey || false),
|
||||||
|
label: component.label || "Location: ",
|
||||||
|
showRegion: component['show-mcr'] || false,
|
||||||
|
showChunk: component['show-chunk'] || false,
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "link":
|
||||||
|
components.linkControl = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "digitalclock":
|
||||||
|
components.clockControl = {
|
||||||
|
showDigitalClock: true,
|
||||||
|
showWeather: false,
|
||||||
|
showTimeOfDay: false,
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "timeofdayclock":
|
||||||
|
components.clockControl = {
|
||||||
|
showTimeOfDay: true,
|
||||||
|
showDigitalClock: component.showdigitalclock || false,
|
||||||
|
showWeather: component.showweather || false,
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "logo":
|
||||||
|
components.logoControls.push({
|
||||||
|
text: component.text || '',
|
||||||
|
url: component.linkurl || undefined,
|
||||||
|
position: component.position.replace('-', '') || 'topleft',
|
||||||
|
image: component.logourl || undefined,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "chat":
|
||||||
|
if (response.allowwebchat) {
|
||||||
|
components.chatSending = {
|
||||||
|
loginRequired: response['webchat-requires-login'] || false,
|
||||||
|
maxLength: response['chatlengthlimit'] || 256,
|
||||||
|
cooldown: response['webchat-interval'] || 5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "chatbox":
|
||||||
|
components.chatBox = {
|
||||||
|
allowUrlName: component.allowurlname || false,
|
||||||
|
showPlayerFaces: component.showplayerfaces || false,
|
||||||
|
messageLifetime: component.messagettl || Infinity,
|
||||||
|
messageHistory: component.scrollback || Infinity,
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "chatballoon":
|
||||||
|
components.chatBalloons = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return components;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildMarkerSet(id: string, data: any): any {
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
label: data.label || "Unnamed set",
|
||||||
|
hidden: data.hide || false,
|
||||||
|
priority: data.layerprio || 0,
|
||||||
|
showLabels: data.showlabels || undefined,
|
||||||
|
minZoom: typeof data.minzoom !== 'undefined' && data.minzoom > -1 ? data.minzoom : undefined,
|
||||||
|
maxZoom: typeof data.maxzoom !== 'undefined' && data.maxzoom > -1 ? data.maxzoom : undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildMarkers(data: any): Map<string, LiveAtlasMarker> {
|
||||||
|
const markers = Object.freeze(new Map()) as Map<string, LiveAtlasMarker>;
|
||||||
|
|
||||||
|
for (const key in data) {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
markers.set(key, buildMarker(data[key]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildMarker(marker: any): LiveAtlasMarker {
|
||||||
|
return Object.seal({
|
||||||
|
label: marker.label || '',
|
||||||
|
isLabelHTML: marker.markup || false,
|
||||||
|
location: {
|
||||||
|
x: marker.x || 0,
|
||||||
|
y: marker.y || 0,
|
||||||
|
z: marker.z || 0,
|
||||||
|
},
|
||||||
|
dimensions: marker.dim ? marker.dim.split('x') : [16, 16],
|
||||||
|
icon: marker.icon || "default",
|
||||||
|
minZoom: typeof marker.minzoom !== 'undefined' && marker.minzoom > -1 ? marker.minzoom : undefined,
|
||||||
|
maxZoom: typeof marker.maxzoom !== 'undefined' && marker.maxzoom > -1 ? marker.maxzoom : undefined,
|
||||||
|
popupContent: marker.desc || undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildAreas(data: any): Map<string, LiveAtlasArea> {
|
||||||
|
const areas = Object.freeze(new Map()) as Map<string, LiveAtlasArea>;
|
||||||
|
|
||||||
|
for (const key in data) {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
areas.set(key, buildArea(data[key]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return areas;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildArea(area: any): LiveAtlasArea {
|
||||||
|
const opacity = area.fillopacity || 0,
|
||||||
|
x = area.x || [0, 0],
|
||||||
|
y: [number, number] = [area.ybottom || 0, area.ytop || 0],
|
||||||
|
z = area.z || [0, 0];
|
||||||
|
|
||||||
|
return Object.seal({
|
||||||
|
style: {
|
||||||
|
color: area.color || '#ff0000',
|
||||||
|
opacity: area.opacity || 1,
|
||||||
|
weight: area.weight || 1,
|
||||||
|
fillColor: area.fillcolor || '#ff0000',
|
||||||
|
fillOpacity: area.fillopacity || 0,
|
||||||
|
},
|
||||||
|
outline: !opacity,
|
||||||
|
points: getPoints(x, y, z, !opacity),
|
||||||
|
minZoom: typeof area.minzoom !== 'undefined' && area.minzoom > -1 ? area.minzoom : undefined,
|
||||||
|
maxZoom: typeof area.maxzoom !== 'undefined' && area.maxzoom > -1 ? area.maxzoom : undefined,
|
||||||
|
|
||||||
|
isPopupHTML: area.desc ? true : area.markup || false,
|
||||||
|
popupContent: area.desc || area.label || undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildLines(data: any): Map<string, LiveAtlasLine> {
|
||||||
|
const lines = Object.freeze(new Map()) as Map<string, LiveAtlasLine>;
|
||||||
|
|
||||||
|
for (const key in data) {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.set(key, buildLine(data[key]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildLine(line: any): LiveAtlasLine {
|
||||||
|
return Object.seal({
|
||||||
|
style: {
|
||||||
|
color: line.color || '#ff0000',
|
||||||
|
opacity: line.opacity || 1,
|
||||||
|
weight: line.weight || 1,
|
||||||
|
},
|
||||||
|
points: getLinePoints(line.x || [0, 0], line.y || [0, 0], line.z || [0, 0]),
|
||||||
|
minZoom: typeof line.minzoom !== 'undefined' && line.minzoom > -1 ? line.minzoom : undefined,
|
||||||
|
maxZoom: typeof line.maxzoom !== 'undefined' && line.maxzoom > -1 ? line.maxzoom : undefined,
|
||||||
|
|
||||||
|
isPopupHTML: line.desc ? true : line.markup || false,
|
||||||
|
popupContent: line.desc || line.label || undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildCircles(data: any): Map<string, LiveAtlasCircle> {
|
||||||
|
const circles = Object.freeze(new Map()) as Map<string, LiveAtlasCircle>;
|
||||||
|
|
||||||
|
for (const key in data) {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
circles.set(key, buildCircle(data[key]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return circles;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildCircle(circle: any): LiveAtlasCircle {
|
||||||
|
return Object.seal({
|
||||||
|
location: {
|
||||||
|
x: circle.x || 0,
|
||||||
|
y: circle.y || 0,
|
||||||
|
z: circle.z || 0,
|
||||||
|
},
|
||||||
|
radius: [circle.xr || 0, circle.zr || 0],
|
||||||
|
style: {
|
||||||
|
fillColor: circle.fillcolor || '#ff0000',
|
||||||
|
fillOpacity: circle.fillopacity || 0,
|
||||||
|
color: circle.color || '#ff0000',
|
||||||
|
opacity: circle.opacity || 1,
|
||||||
|
weight: circle.weight || 1,
|
||||||
|
},
|
||||||
|
minZoom: typeof circle.minzoom !== 'undefined' && circle.minzoom > -1 ? circle.minzoom : undefined,
|
||||||
|
maxZoom: typeof circle.maxzoom !== 'undefined' && circle.maxzoom > -1 ? circle.maxzoom : undefined,
|
||||||
|
|
||||||
|
isPopupHTML: circle.desc ? true : circle.markup || false,
|
||||||
|
popupContent: circle.desc || circle.label || undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildUpdates(data: Array<any>, lastUpdate: Date) {
|
||||||
|
const updates = {
|
||||||
|
markerSets: new Map<string, DynmapMarkerSetUpdates>(),
|
||||||
|
tiles: [] as DynmapTileUpdate[],
|
||||||
|
chat: [] as LiveAtlasChat[],
|
||||||
|
},
|
||||||
|
dropped = {
|
||||||
|
stale: 0,
|
||||||
|
noSet: 0,
|
||||||
|
noId: 0,
|
||||||
|
unknownType: 0,
|
||||||
|
unknownCType: 0,
|
||||||
|
incomplete: 0,
|
||||||
|
notImplemented: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let accepted = 0;
|
||||||
|
|
||||||
|
for (const entry of data) {
|
||||||
|
switch (entry.type) {
|
||||||
|
case 'component': {
|
||||||
|
if (lastUpdate && entry.timestamp < lastUpdate) {
|
||||||
|
dropped.stale++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry.id) {
|
||||||
|
dropped.noId++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set updates don't have a set field, the id is the set
|
||||||
|
const set = entry.msg.startsWith("set") ? entry.id : entry.set;
|
||||||
|
|
||||||
|
if (!set) {
|
||||||
|
dropped.noSet++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.ctype !== 'markers') {
|
||||||
|
dropped.unknownCType++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!updates.markerSets.has(set)) {
|
||||||
|
updates.markerSets.set(set, {
|
||||||
|
areaUpdates: [],
|
||||||
|
markerUpdates: [],
|
||||||
|
lineUpdates: [],
|
||||||
|
circleUpdates: [],
|
||||||
|
removed: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const markerSetUpdates = updates.markerSets.get(set),
|
||||||
|
update: DynmapUpdate = {
|
||||||
|
id: entry.id,
|
||||||
|
removed: entry.msg.endsWith('deleted'),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (entry.msg.startsWith("set")) {
|
||||||
|
markerSetUpdates!.removed = update.removed;
|
||||||
|
markerSetUpdates!.payload = update.removed ? undefined : buildMarkerSet(set, entry);
|
||||||
|
} else if (entry.msg.startsWith("marker")) {
|
||||||
|
update.payload = update.removed ? undefined : buildMarker(entry);
|
||||||
|
markerSetUpdates!.markerUpdates.push(Object.freeze(update));
|
||||||
|
} else if (entry.msg.startsWith("area")) {
|
||||||
|
update.payload = update.removed ? undefined : buildArea(entry);
|
||||||
|
markerSetUpdates!.areaUpdates.push(Object.freeze(update));
|
||||||
|
|
||||||
|
} else if (entry.msg.startsWith("circle")) {
|
||||||
|
update.payload = update.removed ? undefined : buildCircle(entry);
|
||||||
|
markerSetUpdates!.circleUpdates.push(Object.freeze(update));
|
||||||
|
|
||||||
|
} else if (entry.msg.startsWith("line")) {
|
||||||
|
update.payload = update.removed ? undefined : buildLine(entry);
|
||||||
|
markerSetUpdates!.lineUpdates.push(Object.freeze(update));
|
||||||
|
}
|
||||||
|
|
||||||
|
accepted++;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'chat':
|
||||||
|
if (!entry.message || !entry.timestamp) {
|
||||||
|
dropped.incomplete++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.timestamp < lastUpdate) {
|
||||||
|
dropped.stale++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.source !== 'player' && entry.source !== 'web') {
|
||||||
|
dropped.notImplemented++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
updates.chat.push({
|
||||||
|
type: 'chat',
|
||||||
|
source: entry.source || undefined,
|
||||||
|
playerAccount: entry.account || undefined,
|
||||||
|
playerName: entry.playerName || undefined,
|
||||||
|
message: entry.message || "",
|
||||||
|
timestamp: entry.timestamp,
|
||||||
|
channel: entry.channel || undefined,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'playerjoin':
|
||||||
|
if (!entry.account || !entry.timestamp) {
|
||||||
|
dropped.incomplete++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.timestamp < lastUpdate) {
|
||||||
|
dropped.stale++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
updates.chat.push({
|
||||||
|
type: 'playerjoin',
|
||||||
|
playerAccount: entry.account,
|
||||||
|
playerName: entry.playerName || "",
|
||||||
|
timestamp: entry.timestamp || undefined,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'playerquit':
|
||||||
|
if (!entry.account || !entry.timestamp) {
|
||||||
|
dropped.incomplete++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.timestamp < lastUpdate) {
|
||||||
|
dropped.stale++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
updates.chat.push({
|
||||||
|
type: 'playerleave',
|
||||||
|
playerAccount: entry.account,
|
||||||
|
playerName: entry.playerName || "",
|
||||||
|
timestamp: entry.timestamp || undefined,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'tile':
|
||||||
|
if (!entry.name || !entry.timestamp) {
|
||||||
|
dropped.incomplete++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastUpdate && entry.timestamp < lastUpdate) {
|
||||||
|
dropped.stale++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
updates.tiles.push({
|
||||||
|
name: entry.name,
|
||||||
|
timestamp: entry.timestamp,
|
||||||
|
});
|
||||||
|
|
||||||
|
accepted++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dropped.unknownType++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sort chat by newest first
|
||||||
|
updates.chat = updates.chat.sort((one, two) => {
|
||||||
|
return two.timestamp - one.timestamp;
|
||||||
|
});
|
||||||
|
|
||||||
|
console.debug(`Updates: ${accepted} accepted. Rejected: `, dropped);
|
||||||
|
|
||||||
|
return updates;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user