summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/src/JumpStorm.ts57
-rw-r--r--engine/Game.ts10
-rw-r--r--engine/components/NetworkUpdateable.ts8
-rw-r--r--engine/entities/Entity.ts6
-rw-r--r--engine/structures/QuadTree.ts12
-rw-r--r--engine/systems/NetworkUpdate.ts36
-rw-r--r--server/src/server.ts75
-rw-r--r--server/tsconfig.json29
8 files changed, 174 insertions, 59 deletions
diff --git a/client/src/JumpStorm.ts b/client/src/JumpStorm.ts
index bd48483..8075cc8 100644
--- a/client/src/JumpStorm.ts
+++ b/client/src/JumpStorm.ts
@@ -7,15 +7,63 @@ import {
Physics,
Input,
Collision,
+ MessageQueueProvider,
+ MessagePublisher,
+ NetworkUpdate,
} from "@engine/systems";
+class ClientSocketMessageQueueProvider implements MessageQueueProvider {
+ private socket: WebSocket;
+ private messages: any[];
+
+ constructor(socket: WebSocket) {
+ this.socket = socket;
+ this.messages = [];
+
+ this.socket.addEventListener("message", (e) => {
+ console.log(e);
+ });
+ }
+
+ getNewMessages() {
+ return this.messages;
+ }
+
+ clearMessages() {
+ this.messages = [];
+ }
+}
+
+class ClientSocketMessagePublisher implements MessagePublisher {
+ private socket: WebSocket;
+ private messages: any[];
+
+ constructor(socket: WebSocket) {
+ this.socket = socket;
+ this.messages = [];
+
+ this.socket.addEventListener("message", (e) => {
+ console.log(e);
+ });
+ }
+
+ addMessage(_message: any) {}
+
+ publish() {}
+}
+
export class JumpStorm {
private game: Game;
- private socket: WebSocket;
constructor(ctx: CanvasRenderingContext2D) {
this.game = new Game();
- this.socket = new WebSocket("ws://localhost:8080");
+
+ const socket = new WebSocket("ws://localhost:8080");
+ const clientSocketMessageQueueProvider =
+ new ClientSocketMessageQueueProvider(socket);
+ const clientSocketMessagePublisher = new ClientSocketMessagePublisher(
+ socket,
+ );
[
this.createInputSystem(),
@@ -23,6 +71,10 @@ export class JumpStorm {
new Physics(),
new Collision(),
new WallBounds(ctx.canvas.width),
+ new NetworkUpdate(
+ clientSocketMessageQueueProvider,
+ clientSocketMessagePublisher,
+ ),
new Render(ctx),
].forEach((system) => this.game.addSystem(system));
@@ -49,6 +101,7 @@ export class JumpStorm {
inputSystem.keyPressed(e.key);
}
});
+
window.addEventListener("keyup", (e) => inputSystem.keyReleased(e.key));
return inputSystem;
diff --git a/engine/Game.ts b/engine/Game.ts
index 07d06e8..8dc5db7 100644
--- a/engine/Game.ts
+++ b/engine/Game.ts
@@ -7,9 +7,9 @@ export class Game {
private running: boolean;
private lastTimeStamp: number;
- public entities: Map<number, Entity>;
+ public entities: Map<string, Entity>;
public systems: Map<string, System>;
- public componentEntities: Map<string, Set<number>>;
+ public componentEntities: Map<string, Set<string>>;
constructor() {
this.lastTimeStamp = performance.now();
@@ -29,11 +29,11 @@ export class Game {
this.entities.set(entity.id, entity);
}
- public getEntity(id: number): Entity | undefined {
+ public getEntity(id: string): Entity | undefined {
return this.entities.get(id);
}
- public removeEntity(id: number) {
+ public removeEntity(id: string) {
this.entities.delete(id);
}
@@ -75,7 +75,7 @@ export class Game {
if (!this.componentEntities.has(component.name)) {
this.componentEntities.set(
component.name,
- new Set<number>([entity.id]),
+ new Set<string>([entity.id]),
);
return;
}
diff --git a/engine/components/NetworkUpdateable.ts b/engine/components/NetworkUpdateable.ts
index 73ceeba..980b064 100644
--- a/engine/components/NetworkUpdateable.ts
+++ b/engine/components/NetworkUpdateable.ts
@@ -1,7 +1,13 @@
import { Component, ComponentNames } from ".";
export class NetworkUpdateable extends Component {
- constructor() {
+ public isPublish: boolean;
+ public isSubscribe: boolean;
+
+ constructor(isPublish: boolean, isSubscribe: boolean) {
super(ComponentNames.NetworkUpdateable);
+
+ this.isPublish = isPublish;
+ this.isSubscribe = isSubscribe;
}
}
diff --git a/engine/entities/Entity.ts b/engine/entities/Entity.ts
index ca8d314..b2d875d 100644
--- a/engine/entities/Entity.ts
+++ b/engine/entities/Entity.ts
@@ -1,13 +1,11 @@
import type { Component } from "../components";
export abstract class Entity {
- private static ID = 0;
-
- public readonly id: number;
+ public readonly id: string;
public readonly components: Map<string, Component>;
constructor() {
- this.id = Entity.ID++;
+ this.id = crypto.randomUUID();
this.components = new Map();
}
diff --git a/engine/structures/QuadTree.ts b/engine/structures/QuadTree.ts
index a57c6e7..49afdad 100644
--- a/engine/structures/QuadTree.ts
+++ b/engine/structures/QuadTree.ts
@@ -1,7 +1,7 @@
import type { Coord2D, Dimension2D } from "../interfaces";
interface BoxedEntry {
- id: number;
+ id: string;
dimension: Dimension2D;
center: Coord2D;
}
@@ -72,8 +72,8 @@ export class QuadTree {
}
}
- public getNeighborIds(boxedEntry: BoxedEntry): number[] {
- const neighbors: number[] = this.objects.map(({ id }) => id);
+ public getNeighborIds(boxedEntry: BoxedEntry): string[] {
+ const neighbors: string[] = this.objects.map(({ id }) => id);
if (this.hasChildren()) {
this.getQuadrants(boxedEntry).forEach((quadrant) => {
@@ -160,11 +160,7 @@ export class QuadTree {
this.objects.forEach((boxedEntry) => {
this.getQuadrants(boxedEntry).forEach((direction) => {
const quadrant = this.children.get(direction);
- quadrant?.insert(
- boxedEntry.id,
- boxedEntry.dimension,
- boxedEntry.center,
- );
+ quadrant?.insert(boxedEntry);
});
});
diff --git a/engine/systems/NetworkUpdate.ts b/engine/systems/NetworkUpdate.ts
index dc7be20..6f8acb9 100644
--- a/engine/systems/NetworkUpdate.ts
+++ b/engine/systems/NetworkUpdate.ts
@@ -1,10 +1,42 @@
import { System, SystemNames } from ".";
import { Game } from "../Game";
+import { ComponentNames, NetworkUpdateable } from "../components";
+
+export interface MessageQueueProvider {
+ getNewMessages(): any[];
+ clearMessages(): void;
+}
+
+export interface MessagePublisher {
+ addMessage(message: any): void;
+ publish(): void;
+}
export class NetworkUpdate extends System {
- constructor() {
+ private queueProvider: MessageQueueProvider;
+ private publisher: MessagePublisher;
+
+ constructor(
+ queueProvider: MessageQueueProvider,
+ publisher: MessagePublisher,
+ ) {
super(SystemNames.NetworkUpdate);
+
+ this.queueProvider = queueProvider;
+ this.publisher = publisher;
}
- public update(_dt: number, _game: Game) {}
+ public update(_dt: number, game: Game) {
+ const messages = this.queueProvider.getNewMessages();
+ this.queueProvider.clearMessages();
+
+ game.forEachEntityWithComponent(
+ ComponentNames.NetworkUpdateable,
+ (entity) => {
+ const networkUpdateComponent = entity.getComponent<NetworkUpdateable>(
+ ComponentNames.NetworkUpdateable,
+ );
+ },
+ );
+ }
}
diff --git a/server/src/server.ts b/server/src/server.ts
index 74d901b..9a73f11 100644
--- a/server/src/server.ts
+++ b/server/src/server.ts
@@ -1,37 +1,60 @@
import { Game } from "../../engine/Game";
import { Floor, Player } from "../../engine/entities";
-import { WallBounds, Physics, Collision } from "../../engine/systems";
+import {
+ WallBounds,
+ Physics,
+ Collision,
+ MessageQueueProvider,
+ MessagePublisher,
+} from "../../engine/systems";
import { Miscellaneous } from "../../engine/config";
const TICK_RATE = 60 / 1000;
-const game = new Game();
+class Server {
+ private server: any;
+ private game: Game;
-[
- new Physics(),
- new Collision({ width: Miscellaneous.WIDTH, height: Miscellaneous.HEIGHT }),
- new WallBounds(Miscellaneous.WIDTH),
-].forEach((system) => game.addSystem(system));
+ constructor() {
+ this.game = new Game();
-[new Floor(160), new Player()].forEach((entity) => game.addEntity(entity));
+ [
+ new Physics(),
+ new Collision({
+ width: Miscellaneous.WIDTH,
+ height: Miscellaneous.HEIGHT,
+ }),
+ new WallBounds(Miscellaneous.WIDTH),
+ ].forEach((system) => this.game.addSystem(system));
-game.start();
-setInterval(() => {
- game.doGameLoop(performance.now());
-}, TICK_RATE);
+ [new Floor(160), new Player()].forEach((entity) =>
+ this.game.addEntity(entity),
+ );
-const server = Bun.serve<>({
- port: 8080,
- fetch(req, server) {
- server.upgrade(req, {
- data: {},
+ this.game.start();
+ setInterval(() => {
+ this.game.doGameLoop(performance.now());
+ }, TICK_RATE);
+
+ this.server = Bun.serve<any>({
+ websocket: {
+ open(ws) {
+ ws.subscribe("the-group-chat");
+ ws.publish("the-group-chat", msg);
+ },
+ message(ws, message) {
+ // this is a group chat
+ // so the server re-broadcasts incoming message to everyone
+ ws.publish("the-group-chat", `${ws.data.username}: ${message}`);
+ },
+ close(ws) {
+ const msg = `${ws.data.username} has left the chat`;
+ ws.unsubscribe("the-group-chat");
+ ws.publish("the-group-chat", msg);
+ },
+ },
});
- },
- websocket: {
- // handler called when a message is received
- async message(ws, message) {
- console.log(`Received ${message}`);
- },
- },
-});
-console.log(`Listening on localhost:${server.port}`);
+ }
+}
+
+new Server();
diff --git a/server/tsconfig.json b/server/tsconfig.json
index 29f8aa0..2567512 100644
--- a/server/tsconfig.json
+++ b/server/tsconfig.json
@@ -1,21 +1,28 @@
{
"compilerOptions": {
- "lib": ["ESNext"],
+ // add Bun type definitions
+ "types": ["bun-types"],
+
+ // enable latest features
+ "lib": ["esnext"],
"module": "esnext",
"target": "esnext",
+
+ // if TS 5.x+
"moduleResolution": "bundler",
- "moduleDetection": "force",
+ "noEmit": true,
"allowImportingTsExtensions": true,
+ "moduleDetection": "force",
+ // if TS 4.x or earlier
+ "moduleResolution": "nodenext",
+
+ "jsx": "react-jsx", // support JSX
+ "allowJs": true, // allow importing `.js` from `.ts`
+ "esModuleInterop": true, // allow default imports for CommonJS modules
+
+ // best practices
"strict": true,
- "downlevelIteration": true,
- "skipLibCheck": true,
- "jsx": "preserve",
- "allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
- "allowJs": true,
- "noEmit": true,
- "types": [
- "bun-types" // add Bun global
- ]
+ "skipLibCheck": true
}
}