refactor: client code
This commit is contained in:
parent
e8c9633a4e
commit
11457a3c75
|
@ -1,92 +1,27 @@
|
||||||
import Client from '@/silphius/net/client.js';
|
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 {
|
export default class LocalClient extends Client {
|
||||||
server = null;
|
server = null;
|
||||||
interpolator = null;
|
|
||||||
predictor = null;
|
|
||||||
async connect() {
|
async connect() {
|
||||||
|
await super.connect();
|
||||||
this.server = new Worker(
|
this.server = new Worker(
|
||||||
new URL('../server/worker.js', import.meta.url),
|
new URL('../server/worker.js', import.meta.url),
|
||||||
{type: 'module'},
|
{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) => {
|
this.server.addEventListener('message', (event) => {
|
||||||
if (0 === event.data) {
|
if (0 === event.data) {
|
||||||
this.server.terminate();
|
this.server.terminate();
|
||||||
this.server = null;
|
this.server = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.throughput.$$down += event.data.byteLength;
|
this.receive(event.data);
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
disconnect() {
|
disconnect() {
|
||||||
|
super.disconnect();
|
||||||
this.server.postMessage(0);
|
this.server.postMessage(0);
|
||||||
if (CLIENT_INTERPOLATION) {
|
|
||||||
this.interpolator.terminate();
|
|
||||||
}
|
|
||||||
if (CLIENT_PREDICTION) {
|
|
||||||
this.predictor.terminate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
transmit(packet) {
|
transmit(packed) {
|
||||||
if (CLIENT_PREDICTION) {
|
this.server.postMessage(packed);
|
||||||
this.predictor.postMessage([0, packet]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const packed = encode(packet);
|
|
||||||
this.throughput.$$up += packed.byteLength;
|
|
||||||
this.server.postMessage(packed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +1,13 @@
|
||||||
import Client from '@/silphius/net/client.js';
|
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 {
|
export default class RemoteClient extends Client {
|
||||||
socket = null;
|
socket = null;
|
||||||
interpolator = null;
|
|
||||||
predictor = null;
|
|
||||||
async connect(host) {
|
async connect(host) {
|
||||||
if (CLIENT_INTERPOLATION) {
|
await super.connect();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.socket = new WebSocket(`//${host}/silphius`);
|
this.socket = new WebSocket(`//${host}/silphius`);
|
||||||
this.socket.binaryType = 'arraybuffer';
|
this.socket.binaryType = 'arraybuffer';
|
||||||
this.socket.addEventListener('message', (event) => {
|
this.socket.addEventListener('message', (event) => {
|
||||||
this.throughput.$$down += event.data.byteLength;
|
this.receive(event.data);
|
||||||
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.socket.addEventListener('close', () => {
|
this.socket.addEventListener('close', () => {
|
||||||
this.accept({type: 'ConnectionStatus', payload: 'aborted'});
|
this.accept({type: 'ConnectionStatus', payload: 'aborted'});
|
||||||
|
@ -72,22 +19,7 @@ export default class RemoteClient extends Client {
|
||||||
this.accept({type: 'ConnectionStatus', payload: 'connected'});
|
this.accept({type: 'ConnectionStatus', payload: 'connected'});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
disconnect() {
|
transmit(packed) {
|
||||||
if (CLIENT_INTERPOLATION) {
|
this.socket.send(packed);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 EventEmitter from '@/lib/event-emitter.js';
|
||||||
|
import {decode, encode} from '@/silphius/net/packets/index.js';
|
||||||
|
|
||||||
|
import {Flow} from './constants.js';
|
||||||
|
|
||||||
export default class Client {
|
export default class Client {
|
||||||
emitter = new EventEmitter();
|
emitter = new EventEmitter();
|
||||||
|
interpolator = null;
|
||||||
|
predictor = null;
|
||||||
rtt = 0;
|
rtt = 0;
|
||||||
throughput = {$$down: 0, down: 0, $$up: 0, up: 0};
|
throughput = {$$down: 0, down: 0, $$up: 0, up: 0};
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -24,17 +29,90 @@ export default class Client {
|
||||||
addPacketListener(type, listener) {
|
addPacketListener(type, listener) {
|
||||||
this.emitter.addListener(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) {
|
removePacketListener(type, listener) {
|
||||||
this.emitter.removeListener(type, listener);
|
this.emitter.removeListener(type, listener);
|
||||||
}
|
}
|
||||||
send(packet) {
|
send(packet) {
|
||||||
if (CLIENT_LATENCY > 0 && !CLIENT_PREDICTION) {
|
const transmitOrPredict = () => {
|
||||||
setTimeout(() => {
|
if (CLIENT_PREDICTION) {
|
||||||
this.transmit(packet);
|
this.predictor.postMessage([Flow.UP, packet]);
|
||||||
}, CLIENT_LATENCY);
|
}
|
||||||
|
else {
|
||||||
|
const packed = encode(packet);
|
||||||
|
this.throughput.$$up += packed.byteLength;
|
||||||
|
this.transmit(packed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (CLIENT_LATENCY > 0) {
|
||||||
|
setTimeout(transmitOrPredict, CLIENT_LATENCY);
|
||||||
}
|
}
|
||||||
else {
|
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 Systems from '@/silphius/ecs/systems/index.js';
|
||||||
import {get, loadResources, readAsset} from '@/lib/resources.js';
|
import {get, loadResources, readAsset} from '@/lib/resources.js';
|
||||||
|
|
||||||
|
import {Flow} from './constants.js';
|
||||||
|
|
||||||
class PredictionEcs extends Ecs {
|
class PredictionEcs extends Ecs {
|
||||||
readAsset(path) {
|
readAsset(path) {
|
||||||
return readAsset(path) ?? new ArrayBuffer(0);
|
return readAsset(path) ?? new ArrayBuffer(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Flow = {
|
const Action = {
|
||||||
UP: 0,
|
ACTIVE: 0,
|
||||||
DOWN: 1,
|
FINISHING: 1,
|
||||||
|
FINISHED: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
const actions = new Map();
|
const actions = new Map();
|
||||||
|
@ -24,7 +27,7 @@ function applyClientActions(elapsed) {
|
||||||
const {Controlled} = main;
|
const {Controlled} = main;
|
||||||
const finished = [];
|
const finished = [];
|
||||||
for (const [id, action] of actions) {
|
for (const [id, action] of actions) {
|
||||||
if (0 === action.finished && !action.ack) {
|
if (Action.ACTIVE === action.state && !action.ack) {
|
||||||
if (!Controlled.locked) {
|
if (!Controlled.locked) {
|
||||||
switch (action.action.type) {
|
switch (action.action.type) {
|
||||||
case 'moveUp':
|
case 'moveUp':
|
||||||
|
@ -37,7 +40,7 @@ function applyClientActions(elapsed) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (1 === action.finished) {
|
if (Action.FINISHING === action.state) {
|
||||||
if (!Controlled.locked) {
|
if (!Controlled.locked) {
|
||||||
switch (action.action.type) {
|
switch (action.action.type) {
|
||||||
case 'moveUp':
|
case 'moveUp':
|
||||||
|
@ -49,12 +52,12 @@ function applyClientActions(elapsed) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
action.finished = 2;
|
action.state = Action.FINISHED;
|
||||||
}
|
}
|
||||||
if (!action.ack) {
|
if (!action.ack) {
|
||||||
action.stop += elapsed;
|
action.stop += elapsed;
|
||||||
}
|
}
|
||||||
if (action.ack && 2 === action.finished) {
|
if (action.ack && Action.FINISHED === action.state) {
|
||||||
action.start += elapsed;
|
action.start += elapsed;
|
||||||
if (action.start >= action.stop) {
|
if (action.start >= action.stop) {
|
||||||
finished.push(id);
|
finished.push(id);
|
||||||
|
@ -85,7 +88,7 @@ onmessage = (event) => {
|
||||||
if (0 === packet.payload.value) {
|
if (0 === packet.payload.value) {
|
||||||
const ack = pending.get(packet.payload.type);
|
const ack = pending.get(packet.payload.type);
|
||||||
const action = actions.get(ack);
|
const action = actions.get(ack);
|
||||||
action.finished = 1;
|
action.state = Action.FINISHING;
|
||||||
pending.delete(packet.payload.type);
|
pending.delete(packet.payload.type);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -93,7 +96,7 @@ onmessage = (event) => {
|
||||||
const tx = {
|
const tx = {
|
||||||
action: packet.payload,
|
action: packet.payload,
|
||||||
ack: false,
|
ack: false,
|
||||||
finished: 0,
|
state: 0,
|
||||||
start: now,
|
start: now,
|
||||||
stop: now,
|
stop: now,
|
||||||
};
|
};
|
||||||
|
@ -106,7 +109,7 @@ onmessage = (event) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
postMessage([0, packet]);
|
postMessage([Flow.UP, packet]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Flow.DOWN: {
|
case Flow.DOWN: {
|
||||||
|
@ -154,7 +157,7 @@ onmessage = (event) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
postMessage([1, packet]);
|
postMessage([Flow.DOWN, packet]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user