Fix issues
This commit is contained in:
parent
57d7009342
commit
42e4de28b5
15 changed files with 175 additions and 145 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "declared-server",
|
||||
"version": "0.0.12",
|
||||
"version": "0.0.13",
|
||||
"description": "Game server for decla.red",
|
||||
"keywords": [],
|
||||
"author": "András Schmelczer <andras@schmelczer.dev> (https://schmelczer.dev/)",
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ export const defaultOptions: Options = {
|
|||
port: 3000,
|
||||
name: 'Test server',
|
||||
playerLimit: 16,
|
||||
npcCount: 16,
|
||||
npcCount: 12,
|
||||
seed: Math.random(),
|
||||
scoreLimit: 500,
|
||||
scoreLimit: 1000,
|
||||
worldSize: 8000,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -115,11 +115,12 @@ export class GameServer {
|
|||
|
||||
private endGame(winningTeam: CharacterTeam) {
|
||||
this.isInEndGame = true;
|
||||
const endTitleLength = 6000;
|
||||
const endTitleLength = 6;
|
||||
this.players.endGame(winningTeam);
|
||||
this.players.queueCommandForEachClient(
|
||||
new GameEndCommand(winningTeam, endTitleLength / 1000, true),
|
||||
new GameEndCommand(winningTeam, endTitleLength, true),
|
||||
);
|
||||
setTimeout(() => this.destroy(), endTitleLength * 1.1);
|
||||
setTimeout(() => this.destroy(), endTitleLength * 1000 * 1.1);
|
||||
}
|
||||
|
||||
private destroy() {
|
||||
|
|
@ -147,15 +148,17 @@ export class GameServer {
|
|||
);
|
||||
}
|
||||
|
||||
let scaledDelta = delta;
|
||||
if (this.isInEndGame) {
|
||||
this.timeScaling *= Math.pow(settings.endGameDeltaScaling, delta);
|
||||
delta /= this.timeScaling;
|
||||
scaledDelta /= this.timeScaling;
|
||||
} else {
|
||||
this.updatePoints();
|
||||
}
|
||||
|
||||
this.objects.stepObjects(delta);
|
||||
this.players.step(delta);
|
||||
this.objects.stepObjects(scaledDelta);
|
||||
this.players.step(scaledDelta);
|
||||
this.players.stepCommunication(delta);
|
||||
this.objects.resetRemoteCalls();
|
||||
|
||||
this.deltaTimes.push(this.deltaTimeCalculator.getNextDeltaTimeInSeconds());
|
||||
|
|
@ -165,7 +168,7 @@ export class GameServer {
|
|||
}
|
||||
|
||||
private handleStats() {
|
||||
const framesBetweenDeltaTimeCalculation = 1000;
|
||||
const framesBetweenDeltaTimeCalculation = 10000;
|
||||
|
||||
if (this.deltaTimes.length > framesBetweenDeltaTimeCalculation) {
|
||||
this.deltaTimes.sort((a, b) => a - b);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import {
|
|||
settings,
|
||||
PlanetBase,
|
||||
CharacterTeam,
|
||||
PropertyUpdatesForObject,
|
||||
UpdateProperty,
|
||||
} from 'shared';
|
||||
|
||||
import { ImmutableBoundingBox } from '../physics/bounding-boxes/immutable-bounding-box';
|
||||
|
|
@ -102,12 +104,16 @@ export class PlanetPhysical
|
|||
|
||||
public step(deltaTime: number): void {
|
||||
this.timeSinceLastPointGeneration += deltaTime;
|
||||
|
||||
// In reverse order, so that teams can achieve a 100% control.
|
||||
this.remoteCall('setOwnership', this.ownership);
|
||||
this.takeControl(CharacterTeam.neutral, deltaTime);
|
||||
}
|
||||
|
||||
public getPropertyUpdates(): PropertyUpdatesForObject {
|
||||
return new PropertyUpdatesForObject(this.id, [
|
||||
new UpdateProperty('ownership', this.ownership, 0),
|
||||
]);
|
||||
}
|
||||
|
||||
public takeControl(team: CharacterTeam, deltaTime: number) {
|
||||
if (team === CharacterTeam.decla) {
|
||||
this.ownership -= (0.5 / settings.takeControlTimeInSeconds) * deltaTime;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export class PlayerContainer {
|
|||
this.npcMaxCount - this._npcs.length,
|
||||
);
|
||||
for (let i = 0; i < newNpcCount; i++) {
|
||||
const name = `BOT ${Random.choose(settings.npcNames)}`;
|
||||
const name = `🤖 ${Random.choose(settings.npcNames)}`;
|
||||
this._npcs.push(
|
||||
new NPC({ name }, this, this.objects, this.getTeamOfNextPlayer(true)),
|
||||
);
|
||||
|
|
@ -60,6 +60,14 @@ export class PlayerContainer {
|
|||
this.players.forEach((p) => p.step(deltaTimeInSeconds));
|
||||
}
|
||||
|
||||
public stepCommunication(deltaTimeInSeconds: number) {
|
||||
this._players.forEach((p) => p.stepCommunications(deltaTimeInSeconds));
|
||||
}
|
||||
|
||||
public endGame(winner: CharacterTeam) {
|
||||
this._players.forEach((p) => p.onGameEnded(winner));
|
||||
}
|
||||
|
||||
public queueCommandForEachClient(command: Command) {
|
||||
this._players.forEach((p) => p.queueCommandSend(command));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ import { PlayerBase } from './player-base';
|
|||
export class Player extends PlayerBase {
|
||||
// default, until the clients sends its real value
|
||||
private aspectRatio: number = 16 / 9;
|
||||
|
||||
private timeUntilRespawn = 0;
|
||||
private timeSinceLastMessage = 0;
|
||||
private objectsPreviouslyInViewArea: Array<GameObject> = [];
|
||||
|
||||
protected commandExecutors: CommandExecutors = {
|
||||
|
|
@ -68,12 +69,12 @@ export class Player extends PlayerBase {
|
|||
this.queueCommandSend(new CreatePlayerCommand(this.character!));
|
||||
}
|
||||
|
||||
private timeSinceLastMessage = 0;
|
||||
private messageInterval = 1 / 30;
|
||||
private timeUntilRespawn = 0;
|
||||
public step(deltaTimeInSeconds: number) {
|
||||
this.timeSinceLastMessage += deltaTimeInSeconds;
|
||||
private winnerTeam?: CharacterTeam;
|
||||
public onGameEnded(winnerTeam: CharacterTeam) {
|
||||
this.winnerTeam = winnerTeam;
|
||||
}
|
||||
|
||||
public step(deltaTimeInSeconds: number) {
|
||||
if (this.character) {
|
||||
this.center = this.character?.center;
|
||||
|
||||
|
|
@ -85,72 +86,60 @@ export class Player extends PlayerBase {
|
|||
this.timeUntilRespawn = settings.playerDiedTimeout;
|
||||
}
|
||||
} else {
|
||||
if (this.timeSinceLastMessage > this.messageInterval) {
|
||||
this.queueCommandSend(
|
||||
new ServerAnnouncement(`Reviving in ${Math.round(this.timeUntilRespawn)}…`),
|
||||
);
|
||||
}
|
||||
|
||||
if ((this.timeUntilRespawn -= deltaTimeInSeconds) < 0) {
|
||||
this.createCharacter();
|
||||
this.center = this.character!.center;
|
||||
this.queueCommandSend(new ServerAnnouncement(''));
|
||||
}
|
||||
}
|
||||
|
||||
if (this.timeSinceLastMessage > this.messageInterval) {
|
||||
const viewArea = calculateViewArea(this.center, this.aspectRatio, 1.2);
|
||||
const bb = new BoundingBox();
|
||||
bb.topLeft = viewArea.topLeft;
|
||||
bb.size = viewArea.size;
|
||||
const remoteCalls = this.objectsPreviouslyInViewArea
|
||||
.map((g) => new RemoteCallsForObject(g.id, g.getRemoteCalls()))
|
||||
.filter((c) => c.calls.length > 0);
|
||||
|
||||
const objectsInViewArea = Array.from(
|
||||
new Set(this.objectContainer.findIntersecting(bb).map((o) => o.gameObject)),
|
||||
);
|
||||
|
||||
const newlyIntersecting = objectsInViewArea.filter(
|
||||
(o) => !this.objectsPreviouslyInViewArea.includes(o),
|
||||
);
|
||||
|
||||
const noLongerIntersecting = this.objectsPreviouslyInViewArea.filter(
|
||||
(o) => !objectsInViewArea.includes(o),
|
||||
);
|
||||
|
||||
this.objectsPreviouslyInViewArea = objectsInViewArea;
|
||||
|
||||
if (noLongerIntersecting.length > 0) {
|
||||
this.queueCommandSend(
|
||||
new DeleteObjectsCommand(noLongerIntersecting.map((g) => g.id)),
|
||||
);
|
||||
}
|
||||
|
||||
if (newlyIntersecting.length > 0) {
|
||||
this.queueCommandSend(new CreateObjectsCommand(newlyIntersecting));
|
||||
}
|
||||
|
||||
this.queueCommandSend(new UpdateOtherPlayerDirections(this.getOtherPlayers()));
|
||||
|
||||
this.queueCommandSend(
|
||||
new PropertyUpdatesForObjects(
|
||||
this.objectsPreviouslyInViewArea
|
||||
.map((o) => o.getPropertyUpdates())
|
||||
.filter((u) => u) as Array<PropertyUpdatesForObject>,
|
||||
),
|
||||
);
|
||||
if (remoteCalls.length > 0) {
|
||||
this.queueCommandSend(new RemoteCallsForObjects(remoteCalls));
|
||||
}
|
||||
}
|
||||
|
||||
this.queueCommandSend(
|
||||
new RemoteCallsForObjects(
|
||||
this.objectsPreviouslyInViewArea.map(
|
||||
(g) => new RemoteCallsForObject(g.id, g.getRemoteCalls()),
|
||||
),
|
||||
),
|
||||
private handleViewAreaUpdate() {
|
||||
const viewArea = calculateViewArea(this.center, this.aspectRatio, 1.2);
|
||||
const bb = new BoundingBox();
|
||||
bb.topLeft = viewArea.topLeft;
|
||||
bb.size = viewArea.size;
|
||||
|
||||
const objectsInViewArea = Array.from(
|
||||
new Set(this.objectContainer.findIntersecting(bb).map((o) => o.gameObject)),
|
||||
);
|
||||
|
||||
if (this.timeSinceLastMessage > this.messageInterval) {
|
||||
this.sendQueuedCommandsToClient();
|
||||
this.timeSinceLastMessage = 0;
|
||||
const newlyIntersecting = objectsInViewArea.filter(
|
||||
(o) => !this.objectsPreviouslyInViewArea.includes(o),
|
||||
);
|
||||
|
||||
const noLongerIntersecting = this.objectsPreviouslyInViewArea.filter(
|
||||
(o) => !objectsInViewArea.includes(o),
|
||||
);
|
||||
|
||||
this.objectsPreviouslyInViewArea = objectsInViewArea;
|
||||
|
||||
if (noLongerIntersecting.length > 0) {
|
||||
this.queueCommandSend(
|
||||
new DeleteObjectsCommand(noLongerIntersecting.map((g) => g.id)),
|
||||
);
|
||||
}
|
||||
|
||||
if (newlyIntersecting.length > 0) {
|
||||
this.queueCommandSend(new CreateObjectsCommand(newlyIntersecting));
|
||||
}
|
||||
|
||||
this.queueCommandSend(new UpdateOtherPlayerDirections(this.getOtherPlayers()));
|
||||
|
||||
this.queueCommandSend(
|
||||
new PropertyUpdatesForObjects(
|
||||
this.objectsPreviouslyInViewArea
|
||||
.map((o) => o.getPropertyUpdates())
|
||||
.filter((u) => u) as Array<PropertyUpdatesForObject>,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
private getOtherPlayers(): Array<OtherPlayerDirection> {
|
||||
|
|
@ -190,11 +179,33 @@ export class Player extends PlayerBase {
|
|||
this.commandsToBeSent.push(command);
|
||||
}
|
||||
|
||||
public stepCommunications(deltaTime: number) {
|
||||
if ((this.timeSinceLastMessage += deltaTime) > settings.updateMessageInterval) {
|
||||
this.handleAnnouncements();
|
||||
this.handleViewAreaUpdate();
|
||||
this.sendQueuedCommandsToClient();
|
||||
this.timeSinceLastMessage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sendQueuedCommandsToClient() {
|
||||
this.socket.emit(TransportEvents.ServerToPlayer, serialize(this.commandsToBeSent));
|
||||
this.commandsToBeSent = [];
|
||||
}
|
||||
|
||||
private handleAnnouncements() {
|
||||
let announcement = '';
|
||||
if (this.winnerTeam) {
|
||||
announcement = `Team <span class="${this.winnerTeam}">${this.winnerTeam}</span> won 🎉`;
|
||||
} else if (!this.character) {
|
||||
announcement = `Reviving in ${Math.round(this.timeUntilRespawn)}…`;
|
||||
}
|
||||
|
||||
if (announcement) {
|
||||
this.queueCommandSend(new ServerAnnouncement(announcement));
|
||||
}
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
super.destroy();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue