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