mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 18:56:45 +00:00
send game hash to server each second
This commit is contained in:
@@ -6,11 +6,16 @@ import { ClientID, GameConfig, GameID, ServerMessage } from "../core/Schemas";
|
||||
import { loadTerrainMap } from "../core/game/TerrainMapLoader";
|
||||
import {
|
||||
SendAttackIntentEvent,
|
||||
SendHashEvent,
|
||||
SendSpawnIntentEvent,
|
||||
Transport,
|
||||
} from "./Transport";
|
||||
import { createCanvas } from "./Utils";
|
||||
import { ErrorUpdate } from "../core/game/GameUpdates";
|
||||
import {
|
||||
ErrorUpdate,
|
||||
GameUpdateType,
|
||||
HashUpdate,
|
||||
} from "../core/game/GameUpdates";
|
||||
import { WorkerClient } from "../core/worker/WorkerClient";
|
||||
import { consolex, initRemoteSender } from "../core/Consolex";
|
||||
import { getConfig, getServerConfig } from "../core/configuration/Config";
|
||||
@@ -171,6 +176,9 @@ export class ClientGameRunner {
|
||||
showErrorModal(gu.errMsg, gu.stack, this.clientID);
|
||||
return;
|
||||
}
|
||||
gu.updates[GameUpdateType.Hash].forEach((hu: HashUpdate) => {
|
||||
this.eventBus.emit(new SendHashEvent(hu.tick, hu.hash));
|
||||
});
|
||||
this.gameView.update(gu);
|
||||
this.renderer.tick();
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
Player,
|
||||
PlayerID,
|
||||
PlayerType,
|
||||
Tick,
|
||||
UnitType,
|
||||
} from "../core/game/Game";
|
||||
import {
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
GameConfig,
|
||||
ClientLogMessageSchema,
|
||||
ClientSendWinnerSchema,
|
||||
ClientMessageSchema,
|
||||
} from "../core/Schemas";
|
||||
import { LobbyConfig } from "./ClientGameRunner";
|
||||
import { LocalServer } from "./LocalServer";
|
||||
@@ -107,6 +109,12 @@ export class SendSetTargetTroopRatioEvent implements GameEvent {
|
||||
export class SendWinnerEvent implements GameEvent {
|
||||
constructor(public readonly winner: ClientID) {}
|
||||
}
|
||||
export class SendHashEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly tick: Tick,
|
||||
public readonly hash: number,
|
||||
) {}
|
||||
}
|
||||
|
||||
export class Transport {
|
||||
private socket: WebSocket;
|
||||
@@ -159,6 +167,7 @@ export class Transport {
|
||||
this.eventBus.on(SendLogEvent, (e) => this.onSendLogEvent(e));
|
||||
this.eventBus.on(PauseGameEvent, (e) => this.onPauseGameEvent(e));
|
||||
this.eventBus.on(SendWinnerEvent, (e) => this.onSendWinnerEvent(e));
|
||||
this.eventBus.on(SendHashEvent, (e) => this.onSendHashEvent(e));
|
||||
}
|
||||
|
||||
private startPing() {
|
||||
@@ -448,6 +457,26 @@ export class Transport {
|
||||
}
|
||||
}
|
||||
|
||||
private onSendHashEvent(event: SendHashEvent) {
|
||||
if (this.isLocal || this.socket.readyState === WebSocket.OPEN) {
|
||||
const msg = ClientMessageSchema.parse({
|
||||
type: "hash",
|
||||
clientID: this.lobbyConfig.clientID,
|
||||
persistentID: this.lobbyConfig.persistentID,
|
||||
gameID: this.lobbyConfig.gameID,
|
||||
tick: event.tick,
|
||||
hash: event.hash,
|
||||
});
|
||||
this.sendMsg(JSON.stringify(msg));
|
||||
} else {
|
||||
console.log(
|
||||
"WebSocket is not open. Current state:",
|
||||
this.socket.readyState,
|
||||
);
|
||||
console.log("attempting reconnect");
|
||||
}
|
||||
}
|
||||
|
||||
private sendIntent(intent: Intent) {
|
||||
if (this.isLocal || this.socket.readyState === WebSocket.OPEN) {
|
||||
const msg = ClientIntentMessageSchema.parse({
|
||||
|
||||
@@ -63,7 +63,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
],
|
||||
[GameUpdateType.BrokeAlliance, (u) => this.onBrokeAllianceEvent(u)],
|
||||
[GameUpdateType.TargetPlayer, (u) => this.onTargetPlayerEvent(u)],
|
||||
[GameUpdateType.EmojiUpdate, (u) => this.onEmojiMessageEvent(u)],
|
||||
[GameUpdateType.Emoji, (u) => this.onEmojiMessageEvent(u)],
|
||||
]);
|
||||
|
||||
constructor() {
|
||||
|
||||
@@ -107,7 +107,7 @@ export class OptionsMenu extends LitElement implements Layer {
|
||||
tick() {
|
||||
this.hasWinner =
|
||||
this.hasWinner ||
|
||||
this.game.updatesSinceLastTick()[GameUpdateType.WinUpdate].length > 0;
|
||||
this.game.updatesSinceLastTick()[GameUpdateType.Win].length > 0;
|
||||
if (this.game.inSpawnPhase()) {
|
||||
this.timer = 0;
|
||||
} else if (!this.hasWinner && this.game.ticks() % 10 == 0) {
|
||||
|
||||
@@ -208,7 +208,7 @@ export class WinModal extends LitElement implements Layer {
|
||||
}
|
||||
this.show();
|
||||
}
|
||||
this.game.updatesSinceLastTick()[GameUpdateType.WinUpdate].forEach((wu) => {
|
||||
this.game.updatesSinceLastTick()[GameUpdateType.Win].forEach((wu) => {
|
||||
const winner = this.game.playerBySmallID(wu.winnerID) as PlayerView;
|
||||
this.eventBus.emit(new SendWinnerEvent(winner.clientID()));
|
||||
if (winner == this.game.myPlayer()) {
|
||||
|
||||
+11
-2
@@ -48,7 +48,8 @@ export type ClientMessage =
|
||||
| ClientPingMessage
|
||||
| ClientIntentMessage
|
||||
| ClientJoinMessage
|
||||
| ClientLogMessage;
|
||||
| ClientLogMessage
|
||||
| ClientHashMessage;
|
||||
export type ServerMessage =
|
||||
| ServerSyncMessage
|
||||
| ServerStartGameMessage
|
||||
@@ -65,6 +66,7 @@ export type ClientPingMessage = z.infer<typeof ClientPingMessageSchema>;
|
||||
export type ClientIntentMessage = z.infer<typeof ClientIntentMessageSchema>;
|
||||
export type ClientJoinMessage = z.infer<typeof ClientJoinMessageSchema>;
|
||||
export type ClientLogMessage = z.infer<typeof ClientLogMessageSchema>;
|
||||
export type ClientHashMessage = z.infer<typeof ClientHashSchema>;
|
||||
|
||||
export type PlayerRecord = z.infer<typeof PlayerRecordSchema>;
|
||||
export type GameRecord = z.infer<typeof GameRecordSchema>;
|
||||
@@ -268,7 +270,7 @@ export const ServerMessageSchema = z.union([
|
||||
// Client
|
||||
|
||||
const ClientBaseMessageSchema = z.object({
|
||||
type: z.enum(["winner", "join", "intent", "ping", "log"]),
|
||||
type: z.enum(["winner", "join", "intent", "ping", "log", "hash"]),
|
||||
clientID: ID,
|
||||
persistentID: SafeString.nullable(), // WARNING: persistent id is private.
|
||||
gameID: ID,
|
||||
@@ -279,6 +281,12 @@ export const ClientSendWinnerSchema = ClientBaseMessageSchema.extend({
|
||||
winner: ID.nullable(),
|
||||
});
|
||||
|
||||
export const ClientHashSchema = ClientBaseMessageSchema.extend({
|
||||
type: z.literal("hash"),
|
||||
hash: z.number(),
|
||||
tick: z.number(),
|
||||
});
|
||||
|
||||
export const ClientLogMessageSchema = ClientBaseMessageSchema.extend({
|
||||
type: z.literal("log"),
|
||||
severity: z.nativeEnum(LogSeverity),
|
||||
@@ -308,6 +316,7 @@ export const ClientMessageSchema = z.union([
|
||||
ClientIntentMessageSchema,
|
||||
ClientJoinMessageSchema,
|
||||
ClientLogMessageSchema,
|
||||
ClientHashSchema,
|
||||
]);
|
||||
|
||||
export const PlayerRecordSchema = z.object({
|
||||
|
||||
+18
-10
@@ -241,21 +241,29 @@ export class GameImpl implements Game {
|
||||
|
||||
this.execs.push(...inited);
|
||||
this.unInitExecs = unInited;
|
||||
this._ticks++;
|
||||
if (this._ticks % 100 == 0) {
|
||||
let hash = 1;
|
||||
this._players.forEach((p) => {
|
||||
hash += p.hash();
|
||||
});
|
||||
consolex.log(`tick ${this._ticks}: hash ${hash}`);
|
||||
}
|
||||
for (const player of this._players.values()) {
|
||||
// Players change each to so always add them
|
||||
this.addUpdate(player.toUpdate());
|
||||
}
|
||||
if (this.ticks() % 10 == 0) {
|
||||
this.addUpdate({
|
||||
type: GameUpdateType.Hash,
|
||||
tick: this.ticks(),
|
||||
hash: this.hash(),
|
||||
});
|
||||
}
|
||||
this._ticks++;
|
||||
return this.updates;
|
||||
}
|
||||
|
||||
private hash(): number {
|
||||
let hash = 1;
|
||||
this._players.forEach((p) => {
|
||||
hash += p.hash();
|
||||
});
|
||||
return hash;
|
||||
}
|
||||
|
||||
terraNullius(): TerraNullius {
|
||||
return this._terraNullius;
|
||||
}
|
||||
@@ -494,14 +502,14 @@ export class GameImpl implements Game {
|
||||
|
||||
sendEmojiUpdate(msg: EmojiMessage): void {
|
||||
this.addUpdate({
|
||||
type: GameUpdateType.EmojiUpdate,
|
||||
type: GameUpdateType.Emoji,
|
||||
emoji: msg,
|
||||
});
|
||||
}
|
||||
|
||||
setWinner(winner: Player): void {
|
||||
this.addUpdate({
|
||||
type: GameUpdateType.WinUpdate,
|
||||
type: GameUpdateType.Win,
|
||||
winnerID: winner.smallID(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -35,8 +35,9 @@ export enum GameUpdateType {
|
||||
BrokeAlliance,
|
||||
AllianceExpired,
|
||||
TargetPlayer,
|
||||
EmojiUpdate,
|
||||
WinUpdate,
|
||||
Emoji,
|
||||
Win,
|
||||
Hash,
|
||||
}
|
||||
|
||||
export type GameUpdate =
|
||||
@@ -50,7 +51,8 @@ export type GameUpdate =
|
||||
| DisplayMessageUpdate
|
||||
| TargetPlayerUpdate
|
||||
| EmojiUpdate
|
||||
| WinUpdate;
|
||||
| WinUpdate
|
||||
| HashUpdate;
|
||||
|
||||
export interface TileUpdateWrapper {
|
||||
type: GameUpdateType.Tile;
|
||||
@@ -135,7 +137,7 @@ export interface TargetPlayerUpdate {
|
||||
}
|
||||
|
||||
export interface EmojiUpdate {
|
||||
type: GameUpdateType.EmojiUpdate;
|
||||
type: GameUpdateType.Emoji;
|
||||
emoji: EmojiMessage;
|
||||
}
|
||||
|
||||
@@ -147,6 +149,12 @@ export interface DisplayMessageUpdate {
|
||||
}
|
||||
|
||||
export interface WinUpdate {
|
||||
type: GameUpdateType.WinUpdate;
|
||||
type: GameUpdateType.Win;
|
||||
winnerID: number;
|
||||
}
|
||||
|
||||
export interface HashUpdate {
|
||||
type: GameUpdateType.Hash;
|
||||
tick: Tick;
|
||||
hash: number;
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ export class UnitImpl implements Unit {
|
||||
}
|
||||
|
||||
hash(): number {
|
||||
return this.tile() + simpleHash(this.type());
|
||||
return this.tile() + simpleHash(this.type()) * this._id;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import WebSocket from "ws";
|
||||
import { ClientID } from "../core/Schemas";
|
||||
import { Tick } from "../core/game/Game";
|
||||
|
||||
export class Client {
|
||||
public lastPing: number;
|
||||
|
||||
public hashes: Map<Tick, number> = new Map();
|
||||
|
||||
constructor(
|
||||
public readonly clientID: ClientID,
|
||||
public readonly persistentID: string,
|
||||
|
||||
@@ -3,11 +3,8 @@ import {
|
||||
ClientMessage,
|
||||
ClientMessageSchema,
|
||||
GameConfig,
|
||||
GameRecordSchema,
|
||||
Intent,
|
||||
PlayerRecord,
|
||||
ServerPingMessageSchema,
|
||||
ServerStartGameMessage,
|
||||
ServerStartGameMessageSchema,
|
||||
ServerTurnMessageSchema,
|
||||
Turn,
|
||||
@@ -162,6 +159,12 @@ export class GameServer {
|
||||
this.lastPingUpdate = Date.now();
|
||||
client.lastPing = Date.now();
|
||||
}
|
||||
if (clientMsg.type == "hash") {
|
||||
console.log(
|
||||
`client ${clientMsg.clientID} got hash ${clientMsg.hash} on tick ${clientMsg.tick}`,
|
||||
);
|
||||
client.hashes.set(clientMsg.tick, clientMsg.hash);
|
||||
}
|
||||
if (clientMsg.type == "winner") {
|
||||
this.winner = clientMsg.winner;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user