refactor: client code
This commit is contained in:
parent
e8c9633a4e
commit
11457a3c75
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
4
app/silphius/net/constants.js
Normal file
4
app/silphius/net/constants.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
export const Flow = {
|
||||
UP: 0,
|
||||
DOWN: 1,
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user