diff options
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/server.ts | 104 |
1 files changed, 63 insertions, 41 deletions
diff --git a/server/src/server.ts b/server/src/server.ts index b3eb1ea..c77bfef 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -1,21 +1,22 @@ -import { Game } from "@engine/Game"; -import { EntityNames, Player } from "@engine/entities"; -import { WallBounds, Physics, Collision, NetworkUpdate } from "@engine/systems"; +import { Game } from '@engine/Game'; +import { EntityNames, Player } from '@engine/entities'; +import { WallBounds, Physics, Collision, NetworkUpdate } from '@engine/systems'; 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"; + 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 / 100) * 1000; -const GAME_TOPIC = "game"; +const SERVER_TICK_RATE = (1 / 60) * 1000; +const GAME_TOPIC = 'game'; +const MAX_PLAYERS = 8; type SessionData = { sessionId: string }; @@ -70,11 +71,11 @@ class ServerSocketMessagePublisher implements MessagePublisher { } public publish() { - this.messages.forEach( - (message) => this.server?.publish(GAME_TOPIC, stringify(message)), - ); + if (this.messages.length) { + this.server?.publish(GAME_TOPIC, stringify(this.messages)); - this.messages = []; + this.messages = []; + } } } @@ -85,81 +86,102 @@ const messagePublisher = new ServerSocketMessagePublisher(); const messageProcessor = new ServerMessageProcessor(); const sessionControllableEntities: Map<string, Set<string>> = new Map(); +const sessions = new Set<string>(); + const server = Bun.serve<SessionData>({ port: SERVER_PORT, fetch: async (req, server): Promise<Response> => { const url = new URL(req.url); const headers = new Headers(); - headers.set("Access-Control-Allow-Origin", "*"); + headers.set('Access-Control-Allow-Origin', '*'); + + if (url.pathname == '/assign') { + if (sessions.size > MAX_PLAYERS) + return new Response('too many players', { headers, status: 400 }); - if (url.pathname == "/assign") { const sessionId = crypto.randomUUID(); - headers.set("Set-Cookie", `SessionId=${sessionId};`); + headers.set('Set-Cookie', `SessionId=${sessionId};`); + + sessions.add(sessionId); return new Response(sessionId, { headers }); } - const cookie = req.headers.get("cookie"); + const cookie = req.headers.get('cookie'); if (!cookie) { - return new Response("No session", { headers, status: 401 }); + return new Response('No session', { headers, status: 401 }); } - const sessionId = cookie.split(";").at(0)!.split("SessionId=").at(1); + const sessionId = cookie.split(';').at(0)!.split('SessionId=').at(1); - if (url.pathname == "/game") { + if (url.pathname == '/game') { headers.set( - "Set-Cookie", - `SessionId=${sessionId}; HttpOnly; SameSite=Strict;`, + 'Set-Cookie', + `SessionId=${sessionId}; HttpOnly; SameSite=Strict;` ); server.upgrade(req, { headers, data: { - sessionId, - }, + sessionId + } }); - return new Response("upgraded", { headers }); + return new Response('upgraded', { headers }); } - if (url.pathname == "/me") { + + if (url.pathname == '/me') { return new Response(sessionId, { headers }); } - return new Response("Not found", { headers, status: 404 }); + return new Response('Not found', { headers, status: 404 }); }, websocket: { open(ws) { const { sessionId } = ws.data; if (sessionControllableEntities.has(sessionId)) { - // no need to add player return; } const player = new Player(sessionId); game.addEntity(player); - sessionControllableEntities.set(sessionId, new Set(player.id)); + sessionControllableEntities.set(sessionId, new Set([player.id])); messagePublisher.addMessage({ - type: MessageType.NEW_ENTITY, - body: { - entityName: EntityNames.Player, - args: { playerId: sessionId }, - }, + 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") { + if (typeof message == 'string') { const receivedMessage = parse<ServerMessage>(message); receivedMessage.sessionData = ws.data; messageReceiver.addMessage(receivedMessage); } }, - close(_ws) {}, - }, + 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); @@ -167,8 +189,8 @@ messagePublisher.setServer(server); [ new Physics(), new Collision(new Grid()), - new WallBounds(Miscellaneous.WIDTH), - new NetworkUpdate(messageReceiver, messagePublisher, messageProcessor), + new WallBounds(), + new NetworkUpdate(messageReceiver, messagePublisher, messageProcessor) ].forEach((system) => game.addSystem(system)); game.start(); |