From 117027779f4adac34ac1e5302e055628b00dd72d Mon Sep 17 00:00:00 2001 From: evanpelle Date: Sat, 12 Oct 2024 13:50:11 -0700 Subject: [PATCH] single player start --- src/client/Client.ts | 1 + src/client/ClientGame.ts | 14 ++++++- src/client/Transport.ts | 8 ++-- src/core/GameSocket.ts | 80 +++++++++++++++++++++++++++++++++++++++ src/core/LocalServer.ts | 21 ++++++++++ src/server/GameManager.ts | 4 +- src/server/Lobby.ts | 21 ---------- src/server/Server.ts | 4 +- 8 files changed, 122 insertions(+), 31 deletions(-) create mode 100644 src/core/GameSocket.ts create mode 100644 src/core/LocalServer.ts delete mode 100644 src/server/Lobby.ts diff --git a/src/client/Client.ts b/src/client/Client.ts index e931bd712..0bc6e7c2c 100644 --- a/src/client/Client.ts +++ b/src/client/Client.ts @@ -67,6 +67,7 @@ class Client { ]); console.log(`got ip ${clientIP}`) this.game = createClientGame( + false, (): string => {return this.usernameInput.getCurrentUsername()}, uuidv4(), uuidv4(), diff --git a/src/client/ClientGame.ts b/src/client/ClientGame.ts index 00bda4717..fd1ea667a 100644 --- a/src/client/ClientGame.ts +++ b/src/client/ClientGame.ts @@ -13,19 +13,29 @@ import {WinCheckExecution} from "../core/execution/WinCheckExecution"; import {SendAttackIntentEvent, SendSpawnIntentEvent, Transport} from "./Transport"; import {createCanvas} from "./graphics/Utils"; import {DisplayMessageEvent, MessageType} from "./graphics/layers/EventsDisplay"; +import {LocalSocket, LocalSocketFactory, SocketFactory, WebsocketFactory as WebSocketFactory} from "../core/GameSocket"; +import {LocalServer} from "../core/LocalServer"; -export function createClientGame(playerName: () => string, clientID: ClientID, playerID: PlayerID, ip: string | null, gameID: GameID, config: Config, terrainMap: TerrainMap): ClientGame { +export function createClientGame(isLocal: boolean, playerName: () => 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) const canvas = createCanvas() let gameRenderer = createRenderer(canvas, game, eventBus, clientID) + let wsFactory: SocketFactory = null + if (isLocal) { + wsFactory = new LocalSocketFactory(new LocalServer(config)) + } else { + const wsHost = process.env.WEBSOCKET_URL || window.location.host; + const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; + wsFactory = new WebSocketFactory(`${wsProtocol}//${wsHost}`) + } - const transport = new Transport(null, eventBus, gameID, clientID, playerID, playerName) + const transport = new Transport(wsFactory, eventBus, gameID, clientID, playerID, playerName) return new ClientGame( diff --git a/src/client/Transport.ts b/src/client/Transport.ts index bd3d34dec..9af3260b7 100644 --- a/src/client/Transport.ts +++ b/src/client/Transport.ts @@ -1,6 +1,7 @@ import {EventBus, GameEvent} from "../core/EventBus" import {AllianceRequest, AllPlayers, Cell, Player, PlayerID, PlayerType} from "../core/game/Game" import {ClientID, ClientIntentMessageSchema, ClientJoinMessageSchema, ClientLeaveMessageSchema, GameID, Intent, ServerMessage, ServerMessageSchema} from "../core/Schemas" +import {SocketFactory} from "../core/GameSocket" export class SendAllianceRequestIntentEvent implements GameEvent { @@ -68,9 +69,10 @@ export class SendDonateIntentEvent implements GameEvent { export class Transport { public onconnect: () => {} + private socket: WebSocket constructor( - public socket: WebSocket, + private socketFactory: SocketFactory, private eventBus: EventBus, private gameID: GameID, private clientID: ClientID, @@ -89,9 +91,7 @@ export class Transport { } connect(onconnect: () => void, onmessage: (message: ServerMessage) => void, isActive: () => boolean) { - const wsHost = process.env.WEBSOCKET_URL || window.location.host; - const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; - this.socket = new WebSocket(`${wsProtocol}//${wsHost}`) + this.socket = this.socketFactory.createSocket() this.socket.onopen = () => { console.log('Connected to game server!'); onconnect() diff --git a/src/core/GameSocket.ts b/src/core/GameSocket.ts new file mode 100644 index 000000000..7f42fb3bd --- /dev/null +++ b/src/core/GameSocket.ts @@ -0,0 +1,80 @@ +import {LocalServer} from "./LocalServer"; + +export interface SocketFactory { + createSocket(): WebSocket; +} + +export interface Socket { + onopen: ((event: Event) => void) | null; + onmessage: ((event: MessageEvent) => void) | null; + onerror: ((event: Event) => void) | null; + onclose: ((event: CloseEvent) => void) | null; + readyState: number; + + connect(url: string): void; + send(data: string): void; + close(code?: number, reason?: string): void; +} + +export const WebSocketReadyState = { + CONNECTING: 0, + OPEN: 1, + CLOSING: 2, + CLOSED: 3 +}; + +export class WebsocketFactory implements SocketFactory { + + constructor(private url: string) { } + + createSocket(): WebSocket { + return new WebSocket(this.url) + } +} + +export class LocalSocketFactory implements SocketFactory { + constructor(private localServer: LocalServer) { } + + createSocket(): WebSocket { + return new LocalSocket(this.localServer) + } +} + +export class LocalSocket implements WebSocket { + + + constructor(private server: LocalServer) { + server.localSocket = this + } + + binaryType: BinaryType; + bufferedAmount: number; + extensions: string; + onclose: (this: WebSocket, ev: CloseEvent) => any; + onerror: (this: WebSocket, ev: Event) => any; + onmessage: (this: WebSocket, ev: MessageEvent) => any; + onopen: (this: WebSocket, ev: Event) => any; + protocol: string; + readyState: number; + url: string; + close(code?: number, reason?: string): void { + // this.server.onclose(new GameCloseEvent()) + } + send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void { + this.server.onMessage(data as string) + } + CONNECTING: 0; + OPEN: 1; + CLOSING: 2; + CLOSED: 3; + addEventListener(type: unknown, listener: unknown, options?: unknown): void { + throw new Error("Method not implemented."); + } + removeEventListener(type: unknown, listener: unknown, options?: unknown): void { + throw new Error("Method not implemented."); + } + dispatchEvent(event: Event): boolean { + throw new Error("Method not implemented."); + } + +} \ No newline at end of file diff --git a/src/core/LocalServer.ts b/src/core/LocalServer.ts new file mode 100644 index 000000000..ba210cc55 --- /dev/null +++ b/src/core/LocalServer.ts @@ -0,0 +1,21 @@ +import {Config} from "./configuration/Config"; +import {LocalSocket} from "./GameSocket"; +import {ClientMessage, ClientMessageSchema} from "./Schemas"; + +export class LocalServer { + + public localSocket: LocalSocket + + constructor(private config: Config) { + } + + onConnect() { + + } + + onMessage(message: string) { + const clientMsg: ClientMessage = ClientMessageSchema.parse(JSON.parse(message)) + if (clientMsg.type == "intent") { + } + } +} \ No newline at end of file diff --git a/src/server/GameManager.ts b/src/server/GameManager.ts index 53d67442c..b9fee3eb4 100644 --- a/src/server/GameManager.ts +++ b/src/server/GameManager.ts @@ -1,10 +1,10 @@ -import {GamePhase, GameServer} from "./GameServer"; import {Config} from "../core/configuration/Config"; import {PseudoRandom} from "../core/PseudoRandom"; import WebSocket from 'ws'; import {ClientID, GameID} from "../core/Schemas"; -import {Client} from "./Client"; import {v4 as uuidv4} from 'uuid'; +import {Client} from "./Client"; +import {GamePhase, GameServer} from "./GameServer"; diff --git a/src/server/Lobby.ts b/src/server/Lobby.ts deleted file mode 100644 index cf0256e59..000000000 --- a/src/server/Lobby.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {ClientID} from "../core/Schemas"; -import {Client} from "./Client"; - -export class Lobby { - - public clients: Map = new Map() - private startGameTs: number - - - constructor(public readonly id: string, durationMs: number) { - this.startGameTs = Date.now() + durationMs - } - - public addClient(client: Client) { - this.clients.set(client.id, client) - } - - public isExpired(now: number): boolean { - return now > this.startGameTs - } -} \ No newline at end of file diff --git a/src/server/Server.ts b/src/server/Server.ts index 0932d34b4..8a6267d7d 100644 --- a/src/server/Server.ts +++ b/src/server/Server.ts @@ -4,11 +4,11 @@ import {WebSocketServer} from 'ws'; import path from 'path'; import {fileURLToPath} from 'url'; import {GameManager} from './GameManager'; -import {Client} from './Client'; import {ClientMessage, ClientMessageSchema} from '../core/Schemas'; -import {GamePhase} from './GameServer'; import {getConfig} from '../core/configuration/Config'; import {LogSeverity, slog} from './StructuredLog'; +import {Client} from './Client'; +import {GamePhase} from './GameServer'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename);