can leave lobby

This commit is contained in:
evanpelle
2024-08-25 09:33:58 -07:00
parent 2d7d4875f7
commit 6f1848dbc7
7 changed files with 61 additions and 80 deletions
+1
View File
@@ -54,3 +54,4 @@
* BUG: fix hotreload (priority queue breaks it) * BUG: fix hotreload (priority queue breaks it)
* PERF: use hierarchical a* search for boats * PERF: use hierarchical a* search for boats
* Add terrain elevation to map * Add terrain elevation to map
* boats can go around the world
+32 -44
View File
@@ -24,6 +24,7 @@ class Client {
private lobbiesContainer: HTMLElement | null; private lobbiesContainer: HTMLElement | null;
private lobbiesInterval: NodeJS.Timeout | null = null; private lobbiesInterval: NodeJS.Timeout | null = null;
private isLobbyHighlighted: boolean = false;
private random = new PseudoRandom(1234) private random = new PseudoRandom(1234)
@@ -52,34 +53,31 @@ class Client {
} }
private updateLobbiesDisplay(lobbies: Lobby[]): void { private updateLobbiesDisplay(lobbies: Lobby[]): void {
if (!this.lobbiesContainer) return; if (lobbies.length === 0) {
document.getElementById('lobby-button').style.display = 'none';
return;
}
this.lobbiesContainer.innerHTML = ''; // Clear existing lobbies 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');
lobbies.forEach(lobby => { if (lobbyButton) {
const button = document.createElement('button'); lobbyButton.style.display = 'flex';
button.className = 'lobby-button'; lobbyButton.onclick = () => this.joinLobby(lobby);
const nameElement = document.createElement('div'); // Preserve the highlighted state
nameElement.className = 'lobby-name'; lobbyButton.classList.toggle('highlighted', this.isLobbyHighlighted);
nameElement.textContent = `Lobby ${lobby.id}`; }
const timerElement = document.createElement('div'); if (nameElement) nameElement.textContent = `Lobby ${lobby.id}`;
timerElement.className = 'lobby-timer'; if (timerElement) {
const timeRemaining = Math.max(0, Math.floor((lobby.startTime - Date.now()) / 1000)); const timeRemaining = Math.max(0, Math.floor((lobby.startTime - Date.now()) / 1000));
timerElement.textContent = `Starts in: ${timeRemaining}s`; timerElement.textContent = `Starts in: ${timeRemaining}s`;
}
const playerCountElement = document.createElement('div'); if (playerCountElement) playerCountElement.textContent = `Players: ${lobby.numClients}`;
playerCountElement.className = 'player-count';
playerCountElement.textContent = `Players: ${lobby.numClients}`
button.appendChild(nameElement);
button.appendChild(timerElement);
button.appendChild(playerCountElement);
button.onclick = () => this.joinLobby(lobby);
this.lobbiesContainer.appendChild(button);
});
} }
async fetchLobbies(): Promise<Lobby[]> { async fetchLobbies(): Promise<Lobby[]> {
@@ -97,25 +95,16 @@ class Client {
} }
} }
private async joinLobby(lobby: Lobby) { private joinLobby(lobby: Lobby) {
clearInterval(this.lobbiesInterval); const lobbyButton = document.getElementById('lobby-button');
if (lobbyButton) {
if (this.lobbiesContainer) { this.isLobbyHighlighted = !this.isLobbyHighlighted;
// Clear existing content lobbyButton.classList.toggle('highlighted', this.isLobbyHighlighted);
this.lobbiesContainer.innerHTML = ''; }
if (!this.isLobbyHighlighted) {
// Ensure the container takes up the full height of the viewport this.game.stop()
this.lobbiesContainer.style.display = 'flex'; this.game = null
this.lobbiesContainer.style.justifyContent = 'center'; return
this.lobbiesContainer.style.alignItems = 'center';
this.lobbiesContainer.style.minHeight = '100vh';
// Create and add the joining message
const joiningMessage = document.createElement('div');
joiningMessage.textContent = `Joining: ${lobby.id}`;
joiningMessage.className = 'joining-message';
this.lobbiesContainer.appendChild(joiningMessage);
} }
if (this.game != null) { if (this.game != null) {
@@ -123,11 +112,10 @@ class Client {
} }
this.game = createClientGame(getUsername(), new PseudoRandom(Date.now()).nextID(), lobby.id, getConfig(), this.terrainMap); this.game = createClientGame(getUsername(), new PseudoRandom(Date.now()).nextID(), lobby.id, getConfig(), this.terrainMap);
this.game.join(); this.game.join();
const g = this.game const g = this.game;
window.addEventListener('beforeunload', function (event) { window.addEventListener('beforeunload', function (event) {
// Your function logic here
console.log('Browser is closing'); console.log('Browser is closing');
g.stop() g.stop();
}); });
} }
} }
+4
View File
@@ -97,6 +97,9 @@ export class ClientGame {
}; };
this.socket.onclose = (event: CloseEvent) => { this.socket.onclose = (event: CloseEvent) => {
console.log(`WebSocket closed. Code: ${event.code}, Reason: ${event.reason}`); console.log(`WebSocket closed. Code: ${event.code}, Reason: ${event.reason}`);
if (!this.isActive) {
return
}
if (event.code != 1000) { if (event.code != 1000) {
this.join() this.join()
} }
@@ -126,6 +129,7 @@ export class ClientGame {
clearInterval(this.intervalID) clearInterval(this.intervalID)
this.isActive = false this.isActive = false
if (this.socket.readyState === WebSocket.OPEN) { if (this.socket.readyState === WebSocket.OPEN) {
console.log('on stop: leaving game')
const msg = ClientLeaveMessageSchema.parse({ const msg = ClientLeaveMessageSchema.parse({
type: "leave", type: "leave",
clientID: this.id, clientID: this.id,
+17 -30
View File
@@ -5,7 +5,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenFront (ALPHA)</title> <title>OpenFront (ALPHA)</title>
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" type="text/css" href="styles.css">
<style> <style>
body { body {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
@@ -13,7 +13,6 @@
padding: 0; padding: 0;
min-height: 100vh; min-height: 100vh;
background-color: #15151500; background-color: #15151500;
/* Dark grey background */
background-image: url('/resources/images/watercolor_worldmap.jpg'); background-image: url('/resources/images/watercolor_worldmap.jpg');
background-size: cover; background-size: cover;
background-position: center; background-position: center;
@@ -23,17 +22,16 @@
.content { .content {
max-width: 1020px; max-width: 1020px;
/* Allows for two 500px buttons side by side with some margin */
margin: 0 auto; margin: 0 auto;
padding: 20px; padding: 20px;
position: relative; position: relative;
} }
h1 { h1 {
font-family: Arial, serif;
text-align: center; text-align: center;
color: #ffffff; color: #2e2e2e;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); font-size: 8em;
font-size: 2.5em;
margin-bottom: 30px; margin-bottom: 30px;
} }
@@ -50,25 +48,12 @@
background-color: rgba(255, 255, 255, 0.8); background-color: rgba(255, 255, 255, 0.8);
} }
.lobby-button:hover {
background-color: rgba(0, 123, 255, 0.4);
transform: translateY(-5px);
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.4);
}
.player-count {
font-size: 24px;
margin-top: 20px;
color: #aaddff;
}
#lobbies-container { #lobbies-container {
display: flex; display: flex;
flex-wrap: wrap;
justify-content: center; justify-content: center;
gap: 20px;
} }
.lobby-button { .lobby-button {
width: 500px; width: 500px;
height: 500px; height: 500px;
@@ -96,6 +81,13 @@
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.4); box-shadow: 0 6px 15px rgba(0, 0, 0, 0.4);
} }
.lobby-button.highlighted {
background-color: rgba(0, 123, 255, 0.6);
transform: translateY(-5px);
box-shadow: 0 6px 20px rgba(0, 123, 255, 0.6);
border-color: #ffffff;
}
.lobby-name { .lobby-name {
font-size: 36px; font-size: 36px;
margin-bottom: 20px; margin-bottom: 20px;
@@ -117,15 +109,6 @@
text-align: center; text-align: center;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
} }
h1 {
font-family: Overpass, serif;
text-align: center;
color: #3d3c3c;
/* text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); */
font-size: 8em;
margin-bottom: 30px;
}
</style> </style>
</head> </head>
@@ -136,7 +119,11 @@
<input type="text" id="username" placeholder="Enter your username"> <input type="text" id="username" placeholder="Enter your username">
</div> </div>
<div id="lobbies-container"> <div id="lobbies-container">
<!-- Lobby buttons will be inserted here by your existing JavaScript --> <button id="lobby-button" class="lobby-button">
<div id="lobby-name" class="lobby-name"></div>
<div id="lobby-timer" class="lobby-timer"></div>
<div id="player-count" class="player-count"></div>
</button>
</div> </div>
</div> </div>
+2 -2
View File
@@ -71,11 +71,11 @@ export class DefaultPlayerConfig implements PlayerConfig {
} }
troopAdditionRate(player: Player): number { troopAdditionRate(player: Player): number {
const max = Math.sqrt(player.numTilesOwned()) * 1000 + 1000 const max = Math.sqrt(player.numTilesOwned()) * 1000 + 10000
let toAdd = 10 + (player.troops() + Math.sqrt(player.troops() * player.numTilesOwned())) / 250 let toAdd = 10 + (player.troops() + Math.sqrt(player.troops() * player.numTilesOwned())) / 250
return Math.min(player.troops() + toAdd, max) return Math.min(Math.min(player.troops() + toAdd, max), 1_000_0000)
} }
} }
+4 -4
View File
@@ -4,10 +4,10 @@ import {DefaultConfig, DefaultPlayerConfig, defaultPlayerConfig} from "./Default
export const devConfig = new class extends DefaultConfig { export const devConfig = new class extends DefaultConfig {
gameCreationRate(): number { gameCreationRate(): number {
return 2 * 1000 return 21 * 1000
} }
lobbyLifetime(): number { lobbyLifetime(): number {
return 5 * 1000 return 20 * 1000
} }
turnIntervalMs(): number { turnIntervalMs(): number {
return 100 return 100
@@ -16,7 +16,7 @@ export const devConfig = new class extends DefaultConfig {
return devPlayerConfig return devPlayerConfig
} }
numBots(): number { numBots(): number {
return 500 return 250
} }
} }
@@ -25,6 +25,6 @@ export const devPlayerConfig = new class extends DefaultPlayerConfig {
if (playerInfo.isBot) { if (playerInfo.isBot) {
return 5000 return 5000
} }
return 5000 return 10000
} }
} }
+1
View File
@@ -43,6 +43,7 @@ export class GameServer {
} }
} }
if (clientMsg.type == "leave") { if (clientMsg.type == "leave") {
// TODO: get rid of leave message, just use on close?
const toRemove = this.clients.filter(c => c.id) const toRemove = this.clients.filter(c => c.id)
if (toRemove.length == 0) { if (toRemove.length == 0) {
return return