Handle hidden/offworld players

- Respect server config for greying out players in other worlds
- Always grey out players hidden due to other restrictions
- Allow following for hidden players, and show their hidden status on the follow popup
This commit is contained in:
James Lyne 2020-12-18 16:04:06 +00:00
parent 217028e044
commit b92120e801
7 changed files with 92 additions and 15 deletions

View File

@ -43,6 +43,7 @@ function buildServerConfig(response: any): DynmapServerConfig {
return {
version: response.dynmapversion || '',
allowChat: response.allowwebchat || false,
grayHiddenPlayers: response.grayplayerswhenhidden || false,
chatRequiresLogin: response['webchat-requires-login'] || false,
chatInterval: response['webchat-interval'] || 5,
defaultMap: response.defaultmap || undefined,
@ -488,17 +489,20 @@ export default {
const players: Set<DynmapPlayer> = new Set();
(response.players || []).forEach((player: any) => {
const world = player.world && player.world !== '-some-other-bogus-world-' ? player.world : undefined;
players.add({
account: player.account || "",
health: player.health || 0,
armor: player.armor || 0,
name: player.name ? sanitizer.sanitize(player.name) : "Steve",
sort: player.sort || 0,
hidden: !world,
location: {
x: player.x || 0,
y: player.y || 0,
z: player.z || 0,
world: player.world || undefined,
world: world,
}
});
});

View File

@ -232,6 +232,11 @@ export default defineComponent({
return;
}
if(player.hidden) {
console.warn(`Cannot follow ${player.name}. Player is hidden from the map.`);
return;
}
if(!player.location.world) {
console.warn(`Cannot follow ${player.name}. Player isn't in a known world.`);
return;

View File

@ -18,9 +18,12 @@
<section class="sidebar__section following">
<h2>Following</h2>
<div class="following__target">
<div :class="{'following__target': true, 'following__target--hidden': target.hidden}">
<img width="32" height="32" class="target__icon" :src="playerImage" alt="" />
<span class="target__info">
<span class="target__name" v-html="target.name"></span>
<span class="target__status" v-show="target.hidden">Currently hidden</span>
</span>
<button class="target__unfollow" type="button" :title="`Stop following this player`"
@click.prevent="unfollow"
@keydown="onKeydown">Unfollow</button>
@ -80,8 +83,22 @@ export default defineComponent({
right: 1.5rem;
}
.target__name {
.target__info {
margin-left: 2rem;
display: flex;
flex-direction: column;
justify-content: flex-start;
.target__status {
font-size: 1.3rem;
}
}
&.following__target--hidden {
.target__icon {
filter: grayscale(1);
opacity: 0.5;
}
}
}
}

View File

@ -15,9 +15,10 @@
-->
<template>
<li class="player">
<li :class="{'player': true, 'player--hidden' : !!player.hidden, 'player--other-world': otherWorld}">
<img width="16" height="16" class="player__icon" :src="playerImage" alt="" />
<button class="player__name" type="button" title="Click to center on player&#10;Double-click to follow player"
<button class="player__name" type="button" :title="title"
:disbled="player.hidden"
@click.prevent="pan"
@keydown="onKeydown"
@dblclick.prevent="follow" v-html="player.name"></button>
@ -45,20 +46,44 @@ export default defineComponent({
playerImage: playerImage,
}
},
computed: {
otherWorld(): boolean {
const store = useStore();
return store.state.configuration.grayHiddenPlayers
&& (!store.state.currentWorld || store.state.currentWorld.name !== this.player.location.world);
},
title(): string {
if(this.player.hidden) {
return 'This player is currently hidden from the map\nDouble-click to follow player when they become visible';
} else if(this.otherWorld) {
return 'This player is in another world.\nClick to center on player\nDouble-click to follow player';
} else {
return 'Click to center on player\nDouble-click to follow player';
}
}
},
methods: {
follow() {
useStore().commit(MutationTypes.SET_FOLLOW_TARGET, this.player);
},
pan() {
if(!this.player.hidden) {
useStore().commit(MutationTypes.CLEAR_FOLLOW_TARGET, undefined);
useStore().commit(MutationTypes.SET_PAN_TARGET, this.player);
}
},
onKeydown(e: KeyboardEvent) {
if(e.key !== ' ') {
if(e.key !== ' ' && e.key !== 'Enter') {
return;
}
e.shiftKey ? this.follow() : this.pan();
if(e.shiftKey) {
this.follow();
} else {
if(!this.player.hidden) {
this.pan();
}
}
}
}
});
@ -88,5 +113,26 @@ export default defineComponent({
width: 100%;
height: 100%;
}
&.player--hidden {
.player__icon {
filter: grayscale(1);
opacity: 0.5;
}
.player__name {
cursor: not-allowed;
}
color: #999999;
}
&.player--other-world {
.player__icon {
opacity: 0.5;
}
color: #999999;
}
}
</style>

12
src/dynmap.d.ts vendored
View File

@ -57,6 +57,7 @@ interface DynmapServerConfig {
loginEnabled: boolean;
loginRequired: boolean;
maxPlayers: number;
grayHiddenPlayers: boolean;
hash: number;
}
@ -169,11 +170,12 @@ interface DynmapUpdateResponse {
}
interface DynmapPlayer {
account: string
armor: number
health: number
name: string
sort: number
account: string;
armor: number;
health: number;
name: string;
sort: number;
hidden: boolean;
location: DynmapLocation;
}

View File

@ -259,6 +259,7 @@ export const mutations: MutationTree<State> & Mutations = {
existing!.health = player.health;
existing!.armor = player.armor;
existing!.location = Object.assign(existing!.location, player.location);
existing!.hidden = player.hidden;
existing!.name = player.name;
existing!.sort = player.sort;
} else {
@ -269,6 +270,7 @@ export const mutations: MutationTree<State> & Mutations = {
location: player.location,
name: player.name,
sort: player.sort,
hidden: player.hidden,
});
}

View File

@ -74,6 +74,7 @@ export const state: State = {
loginEnabled: false,
loginRequired: false,
maxPlayers: 0,
grayHiddenPlayers: false,
hash: 0,
},