make next update interval a property on network update component instead of inheritable attribute on entities

This commit is contained in:
Elizabeth Hunt 2023-09-02 14:40:46 -06:00
parent c551f519ca
commit 29ba1c29d7
Signed by: simponic
GPG Key ID: 52B3774857EB24B1
7 changed files with 42 additions and 33 deletions

View File

@ -16,6 +16,7 @@ export class BoundingBox extends Component {
}
public isCollidingWith(box: BoundingBox): boolean {
// optimization; when neither rotates just check if they overlap
if (this.rotation == 0 && box.rotation == 0) {
const thisTopLeft = this.getTopLeft();
const thisBottomRight = this.getBottomRight();

View File

@ -1,7 +1,23 @@
import { Component, ComponentNames } from '.';
export class NetworkUpdateable extends Component {
constructor() {
static DEFAULT_UPDATE_JITTER_MS = 30;
static DEFAULT_THRESHOLD_TIME_MS = 20;
public updateThreshold: number;
public jitter: number;
constructor(
updateThreshold = NetworkUpdateable.DEFAULT_THRESHOLD_TIME_MS,
jitter = NetworkUpdateable.DEFAULT_UPDATE_JITTER_MS
) {
super(ComponentNames.NetworkUpdateable);
this.updateThreshold = updateThreshold;
this.jitter = jitter;
}
public getNextUpdateTime() {
return Math.random() * this.jitter + this.updateThreshold;
}
}

View File

@ -1,8 +1,7 @@
import { EntityNames, Floor, Player } from '.';
import { type Component } from '../components';
const randomId = () =>
(performance.now() + Math.random() * 10_000_000).toString();
const randomId = () => (Math.random() * 1_000_000_000).toString();
export abstract class Entity {
public id: string;
@ -59,6 +58,4 @@ export abstract class Entity {
public abstract setFrom(args: Record<string, any>): void;
public abstract serialize(): Record<string, any>;
public abstract getNextUpdateInterval(): number;
}

View File

@ -17,7 +17,7 @@ export class Floor extends Entity {
this.addComponent(
new Sprite(
IMAGES.get((Floor.spriteSpec?.states?.get(width) as SpriteSpec).sheet),
IMAGES.get(Floor.spriteSpec!.states!.get(width)!.sheet!)!,
{ x: 0, y: 0 },
{ width, height: Floor.spriteSpec.height },
Floor.spriteSpec.msPerFrame,
@ -45,8 +45,4 @@ export class Floor extends Entity {
)
);
}
public getNextUpdateInterval() {
return Math.random() * 500;
}
}

View File

@ -60,7 +60,7 @@ export class Player extends Entity {
const [leftSprite, rightSprite] = [Direction.LEFT, Direction.RIGHT].map(
(direction) =>
new Sprite(
IMAGES.get(Player.spriteSpec.states?.get(direction)?.sheet as string),
IMAGES.get(Player.spriteSpec.states!.get(direction)!.sheet!)!,
{ x: 0, y: 0 },
{ width: Player.spriteSpec.width, height: Player.spriteSpec.height },
Player.spriteSpec.msPerFrame,
@ -102,8 +102,4 @@ export class Player extends Entity {
new BoundingBox(center, boundingBox.dimension, boundingBox.rotation)
].forEach((component) => this.addComponent(component));
}
public getNextUpdateInterval() {
return Math.random() * 30 + 50;
}
}

View File

@ -1,6 +1,6 @@
import { System, SystemNames } from '.';
import { Game } from '../Game';
import { ComponentNames } from '../components';
import { ComponentNames, NetworkUpdateable } from '../components';
import {
type MessageQueueProvider,
type MessagePublisher,
@ -55,15 +55,20 @@ export class NetworkUpdate extends System {
// 2. send entity updates
const updateMessages: EntityUpdateBody[] = [];
// todo: figure out if we can use the controllable component to determine if we should publish an update
game.forEachEntityWithComponent(
ComponentNames.NetworkUpdateable,
(entity) => {
const networkUpdateableComponent =
entity.getComponent<NetworkUpdateable>(
ComponentNames.NetworkUpdateable
);
const nextUpdateTime = networkUpdateableComponent.getNextUpdateTime();
const newHash = stringify(entity.serialize());
let updateInfo: EntityUpdateInfo = this.entityUpdateInfo.get(
entity.id
) ?? {
timer: this.getNextUpdateTimeMs(),
timer: nextUpdateTime,
hash: newHash
};
@ -71,13 +76,11 @@ export class NetworkUpdate extends System {
updateInfo.timer -= dt;
this.entityUpdateInfo.set(entity.id, updateInfo);
if (updateInfo.timer > 0) return;
updateInfo.timer = entity.getNextUpdateInterval();
updateInfo.timer = nextUpdateTime;
this.entityUpdateInfo.set(entity.id, updateInfo);
// maybe update if hash is not consitent
if (updateInfo.hash == newHash) {
return;
}
// maybe update, if hash is not consistent
if (updateInfo.hash == newHash) return;
updateInfo.hash = newHash;
this.entityUpdateInfo.set(entity.id, updateInfo);
@ -102,7 +105,7 @@ export class NetworkUpdate extends System {
}
}
private getNextUpdateInterval(): number {
return Math.random() * 30;
private getNextUpdateInterval() {
return Math.random() * 30 + 20;
}
}

View File

@ -42,7 +42,9 @@ export class GameServer {
fetch: (req, srv) => this.fetchHandler(req, srv),
websocket: {
open: (ws) => this.openWebsocket(ws),
message: (ws, msg) => this.websocketMessage(ws, msg),
message: (ws, msg) => {
if (typeof msg === 'string') this.websocketMessage(ws, msg);
},
close: (ws) => this.closeWebsocket(ws)
}
});
@ -54,21 +56,19 @@ export class GameServer {
private websocketMessage(
websocket: ServerWebSocket<SessionData>,
message: string | Uint8Array
message: string
) {
if (typeof message == 'string') {
const receivedMessage = parse<ServerMessage>(message);
receivedMessage.sessionData = websocket.data;
this.messageReceiver.addMessage(receivedMessage);
}
}
private closeWebsocket(websocket: ServerWebSocket<SessionData>) {
const { sessionId } = websocket.data;
const sessionEntities =
this.sessionManager.getSession(sessionId)!.controllableEntities;
this.sessionManager.getSession(sessionId)?.controllableEntities;
this.sessionManager.removeSession(sessionId);
if (!sessionEntities) return;