diff --git a/app/silphius/client/local.js b/app/silphius/client/local.js index 8cecda6..f6bb8fd 100644 --- a/app/silphius/client/local.js +++ b/app/silphius/client/local.js @@ -1,92 +1,27 @@ import Client from '@/silphius/net/client.js'; -import {decode, encode} from '@/silphius/net/packets/index.js'; -import {CLIENT_INTERPOLATION, CLIENT_PREDICTION} from '@/lib/constants.js'; export default class LocalClient extends Client { server = null; - interpolator = null; - predictor = null; async connect() { + await super.connect(); this.server = new Worker( new URL('../server/worker.js', import.meta.url), {type: 'module'}, ); - if (CLIENT_INTERPOLATION) { - this.interpolator = new Worker( - new URL('./interpolator.js', import.meta.url), - {type: 'module'}, - ); - this.interpolator.addEventListener('message', (event) => { - const packet = event.data; - if (CLIENT_PREDICTION) { - this.predictor.postMessage([1, packet]); - } - else { - this.accept(packet); - } - }); - } - if (CLIENT_PREDICTION) { - this.predictor = new Worker( - new URL('./predictor.js', import.meta.url), - {type: 'module'}, - ); - // loaded - await new Promise((resolve) => { - this.predictor.addEventListener('message', resolve, {once: true}); - }); - this.predictor.addEventListener('message', (event) => { - const [flow, packet] = event.data; - switch (flow) { - case 0: { - const packed = encode(packet); - this.throughput.$$up += packed.byteLength; - this.server.postMessage(packed); - break; - } - case 1: { - this.accept(packet); - break; - } - } - }); - } this.server.addEventListener('message', (event) => { if (0 === event.data) { this.server.terminate(); this.server = null; return; } - this.throughput.$$down += event.data.byteLength; - const packet = decode(event.data); - if (CLIENT_INTERPOLATION) { - this.interpolator.postMessage(packet); - } - else if (CLIENT_PREDICTION) { - this.predictor.postMessage([1, packet]); - } - else { - this.accept(packet); - } + this.receive(event.data); }); } disconnect() { + super.disconnect(); this.server.postMessage(0); - if (CLIENT_INTERPOLATION) { - this.interpolator.terminate(); - } - if (CLIENT_PREDICTION) { - this.predictor.terminate(); - } } - transmit(packet) { - if (CLIENT_PREDICTION) { - this.predictor.postMessage([0, packet]); - } - else { - const packed = encode(packet); - this.throughput.$$up += packed.byteLength; - this.server.postMessage(packed); - } + transmit(packed) { + this.server.postMessage(packed); } } diff --git a/app/silphius/client/remote.js b/app/silphius/client/remote.js index 9028339..6dbc819 100644 --- a/app/silphius/client/remote.js +++ b/app/silphius/client/remote.js @@ -1,66 +1,13 @@ import Client from '@/silphius/net/client.js'; -import {decode, encode} from '@/silphius/net/packets/index.js'; -import {CLIENT_INTERPOLATION, CLIENT_PREDICTION} from '@/lib/constants.js'; export default class RemoteClient extends Client { socket = null; - interpolator = null; - predictor = null; async connect(host) { - if (CLIENT_INTERPOLATION) { - this.interpolator = new Worker( - new URL('./interpolator.js', import.meta.url), - {type: 'module'}, - ); - this.interpolator.addEventListener('message', (event) => { - const packet = event.data; - if (CLIENT_PREDICTION) { - this.predictor.postMessage([1, packet]); - } - else { - this.accept(packet); - } - }); - } - if (CLIENT_PREDICTION) { - this.predictor = new Worker( - new URL('./predictor.js', import.meta.url), - {type: 'module'}, - ); - // loaded - await new Promise((resolve) => { - this.predictor.addEventListener('message', resolve, {once: true}); - }); - this.predictor.addEventListener('message', (event) => { - const [flow, packet] = event.data; - switch (flow) { - case 0: { - const packed = encode(packet); - this.throughput.$$up += packed.byteLength; - this.socket.send(packed); - break; - } - case 1: { - this.accept(packet); - break; - } - } - }); - } + await super.connect(); this.socket = new WebSocket(`//${host}/silphius`); this.socket.binaryType = 'arraybuffer'; this.socket.addEventListener('message', (event) => { - this.throughput.$$down += event.data.byteLength; - const packet = decode(event.data); - if (CLIENT_INTERPOLATION) { - this.interpolator.postMessage(packet); - } - else if (CLIENT_PREDICTION) { - this.predictor.postMessage([1, packet]); - } - else { - this.accept(packet); - } + this.receive(event.data); }); this.socket.addEventListener('close', () => { this.accept({type: 'ConnectionStatus', payload: 'aborted'}); @@ -72,22 +19,7 @@ export default class RemoteClient extends Client { this.accept({type: 'ConnectionStatus', payload: 'connected'}); }); } - disconnect() { - if (CLIENT_INTERPOLATION) { - this.interpolator.terminate(); - } - if (CLIENT_PREDICTION) { - this.predictor.terminate(); - } - } - transmit(packet) { - if (CLIENT_PREDICTION) { - this.predictor.postMessage([0, packet]); - } - else { - const packed = encode(packet); - this.throughput.$$up += packed.byteLength; - this.socket.send(packed); - } + transmit(packed) { + this.socket.send(packed); } } diff --git a/app/silphius/net/client.js b/app/silphius/net/client.js index a2183a2..facebec 100644 --- a/app/silphius/net/client.js +++ b/app/silphius/net/client.js @@ -1,8 +1,13 @@ -import {CLIENT_LATENCY, CLIENT_PREDICTION} from '@/lib/constants.js'; +import {CLIENT_LATENCY, CLIENT_INTERPOLATION, CLIENT_PREDICTION} from '@/lib/constants.js'; import EventEmitter from '@/lib/event-emitter.js'; +import {decode, encode} from '@/silphius/net/packets/index.js'; + +import {Flow} from './constants.js'; export default class Client { emitter = new EventEmitter(); + interpolator = null; + predictor = null; rtt = 0; throughput = {$$down: 0, down: 0, $$up: 0, up: 0}; constructor() { @@ -24,17 +29,90 @@ export default class Client { addPacketListener(type, listener) { this.emitter.addListener(type, listener); } + async connect() { + if (CLIENT_INTERPOLATION) { + this.interpolator = new Worker( + new URL('./interpolator.js', import.meta.url), + {type: 'module'}, + ); + this.interpolator.addEventListener('message', (event) => { + const packet = event.data; + if (CLIENT_PREDICTION) { + this.predictor.postMessage([1, packet]); + } + else { + this.accept(packet); + } + }); + } + if (CLIENT_PREDICTION) { + this.predictor = new Worker( + new URL('./predictor.js', import.meta.url), + {type: 'module'}, + ); + // loaded + await new Promise((resolve) => { + this.predictor.addEventListener('message', resolve, {once: true}); + }); + this.predictor.addEventListener('message', (event) => { + const [flow, packet] = event.data; + switch (flow) { + case Flow.UP: { + const packed = encode(packet); + this.throughput.$$up += packed.byteLength; + this.transmit(packed); + break; + } + case Flow.DOWN: { + this.accept(packet); + break; + } + } + }); + } + } + disconnect() { + if (CLIENT_INTERPOLATION) { + this.interpolator?.terminate(); + this.interpolator = null; + } + if (CLIENT_PREDICTION) { + this.predictor?.terminate(); + this.predictor = null; + } + } + receive(packed) { + this.throughput.$$down += packed.byteLength; + const packet = decode(packed); + if (CLIENT_INTERPOLATION) { + this.interpolator.postMessage(packet); + } + else if (CLIENT_PREDICTION) { + this.predictor.postMessage([Flow.DOWN, packet]); + } + else { + this.accept(packet); + } + } removePacketListener(type, listener) { this.emitter.removeListener(type, listener); } send(packet) { - if (CLIENT_LATENCY > 0 && !CLIENT_PREDICTION) { - setTimeout(() => { - this.transmit(packet); - }, CLIENT_LATENCY); + const transmitOrPredict = () => { + if (CLIENT_PREDICTION) { + this.predictor.postMessage([Flow.UP, packet]); + } + else { + const packed = encode(packet); + this.throughput.$$up += packed.byteLength; + this.transmit(packed); + } + } + if (CLIENT_LATENCY > 0) { + setTimeout(transmitOrPredict, CLIENT_LATENCY); } else { - this.transmit(packet); + transmitOrPredict(); } } } diff --git a/app/silphius/net/constants.js b/app/silphius/net/constants.js new file mode 100644 index 0000000..9960ee0 --- /dev/null +++ b/app/silphius/net/constants.js @@ -0,0 +1,4 @@ +export const Flow = { + UP: 0, + DOWN: 1, +}; diff --git a/app/silphius/client/interpolator.js b/app/silphius/net/interpolator.js similarity index 100% rename from app/silphius/client/interpolator.js rename to app/silphius/net/interpolator.js diff --git a/app/silphius/client/predictor.js b/app/silphius/net/predictor.js similarity index 90% rename from app/silphius/client/predictor.js rename to app/silphius/net/predictor.js index 5412608..e6ef0fa 100644 --- a/app/silphius/client/predictor.js +++ b/app/silphius/net/predictor.js @@ -3,15 +3,18 @@ import Ecs from '@/silphius/ecs/ecs.js'; import Systems from '@/silphius/ecs/systems/index.js'; import {get, loadResources, readAsset} from '@/lib/resources.js'; +import {Flow} from './constants.js'; + class PredictionEcs extends Ecs { readAsset(path) { return readAsset(path) ?? new ArrayBuffer(0); } } -const Flow = { - UP: 0, - DOWN: 1, +const Action = { + ACTIVE: 0, + FINISHING: 1, + FINISHED: 2, }; const actions = new Map(); @@ -24,7 +27,7 @@ function applyClientActions(elapsed) { const {Controlled} = main; const finished = []; for (const [id, action] of actions) { - if (0 === action.finished && !action.ack) { + if (Action.ACTIVE === action.state && !action.ack) { if (!Controlled.locked) { switch (action.action.type) { case 'moveUp': @@ -37,7 +40,7 @@ function applyClientActions(elapsed) { } } } - if (1 === action.finished) { + if (Action.FINISHING === action.state) { if (!Controlled.locked) { switch (action.action.type) { case 'moveUp': @@ -49,12 +52,12 @@ function applyClientActions(elapsed) { } } } - action.finished = 2; + action.state = Action.FINISHED; } if (!action.ack) { action.stop += elapsed; } - if (action.ack && 2 === action.finished) { + if (action.ack && Action.FINISHED === action.state) { action.start += elapsed; if (action.start >= action.stop) { finished.push(id); @@ -85,7 +88,7 @@ onmessage = (event) => { if (0 === packet.payload.value) { const ack = pending.get(packet.payload.type); const action = actions.get(ack); - action.finished = 1; + action.state = Action.FINISHING; pending.delete(packet.payload.type); } else { @@ -93,7 +96,7 @@ onmessage = (event) => { const tx = { action: packet.payload, ack: false, - finished: 0, + state: 0, start: now, stop: now, }; @@ -106,7 +109,7 @@ onmessage = (event) => { break; } } - postMessage([0, packet]); + postMessage([Flow.UP, packet]); break; } case Flow.DOWN: { @@ -154,7 +157,7 @@ onmessage = (event) => { break; } } - postMessage([1, packet]); + postMessage([Flow.DOWN, packet]); break; } }