57 lines
2 KiB
TypeScript
57 lines
2 KiB
TypeScript
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<LocalInput, State> = Callbag<ServerMessage<LocalInput[], State>, ClientMessage<LocalInput, State>>;
|
|
|
|
/** Stub loopback server that handles multiple clients, for schemes where GlobalInput = LocalInput[] */
|
|
export class LoopbackServer<LocalInput, State> {
|
|
|
|
private nextClientId = 0;
|
|
private inputBuffer: LocalInput[] = [];
|
|
|
|
private heartbeat = pipe(
|
|
interval(INPUT_FREQUENCY),
|
|
map(() => ({
|
|
t: MessageTypes.INPUT,
|
|
i: this.inputBuffer.slice()
|
|
} as ServerMessage<LocalInput[], State>)),
|
|
);
|
|
private broadcast = makeSubject<ServerMessage<LocalInput[], State>>();
|
|
|
|
private serverFeed = share(merge(this.heartbeat, this.broadcast));
|
|
|
|
public readonly socket = defer(() => {
|
|
const playerNumber = this.nextClientId++;
|
|
return pipe(
|
|
this.serverFeed,
|
|
catchTalkback<ServerMessage<LocalInput[], State>, ClientMessage<LocalInput, State>>(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<State>) {
|
|
this.broadcast(1, { t: MessageTypes.SET_STATE, u: -1, s: newState });
|
|
}
|
|
}
|