diff options
author | Elizabeth (Lizzy) Hunt <elizabeth.hunt@simponic.xyz> | 2023-08-26 17:57:05 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-26 17:57:05 -0600 |
commit | 8a4ab8d79b5ce1dabb431168398b5d5111fe326c (patch) | |
tree | e60767dc5295edf379cf421e20171dc418e548b7 /client | |
parent | c6e9baa0009f7cce0f6ff156a3957ef04a8cb684 (diff) | |
parent | 6ce6946a4401d2ee6fa5cb747fab7d4c658a63c8 (diff) | |
download | jumpstorm-8a4ab8d79b5ce1dabb431168398b5d5111fe326c.tar.gz jumpstorm-8a4ab8d79b5ce1dabb431168398b5d5111fe326c.zip |
Merge pull request #1 from Simponic/network
Network
Diffstat (limited to 'client')
-rw-r--r-- | client/.eslintrc.js | 6 | ||||
-rw-r--r-- | client/index.html | 2 | ||||
-rw-r--r-- | client/public/css/colors.css | 2 | ||||
-rw-r--r-- | client/public/css/style.css | 10 | ||||
-rw-r--r-- | client/public/css/tf.css | 2 | ||||
-rw-r--r-- | client/public/css/theme.css | 2 | ||||
-rw-r--r-- | client/src/JumpStorm.ts | 168 | ||||
-rw-r--r-- | client/src/components/GameCanvas.svelte | 18 | ||||
-rw-r--r-- | client/src/components/LeaderBoard.svelte | 2 | ||||
-rw-r--r-- | client/src/main.ts | 4 | ||||
-rw-r--r-- | client/src/routes/Home.svelte | 3 | ||||
-rw-r--r-- | client/svelte.config.js | 6 | ||||
-rw-r--r-- | client/tsconfig.json | 5 | ||||
-rw-r--r-- | client/vite.config.ts | 23 |
14 files changed, 193 insertions, 60 deletions
diff --git a/client/.eslintrc.js b/client/.eslintrc.js index f200fbf..a9b1e2d 100644 --- a/client/.eslintrc.js +++ b/client/.eslintrc.js @@ -1,11 +1,11 @@ module.exports = { extends: [ // add more generic rule sets here, such as: - "eslint:recommended", - "plugin:svelte/recommended", + 'eslint:recommended', + 'plugin:svelte/recommended' ], rules: { // override/add rules settings here, such as: // 'svelte/rule-name': 'error' - }, + } }; diff --git a/client/index.html b/client/index.html index 00b94e7..892a3af 100644 --- a/client/index.html +++ b/client/index.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> +<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> diff --git a/client/public/css/colors.css b/client/public/css/colors.css index 067ddcd..6108028 100644 --- a/client/public/css/colors.css +++ b/client/public/css/colors.css @@ -10,7 +10,7 @@ --orange: #af3a03; } -[data-theme="dark"] { +[data-theme='dark'] { --bg: #282828; --text: #f9f5d7; --red: #fb4934; diff --git a/client/public/css/style.css b/client/public/css/style.css index cdfef76..4dfe605 100644 --- a/client/public/css/style.css +++ b/client/public/css/style.css @@ -1,15 +1,15 @@ -@import url("./theme.css"); -@import url("./tf.css"); +@import url('./theme.css'); +@import url('./tf.css'); @font-face { - font-family: "scientifica"; - src: url("/fonts/scientifica.ttf"); + font-family: 'scientifica'; + src: url('/fonts/scientifica.ttf'); } * { padding: 0; margin: 0; - font-family: "scientifica", monospace; + font-family: 'scientifica', monospace; transition: background 0.2s ease-in-out; font-smooth: never; } diff --git a/client/public/css/tf.css b/client/public/css/tf.css index c1acd72..855fe0d 100644 --- a/client/public/css/tf.css +++ b/client/public/css/tf.css @@ -17,7 +17,7 @@ rgba(162, 254, 254, 1) 100% ); - content: ""; + content: ''; width: 100%; height: 100%; top: 0; diff --git a/client/public/css/theme.css b/client/public/css/theme.css index c65b2a8..eeb15ee 100644 --- a/client/public/css/theme.css +++ b/client/public/css/theme.css @@ -1,4 +1,4 @@ -@import url("./colors.css"); +@import url('./colors.css'); .primary { color: var(--aqua); diff --git a/client/src/JumpStorm.ts b/client/src/JumpStorm.ts index bd48483..6f9e24f 100644 --- a/client/src/JumpStorm.ts +++ b/client/src/JumpStorm.ts @@ -1,5 +1,6 @@ -import { Floor, Player } from "@engine/entities"; -import { Game } from "@engine/Game"; +import { Game } from '@engine/Game'; +import { Entity } from '@engine/entities'; +import { Grid } from '@engine/structures'; import { WallBounds, FacingDirection, @@ -7,28 +8,141 @@ import { Physics, Input, Collision, -} from "@engine/systems"; + NetworkUpdate +} from '@engine/systems'; +import { + type MessageQueueProvider, + type MessagePublisher, + type MessageProcessor, + type Message, + type EntityAddBody, + MessageType, + type EntityUpdateBody +} from '@engine/network'; +import { stringify, parse } from '@engine/utils'; -export class JumpStorm { +class ClientMessageProcessor implements MessageProcessor { private game: Game; + + constructor(game: Game) { + this.game = game; + } + + public process(message: Message) { + switch (message.type) { + case MessageType.NEW_ENTITIES: + const entityAdditions = message.body as unknown as EntityAddBody[]; + entityAdditions.forEach((addBody) => + this.game.addEntity( + Entity.from(addBody.entityName, addBody.id, addBody.args) + ) + ); + break; + case MessageType.REMOVE_ENTITIES: + const ids = message.body as unknown as string[]; + ids.forEach((id) => this.game.removeEntity(id)); + break; + case MessageType.UPDATE_ENTITIES: + const entityUpdates = message.body as unknown as EntityUpdateBody[]; + entityUpdates.forEach( + ({ id, args }) => this.game.getEntity(id)?.setFrom(args) + ); + break; + default: + break; + } + } +} + +class ClientSocketMessageQueueProvider implements MessageQueueProvider { private socket: WebSocket; + private messages: Message[]; + + constructor(socket: WebSocket) { + this.socket = socket; + this.messages = []; - constructor(ctx: CanvasRenderingContext2D) { - this.game = new Game(); - this.socket = new WebSocket("ws://localhost:8080"); + this.socket.addEventListener('message', (e) => { + const messages = parse<Message[]>(e.data); + this.messages = this.messages.concat(messages); + }); + } + + public getNewMessages() { + return this.messages; + } + + public clearMessages() { + this.messages = []; + } +} + +class ClientSocketMessagePublisher implements MessagePublisher { + private socket: WebSocket; + private messages: Message[]; + + constructor(socket: WebSocket) { + this.socket = socket; + this.messages = []; + } + + public addMessage(message: Message) { + this.messages.push(message); + } + + public publish() { + if (this.socket.readyState == WebSocket.OPEN) { + this.messages.forEach((message: Message) => + this.socket.send(stringify(message)) + ); + this.messages = []; + } + } +} + +export class JumpStorm { + private game: Game; + private clientId: string; + + constructor(game: Game) { + this.game = game; + } + + public async init( + ctx: CanvasRenderingContext2D, + httpMethod: string, + wsMethod: string, + host: string + ) { + this.clientId = await this.getAssignedCookie( + `${httpMethod}://${host}/assign` + ); + const socket = new WebSocket(`${wsMethod}://${host}/game`); + const clientSocketMessageQueueProvider = + new ClientSocketMessageQueueProvider(socket); + const clientSocketMessagePublisher = new ClientSocketMessagePublisher( + socket + ); + const clientMessageProcessor = new ClientMessageProcessor(this.game); + + const inputSystem = new Input(this.clientId, clientSocketMessagePublisher); + this.addWindowEventListenersToInputSystem(inputSystem); + + const grid = new Grid(); [ - this.createInputSystem(), + new NetworkUpdate( + clientSocketMessageQueueProvider, + clientSocketMessagePublisher, + clientMessageProcessor + ), + inputSystem, new FacingDirection(), new Physics(), - new Collision(), - new WallBounds(ctx.canvas.width), - new Render(ctx), + new Collision(grid), + new WallBounds(), + new Render(ctx) ].forEach((system) => this.game.addSystem(system)); - - [new Floor(160), new Player()].forEach((entity) => - this.game.addEntity(entity), - ); } public play() { @@ -41,16 +155,26 @@ export class JumpStorm { requestAnimationFrame(loop); } - private createInputSystem(): Input { - const inputSystem = new Input(); - - window.addEventListener("keydown", (e) => { + private addWindowEventListenersToInputSystem(input: Input) { + window.addEventListener('keydown', (e) => { if (!e.repeat) { - inputSystem.keyPressed(e.key); + input.keyPressed(e.key.toLowerCase()); } }); - window.addEventListener("keyup", (e) => inputSystem.keyReleased(e.key)); - return inputSystem; + window.addEventListener('keyup', (e) => + input.keyReleased(e.key.toLowerCase()) + ); + } + + private async getAssignedCookie(endpoint: string): Promise<string> { + return fetch(endpoint) + .then((resp) => { + if (resp.ok) { + return resp.text(); + } + throw resp; + }) + .then((cookie) => cookie); } } diff --git a/client/src/components/GameCanvas.svelte b/client/src/components/GameCanvas.svelte index ae8c1b0..ea7dd15 100644 --- a/client/src/components/GameCanvas.svelte +++ b/client/src/components/GameCanvas.svelte @@ -1,24 +1,26 @@ <script lang="ts"> import { onMount } from "svelte"; import { loadAssets } from "@engine/config"; + import { Game } from "@engine/Game"; import { JumpStorm } from "../JumpStorm"; - + let canvas: HTMLCanvasElement; let ctx: CanvasRenderingContext2D; export let width: number; export let height: number; - let jumpStorm: JumpStorm; - - onMount(() => { + onMount(async () => { ctx = canvas.getContext("2d"); ctx.imageSmoothingEnabled = false; - loadAssets().then(() => { - jumpStorm = new JumpStorm(ctx); - jumpStorm.play(); - }); + await loadAssets(); + + const game = new Game(); + const jumpStorm = new JumpStorm(game); + + await jumpStorm.init(ctx, "http", "ws", document.location.host + "/api"); + jumpStorm.play(); }); </script> diff --git a/client/src/components/LeaderBoard.svelte b/client/src/components/LeaderBoard.svelte index 8343c56..2f3e411 100644 --- a/client/src/components/LeaderBoard.svelte +++ b/client/src/components/LeaderBoard.svelte @@ -3,7 +3,7 @@ const MAX_ENTRIES = 8; - export let entries: { name: string, score: number }[] = []; + export let entries: { name: string; score: number }[] = []; </script> <div class="leaderboard"> diff --git a/client/src/main.ts b/client/src/main.ts index 5332616..aa7431f 100644 --- a/client/src/main.ts +++ b/client/src/main.ts @@ -1,7 +1,7 @@ -import App from "./App.svelte"; +import App from './App.svelte'; const app = new App({ - target: document.getElementById("app"), + target: document.getElementById('app') }); export default app; diff --git a/client/src/routes/Home.svelte b/client/src/routes/Home.svelte index 9ada10e..71ad324 100644 --- a/client/src/routes/Home.svelte +++ b/client/src/routes/Home.svelte @@ -3,10 +3,9 @@ import LeaderBoard from "../components/LeaderBoard.svelte"; import { Miscellaneous } from "@engine/config"; - + let width: number = Miscellaneous.WIDTH; let height: number = Miscellaneous.HEIGHT; - </script> <div class="centered-game"> diff --git a/client/svelte.config.js b/client/svelte.config.js index b0683fd..db735be 100644 --- a/client/svelte.config.js +++ b/client/svelte.config.js @@ -1,7 +1,7 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; export default { // Consult https://svelte.dev/docs#compile-time-svelte-preprocess // for more information about preprocessors - preprocess: vitePreprocess(), -} + preprocess: vitePreprocess() +}; diff --git a/client/tsconfig.json b/client/tsconfig.json index 781d1b3..fadebb0 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@tsconfig/svelte/tsconfig.json", + "extends": ["@tsconfig/svelte/tsconfig.json", "../tsconfig.engine.json"], "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, @@ -24,8 +24,5 @@ "src/**/*.js", "src/**/*.svelte" ], - "paths": { - "@engine/*": ["../engine/*"] - }, "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/client/vite.config.ts b/client/vite.config.ts index 0307338..6f0e1d0 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -1,13 +1,24 @@ -import { defineConfig } from "vite"; -import { svelte } from "@sveltejs/vite-plugin-svelte"; -import { fileURLToPath, URL } from "node:url"; +import { defineConfig } from 'vite'; +import { svelte } from '@sveltejs/vite-plugin-svelte'; +import { fileURLToPath, URL } from 'node:url'; // https://vitejs.dev/config/ export default defineConfig({ + server: { + host: '0.0.0.0', + proxy: { + '/api': { + target: 'http://10.0.0.237:8080', + ws: true, + rewrite: (path) => path.replace(/^\/api/, '') + } + } + }, + cors: true, plugins: [svelte()], resolve: { alias: { - "@engine": fileURLToPath(new URL("../engine", import.meta.url)), - }, - }, + '@engine': fileURLToPath(new URL('../engine', import.meta.url)) + } + } }); |