diff --git a/client/svelte-client/src/components/NetworkSessionWrapper.svelte b/client/svelte-client/src/components/NetworkSessionWrapper.svelte index e7db3e3..2e40482 100644 --- a/client/svelte-client/src/components/NetworkSessionWrapper.svelte +++ b/client/svelte-client/src/components/NetworkSessionWrapper.svelte @@ -5,31 +5,36 @@ import {SessionState, SessionType} from "../store/model/session"; import CopyToClipboard from "./CopyToClipboard.svelte"; import api from "../api/session"; - import {playerKeyboardInputs} from "../store/input"; + import type {Readable} from "svelte/store"; + import type {Input} from "../store/model/input"; + import {getPlayerKeyboardInputs} from "../store/input"; export let session: NetworkSession; let joinLink; let cachedSessionId; - let relevantKeyboardEvents; - $: relevantKeyboardEvents = $playerKeyboardInputs.filter(({player}) => player === session.you.nr); + let relevantKeyboardEvents: Readable; + $: if (!cachedSessionId && session) { + } $: if(!cachedSessionId && session) { cachedSessionId = session.session_id; console.log("NetworkSessionWrapper ready, now setting up sessionEvents") joinLink = api.createJoinLink(session.session_id); + + relevantKeyboardEvents = getPlayerKeyboardInputs(session.you.nr); } - $: if(session) { + $: if(session && session.state === SessionState.RUNNING) { switch(session.type) { case SessionType.HOST: console.debug("sending host snapshot") - networkEvents.produce({inputs: relevantKeyboardEvents, session_id: session.session_id, objects: [], player_id: session.you.id, ts: Date.now()}) + networkEvents.produce({inputs: $relevantKeyboardEvents, session_id: session.session_id, objects: [], player_id: session.you.id, ts: Date.now()}) break; case SessionType.PEER: console.debug("sending peer snapshot") - networkEvents.produce({inputs: relevantKeyboardEvents, session_id: session.session_id, player_id: session.you.id, ts: Date.now()}) + networkEvents.produce({inputs: $relevantKeyboardEvents, session_id: session.session_id, player_id: session.you.id, ts: Date.now()}) break; default: // noop diff --git a/client/svelte-client/src/store/input.ts b/client/svelte-client/src/store/input.ts index e025830..67f00da 100644 --- a/client/svelte-client/src/store/input.ts +++ b/client/svelte-client/src/store/input.ts @@ -19,8 +19,8 @@ export const playerKeyboardInputs = derived(keysPressed, $keysPressed => { }).filter(it => !!it); }) -export const getPlayerKeyboardInputs = (player_nr: number) => readable([], set => { +export const getPlayerKeyboardInputs = (player_nr: number) => readable([], set => { return playerKeyboardInputs.subscribe(inputs => { - return inputs.filter(({player}) => player === player_nr); + set(inputs.filter(({player}) => player === player_nr)); }) }) diff --git a/client/svelte-client/src/store/session.ts b/client/svelte-client/src/store/session.ts index a1c9627..a00b5e1 100644 --- a/client/svelte-client/src/store/session.ts +++ b/client/svelte-client/src/store/session.ts @@ -1,13 +1,14 @@ -import {derived, get, readable, writable} from "svelte/store"; +import {derived, get, Readable, readable, Unsubscriber, writable} from "svelte/store"; import {keysPressed} from "./io"; import api from "../api/session"; import session from "../api/session"; -import type {LocalSession, Message, NetworkSession, Session, SessionSnapshot} from "./model/session"; +import type {Heartbeat, LocalSession, Message, NetworkSession, Session, SessionSnapshot} from "./model/session"; import {isLocalSession, isNetworkSession, MessageType, SessionState, SessionType} from "./model/session"; import type {NetworkStore} from "./network"; import type {GameEventWrapper, InputEventPayload, InputEventWrapper, SessionEventPayload} from "./model/event"; import {isInputEvent} from "./model/event"; import {getPlayerKeyboardInputs, playerKeyboardInputs} from "./input"; +import type {Subscriber} from "svelte/types/runtime/store"; const sessionStore = writable(null) @@ -16,6 +17,7 @@ function createNetworkEvents() { const websocket = writable(null); const sessionId = writable(null); + const playerId = writable(null); const lastSnapshot = writable(null); const unsubscribeSession = sessionStore.subscribe(session => { @@ -26,6 +28,7 @@ function createNetworkEvents() { return; } sessionId.set(session.session_id); + playerId.set(session.you.id); console.log("creating ws to receive/send websocket events for session: ", JSON.stringify(session)) api.createEventWebsocket(session).then(ws => { console.log("ws successfully established: ", ws) @@ -54,15 +57,13 @@ function createNetworkEvents() { const interval = setInterval(() => { const last = get(lastSnapshot); - if (last === null) { - return; - } const now = Date.now(); - if (now - last.ts < 1_000) { + if (last && now - last.ts < 1_000) { return } console.debug("sending heartbeat") - sendMessage({msg_type: MessageType.Heartbeat, payload: {session_id: last.session_id, player_id: last.player_id, ts: now}}); + const heartbeat: Message = {msg_type: MessageType.Heartbeat, payload: {session_id: get(sessionId), player_id: get(playerId), ts: now}}; + sendMessage(heartbeat); }, 1_000) function sendMessage(message: Message) { @@ -80,14 +81,26 @@ function createNetworkEvents() { sendMessage({msg_type: MessageType.Snapshot, payload: snapshot}); } - // TODO: Handle unsubscribe + const customSubscribe = (run: Subscriber, invalidate): Unsubscriber => { + const unsubscribe = subscribe(run, invalidate); + return () => { + unsubscribeSession(); + clearInterval(interval); + unsubscribe(); + } + } + return { - subscribe, + subscribe: customSubscribe, produce } } -export const networkEvents = createNetworkEvents(); +export type NetworkEventStore = Readable & { + produce: (snapshot: SessionSnapshot) => void +} + +export const networkEvents: NetworkEventStore = createNetworkEvents(); export const networkSessionStateEvents = derived(networkEvents, $sessionEvents => { const sessionEvents = $sessionEvents.filter(({topic}) => topic === 'session').map(({event}) => event);