store name, anon has random suffix, color a hash of name

This commit is contained in:
evanpelle
2024-09-11 20:06:55 -07:00
parent 76634489aa
commit 8f56fea0cd
8 changed files with 72 additions and 28 deletions
+45 -7
View File
@@ -11,8 +11,12 @@ import './styles.css';
import {simpleHash} from "../core/Util";
import {PseudoRandom} from "../core/PseudoRandom";
const usernameKey: string = 'username';
class Client {
private terrainMap: Promise<TerrainMap>
private game: ClientGame
private lobbiesInterval: NodeJS.Timeout | null = null;
@@ -26,6 +30,13 @@ class Client {
}
initialize(): void {
const storedUsername = localStorage.getItem(usernameKey)
if (storedUsername) {
const usernameInput = document.getElementById('username') as HTMLInputElement | null;
if (usernameInput) {
usernameInput.value = storedUsername
}
}
this.config = getConfig()
setFavicon()
this.terrainMap = loadTerrainMap()
@@ -125,7 +136,7 @@ class Client {
]);
console.log(`got ip ${clientIP}`)
this.game = createClientGame(
getUsername(),
refreshUsername(),
uuidv4(),
uuidv4(),
clientIP,
@@ -164,20 +175,32 @@ class Client {
}
}
function getUsername(): string {
function refreshUsername(): string {
const usernameInput = document.getElementById('username') as HTMLInputElement | null;
if (usernameInput) {
const trimmedValue = usernameInput.value.trim();
return trimmedValue || 'Anon'; // Return 'Anon' if the trimmed value is empty
if (usernameInput == null) {
console.warn('username element not found')
return "Anon"
}
if (usernameInput && usernameInput.value.trim()) {
const trimmedValue = usernameInput.value.trim();
localStorage.setItem(usernameKey, trimmedValue)
return trimmedValue
} else {
const storedUsername = localStorage.getItem(usernameKey);
if (storedUsername) {
return storedUsername
}
const newUsername = "Anon" + uuidToThreeDigits()
localStorage.setItem(usernameKey, newUsername)
return newUsername
}
return 'Anon'; // Return 'Anon' if the input element is not found
}
function setupUsernameCallback(callback: (username: string) => void): void {
const usernameInput = document.getElementById('username') as HTMLInputElement | null;
if (usernameInput) {
usernameInput.addEventListener('input', () => {
const username = getUsername();
const username = refreshUsername();
callback(username);
});
} else {
@@ -229,4 +252,19 @@ function setFavicon(): void {
link.rel = 'shortcut icon';
link.href = favicon;
document.head.appendChild(link);
}
function uuidToThreeDigits(): string {
const uuid = uuidv4()
// Remove hyphens and convert to lowercase
const cleanUuid = uuid.replace(/-/g, '').toLowerCase();
// Convert hex string to decimal
const decimal = BigInt(`0x${cleanUuid}`);
// Get last 3 digits
const threeDigits = decimal % 1000n;
// Pad with leading zeros if necessary
return threeDigits.toString().padStart(3, '0');
}
+3 -1
View File
@@ -11,6 +11,7 @@ import {and, bfs, dist, manhattanDist} from "../core/Util";
import {TerrainRenderer} from "./graphics/TerrainRenderer";
export function createClientGame(name: string, clientID: ClientID, playerID: PlayerID, ip: string | null, gameID: GameID, config: Config, terrainMap: TerrainMap): ClientGame {
let eventBus = new EventBus()
let game = createGame(terrainMap, eventBus, config)
@@ -32,7 +33,6 @@ export function createClientGame(name: string, clientID: ClientID, playerID: Pla
}
export class ClientGame {
private myPlayer: Player
private turns: Turn[] = []
private socket: WebSocket
@@ -119,6 +119,8 @@ export class ClientGame {
public start() {
console.log('version 3')
this.isActive = true
// TODO: make each class do this, or maybe have client intercept all requests?
//this.eventBus.on(TickEvent, (e) => this.tick(e))
+7 -6
View File
@@ -1,5 +1,5 @@
import {PriorityQueue} from "@datastructures-js/priority-queue";
import {Boat, BoatEvent, Cell, Game, Tile, TileEvent} from "../../core/Game";
import {Boat, BoatEvent, Cell, Game, Player, Tile, TileEvent} from "../../core/Game";
import {PseudoRandom} from "../../core/PseudoRandom";
import {Colord} from "colord";
import {bfs, dist} from "../../core/Util";
@@ -65,12 +65,12 @@ export class TerritoryRenderer {
bfs(event.boat.tile(), dist(event.boat.tile(), 4)).forEach(
t => {
if (trail.has(t)) {
this.paintCell(t.cell(), this.theme.territoryColor(event.boat.owner().id()), 150)
this.paintCell(t.cell(), this.theme.territoryColor(event.boat.owner().info()), 150)
}
}
)
bfs(event.boat.tile(), dist(event.boat.tile(), 2)).forEach(t => this.paintCell(t.cell(), this.theme.borderColor(event.boat.owner().id()), 255))
bfs(event.boat.tile(), dist(event.boat.tile(), 1)).forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(event.boat.owner().id()), 180))
bfs(event.boat.tile(), dist(event.boat.tile(), 2)).forEach(t => this.paintCell(t.cell(), this.theme.borderColor(event.boat.owner().info()), 255))
bfs(event.boat.tile(), dist(event.boat.tile(), 1)).forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(event.boat.owner().info()), 180))
} else {
trail.forEach(t => this.paintTerritory(t))
this.boatToTrail.delete(event.boat)
@@ -96,16 +96,17 @@ export class TerritoryRenderer {
this.clearCell(tile.cell())
return
}
const owner = tile.owner() as Player
if (tile.isBorder()) {
this.paintCell(
tile.cell(),
this.theme.borderColor(tile.owner().id()),
this.theme.borderColor(owner.info()),
255
)
} else {
this.paintCell(
tile.cell(),
this.theme.territoryColor(tile.owner().id()),
this.theme.territoryColor(owner.info()),
110
)
}
+3 -2
View File
@@ -58,14 +58,15 @@ h3 {
}
#username {
width: 100%;
width: 60%;
padding: 15px;
font-size: 30px;
font-size: 40px;
text-align: center;
border: 2px solid #007bff;
border-radius: 5px;
background-color: rgba(255, 255, 255, 0.8);
margin: 30px auto;
display: block;
}
#lobbies-container {
+1
View File
@@ -1,3 +1,4 @@
import {info} from "console"
import {Config} from "./configuration/Config"
import {GameEvent} from "./EventBus"
import {ClientID, GameID} from "./Schemas"
+2 -2
View File
@@ -50,8 +50,8 @@ export interface Config {
export interface Theme {
playerInfoColor(id: PlayerID): Colord;
territoryColor(id: PlayerID): Colord;
borderColor(id: PlayerID): Colord;
territoryColor(playerInfo: PlayerInfo): Colord;
borderColor(playerInfo: PlayerInfo): Colord;
terrainColor(tile: Tile): Colord;
backgroundColor(): Colord;
font(): string;
+5 -5
View File
@@ -1,5 +1,5 @@
import {Colord, colord, random} from "colord";
import {PlayerID, TerrainType, Tile} from "../Game";
import {PlayerID, PlayerInfo, TerrainType, Tile} from "../Game";
import {Theme} from "./Config";
import {time} from "console";
import {PseudoRandom} from "../PseudoRandom";
@@ -119,12 +119,12 @@ export const pastelTheme = new class implements Theme {
return colord({r: 50, g: 50, b: 50})
}
territoryColor(id: PlayerID): Colord {
return this.territoryColors[simpleHash(id) % this.territoryColors.length]
territoryColor(playerInfo: PlayerInfo): Colord {
return this.territoryColors[simpleHash(playerInfo.name) % this.territoryColors.length]
}
borderColor(id: PlayerID): Colord {
const tc = this.territoryColor(id).rgba;
borderColor(playerInfo: PlayerInfo): Colord {
const tc = this.territoryColor(playerInfo).rgba;
return colord({
r: Math.max(tc.r - 40, 0),
g: Math.max(tc.g - 40, 0),