mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 13:30:43 +00:00
Implement vote for winner (#2013)
## Description: Require majority of ips to report a winner. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: evan
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
import WebSocket from "ws";
|
||||
import { TokenPayload } from "../core/ApiSchemas";
|
||||
import { Tick } from "../core/game/Game";
|
||||
import { ClientID } from "../core/Schemas";
|
||||
import { ClientID, Winner } from "../core/Schemas";
|
||||
|
||||
export class Client {
|
||||
public lastPing: number = Date.now();
|
||||
|
||||
public hashes: Map<Tick, number> = new Map();
|
||||
|
||||
public reportedWinner: Winner | null = null;
|
||||
|
||||
constructor(
|
||||
public readonly clientID: ClientID,
|
||||
public readonly persistentID: string,
|
||||
|
||||
@@ -64,6 +64,11 @@ export class GameServer {
|
||||
|
||||
private websockets: Set<WebSocket> = new Set();
|
||||
|
||||
private winnerVotes: Map<
|
||||
string,
|
||||
{ winner: ClientSendWinnerMessage; ips: Set<string> }
|
||||
> = new Map();
|
||||
|
||||
constructor(
|
||||
public readonly id: string,
|
||||
readonly log_: Logger,
|
||||
@@ -184,6 +189,7 @@ export class GameServer {
|
||||
}
|
||||
|
||||
client.lastPing = existing.lastPing;
|
||||
client.reportedWinner = existing.reportedWinner;
|
||||
|
||||
this.activeClients = this.activeClients.filter((c) => c !== existing);
|
||||
}
|
||||
@@ -283,15 +289,7 @@ export class GameServer {
|
||||
break;
|
||||
}
|
||||
case "winner": {
|
||||
if (
|
||||
this.outOfSyncClients.has(client.clientID) ||
|
||||
this.kickedClients.has(client.clientID) ||
|
||||
this.winner !== null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.winner = clientMsg;
|
||||
this.archiveGame();
|
||||
this.handleWinner(client, clientMsg);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -793,4 +791,48 @@ export class GameServer {
|
||||
outOfSyncClients,
|
||||
};
|
||||
}
|
||||
|
||||
private handleWinner(client: Client, clientMsg: ClientSendWinnerMessage) {
|
||||
if (
|
||||
this.outOfSyncClients.has(client.clientID) ||
|
||||
this.kickedClients.has(client.clientID) ||
|
||||
this.winner !== null ||
|
||||
client.reportedWinner !== null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
client.reportedWinner = clientMsg.winner;
|
||||
|
||||
// Add client vote
|
||||
const winnerKey = JSON.stringify(clientMsg.winner);
|
||||
if (!this.winnerVotes.has(winnerKey)) {
|
||||
this.winnerVotes.set(winnerKey, { ips: new Set(), winner: clientMsg });
|
||||
}
|
||||
const potentialWinner = this.winnerVotes.get(winnerKey)!;
|
||||
potentialWinner.ips.add(client.ip);
|
||||
|
||||
const activeUniqueIPs = new Set(this.activeClients.map((c) => c.ip));
|
||||
|
||||
const ratio = `${potentialWinner.ips.size}/${activeUniqueIPs.size}`;
|
||||
this.log.info(
|
||||
`recieved winner vote ${clientMsg.winner}, ${ratio} votes for this winner`,
|
||||
{
|
||||
clientID: client.clientID,
|
||||
},
|
||||
);
|
||||
|
||||
if (potentialWinner.ips.size * 2 < activeUniqueIPs.size) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Vote succeeded
|
||||
this.winner = potentialWinner.winner;
|
||||
this.log.info(
|
||||
`Winner determined by ${potentialWinner.ips.size}/${activeUniqueIPs.size} active IPs`,
|
||||
{
|
||||
winnerKey: winnerKey,
|
||||
},
|
||||
);
|
||||
this.archiveGame();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user