Merge branch 'pl3xmap'
This commit is contained in:
commit
f2bfbf732a
13
src/App.vue
13
src/App.vue
@ -29,6 +29,7 @@ import {useStore} from "@/store";
|
|||||||
import {ActionTypes} from "@/store/action-types";
|
import {ActionTypes} from "@/store/action-types";
|
||||||
import {parseUrl} from '@/util';
|
import {parseUrl} from '@/util';
|
||||||
import {MutationTypes} from "@/store/mutation-types";
|
import {MutationTypes} from "@/store/mutation-types";
|
||||||
|
import {LiveAtlasServerDefinition} from "@/index";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'App',
|
name: 'App',
|
||||||
@ -62,7 +63,7 @@ export default defineComponent({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const error = `Failed to load server configuration for '${store.state.currentServer}'`;
|
const error = `Failed to load server configuration for '${store.state.currentServer.id}'`;
|
||||||
console.error(`${error}:`, e);
|
console.error(`${error}:`, e);
|
||||||
window.showSplashError(`${error}\n${e}`, false, ++configAttempts.value);
|
window.showSplashError(`${error}\n${e}`, false, ++configAttempts.value);
|
||||||
setTimeout(() => loadConfiguration(), 1000);
|
setTimeout(() => loadConfiguration(), 1000);
|
||||||
@ -125,10 +126,14 @@ export default defineComponent({
|
|||||||
|
|
||||||
watch(title, (title) => document.title = title);
|
watch(title, (title) => document.title = title);
|
||||||
watch(currentUrl, (url) => window.history.replaceState({}, '', url));
|
watch(currentUrl, (url) => window.history.replaceState({}, '', url));
|
||||||
watch(currentServer, (newServer) => {
|
watch(currentServer, (newServer: LiveAtlasServerDefinition) => {
|
||||||
window.showSplash();
|
window.showSplash();
|
||||||
stopUpdates();
|
stopUpdates();
|
||||||
|
|
||||||
|
if(!newServer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Cleanup
|
//Cleanup
|
||||||
store.commit(MutationTypes.CLEAR_PLAYERS, undefined);
|
store.commit(MutationTypes.CLEAR_PLAYERS, undefined);
|
||||||
store.commit(MutationTypes.CLEAR_CURRENT_MAP, undefined);
|
store.commit(MutationTypes.CLEAR_CURRENT_MAP, undefined);
|
||||||
@ -136,9 +141,9 @@ export default defineComponent({
|
|||||||
store.commit(MutationTypes.CLEAR_WORLDS, undefined);
|
store.commit(MutationTypes.CLEAR_WORLDS, undefined);
|
||||||
store.commit(MutationTypes.CLEAR_MARKER_SETS, undefined);
|
store.commit(MutationTypes.CLEAR_MARKER_SETS, undefined);
|
||||||
|
|
||||||
window.history.replaceState({}, '', newServer);
|
window.history.replaceState({}, '', newServer.id);
|
||||||
loadConfiguration();
|
loadConfiguration();
|
||||||
});
|
}, {deep: true});
|
||||||
watch(configurationHash, (newHash, oldHash) => {
|
watch(configurationHash, (newHash, oldHash) => {
|
||||||
if(newHash && oldHash) {
|
if(newHash && oldHash) {
|
||||||
window.showSplash();
|
window.showSplash();
|
||||||
|
106
src/api.ts
106
src/api.ts
@ -30,14 +30,12 @@ import {
|
|||||||
DynmapTileUpdate,
|
DynmapTileUpdate,
|
||||||
DynmapUpdate,
|
DynmapUpdate,
|
||||||
DynmapUpdateResponse,
|
DynmapUpdateResponse,
|
||||||
DynmapUpdates, DynmapUrlConfig,
|
DynmapUpdates,
|
||||||
DynmapWorld,
|
DynmapWorld,
|
||||||
DynmapWorldMap
|
DynmapWorldMap
|
||||||
} from "@/dynmap";
|
} from "@/dynmap";
|
||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
import ChatError from "@/errors/ChatError";
|
import ChatError from "@/errors/ChatError";
|
||||||
import {LiveAtlasDynmapServerDefinition, LiveAtlasServerDefinition} from "@/index";
|
|
||||||
import ConfigurationError from "@/errors/ConfigurationError";
|
|
||||||
|
|
||||||
const titleColours = /§[0-9a-f]/ig;
|
const titleColours = /§[0-9a-f]/ig;
|
||||||
|
|
||||||
@ -556,96 +554,6 @@ function buildUpdates(data: Array<any>): DynmapUpdates {
|
|||||||
return updates;
|
return updates;
|
||||||
}
|
}
|
||||||
|
|
||||||
const validateLiveAtlasConfiguration = (config: any): Map<string, LiveAtlasServerDefinition> => {
|
|
||||||
const check = '\nCheck your server configuration in index.html is correct.',
|
|
||||||
result = new Map<string, LiveAtlasServerDefinition>();
|
|
||||||
|
|
||||||
if (!Object.keys(config).length) {
|
|
||||||
throw new ConfigurationError(`No servers defined. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const server in config) {
|
|
||||||
if (!Object.hasOwnProperty.call(config, server)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const serverConfig = config[server];
|
|
||||||
|
|
||||||
if (!serverConfig || serverConfig.constructor !== Object || !Object.keys(serverConfig).length) {
|
|
||||||
throw new ConfigurationError(`Server '${server}': Configuration missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
serverConfig.id = server;
|
|
||||||
serverConfig.type = 'dynmap';
|
|
||||||
|
|
||||||
if (!serverConfig.dynmap || serverConfig.dynmap.constructor !== Object) {
|
|
||||||
throw new ConfigurationError(`Server '${server}': Dynmap configuration object missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!serverConfig.dynmap.configuration) {
|
|
||||||
throw new ConfigurationError(`Server '${server}': Dynmap configuration URL missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!serverConfig.dynmap.update) {
|
|
||||||
throw new ConfigurationError(`Server '${server}': Dynmap update URL missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!serverConfig.dynmap.markers) {
|
|
||||||
throw new ConfigurationError(`Server '${server}': Dynmap markers URL missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!serverConfig.dynmap.tiles) {
|
|
||||||
throw new ConfigurationError(`Server '${server}': Dynmap tiles URL missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!serverConfig.dynmap.sendmessage) {
|
|
||||||
throw new ConfigurationError(`Server '${server}': Dynmap sendmessage URL missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.set(server, serverConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateDynmapConfiguration = (config: DynmapUrlConfig): Map<string, LiveAtlasDynmapServerDefinition> => {
|
|
||||||
const check = '\nCheck your standalone/config.js file exists and is being loaded correctly.';
|
|
||||||
|
|
||||||
if (!config) {
|
|
||||||
throw new ConfigurationError(`Dynmap configuration is missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.configuration) {
|
|
||||||
throw new ConfigurationError(`Dynmap configuration URL is missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.update) {
|
|
||||||
throw new ConfigurationError(`Dynmap update URL is missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.markers) {
|
|
||||||
throw new ConfigurationError(`Dynmap markers URL is missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.tiles) {
|
|
||||||
throw new ConfigurationError(`Dynmap tiles URL is missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.sendmessage) {
|
|
||||||
throw new ConfigurationError(`Dynmap sendmessage URL is missing. ${check}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = new Map<string, LiveAtlasDynmapServerDefinition>();
|
|
||||||
result.set('dynmap', {
|
|
||||||
id: 'dynmap',
|
|
||||||
label: 'dynmap',
|
|
||||||
type: 'dynmap',
|
|
||||||
dynmap: config
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
async function fetchJSON(url: string, signal: AbortSignal) {
|
async function fetchJSON(url: string, signal: AbortSignal) {
|
||||||
let response, json;
|
let response, json;
|
||||||
|
|
||||||
@ -685,18 +593,6 @@ let configurationAbort: AbortController | undefined = undefined,
|
|||||||
updateAbort: AbortController | undefined = undefined;
|
updateAbort: AbortController | undefined = undefined;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
validateConfiguration(): Map<string, LiveAtlasServerDefinition> {
|
|
||||||
if (!window.liveAtlasConfig) {
|
|
||||||
throw new ConfigurationError(`Configuration object is missing`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof window.liveAtlasConfig.servers !== 'undefined') {
|
|
||||||
return validateLiveAtlasConfiguration(window.liveAtlasConfig.servers || {});
|
|
||||||
}
|
|
||||||
|
|
||||||
return validateDynmapConfiguration(window.config?.url || null);
|
|
||||||
},
|
|
||||||
|
|
||||||
async getConfiguration(): Promise<DynmapConfigurationResponse> {
|
async getConfiguration(): Promise<DynmapConfigurationResponse> {
|
||||||
if(configurationAbort) {
|
if(configurationAbort) {
|
||||||
configurationAbort.abort();
|
configurationAbort.abort();
|
||||||
|
@ -19,10 +19,10 @@ import {defineComponent, onUnmounted, computed, watch} from "@vue/runtime-core";
|
|||||||
import {DynmapWorldMap} from "@/dynmap";
|
import {DynmapWorldMap} from "@/dynmap";
|
||||||
import {Map} from 'leaflet';
|
import {Map} from 'leaflet';
|
||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
import {HDMapType} from "@/leaflet/mapType/HDMapType";
|
|
||||||
import {MutationTypes} from "@/store/mutation-types";
|
import {MutationTypes} from "@/store/mutation-types";
|
||||||
import {ActionTypes} from "@/store/action-types";
|
import {ActionTypes} from "@/store/action-types";
|
||||||
import {getMinecraftTime} from "@/util";
|
import {getMinecraftTime} from "@/util";
|
||||||
|
import {DynmapTileLayer} from "@/leaflet/tileLayer/DynmapTileLayer";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@ -46,7 +46,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
const store = useStore(),
|
const store = useStore(),
|
||||||
night = computed(() => getMinecraftTime(store.state.currentWorldState.timeOfDay).night),
|
night = computed(() => getMinecraftTime(store.state.currentWorldState.timeOfDay).night),
|
||||||
layer = new HDMapType({
|
layer = new DynmapTileLayer({
|
||||||
errorTileUrl: 'images/blank.png',
|
errorTileUrl: 'images/blank.png',
|
||||||
mapSettings: Object.freeze(JSON.parse(JSON.stringify(props.map))),
|
mapSettings: Object.freeze(JSON.parse(JSON.stringify(props.map))),
|
||||||
night: night.value,
|
night: night.value,
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<li :class="{'server': true, 'server--selected': server.id === currentServer}">
|
<li :class="{'server': true, 'server--selected': server.id === currentServer.id}">
|
||||||
<button type="button" :class="{'active': server.id === currentServer}"
|
<button type="button" :class="{'active': server.id === currentServer.id}"
|
||||||
:title="server.label || server.id" @click="setCurrentServer(server.id)">{{ server.label || server.id }}
|
:title="server.label || server.id" @click="setCurrentServer(server.id)">{{ server.label || server.id }}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
@ -38,7 +38,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
currentServer(): string | undefined {
|
currentServer(): LiveAtlasServerDefinition | undefined {
|
||||||
return useStore().state.currentServer;
|
return useStore().state.currentServer;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 James Lyne
|
|
||||||
*
|
|
||||||
* Some portions of this file were taken from https://github.com/webbukkit/dynmap.
|
|
||||||
* These portions are Copyright 2020 Dynmap Contributors.
|
|
||||||
*
|
|
||||||
* 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 {Util} from 'leaflet';
|
|
||||||
import HDProjection from "@/leaflet/projection/HDProjection";
|
|
||||||
import {Coordinate} from "@/dynmap";
|
|
||||||
import {DynmapTileLayer, DynmapTileLayerOptions} from "@/leaflet/tileLayer/DynmapTileLayer";
|
|
||||||
|
|
||||||
export interface HDMapTypeOptions extends DynmapTileLayerOptions {}
|
|
||||||
|
|
||||||
export interface HDMapType extends DynmapTileLayer {
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HDMapType extends DynmapTileLayer {
|
|
||||||
constructor(options: DynmapTileLayerOptions) {
|
|
||||||
super(options);
|
|
||||||
|
|
||||||
options.maxZoom = this._mapSettings.nativeZoomLevels + this._mapSettings.extraZoomLevels;
|
|
||||||
options.maxNativeZoom = this._mapSettings.nativeZoomLevels;
|
|
||||||
options.zoomReverse = true;
|
|
||||||
options.tileSize = 128;
|
|
||||||
options.minZoom = 0;
|
|
||||||
|
|
||||||
Util.setOptions(this, options);
|
|
||||||
this._projection = Object.freeze(new HDProjection({
|
|
||||||
mapToWorld: this._mapSettings.mapToWorld,
|
|
||||||
worldToMap: this._mapSettings.worldToMap,
|
|
||||||
nativeZoomLevels: this._mapSettings.nativeZoomLevels,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
getTileName(coords: Coordinate) {
|
|
||||||
const info = super.getTileInfo(coords);
|
|
||||||
// Y is inverted for HD-map.
|
|
||||||
info.y = -info.y;
|
|
||||||
info.scaledy = info.y >> 5;
|
|
||||||
return `${info.prefix}${info.nightday}/${info.scaledx}_${info.scaledy}/${info.zoom}${info.x}_${info.y}.${info.fmt}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
zoomprefix(amount: number) {
|
|
||||||
// amount == 0 -> ''
|
|
||||||
// amount == 1 -> 'z_'
|
|
||||||
// amount == 2 -> 'zz_'
|
|
||||||
return 'z'.repeat(amount) + (amount === 0 ? '' : '_');
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,25 +20,42 @@
|
|||||||
import {Util, LatLng, Class} from 'leaflet';
|
import {Util, LatLng, Class} from 'leaflet';
|
||||||
import {Coordinate} from "@/dynmap";
|
import {Coordinate} from "@/dynmap";
|
||||||
|
|
||||||
export interface DynmapProjectionOptions {}
|
export interface DynmapProjectionOptions {
|
||||||
|
mapToWorld: [number, number, number, number, number, number, number, number, number],
|
||||||
|
worldToMap: [number, number, number, number, number, number, number, number, number],
|
||||||
|
nativeZoomLevels: number
|
||||||
|
}
|
||||||
|
|
||||||
export interface DynmapProjection {
|
export interface DynmapProjection {
|
||||||
|
options: DynmapProjectionOptions
|
||||||
locationToLatLng(location: Coordinate): LatLng;
|
locationToLatLng(location: Coordinate): LatLng;
|
||||||
latLngToLocation(latLng: LatLng, y: number): Coordinate;
|
latLngToLocation(latLng: LatLng, y: number): Coordinate;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DynmapProjection extends Class {
|
export class DynmapProjection extends Class {
|
||||||
|
|
||||||
constructor(options?: DynmapProjectionOptions) {
|
constructor(options: DynmapProjectionOptions) {
|
||||||
super();
|
super();
|
||||||
Util.setOptions(this, options);
|
Util.setOptions(this, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
locationToLatLng(location: Coordinate): LatLng {
|
locationToLatLng(location: Coordinate): LatLng {
|
||||||
return new LatLng(location.x, location.z);
|
const wtp = this.options.worldToMap,
|
||||||
|
lat = wtp[3] * location.x + wtp[4] * location.y + wtp[5] * location.z,
|
||||||
|
lng = wtp[0] * location.x + wtp[1] * location.y + wtp[2] * location.z;
|
||||||
|
|
||||||
|
return new LatLng(
|
||||||
|
-((128 - lat) / (1 << this.options.nativeZoomLevels)),
|
||||||
|
lng / (1 << this.options.nativeZoomLevels));
|
||||||
}
|
}
|
||||||
|
|
||||||
latLngToLocation(latLng: LatLng, y: number): Coordinate {
|
latLngToLocation(latLng: LatLng, y: number): Coordinate {
|
||||||
return {x: latLng.lat, y, z: latLng.lng};
|
const ptw = this.options.mapToWorld,
|
||||||
|
lat = latLng.lng * (1 << this.options.nativeZoomLevels),
|
||||||
|
lon = 128 + latLng.lat * (1 << this.options.nativeZoomLevels),
|
||||||
|
x = ptw[0] * lat + ptw[1] * lon + ptw[2] * y,
|
||||||
|
z = ptw[6] * lat + ptw[7] * lon + ptw[8] * y;
|
||||||
|
|
||||||
|
return {x: x, y: y, z: z};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 James Lyne
|
|
||||||
*
|
|
||||||
* Some portions of this file were taken from https://github.com/webbukkit/dynmap.
|
|
||||||
* These portions are Copyright 2020 Dynmap Contributors.
|
|
||||||
*
|
|
||||||
* 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 {DynmapProjection} from "@/leaflet/projection/DynmapProjection";
|
|
||||||
import {Util, LatLng} from 'leaflet';
|
|
||||||
import {Coordinate} from "@/dynmap";
|
|
||||||
|
|
||||||
export interface HDProjectionOptions {
|
|
||||||
mapToWorld: [number, number, number, number, number, number, number, number, number],
|
|
||||||
worldToMap: [number, number, number, number, number, number, number, number, number],
|
|
||||||
nativeZoomLevels: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HDProjection extends DynmapProjection {
|
|
||||||
options: HDProjectionOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HDProjection extends DynmapProjection {
|
|
||||||
constructor(options: HDProjectionOptions) {
|
|
||||||
super(options);
|
|
||||||
Util.setOptions(this, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
locationToLatLng(location: Coordinate): LatLng {
|
|
||||||
const wtp = this.options.worldToMap,
|
|
||||||
lat = wtp[3] * location.x + wtp[4] * location.y + wtp[5] * location.z,
|
|
||||||
lng = wtp[0] * location.x + wtp[1] * location.y + wtp[2] * location.z;
|
|
||||||
|
|
||||||
return new LatLng(
|
|
||||||
-((128 - lat) / (1 << this.options.nativeZoomLevels)),
|
|
||||||
lng / (1 << this.options.nativeZoomLevels));
|
|
||||||
}
|
|
||||||
|
|
||||||
latLngToLocation(latLng: LatLng, y: number): Coordinate {
|
|
||||||
const ptw = this.options.mapToWorld,
|
|
||||||
lat = latLng.lng * (1 << this.options.nativeZoomLevels),
|
|
||||||
lon = 128 + latLng.lat * (1 << this.options.nativeZoomLevels),
|
|
||||||
x = ptw[0] * lat + ptw[1] * lon + ptw[2] * y,
|
|
||||||
z = ptw[6] * lat + ptw[7] * lon + ptw[8] * y;
|
|
||||||
|
|
||||||
return {x: x, y: y, z: z};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default HDProjection;
|
|
@ -69,18 +69,29 @@ export interface TileInfo {
|
|||||||
fmt: string;
|
fmt: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
export class DynmapTileLayer extends TileLayer {
|
export class DynmapTileLayer extends TileLayer {
|
||||||
|
|
||||||
constructor(options: DynmapTileLayerOptions) {
|
constructor(options: DynmapTileLayerOptions) {
|
||||||
super('', options);
|
super('', options);
|
||||||
|
|
||||||
|
this._mapSettings = options.mapSettings;
|
||||||
|
options.maxZoom = this._mapSettings.nativeZoomLevels + this._mapSettings.extraZoomLevels;
|
||||||
|
options.maxNativeZoom = this._mapSettings.nativeZoomLevels;
|
||||||
|
options.zoomReverse = true;
|
||||||
|
options.tileSize = 128;
|
||||||
|
options.minZoom = 0;
|
||||||
|
|
||||||
Util.setOptions(this, options);
|
Util.setOptions(this, options);
|
||||||
|
|
||||||
if (options.mapSettings === null) {
|
if (options.mapSettings === null) {
|
||||||
throw new TypeError("mapSettings missing");
|
throw new TypeError("mapSettings missing");
|
||||||
}
|
}
|
||||||
|
|
||||||
this._projection = new DynmapProjection({});
|
this._projection = new DynmapProjection({
|
||||||
this._mapSettings = options.mapSettings;
|
mapToWorld: this._mapSettings.mapToWorld,
|
||||||
|
worldToMap: this._mapSettings.worldToMap,
|
||||||
|
nativeZoomLevels: this._mapSettings.nativeZoomLevels,
|
||||||
|
});
|
||||||
this._cachedTileUrls = Object.seal(new Map());
|
this._cachedTileUrls = Object.seal(new Map());
|
||||||
this._namedTiles = Object.seal(new Map());
|
this._namedTiles = Object.seal(new Map());
|
||||||
this._loadQueue = [];
|
this._loadQueue = [];
|
||||||
@ -99,8 +110,12 @@ export class DynmapTileLayer extends TileLayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getTileName(coords: Coordinate): string {
|
getTileName(coords: Coordinate) {
|
||||||
throw "getTileName not implemented";
|
const info = this.getTileInfo(coords);
|
||||||
|
// Y is inverted for HD-map.
|
||||||
|
info.y = -info.y;
|
||||||
|
info.scaledy = info.y >> 5;
|
||||||
|
return `${info.prefix}${info.nightday}/${info.scaledx}_${info.scaledy}/${info.zoom}${info.x}_${info.y}.${info.fmt}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTileUrl(coords: Coordinate) {
|
getTileUrl(coords: Coordinate) {
|
||||||
@ -232,7 +247,10 @@ export class DynmapTileLayer extends TileLayer {
|
|||||||
|
|
||||||
// Some helper functions.
|
// Some helper functions.
|
||||||
zoomprefix(amount: number) {
|
zoomprefix(amount: number) {
|
||||||
return 'z'.repeat(amount);
|
// amount == 0 -> ''
|
||||||
|
// amount == 1 -> 'z_'
|
||||||
|
// amount == 2 -> 'zz_'
|
||||||
|
return 'z'.repeat(amount) + (amount === 0 ? '' : '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
getTileInfo(coords: Coordinate): TileInfo {
|
getTileInfo(coords: Coordinate): TileInfo {
|
||||||
|
@ -15,14 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue';
|
||||||
import API from './api';
|
|
||||||
import {store} from "@/store";
|
import {store} from "@/store";
|
||||||
|
|
||||||
import 'leaflet/dist/leaflet.css';
|
import 'leaflet/dist/leaflet.css';
|
||||||
import 'normalize-scss/sass/normalize/_import-now.scss';
|
import 'normalize-scss/sass/normalize/_import-now.scss';
|
||||||
import '@/scss/style.scss';
|
import '@/scss/style.scss';
|
||||||
import {MutationTypes} from "@/store/mutation-types";
|
import {MutationTypes} from "@/store/mutation-types";
|
||||||
|
import {validateConfiguration} from "@/util";
|
||||||
|
|
||||||
const splash = document.getElementById('splash'),
|
const splash = document.getElementById('splash'),
|
||||||
splashSpinner = document.getElementById('splash__spinner'),
|
splashSpinner = document.getElementById('splash__spinner'),
|
||||||
@ -86,7 +86,7 @@ window.showSplashError = function(message: string, fatal: boolean, attempts: num
|
|||||||
console.info(`LiveAtlas version ${store.state.version} - https://github.com/JLyne/LiveAtlas`);
|
console.info(`LiveAtlas version ${store.state.version} - https://github.com/JLyne/LiveAtlas`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const config = API.validateConfiguration();
|
const config = validateConfiguration();
|
||||||
|
|
||||||
store.commit(MutationTypes.SET_SERVERS, config);
|
store.commit(MutationTypes.SET_SERVERS, config);
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ import {MutationTypes} from "@/store/mutation-types";
|
|||||||
import {ActionContext, ActionTree} from "vuex";
|
import {ActionContext, ActionTree} from "vuex";
|
||||||
import {State} from "@/store/state";
|
import {State} from "@/store/state";
|
||||||
import {ActionTypes} from "@/store/action-types";
|
import {ActionTypes} from "@/store/action-types";
|
||||||
import API from '@/api';
|
|
||||||
import {Mutations} from "@/store/mutations";
|
import {Mutations} from "@/store/mutations";
|
||||||
import {
|
import {
|
||||||
DynmapAreaUpdate, DynmapCircleUpdate,
|
DynmapAreaUpdate, DynmapCircleUpdate,
|
||||||
@ -28,6 +27,7 @@ import {
|
|||||||
DynmapPlayer, DynmapTileUpdate,
|
DynmapPlayer, DynmapTileUpdate,
|
||||||
DynmapUpdateResponse, DynmapWorld
|
DynmapUpdateResponse, DynmapWorld
|
||||||
} from "@/dynmap";
|
} from "@/dynmap";
|
||||||
|
import {getAPI} from "@/util";
|
||||||
|
|
||||||
type AugmentedActionContext = {
|
type AugmentedActionContext = {
|
||||||
commit<K extends keyof Mutations>(
|
commit<K extends keyof Mutations>(
|
||||||
@ -81,7 +81,7 @@ export const actions: ActionTree<State, State> & Actions = {
|
|||||||
//Clear any existing has to avoid triggering a second config load, after this load changes the hash
|
//Clear any existing has to avoid triggering a second config load, after this load changes the hash
|
||||||
commit(MutationTypes.CLEAR_CONFIGURATION_HASH, undefined);
|
commit(MutationTypes.CLEAR_CONFIGURATION_HASH, undefined);
|
||||||
|
|
||||||
const config = await API.getConfiguration();
|
const config = await getAPI().getConfiguration();
|
||||||
|
|
||||||
commit(MutationTypes.SET_CONFIGURATION, config.config);
|
commit(MutationTypes.SET_CONFIGURATION, config.config);
|
||||||
commit(MutationTypes.SET_MESSAGES, config.messages);
|
commit(MutationTypes.SET_MESSAGES, config.messages);
|
||||||
@ -150,7 +150,7 @@ export const actions: ActionTree<State, State> & Actions = {
|
|||||||
return Promise.reject("No current world");
|
return Promise.reject("No current world");
|
||||||
}
|
}
|
||||||
|
|
||||||
const update = await API.getUpdate(state.updateRequestId, state.currentWorld.name, state.updateTimestamp.valueOf())
|
const update = await getAPI().getUpdate(state.updateRequestId, state.currentWorld.name, state.updateTimestamp.valueOf());
|
||||||
|
|
||||||
commit(MutationTypes.SET_WORLD_STATE, update.worldState);
|
commit(MutationTypes.SET_WORLD_STATE, update.worldState);
|
||||||
commit(MutationTypes.SET_UPDATE_TIMESTAMP, new Date(update.timestamp));
|
commit(MutationTypes.SET_UPDATE_TIMESTAMP, new Date(update.timestamp));
|
||||||
@ -195,7 +195,7 @@ export const actions: ActionTree<State, State> & Actions = {
|
|||||||
throw new Error("No current world");
|
throw new Error("No current world");
|
||||||
}
|
}
|
||||||
|
|
||||||
const markerSets = await API.getMarkerSets(state.currentWorld.name)
|
const markerSets = await getAPI().getMarkerSets(state.currentWorld.name)
|
||||||
commit(MutationTypes.SET_MARKER_SETS, markerSets);
|
commit(MutationTypes.SET_MARKER_SETS, markerSets);
|
||||||
|
|
||||||
return markerSets;
|
return markerSets;
|
||||||
@ -262,6 +262,6 @@ export const actions: ActionTree<State, State> & Actions = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async [ActionTypes.SEND_CHAT_MESSAGE]({commit, state}, message: string): Promise<void> {
|
async [ActionTypes.SEND_CHAT_MESSAGE]({commit, state}, message: string): Promise<void> {
|
||||||
await API.sendChatMessage(message);
|
await getAPI().sendChatMessage(message);
|
||||||
},
|
},
|
||||||
}
|
}
|
@ -81,6 +81,6 @@ export const getters: GetterTree<State, State> & Getters = {
|
|||||||
throw RangeError("No current server");
|
throw RangeError("No current server");
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.servers.get(state.currentServer) as LiveAtlasDynmapServerDefinition;
|
return state.currentServer as LiveAtlasDynmapServerDefinition;
|
||||||
},
|
},
|
||||||
}
|
}
|
@ -92,7 +92,7 @@ export const mutations: MutationTree<State> & Mutations = {
|
|||||||
[MutationTypes.SET_SERVERS](state: State, config: Map<string, LiveAtlasServerDefinition>) {
|
[MutationTypes.SET_SERVERS](state: State, config: Map<string, LiveAtlasServerDefinition>) {
|
||||||
state.servers = config;
|
state.servers = config;
|
||||||
|
|
||||||
if(state.currentServer && !state.servers.has(state.currentServer)) {
|
if(state.currentServer && !state.servers.has(state.currentServer.id)) {
|
||||||
state.currentServer = undefined;
|
state.currentServer = undefined;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -414,7 +414,7 @@ export const mutations: MutationTree<State> & Mutations = {
|
|||||||
throw new RangeError(`Unknown server ${serverName}`);
|
throw new RangeError(`Unknown server ${serverName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.currentServer = serverName;
|
state.currentServer = state.servers.get(serverName);
|
||||||
},
|
},
|
||||||
|
|
||||||
//Sets the currently active map/world
|
//Sets the currently active map/world
|
||||||
|
@ -51,7 +51,7 @@ export type State = {
|
|||||||
followTarget?: DynmapPlayer;
|
followTarget?: DynmapPlayer;
|
||||||
panTarget?: DynmapPlayer;
|
panTarget?: DynmapPlayer;
|
||||||
|
|
||||||
currentServer?: string;
|
currentServer?: LiveAtlasServerDefinition;
|
||||||
currentWorldState: DynmapWorldState;
|
currentWorldState: DynmapWorldState;
|
||||||
currentWorld?: DynmapWorld;
|
currentWorld?: DynmapWorld;
|
||||||
currentMap?: DynmapWorldMap;
|
currentMap?: DynmapWorldMap;
|
||||||
|
128
src/util.ts
128
src/util.ts
@ -14,8 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {DynmapPlayer} from "@/dynmap";
|
import API from '@/api';
|
||||||
|
import {DynmapPlayer, DynmapUrlConfig} from "@/dynmap";
|
||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
|
import {LiveAtlasDynmapServerDefinition, LiveAtlasServerDefinition} from "@/index";
|
||||||
|
import ConfigurationError from "@/errors/ConfigurationError";
|
||||||
|
|
||||||
interface HeadQueueEntry {
|
interface HeadQueueEntry {
|
||||||
cacheKey: string;
|
cacheKey: string;
|
||||||
@ -201,4 +204,127 @@ export const parseMapSearchParams = (query: URLSearchParams) => {
|
|||||||
zoom,
|
zoom,
|
||||||
legacy: true,
|
legacy: true,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const validateLiveAtlasConfiguration = (config: any): Map<string, LiveAtlasServerDefinition> => {
|
||||||
|
const check = '\nCheck your server configuration in index.html is correct.',
|
||||||
|
result = new Map<string, LiveAtlasServerDefinition>();
|
||||||
|
|
||||||
|
if (!Object.keys(config).length) {
|
||||||
|
throw new ConfigurationError(`No servers defined. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const server in config) {
|
||||||
|
if (!Object.hasOwnProperty.call(config, server)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverConfig = config[server];
|
||||||
|
|
||||||
|
if (!serverConfig || serverConfig.constructor !== Object || !Object.keys(serverConfig).length) {
|
||||||
|
throw new ConfigurationError(`Server '${server}': Configuration missing. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
serverConfig.id = server;
|
||||||
|
serverConfig.type = serverConfig.type || 'dynmap';
|
||||||
|
|
||||||
|
switch(serverConfig.type) {
|
||||||
|
case 'dynmap':
|
||||||
|
if (!serverConfig.dynmap || serverConfig.dynmap.constructor !== Object) {
|
||||||
|
throw new ConfigurationError(`Server '${server}': Dynmap configuration object missing. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serverConfig.dynmap.configuration) {
|
||||||
|
throw new ConfigurationError(`Server '${server}': Dynmap configuration URL missing. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serverConfig.dynmap.update) {
|
||||||
|
throw new ConfigurationError(`Server '${server}': Dynmap update URL missing. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serverConfig.dynmap.markers) {
|
||||||
|
throw new ConfigurationError(`Server '${server}': Dynmap markers URL missing. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serverConfig.dynmap.tiles) {
|
||||||
|
throw new ConfigurationError(`Server '${server}': Dynmap tiles URL missing. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serverConfig.dynmap.sendmessage) {
|
||||||
|
throw new ConfigurationError(`Server '${server}': Dynmap sendmessage URL missing. ${check}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'pl3xmap':
|
||||||
|
case 'plexmap':
|
||||||
|
if (!serverConfig.plexmap || serverConfig.plexmap.constructor !== Object) {
|
||||||
|
throw new ConfigurationError(`Server '${server}': Pl3xmap configuration object missing. ${check}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.set(server, serverConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateDynmapConfiguration = (config: DynmapUrlConfig): Map<string, LiveAtlasDynmapServerDefinition> => {
|
||||||
|
const check = '\nCheck your standalone/config.js file exists and is being loaded correctly.';
|
||||||
|
|
||||||
|
if (!config) {
|
||||||
|
throw new ConfigurationError(`Dynmap configuration is missing. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.configuration) {
|
||||||
|
throw new ConfigurationError(`Dynmap configuration URL is missing. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.update) {
|
||||||
|
throw new ConfigurationError(`Dynmap update URL is missing. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.markers) {
|
||||||
|
throw new ConfigurationError(`Dynmap markers URL is missing. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.tiles) {
|
||||||
|
throw new ConfigurationError(`Dynmap tiles URL is missing. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.sendmessage) {
|
||||||
|
throw new ConfigurationError(`Dynmap sendmessage URL is missing. ${check}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = new Map<string, LiveAtlasDynmapServerDefinition>();
|
||||||
|
result.set('dynmap', {
|
||||||
|
id: 'dynmap',
|
||||||
|
label: 'dynmap',
|
||||||
|
type: 'dynmap',
|
||||||
|
dynmap: config
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const validateConfiguration = (): Map<string, LiveAtlasServerDefinition> => {
|
||||||
|
if (!window.liveAtlasConfig) {
|
||||||
|
throw new ConfigurationError(`Configuration object is missing`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof window.liveAtlasConfig.servers !== 'undefined') {
|
||||||
|
return validateLiveAtlasConfiguration(window.liveAtlasConfig.servers || {});
|
||||||
|
}
|
||||||
|
|
||||||
|
return validateDynmapConfiguration(window.config?.url || null);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAPI = () => {
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
if(!store.state.currentServer) {
|
||||||
|
throw new RangeError("No current server");
|
||||||
|
}
|
||||||
|
|
||||||
|
return API;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user