stop fetching public lobbies when game starts

This commit is contained in:
Evan
2025-02-06 13:56:25 -08:00
parent 4323888fde
commit 19fa49763c
2 changed files with 225 additions and 188 deletions
+125 -105
View File
@@ -1,10 +1,10 @@
import { GameRunner, joinLobby } from "./GameRunner";
import backgroundImage from '../../resources/images/TerrainMapFrontPage.png';
import favicon from '../../resources/images/Favicon.svg';
import backgroundImage from "../../resources/images/TerrainMapFrontPage.png";
import favicon from "../../resources/images/Favicon.svg";
import './PublicLobby';
import './UsernameInput';
import './styles.css';
import "./PublicLobby";
import "./UsernameInput";
import "./styles.css";
import { UsernameInput } from "./UsernameInput";
import { SinglePlayerModal } from "./SinglePlayerModal";
import { HostLobbyModal as HostPrivateLobbyModal } from "./HostLobbyModal";
@@ -12,132 +12,152 @@ import { JoinPrivateLobbyModal } from "./JoinPrivateLobbyModal";
import { generateID } from "../core/Util";
import { generateCryptoRandomUUID } from "./Utils";
import { consolex } from "../core/Consolex";
import { PublicLobby } from "./PublicLobby";
class Client {
private gameStop: () => void
private gameStop: () => void;
private usernameInput: UsernameInput | null = null;
private usernameInput: UsernameInput | null = null;
private joinModal: JoinPrivateLobbyModal
constructor() {
private joinModal: JoinPrivateLobbyModal;
private publicLobby: PublicLobby;
constructor() {}
initialize(): void {
this.usernameInput = document.querySelector(
"username-input"
) as UsernameInput;
if (!this.usernameInput) {
consolex.warn("Username input element not found");
}
window.addEventListener("beforeunload", (event) => {
consolex.log("Browser is closing");
if (this.gameStop != null) {
this.gameStop();
}
});
initialize(): void {
this.usernameInput = document.querySelector('username-input') as UsernameInput;
if (!this.usernameInput) {
consolex.warn('Username input element not found');
setFavicon();
document.addEventListener("join-lobby", this.handleJoinLobby.bind(this));
document.addEventListener("leave-lobby", this.handleLeaveLobby.bind(this));
document.addEventListener(
"single-player",
this.handleSinglePlayer.bind(this)
);
const spModal = document.querySelector(
"single-player-modal"
) as SinglePlayerModal;
spModal instanceof SinglePlayerModal;
document.getElementById("single-player").addEventListener("click", () => {
if (this.usernameInput.isValid()) {
spModal.open();
}
});
this.publicLobby = document.querySelector("public-lobby") as PublicLobby;
const hostModal = document.querySelector(
"host-lobby-modal"
) as HostPrivateLobbyModal;
hostModal instanceof HostPrivateLobbyModal;
document
.getElementById("host-lobby-button")
.addEventListener("click", () => {
if (this.usernameInput.isValid()) {
hostModal.open();
}
window.addEventListener('beforeunload', (event) => {
consolex.log('Browser is closing');
if (this.gameStop != null) {
this.gameStop()
}
});
});
setFavicon()
document.addEventListener('join-lobby', this.handleJoinLobby.bind(this));
document.addEventListener('leave-lobby', this.handleLeaveLobby.bind(this));
document.addEventListener('single-player', this.handleSinglePlayer.bind(this));
const spModal = document.querySelector('single-player-modal') as SinglePlayerModal;
spModal instanceof SinglePlayerModal
document.getElementById('single-player').addEventListener('click', () => {
if (this.usernameInput.isValid()) {
spModal.open();
}
})
const hostModal = document.querySelector('host-lobby-modal') as HostPrivateLobbyModal;
hostModal instanceof HostPrivateLobbyModal
document.getElementById('host-lobby-button').addEventListener('click', () => {
if (this.usernameInput.isValid()) {
hostModal.open();
}
})
this.joinModal = document.querySelector('join-private-lobby-modal') as JoinPrivateLobbyModal;
this.joinModal instanceof JoinPrivateLobbyModal
document.getElementById('join-private-lobby-button').addEventListener('click', () => {
if (this.usernameInput.isValid()) {
this.joinModal.open();
}
})
}
private async handleJoinLobby(event: CustomEvent) {
const lobby = event.detail.lobby
consolex.log(`joining lobby ${lobby.id}`)
if (this.gameStop != null) {
consolex.log('joining lobby, stopping existing game')
this.gameStop()
this.joinModal = document.querySelector(
"join-private-lobby-modal"
) as JoinPrivateLobbyModal;
this.joinModal instanceof JoinPrivateLobbyModal;
document
.getElementById("join-private-lobby-button")
.addEventListener("click", () => {
if (this.usernameInput.isValid()) {
this.joinModal.open();
}
this.gameStop = joinLobby(
{
gameType: event.detail.gameType,
playerName: (): string => this.usernameInput.getCurrentUsername(),
gameID: lobby.id,
persistentID: getPersistentIDFromCookie(),
playerID: generateID(),
clientID: generateID(),
map: event.detail.map,
difficulty: event.detail.difficulty,
},
() => this.joinModal.close()
);
}
});
}
private async handleLeaveLobby(event: CustomEvent) {
if (this.gameStop == null) {
return
}
consolex.log('leaving lobby, cancelling game')
this.gameStop()
this.gameStop = null
private async handleJoinLobby(event: CustomEvent) {
const lobby = event.detail.lobby;
consolex.log(`joining lobby ${lobby.id}`);
if (this.gameStop != null) {
consolex.log("joining lobby, stopping existing game");
this.gameStop();
}
this.gameStop = joinLobby(
{
gameType: event.detail.gameType,
playerName: (): string => this.usernameInput.getCurrentUsername(),
gameID: lobby.id,
persistentID: getPersistentIDFromCookie(),
playerID: generateID(),
clientID: generateID(),
map: event.detail.map,
difficulty: event.detail.difficulty,
},
() => {
this.joinModal.close();
this.publicLobby.stop();
}
);
}
private async handleSinglePlayer(event: CustomEvent) {
alert('coming soon')
private async handleLeaveLobby(event: CustomEvent) {
if (this.gameStop == null) {
return;
}
consolex.log("leaving lobby, cancelling game");
this.gameStop();
this.gameStop = null;
}
private async handleSinglePlayer(event: CustomEvent) {
alert("coming soon");
}
}
// Initialize the client when the DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
new Client().initialize();
document.addEventListener("DOMContentLoaded", () => {
new Client().initialize();
});
document.body.style.backgroundImage = `url(${backgroundImage})`;
function setFavicon(): void {
const link = document.createElement('link');
link.type = 'image/x-icon';
link.rel = 'shortcut icon';
link.href = favicon;
document.head.appendChild(link);
const link = document.createElement("link");
link.type = "image/x-icon";
link.rel = "shortcut icon";
link.href = favicon;
document.head.appendChild(link);
}
// WARNING: DO NOT EXPOSE THIS ID
export function getPersistentIDFromCookie(): string {
const COOKIE_NAME = 'player_persistent_id'
const COOKIE_NAME = "player_persistent_id";
// Try to get existing cookie
const cookies = document.cookie.split(';')
for (let cookie of cookies) {
const [cookieName, cookieValue] = cookie.split('=').map(c => c.trim())
if (cookieName === COOKIE_NAME) {
return cookieValue
}
// Try to get existing cookie
const cookies = document.cookie.split(";");
for (let cookie of cookies) {
const [cookieName, cookieValue] = cookie.split("=").map((c) => c.trim());
if (cookieName === COOKIE_NAME) {
return cookieValue;
}
}
// If no cookie exists, create new ID and set cookie
const newID = generateCryptoRandomUUID()
document.cookie = [
`${COOKIE_NAME}=${newID}`,
`max-age=${5 * 365 * 24 * 60 * 60}`, // 5 years
'path=/',
'SameSite=Strict',
'Secure'
].join(';')
// If no cookie exists, create new ID and set cookie
const newID = generateCryptoRandomUUID();
document.cookie = [
`${COOKIE_NAME}=${newID}`,
`max-age=${5 * 365 * 24 * 60 * 60}`, // 5 years
"path=/",
"SameSite=Strict",
"Secure",
].join(";");
return newID
}
return newID;
}
+100 -83
View File
@@ -1,18 +1,18 @@
import { LitElement, html, css } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { LitElement, html, css } from "lit";
import { customElement, state } from "lit/decorators.js";
import { Lobby } from "../core/Schemas";
import { Difficulty, GameMap, GameType } from '../core/game/Game';
import { consolex } from '../core/Consolex';
import { Difficulty, GameMap, GameType } from "../core/game/Game";
import { consolex } from "../core/Consolex";
@customElement('public-lobby')
@customElement("public-lobby")
export class PublicLobby extends LitElement {
@state() private lobbies: Lobby[] = [];
@state() private isLobbyHighlighted: boolean = false;
private lobbiesInterval: number | null = null;
@state() private lobbies: Lobby[] = [];
@state() private isLobbyHighlighted: boolean = false;
private lobbiesInterval: number | null = null;
private currLobby: Lobby = null
private currLobby: Lobby = null;
static styles = css`
static styles = css`
/* Add your styles here, based on your existing CSS */
.lobby-button {
display: flex;
@@ -22,7 +22,7 @@ export class PublicLobby extends LitElement {
width: 100%;
max-width: 20rem;
margin: 0 auto;
padding: .5rem 1rem;
padding: 0.5rem 1rem;
background-color: #2563eb;
color: white;
font-weight: bold;
@@ -42,90 +42,107 @@ export class PublicLobby extends LitElement {
background-color: #15803d;
}
.lobby-name { font-size: 1.2rem; }
.lobby-timer { font-size: 1rem; }
.player-count { font-size: 1rem; }
.lobby-name {
font-size: 1.2rem;
}
.lobby-timer {
font-size: 1rem;
}
.player-count {
font-size: 1rem;
}
`;
connectedCallback() {
super.connectedCallback();
this.fetchAndUpdateLobbies(); // Fetch immediately on start
this.lobbiesInterval = window.setInterval(() => this.fetchAndUpdateLobbies(), 1000);
connectedCallback() {
super.connectedCallback();
this.fetchAndUpdateLobbies(); // Fetch immediately on start
this.lobbiesInterval = window.setInterval(
() => this.fetchAndUpdateLobbies(),
1000
);
}
disconnectedCallback() {
super.disconnectedCallback();
this.stop();
}
public stop() {
if (this.lobbiesInterval !== null) {
clearInterval(this.lobbiesInterval);
this.lobbiesInterval = null;
}
}
private async fetchAndUpdateLobbies(): Promise<void> {
try {
const lobbies = await this.fetchLobbies();
this.lobbies = lobbies;
} catch (error) {
consolex.error("Error fetching and updating lobbies:", error);
}
}
async fetchLobbies(): Promise<Lobby[]> {
const url = "/lobbies";
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data.lobbies;
} catch (error) {
consolex.error("Error fetching lobbies:", error);
throw error;
}
}
render() {
if (this.lobbies.length === 0) {
return html``;
}
disconnectedCallback() {
super.disconnectedCallback();
if (this.lobbiesInterval !== null) {
clearInterval(this.lobbiesInterval);
this.lobbiesInterval = null;
}
}
const lobby = this.lobbies[0];
const timeRemaining = Math.max(0, Math.floor(lobby.msUntilStart / 1000));
private async fetchAndUpdateLobbies(): Promise<void> {
try {
const lobbies = await this.fetchLobbies();
this.lobbies = lobbies;
} catch (error) {
consolex.error('Error fetching and updating lobbies:', error);
}
}
async fetchLobbies(): Promise<Lobby[]> {
const url = '/lobbies';
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data.lobbies;
} catch (error) {
consolex.error('Error fetching lobbies:', error);
throw error;
}
}
render() {
if (this.lobbies.length === 0) {
return html``;
}
const lobby = this.lobbies[0];
const timeRemaining = Math.max(0, Math.floor(lobby.msUntilStart / 1000));
return html`
return html`
<button
@click=${() => this.lobbyClicked(lobby)}
class="lobby-button ${this.isLobbyHighlighted ? 'highlighted' : ''}"
class="lobby-button ${this.isLobbyHighlighted ? "highlighted" : ""}"
>
<div class="lobby-name">Game ${lobby.id}</div>
<div class="lobby-timer">Starts in: ${timeRemaining}s</div>
<div class="player-count">Players: ${lobby.numClients}</div>
</button>
`;
}
}
private lobbyClicked(lobby: Lobby) {
this.isLobbyHighlighted = !this.isLobbyHighlighted;
if (this.currLobby == null) {
this.currLobby = lobby
this.dispatchEvent(new CustomEvent('join-lobby', {
detail: {
lobby: lobby,
gameType: GameType.Public,
map: GameMap.World,
difficulty: Difficulty.Medium,
},
bubbles: true,
composed: true
}));
} else {
this.dispatchEvent(new CustomEvent('leave-lobby', {
detail: { lobby: this.currLobby },
bubbles: true,
composed: true
}));
this.currLobby = null
}
private lobbyClicked(lobby: Lobby) {
this.isLobbyHighlighted = !this.isLobbyHighlighted;
if (this.currLobby == null) {
this.currLobby = lobby;
this.dispatchEvent(
new CustomEvent("join-lobby", {
detail: {
lobby: lobby,
gameType: GameType.Public,
map: GameMap.World,
difficulty: Difficulty.Medium,
},
bubbles: true,
composed: true,
})
);
} else {
this.dispatchEvent(
new CustomEvent("leave-lobby", {
detail: { lobby: this.currLobby },
bubbles: true,
composed: true,
})
);
this.currLobby = null;
}
}
}
}