Implement connection to websocket server
This commit is contained in:
parent
6491588223
commit
e9c73ae998
6 changed files with 79 additions and 4 deletions
8
package-lock.json
generated
8
package-lock.json
generated
|
@ -2685,6 +2685,14 @@
|
||||||
"callbag-share": "^1.1.1"
|
"callbag-share": "^1.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"callbag-create": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/callbag-create/-/callbag-create-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-ypHk+Pdqq0Cmgb7+kszctTHWuqLEX1dTNL0BMWld68ARtEtbGMnikzTY5A4oWc1tgZGixtjCx5cpc3l5aUyUAg==",
|
||||||
|
"requires": {
|
||||||
|
"callbag": "1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"callbag-map": {
|
"callbag-map": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/callbag-map/-/callbag-map-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/callbag-map/-/callbag-map-1.1.0.tgz",
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"callbag": "^1.2.0",
|
"callbag": "^1.2.0",
|
||||||
"callbag-animation-frames": "^2.1.0",
|
"callbag-animation-frames": "^2.1.0",
|
||||||
|
"callbag-create": "^2.1.0",
|
||||||
"callbag-map": "^1.1.0",
|
"callbag-map": "^1.1.0",
|
||||||
"callbag-pipe": "^1.2.0",
|
"callbag-pipe": "^1.2.0",
|
||||||
"callbag-share": "^1.2.0",
|
"callbag-share": "^1.2.0",
|
||||||
|
|
3
plan.txt
3
plan.txt
|
@ -1,5 +1,8 @@
|
||||||
Open:
|
Open:
|
||||||
- Insecured websocket server implementation
|
- Insecured websocket server implementation
|
||||||
|
- desynced on join
|
||||||
|
- reset on join
|
||||||
|
- sync to op on join
|
||||||
- Cloneable RNG that goes in state (use MurmurHash3 finalizer in counter mode?)
|
- Cloneable RNG that goes in state (use MurmurHash3 finalizer in counter mode?)
|
||||||
- remove all random() calls
|
- remove all random() calls
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,15 @@
|
||||||
|
|
||||||
|
export type Jsonified<T> = {
|
||||||
|
[K in keyof T]: JsonEncoded<T[K]>;
|
||||||
|
};
|
||||||
|
export type JsonEncoded<T> =
|
||||||
|
T extends Function ? never
|
||||||
|
: T extends Date ? string
|
||||||
|
: T extends (infer U)[] ? JsonEncoded<U>[]
|
||||||
|
: T extends Record<string, any> ? Jsonified<T>
|
||||||
|
: T
|
||||||
|
;
|
||||||
|
|
||||||
export type Store<T extends Component<T>> = Record<number, T>;
|
export type Store<T extends Component<T>> = Record<number, T>;
|
||||||
export interface Clone<T> {
|
export interface Clone<T> {
|
||||||
clone(): T;
|
clone(): T;
|
||||||
|
|
10
src/index.ts
10
src/index.ts
|
@ -3,7 +3,8 @@ import { KeyName } from "./applet/Keyboard";
|
||||||
import { BindTests } from "./ecs/test";
|
import { BindTests } from "./ecs/test";
|
||||||
import { Data } from "./game/GameComponents";
|
import { Data } from "./game/GameComponents";
|
||||||
import { Main } from "./game/Main";
|
import { Main } from "./game/Main";
|
||||||
import { LoopbackServer } from "./net/LoopbackServer";
|
import { Connection } from "./net/Connection";
|
||||||
|
import {} from "./net/LoopbackServer";
|
||||||
|
|
||||||
/* // Hot Module Reloading stub, if that's viable
|
/* // Hot Module Reloading stub, if that's viable
|
||||||
* declare const module: any;
|
* declare const module: any;
|
||||||
|
@ -16,8 +17,9 @@ import { LoopbackServer } from "./net/LoopbackServer";
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const server = new LoopbackServer<KeyName[], Data>();
|
Select(".GameCanvas").forEachCanvas((c, cx, keys) => {
|
||||||
|
const connection = new Connection<KeyName[], Data>("ws://localhost:9090/");
|
||||||
Select(".GameCanvas").forEachCanvas((c, cx, keys) => new Main(c, cx, keys, server.socket));
|
new Main(c, cx, keys, connection.socket);
|
||||||
|
});
|
||||||
|
|
||||||
BindTests();
|
BindTests();
|
||||||
|
|
50
src/net/Connection.ts
Normal file
50
src/net/Connection.ts
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import { Callbag, Source } from "callbag";
|
||||||
|
import create from "callbag-create";
|
||||||
|
import pipe from "callbag-pipe";
|
||||||
|
import share from "callbag-share";
|
||||||
|
|
||||||
|
import { Jsonified } from "../ecs/Data";
|
||||||
|
import { catchTalkback, defer, interval, makeSubject, map, merge } from "../utilities/Callbag";
|
||||||
|
import { ClientMessage, MessageTypes, ServerMessage } from "./LockstepClient";
|
||||||
|
|
||||||
|
type Server<LocalInput, State> = Callbag<ClientMessage<LocalInput, State>, ServerMessage<LocalInput[], State>>;
|
||||||
|
|
||||||
|
/** Connection to a websocket server that handles multiple clients, for schemes where GlobalInput = LocalInput[] */
|
||||||
|
export class Connection<LocalInput, State> {
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
private url: string
|
||||||
|
) { }
|
||||||
|
|
||||||
|
public readonly socket = defer(() => {
|
||||||
|
const ws = new WebSocket(this.url);
|
||||||
|
|
||||||
|
const source: Source<ServerMessage<LocalInput[], State>> = create((data, { }, close) => {
|
||||||
|
ws.onopen = () => {
|
||||||
|
// fake a HELO message & set state message until the server actually sends them
|
||||||
|
data({ t: MessageTypes.META, helo: "Websocket Server" });
|
||||||
|
data({ t: MessageTypes.SET_STATE, u: 0, s: {} });
|
||||||
|
};
|
||||||
|
ws.onmessage = msg => {
|
||||||
|
const decoded: Jsonified<ServerMessage<LocalInput[], State>> = JSON.parse(msg.data);
|
||||||
|
data(decoded as ServerMessage<LocalInput[], State>);
|
||||||
|
};
|
||||||
|
ws.onclose = () => {
|
||||||
|
close();
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
// cleanup
|
||||||
|
ws.close();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return pipe(
|
||||||
|
source,
|
||||||
|
catchTalkback((message: ClientMessage<LocalInput, State>) => {
|
||||||
|
const encoded = JSON.stringify(message);
|
||||||
|
ws.send(encoded);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in a new issue