mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 12:00:44 +00:00
adding persistent id
This commit is contained in:
@@ -239,9 +239,11 @@
|
||||
* add capture alert DONE 12/13/2024
|
||||
* better emojis 🏳️🤦♂️🖕☮️🫡😡😈🤡 DONE 12/13/2024
|
||||
* store ips in bigquery table DONE 12/14/2024
|
||||
* better error logging in server
|
||||
* better error logging in server DONE 12/16/2024
|
||||
* store and archive player cookies
|
||||
* make ips less precise
|
||||
* send client logs back to server
|
||||
* seperate server config from client config
|
||||
* right click brings up player info menu
|
||||
* give naval units health
|
||||
* bug: player names not updating sometimes
|
||||
|
||||
@@ -10,7 +10,7 @@ import { createMiniMap, loadTerrainMap, TerrainMapImpl } from "../core/game/Terr
|
||||
import { and, bfs, dist, generateID, manhattanDist } from "../core/Util";
|
||||
import { WinCheckExecution } from "../core/execution/WinCheckExecution";
|
||||
import { SendAttackIntentEvent, SendSpawnIntentEvent, Transport } from "./Transport";
|
||||
import { createCanvas } from "./graphics/Utils";
|
||||
import { createCanvas } from "./Utils";
|
||||
import { DisplayMessageEvent, MessageType } from "./graphics/layers/EventsDisplay";
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { WorkerClient } from "../core/worker/WorkerClient";
|
||||
|
||||
@@ -3,6 +3,7 @@ import { EventBus, GameEvent } from "../core/EventBus"
|
||||
import { AllianceRequest, AllPlayers, Cell, Player, PlayerID, PlayerType, Tile, UnitType } from "../core/game/Game"
|
||||
import { ClientID, ClientIntentMessageSchema, ClientJoinMessageSchema, GameID, Intent, ServerMessage, ServerMessageSchema, ClientPingMessageSchema, GameConfig } from "../core/Schemas"
|
||||
import { LocalServer } from "./LocalServer"
|
||||
import { getPersistentIDFromCookie } from "./Utils"
|
||||
|
||||
|
||||
export class SendAllianceRequestIntentEvent implements GameEvent {
|
||||
@@ -194,7 +195,8 @@ export class Transport {
|
||||
type: "join",
|
||||
gameID: this.gameID,
|
||||
clientID: this.clientID,
|
||||
lastTurn: numTurns
|
||||
lastTurn: numTurns,
|
||||
persistentID: getPersistentIDFromCookie(),
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
@@ -34,3 +34,29 @@ export function createCanvas(): HTMLCanvasElement {
|
||||
|
||||
return canvas
|
||||
}
|
||||
|
||||
// WARNING: DO NOT EXPOSE THIS ID
|
||||
export function getPersistentIDFromCookie(): string {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// If no cookie exists, create new ID and set cookie
|
||||
const newId = crypto.randomUUID(); // Using built-in UUID generator
|
||||
document.cookie = [
|
||||
`${COOKIE_NAME}=${newId}`,
|
||||
`max-age=${5 * 365 * 24 * 60 * 60}`, // 5 years
|
||||
'path=/',
|
||||
'SameSite=Strict',
|
||||
'Secure'
|
||||
].join(';');
|
||||
|
||||
return newId;
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { Layer } from './Layer';
|
||||
import { Game } from '../../../core/game/Game';
|
||||
import { ClientID } from '../../../core/Schemas';
|
||||
import { renderNumber, renderTroops } from '../Utils';
|
||||
import { renderNumber, renderTroops } from '../../Utils';
|
||||
import { EventBus } from '../../../core/EventBus';
|
||||
import { UIState } from '../UIState';
|
||||
import { SendSetTargetTroopRatioEvent } from '../../Transport';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Theme } from "../../../core/configuration/Config"
|
||||
import { Layer } from "./Layer"
|
||||
import { placeName } from "../NameBoxCalculator"
|
||||
import { TransformHandler } from "../TransformHandler"
|
||||
import { renderTroops } from "../Utils"
|
||||
import { renderTroops } from "../../Utils"
|
||||
import traitorIcon from '../../../../resources/images/TraitorIcon.png';
|
||||
import allianceIcon from '../../../../resources/images/AllianceIcon.png';
|
||||
import crownIcon from '../../../../resources/images/CrownIcon.png';
|
||||
|
||||
@@ -12,7 +12,7 @@ import goldCoinIcon from '../../../../../resources/images/GoldCoinIcon.svg';
|
||||
import portIcon from '../../../../../resources/images/PortIcon.svg';
|
||||
import shieldIcon from '../../../../../resources/images/ShieldIconWhite.svg';
|
||||
import cityIcon from '../../../../../resources/images/CityIconWhite.svg';
|
||||
import { renderNumber } from '../../Utils';
|
||||
import { renderNumber } from '../../../Utils';
|
||||
import { ContextMenuEvent } from '../../../InputHandler';
|
||||
|
||||
interface BuildItemDisplay {
|
||||
|
||||
+3
-1
@@ -224,6 +224,7 @@ export const ClientIntentMessageSchema = ClientBaseMessageSchema.extend({
|
||||
|
||||
export const ClientJoinMessageSchema = ClientBaseMessageSchema.extend({
|
||||
type: z.literal('join'),
|
||||
persistentID: z.string(),
|
||||
lastTurn: z.number() // The last turn the client saw.
|
||||
})
|
||||
|
||||
@@ -236,7 +237,8 @@ export const PlayerRecordSchema = z.object({
|
||||
})
|
||||
|
||||
export const GameRecordSchema = z.object({
|
||||
id: z.string(),
|
||||
id: z.string(), // WARNING: PII
|
||||
persistentID: z.string(), // WARNING: PII
|
||||
gameConfig: GameConfigSchema,
|
||||
players: z.array(PlayerRecordSchema),
|
||||
startTimestampMS: z.number(),
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerTy
|
||||
import { PseudoRandom } from "../PseudoRandom";
|
||||
import { manhattanDist } from "../Util";
|
||||
import { MessageType } from "../../client/graphics/layers/EventsDisplay";
|
||||
import { renderNumber } from "../../client/graphics/Utils";
|
||||
import { renderNumber } from "../../client/Utils";
|
||||
|
||||
export class AttackExecution implements Execution {
|
||||
private breakAlliance = false
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MessageType } from "../../client/graphics/layers/EventsDisplay";
|
||||
import { renderNumber } from "../../client/graphics/Utils";
|
||||
import { renderNumber } from "../../client/Utils";
|
||||
import { AllPlayers, Cell, Execution, MutableGame, MutablePlayer, MutableUnit, Player, PlayerID, Tile, Unit, UnitType } from "../game/Game";
|
||||
import { PathFinder } from "../pathfinding/PathFinding";
|
||||
import { PathFindResultType } from "../pathfinding/AStar";
|
||||
|
||||
@@ -5,7 +5,7 @@ import { CellString, GameImpl } from "./GameImpl";
|
||||
import { UnitImpl } from "./UnitImpl";
|
||||
import { TileImpl } from "./TileImpl";
|
||||
import { MessageType } from "../../client/graphics/layers/EventsDisplay";
|
||||
import { renderTroops } from "../../client/graphics/Utils";
|
||||
import { renderTroops } from "../../client/Utils";
|
||||
|
||||
interface Target {
|
||||
tick: Tick
|
||||
|
||||
@@ -7,7 +7,8 @@ export class Client {
|
||||
public lastPing: number
|
||||
|
||||
constructor(
|
||||
public readonly id: ClientID,
|
||||
public readonly clientID: ClientID,
|
||||
public readonly persistentID: string,
|
||||
public readonly ip: string | null,
|
||||
public readonly ws: WebSocket,
|
||||
) { }
|
||||
|
||||
+11
-11
@@ -50,23 +50,23 @@ export class GameServer {
|
||||
}
|
||||
|
||||
public addClient(client: Client, lastTurn: number) {
|
||||
console.log(`${this.id}: adding client ${client.id}`)
|
||||
slog('client_joined_game', `client ${client.id} (re)joining game ${this.id}`, {
|
||||
clientID: client.id,
|
||||
console.log(`${this.id}: adding client ${client.clientID}`)
|
||||
slog('client_joined_game', `client ${client.clientID} (re)joining game ${this.id}`, {
|
||||
clientID: client.clientID,
|
||||
clientIP: client.ip,
|
||||
gameID: this.id,
|
||||
isRejoin: lastTurn > 0
|
||||
})
|
||||
// Remove stale client if this is a reconnect
|
||||
const existing = this.activeClients.find(c => c.id == client.id)
|
||||
const existing = this.activeClients.find(c => c.clientID == client.clientID)
|
||||
if (existing != null) {
|
||||
existing.ws.removeAllListeners('message')
|
||||
}
|
||||
this.activeClients = this.activeClients.filter(c => c.id != client.id)
|
||||
this.activeClients = this.activeClients.filter(c => c.clientID != client.clientID)
|
||||
this.activeClients.push(client)
|
||||
client.lastPing = Date.now()
|
||||
|
||||
this.allClients.set(client.id, client)
|
||||
this.allClients.set(client.clientID, client)
|
||||
|
||||
client.ws.on('message', (message: string) => {
|
||||
const clientMsg: ClientMessage = ClientMessageSchema.parse(JSON.parse(message))
|
||||
@@ -83,8 +83,8 @@ export class GameServer {
|
||||
}
|
||||
})
|
||||
client.ws.on('close', () => {
|
||||
console.log(`${this.id}: client ${client.id} disconnected`)
|
||||
this.activeClients = this.activeClients.filter(c => c.id != client.id)
|
||||
console.log(`${this.id}: client ${client.clientID} disconnected`)
|
||||
this.activeClients = this.activeClients.filter(c => c.clientID != client.clientID)
|
||||
})
|
||||
|
||||
// In case a client joined the game late and missed the start message.
|
||||
@@ -112,7 +112,7 @@ export class GameServer {
|
||||
|
||||
this.endTurnIntervalID = setInterval(() => this.endTurn(), this.config.turnIntervalMs());
|
||||
this.activeClients.forEach(c => {
|
||||
console.log(`${this.id}: sending start message to ${c.id}`)
|
||||
console.log(`${this.id}: sending start message to ${c.clientID}`)
|
||||
this.sendStartGameMsg(c.ws, 0)
|
||||
})
|
||||
}
|
||||
@@ -165,7 +165,7 @@ export class GameServer {
|
||||
if (this.allClients.size > 0) {
|
||||
const playerRecords: PlayerRecord[] = Array.from(this.allClients.values()).map(client => ({
|
||||
ip: client.ip,
|
||||
clientID: client.id,
|
||||
clientID: client.clientID,
|
||||
}));
|
||||
const record = CreateGameRecord(this.id, this.gameConfig, playerRecords, this.turns, this._startTime, Date.now())
|
||||
archive(record)
|
||||
@@ -202,7 +202,7 @@ export class GameServer {
|
||||
const alive = []
|
||||
for (const client of this.activeClients) {
|
||||
if (now - client.lastPing > 60_000) {
|
||||
console.log(`${this.id}: no pings from ${client.id}, terminating connection`)
|
||||
console.log(`${this.id}: no pings from ${client.clientID}, terminating connection`)
|
||||
if (client.ws.readyState === WebSocket.OPEN) {
|
||||
client.ws.close(1000, "no heartbeats received, closing connection");
|
||||
}
|
||||
|
||||
+10
-1
@@ -110,7 +110,16 @@ wss.on('connection', (ws, req) => {
|
||||
? forwarded[0] // Get the first IP if it's an array
|
||||
: forwarded || req.socket.remoteAddress;
|
||||
|
||||
gm.addClient(new Client(clientMsg.clientID, ip, ws), clientMsg.gameID, clientMsg.lastTurn)
|
||||
gm.addClient(
|
||||
new Client(
|
||||
clientMsg.clientID,
|
||||
clientMsg.persistentID,
|
||||
ip,
|
||||
ws
|
||||
),
|
||||
clientMsg.gameID,
|
||||
clientMsg.lastTurn
|
||||
)
|
||||
}
|
||||
// TODO: send error message
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user