mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 13:20:43 +00:00
bac29448c2
The Layer interface dates to the canvas2D era when each entry drew to
the shared 2D context via renderLayer(ctx). With canvas2D gone, nothing
draws there and the renderLayer hook is dead. Rename the interface
("main-thread analog of the worker's Execution") and trim it:
interface Controller {
init?: () => void;
tick?: () => void;
getTickIntervalMs?: () => number;
}
renderLayer / shouldTransform / redraw are gone.
Sweep across 28 files: from "./Layer" → "./Controller", implements
Layer → implements Controller, Layer[] / Map<Layer,…> →
Controller[] / Map<Controller,…>. Delete the no-op renderLayer +
shouldTransform method bodies that every layer had inherited.
GameRenderer drops the RedrawGraphicsEvent listener + redraw() fanout
(nothing implements redraw anymore) and the now-unused eventBus
constructor field.
One real case: AttackingTroopsOverlay.renderLayer wasn't a no-op — it
updates DOM label transforms each frame so labels track the WebGL
camera during pan/zoom. Rename to private updateLabelDOM() and start
a self-driven RAF in init() so the per-frame updates keep running.
Class names ending in "Layer" (UILayer, StructureIconsLayer, NameLayer,
etc.) intentionally left as-is — those are separate identifiers and
the class-rename / file-move is a follow-up.
407 tests pass.
206 lines
7.0 KiB
TypeScript
206 lines
7.0 KiB
TypeScript
import { Colord } from "colord";
|
|
import { html, LitElement } from "lit";
|
|
import { customElement, state } from "lit/decorators.js";
|
|
import { assetUrl } from "../../../core/AssetUrls";
|
|
import { EventBus } from "../../../core/EventBus";
|
|
import { GameMode, Team } from "../../../core/game/Game";
|
|
import { GameView } from "../../../core/game/GameView";
|
|
import { Platform } from "../../Platform";
|
|
import { getTranslatedPlayerTeamLabel, translateText } from "../../Utils";
|
|
import { Controller } from "./Controller";
|
|
import { ImmunityBarVisibleEvent } from "./ImmunityTimer";
|
|
import { SpawnBarVisibleEvent } from "./SpawnTimer";
|
|
const leaderboardRegularIcon = assetUrl(
|
|
"images/LeaderboardIconRegularWhite.svg",
|
|
);
|
|
const leaderboardSolidIcon = assetUrl("images/LeaderboardIconSolidWhite.svg");
|
|
const teamRegularIcon = assetUrl("images/TeamIconRegularWhite.svg");
|
|
const teamSolidIcon = assetUrl("images/TeamIconSolidWhite.svg");
|
|
|
|
@customElement("game-left-sidebar")
|
|
export class GameLeftSidebar extends LitElement implements Controller {
|
|
@state()
|
|
private isLeaderboardShow = false;
|
|
@state()
|
|
private isTeamLeaderboardShow = false;
|
|
@state()
|
|
private isVisible = false;
|
|
@state()
|
|
private isPlayerTeamLabelVisible = false;
|
|
@state()
|
|
private playerTeam: Team | null = null;
|
|
@state()
|
|
private spawnBarVisible = false;
|
|
@state()
|
|
private immunityBarVisible = false;
|
|
|
|
private playerColor: Colord = new Colord("#FFFFFF");
|
|
public game: GameView;
|
|
public eventBus: EventBus;
|
|
private _shownOnInit = false;
|
|
|
|
createRenderRoot() {
|
|
return this;
|
|
}
|
|
|
|
init() {
|
|
this.isVisible = true;
|
|
this.eventBus.on(SpawnBarVisibleEvent, (e) => {
|
|
this.spawnBarVisible = e.visible;
|
|
});
|
|
this.eventBus.on(ImmunityBarVisibleEvent, (e) => {
|
|
this.immunityBarVisible = e.visible;
|
|
});
|
|
if (this.isTeamGame) {
|
|
this.isPlayerTeamLabelVisible = true;
|
|
}
|
|
// Make it visible by default on large screens
|
|
if (Platform.isDesktopWidth) {
|
|
// lg breakpoint
|
|
this._shownOnInit = true;
|
|
}
|
|
this.requestUpdate();
|
|
}
|
|
|
|
tick() {
|
|
if (!this.playerTeam && this.game.myPlayer()?.team()) {
|
|
this.playerTeam = this.game.myPlayer()!.team();
|
|
if (this.playerTeam) {
|
|
this.playerColor = this.game
|
|
.config()
|
|
.theme()
|
|
.teamColor(this.playerTeam);
|
|
this.requestUpdate();
|
|
}
|
|
}
|
|
|
|
if (this._shownOnInit && !this.game.inSpawnPhase()) {
|
|
this._shownOnInit = false;
|
|
this.isLeaderboardShow = true;
|
|
this.requestUpdate();
|
|
}
|
|
|
|
if (!this.game.inSpawnPhase() && this.isPlayerTeamLabelVisible) {
|
|
this.isPlayerTeamLabelVisible = false;
|
|
this.requestUpdate();
|
|
}
|
|
}
|
|
|
|
private get barOffset(): number {
|
|
return (this.spawnBarVisible ? 7 : 0) + (this.immunityBarVisible ? 7 : 0);
|
|
}
|
|
|
|
private toggleLeaderboard(): void {
|
|
this.isLeaderboardShow = !this.isLeaderboardShow;
|
|
}
|
|
|
|
private toggleTeamLeaderboard(): void {
|
|
this.isTeamLeaderboardShow = !this.isTeamLeaderboardShow;
|
|
}
|
|
|
|
private get isTeamGame(): boolean {
|
|
return this.game?.config().gameConfig().gameMode === GameMode.Team;
|
|
}
|
|
|
|
render() {
|
|
return html`
|
|
<aside
|
|
class=${`fixed top-0 min-[1200px]:top-4 left-0 min-[1200px]:left-4 z-900 flex flex-col max-h-[calc(100vh-80px)] overflow-y-auto p-2 bg-gray-800/92 backdrop-blur-sm shadow-xs min-[1200px]:rounded-lg rounded-br-lg ${this.isLeaderboardShow || this.isTeamLeaderboardShow ? "max-[400px]:w-full max-[400px]:rounded-none" : ""} transition-all duration-300 ease-out transform ${
|
|
this.isVisible ? "translate-x-0" : "hidden"
|
|
}`}
|
|
style="margin-top: ${this.barOffset}px;"
|
|
>
|
|
<div class="flex items-center gap-4 xl:gap-6 text-white">
|
|
<div
|
|
class="cursor-pointer p-0.5 bg-gray-700/50 hover:bg-gray-600 border rounded-md border-slate-500 transition-colors"
|
|
@click=${this.toggleLeaderboard}
|
|
role="button"
|
|
tabindex="0"
|
|
@keydown=${(e: KeyboardEvent) => {
|
|
if (e.key === "Enter" || e.key === " " || e.code === "Space") {
|
|
e.preventDefault();
|
|
this.toggleLeaderboard();
|
|
}
|
|
}}
|
|
>
|
|
<img
|
|
src=${this.isLeaderboardShow
|
|
? leaderboardSolidIcon
|
|
: leaderboardRegularIcon}
|
|
alt=${translateText("help_modal.icon_alt_player_leaderboard") ||
|
|
"Player Leaderboard Icon"}
|
|
width="20"
|
|
height="20"
|
|
/>
|
|
</div>
|
|
${this.isTeamGame
|
|
? html`
|
|
<div
|
|
class="cursor-pointer p-0.5 bg-gray-700/50 hover:bg-gray-600 border rounded-md border-slate-500 transition-colors"
|
|
@click=${this.toggleTeamLeaderboard}
|
|
role="button"
|
|
tabindex="0"
|
|
@keydown=${(e: KeyboardEvent) => {
|
|
if (
|
|
e.key === "Enter" ||
|
|
e.key === " " ||
|
|
e.code === "Space"
|
|
) {
|
|
e.preventDefault();
|
|
this.toggleTeamLeaderboard();
|
|
}
|
|
}}
|
|
>
|
|
<img
|
|
src=${this.isTeamLeaderboardShow
|
|
? teamSolidIcon
|
|
: teamRegularIcon}
|
|
alt=${translateText(
|
|
"help_modal.icon_alt_team_leaderboard",
|
|
) || "Team Leaderboard Icon"}
|
|
width="20"
|
|
height="20"
|
|
/>
|
|
</div>
|
|
`
|
|
: null}
|
|
${this.isLeaderboardShow || this.isTeamLeaderboardShow
|
|
? html`<span
|
|
class="ml-auto text-[10px] text-slate-500 select-all leading-none self-start"
|
|
title=${translateText("help_modal.game_id_tooltip")}
|
|
>${this.game?.gameID() ?? ""}</span
|
|
>`
|
|
: null}
|
|
</div>
|
|
${this.isPlayerTeamLabelVisible
|
|
? html`
|
|
<div
|
|
class="flex items-center w-full text-white mt-2"
|
|
@contextmenu=${(e: Event) => e.preventDefault()}
|
|
>
|
|
${translateText("help_modal.ui_your_team")}
|
|
<span
|
|
style="--color: ${this.playerColor.toRgbString()}"
|
|
class="text-(--color)"
|
|
>
|
|
${getTranslatedPlayerTeamLabel(this.playerTeam)}
|
|
⦿
|
|
</span>
|
|
</div>
|
|
`
|
|
: null}
|
|
<div
|
|
class=${`block lg:flex flex-wrap overflow-x-auto min-w-0 w-full ${this.isLeaderboardShow && this.isTeamLeaderboardShow ? "gap-2" : ""}`}
|
|
>
|
|
<leader-board .visible=${this.isLeaderboardShow}></leader-board>
|
|
<team-stats
|
|
class="flex-1"
|
|
.visible=${this.isTeamLeaderboardShow && this.isTeamGame}
|
|
></team-stats>
|
|
</div>
|
|
<slot></slot>
|
|
</aside>
|
|
`;
|
|
}
|
|
}
|