mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:30:45 +00:00
Created PublicLobby lit element
This commit is contained in:
@@ -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
@@ -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})`;
|
||||
|
||||
@@ -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
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user