diff --git a/client/src/JumpStorm.ts b/client/src/JumpStorm.ts index e094a6f..ae99b8e 100644 --- a/client/src/JumpStorm.ts +++ b/client/src/JumpStorm.ts @@ -1,7 +1,5 @@ -import { Floor, Player } from "@engine/entities"; import { Game } from "@engine/Game"; import { Grid } from "@engine/structures"; -import { Miscellaneous } from "@engine/config"; import { WallBounds, FacingDirection, @@ -61,16 +59,14 @@ export class JumpStorm { this.game = new Game(); const socket = new WebSocket("ws://localhost:8080"); + setInterval(() => socket.send(JSON.stringify({ x: 1 })), 1_000); const clientSocketMessageQueueProvider = new ClientSocketMessageQueueProvider(socket); const clientSocketMessagePublisher = new ClientSocketMessagePublisher( socket ); - const grid = new Grid( - { width: Miscellaneous.WIDTH, height: Miscellaneous.HEIGHT }, - { width: 30, height: 30 } - ); + const grid = new Grid(); [ this.createInputSystem(), @@ -84,10 +80,6 @@ export class JumpStorm { ), new Render(ctx), ].forEach((system) => this.game.addSystem(system)); - - [new Floor(160), new Player()].forEach((entity) => - this.game.addEntity(entity) - ); } public play() { diff --git a/engine/components/Control.ts b/engine/components/Control.ts index fb7b916..a3621b0 100644 --- a/engine/components/Control.ts +++ b/engine/components/Control.ts @@ -3,7 +3,10 @@ import { Component, ComponentNames, Velocity } from "."; export class Control extends Component { public controlVelocityComponent: Velocity; - constructor(controlVelocityComponent: Velocity = new Velocity()) { + constructor( + controlVelocityComponent: Velocity = new Velocity(), + controllableBy: string + ) { super(ComponentNames.Control); this.controlVelocityComponent = controlVelocityComponent; diff --git a/engine/config/constants.ts b/engine/config/constants.ts index b3c3f62..fa3f81b 100644 --- a/engine/config/constants.ts +++ b/engine/config/constants.ts @@ -4,25 +4,28 @@ export namespace KeyConstants { export const KeyActions: Record = { a: Action.MOVE_LEFT, ArrowLeft: Action.MOVE_LEFT, + d: Action.MOVE_RIGHT, ArrowRight: Action.MOVE_RIGHT, + w: Action.JUMP, ArrowUp: Action.JUMP, }; + // value -> [key] from KeyActions export const ActionKeys: Map = Object.keys( KeyActions ).reduce((acc: Map, key) => { const action = KeyActions[key]; if (acc.has(action)) { - acc.get(action)?.push(key); + acc.get(action)!.push(key); return acc; } acc.set(action, [key]); return acc; - }, new Map()); + }, new Map()); } export namespace PhysicsConstants { @@ -37,6 +40,8 @@ export namespace Miscellaneous { export const WIDTH = 600; export const HEIGHT = 800; - export const DEFAULT_GRID_WIDTH = 40; - export const DEFAULT_GRID_HEIGHT = 40; + export const DEFAULT_GRID_WIDTH = 30; + export const DEFAULT_GRID_HEIGHT = 30; + + export const SERVER_TICK_RATE = 5 / 100; } diff --git a/engine/entities/Entity.ts b/engine/entities/Entity.ts index b2d875d..4e9df78 100644 --- a/engine/entities/Entity.ts +++ b/engine/entities/Entity.ts @@ -4,8 +4,8 @@ export abstract class Entity { public readonly id: string; public readonly components: Map; - constructor() { - this.id = crypto.randomUUID(); + constructor(id: string = crypto.randomUUID()) { + this.id = id; this.components = new Map(); } diff --git a/engine/entities/Player.ts b/engine/entities/Player.ts index 377e0ca..03fa69b 100644 --- a/engine/entities/Player.ts +++ b/engine/entities/Player.ts @@ -21,7 +21,7 @@ export class Player extends Entity { private static MOI: number = 100; private static spriteSpec: SpriteSpec = SPRITE_SPECS.get( - Sprites.COFFEE, + Sprites.COFFEE ) as SpriteSpec; constructor() { @@ -34,12 +34,12 @@ export class Player extends Entity { y: 100, }, { width: Player.spriteSpec.width, height: Player.spriteSpec.height }, - 0, - ), + 0 + ) ); this.addComponent( - new Velocity({ dCartesian: { dx: 0, dy: 0 }, dTheta: 0 }), + new Velocity({ dCartesian: { dx: 0, dy: 0 }, dTheta: 0 }) ); this.addComponent(new Mass(Player.MASS)); @@ -64,8 +64,8 @@ export class Player extends Entity { { x: 0, y: 0 }, { width: Player.spriteSpec.width, height: Player.spriteSpec.height }, Player.spriteSpec.msPerFrame, - Player.spriteSpec.frames, - ), + Player.spriteSpec.frames + ) ); this.addComponent(new FacingDirection(leftSprite, rightSprite)); diff --git a/engine/systems/NetworkUpdate.ts b/engine/systems/NetworkUpdate.ts index 6f8acb9..cdd6de7 100644 --- a/engine/systems/NetworkUpdate.ts +++ b/engine/systems/NetworkUpdate.ts @@ -18,7 +18,7 @@ export class NetworkUpdate extends System { constructor( queueProvider: MessageQueueProvider, - publisher: MessagePublisher, + publisher: MessagePublisher ) { super(SystemNames.NetworkUpdate); @@ -28,15 +28,16 @@ export class NetworkUpdate extends System { public update(_dt: number, game: Game) { const messages = this.queueProvider.getNewMessages(); + if (messages.length) console.log(messages); this.queueProvider.clearMessages(); game.forEachEntityWithComponent( ComponentNames.NetworkUpdateable, (entity) => { const networkUpdateComponent = entity.getComponent( - ComponentNames.NetworkUpdateable, + ComponentNames.NetworkUpdateable ); - }, + } ); } } diff --git a/server/src/server.ts b/server/src/server.ts index 18829e4..713d3ed 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -4,20 +4,96 @@ import { WallBounds, Physics, Collision, + NetworkUpdate, MessageQueueProvider, MessagePublisher, } from "@engine/systems"; import { Grid } from "@engine/structures"; import { Miscellaneous } from "@engine/config"; +import { Server } from "bun"; -const TICK_RATE = 60 / 1000; +class ServerSocketMessageReceiver implements MessageQueueProvider { + private messages: any[]; + + constructor() { + this.messages = []; + } + + addMessage(message: any) { + this.messages.push(message); + } + + getNewMessages() { + return this.messages; + } + + clearMessages() { + this.messages = []; + } +} + +class ServerSocketMessagePublisher implements MessagePublisher { + private server: Server; + private messages: any[]; + + constructor(server: Server) { + this.server = server; + this.messages = []; + } + + addMessage(_message: any) {} + + publish() {} +} const game = new Game(); +const messageReceiver = new ServerSocketMessageReceiver(); + +const server = Bun.serve<{ sessionId: string }>({ + port: 8080, + fetch: async (req, server): Promise => { + const sessionId = crypto.randomUUID(); + + server.upgrade(req, { + headers: { + "Set-Cookie": `SessionId=${sessionId}`, + }, + data: { + sessionId, + }, + }); + + return sessionId; + }, + websocket: { + open(ws) { + const { sessionId } = ws.data; + + if (sessionControllableEntities.has(sessionId)) { + return; + } + + const player = new Player(); + game.addEntity(player); + + sessionControllableEntities.set(sessionId, new Set(player.id)); + }, + message(ws, message) { + console.log(JSON.parse(message)); + messageReceiver.addMessage(message); + }, + close(ws) {}, + }, +}); + +const messagePublisher = new ServerSocketMessagePublisher(server); + [ new Physics(), new Collision(new Grid()), new WallBounds(Miscellaneous.WIDTH), + new NetworkUpdate(messageReceiver, messagePublisher), ].forEach((system) => game.addSystem(system)); [new Floor(160), new Player()].forEach((entity) => game.addEntity(entity)); @@ -26,28 +102,8 @@ game.start(); setInterval(() => { game.doGameLoop(performance.now()); -}, TICK_RATE); +}, Miscellaneous.SERVER_TICK_RATE); -const server = Bun.serve({ - port: 8080, - fetch: async (req, server): Promise => { - const sessionId = Math.floor(Math.random() * 1e10).toString(); - - server.upgrade(req, { - headers: { - "Set-Cookie": `SessionId=${sessionId}`, - }, - }); - - return "200 OK"; - }, - websocket: { - open(ws) {}, - message(ws, message) { - console.log(message); - }, - close(ws) {}, - }, -}); +const sessionControllableEntities: Map> = new Map(); console.log(`Listening on ${server.hostname}:${server.port}`);