import Client from '@/net/client.js'; import {encode} from '@/net/packets/index.js'; import {CLIENT_PREDICTION} from '@/util/constants.js'; import {withResolvers} from '@/util/promise.js'; export default class RemoteClient extends Client { constructor() { super(); if (CLIENT_PREDICTION) { this.worker = undefined; } else { this.socket = undefined; } } async connect(host) { if (CLIENT_PREDICTION) { this.worker = new Worker( new URL('./prediction.js', import.meta.url), {type: 'module'}, ); this.worker.postMessage({host}); this.worker.onmessage = (event) => { this.throughput.$$down += event.data.byteLength; this.accept(event.data); }; } else { const url = new URL(`wss://${host}/ws`) this.socket = new WebSocket(url.href); this.socket.binaryType = 'arraybuffer'; const onMessage = (event) => { this.throughput.$$down += event.data.byteLength; this.accept(event.data); } const {promise, resolve} = withResolvers(); this.socket.addEventListener('open', resolve); this.socket.addEventListener('error', () => { this.accept(encode({type: 'ConnectionStatus', payload: 'aborted'})); }); await promise; this.socket.removeEventListener('open', resolve); this.socket.addEventListener('message', onMessage); this.socket.addEventListener('close', () => { this.accept(encode({type: 'ConnectionStatus', payload: 'aborted'})); }); this.accept(encode({type: 'ConnectionStatus', payload: 'connected'})); } } disconnect() { if (CLIENT_PREDICTION) { this.worker.terminate(); } else { this.socket.close(); } } transmit(packed) { this.throughput.$$up += packed.byteLength; if (CLIENT_PREDICTION) { this.worker.postMessage(packed); } else { this.socket.send(packed); } } }