decrease CSP threshold, move client networking to its own folder
This commit is contained in:
parent
ba989bd7f8
commit
d19da30f6d
@ -1,5 +1,4 @@
|
|||||||
import { Game } from '@engine/Game';
|
import { Game } from '@engine/Game';
|
||||||
import { Entity } from '@engine/entities';
|
|
||||||
import { Grid } from '@engine/structures';
|
import { Grid } from '@engine/structures';
|
||||||
import {
|
import {
|
||||||
WallBounds,
|
WallBounds,
|
||||||
@ -8,128 +7,13 @@ import {
|
|||||||
Physics,
|
Physics,
|
||||||
Input,
|
Input,
|
||||||
Collision,
|
Collision,
|
||||||
NetworkUpdate,
|
NetworkUpdate
|
||||||
SystemNames
|
|
||||||
} from '@engine/systems';
|
} from '@engine/systems';
|
||||||
import {
|
import {
|
||||||
type MessageQueueProvider,
|
ClientMessageProcessor,
|
||||||
type MessagePublisher,
|
ClientSocketMessagePublisher,
|
||||||
type MessageProcessor,
|
ClientSocketMessageQueueProvider
|
||||||
type Message,
|
} from './network';
|
||||||
type EntityAddBody,
|
|
||||||
MessageType,
|
|
||||||
type EntityUpdateBody
|
|
||||||
} from '@engine/network';
|
|
||||||
import { stringify, parse } from '@engine/utils';
|
|
||||||
import { ComponentNames, Control, NetworkUpdateable } from '@engine/components';
|
|
||||||
|
|
||||||
class ClientMessageProcessor implements MessageProcessor {
|
|
||||||
private game: Game;
|
|
||||||
|
|
||||||
constructor(game: Game) {
|
|
||||||
this.game = game;
|
|
||||||
}
|
|
||||||
|
|
||||||
public process(message: Message) {
|
|
||||||
switch (message.type) {
|
|
||||||
case MessageType.NEW_ENTITIES:
|
|
||||||
const entityAdditions = message.body as unknown as EntityAddBody[];
|
|
||||||
entityAdditions.forEach((addBody) => {
|
|
||||||
const entity = Entity.from(
|
|
||||||
addBody.entityName,
|
|
||||||
addBody.id,
|
|
||||||
addBody.args
|
|
||||||
);
|
|
||||||
if (entity.hasComponent(ComponentNames.Control)) {
|
|
||||||
const clientId = this.game.getSystem<Input>(
|
|
||||||
SystemNames.Input
|
|
||||||
).clientId;
|
|
||||||
const control = entity.getComponent<Control>(
|
|
||||||
ComponentNames.Control
|
|
||||||
);
|
|
||||||
|
|
||||||
if (control.controllableBy === clientId) {
|
|
||||||
entity.addComponent(new NetworkUpdateable());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.game.addEntity(entity);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case MessageType.REMOVE_ENTITIES:
|
|
||||||
const ids = message.body as unknown as string[];
|
|
||||||
ids.forEach((id) => this.game.removeEntity(id));
|
|
||||||
break;
|
|
||||||
case MessageType.UPDATE_ENTITIES:
|
|
||||||
const entityUpdates = message.body as unknown as EntityUpdateBody[];
|
|
||||||
entityUpdates.forEach(({ id, args }) => {
|
|
||||||
const entity = this.game.getEntity(id);
|
|
||||||
if (!entity) return;
|
|
||||||
if (entity && entity.hasComponent(ComponentNames.Control)) {
|
|
||||||
const clientId = this.game.getSystem<Input>(
|
|
||||||
SystemNames.Input
|
|
||||||
).clientId;
|
|
||||||
const control = entity.getComponent<Control>(
|
|
||||||
ComponentNames.Control
|
|
||||||
);
|
|
||||||
|
|
||||||
// don't listen to entities which we control
|
|
||||||
if (control.controllableBy == clientId) return;
|
|
||||||
}
|
|
||||||
entity.setFrom(args);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClientSocketMessageQueueProvider implements MessageQueueProvider {
|
|
||||||
private socket: WebSocket;
|
|
||||||
private messages: Message[];
|
|
||||||
|
|
||||||
constructor(socket: WebSocket) {
|
|
||||||
this.socket = socket;
|
|
||||||
this.messages = [];
|
|
||||||
|
|
||||||
this.socket.addEventListener('message', (e) => {
|
|
||||||
const messages = parse<Message[]>(e.data);
|
|
||||||
this.messages = this.messages.concat(messages);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNewMessages() {
|
|
||||||
return this.messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
public clearMessages() {
|
|
||||||
this.messages = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClientSocketMessagePublisher implements MessagePublisher {
|
|
||||||
private socket: WebSocket;
|
|
||||||
private messages: Message[];
|
|
||||||
|
|
||||||
constructor(socket: WebSocket) {
|
|
||||||
this.socket = socket;
|
|
||||||
this.messages = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public addMessage(message: Message) {
|
|
||||||
this.messages.push(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public publish() {
|
|
||||||
if (this.socket.readyState == WebSocket.OPEN) {
|
|
||||||
this.messages.forEach((message: Message) =>
|
|
||||||
this.socket.send(stringify(message))
|
|
||||||
);
|
|
||||||
this.messages = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class JumpStorm {
|
export class JumpStorm {
|
||||||
private game: Game;
|
private game: Game;
|
||||||
@ -148,6 +32,7 @@ export class JumpStorm {
|
|||||||
this.clientId = await this.getAssignedCookie(
|
this.clientId = await this.getAssignedCookie(
|
||||||
`${httpMethod}://${host}/assign`
|
`${httpMethod}://${host}/assign`
|
||||||
);
|
);
|
||||||
|
|
||||||
const socket = new WebSocket(`${wsMethod}://${host}/game`);
|
const socket = new WebSocket(`${wsMethod}://${host}/game`);
|
||||||
const clientSocketMessageQueueProvider =
|
const clientSocketMessageQueueProvider =
|
||||||
new ClientSocketMessageQueueProvider(socket);
|
new ClientSocketMessageQueueProvider(socket);
|
||||||
@ -159,8 +44,6 @@ export class JumpStorm {
|
|||||||
const inputSystem = new Input(this.clientId, clientSocketMessagePublisher);
|
const inputSystem = new Input(this.clientId, clientSocketMessagePublisher);
|
||||||
this.addWindowEventListenersToInputSystem(inputSystem);
|
this.addWindowEventListenersToInputSystem(inputSystem);
|
||||||
|
|
||||||
const grid = new Grid();
|
|
||||||
|
|
||||||
[
|
[
|
||||||
new Physics(),
|
new Physics(),
|
||||||
new NetworkUpdate(
|
new NetworkUpdate(
|
||||||
@ -170,7 +53,7 @@ export class JumpStorm {
|
|||||||
),
|
),
|
||||||
inputSystem,
|
inputSystem,
|
||||||
new FacingDirection(),
|
new FacingDirection(),
|
||||||
new Collision(grid),
|
new Collision(new Grid()),
|
||||||
new WallBounds(),
|
new WallBounds(),
|
||||||
new Render(ctx)
|
new Render(ctx)
|
||||||
].forEach((system) => this.game.addSystem(system));
|
].forEach((system) => this.game.addSystem(system));
|
||||||
|
74
client/src/network/MessageProcessor.ts
Normal file
74
client/src/network/MessageProcessor.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import type { Game } from '@engine/Game';
|
||||||
|
import { ComponentNames, Control, NetworkUpdateable } from '@engine/components';
|
||||||
|
import { Entity } from '@engine/entities';
|
||||||
|
import {
|
||||||
|
MessageType,
|
||||||
|
type Message,
|
||||||
|
type EntityAddBody,
|
||||||
|
type EntityUpdateBody,
|
||||||
|
type MessageProcessor
|
||||||
|
} from '@engine/network';
|
||||||
|
import { Input, SystemNames } from '@engine/systems';
|
||||||
|
|
||||||
|
export class ClientMessageProcessor implements MessageProcessor {
|
||||||
|
private game: Game;
|
||||||
|
|
||||||
|
constructor(game: Game) {
|
||||||
|
this.game = game;
|
||||||
|
}
|
||||||
|
|
||||||
|
public process(message: Message) {
|
||||||
|
switch (message.type) {
|
||||||
|
case MessageType.NEW_ENTITIES:
|
||||||
|
const entityAdditions = message.body as unknown as EntityAddBody[];
|
||||||
|
entityAdditions.forEach((addBody) => {
|
||||||
|
const entity = Entity.from(
|
||||||
|
addBody.entityName,
|
||||||
|
addBody.id,
|
||||||
|
addBody.args
|
||||||
|
);
|
||||||
|
if (entity.hasComponent(ComponentNames.Control)) {
|
||||||
|
const clientId = this.game.getSystem<Input>(
|
||||||
|
SystemNames.Input
|
||||||
|
).clientId;
|
||||||
|
const control = entity.getComponent<Control>(
|
||||||
|
ComponentNames.Control
|
||||||
|
);
|
||||||
|
|
||||||
|
if (control.controllableBy === clientId) {
|
||||||
|
entity.addComponent(new NetworkUpdateable());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.game.addEntity(entity);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case MessageType.REMOVE_ENTITIES:
|
||||||
|
const ids = message.body as unknown as string[];
|
||||||
|
ids.forEach((id) => this.game.removeEntity(id));
|
||||||
|
break;
|
||||||
|
case MessageType.UPDATE_ENTITIES:
|
||||||
|
const entityUpdates = message.body as unknown as EntityUpdateBody[];
|
||||||
|
entityUpdates.forEach(({ id, args }) => {
|
||||||
|
const entity = this.game.getEntity(id);
|
||||||
|
if (!entity) return;
|
||||||
|
|
||||||
|
if (entity && entity.hasComponent(ComponentNames.Control)) {
|
||||||
|
const clientId = this.game.getSystem<Input>(
|
||||||
|
SystemNames.Input
|
||||||
|
).clientId;
|
||||||
|
const control = entity.getComponent<Control>(
|
||||||
|
ComponentNames.Control
|
||||||
|
);
|
||||||
|
|
||||||
|
// don't listen to entities which we control
|
||||||
|
if (control.controllableBy === clientId) return;
|
||||||
|
}
|
||||||
|
entity.setFrom(args);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
client/src/network/MessagePublisher.ts
Normal file
25
client/src/network/MessagePublisher.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import type { Message, MessagePublisher } from '@engine/network';
|
||||||
|
import { stringify } from '@engine/utils';
|
||||||
|
|
||||||
|
export class ClientSocketMessagePublisher implements MessagePublisher {
|
||||||
|
private socket: WebSocket;
|
||||||
|
private messages: Message[];
|
||||||
|
|
||||||
|
constructor(socket: WebSocket) {
|
||||||
|
this.socket = socket;
|
||||||
|
this.messages = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public addMessage(message: Message) {
|
||||||
|
this.messages.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public publish() {
|
||||||
|
if (this.socket.readyState == WebSocket.OPEN) {
|
||||||
|
this.messages.forEach((message: Message) =>
|
||||||
|
this.socket.send(stringify(message))
|
||||||
|
);
|
||||||
|
this.messages = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
client/src/network/MessageQueueReceiver.ts
Normal file
25
client/src/network/MessageQueueReceiver.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import type { Message, MessageQueueProvider } from '@engine/network';
|
||||||
|
import { parse } from '@engine/utils';
|
||||||
|
|
||||||
|
export class ClientSocketMessageQueueProvider implements MessageQueueProvider {
|
||||||
|
private socket: WebSocket;
|
||||||
|
private messages: Message[];
|
||||||
|
|
||||||
|
constructor(socket: WebSocket) {
|
||||||
|
this.socket = socket;
|
||||||
|
this.messages = [];
|
||||||
|
|
||||||
|
this.socket.addEventListener('message', (e) => {
|
||||||
|
const messages = parse<Message[]>(e.data);
|
||||||
|
this.messages = this.messages.concat(messages);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getNewMessages() {
|
||||||
|
return this.messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public clearMessages() {
|
||||||
|
this.messages = [];
|
||||||
|
}
|
||||||
|
}
|
3
client/src/network/index.ts
Normal file
3
client/src/network/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './MessageProcessor';
|
||||||
|
export * from './MessagePublisher';
|
||||||
|
export * from './MessageQueueReceiver';
|
@ -92,7 +92,7 @@ export class Player extends Entity {
|
|||||||
const distance = Math.sqrt(
|
const distance = Math.sqrt(
|
||||||
Math.pow(center.y - myCenter.y, 2) + Math.pow(center.x - myCenter.x, 2)
|
Math.pow(center.y - myCenter.y, 2) + Math.pow(center.x - myCenter.x, 2)
|
||||||
);
|
);
|
||||||
const clientServerPredictionCenterThreshold = 20;
|
const clientServerPredictionCenterThreshold = 15;
|
||||||
if (distance < clientServerPredictionCenterThreshold) center = myCenter;
|
if (distance < clientServerPredictionCenterThreshold) center = myCenter;
|
||||||
|
|
||||||
[
|
[
|
||||||
|
@ -38,7 +38,7 @@ export class GameServer {
|
|||||||
public serve() {
|
public serve() {
|
||||||
if (!this.server)
|
if (!this.server)
|
||||||
this.server = Bun.serve<SessionData>({
|
this.server = Bun.serve<SessionData>({
|
||||||
host: Constants.HOST,
|
hostname: Constants.HOST,
|
||||||
port: Constants.SERVER_PORT,
|
port: Constants.SERVER_PORT,
|
||||||
fetch: (req, srv) => this.fetchHandler(req, srv),
|
fetch: (req, srv) => this.fetchHandler(req, srv),
|
||||||
websocket: {
|
websocket: {
|
||||||
|
Loading…
Reference in New Issue
Block a user