base2020/src/Net/LoopbackServer.ts

58 lines
2 KiB
TypeScript
Raw Normal View History

2020-02-16 05:42:58 +00:00
import { Callbag } from "callbag";
import pipe from "callbag-pipe";
import share from "callbag-share";
2020-02-16 05:42:58 +00:00
import { INPUT_FREQUENCY } from "../Ecs/Lockstep";
import { catchTalkback, defer, interval, makeSubject, map, merge } from "../Utilities/Callbag";
import { ClientMessage, MessageTypes, Server, ServerMessage } from "./LockstepClient";
2020-02-16 05:42:58 +00:00
type Client<LocalInput, State> = Callbag<ServerMessage<LocalInput[], State>, ClientMessage<LocalInput, State>>;
2020-02-16 05:42:58 +00:00
/** 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;
}
})
);
2020-02-16 05:42:58 +00:00
});
public resetState(newState: Partial<State>) {
this.broadcast(1, { t: MessageTypes.SET_STATE, u: -1, s: newState });
}
}