Configuration improvements

- Default playersAboveMarkers to true to match previous behaviour
- Move all window.liveAtlasConfig handling to main.ts and a single mutation
- Rename server configuration mutations to differentiate server and global configurations
This commit is contained in:
James Lyne 2021-07-20 21:12:08 +01:00
parent c67db75586
commit 649f571a20
10 changed files with 136 additions and 94 deletions

View File

@ -117,7 +117,7 @@
ui: { ui: {
// If true, player markers will always be displayed in front of other marker types // If true, player markers will always be displayed in front of other marker types
playersAboveMarkers: false playersAboveMarkers: true
} }
}; };
</script> </script>

View File

@ -33,7 +33,7 @@ import {
} from "@/dynmap"; } from "@/dynmap";
import {useStore} from "@/store"; import {useStore} from "@/store";
import ChatError from "@/errors/ChatError"; import ChatError from "@/errors/ChatError";
import {LiveAtlasMessageConfig, LiveAtlasWorld} from "@/index"; import {LiveAtlasServerMessageConfig, LiveAtlasWorld} from "@/index";
const titleColours = /§[0-9a-f]/ig; const titleColours = /§[0-9a-f]/ig;
@ -56,48 +56,17 @@ function buildServerConfig(response: any): DynmapServerConfig {
}; };
} }
function buildMessagesConfig(response: any): LiveAtlasMessageConfig { function buildMessagesConfig(response: any): LiveAtlasServerMessageConfig {
const liveAtlasMessages = window.liveAtlasConfig?.messages || {};
return { return {
chatPlayerJoin: response.joinmessage || '', chatPlayerJoin: response.joinmessage || '',
chatPlayerQuit: response.quitmessage || '', chatPlayerQuit: response.quitmessage || '',
chatAnonymousJoin: response['msg-hiddennamejoin'] || '', chatAnonymousJoin: response['msg-hiddennamejoin'] || '',
chatAnonymousQuit: response['msg-hiddennamequit'] || '', chatAnonymousQuit: response['msg-hiddennamequit'] || '',
chatTitle: liveAtlasMessages.chatTitle || '',
chatLogin: liveAtlasMessages.chatLogin || '',
chatLoginLink: liveAtlasMessages.chatLoginLink || '',
chatNoMessages: liveAtlasMessages.chatNoMessages || '',
chatSend: liveAtlasMessages.chatSend || '',
chatPlaceholder: liveAtlasMessages.chatPlaceholder || '',
chatErrorNotAllowed: response['msg-chatnotallowed'] || '', chatErrorNotAllowed: response['msg-chatnotallowed'] || '',
chatErrorRequiresLogin: response['msg-chatrequireslogin'] || '', chatErrorRequiresLogin: response['msg-chatrequireslogin'] || '',
chatErrorCooldown: response.spammessage || '', chatErrorCooldown: response.spammessage || '',
chatErrorDisabled: liveAtlasMessages.chatErrorDisabled || '',
chatErrorUnknown: liveAtlasMessages.chatErrorUnknown || '',
serversHeading: liveAtlasMessages.serversHeading || '',
worldsHeading: response['msg-maptypes'] || '', worldsHeading: response['msg-maptypes'] || '',
worldsSkeleton: liveAtlasMessages.worldsSkeleton || '',
playersHeading: response['msg-players'] || '', playersHeading: response['msg-players'] || '',
playersSkeleton: liveAtlasMessages.playersSkeleton || '',
playersTitle: liveAtlasMessages.playersTitle || '',
playersTitleHidden: liveAtlasMessages.playersTitleHidden || '',
playersTitleOtherWorld: liveAtlasMessages.playersTitleOtherWorld || '',
followingHeading: liveAtlasMessages.followingHeading || '',
followingHidden: liveAtlasMessages.followingHidden || '',
followingUnfollow: liveAtlasMessages.followingUnfollow || '',
followingTitleUnfollow: liveAtlasMessages.followingTitleUnfollow || '',
linkTitle: liveAtlasMessages.linkTitle || '',
loadingTitle: liveAtlasMessages.loadingTitle || '',
locationRegion: liveAtlasMessages.locationRegion || '',
locationChunk: liveAtlasMessages.locationChunk || '',
contextMenuCopyLink: liveAtlasMessages.contextMenuCopyLink || '',
contextMenuCenterHere: liveAtlasMessages.contextMenuCenterHere || '',
toggleTitle: liveAtlasMessages.toggleTitle || '',
mapTitle: liveAtlasMessages.mapTitle || '',
layersTitle: liveAtlasMessages.layersTitle || '',
copyToClipboardSuccess: liveAtlasMessages.copyToClipboardSuccess || '',
copyToClipboardError: liveAtlasMessages.copyToClipboardError || '',
} }
} }

