Created PublicLobby lit element

This commit is contained in:
evanpelle
2024-10-12 08:56:11 -07:00
parent 180769bf35
commit a02d148151
4 changed files with 128 additions and 106 deletions
+6 -5
View File
@@ -162,21 +162,22 @@
* disable double tap on mobile DONE 10/6/2024
* donate troops button DONE 10/7/2024
* Make fake humans spawn by their country DONE 10/9/2024
* UI: leader board DONE 10/12/2024
* single player menu
* private game menu
* optimize sendBoat function
* Test on android
* Increase disk size
* NPC more likely to accept alliance fewer alliance player has
* fake humans target enemies
* create private lobby menu
* better NPC relation logic
* surface NPC relations
* block user inputs if too far behind server
* BUG: FakeHuman don't be enemy if don't share border (or send boat)
* store cookies
* UI: leader board
* Load terrain dataImage in background
* BUG: half encircle Antartica causes capture
* improve front page (make map larger?)
* Add additional maps
* add offline mode
* REFACTOR: give terranullius an ID, game.player() returns terranullius
* REFACTOR: ocean is considered TerraNullius ?
* Make icons svgs
+6 -92
View File
@@ -6,11 +6,10 @@ import backgroundImage from '../../resources/images/TerrainMapFrontPage.png';
import favicon from '../../resources/images/Favicon.png';
import {v4 as uuidv4} from 'uuid';
import './PublicLobby';
import './styles.css';
import {simpleHash} from "../core/Util";
import {PseudoRandom} from "../core/PseudoRandom";
const usernameKey: string = 'username';
@@ -20,8 +19,6 @@ class Client {
private terrainMap: Promise<TerrainMap>
private game: ClientGame
private lobbiesInterval: NodeJS.Timeout | null = null;
private isLobbyHighlighted: boolean = false;
private ip: Promise<string | null> = null
@@ -38,101 +35,17 @@ class Client {
usernameInput.value = storedUsername
}
}
this.config = getConfig()
setFavicon()
this.terrainMap = loadTerrainMap()
this.startLobbyPolling()
this.ip = getClientIP()
document.addEventListener('join-lobby', this.handleJoinLobby.bind(this));
}
private startLobbyPolling(): void {
this.fetchAndUpdateLobbies(); // Fetch immediately on start
this.lobbiesInterval = setInterval(() => this.fetchAndUpdateLobbies(), 1000);
}
private async fetchAndUpdateLobbies(): Promise<void> {
try {
const lobbies = await this.fetchLobbies();
this.updateLobbiesDisplay(lobbies);
} catch (error) {
console.error('Error fetching and updating lobbies:', error);
}
}
private updateLobbiesDisplay(lobbies: Lobby[]): void {
if (lobbies.length === 0) {
document.getElementById('lobby-button').style.display = 'none';
return;
}
const lobby = lobbies[0];
const lobbyButton = document.getElementById('lobby-button');
const nameElement = document.getElementById('lobby-name');
const timerElement = document.getElementById('lobby-timer');
const playerCountElement = document.getElementById('player-count');
if (lobbyButton) {
lobbyButton.style.display = 'flex';
lobbyButton.onclick = () => this.joinLobby(lobby);
// Preserve the highlighted state
lobbyButton.classList.toggle('highlighted', this.isLobbyHighlighted);
}
if (nameElement) nameElement.textContent = `Game ${lobby.id.substring(0, 3)}`;
if (timerElement) {
const timeRemaining = Math.max(0, Math.floor((lobby.msUntilStart) / 1000));
timerElement.textContent = `Starts in: ${timeRemaining}s`;
}
if (playerCountElement) playerCountElement.textContent = `Players: ${lobby.numClients}`;
if (lobbies.length > 1) {
const nextLobby = lobbies[1]
const nextGame = document.getElementById('next-game');
nextGame.textContent = `Next Game: ${nextLobby.id.substring(0, 3)}`
}
}
async fetchLobbies(): Promise<Lobby[]> {
const url = '/lobbies';
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}, statusText: ${response.statusText}`);
}
const data = await response.json();
return data.lobbies;
} catch (error) {
console.error('Error fetching lobbies:', error);
throw error;
}
}
private async joinLobby(lobby: Lobby) {
private async handleJoinLobby(event: CustomEvent) {
const lobby = event.detail
console.log(`joining lobby ${lobby.id}`)
const lobbyButton = document.getElementById('lobby-button');
if (lobbyButton) {
this.isLobbyHighlighted = !this.isLobbyHighlighted;
lobbyButton.classList.toggle('highlighted', this.isLobbyHighlighted);
}
if (this.isLobbyHighlighted) {
lobbyButton.classList.remove('bg-blue-600', 'hover:bg-blue-700');
lobbyButton.classList.add('bg-green-600', 'hover:bg-green-700');
} else {
lobbyButton.classList.remove('bg-green-600', 'hover:bg-green-700');
lobbyButton.classList.add('bg-blue-600', 'hover:bg-blue-700');
}
if (!this.isLobbyHighlighted) {
this.game.stop()
this.game = null
return
}
if (this.game != null) {
return;
}
const [terrainMap, clientIP] = await Promise.all([
this.terrainMap,
this.ip
@@ -223,6 +136,7 @@ async function getClientIP(timeoutMs: number = 1000): Promise<string | null> {
// Initialize the client when the DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
new Client().initialize();
});
document.body.style.backgroundImage = `url(${backgroundImage})`;
+115
View File
@@ -0,0 +1,115 @@
import {LitElement, html, css} from 'lit';
import {customElement, state} from 'lit/decorators.js';
import {Lobby} from "../core/Schemas";
@customElement('public-lobby')
export class PublicLobby extends LitElement {
@state() private lobbies: Lobby[] = [];
@state() private isLobbyHighlighted: boolean = false;
private lobbiesInterval: number | null = null;
static styles = css`
/* Add your styles here, based on your existing CSS */
.lobby-button {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
max-width: 20rem;
margin: 0 auto;
padding: 1.5rem 2rem;
background-color: #2563eb;
color: white;
font-weight: bold;
border-radius: 0.5rem;
transition: background-color 0.3s ease-in-out;
}
.lobby-button:hover {
background-color: #1d4ed8;
}
.lobby-button.highlighted {
background-color: #16a34a;
}
.lobby-button.highlighted:hover {
background-color: #15803d;
}
.lobby-name { font-size: 1.5rem; }
.lobby-timer { font-size: 1.25rem; }
.player-count { font-size: 1rem; }
`;
connectedCallback() {
super.connectedCallback();
this.fetchAndUpdateLobbies(); // Fetch immediately on start
this.lobbiesInterval = window.setInterval(() => this.fetchAndUpdateLobbies(), 1000);
}
disconnectedCallback() {
super.disconnectedCallback();
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) {
console.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) {
console.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`
<button
@click=${() => this.joinLobby(lobby)}
class="lobby-button ${this.isLobbyHighlighted ? 'highlighted' : ''}"
>
<div class="lobby-name">Game ${lobby.id.substring(0, 3)}</div>
<div class="lobby-timer">Starts in: ${timeRemaining}s</div>
<div class="player-count">Players: ${lobby.numClients}</div>
</button>
${this.lobbies.length > 1 ? html`
<div id="next-game">Next Game: ${this.lobbies[1].id.substring(0, 3)}</div>
` : ''}
`;
}
private joinLobby(lobby: Lobby) {
this.isLobbyHighlighted = !this.isLobbyHighlighted;
this.dispatchEvent(new CustomEvent('join-lobby', {
detail: lobby,
bubbles: true,
composed: true
}));
}
}
+1 -9
View File
@@ -57,15 +57,7 @@
</div>
<h3 class="text-6xl mt-8 tracking-wide pt-8">Public Games</h3>
<div id="lobbies-container" class="p-4">
<button id="lobby-button"
class="w-full max-w-md mx-auto bg-blue-600 hover:bg-blue-700 text-white font-bold py-6 px-8 rounded-lg shadow-lg transition duration-300 ease-in-out flex flex-col items-center justify-center space-y-3 group"
data-selected="false">
<div id="lobby-name" class="text-2xl group-data-[selected=true]:text-green-200"></div>
<div id="lobby-timer" class="text-xl group-data-[selected=true]:text-green-200"></div>
<div id="player-count" class="text-lg group-data-[selected=true]:text-green-200"></div>
</button>
</div>
<public-lobby></public-lobby>
</div>
</div>
<h3 id="next-game" class="invisible"> </h3>