Initial work for multiple servers
This commit is contained in:
parent
9720bf90d9
commit
0facb446f5
42
index.html
42
index.html
@ -20,8 +20,49 @@
|
||||
<meta name="description" content="Minecraft Dynamic Map" />
|
||||
|
||||
<title>Minecraft Dynamic Map - LiveAtlas</title>
|
||||
<!-- Remove this if you are using multiple maps -->
|
||||
<script src="./standalone/config.js"></script>
|
||||
<script>
|
||||
window.liveAtlasConfig = {
|
||||
// Server URLS can be defined here instead of using the standalone/config.js file.
|
||||
// Multiple servers are supported too.
|
||||
// servers: {
|
||||
// creative: {
|
||||
// label: 'Creative',
|
||||
// configuration: 'http://dynmap.local/standalone/creative/MySQL_configuration.php',
|
||||
// update: 'http://dynmap.local/standalone/creative/MySQL_update.php?world={world}&ts={timestamp}',
|
||||
// sendmessage: 'http://dynmap.local/standalone/creative/MySQL_sendmessage.php',
|
||||
// login: 'http://dynmap.local/standalone/creative/MySQL_login.php',
|
||||
// register: 'http://dynmap.local/standalone/creative/MySQL_register.php',
|
||||
// tiles: 'http://dynmap.local/standalone/creative/MySQL_tiles.php?tile=',
|
||||
// markers: 'http://dynmap.local/standalone/creative/MySQL_markers.php?marker='
|
||||
// },
|
||||
// survival: {
|
||||
// label: 'Survival',
|
||||
// configuration: 'http://dynmap.local/standalone/survival/MySQL_configuration.php',
|
||||
// update: 'http://dynmap.local/standalone/survival/MySQL_update.php?world={world}&ts={timestamp}',
|
||||
// sendmessage: 'http://dynmap.local/standalone/survival/MySQL_sendmessage.php',
|
||||
// login: 'http://dynmap.local/standalone/survival/MySQL_login.php',
|
||||
// register: 'http://dynmap.local/standalone/survival/MySQL_register.php',
|
||||
// tiles: 'http://dynmap.local/standalone/survival/MySQL_tiles.php?tile=',
|
||||
// markers: 'http://dynmap.local/standalone/survival/MySQL_markers.php?marker='
|
||||
// },
|
||||
// build: {
|
||||
// label: 'Build',
|
||||
// configuration: 'http://dynmap.local/standalone/build/MySQL_configuration.php',
|
||||
// update: 'http://dynmap.local/standalone/build/MySQL_update.php?world={world}&ts={timestamp}',
|
||||
// sendmessage: 'http://dynmap.local/standalone/build/MySQL_sendmessage.php',
|
||||
// login: 'http://dynmap.local/standalone/build/MySQL_login.php',
|
||||
// register: 'http://dynmap.local/standalone/build/MySQL_register.php',
|
||||
// tiles: 'http://dynmap.local/standalone/build/MySQL_tiles.php?tile=',
|
||||
// markers: 'http://dynmap.local/standalone/build/MySQL_markers.php?marker='
|
||||
// }
|
||||
// }
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Theme colours */
|
||||
:root {
|
||||
--background-base: #222222; /* Buttons/sidebar */
|
||||
--background-dark: #121212; /* Body/map labels */
|
||||
@ -171,7 +212,6 @@
|
||||
</noscript>
|
||||
|
||||
<div id="mcmap" class="dynmap"></div>
|
||||
<script src="./standalone/config.js"></script>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
3376
package-lock.json
generated
3376
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
32
package.json
32
package.json
@ -9,32 +9,28 @@
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.5",
|
||||
"vue": "^3.0.0"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/clipboard": "^2.0.1",
|
||||
"@types/leaflet": "^1.5.19",
|
||||
"@typescript-eslint/eslint-plugin": "^4.1.0",
|
||||
"@typescript-eslint/parser": "^4.1.0",
|
||||
"@types/leaflet": "^1.7.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.23.0",
|
||||
"@typescript-eslint/parser": "^4.23.0",
|
||||
"@vitejs/plugin-vue": "^1.2.2",
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"@vue/eslint-config-typescript": "^5.0.2",
|
||||
"clipboard": "^2.0.6",
|
||||
"eslint": "^7.5.0",
|
||||
"eslint-plugin-vue": "^7.0.0-0",
|
||||
"@vue/compiler-sfc": "^3.0.11",
|
||||
"@vue/eslint-config-typescript": "^7.0.0",
|
||||
"clipboard": "^2.0.8",
|
||||
"eslint": "^7.26.0",
|
||||
"eslint-plugin-vue": "^7.9.0",
|
||||
"leaflet": "^1.7.1",
|
||||
"normalize-scss": "^7.0.1",
|
||||
"sass": "^1.29.0",
|
||||
"svgo": "^1.1.0",
|
||||
"svgo-loader": "^2.1.0",
|
||||
"typescript": "~3.9.3",
|
||||
"sass": "^1.32.13",
|
||||
"typescript": "~4.2.4",
|
||||
"vite": "^2.3.2",
|
||||
"vite-plugin-cdn": "^1.0.0-beta.3",
|
||||
"vite-plugin-svg-sprite-component": "^1.0.8",
|
||||
"vue-cli-plugin-svg-sprite": "~1.0.0",
|
||||
"vue": "^3.0.11",
|
||||
"vue-tsc": "^0.1.2",
|
||||
"vuex": "^4.0.0-rc.1"
|
||||
"vuex": "^4.0.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
32
src/App.vue
32
src/App.vue
@ -44,6 +44,7 @@ export default defineComponent({
|
||||
updateInterval = computed(() => store.state.configuration.updateInterval),
|
||||
title = computed(() => store.state.configuration.title),
|
||||
currentUrl = computed(() => store.getters.url),
|
||||
currentServer = computed(() => store.state.currentServer),
|
||||
chatBoxEnabled = computed(() => store.state.components.chatBox),
|
||||
chatVisible = computed(() => store.state.ui.visibleElements.has('chat')),
|
||||
updatesEnabled = ref(false),
|
||||
@ -51,24 +52,14 @@ export default defineComponent({
|
||||
configAttempts = ref(0),
|
||||
|
||||
loadConfiguration = () => {
|
||||
let validated = false;
|
||||
|
||||
API.validateConfiguration().then(() => {
|
||||
validated = true;
|
||||
|
||||
return store.dispatch(ActionTypes.LOAD_CONFIGURATION, undefined).then(() => {
|
||||
startUpdates();
|
||||
window.hideSplash();
|
||||
});
|
||||
return store.dispatch(ActionTypes.LOAD_CONFIGURATION, undefined).then(() => {
|
||||
startUpdates();
|
||||
window.hideSplash();
|
||||
}).catch(e => {
|
||||
console.error('Failed to load server configuration: ', e);
|
||||
window.showSplashError(e, !validated, ++configAttempts.value);
|
||||
|
||||
//Don't retry if config isn't valid
|
||||
if(validated) {
|
||||
setTimeout(() => loadConfiguration(), 1000);
|
||||
}
|
||||
})
|
||||
window.showSplashError(e, false, ++configAttempts.value);
|
||||
setTimeout(() => loadConfiguration(), 1000);
|
||||
});
|
||||
},
|
||||
|
||||
startUpdates = () => {
|
||||
@ -121,6 +112,15 @@ export default defineComponent({
|
||||
|
||||
watch(title, (title) => document.title = title);
|
||||
watch(currentUrl, (url) => window.history.replaceState({}, '', url));
|
||||
watch(currentServer, (newServer) => {
|
||||
window.showSplash();
|
||||
stopUpdates();
|
||||
window.history.replaceState({}, '', newServer);
|
||||
store.commit(MutationTypes.CLEAR_PARSED_URL, undefined);
|
||||
store.commit(MutationTypes.CLEAR_CURRENT_ZOOM, undefined);
|
||||
|
||||
loadConfiguration();
|
||||
});
|
||||
|
||||
onMounted(() => loadConfiguration());
|
||||
onBeforeUnmount(() => stopUpdates());
|
||||
|
195
src/api.ts
195
src/api.ts
@ -36,6 +36,7 @@ import {
|
||||
} from "@/dynmap";
|
||||
import {useStore} from "@/store";
|
||||
import ChatError from "@/errors/ChatError";
|
||||
import {LiveAtlasServerDefinition} from "@/index";
|
||||
|
||||
function buildServerConfig(response: any): DynmapServerConfig {
|
||||
return {
|
||||
@ -118,22 +119,22 @@ function buildWorlds(response: any): Array<DynmapWorld> {
|
||||
|
||||
function buildComponents(response: any): DynmapComponentConfig {
|
||||
const components: DynmapComponentConfig = {
|
||||
markers: {
|
||||
showLabels: false,
|
||||
},
|
||||
chatBox: undefined,
|
||||
chatBalloons: false,
|
||||
playerMarkers: undefined,
|
||||
coordinatesControl: undefined,
|
||||
linkControl: false,
|
||||
clockControl: undefined,
|
||||
logoControls: [],
|
||||
};
|
||||
markers: {
|
||||
showLabels: false,
|
||||
},
|
||||
chatBox: undefined,
|
||||
chatBalloons: false,
|
||||
playerMarkers: undefined,
|
||||
coordinatesControl: undefined,
|
||||
linkControl: false,
|
||||
clockControl: undefined,
|
||||
logoControls: [],
|
||||
};
|
||||
|
||||
(response.components || []).forEach((component: any) => {
|
||||
const type = component.type || "unknown";
|
||||
|
||||
switch(type) {
|
||||
switch (type) {
|
||||
case "markers":
|
||||
components.markers = {
|
||||
showLabels: component.showlabel || false,
|
||||
@ -195,7 +196,7 @@ function buildComponents(response: any): DynmapComponentConfig {
|
||||
break;
|
||||
|
||||
case "chat":
|
||||
if(response.allowwebchat) {
|
||||
if (response.allowwebchat) {
|
||||
components.chatSending = {
|
||||
loginRequired: response['webchat-requires-login'] || false,
|
||||
maxLength: response['chatlengthlimit'] || 256,
|
||||
@ -236,7 +237,7 @@ function buildMarkerSet(id: string, data: any): any {
|
||||
function buildMarkers(data: any): Map<string, DynmapMarker> {
|
||||
const markers = Object.freeze(new Map()) as Map<string, DynmapMarker>;
|
||||
|
||||
for(const key in data) {
|
||||
for (const key in data) {
|
||||
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
||||
continue;
|
||||
}
|
||||
@ -267,7 +268,7 @@ function buildMarker(marker: any): DynmapMarker {
|
||||
function buildAreas(data: any): Map<string, DynmapArea> {
|
||||
const areas = Object.freeze(new Map()) as Map<string, DynmapArea>;
|
||||
|
||||
for(const key in data) {
|
||||
for (const key in data) {
|
||||
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
||||
continue;
|
||||
}
|
||||
@ -279,7 +280,7 @@ function buildAreas(data: any): Map<string, DynmapArea> {
|
||||
}
|
||||
|
||||
function buildArea(area: any): DynmapArea {
|
||||
return {
|
||||
return {
|
||||
style: {
|
||||
color: area.color || '#ff0000',
|
||||
opacity: area.opacity || 1,
|
||||
@ -301,7 +302,7 @@ function buildArea(area: any): DynmapArea {
|
||||
function buildLines(data: any): Map<string, DynmapLine> {
|
||||
const lines = Object.freeze(new Map()) as Map<string, DynmapLine>;
|
||||
|
||||
for(const key in data) {
|
||||
for (const key in data) {
|
||||
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
||||
continue;
|
||||
}
|
||||
@ -333,7 +334,7 @@ function buildLine(line: any): DynmapLine {
|
||||
function buildCircles(data: any): Map<string, DynmapCircle> {
|
||||
const circles = Object.freeze(new Map()) as Map<string, DynmapCircle>;
|
||||
|
||||
for(const key in data) {
|
||||
for (const key in data) {
|
||||
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
||||
continue;
|
||||
}
|
||||
@ -370,10 +371,10 @@ function buildCircle(circle: any): DynmapCircle {
|
||||
|
||||
function buildUpdates(data: Array<any>): DynmapUpdates {
|
||||
const updates = {
|
||||
markerSets: new Map<string, DynmapMarkerSetUpdates>(),
|
||||
tiles: [] as DynmapTileUpdate[],
|
||||
chat: [] as DynmapChat[],
|
||||
},
|
||||
markerSets: new Map<string, DynmapMarkerSetUpdates>(),
|
||||
tiles: [] as DynmapTileUpdate[],
|
||||
chat: [] as DynmapChat[],
|
||||
},
|
||||
dropped = {
|
||||
stale: 0,
|
||||
noSet: 0,
|
||||
@ -387,15 +388,15 @@ function buildUpdates(data: Array<any>): DynmapUpdates {
|
||||
|
||||
let accepted = 0;
|
||||
|
||||
for(const entry of data) {
|
||||
switch(entry.type) {
|
||||
for (const entry of data) {
|
||||
switch (entry.type) {
|
||||
case 'component': {
|
||||
if(lastUpdate && entry.timestamp < lastUpdate) {
|
||||
if (lastUpdate && entry.timestamp < lastUpdate) {
|
||||
dropped.stale++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!entry.id) {
|
||||
if (!entry.id) {
|
||||
dropped.noId++;
|
||||
continue;
|
||||
}
|
||||
@ -403,17 +404,17 @@ function buildUpdates(data: Array<any>): DynmapUpdates {
|
||||
//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) {
|
||||
if (!set) {
|
||||
dropped.noSet++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(entry.ctype !== 'markers') {
|
||||
if (entry.ctype !== 'markers') {
|
||||
dropped.unknownCType++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!updates.markerSets.has(set)) {
|
||||
if (!updates.markerSets.has(set)) {
|
||||
updates.markerSets.set(set, {
|
||||
areaUpdates: [],
|
||||
markerUpdates: [],
|
||||
@ -429,21 +430,21 @@ function buildUpdates(data: Array<any>): DynmapUpdates {
|
||||
removed: entry.msg.endsWith('deleted'),
|
||||
};
|
||||
|
||||
if(entry.msg.startsWith("set")) {
|
||||
if (entry.msg.startsWith("set")) {
|
||||
markerSetUpdates!.removed = update.removed;
|
||||
markerSetUpdates!.payload = update.removed ? undefined : buildMarkerSet(set, entry);
|
||||
} else if(entry.msg.startsWith("marker")) {
|
||||
} 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")) {
|
||||
} 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")) {
|
||||
} 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")) {
|
||||
} else if (entry.msg.startsWith("line")) {
|
||||
update.payload = update.removed ? undefined : buildLine(entry);
|
||||
markerSetUpdates!.lineUpdates.push(Object.freeze(update));
|
||||
}
|
||||
@ -454,17 +455,17 @@ function buildUpdates(data: Array<any>): DynmapUpdates {
|
||||
}
|
||||
|
||||
case 'chat':
|
||||
if(!entry.message || !entry.timestamp) {
|
||||
if (!entry.message || !entry.timestamp) {
|
||||
dropped.incomplete++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(entry.timestamp < lastUpdate) {
|
||||
if (entry.timestamp < lastUpdate) {
|
||||
dropped.stale++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(entry.source !== 'player' && entry.source !== 'web') {
|
||||
if (entry.source !== 'player' && entry.source !== 'web') {
|
||||
dropped.notImplemented++;
|
||||
continue;
|
||||
}
|
||||
@ -481,12 +482,12 @@ function buildUpdates(data: Array<any>): DynmapUpdates {
|
||||
break;
|
||||
|
||||
case 'playerjoin':
|
||||
if(!entry.account || !entry.timestamp) {
|
||||
if (!entry.account || !entry.timestamp) {
|
||||
dropped.incomplete++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(entry.timestamp < lastUpdate) {
|
||||
if (entry.timestamp < lastUpdate) {
|
||||
dropped.stale++;
|
||||
continue;
|
||||
}
|
||||
@ -500,12 +501,12 @@ function buildUpdates(data: Array<any>): DynmapUpdates {
|
||||
break;
|
||||
|
||||
case 'playerquit':
|
||||
if(!entry.account || !entry.timestamp) {
|
||||
if (!entry.account || !entry.timestamp) {
|
||||
dropped.incomplete++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(entry.timestamp < lastUpdate) {
|
||||
if (entry.timestamp < lastUpdate) {
|
||||
dropped.stale++;
|
||||
continue;
|
||||
}
|
||||
@ -519,12 +520,12 @@ function buildUpdates(data: Array<any>): DynmapUpdates {
|
||||
break;
|
||||
|
||||
case 'tile':
|
||||
if(!entry.name || !entry.timestamp) {
|
||||
if (!entry.name || !entry.timestamp) {
|
||||
dropped.incomplete++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(lastUpdate && entry.timestamp < lastUpdate) {
|
||||
if (lastUpdate && entry.timestamp < lastUpdate) {
|
||||
dropped.stale++;
|
||||
continue;
|
||||
}
|
||||
@ -553,45 +554,105 @@ function buildUpdates(data: Array<any>): DynmapUpdates {
|
||||
}
|
||||
|
||||
export default {
|
||||
validateConfiguration(): Promise<void> {
|
||||
validateConfiguration(): Promise<Map<string, LiveAtlasServerDefinition>> {
|
||||
if (typeof window.liveAtlasConfig.servers !== 'undefined') {
|
||||
return this.validateLiveAtlasConfiguration(window.liveAtlasConfig.servers);
|
||||
}
|
||||
|
||||
return this.validateDynmapConfiguration(window.config.url ?? null);
|
||||
},
|
||||
|
||||
validateLiveAtlasConfiguration(config: any): Promise<Map<string, LiveAtlasServerDefinition>> {
|
||||
const check = '\nCheck your LiveAtlas configuration in index.html is correct.',
|
||||
result = new Map<string, LiveAtlasServerDefinition>();
|
||||
|
||||
if (!Object.keys(config).length) {
|
||||
return Promise.reject(`No servers defined in LiveAtlas configuration.`);
|
||||
}
|
||||
|
||||
for (const server in config) {
|
||||
if (!Object.hasOwnProperty.call(config, server)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const serverConfig = config[server];
|
||||
|
||||
if (!serverConfig || serverConfig.constructor !== Object) {
|
||||
return Promise.reject(`Server '${server} has an invalid configuration. ${check}`);
|
||||
}
|
||||
|
||||
if (!serverConfig.configuration) {
|
||||
return Promise.reject(`Server '${server} has no configuration URL. ${check}`);
|
||||
}
|
||||
|
||||
if (!serverConfig.update) {
|
||||
return Promise.reject(`Server '${server} has no update URL. ${check}`);
|
||||
}
|
||||
|
||||
if (!serverConfig.markers) {
|
||||
return Promise.reject(`Server '${server} has no markers URL. ${check}`);
|
||||
}
|
||||
|
||||
if (!serverConfig.tiles) {
|
||||
return Promise.reject(`Server '${server} has no tiles URL. ${check}`);
|
||||
}
|
||||
|
||||
if (!serverConfig.sendmessage) {
|
||||
return Promise.reject(`Server '${server} has no sendmessage URL. ${check}`);
|
||||
}
|
||||
|
||||
serverConfig.id = server;
|
||||
result.set(server, serverConfig);
|
||||
}
|
||||
|
||||
return Promise.resolve(result);
|
||||
},
|
||||
|
||||
validateDynmapConfiguration(config: LiveAtlasServerDefinition): Promise<Map<string, LiveAtlasServerDefinition>> {
|
||||
const check = '\nCheck your standalone/config.js file exists and is being loaded correctly.';
|
||||
|
||||
if(!window.config || !window.config.url) {
|
||||
return Promise.reject(`Dynmap's configuration is missing. ${check}`);
|
||||
if (!config) {
|
||||
return Promise.reject(`Dynmap configuration is missing. ${check}`);
|
||||
}
|
||||
|
||||
if(!window.config.url.configuration) {
|
||||
return Promise.reject(`Dynmap's configuration URL is missing. ${check}`);
|
||||
if (!config.configuration) {
|
||||
return Promise.reject(`Dynmap configuration URL is missing. ${check}`);
|
||||
}
|
||||
|
||||
if(!window.config.url.update) {
|
||||
return Promise.reject(`Dynmap's update URL is missing. ${check}`);
|
||||
if (!config.update) {
|
||||
return Promise.reject(`Dynmap update URL is missing. ${check}`);
|
||||
}
|
||||
|
||||
if(!window.config.url.markers) {
|
||||
return Promise.reject(`Dynmap's markers URL is missing. ${check}`);
|
||||
if (!config.markers) {
|
||||
return Promise.reject(`Dynmap markers URL is missing. ${check}`);
|
||||
}
|
||||
|
||||
if(!window.config.url.tiles) {
|
||||
return Promise.reject(`Dynmap's tiles URL is missing. ${check}`);
|
||||
if (!config.tiles) {
|
||||
return Promise.reject(`Dynmap tiles URL is missing. ${check}`);
|
||||
}
|
||||
|
||||
if(!window.config.url.sendmessage) {
|
||||
return Promise.reject(`Dynmap's sendmessage URL is missing. ${check}`);
|
||||
if (!config.sendmessage) {
|
||||
return Promise.reject(`Dynmap sendmessage URL is missing. ${check}`);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
config.id = 'dynmap';
|
||||
config.label = 'Dynmap';
|
||||
|
||||
const result = new Map<string, LiveAtlasServerDefinition>();
|
||||
result.set('dynmap', config);
|
||||
|
||||
return Promise.resolve(result);
|
||||
},
|
||||
|
||||
getConfiguration(): Promise<DynmapConfigurationResponse> {
|
||||
return fetch(window.config.url.configuration).then(response => {
|
||||
return fetch(useStore().getters.serverConfig.configuration).then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network request failed: ' + response.statusText);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}).then((response): DynmapConfigurationResponse => {
|
||||
if(response.error === 'login-required') {
|
||||
if (response.error === 'login-required') {
|
||||
throw new Error("Login required");
|
||||
} else if (response.error) {
|
||||
throw new Error(response.error);
|
||||
@ -608,7 +669,7 @@ export default {
|
||||
},
|
||||
|
||||
getUpdate(requestId: number, world: string, timestamp: number): Promise<DynmapUpdateResponse> {
|
||||
let url = window.config.url.update;
|
||||
let url = useStore().getters.serverConfig.update;
|
||||
url = url.replace('{world}', world);
|
||||
url = url.replace('{timestamp}', timestamp.toString());
|
||||
|
||||
@ -674,7 +735,7 @@ export default {
|
||||
},
|
||||
|
||||
getMarkerSets(world: string): Promise<Map<string, DynmapMarkerSet>> {
|
||||
const url = `${window.config.url.markers}_markers_/marker_${world}.json`;
|
||||
const url = `${useStore().getters.serverConfig.markers}_markers_/marker_${world}.json`;
|
||||
|
||||
return fetch(url).then(response => {
|
||||
if (!response.ok) {
|
||||
@ -687,8 +748,8 @@ export default {
|
||||
|
||||
response.sets = response.sets || {};
|
||||
|
||||
for(const key in response.sets) {
|
||||
if(!Object.prototype.hasOwnProperty.call(response.sets, key)) {
|
||||
for (const key in response.sets) {
|
||||
if (!Object.prototype.hasOwnProperty.call(response.sets, key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -714,18 +775,18 @@ export default {
|
||||
sendChatMessage(message: string) {
|
||||
const store = useStore();
|
||||
|
||||
if(!store.state.components.chatSending) {
|
||||
if (!store.state.components.chatSending) {
|
||||
return Promise.reject(new ChatError("Chat is not enabled"));
|
||||
}
|
||||
|
||||
return fetch(window.config.url.sendmessage, {
|
||||
return fetch(useStore().getters.serverConfig.sendmessage, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
name: null,
|
||||
message: message,
|
||||
})
|
||||
}).then((response) => {
|
||||
if(response.status === 403) { //Rate limited
|
||||
if (response.status === 403) { //Rate limited
|
||||
throw new ChatError(store.state.messages.chatCooldown
|
||||
.replace('%interval%', store.state.components.chatSending!.cooldown.toString()));
|
||||
}
|
||||
@ -740,7 +801,7 @@ export default {
|
||||
throw new ChatError(store.state.messages.chatNotAllowed);
|
||||
}
|
||||
}).catch(e => {
|
||||
if(!(e instanceof ChatError)) {
|
||||
if (!(e instanceof ChatError)) {
|
||||
console.error('Unexpected error while sending chat message');
|
||||
console.trace(e);
|
||||
}
|
||||
|
@ -168,6 +168,11 @@ export default defineComponent({
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
will-change: transform;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.section__skeleton {
|
||||
|
68
src/components/sidebar/ServerListItem.vue
Normal file
68
src/components/sidebar/ServerListItem.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<!--
|
||||
- Copyright 2020 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.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<li :class="{'server': true, 'server--selected': server.id === currentServer.id}">
|
||||
<button type="button" :title="server.label || server.id" @click="setCurrentServer(server.id)">{{ server.label || server.id }}</button>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {useStore} from "@/store";
|
||||
import {defineComponent} from 'vue';
|
||||
import {MutationTypes} from "@/store/mutation-types";
|
||||
import {LiveAtlasServerDefinition} from "@/index";
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ServerListItem',
|
||||
props: {
|
||||
server: {
|
||||
type: Object as () => LiveAtlasServerDefinition,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
currentServer(): LiveAtlasServerDefinition | undefined {
|
||||
return useStore().state.currentServer;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setCurrentServer(serverId: string) {
|
||||
useStore().commit(MutationTypes.SET_CURRENT_SERVER, serverId);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.server {
|
||||
height: 3.2rem;
|
||||
|
||||
button {
|
||||
text-align: left;
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
&.server--selected button {
|
||||
background-color: var(--background-hover);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -15,6 +15,12 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<section class="sidebar__section" v-if="servers.size > 1">
|
||||
<span class="section__heading">Servers</span>
|
||||
<ul class="section__content">
|
||||
<ServerListItem :server="server" v-for="[name, server] in servers" :key="name"></ServerListItem>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="sidebar__section">
|
||||
<span class="section__heading">{{ heading }}</span>
|
||||
<ul class="section__content">
|
||||
@ -28,13 +34,15 @@
|
||||
|
||||
<script lang="ts">
|
||||
import WorldListItem from './WorldListItem.vue';
|
||||
import ServerListItem from './ServerListItem.vue';
|
||||
import {defineComponent} from 'vue';
|
||||
import {useStore} from "@/store";
|
||||
|
||||
export default defineComponent({
|
||||
name: 'WorldList',
|
||||
components: {
|
||||
WorldListItem
|
||||
WorldListItem,
|
||||
ServerListItem
|
||||
},
|
||||
|
||||
computed: {
|
||||
@ -44,6 +52,10 @@ export default defineComponent({
|
||||
|
||||
worlds() {
|
||||
return useStore().state.worlds;
|
||||
},
|
||||
|
||||
servers() {
|
||||
return useStore().state.servers;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
8
src/dynmap.d.ts
vendored
8
src/dynmap.d.ts
vendored
@ -21,16 +21,14 @@ import {ClockControlOptions} from "@/leaflet/control/ClockControl";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
config: DynmapConfig;
|
||||
config: { url: DynmapUrlConfig };
|
||||
liveAtlasConfig: any,
|
||||
hideSplash: Function;
|
||||
showSplash: Function;
|
||||
showSplashError: Function;
|
||||
}
|
||||
}
|
||||
|
||||
type DynmapConfig = {
|
||||
url: DynmapUrlConfig;
|
||||
};
|
||||
|
||||
type DynmapUrlConfig = {
|
||||
configuration: string;
|
||||
update: string;
|
||||
|
6
src/index.d.ts
vendored
6
src/index.d.ts
vendored
@ -1,5 +1,6 @@
|
||||
import { ComponentCustomProperties } from 'vue'
|
||||
import {State, Store} from "@/store";
|
||||
import {DynmapUrlConfig} from "@/dynmap";
|
||||
|
||||
declare module "*.png" {
|
||||
const value: any;
|
||||
@ -17,4 +18,9 @@ declare module '@vue/runtime-core' {
|
||||
interface ComponentCustomProperties {
|
||||
$store: Store<State>
|
||||
}
|
||||
}
|
||||
|
||||
interface LiveAtlasServerDefinition extends DynmapUrlConfig {
|
||||
id: string
|
||||
label?: string
|
||||
}
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
import {DivIconOptions, PointExpression, Icon, DivIcon, DomUtil, point} from 'leaflet';
|
||||
import {useStore} from "@/store";
|
||||
|
||||
export interface DynmapIconOptions extends DivIconOptions {
|
||||
icon: string;
|
||||
@ -59,7 +60,7 @@ export class DynmapIcon extends DivIcon {
|
||||
}
|
||||
|
||||
const div = markerContainer.cloneNode(false) as HTMLDivElement,
|
||||
url = `${window.config.url.markers}_markers_/${this.options.icon}.png`,
|
||||
url = `${useStore().getters.serverConfig.markers}_markers_/${this.options.icon}.png`,
|
||||
size = point(this.options.iconSize as PointExpression);
|
||||
|
||||
this._image = markerIcon.cloneNode(false) as HTMLImageElement;
|
||||
@ -95,7 +96,7 @@ export class DynmapIcon extends DivIcon {
|
||||
|
||||
update(options: DynmapIconOptions) {
|
||||
if(this._image && options.icon !== this.options.icon) {
|
||||
this._image!.src = `${window.config.url.markers}_markers_/${options.icon}.png`;
|
||||
this._image!.src = `${useStore().getters.serverConfig.markers}_markers_/${options.icon}.png`;
|
||||
this.options.icon = options.icon;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
import {TileLayer, Coords, DoneCallback, TileLayerOptions, DomUtil, Util, LatLng} from 'leaflet';
|
||||
import {DynmapProjection} from "@/leaflet/projection/DynmapProjection";
|
||||
import {Coordinate, DynmapWorldMap} from "@/dynmap";
|
||||
import {store} from "@/store";
|
||||
|
||||
export interface DynmapTileLayerOptions extends TileLayerOptions {
|
||||
mapSettings: DynmapWorldMap;
|
||||
@ -111,7 +112,7 @@ export class DynmapTileLayer extends TileLayer {
|
||||
|
||||
if (!url) {
|
||||
const path = escape(`${this._mapSettings.world.name}/${name}`);
|
||||
url = `${window.config.url.tiles}${path}`;
|
||||
url = `${store.getters.serverConfig.tiles}${path}`;
|
||||
|
||||
if(typeof timestamp !== 'undefined') {
|
||||
url += (url.indexOf('?') === -1 ? `?timestamp=${timestamp}` : `×tamp=${timestamp}`);
|
||||
|
58
src/main.ts
58
src/main.ts
@ -16,11 +16,13 @@
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import API from './api';
|
||||
import {store} from "@/store";
|
||||
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import 'normalize-scss/sass/normalize/_import-now.scss';
|
||||
import '@/scss/style.scss';
|
||||
import {MutationTypes} from "@/store/mutation-types";
|
||||
|
||||
const splash = document.getElementById('splash'),
|
||||
splashSpinner = document.getElementById('splash__spinner'),
|
||||
@ -30,14 +32,37 @@ const splash = document.getElementById('splash'),
|
||||
splashAttempt = document.getElementById('splash__error-attempt'),
|
||||
svgs = import.meta.globEager('/assets/icons/*.svg');
|
||||
|
||||
window.hideSplash = function() {
|
||||
window.showSplash = function() {
|
||||
if(!splash) {
|
||||
return;
|
||||
}
|
||||
|
||||
splash.ontransitionend = null;
|
||||
splash.hidden = false;
|
||||
|
||||
requestAnimationFrame(function() {
|
||||
if(splash) {
|
||||
splash.style.opacity = '0';
|
||||
splash.style.opacity = '1';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.hideSplash = function() {
|
||||
if(!splash) {
|
||||
return;
|
||||
}
|
||||
|
||||
splash.ontransitionend = function(e) {
|
||||
if(e.target === splash) {
|
||||
splash.hidden = true;
|
||||
}
|
||||
};
|
||||
|
||||
requestAnimationFrame(function() {
|
||||
splash.style.opacity = '0';
|
||||
});
|
||||
};
|
||||
|
||||
window.showSplashError = function(message: string, fatal: boolean, attempts: number) {
|
||||
if(splashError) {
|
||||
splashError.setAttribute('aria-hidden', 'false');
|
||||
@ -61,17 +86,24 @@ window.showSplashError = function(message: string, fatal: boolean, attempts: num
|
||||
}
|
||||
};
|
||||
|
||||
if(splash) {
|
||||
splash.addEventListener('transitionend', function(e) {
|
||||
if(e.target === splash) {
|
||||
splash.hidden = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.info(`LiveAtlas version ${store.state.version} - https://github.com/JLyne/LiveAtlas`);
|
||||
|
||||
const app = createApp(App).use(store);
|
||||
API.validateConfiguration().then((config) => {
|
||||
store.commit(MutationTypes.SET_SERVERS, config);
|
||||
|
||||
// app.config.performance = true;
|
||||
app.mount('#mcmap');
|
||||
if(config.size > 1) {
|
||||
const lastSegment = window.location.pathname.split('/').pop(),
|
||||
serverName = lastSegment && config.has(lastSegment) ? lastSegment : config.keys().next().value;
|
||||
|
||||
store.commit(MutationTypes.SET_CURRENT_SERVER, serverName);
|
||||
} else {
|
||||
store.commit(MutationTypes.SET_CURRENT_SERVER, config.keys().next().value);
|
||||
}
|
||||
|
||||
console.log(store.state.currentServer);
|
||||
|
||||
const app = createApp(App).use(store);
|
||||
|
||||
// app.config.performance = true;
|
||||
app.mount('#mcmap');
|
||||
});
|
||||
|
@ -78,7 +78,11 @@ export interface Actions {
|
||||
|
||||
export const actions: ActionTree<State, State> & Actions = {
|
||||
[ActionTypes.LOAD_CONFIGURATION]({commit, state}): Promise<DynmapConfigurationResponse> {
|
||||
commit(MutationTypes.CLEAR_MARKER_SETS, undefined);
|
||||
commit(MutationTypes.CLEAR_PLAYERS, undefined);
|
||||
|
||||
return API.getConfiguration().then(config => {
|
||||
commit(MutationTypes.CLEAR_WORLDS, undefined);
|
||||
commit(MutationTypes.SET_CONFIGURATION, config.config);
|
||||
commit(MutationTypes.SET_MESSAGES, config.messages);
|
||||
commit(MutationTypes.SET_WORLDS, config.worlds);
|
||||
|
@ -17,6 +17,7 @@
|
||||
import {GetterTree} from "vuex";
|
||||
import {State} from "@/store/state";
|
||||
import {getMinecraftTime} from "@/util";
|
||||
import {LiveAtlasServerDefinition} from "@/index";
|
||||
|
||||
export type Getters = {
|
||||
playerMarkersEnabled(state: State): boolean;
|
||||
@ -25,6 +26,7 @@ export type Getters = {
|
||||
night(state: State): boolean;
|
||||
mapBackground(state: State, getters: GetterTree<State, State> & Getters): string;
|
||||
url(state: State, getters: GetterTree<State, State> & Getters): string;
|
||||
serverConfig(state: State, getters: GetterTree<State, State> & Getters): LiveAtlasServerDefinition;
|
||||
}
|
||||
|
||||
export const getters: GetterTree<State, State> & Getters = {
|
||||
@ -72,5 +74,13 @@ export const getters: GetterTree<State, State> & Getters = {
|
||||
}
|
||||
|
||||
return `#${state.currentWorld.name};${state.currentMap.name};${locationString};${zoom}`;
|
||||
},
|
||||
|
||||
serverConfig(state: State): LiveAtlasServerDefinition {
|
||||
if(!state.currentServer) {
|
||||
throw RangeError("No current server");
|
||||
}
|
||||
|
||||
return state.servers.get(state.currentServer) as LiveAtlasServerDefinition;
|
||||
}
|
||||
}
|
@ -15,12 +15,15 @@
|
||||
*/
|
||||
|
||||
export enum MutationTypes {
|
||||
SET_SERVERS ='setServers',
|
||||
SET_CONFIGURATION = 'setConfiguration',
|
||||
SET_MESSAGES = 'setMessages',
|
||||
SET_WORLDS = 'setWorlds',
|
||||
SET_COMPONENTS = 'setComponents',
|
||||
SET_MARKER_SETS = 'setMarkerSets',
|
||||
CLEAR_MARKER_SETS = 'clearMarkerSets',
|
||||
ADD_WORLD = 'addWorld',
|
||||
CLEAR_WORLDS = 'clearWorlds',
|
||||
SET_WORLD_STATE = 'setWorldState',
|
||||
SET_UPDATE_TIMESTAMP = 'setUpdateTimestamp',
|
||||
ADD_MARKER_SET_UPDATES = 'addMarkerSetUpdates',
|
||||
@ -32,15 +35,18 @@ export enum MutationTypes {
|
||||
POP_LINE_UPDATES = 'popLineUpdates',
|
||||
POP_TILE_UPDATES = 'popTileUpdates',
|
||||
INCREMENT_REQUEST_ID = 'incrementRequestId',
|
||||
SET_PLAYERS = 'setPlayers',
|
||||
SET_PLAYERS_ASYNC = 'setPlayersAsync',
|
||||
CLEAR_PLAYERS = 'clearPlayers',
|
||||
SYNC_PLAYERS = 'syncPlayers',
|
||||
|
||||
SET_CURRENT_SERVER = 'setCurrentServer',
|
||||
SET_CURRENT_MAP = 'setCurrentMap',
|
||||
SET_CURRENT_PROJECTION = 'setCurrentProjection',
|
||||
SET_CURRENT_LOCATION = 'setCurrentLocation',
|
||||
SET_CURRENT_ZOOM = 'setCurrentZoom',
|
||||
CLEAR_CURRENT_ZOOM = 'clearCurrentZoom',
|
||||
SET_PARSED_URL = 'setParsedUrl',
|
||||
CLEAR_PARSED_URL = 'clearParsedUrl',
|
||||
|
||||
SET_FOLLOW_TARGET = 'setFollowTarget',
|
||||
SET_PAN_TARGET = 'setPanTarget',
|
||||
|
@ -32,6 +32,7 @@ import {
|
||||
DynmapWorldState, DynmapParsedUrl, DynmapChat, DynmapUIElement
|
||||
} from "@/dynmap";
|
||||
import {DynmapProjection} from "@/leaflet/projection/DynmapProjection";
|
||||
import {LiveAtlasServerDefinition} from "@/index";
|
||||
|
||||
export type CurrentMapPayload = {
|
||||
worldName: string;
|
||||
@ -39,12 +40,15 @@ export type CurrentMapPayload = {
|
||||
}
|
||||
|
||||
export type Mutations<S = State> = {
|
||||
[MutationTypes.SET_SERVERS](state: S, servers: Map<string, LiveAtlasServerDefinition>): void
|
||||
[MutationTypes.SET_CONFIGURATION](state: S, config: DynmapServerConfig): void
|
||||
[MutationTypes.SET_MESSAGES](state: S, messages: DynmapMessageConfig): void
|
||||
[MutationTypes.SET_WORLDS](state: S, worlds: Array<DynmapWorld>): void
|
||||
[MutationTypes.SET_COMPONENTS](state: S, worlds: DynmapComponentConfig): void
|
||||
[MutationTypes.SET_MARKER_SETS](state: S, worlds: Map<string, DynmapMarkerSet>): void
|
||||
[MutationTypes.CLEAR_MARKER_SETS](state: S): void
|
||||
[MutationTypes.ADD_WORLD](state: S, world: DynmapWorld): void
|
||||
[MutationTypes.CLEAR_WORLDS](state: S): void
|
||||
[MutationTypes.SET_WORLD_STATE](state: S, worldState: DynmapWorldState): void
|
||||
[MutationTypes.SET_UPDATE_TIMESTAMP](state: S, time: Date): void
|
||||
[MutationTypes.ADD_MARKER_SET_UPDATES](state: S, updates: Map<string, DynmapMarkerSetUpdates>): void
|
||||
@ -60,11 +64,15 @@ export type Mutations<S = State> = {
|
||||
[MutationTypes.INCREMENT_REQUEST_ID](state: S): void
|
||||
[MutationTypes.SET_PLAYERS_ASYNC](state: S, players: Set<DynmapPlayer>): Set<DynmapPlayer>
|
||||
[MutationTypes.SYNC_PLAYERS](state: S, keep: Set<string>): void
|
||||
[MutationTypes.CLEAR_PLAYERS](state: S): void
|
||||
[MutationTypes.SET_CURRENT_SERVER](state: S, server: string): void
|
||||
[MutationTypes.SET_CURRENT_MAP](state: S, payload: CurrentMapPayload): void
|
||||
[MutationTypes.SET_CURRENT_PROJECTION](state: S, payload: DynmapProjection): void
|
||||
[MutationTypes.SET_CURRENT_LOCATION](state: S, payload: Coordinate): void
|
||||
[MutationTypes.SET_CURRENT_ZOOM](state: S, payload: number): void
|
||||
[MutationTypes.CLEAR_CURRENT_ZOOM](state: S): void
|
||||
[MutationTypes.SET_PARSED_URL](state: S, payload: DynmapParsedUrl): void
|
||||
[MutationTypes.CLEAR_PARSED_URL](state: S): void
|
||||
[MutationTypes.SET_FOLLOW_TARGET](state: S, payload: DynmapPlayer): void
|
||||
[MutationTypes.SET_PAN_TARGET](state: S, payload: DynmapPlayer): void
|
||||
[MutationTypes.CLEAR_FOLLOW_TARGET](state: S, a?: void): void
|
||||
@ -78,6 +86,15 @@ export type Mutations<S = State> = {
|
||||
}
|
||||
|
||||
export const mutations: MutationTree<State> & Mutations = {
|
||||
// Sets configuration options from the initial config fetch
|
||||
[MutationTypes.SET_SERVERS](state: State, config: Map<string, LiveAtlasServerDefinition>) {
|
||||
state.servers = config;
|
||||
|
||||
if(state.currentServer && !state.servers.has(state.currentServer)) {
|
||||
state.currentServer = undefined;
|
||||
}
|
||||
},
|
||||
|
||||
// Sets configuration options from the initial config fetch
|
||||
[MutationTypes.SET_CONFIGURATION](state: State, config: DynmapServerConfig) {
|
||||
state.configuration = Object.assign(state.configuration, config);
|
||||
@ -128,10 +145,31 @@ export const mutations: MutationTree<State> & Mutations = {
|
||||
}
|
||||
},
|
||||
|
||||
//Sets the existing marker sets from the last marker fetch
|
||||
[MutationTypes.CLEAR_MARKER_SETS](state: State) {
|
||||
state.markerSets.clear();
|
||||
state.pendingSetUpdates.clear();
|
||||
},
|
||||
|
||||
[MutationTypes.ADD_WORLD](state: State, world: DynmapWorld) {
|
||||
state.worlds.set(world.name, world);
|
||||
},
|
||||
|
||||
[MutationTypes.CLEAR_WORLDS](state: State) {
|
||||
console.log('??????');
|
||||
state.worlds.clear();
|
||||
state.maps.clear();
|
||||
|
||||
state.currentMap = undefined;
|
||||
state.currentWorld = undefined;
|
||||
state.followTarget = undefined;
|
||||
state.panTarget = undefined;
|
||||
|
||||
state.currentWorldState.timeOfDay = 0;
|
||||
state.currentWorldState.raining = false;
|
||||
state.currentWorldState.thundering = false;
|
||||
},
|
||||
|
||||
//Sets the current world state an update fetch
|
||||
[MutationTypes.SET_WORLD_STATE](state: State, worldState: DynmapWorldState) {
|
||||
state.currentWorldState = Object.assign(state.currentWorldState, worldState);
|
||||
@ -341,6 +379,25 @@ export const mutations: MutationTree<State> & Mutations = {
|
||||
}
|
||||
},
|
||||
|
||||
//Removes all players not found in the provided keep set
|
||||
[MutationTypes.CLEAR_PLAYERS](state: State) {
|
||||
state.followTarget = undefined;
|
||||
state.panTarget = undefined;
|
||||
|
||||
for(const [key, player] of state.players) {
|
||||
state.players.delete(key);
|
||||
}
|
||||
},
|
||||
|
||||
//Sets the currently active server
|
||||
[MutationTypes.SET_CURRENT_SERVER](state: State, serverName) {
|
||||
if(!state.servers.has(serverName)) {
|
||||
throw new RangeError(`Unknown server ${serverName}`);
|
||||
}
|
||||
|
||||
state.currentServer = serverName;
|
||||
},
|
||||
|
||||
//Sets the currently active map/world
|
||||
[MutationTypes.SET_CURRENT_MAP](state: State, {worldName, mapName}) {
|
||||
mapName = [worldName, mapName].join('_');
|
||||
@ -380,11 +437,26 @@ export const mutations: MutationTree<State> & Mutations = {
|
||||
state.currentZoom = payload;
|
||||
},
|
||||
|
||||
[MutationTypes.CLEAR_CURRENT_ZOOM](state: State) {
|
||||
state.currentZoom = 0;
|
||||
},
|
||||
|
||||
//Sets the result of parsing the current map url, if present and valid
|
||||
[MutationTypes.SET_PARSED_URL](state: State, payload: DynmapParsedUrl) {
|
||||
state.parsedUrl = payload;
|
||||
},
|
||||
|
||||
//Clear any existing parsed url
|
||||
[MutationTypes.CLEAR_PARSED_URL](state: State) {
|
||||
state.parsedUrl = {
|
||||
world: undefined,
|
||||
map: undefined,
|
||||
location: undefined,
|
||||
zoom: undefined,
|
||||
legacy: false,
|
||||
};
|
||||
},
|
||||
|
||||
//Set the follow target, which the map will automatically pan to keep in view
|
||||
[MutationTypes.SET_FOLLOW_TARGET](state: State, player: DynmapPlayer) {
|
||||
state.followTarget = player;
|
||||
|
@ -23,9 +23,11 @@ import {
|
||||
DynmapWorld, DynmapWorldState, Coordinate, DynmapParsedUrl, DynmapChat, DynmapUIElement
|
||||
} from "@/dynmap";
|
||||
import {DynmapProjection} from "@/leaflet/projection/DynmapProjection";
|
||||
import {LiveAtlasServerDefinition} from "@/index";
|
||||
|
||||
export type State = {
|
||||
version: string;
|
||||
servers: Map<string, LiveAtlasServerDefinition>;
|
||||
configuration: DynmapServerConfig;
|
||||
messages: DynmapMessageConfig;
|
||||
components: DynmapComponentConfig;
|
||||
@ -48,6 +50,7 @@ export type State = {
|
||||
followTarget?: DynmapPlayer;
|
||||
panTarget?: DynmapPlayer;
|
||||
|
||||
currentServer?: string;
|
||||
currentWorldState: DynmapWorldState;
|
||||
currentWorld?: DynmapWorld;
|
||||
currentMap?: DynmapWorldMap;
|
||||
@ -69,6 +72,7 @@ export type State = {
|
||||
|
||||
export const state: State = {
|
||||
version: (import.meta.env.VITE_VERSION || 'Unknown') as string,
|
||||
servers: new Map(),
|
||||
|
||||
configuration: {
|
||||
version: '',
|
||||
@ -150,6 +154,7 @@ export const state: State = {
|
||||
followTarget: undefined,
|
||||
panTarget: undefined,
|
||||
|
||||
currentServer: undefined,
|
||||
currentWorld: undefined,
|
||||
currentMap: undefined,
|
||||
currentLocation: {
|
||||
|
@ -99,7 +99,7 @@ const tickHeadQueue = () => {
|
||||
src = (head.size === 'body') ? `faces/body/${head.account}.png` :`faces/${head.size}x${head.size}/${head.account}.png`;
|
||||
|
||||
headsLoading.add(head.cacheKey);
|
||||
head.image.src = concatURL(window.config.url.markers, src);
|
||||
head.image.src = concatURL(useStore().getters.serverConfig.markers, src);
|
||||
|
||||
tickHeadQueue();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user