11
src/dynmap.d.ts vendored
View File

@ -18,13 +18,18 @@ import {PathOptions, PointTuple, PolylineOptions} from "leaflet";
import {CoordinatesControlOptions} from "@/leaflet/control/CoordinatesControl"; import {CoordinatesControlOptions} from "@/leaflet/control/CoordinatesControl";
import {LogoControlOptions} from "@/leaflet/control/LogoControl"; import {LogoControlOptions} from "@/leaflet/control/LogoControl";
import {ClockControlOptions} from "@/leaflet/control/ClockControl"; import {ClockControlOptions} from "@/leaflet/control/ClockControl";
import {Coordinate, LiveAtlasLocation, LiveAtlasMessageConfig, LiveAtlasWorld, LiveAtlasWorldState} from "@/index"; import {
Coordinate,
LiveAtlasLocation,
LiveAtlasServerMessageConfig,
LiveAtlasWorld,
LiveAtlasWorldState
} from "@/index";
declare global { declare global {
// noinspection JSUnusedGlobalSymbols // noinspection JSUnusedGlobalSymbols
interface Window { interface Window {
config: { url: DynmapUrlConfig }; config: { url: DynmapUrlConfig };
liveAtlasConfig: any,
} }
} }
@ -96,7 +101,7 @@ interface DynmapChatSendingConfig {
interface DynmapConfigurationResponse { interface DynmapConfigurationResponse {
config: DynmapServerConfig, config: DynmapServerConfig,
messages: LiveAtlasMessageConfig, messages: LiveAtlasServerMessageConfig,
worlds: Array<LiveAtlasWorld>, worlds: Array<LiveAtlasWorld>,
components: DynmapComponentConfig, components: DynmapComponentConfig,
loggedIn: boolean, loggedIn: boolean,

44
src/index.d.ts vendored
View File

@ -12,6 +12,13 @@ declare module '*.vue' {
export default component export default component
} }
declare global {
// noinspection JSUnusedGlobalSymbols
interface Window {
liveAtlasConfig: LiveAtlasGlobalConfig,
}
}
interface Coordinate { interface Coordinate {
x: number; x: number;
y: number; y: number;
@ -25,6 +32,12 @@ interface LiveAtlasLocation {
world?: string; world?: string;
} }
interface LiveAtlasGlobalConfig {
servers: Map<string, LiveAtlasServerDefinition>;
messages: LiveAtlasGlobalMessageConfig;
ui: LiveAtlasUIConfig;
}
interface LiveAtlasServerDefinition { interface LiveAtlasServerDefinition {
id: string id: string
label?: string label?: string
@ -35,27 +48,19 @@ interface LiveAtlasDynmapServerDefinition extends LiveAtlasServerDefinition {
dynmap: DynmapUrlConfig, dynmap: DynmapUrlConfig,
} }
interface LiveAtlasMessageConfig { // Messages defined directly in LiveAtlas and used for all servers
chatPlayerJoin: string; interface LiveAtlasGlobalMessageConfig {
chatPlayerQuit: string;
chatAnonymousJoin: string;
chatAnonymousQuit: string;
chatNoMessages: string; chatNoMessages: string;
chatTitle: string; chatTitle: string;
chatLogin: string; chatLogin: string;
chatLoginLink: string; chatLoginLink: string;
chatSend: string; chatSend: string;
chatPlaceholder: string; chatPlaceholder: string;
chatErrorNotAllowed: string;
chatErrorRequiresLogin: string;
chatErrorCooldown: string;
chatErrorDisabled: string; chatErrorDisabled: string;
chatErrorUnknown: string; chatErrorUnknown: string;
serversHeading: string; serversHeading: string;
worldsHeading: string;
worldsSkeleton: string; worldsSkeleton: string;
playersSkeleton: string; playersSkeleton: string;
playersHeading: string;
playersTitle: string; playersTitle: string;
playersTitleHidden: string; playersTitleHidden: string;
playersTitleOtherWorld: string; playersTitleOtherWorld: string;
@ -76,6 +81,25 @@ interface LiveAtlasMessageConfig {
copyToClipboardError: string; copyToClipboardError: string;
} }
// Messages defined by dynmap configuration responses and can vary per server
interface LiveAtlasServerMessageConfig {
chatPlayerJoin: string;
chatPlayerQuit: string;
chatAnonymousJoin: string;
chatAnonymousQuit: string;
chatErrorNotAllowed: string;
chatErrorRequiresLogin: string;
chatErrorCooldown: string;
worldsHeading: string;
playersHeading: string;
}
type LiveAtlasMessageConfig = LiveAtlasGlobalMessageConfig & LiveAtlasServerMessageConfig;
interface LiveAtlasUIConfig {
playersAboveMarkers: boolean;
}
export type LiveAtlasUIElement = 'layers' | 'chat' | 'players' | 'maps' | 'settings'; export type LiveAtlasUIElement = 'layers' | 'chat' | 'players' | 'maps' | 'settings';
export type LiveAtlasSidebarSection = 'servers' | 'players' | 'maps'; export type LiveAtlasSidebarSection = 'servers' | 'players' | 'maps';

View File

@ -24,10 +24,10 @@ import '@/scss/style.scss';
import 'focus-visible'; import 'focus-visible';
import {MutationTypes} from "@/store/mutation-types"; import {MutationTypes} from "@/store/mutation-types";
import {validateConfiguration} from "@/util/config";
import {showSplashError} from "@/util/splash"; 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";
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,14 +49,14 @@ store.subscribe((mutation, state) => {
}); });
try { try {
const config = validateConfiguration(); const config = window.liveAtlasConfig;
config.servers = getServerDefinitions(config);
store.commit(MutationTypes.INIT, undefined); store.commit(MutationTypes.INIT, config);
store.commit(MutationTypes.SET_SERVERS, config);
if(config.size > 1) { if(store.state.servers.size > 1) {
const lastSegment = window.location.pathname.split('/').pop(), const lastSegment = window.location.pathname.split('/').pop(),
serverName = lastSegment && config.has(lastSegment) ? lastSegment : config.keys().next().value; serverName = lastSegment && store.state.servers.has(lastSegment) ? lastSegment : store.state.servers.keys().next().value;
//Update url if server doesn't exist //Update url if server doesn't exist
if(serverName !== lastSegment) { if(serverName !== lastSegment) {
@ -65,7 +65,7 @@ try {
store.commit(MutationTypes.SET_CURRENT_SERVER, serverName); store.commit(MutationTypes.SET_CURRENT_SERVER, serverName);
} else { } else {
store.commit(MutationTypes.SET_CURRENT_SERVER, config.keys().next().value); store.commit(MutationTypes.SET_CURRENT_SERVER, store.state.servers.keys().next().value);
} }
const app = createApp(App) const app = createApp(App)

View File

@ -80,12 +80,12 @@ export interface Actions {
export const actions: ActionTree<State, State> & Actions = { export const actions: ActionTree<State, State> & Actions = {
async [ActionTypes.LOAD_CONFIGURATION]({commit, state}): Promise<DynmapConfigurationResponse> { async [ActionTypes.LOAD_CONFIGURATION]({commit, state}): Promise<DynmapConfigurationResponse> {
//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_SERVER_CONFIGURATION_HASH, undefined);
const config = await getAPI().getConfiguration(); const config = await getAPI().getConfiguration();
commit(MutationTypes.SET_CONFIGURATION, config.config); commit(MutationTypes.SET_SERVER_CONFIGURATION, config.config);
commit(MutationTypes.SET_MESSAGES, config.messages); commit(MutationTypes.SET_SERVER_MESSAGES, config.messages);
commit(MutationTypes.SET_WORLDS, config.worlds); commit(MutationTypes.SET_WORLDS, config.worlds);
commit(MutationTypes.SET_COMPONENTS, config.components); commit(MutationTypes.SET_COMPONENTS, config.components);
commit(MutationTypes.SET_LOGGED_IN, config.loggedIn); commit(MutationTypes.SET_LOGGED_IN, config.loggedIn);
@ -159,7 +159,7 @@ export const actions: ActionTree<State, State> & Actions = {
commit(MutationTypes.ADD_MARKER_SET_UPDATES, update.updates.markerSets); commit(MutationTypes.ADD_MARKER_SET_UPDATES, update.updates.markerSets);
commit(MutationTypes.ADD_TILE_UPDATES, update.updates.tiles); commit(MutationTypes.ADD_TILE_UPDATES, update.updates.tiles);
commit(MutationTypes.ADD_CHAT, update.updates.chat); commit(MutationTypes.ADD_CHAT, update.updates.chat);
commit(MutationTypes.SET_CONFIGURATION_HASH, update.configHash); commit(MutationTypes.SET_SERVER_CONFIGURATION_HASH, update.configHash);
await dispatch(ActionTypes.SET_PLAYERS, update.players); await dispatch(ActionTypes.SET_PLAYERS, update.players);
return update; return update;

View File

@ -17,11 +17,10 @@
export enum MutationTypes { export enum MutationTypes {
INIT ='init', INIT ='init',
SET_SERVERS ='setServers', SET_SERVER_CONFIGURATION = 'setServerConfiguration',
SET_CONFIGURATION = 'setConfiguration', SET_SERVER_CONFIGURATION_HASH = 'setServerConfigurationHash',
SET_CONFIGURATION_HASH = 'setConfigurationHash', CLEAR_SERVER_CONFIGURATION_HASH = 'clearServerConfigurationHash',
CLEAR_CONFIGURATION_HASH = 'clearConfigurationHash', SET_SERVER_MESSAGES = 'setServerMessages',
SET_MESSAGES = 'setMessages',
SET_WORLDS = 'setWorlds', SET_WORLDS = 'setWorlds',
CLEAR_WORLDS = 'clearWorlds', CLEAR_WORLDS = 'clearWorlds',
SET_COMPONENTS = 'setComponents', SET_COMPONENTS = 'setComponents',

View File

@ -30,12 +30,16 @@ import {
} from "@/dynmap"; } from "@/dynmap";
import {DynmapProjection} from "@/leaflet/projection/DynmapProjection"; import {DynmapProjection} from "@/leaflet/projection/DynmapProjection";
import { import {
Coordinate, LiveAtlasWorldState, Coordinate,
LiveAtlasMessageConfig, LiveAtlasWorldState,
LiveAtlasServerDefinition,
LiveAtlasSidebarSection, LiveAtlasSidebarSection,
LiveAtlasSortedPlayers, LiveAtlasSortedPlayers,
LiveAtlasUIElement, LiveAtlasWorld, LiveAtlasParsedUrl LiveAtlasUIElement,
LiveAtlasWorld,
LiveAtlasParsedUrl,
LiveAtlasGlobalConfig,
LiveAtlasGlobalMessageConfig,
LiveAtlasServerMessageConfig
} from "@/index"; } from "@/index";
export type CurrentMapPayload = { export type CurrentMapPayload = {
@ -44,12 +48,11 @@ export type CurrentMapPayload = {
} }
export type Mutations<S = State> = { export type Mutations<S = State> = {
[MutationTypes.INIT](state: S): void [MutationTypes.INIT](state: S, config: LiveAtlasGlobalConfig): void
[MutationTypes.SET_SERVERS](state: S, servers: Map<string, LiveAtlasServerDefinition>): void [MutationTypes.SET_SERVER_CONFIGURATION](state: S, config: DynmapServerConfig): void
[MutationTypes.SET_CONFIGURATION](state: S, config: DynmapServerConfig): void [MutationTypes.SET_SERVER_CONFIGURATION_HASH](state: S, hash: number): void
[MutationTypes.SET_CONFIGURATION_HASH](state: S, hash: number): void [MutationTypes.CLEAR_SERVER_CONFIGURATION_HASH](state: S): void
[MutationTypes.CLEAR_CONFIGURATION_HASH](state: S): void [MutationTypes.SET_SERVER_MESSAGES](state: S, messages: LiveAtlasServerMessageConfig): void
[MutationTypes.SET_MESSAGES](state: S, messages: LiveAtlasMessageConfig): void
[MutationTypes.SET_WORLDS](state: S, worlds: Array<LiveAtlasWorld>): void [MutationTypes.SET_WORLDS](state: S, worlds: Array<LiveAtlasWorld>): void
[MutationTypes.CLEAR_WORLDS](state: S): void [MutationTypes.CLEAR_WORLDS](state: S): void
[MutationTypes.SET_COMPONENTS](state: S, worlds: DynmapComponentConfig): void [MutationTypes.SET_COMPONENTS](state: S, worlds: DynmapComponentConfig): void
@ -96,17 +99,54 @@ export type Mutations<S = State> = {
} }
export const mutations: MutationTree<State> & Mutations = { export const mutations: MutationTree<State> & Mutations = {
[MutationTypes.INIT](state: State) { [MutationTypes.INIT](state: State, config: LiveAtlasGlobalConfig) {
const collapsedSections = localStorage.getItem('collapsedSections'); const collapsedSections = localStorage.getItem('collapsedSections'),
messageConfig = config?.messages || {},
uiConfig = config?.ui || {};
if(collapsedSections) { if(collapsedSections) {
state.ui.sidebar.collapsedSections = new Set(JSON.parse(collapsedSections)); state.ui.sidebar.collapsedSections = new Set(JSON.parse(collapsedSections));
} }
},
// Sets configuration options from the initial config fetch const messages: LiveAtlasGlobalMessageConfig = {
[MutationTypes.SET_SERVERS](state: State, config: Map<string, LiveAtlasServerDefinition>) { chatTitle: messageConfig.chatTitle || '',
state.servers = config; chatLogin: messageConfig.chatLogin || '',
chatLoginLink: messageConfig.chatLoginLink || '',
chatNoMessages: messageConfig.chatNoMessages || '',
chatSend: messageConfig.chatSend || '',
chatPlaceholder: messageConfig.chatPlaceholder || '',
chatErrorDisabled: messageConfig.chatErrorDisabled || '',
chatErrorUnknown: messageConfig.chatErrorUnknown || '',
serversHeading: messageConfig.serversHeading || '',
worldsSkeleton: messageConfig.worldsSkeleton || '',
playersSkeleton: messageConfig.playersSkeleton || '',
playersTitle: messageConfig.playersTitle || '',
playersTitleHidden: messageConfig.playersTitleHidden || '',
playersTitleOtherWorld: messageConfig.playersTitleOtherWorld || '',
followingHeading: messageConfig.followingHeading || '',
followingHidden: messageConfig.followingHidden || '',
followingUnfollow: messageConfig.followingUnfollow || '',
followingTitleUnfollow: messageConfig.followingTitleUnfollow || '',
linkTitle: messageConfig.linkTitle || '',
loadingTitle: messageConfig.loadingTitle || '',
locationRegion: messageConfig.locationRegion || '',
locationChunk: messageConfig.locationChunk || '',
contextMenuCopyLink: messageConfig.contextMenuCopyLink || '',
contextMenuCenterHere: messageConfig.contextMenuCenterHere || '',
toggleTitle: messageConfig.toggleTitle || '',
mapTitle: messageConfig.mapTitle || '',
layersTitle: messageConfig.layersTitle || '',
copyToClipboardSuccess: messageConfig.copyToClipboardSuccess || '',
copyToClipboardError: messageConfig.copyToClipboardError || '',
}
state.messages = Object.assign(state.messages, messages);
if(typeof uiConfig.playersAboveMarkers === 'boolean') {
state.ui.playersAboveMarkers = uiConfig.playersAboveMarkers;
}
state.servers = config.servers;
if(state.currentServer && !state.servers.has(state.currentServer.id)) { if(state.currentServer && !state.servers.has(state.currentServer.id)) {
state.currentServer = undefined; state.currentServer = undefined;
@ -114,23 +154,23 @@ export const mutations: MutationTree<State> & Mutations = {
}, },
// Sets configuration options from the initial config fetch // Sets configuration options from the initial config fetch
[MutationTypes.SET_CONFIGURATION](state: State, config: DynmapServerConfig) { [MutationTypes.SET_SERVER_CONFIGURATION](state: State, config: DynmapServerConfig) {
state.configuration = Object.assign(state.configuration, config); state.configuration = Object.assign(state.configuration, config);
state.configurationHash = config.hash; state.configurationHash = config.hash;
}, },
// Sets configuration hash // Sets configuration hash
[MutationTypes.SET_CONFIGURATION_HASH](state: State, hash: number) { [MutationTypes.SET_SERVER_CONFIGURATION_HASH](state: State, hash: number) {
state.configurationHash = hash; state.configurationHash = hash;
}, },
// Sets configuration hash // Sets configuration hash
[MutationTypes.CLEAR_CONFIGURATION_HASH](state: State) { [MutationTypes.CLEAR_SERVER_CONFIGURATION_HASH](state: State) {
state.configurationHash = undefined; state.configurationHash = undefined;
}, },
//Set messages from the initial config fetch // Sets messages from the initial config fetch
[MutationTypes.SET_MESSAGES](state: State, messages: LiveAtlasMessageConfig) { [MutationTypes.SET_SERVER_MESSAGES](state: State, messages: LiveAtlasServerMessageConfig) {
state.messages = Object.assign(state.messages, messages); state.messages = Object.assign(state.messages, messages);
}, },

View File

@ -22,12 +22,16 @@ import {
} from "@/dynmap"; } from "@/dynmap";
import {DynmapProjection} from "@/leaflet/projection/DynmapProjection"; import {DynmapProjection} from "@/leaflet/projection/DynmapProjection";
import { import {
Coordinate, LiveAtlasWorldState, Coordinate,
LiveAtlasMessageConfig, LiveAtlasWorldState,
LiveAtlasServerDefinition, LiveAtlasServerDefinition,
LiveAtlasSidebarSection, LiveAtlasSidebarSection,
LiveAtlasSortedPlayers, LiveAtlasSortedPlayers,
LiveAtlasUIElement, LiveAtlasWorld, LiveAtlasWorldMap, LiveAtlasParsedUrl LiveAtlasUIElement,
LiveAtlasWorld,
LiveAtlasWorldMap,
LiveAtlasParsedUrl,
LiveAtlasMessageConfig
} from "@/index"; } from "@/index";
export type State = { export type State = {
@ -222,7 +226,7 @@ export const state: State = {
updateTimestamp: new Date(), updateTimestamp: new Date(),
ui: { ui: {
playersAboveMarkers: window.liveAtlasConfig?.ui?.playersAboveMarkers || false, playersAboveMarkers: true,
smallScreen: false, smallScreen: false,
visibleElements: new Set(), visibleElements: new Set(),

View File

@ -1,4 +1,4 @@
import {LiveAtlasDynmapServerDefinition, LiveAtlasServerDefinition} from "@/index"; import {LiveAtlasDynmapServerDefinition, LiveAtlasGlobalConfig, LiveAtlasServerDefinition} from "@/index";
import ConfigurationError from "@/errors/ConfigurationError"; import ConfigurationError from "@/errors/ConfigurationError";
import {DynmapUrlConfig} from "@/dynmap"; import {DynmapUrlConfig} from "@/dynmap";
@ -102,14 +102,15 @@ const validateDynmapConfiguration = (config: DynmapUrlConfig): Map<string, LiveA
return result; return result;
}; };
export const validateConfiguration = (): Map<string, LiveAtlasServerDefinition> => { export const getServerDefinitions = (config: LiveAtlasGlobalConfig): Map<string, LiveAtlasServerDefinition> => {
if (!window.liveAtlasConfig) { if (!config) {
throw new ConfigurationError(`Configuration object is missing`); throw new ConfigurationError(`Configuration object is missing`);
} }
if (typeof window.liveAtlasConfig.servers !== 'undefined') { if (typeof config !== 'undefined') {
return validateLiveAtlasConfiguration(window.liveAtlasConfig.servers || {}); return validateLiveAtlasConfiguration(config.servers || {});
} }
return validateDynmapConfiguration(window.config?.url || null); return validateDynmapConfiguration(window.config?.url || null);
}; };