From 6a1b3e55e1e254654d9e647ba06fa7f9d0c009c6 Mon Sep 17 00:00:00 2001 From: Pierre Borgmann Date: Mon, 29 May 2023 06:41:47 +0200 Subject: [PATCH] #52 Fennec: Top Bar section --- src/server/gsi.js | 16 + src/server/helpers/paths.js | 2 + src/server/settings.js | 30 +- src/server/state.js | 1 + src/server/websocket.js | 14 +- src/themes/fennec/css/base.css | 1 - src/themes/fennec/css/vars.css | 12 +- src/themes/fennec/digits/digits.js | 5 +- .../name-and-stats/data-row/taser/taser.css | 1 + src/themes/fennec/img/icons/bombsite-a.svg | 1 + src/themes/fennec/img/icons/bombsite-b.svg | 1 + src/themes/fennec/img/icons/pause.svg | 1 + src/themes/fennec/img/icons/planted-bomb.svg | 1 + .../fennec/progress-bar/progress-bar.css | 32 ++ .../fennec/progress-bar/progress-bar.html | 3 + .../fennec/progress-bar/progress-bar.js | 20 + src/themes/fennec/shell/shell.html | 2 +- src/themes/fennec/shell/shell.js | 2 + src/themes/fennec/theme.json | 35 ++ src/themes/fennec/top-bar/center/center.css | 209 +++++++++ src/themes/fennec/top-bar/center/center.html | 70 ++++ src/themes/fennec/top-bar/center/center.js | 35 ++ src/themes/fennec/top-bar/team/team.css | 204 +++++++++ src/themes/fennec/top-bar/team/team.html | 51 +++ src/themes/fennec/top-bar/team/team.js | 84 ++++ src/themes/fennec/top-bar/top-bar.css | 13 + src/themes/fennec/top-bar/top-bar.html | 5 + src/themes/fennec/top-bar/top-bar.js | 10 + src/themes/raw/bombsites.json | 395 ++++++++++++++++++ src/themes/raw/core/app.js | 4 +- src/themes/raw/core/state.js | 2 + src/themes/raw/core/websocket-on-message.js | 6 +- src/themes/raw/gsi/helpers/find-bomb-site.js | 23 + .../raw/gsi/{ => helpers}/format-map-name.js | 2 +- src/themes/raw/gsi/helpers/inside-vector.js | 4 + src/themes/raw/gsi/helpers/vector-distance.js | 3 + src/themes/raw/gsi/parse-bomb.js | 40 +- src/themes/raw/gsi/parse-map.js | 2 +- src/themes/raw/gsi/parse-round.js | 42 +- src/themes/raw/gsi/parse-rounds.js | 1 + 40 files changed, 1356 insertions(+), 29 deletions(-) create mode 100644 src/themes/fennec/img/icons/bombsite-a.svg create mode 100644 src/themes/fennec/img/icons/bombsite-b.svg create mode 100644 src/themes/fennec/img/icons/pause.svg create mode 100644 src/themes/fennec/img/icons/planted-bomb.svg create mode 100644 src/themes/fennec/progress-bar/progress-bar.css create mode 100644 src/themes/fennec/progress-bar/progress-bar.html create mode 100644 src/themes/fennec/progress-bar/progress-bar.js create mode 100644 src/themes/fennec/top-bar/center/center.css create mode 100644 src/themes/fennec/top-bar/center/center.html create mode 100644 src/themes/fennec/top-bar/center/center.js create mode 100644 src/themes/fennec/top-bar/team/team.css create mode 100644 src/themes/fennec/top-bar/team/team.html create mode 100644 src/themes/fennec/top-bar/team/team.js create mode 100644 src/themes/fennec/top-bar/top-bar.css create mode 100644 src/themes/fennec/top-bar/top-bar.html create mode 100644 src/themes/fennec/top-bar/top-bar.js create mode 100644 src/themes/raw/bombsites.json create mode 100644 src/themes/raw/gsi/helpers/find-bomb-site.js rename src/themes/raw/gsi/{ => helpers}/format-map-name.js (86%) create mode 100644 src/themes/raw/gsi/helpers/inside-vector.js create mode 100644 src/themes/raw/gsi/helpers/vector-distance.js diff --git a/src/server/gsi.js b/src/server/gsi.js index 2af6ef4..e27e73d 100644 --- a/src/server/gsi.js +++ b/src/server/gsi.js @@ -29,9 +29,25 @@ const updateGsiState = (body) => { } const updateAdditionalState = (body) => { + updateLastKnownBombPlantedCountdown(body) updateRoundDamages(body) } +const updateLastKnownBombPlantedCountdown = (body) => { + const bomb = body.bomb + if (bomb?.state === 'defusing') return + + if (! bomb || bomb.state !== 'planted') { + additionalState.lastKnownBombPlantedCountdown = {} + return + } + + additionalState.lastKnownBombPlantedCountdown = { + unixTimestamp: +new Date(), + value: bomb.countdown, + } +} + const updateRoundDamages = (body) => { const roundNumber = body.map?.round if (! roundNumber) return diff --git a/src/server/helpers/paths.js b/src/server/helpers/paths.js index f5a4c5d..7843a66 100644 --- a/src/server/helpers/paths.js +++ b/src/server/helpers/paths.js @@ -9,4 +9,6 @@ export const themesDirectory = `${rootDirectory}/src/themes` export const userspaceDirectory = `${themesDirectory}/userspace` // files +export const userspaceBombsitesPath = `${userspaceDirectory}/bombsites.json` +export const userspaceRadarsPath = `${userspaceDirectory}/radars.json` export const userspaceSettingsPath = `${userspaceDirectory}/theme.json` diff --git a/src/server/settings.js b/src/server/settings.js index b7dcb0d..353991f 100644 --- a/src/server/settings.js +++ b/src/server/settings.js @@ -2,7 +2,7 @@ import { mkdir, readFile, writeFile } from 'fs/promises' import { merge } from 'lodash-es' -import { themesDirectory, userspaceDirectory, userspaceSettingsPath } from './helpers/paths.js' +import { themesDirectory, userspaceBombsitesPath, userspaceDirectory, userspaceRadarsPath, userspaceSettingsPath } from './helpers/paths.js' import { fileExists } from './helpers/file-exists.js' export const initSettings = async () => { @@ -16,18 +16,33 @@ export const initSettings = async () => { } export const getSettings = async () => { - const settingsObjects = [await readJson(userspaceSettingsPath)] const themeTree = ['userspace'] + const bombsiteObjects = [await readJsonIfExists(userspaceBombsitesPath)] + const radarObjects = [await readJsonIfExists(userspaceRadarsPath)] + const settingsObjects = [await readJson(userspaceSettingsPath)] + while (settingsObjects[settingsObjects.length - 1].parent) { themeTree.push(settingsObjects[settingsObjects.length - 1].parent) + settingsObjects.push( - await readJson(`${themesDirectory}/${settingsObjects[settingsObjects.length - 1].parent}/theme.json`) + await readJson(`${themesDirectory}/${settingsObjects[settingsObjects.length - 1].parent}/theme.json`), + ) + + bombsiteObjects.push( + await readJsonIfExists(`${themesDirectory}/${settingsObjects[settingsObjects.length - 1].parent}/bombsites.json`), + ) + + radarObjects.push( + await readJsonIfExists(`${themesDirectory}/${settingsObjects[settingsObjects.length - 1].parent}/radars.json`), ) } return { themeTree, + + bombsites: merge({}, ...bombsiteObjects.reverse()), + radars: merge({}, ...radarObjects.reverse()), settings: merge({}, ...settingsObjects.reverse()), } } @@ -38,3 +53,12 @@ const readJson = async (path) => { const str = await readFile(path, 'utf-8') return JSON.parse(str) } + +const readJsonIfExists = async (path) => { + try { + return await readJson(path) + } catch (err) { + if (err.code === 'ENOENT') return {} + throw err + } +} diff --git a/src/server/state.js b/src/server/state.js index 58361ca..a081c78 100644 --- a/src/server/state.js +++ b/src/server/state.js @@ -1,5 +1,6 @@ export const gsiState = {} export const additionalState = { + lastKnownBombPlantedCountdown: {}, roundDamages: {}, } diff --git a/src/server/websocket.js b/src/server/websocket.js index f4b5f4b..b2dc9f5 100644 --- a/src/server/websocket.js +++ b/src/server/websocket.js @@ -11,15 +11,19 @@ export class Websocket { this.sendState(client) }) + this.bombsitesCache = {} this.optionsCache = {} + this.radarsCache = {} setInterval(() => { - this.broadcastState() // TODO just completely remove this (probably) - // TODO run this when a value is changed on the config page instead (and maybe on a rare interval or something) - getSettings().then(({ settings }) => { + getSettings().then(({ bombsites, radars, settings }) => { + this.bombsitesCache = bombsites this.optionsCache = Object.fromEntries(Object.entries(settings.options).map(([key, { value }]) => [key, value])) + this.radarsCache = radars }) + + this.broadcastState() // TODO just completely remove this (probably) }, 5000) } @@ -28,8 +32,10 @@ export class Websocket { additionalState, gsiState, + bombsites: this.bombsitesCache, options: this.optionsCache, - timestamp: new Date(), + radars: this.radarsCache, + unixTimestamp: +new Date(), } } diff --git a/src/themes/fennec/css/base.css b/src/themes/fennec/css/base.css index 00be8e0..73fbece 100644 --- a/src/themes/fennec/css/base.css +++ b/src/themes/fennec/css/base.css @@ -1,7 +1,6 @@ *, *::after, *::before { - box-sizing: border-box; margin: 0; padding: 0; } diff --git a/src/themes/fennec/css/vars.css b/src/themes/fennec/css/vars.css index 612bf51..13ebb5f 100644 --- a/src/themes/fennec/css/vars.css +++ b/src/themes/fennec/css/vars.css @@ -4,12 +4,14 @@ */ --background-color: green; --text-color: #fff; + --red: #f00; + --counter-terrorists-rgb: 29, 158, 222; --counter-terrorists: #1d9ede; + --terrorists-rgb: 193, 136, 3; --terrorists: #c18803; - --counter-terrorists-rgb: 29, 158, 222; - --terrorists-rgb: 193, 136, 3; + --progress-bar-fill-color-bomb: var(--red); /* * Spacing, Sizes @@ -19,6 +21,12 @@ --focused-player-width: 50%; --focused-player-icon-height: 2rem; + --top-bar-width: 50%; + --top-bar-padding-x: 0.8rem; + --top-bar-score-font-size: 3rem; + --top-bar-row-height: calc(2 * var(--top-bar-padding-x) + var(--top-bar-score-font-size)); + --top-bar-half-row-height: calc(var(--top-bar-row-height) / 2); + /* Viewport Margin */ --viewport-margin-x: 2rem; --viewport-margin-y: 1.5rem; diff --git a/src/themes/fennec/digits/digits.js b/src/themes/fennec/digits/digits.js index 128c011..73ca364 100644 --- a/src/themes/fennec/digits/digits.js +++ b/src/themes/fennec/digits/digits.js @@ -1,12 +1,13 @@ export default { props: [ - 'value', 'digits', + 'pad', + 'value', ], computed: { elements() { - return `${this.value}`.padStart(this.digits, ' ').split('') + return `${this.value}`.padStart(this.digits, this.pad ?? ' ').split('') }, }, } diff --git a/src/themes/fennec/focused-player/name-and-stats/data-row/taser/taser.css b/src/themes/fennec/focused-player/name-and-stats/data-row/taser/taser.css index 22ff18f..ba5ac73 100644 --- a/src/themes/fennec/focused-player/name-and-stats/data-row/taser/taser.css +++ b/src/themes/fennec/focused-player/name-and-stats/data-row/taser/taser.css @@ -1 +1,2 @@ +/* TODO this ends up not scoped */ @import '/hud/focused-player/name-and-stats/data-row/data-row-item-shared.css'; diff --git a/src/themes/fennec/img/icons/bombsite-a.svg b/src/themes/fennec/img/icons/bombsite-a.svg new file mode 100644 index 0000000..84caea0 --- /dev/null +++ b/src/themes/fennec/img/icons/bombsite-a.svg @@ -0,0 +1 @@ + diff --git a/src/themes/fennec/img/icons/bombsite-b.svg b/src/themes/fennec/img/icons/bombsite-b.svg new file mode 100644 index 0000000..b822dc6 --- /dev/null +++ b/src/themes/fennec/img/icons/bombsite-b.svg @@ -0,0 +1 @@ + diff --git a/src/themes/fennec/img/icons/pause.svg b/src/themes/fennec/img/icons/pause.svg new file mode 100644 index 0000000..330dda0 --- /dev/null +++ b/src/themes/fennec/img/icons/pause.svg @@ -0,0 +1 @@ + diff --git a/src/themes/fennec/img/icons/planted-bomb.svg b/src/themes/fennec/img/icons/planted-bomb.svg new file mode 100644 index 0000000..18be6e4 --- /dev/null +++ b/src/themes/fennec/img/icons/planted-bomb.svg @@ -0,0 +1 @@ + diff --git a/src/themes/fennec/progress-bar/progress-bar.css b/src/themes/fennec/progress-bar/progress-bar.css new file mode 100644 index 0000000..904e8e0 --- /dev/null +++ b/src/themes/fennec/progress-bar/progress-bar.css @@ -0,0 +1,32 @@ +.progress-bar-background { + width: 100%; + height: 0.6rem; + background: rgba(255, 255, 255, 0.5); + overflow: hidden; +} + +.progress-bar-fill { + height: 100%; + + &.--to-left, + &.--left { + transform-origin: left; + } + + &.--to-right, + &.--right { + transform-origin: right; + } + + &.--ct { + background: var(--counter-terrorists); + } + + &.--t { + background: var(--terrorists); + } + + &.--bomb { + background: var(--progress-bar-fill-color-bomb); + } +} diff --git a/src/themes/fennec/progress-bar/progress-bar.html b/src/themes/fennec/progress-bar/progress-bar.html new file mode 100644 index 0000000..0df3ca5 --- /dev/null +++ b/src/themes/fennec/progress-bar/progress-bar.html @@ -0,0 +1,3 @@ +
+
+
diff --git a/src/themes/fennec/progress-bar/progress-bar.js b/src/themes/fennec/progress-bar/progress-bar.js new file mode 100644 index 0000000..fb42692 --- /dev/null +++ b/src/themes/fennec/progress-bar/progress-bar.js @@ -0,0 +1,20 @@ +export default { + props: [ + 'colorClass', + 'direction', + 'max', + 'min', + 'value', + ], + + computed: { + styleAttr() { + const min = this.min || 0 + const max = this.max ?? 1 + + const percent = (this.value - min) / (max - min) + + return `transform: scaleX(${percent})` + }, + }, +} diff --git a/src/themes/fennec/shell/shell.html b/src/themes/fennec/shell/shell.html index 8dd5477..bafe685 100644 --- a/src/themes/fennec/shell/shell.html +++ b/src/themes/fennec/shell/shell.html @@ -1,6 +1,6 @@