Refactor config loading

- Move config validation into map providers
- Move TileLayer creation into map providers
- Simplify config loading logic
This commit is contained in:
James Lyne 2022-01-21 20:20:01 +00:00
parent 52e512e316
commit 80fe8916f3
10 changed files with 179 additions and 189 deletions

View File

@ -169,6 +169,7 @@ export default defineComponent({
const store = useStore(); const store = useStore();
if(newValue) { if(newValue) {
store.state.currentMapProvider!.populateWorld(newValue);
let viewTarget = this.scheduledView || {} as LiveAtlasMapViewTarget; let viewTarget = this.scheduledView || {} as LiveAtlasMapViewTarget;
// Abort if follow target is present, to avoid panning twice // Abort if follow target is present, to avoid panning twice

View File

@ -18,10 +18,8 @@
import {defineComponent, onUnmounted, computed, watch} from "@vue/runtime-core"; import {defineComponent, onUnmounted, computed, watch} from "@vue/runtime-core";
import {Map} from 'leaflet'; import {Map} from 'leaflet';
import {useStore} from "@/store"; import {useStore} from "@/store";
import {DynmapTileLayer} from "@/leaflet/tileLayer/DynmapTileLayer";
import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition"; import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition";
import {LiveAtlasTileLayer} from "@/leaflet/tileLayer/LiveAtlasTileLayer"; import {LiveAtlasTileLayer} from "@/leaflet/tileLayer/LiveAtlasTileLayer";
import {Pl3xmapTileLayer} from "@/leaflet/tileLayer/Pl3xmapTileLayer";
export default defineComponent({ export default defineComponent({
props: { props: {
@ -54,17 +52,10 @@ export default defineComponent({
refreshTimeout = setTimeout(refresh, props.map.tileUpdateInterval); refreshTimeout = setTimeout(refresh, props.map.tileUpdateInterval);
}; };
if(store.state.currentServer?.type === 'dynmap') { layer = store.state.currentMapProvider!.createTileLayer({
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))),
}); });
} else {
layer = new Pl3xmapTileLayer({
errorTileUrl: 'images/blank.png',
mapSettings: Object.freeze(JSON.parse(JSON.stringify(props.map)))
});
}
const enableLayer = () => { const enableLayer = () => {
props.leaflet.addLayer(layer); props.leaflet.addLayer(layer);

4
src/index.d.ts vendored
View File

@ -30,6 +30,7 @@ import {ClockControlOptions} from "@/leaflet/control/ClockControl";
import {LogoControlOptions} from "@/leaflet/control/LogoControl"; import {LogoControlOptions} from "@/leaflet/control/LogoControl";
import {globalMessages, serverMessages} from "../messages"; import {globalMessages, serverMessages} from "../messages";
import {LiveAtlasMarkerType} from "@/util/markers"; import {LiveAtlasMarkerType} from "@/util/markers";
import {LiveAtlasTileLayerOptions} from "@/leaflet/tileLayer/LiveAtlasTileLayer";
declare module "*.png" { declare module "*.png" {
const value: any; const value: any;
@ -100,7 +101,6 @@ interface LiveAtlasGlobalConfig {
interface LiveAtlasServerDefinition { interface LiveAtlasServerDefinition {
id: string; id: string;
label?: string; label?: string;
type: 'dynmap' | 'pl3xmap';
dynmap?: DynmapUrlConfig; dynmap?: DynmapUrlConfig;
pl3xmap?: string; pl3xmap?: string;
squaremap?: string; squaremap?: string;
@ -178,11 +178,11 @@ interface LiveAtlasMapProvider {
populateWorld(world: LiveAtlasWorldDefinition): Promise<void>; populateWorld(world: LiveAtlasWorldDefinition): Promise<void>;
startUpdates(): void; startUpdates(): void;
stopUpdates(): void; stopUpdates(): void;
createTileLayer(options: LiveAtlasTileLayerOptions): LiveAtlasTileLayer;
sendChatMessage(message: string): void; sendChatMessage(message: string): void;
login(formData: FormData): void; login(formData: FormData): void;
logout(): void; logout(): void;
register(formData: FormData): void; register(formData: FormData): void;
destroy(): void;
getPlayerHeadUrl(entry: HeadQueueEntry): string; getPlayerHeadUrl(entry: HeadQueueEntry): string;
getTilesUrl(): string; getTilesUrl(): string;

View File

@ -18,7 +18,7 @@
*/ */
import {Map as LeafletMap, Coords, DoneCallback} from 'leaflet'; import {Map as LeafletMap, Coords, DoneCallback} from 'leaflet';
import {useStore} from "@/store"; import {Store, useStore} from "@/store";
import {Coordinate, Coordinate2D} from "@/index"; import {Coordinate, Coordinate2D} from "@/index";
import {LiveAtlasTileLayer, LiveAtlasTileLayerOptions} from "@/leaflet/tileLayer/LiveAtlasTileLayer"; import {LiveAtlasTileLayer, LiveAtlasTileLayerOptions} from "@/leaflet/tileLayer/LiveAtlasTileLayer";
import {computed, watch} from "@vue/runtime-core"; import {computed, watch} from "@vue/runtime-core";
@ -27,12 +27,12 @@ import {WatchStopHandle} from "vue";
import {ActionTypes} from "@/store/action-types"; import {ActionTypes} from "@/store/action-types";
import {TileInformation} from "dynmap"; import {TileInformation} from "dynmap";
const store = useStore();
// noinspection JSUnusedGlobalSymbols // noinspection JSUnusedGlobalSymbols
export class DynmapTileLayer extends LiveAtlasTileLayer { export class DynmapTileLayer extends LiveAtlasTileLayer {
private readonly _namedTiles: Map<any, any>; private readonly _namedTiles: Map<any, any>;
private readonly _baseUrl: string; private readonly _baseUrl: string;
private readonly _store: Store = useStore();
private readonly _night: ComputedRef<boolean>; private readonly _night: ComputedRef<boolean>;
private readonly _pendingUpdates: ComputedRef<boolean>; private readonly _pendingUpdates: ComputedRef<boolean>;
@ -44,11 +44,11 @@ export class DynmapTileLayer extends LiveAtlasTileLayer {
super('', options); super('', options);
this._mapSettings = options.mapSettings; this._mapSettings = options.mapSettings;
this._baseUrl = store.state.currentMapProvider!.getTilesUrl(); this._baseUrl = this._store.state.currentMapProvider!.getTilesUrl();
this._namedTiles = Object.seal(new Map()); this._namedTiles = Object.seal(new Map());
this._pendingUpdates = computed(() => !!store.state.pendingTileUpdates.length); this._pendingUpdates = computed(() => !!this._store.state.pendingTileUpdates.length);
this._night = computed(() => store.getters.night); this._night = computed(() => this._store.getters.night);
} }
onAdd(map: LeafletMap) { onAdd(map: LeafletMap) {
@ -183,7 +183,7 @@ export class DynmapTileLayer extends LiveAtlasTileLayer {
} }
private async handlePendingUpdates() { private async handlePendingUpdates() {
const updates = await store.dispatch(ActionTypes.POP_TILE_UPDATES, 10); const updates = await this._store.dispatch(ActionTypes.POP_TILE_UPDATES, 10);
for(const update of updates) { for(const update of updates) {
this.updateNamedTile(update.name, update.timestamp); this.updateNamedTile(update.name, update.timestamp);

View File

@ -23,10 +23,13 @@ import 'leaflet/dist/leaflet.css';
import '@/scss/style.scss'; import '@/scss/style.scss';
import {MutationTypes} from "@/store/mutation-types"; import {MutationTypes} from "@/store/mutation-types";
import {showSplashError} from "@/util/splash";
import { VueClipboard } from '@soerenmartius/vue3-clipboard'; import { VueClipboard } from '@soerenmartius/vue3-clipboard';
import Notifications from '@kyvg/vue3-notification' import Notifications from '@kyvg/vue3-notification'
import {getServerDefinitions} from "@/util/config"; import {loadConfig, registerMapProvider} from "@/util/config";
import DynmapMapProvider from "@/providers/DynmapMapProvider";
import Pl3xmapMapProvider from "@/providers/Pl3xmapMapProvider";
import {showSplashError} from "@/util/splash";
import ConfigurationError from "@/errors/ConfigurationError";
const splash = document.getElementById('splash'), const splash = document.getElementById('splash'),
svgs = import.meta.globEager('/assets/icons/*.svg'); svgs = import.meta.globEager('/assets/icons/*.svg');
@ -49,10 +52,14 @@ store.subscribe((mutation, state) => {
} }
}); });
try { registerMapProvider('dynmap', DynmapMapProvider);
const config = window.liveAtlasConfig; registerMapProvider('pl3xmap', Pl3xmapMapProvider);
config.servers = getServerDefinitions(config); registerMapProvider('squaremap', Pl3xmapMapProvider);
const config = window.liveAtlasConfig;
try {
config.servers = loadConfig(config);
store.commit(MutationTypes.INIT, config); store.commit(MutationTypes.INIT, config);
if(store.state.servers.size > 1) { if(store.state.servers.size > 1) {
@ -77,6 +84,11 @@ try {
// app.config.performance = true; // app.config.performance = true;
app.mount('#app'); app.mount('#app');
} catch (e) { } catch (e) {
if(e instanceof ConfigurationError) {
console.error('LiveAtlas configuration is invalid:', e); console.error('LiveAtlas configuration is invalid:', e);
showSplashError('LiveAtlas configuration is invalid:\n' + e, true); showSplashError('LiveAtlas configuration is invalid:\n' + e, true);
} else {
console.error('LiveAtlas failed to load:', e);
showSplashError('LiveAtlas failed to load:\n' + e, true);
}
} }

View File

@ -18,7 +18,6 @@ import {
HeadQueueEntry, LiveAtlasMarker, HeadQueueEntry, LiveAtlasMarker,
LiveAtlasMarkerSet, LiveAtlasMarkerSet,
LiveAtlasPlayer, LiveAtlasPlayer,
LiveAtlasServerDefinition,
LiveAtlasWorldDefinition LiveAtlasWorldDefinition
} from "@/index"; } from "@/index";
import ChatError from "@/errors/ChatError"; import ChatError from "@/errors/ChatError";
@ -36,6 +35,10 @@ import {
} from "@/util/dynmap"; } from "@/util/dynmap";
import {getImagePixelSize} from "@/util"; import {getImagePixelSize} from "@/util";
import {MarkerSet} from "dynmap"; import {MarkerSet} from "dynmap";
import {DynmapUrlConfig} from "@/dynmap";
import ConfigurationError from "@/errors/ConfigurationError";
import {DynmapTileLayer} from "@/leaflet/tileLayer/DynmapTileLayer";
import {LiveAtlasTileLayer, LiveAtlasTileLayerOptions} from "@/leaflet/tileLayer/LiveAtlasTileLayer";
export default class DynmapMapProvider extends MapProvider { export default class DynmapMapProvider extends MapProvider {
private configurationAbort?: AbortController = undefined; private configurationAbort?: AbortController = undefined;
@ -50,12 +53,41 @@ export default class DynmapMapProvider extends MapProvider {
private markerSets: Map<string, LiveAtlasMarkerSet> = new Map(); private markerSets: Map<string, LiveAtlasMarkerSet> = new Map();
private markers = new Map<string, Map<string, LiveAtlasMarker>>(); private markers = new Map<string, Map<string, LiveAtlasMarker>>();
constructor(config: LiveAtlasServerDefinition) { constructor(config: DynmapUrlConfig) {
super(config); super(config);
this.validateConfig();
}
private validateConfig() {
if(typeof this.config !== 'undefined') {
if (!this.config || this.config.constructor !== Object) {
throw new ConfigurationError(`Dynmap configuration object missing`);
}
if (!this.config.configuration) {
throw new ConfigurationError(`Dynmap configuration URL missing`);
}
if (!this.config.update) {
throw new ConfigurationError(`Dynmap update URL missing`);
}
if (!this.config.markers) {
throw new ConfigurationError(`Dynmap markers URL missing`);
}
if (!this.config.tiles) {
throw new ConfigurationError(`Dynmap tiles URL missing`);
}
if (!this.config.sendmessage) {
throw new ConfigurationError(`Dynmap sendmessage URL missing`);
}
}
} }
private async getMarkerSets(world: LiveAtlasWorldDefinition): Promise<void> { private async getMarkerSets(world: LiveAtlasWorldDefinition): Promise<void> {
const url = `${this.config.dynmap!.markers}_markers_/marker_${world.name}.json`; const url = `${this.config.markers}_markers_/marker_${world.name}.json`;
if(this.markersAbort) { if(this.markersAbort) {
this.markersAbort.abort(); this.markersAbort.abort();
@ -93,7 +125,7 @@ export default class DynmapMapProvider extends MapProvider {
this.configurationAbort = new AbortController(); this.configurationAbort = new AbortController();
const response = await this.getJSON(this.config.dynmap!.configuration, this.configurationAbort.signal); const response = await this.getJSON(this.config.configuration, this.configurationAbort.signal);
if (response.error) { if (response.error) {
throw new Error(response.error); throw new Error(response.error);
@ -122,8 +154,12 @@ export default class DynmapMapProvider extends MapProvider {
this.markers.clear(); this.markers.clear();
} }
createTileLayer(options: LiveAtlasTileLayerOptions): LiveAtlasTileLayer {
return new DynmapTileLayer(options);
}
private async getUpdate(): Promise<void> { private async getUpdate(): Promise<void> {
let url = this.config.dynmap!.update; let url = this.config.update;
url = url.replace('{world}', this.store.state.currentWorld!.name); url = url.replace('{world}', this.store.state.currentWorld!.name);
url = url.replace('{timestamp}', this.updateTimestamp.getTime().toString()); url = url.replace('{timestamp}', this.updateTimestamp.getTime().toString());
@ -200,7 +236,7 @@ export default class DynmapMapProvider extends MapProvider {
return Promise.reject(this.store.state.messages.chatErrorDisabled); return Promise.reject(this.store.state.messages.chatErrorDisabled);
} }
return fetch(this.config.dynmap!.sendmessage, { return fetch(this.config.sendmessage, {
method: 'POST', method: 'POST',
credentials: 'include', credentials: 'include',
body: JSON.stringify({ body: JSON.stringify({
@ -259,14 +295,26 @@ export default class DynmapMapProvider extends MapProvider {
} }
this.updateTimeout = null; this.updateTimeout = null;
if(this.configurationAbort) {
this.configurationAbort.abort();
}
if(this.updateAbort) {
this.updateAbort.abort();
}
if(this.markersAbort) {
this.markersAbort.abort();
}
} }
getTilesUrl(): string { getTilesUrl(): string {
return this.config.dynmap!.tiles; return this.config.tiles;
} }
getPlayerHeadUrl(head: HeadQueueEntry): string { getPlayerHeadUrl(head: HeadQueueEntry): string {
const baseUrl = `${this.config.dynmap!.markers}faces/`; const baseUrl = `${this.config.markers}faces/`;
if(head.size === 'body') { if(head.size === 'body') {
return `${baseUrl}body/${head.name}.png`; return `${baseUrl}body/${head.name}.png`;
@ -277,7 +325,7 @@ export default class DynmapMapProvider extends MapProvider {
} }
getMarkerIconUrl(icon: string): string { getMarkerIconUrl(icon: string): string {
return `${this.config.dynmap!.markers}_markers_/${icon}.png`; return `${this.config.markers}_markers_/${icon}.png`;
} }
async login(data: any) { async login(data: any) {
@ -294,7 +342,7 @@ export default class DynmapMapProvider extends MapProvider {
body.append('j_password', data.password || ''); body.append('j_password', data.password || '');
const response = await DynmapMapProvider.fetchJSON(this.config.dynmap!.login, { const response = await DynmapMapProvider.fetchJSON(this.config.login, {
method: 'POST', method: 'POST',
body, body,
}); });
@ -323,7 +371,7 @@ export default class DynmapMapProvider extends MapProvider {
} }
try { try {
await DynmapMapProvider.fetchJSON(this.config.dynmap!.login, { await DynmapMapProvider.fetchJSON(this.config.login, {
method: 'POST', method: 'POST',
}); });
@ -348,7 +396,7 @@ export default class DynmapMapProvider extends MapProvider {
body.append('j_verify_password', data.password || ''); body.append('j_verify_password', data.password || '');
body.append('j_passcode', data.code || ''); body.append('j_passcode', data.code || '');
const response = await DynmapMapProvider.fetchJSON(this.config.dynmap!.register, { const response = await DynmapMapProvider.fetchJSON(this.config.register, {
method: 'POST', method: 'POST',
body, body,
}); });
@ -374,22 +422,6 @@ export default class DynmapMapProvider extends MapProvider {
} }
} }
destroy() {
super.destroy();
if(this.configurationAbort) {
this.configurationAbort.abort();
}
if(this.updateAbort) {
this.updateAbort.abort();
}
if(this.markersAbort) {
this.markersAbort.abort();
}
}
protected async getJSON(url: string, signal: AbortSignal) { protected async getJSON(url: string, signal: AbortSignal) {
return MapProvider.fetchJSON(url, {signal, credentials: 'include'}).then(response => { return MapProvider.fetchJSON(url, {signal, credentials: 'include'}).then(response => {
if(response.error === 'login-required') { if(response.error === 'login-required') {

View File

@ -17,31 +17,22 @@
import { import {
HeadQueueEntry, HeadQueueEntry,
LiveAtlasMapProvider, LiveAtlasMapProvider,
LiveAtlasServerDefinition,
LiveAtlasWorldDefinition LiveAtlasWorldDefinition
} from "@/index"; } from "@/index";
import {useStore} from "@/store"; import {useStore} from "@/store";
import {computed, watch} from "@vue/runtime-core"; import {LiveAtlasTileLayer, LiveAtlasTileLayerOptions} from "@/leaflet/tileLayer/LiveAtlasTileLayer";
import {WatchStopHandle} from "vue";
export default abstract class MapProvider implements LiveAtlasMapProvider { export default abstract class MapProvider implements LiveAtlasMapProvider {
protected readonly store = useStore(); protected readonly store = useStore();
protected readonly config: LiveAtlasServerDefinition; protected config: any;
private readonly currentWorldUnwatch: WatchStopHandle;
protected constructor(config: LiveAtlasServerDefinition) { protected constructor(config: any) {
this.config = config; this.config = config;
const currentWorld = computed(() => this.store.state.currentWorld);
this.currentWorldUnwatch = watch(currentWorld, (newValue) => {
if (newValue) {
this.populateWorld(newValue);
}
});
} }
abstract loadServerConfiguration(): Promise<void>; abstract loadServerConfiguration(): Promise<void>;
abstract populateWorld(world: LiveAtlasWorldDefinition): Promise<void>; abstract populateWorld(world: LiveAtlasWorldDefinition): Promise<void>;
abstract createTileLayer(options: LiveAtlasTileLayerOptions): LiveAtlasTileLayer;
abstract startUpdates(): void; abstract startUpdates(): void;
abstract stopUpdates(): void; abstract stopUpdates(): void;
@ -66,10 +57,6 @@ export default abstract class MapProvider implements LiveAtlasMapProvider {
throw new Error('Provider does not support registration'); throw new Error('Provider does not support registration');
} }
destroy() {
this.currentWorldUnwatch();
}
protected static async fetchJSON(url: string, options: any) { protected static async fetchJSON(url: string, options: any) {
let response, json; let response, json;

View File

@ -26,7 +26,6 @@ import {
LiveAtlasPlayer, LiveAtlasPlayer,
LiveAtlasPointMarker, LiveAtlasPointMarker,
LiveAtlasServerConfig, LiveAtlasServerConfig,
LiveAtlasServerDefinition,
LiveAtlasServerMessageConfig, LiveAtlasServerMessageConfig,
LiveAtlasWorldDefinition LiveAtlasWorldDefinition
} from "@/index"; } from "@/index";
@ -37,6 +36,9 @@ import {ActionTypes} from "@/store/action-types";
import {getBoundsFromPoints, getMiddle, stripHTML, titleColoursRegex} from "@/util"; import {getBoundsFromPoints, getMiddle, stripHTML, titleColoursRegex} from "@/util";
import {LiveAtlasMarkerType} from "@/util/markers"; import {LiveAtlasMarkerType} from "@/util/markers";
import {PointTuple} from "leaflet"; import {PointTuple} from "leaflet";
import ConfigurationError from "@/errors/ConfigurationError";
import {Pl3xmapTileLayer} from "@/leaflet/tileLayer/Pl3xmapTileLayer";
import {LiveAtlasTileLayer, LiveAtlasTileLayerOptions} from "@/leaflet/tileLayer/LiveAtlasTileLayer";
export default class Pl3xmapMapProvider extends MapProvider { export default class Pl3xmapMapProvider extends MapProvider {
private configurationAbort?: AbortController = undefined; private configurationAbort?: AbortController = undefined;
@ -61,8 +63,16 @@ export default class Pl3xmapMapProvider extends MapProvider {
private markerSets: Map<string, LiveAtlasMarkerSet> = new Map(); private markerSets: Map<string, LiveAtlasMarkerSet> = new Map();
private markers = new Map<string, Map<string, LiveAtlasMarker>>(); private markers = new Map<string, Map<string, LiveAtlasMarker>>();
constructor(config: LiveAtlasServerDefinition) { constructor(config: string) {
super(config); super(config);
if(!this.config) {
throw new ConfigurationError("URL missing");
}
if(this.config.slice(-1) !== '/') {
this.config = `${config}/`;
}
} }
private static buildServerConfig(response: any): LiveAtlasServerConfig { private static buildServerConfig(response: any): LiveAtlasServerConfig {
@ -168,7 +178,7 @@ export default class Pl3xmapMapProvider extends MapProvider {
background: 'transparent', background: 'transparent',
backgroundDay: 'transparent', backgroundDay: 'transparent',
backgroundNight: 'transparent', backgroundNight: 'transparent',
icon: world.icon ? `${this.config.pl3xmap}images/icon/${world.icon}.png` : undefined, icon: world.icon ? `${this.config}images/icon/${world.icon}.png` : undefined,
imageFormat: 'png', imageFormat: 'png',
name: 'flat', name: 'flat',
displayName: 'Flat', displayName: 'Flat',
@ -226,7 +236,7 @@ export default class Pl3xmapMapProvider extends MapProvider {
} }
private async getMarkerSets(world: LiveAtlasWorldDefinition): Promise<void> { private async getMarkerSets(world: LiveAtlasWorldDefinition): Promise<void> {
const url = `${this.config.pl3xmap}tiles/${world.name}/markers.json`; const url = `${this.config}tiles/${world.name}/markers.json`;
if(this.markersAbort) { if(this.markersAbort) {
this.markersAbort.abort(); this.markersAbort.abort();
@ -424,7 +434,7 @@ export default class Pl3xmapMapProvider extends MapProvider {
this.configurationAbort = new AbortController(); this.configurationAbort = new AbortController();
const baseUrl = this.config.pl3xmap, const baseUrl = this.config,
response = await Pl3xmapMapProvider.getJSON(`${baseUrl}tiles/settings.json`, this.configurationAbort.signal); response = await Pl3xmapMapProvider.getJSON(`${baseUrl}tiles/settings.json`, this.configurationAbort.signal);
if (response.error) { if (response.error) {
@ -459,8 +469,12 @@ export default class Pl3xmapMapProvider extends MapProvider {
this.markers.clear(); this.markers.clear();
} }
createTileLayer(options: LiveAtlasTileLayerOptions): LiveAtlasTileLayer {
return new Pl3xmapTileLayer(options);
}
private async getPlayers(): Promise<Set<LiveAtlasPlayer>> { private async getPlayers(): Promise<Set<LiveAtlasPlayer>> {
const url = `${this.config.pl3xmap}tiles/players.json`; const url = `${this.config}tiles/players.json`;
if(this.playersAbort) { if(this.playersAbort) {
this.playersAbort.abort(); this.playersAbort.abort();
@ -557,23 +571,6 @@ export default class Pl3xmapMapProvider extends MapProvider {
this.markerUpdateTimeout = null; this.markerUpdateTimeout = null;
this.playerUpdateTimeout = null; this.playerUpdateTimeout = null;
}
getTilesUrl(): string {
return `${this.config.pl3xmap}tiles/`;
}
getPlayerHeadUrl(head: HeadQueueEntry): string {
//TODO: Listen to config
return 'https://mc-heads.net/avatar/{uuid}/16'.replace('{uuid}', head.uuid || '');
}
getMarkerIconUrl(icon: string): string {
return `${this.config.pl3xmap}images/icon/registered/${icon}.png`;
}
destroy() {
super.destroy();
if(this.configurationAbort) { if(this.configurationAbort) {
this.configurationAbort.abort(); this.configurationAbort.abort();
@ -587,4 +584,17 @@ export default class Pl3xmapMapProvider extends MapProvider {
this.markersAbort.abort(); this.markersAbort.abort();
} }
} }
getTilesUrl(): string {
return `${this.config}tiles/`;
}
getPlayerHeadUrl(head: HeadQueueEntry): string {
//TODO: Listen to config
return 'https://mc-heads.net/avatar/{uuid}/16'.replace('{uuid}', head.uuid || '');
}
getMarkerIconUrl(icon: string): string {
return `${this.config}images/icon/registered/${icon}.png`;
}
} }

View File

@ -33,7 +33,6 @@ import {
LiveAtlasServerMessageConfig, LiveAtlasServerMessageConfig,
LiveAtlasPlayer, LiveAtlasPlayer,
LiveAtlasMarkerSet, LiveAtlasMarkerSet,
LiveAtlasServerDefinition,
LiveAtlasServerConfig, LiveAtlasServerConfig,
LiveAtlasChat, LiveAtlasChat,
LiveAtlasPartialComponentConfig, LiveAtlasPartialComponentConfig,
@ -41,9 +40,8 @@ import {
LiveAtlasUIModal, LiveAtlasUIModal,
LiveAtlasSidebarSectionState, LiveAtlasMarker, LiveAtlasMapViewTarget LiveAtlasSidebarSectionState, LiveAtlasMarker, LiveAtlasMapViewTarget
} from "@/index"; } from "@/index";
import DynmapMapProvider from "@/providers/DynmapMapProvider";
import Pl3xmapMapProvider from "@/providers/Pl3xmapMapProvider";
import {getGlobalMessages} from "@/util"; import {getGlobalMessages} from "@/util";
import {getServerMapProvider} from "@/util/config";
export type CurrentMapPayload = { export type CurrentMapPayload = {
worldName: string; worldName: string;
@ -383,19 +381,9 @@ export const mutations: MutationTree<State> & Mutations = {
if(state.currentMapProvider) { if(state.currentMapProvider) {
state.currentMapProvider.stopUpdates(); state.currentMapProvider.stopUpdates();
state.currentMapProvider.destroy();
} }
switch(state.currentServer!.type) { state.currentMapProvider = getServerMapProvider(serverName);
case 'pl3xmap':
state.currentMapProvider = Object.seal(
new Pl3xmapMapProvider(state.servers.get(serverName) as LiveAtlasServerDefinition));
break;
case 'dynmap':
state.currentMapProvider = Object.seal(
new DynmapMapProvider(state.servers.get(serverName) as LiveAtlasServerDefinition));
break;
}
}, },
//Sets the currently active map/world //Sets the currently active map/world

View File

@ -18,10 +18,27 @@ import {LiveAtlasGlobalConfig, LiveAtlasServerDefinition} from "@/index";
import ConfigurationError from "@/errors/ConfigurationError"; import ConfigurationError from "@/errors/ConfigurationError";
import {DynmapUrlConfig} from "@/dynmap"; import {DynmapUrlConfig} from "@/dynmap";
import {useStore} from "@/store"; import {useStore} from "@/store";
import MapProvider from "@/providers/MapProvider";
import DynmapMapProvider from "@/providers/DynmapMapProvider";
const expectedConfigVersion = 1; const expectedConfigVersion = 1;
const validateLiveAtlasConfiguration = (config: any): Map<string, LiveAtlasServerDefinition> => { const registeredProviders: Map<string, new (config: any) => MapProvider> = new Map();
const serverProviders: Map<string, MapProvider> = new Map();
export const registerMapProvider = (id: string, provider: new (config: any) => MapProvider) => {
if(registeredProviders.has(id)) {
throw new TypeError(`${id} is already registered`);
}
registeredProviders.set(id, provider);
}
export const getServerMapProvider = (server: string): MapProvider | undefined => {
return serverProviders.get(server);
}
const loadLiveAtlasConfig = (config: any): Map<string, LiveAtlasServerDefinition> => {
const check = '\nCheck your server configuration in index.html is correct.', const check = '\nCheck your server configuration in index.html is correct.',
result = new Map<string, LiveAtlasServerDefinition>(); result = new Map<string, LiveAtlasServerDefinition>();
@ -35,100 +52,52 @@ const validateLiveAtlasConfiguration = (config: any): Map<string, LiveAtlasServe
} }
const serverConfig = config[server]; const serverConfig = config[server];
let foundProvider = false;
if (!serverConfig || serverConfig.constructor !== Object || !Object.keys(serverConfig).length) { for (const mapProvider of registeredProviders) {
throw new ConfigurationError(`Server '${server}': Configuration missing. ${check}`); if(serverConfig && Object.hasOwnProperty.call(serverConfig, mapProvider[0])) {
} try {
serverProviders.set(server, new mapProvider[1](serverConfig[mapProvider[0]]));
serverConfig.id = server; } catch(e: any) {
e.message = `Server "${server}": ${e.message}. ${check}`;
//Squaremap and Pl3xmap are currently interchangeable throw e;
if(typeof serverConfig.squaremap !== 'undefined') {
serverConfig.pl3xmap = serverConfig.squaremap;
}
if(typeof serverConfig.pl3xmap !== 'undefined') {
serverConfig.type = 'pl3xmap';
// Ensure trailing /
if(serverConfig.pl3xmap.slice(-1) !== '/') {
serverConfig.pl3xmap = `${serverConfig.pl3xmap}/`;
}
} else if(typeof serverConfig.dynmap !== 'undefined') {
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}`);
}
serverConfig.type = 'dynmap';
} else {
throw new ConfigurationError(`Server '${server}': No Dynmap or Pl3xmap configuration defined. ${check}`);
} }
result.set(server, serverConfig); result.set(server, serverConfig);
foundProvider = true;
}
}
if(!foundProvider) {
throw new ConfigurationError(`Server "${server}": No configuration found for any supported map type. ${check}`);
}
serverConfig.id = server;
} }
return result; return result;
}; };
const validateDynmapConfiguration = (config: DynmapUrlConfig): Map<string, LiveAtlasServerDefinition> => { const loadDefaultConfig = (config: DynmapUrlConfig): Map<string, LiveAtlasServerDefinition> => {
const check = '\nCheck your standalone/config.js file exists and is being loaded correctly.'; 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, LiveAtlasServerDefinition>(); const result = new Map<string, LiveAtlasServerDefinition>();
result.set('dynmap', { result.set('dynmap', {
id: 'dynmap', id: 'dynmap',
label: 'dynmap', label: 'dynmap',
type: 'dynmap',
dynmap: config dynmap: config
}); });
try {
serverProviders.set('dynmap', new DynmapMapProvider(config));
} catch (e: any) {
e.message = `${e.message}. ${check}`;
throw e;
}
return result; return result;
}; };
export const getServerDefinitions = (config: LiveAtlasGlobalConfig): Map<string, LiveAtlasServerDefinition> => { export const loadConfig = (config: LiveAtlasGlobalConfig): Map<string, LiveAtlasServerDefinition> => {
if (!config) { if (!config) {
throw new ConfigurationError(`No configuration found.\nCheck for any syntax errors in your configuration in index.html. Your browser console may contain additional information.`); throw new ConfigurationError(`No configuration found.\nCheck for any syntax errors in your configuration in index.html. Your browser console may contain additional information.`);
} }
@ -138,9 +107,9 @@ export const getServerDefinitions = (config: LiveAtlasGlobalConfig): Map<string,
} }
if (typeof config.servers !== 'undefined') { if (typeof config.servers !== 'undefined') {
return validateLiveAtlasConfiguration(config.servers); return loadLiveAtlasConfig(config.servers);
} }
return validateDynmapConfiguration(window.config?.url || null); return loadDefaultConfig(window.config?.url || null);
}; };