diff options
author | Elizabeth Hunt <elizabeth.hunt@simponic.xyz> | 2023-08-25 18:10:09 -0600 |
---|---|---|
committer | Elizabeth Hunt <elizabeth.hunt@simponic.xyz> | 2023-08-25 18:10:09 -0600 |
commit | 2fbe0f0595d06800c1a648a4168b57471d395ee4 (patch) | |
tree | 830342a963be8e560cf07cfca8b8346bdcb51d90 /server/src/server.ts | |
parent | 773ce84f4bf559337e132edd7fcce02a0a2598fd (diff) | |
download | jumpstorm-2fbe0f0595d06800c1a648a4168b57471d395ee4.tar.gz jumpstorm-2fbe0f0595d06800c1a648a4168b57471d395ee4.zip |
refactor server structure
Diffstat (limited to 'server/src/server.ts')
-rw-r--r-- | server/src/server.ts | 228 |
1 files changed, 90 insertions, 138 deletions
diff --git a/server/src/server.ts b/server/src/server.ts index c77bfef..6acbe74 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -1,110 +1,124 @@ import { Game } from '@engine/Game'; import { EntityNames, Player } from '@engine/entities'; -import { WallBounds, Physics, Collision, NetworkUpdate } from '@engine/systems'; +import { MessageType } from '@engine/network'; +import { Constants } from './constants'; import { - type MessageQueueProvider, - type MessagePublisher, - MessageType, - type MessageProcessor, - type Message -} from '@engine/network'; -import { stringify, parse } from '@engine/utils'; -import { Grid } from '@engine/structures'; -import { Miscellaneous } from '@engine/config'; -import { Server } from 'bun'; - -const SERVER_PORT = 8080; -const SERVER_TICK_RATE = (1 / 60) * 1000; -const GAME_TOPIC = 'game'; -const MAX_PLAYERS = 8; - -type SessionData = { sessionId: string }; - -interface ServerMessage extends Message { - sessionData: SessionData; -} - -class ServerSocketMessageReceiver implements MessageQueueProvider { - private messages: ServerMessage[]; + ServerSocketMessageReceiver, + ServerSocketMessagePublisher, + SessionData, + ServerMessage, + Session +} from './network'; +import { parse } from '@engine/utils'; +import { Server, ServerWebSocket } from 'bun'; + +export class GameServer { + private sessions: Map<string, Session>; - constructor() { - this.messages = []; + private server?: Server; + private game: Game; + private messageReceiver: ServerSocketMessageReceiver; + private messagePublisher: ServerSocketMessagePublisher; + + constructor( + game: Game, + messageReceiver: ServerSocketMessageReceiver, + messagePublisher: ServerSocketMessagePublisher + ) { + this.sessions = new Map(); + + this.game = game; + this.messageReceiver = messageReceiver; + this.messagePublisher = messagePublisher; } - public addMessage(message: ServerMessage) { - this.messages.push(message); - } + public serve() { + if (!this.server) + this.server = Bun.serve<SessionData>({ + port: Constants.SERVER_PORT, + fetch: (req, srv) => this.fetchHandler(req, srv), + websocket: { + open: (ws) => this.openWebsocket(ws), + message: (ws, msg) => this.websocketMessage(ws, msg), + close: (ws) => this.closeWebsocket(ws) + } + }); - public getNewMessages() { - return this.messages; - } + this.messagePublisher.setServer(this.server); - public clearMessages() { - this.messages = []; + console.log(`Listening on ${this.server.hostname}:${this.server.port}`); } -} - -class ServerMessageProcessor implements MessageProcessor { - constructor() {} - public process(_message: ServerMessage) {} -} - -class ServerSocketMessagePublisher implements MessagePublisher { - private server?: Server; - private messages: Message[]; + private websocketMessage( + websocket: ServerWebSocket<SessionData>, + message: string | Uint8Array + ) { + if (typeof message == 'string') { + const receivedMessage = parse<ServerMessage>(message); + receivedMessage.sessionData = websocket.data; - constructor(server?: Server) { - if (server) { - this.server = server; + this.messageReceiver.addMessage(receivedMessage); } - - this.messages = []; } - public setServer(server: Server) { - this.server = server; - } + private closeWebsocket(websocket: ServerWebSocket<SessionData>) { + const { sessionId } = websocket.data; - public addMessage(message: Message) { - this.messages.push(message); - } + const sessionEntities = this.sessions.get(sessionId)!.controllableEntities; - public publish() { - if (this.messages.length) { - this.server?.publish(GAME_TOPIC, stringify(this.messages)); + this.sessions.delete(sessionId); - this.messages = []; - } + if (!sessionEntities) return; + this.messagePublisher.addMessage({ + type: MessageType.REMOVE_ENTITIES, + body: Array.from(sessionEntities) + }); } -} -const game = new Game(); + private openWebsocket(websocket: ServerWebSocket<SessionData>) { + websocket.subscribe(Constants.GAME_TOPIC); -const messageReceiver = new ServerSocketMessageReceiver(); -const messagePublisher = new ServerSocketMessagePublisher(); -const messageProcessor = new ServerMessageProcessor(); -const sessionControllableEntities: Map<string, Set<string>> = new Map(); + const { sessionId } = websocket.data; + if (this.sessions.has(sessionId)) { + return; + } -const sessions = new Set<string>(); + this.sessions.set(sessionId, { + sessionId, + controllableEntities: new Set() + }); + + const player = new Player(sessionId); + this.game.addEntity(player); + this.messagePublisher.addMessage({ + type: MessageType.NEW_ENTITIES, + body: [ + { + entityName: EntityNames.Player, + args: { playerId: sessionId, id: player.id } + } + ] + }); + + this.sessions.get(sessionId)!.controllableEntities.add(player.id); + } -const server = Bun.serve<SessionData>({ - port: SERVER_PORT, - fetch: async (req, server): Promise<Response> => { + private fetchHandler( + req: Request, + server: Server + ): Promise<Response> | Response { const url = new URL(req.url); const headers = new Headers(); headers.set('Access-Control-Allow-Origin', '*'); if (url.pathname == '/assign') { - if (sessions.size > MAX_PLAYERS) + if (this.sessions.size > Constants.MAX_PLAYERS) return new Response('too many players', { headers, status: 400 }); const sessionId = crypto.randomUUID(); headers.set('Set-Cookie', `SessionId=${sessionId};`); - sessions.add(sessionId); - return new Response(sessionId, { headers }); } @@ -127,7 +141,7 @@ const server = Bun.serve<SessionData>({ } }); - return new Response('upgraded', { headers }); + return new Response('upgraded to ws', { headers }); } if (url.pathname == '/me') { @@ -135,67 +149,5 @@ const server = Bun.serve<SessionData>({ } return new Response('Not found', { headers, status: 404 }); - }, - websocket: { - open(ws) { - const { sessionId } = ws.data; - - if (sessionControllableEntities.has(sessionId)) { - return; - } - - const player = new Player(sessionId); - game.addEntity(player); - sessionControllableEntities.set(sessionId, new Set([player.id])); - - messagePublisher.addMessage({ - type: MessageType.NEW_ENTITIES, - body: [ - { - entityName: EntityNames.Player, - args: { playerId: sessionId, id: player.id } - } - ] - }); - - ws.subscribe(GAME_TOPIC); - }, - message(ws, message) { - if (typeof message == 'string') { - const receivedMessage = parse<ServerMessage>(message); - receivedMessage.sessionData = ws.data; - - messageReceiver.addMessage(receivedMessage); - } - }, - close(ws) { - const { sessionId } = ws.data; - - sessions.delete(sessionId); - - const sessionEntities = sessionControllableEntities.get(sessionId); - if (!sessionEntities) return; - - messagePublisher.addMessage({ - type: MessageType.REMOVE_ENTITIES, - body: Array.from(sessionEntities) - }); - } } -}); - -messagePublisher.setServer(server); - -[ - new Physics(), - new Collision(new Grid()), - new WallBounds(), - new NetworkUpdate(messageReceiver, messagePublisher, messageProcessor) -].forEach((system) => game.addSystem(system)); - -game.start(); -setInterval(() => { - game.doGameLoop(performance.now()); -}, SERVER_TICK_RATE); - -console.log(`Listening on ${server.hostname}:${server.port}`); +} |