import { Callbag } from "callbag"; import pipe from "callbag-pipe"; import share from "callbag-share"; import { INPUT_FREQUENCY } from "../Ecs/Lockstep"; import { catchTalkback, defer, interval, makeSubject, map, merge } from "../Utilities/Callbag"; import { ClientMessage, MessageTypes, Server, ServerMessage } from "./LockstepClient"; type Client = Callbag, ClientMessage>; /** Stub loopback server that handles multiple clients, for schemes where GlobalInput = LocalInput[] */ export class LoopbackServer { private nextClientId = 0; private inputBuffer: LocalInput[] = []; private heartbeat = pipe( interval(INPUT_FREQUENCY), map(() => ({ t: MessageTypes.INPUT, i: this.inputBuffer.slice() } as ServerMessage)), ); private broadcast = makeSubject>(); private serverFeed = share(merge(this.heartbeat, this.broadcast)); public readonly socket = defer(() => { const playerNumber = this.nextClientId++; return pipe( this.serverFeed, catchTalkback, ClientMessage>(message => { switch (message.t) { case MessageTypes.INPUT: if (playerNumber >= 0) { this.inputBuffer[playerNumber] = message.i; } break; } }), map(message => { if (message.t === MessageTypes.SET_STATE && playerNumber >= 0) { return { ...message, u: playerNumber, }; } else { return message; } }) ); }); public resetState(newState: Partial) { this.broadcast(1, { t: MessageTypes.SET_STATE, u: -1, s: newState }); } }