Added Websockets
This commit is contained in:
106
src/lib/websocket.svelte.ts
Normal file
106
src/lib/websocket.svelte.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
export enum SocketConnectionType {
|
||||||
|
NONE,
|
||||||
|
HOST,
|
||||||
|
DISPLAY
|
||||||
|
}
|
||||||
|
|
||||||
|
const messages: string[] = $state([]);
|
||||||
|
let connectionType = $state(SocketConnectionType.NONE);
|
||||||
|
|
||||||
|
let socket: WebSocket | undefined;
|
||||||
|
|
||||||
|
const connectAsHost = () => {
|
||||||
|
if (socket !== undefined) return;
|
||||||
|
socket = new WebSocket("ws://127.0.0.1:12345");
|
||||||
|
socket.addEventListener("open", onOpen(SocketConnectionType.HOST));
|
||||||
|
socket.addEventListener("message", onFirstMessage);
|
||||||
|
socket.addEventListener("close", onClose);
|
||||||
|
socket.addEventListener("error", onError);
|
||||||
|
};
|
||||||
|
|
||||||
|
const connectAsDisplay = () => {
|
||||||
|
if (socket !== undefined) return;
|
||||||
|
socket = new WebSocket("ws://127.0.0.1:12345");
|
||||||
|
socket.addEventListener("open", onOpen(SocketConnectionType.DISPLAY));
|
||||||
|
socket.addEventListener("message", onFirstMessage);
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendMessage = (obj: unknown) => {
|
||||||
|
if (socket === undefined) return;
|
||||||
|
if (socket.readyState <= 1) {
|
||||||
|
try {
|
||||||
|
socket.send(JSON.stringify(obj));
|
||||||
|
} catch {
|
||||||
|
console.error(`Could not send ${obj}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function onOpen(type: SocketConnectionType) {
|
||||||
|
return (event: Event) => {
|
||||||
|
console.log("Connection established");
|
||||||
|
console.log(event);
|
||||||
|
if (socket === undefined) return;
|
||||||
|
socket.send(type == SocketConnectionType.HOST ? "HOST" : "DISPLAY");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
function onFirstMessage(event: MessageEvent<any>) {
|
||||||
|
if (socket === undefined) return;
|
||||||
|
console.log(event.data);
|
||||||
|
if (event.data === "HOST") {
|
||||||
|
connectionType = SocketConnectionType.HOST;
|
||||||
|
socket.removeEventListener("message", onFirstMessage);
|
||||||
|
socket.addEventListener("message", onMessage);
|
||||||
|
} else if (event.data === "DISPLAY") {
|
||||||
|
connectionType = SocketConnectionType.DISPLAY;
|
||||||
|
socket.removeEventListener("message", onFirstMessage);
|
||||||
|
socket.addEventListener("message", onMessage);
|
||||||
|
} else {
|
||||||
|
console.error("Failed to register");
|
||||||
|
socket.close();
|
||||||
|
socket = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
function onMessage(event: MessageEvent<any>) {
|
||||||
|
messages.push(event.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClose(event: CloseEvent) {
|
||||||
|
console.log("Connection closed");
|
||||||
|
console.log(event);
|
||||||
|
connectionType = SocketConnectionType.NONE;
|
||||||
|
if (socket === undefined) return;
|
||||||
|
socket.close();
|
||||||
|
socket = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onError(event: Event) {
|
||||||
|
console.error("Websocket error occured");
|
||||||
|
console.error(event);
|
||||||
|
connectionType = SocketConnectionType.NONE;
|
||||||
|
if (socket === undefined) return;
|
||||||
|
socket.close();
|
||||||
|
socket = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
get message() {
|
||||||
|
return messages[0];
|
||||||
|
},
|
||||||
|
nextMessage() {
|
||||||
|
return messages.shift();
|
||||||
|
},
|
||||||
|
get messageNum() {
|
||||||
|
return messages.length;
|
||||||
|
},
|
||||||
|
get connectionType() {
|
||||||
|
return connectionType;
|
||||||
|
},
|
||||||
|
sendMessage,
|
||||||
|
connectAsHost,
|
||||||
|
connectAsDisplay
|
||||||
|
};
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '../app.css';
|
import "../app.css";
|
||||||
import favicon from '$lib/assets/favicon.svg';
|
import favicon from "$lib/assets/favicon.svg";
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<link rel="icon" href={favicon} />
|
<link rel="icon" href={favicon} />
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
|
|||||||
@@ -1,14 +1,28 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
let { data } = $props();
|
import { goto } from "$app/navigation";
|
||||||
</script>
|
import websocket, { SocketConnectionType } from "$lib/websocket.svelte";
|
||||||
|
|
||||||
<h1 class="m-4 mb-8 text-7xl font-bold">Jeopardy</h1>
|
$effect(() => {
|
||||||
|
if (websocket.connectionType === SocketConnectionType.HOST) {
|
||||||
<div class="flex flex-col space-y-4">
|
console.log(`Type: ${websocket.connectionType}. Redirecting to /connected/games`);
|
||||||
{#each data.games as game, i}
|
goto("/connected/games");
|
||||||
<a
|
}
|
||||||
class="ms-4 me-4 rounded-xl border-2 p-4 hover:cursor-pointer hover:bg-emerald-200"
|
if (websocket.connectionType === SocketConnectionType.DISPLAY) {
|
||||||
href="/{i}">{game.name}</a
|
console.log(`Type: ${websocket.connectionType}. Redirecting to /connected/display`);
|
||||||
>
|
goto("/connected/display");
|
||||||
{/each}
|
}
|
||||||
</div>
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex h-full flex-col">
|
||||||
|
<h1 class="m-4 mb-8 text-7xl font-bold">Jeopardy</h1>
|
||||||
|
|
||||||
|
<div class="flex h-full grow items-center justify-around p-4">
|
||||||
|
<button class="btn m-2 h-1/2 w-1/2 text-5xl" onclick={websocket.connectAsHost}
|
||||||
|
>Connect as Host</button
|
||||||
|
>
|
||||||
|
<button class="btn m-2 h-1/2 w-1/2 text-5xl" onclick={websocket.connectAsDisplay}
|
||||||
|
>Connect as Display</button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
14
src/routes/connected/+layout.svelte
Normal file
14
src/routes/connected/+layout.svelte
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { goto } from "$app/navigation";
|
||||||
|
import ws, { SocketConnectionType } from "$lib/websocket.svelte";
|
||||||
|
|
||||||
|
let { children } = $props();
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (ws.connectionType === SocketConnectionType.NONE) {
|
||||||
|
goto("/");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{@render children?.()}
|
||||||
15
src/routes/connected/display/+page.svelte
Normal file
15
src/routes/connected/display/+page.svelte
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { goto } from "$app/navigation";
|
||||||
|
import ws from "$lib/websocket.svelte";
|
||||||
|
$effect(() => {
|
||||||
|
if (!ws.message) return;
|
||||||
|
console.log(ws.message);
|
||||||
|
if (ws.nextMessage() == "HOST-DISCONNECTED") {
|
||||||
|
goto("/connected/display");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex h-full w-full items-center justify-center">
|
||||||
|
<p class="text-9xl">Waiting for game to start</p>
|
||||||
|
</div>
|
||||||
14
src/routes/connected/games/+page.svelte
Normal file
14
src/routes/connected/games/+page.svelte
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
let { data } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1 class="m-4 mb-8 text-7xl font-bold">Games</h1>
|
||||||
|
|
||||||
|
<div class="flex flex-col space-y-4">
|
||||||
|
{#each data.games as game, i}
|
||||||
|
<a
|
||||||
|
class="ms-4 me-4 rounded-xl border-2 p-4 hover:cursor-pointer hover:bg-emerald-200"
|
||||||
|
href="/connected/games/{i}">{game.name}</a
|
||||||
|
>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
@@ -3,6 +3,24 @@
|
|||||||
import type { Player } from "./Player";
|
import type { Player } from "./Player";
|
||||||
import { GameState } from "./GameState";
|
import { GameState } from "./GameState";
|
||||||
import type { Game } from "$lib/games/games";
|
import type { Game } from "$lib/games/games";
|
||||||
|
import ws from "$lib/websocket.svelte";
|
||||||
|
import { page } from "$app/state";
|
||||||
|
|
||||||
|
let startDisabled = $state(true);
|
||||||
|
let _startDisabled = true;
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (!ws.message) return;
|
||||||
|
console.log(ws.message);
|
||||||
|
if (ws.nextMessage() == "DISPLAY-CONNECTED") {
|
||||||
|
if (!_startDisabled) {
|
||||||
|
gameManager?.sendStart();
|
||||||
|
gameManager?.sendCurrentState();
|
||||||
|
}
|
||||||
|
_startDisabled = false;
|
||||||
|
startDisabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
class GameManager {
|
class GameManager {
|
||||||
public state: GameState = $state(GameState.INIT);
|
public state: GameState = $state(GameState.INIT);
|
||||||
@@ -17,8 +35,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
startGame(): void {
|
startGame(): void {
|
||||||
this.state = GameState.RUNNING;
|
this.state = GameState.CHOOSING_QUESTION;
|
||||||
console.log("hello");
|
this.sendStart();
|
||||||
|
this.sendCurrentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
sendStart(): void {
|
||||||
|
ws.sendMessage({
|
||||||
|
type: "start"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCurrentState(): void {
|
||||||
|
ws.sendMessage({
|
||||||
|
type: "players",
|
||||||
|
players
|
||||||
|
});
|
||||||
|
ws.sendMessage({
|
||||||
|
type: "goto",
|
||||||
|
route: `/${page.params.game}/${this.currentWall}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +93,9 @@
|
|||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<h2 class="grow pb-4 text-5xl">Spieler</h2>
|
<h2 class="grow pb-4 text-5xl">Spieler</h2>
|
||||||
<button class="btn" onclick={() => gameManager.startGame()}>Start</button>
|
<button class="btn" disabled={startDisabled} onclick={() => gameManager.startGame()}
|
||||||
|
>Start</button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col space-y-2 pb-4">
|
<div class="flex flex-col space-y-2 pb-4">
|
||||||
{#each gameManager.players as player, i}
|
{#each gameManager.players as player, i}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export enum GameState {
|
export enum GameState {
|
||||||
INIT,
|
INIT,
|
||||||
RUNNING
|
CHOOSING_QUESTION
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user