diff --git a/common/types/room.ts b/common/types/room.ts index cb08f85..ee8701b 100644 --- a/common/types/room.ts +++ b/common/types/room.ts @@ -57,17 +57,3 @@ export type Room = { */ maxPlayerAcceleration: number; }; - -export function makeRoom(roomId: number): Room { - const roomSize = { x: 2000, y: 2000 }; - - return { - id: roomId, - maxPlayers: 5, - players: {}, - size: roomSize, - gravity: { x: 0, y: 200 }, - maxPlayerSpeed: 500, - maxPlayerAcceleration: 400, - }; -} diff --git a/server/logic/logic.ts b/server/logic/logic.ts index ebe756d..967dfcd 100644 --- a/server/logic/logic.ts +++ b/server/logic/logic.ts @@ -5,8 +5,8 @@ import { getLogger } from "../logger"; import { Socket } from "../server"; import { getRoom, world } from "../world"; import { RoomController } from "./room-controller.base"; -import { makeBotsRoom } from "./room-controller.bots"; -import { makeNormalRoom } from "./room-controller.normal"; +import { BotsRoom } from "./room-controller.bots"; +import { NormalRoom } from "./room-controller.normal"; const roomControllers: Record = {}; @@ -58,6 +58,11 @@ export function findOrCreateRoomWithSpace(roomWithBots: boolean): Room { world.rooms[newRoom.id] = newRoom; + assert( + Object.keys(newRoom.players).length < newRoom.maxPlayers, + "Room was created full", + ); + return newRoom; } @@ -65,7 +70,8 @@ export function findOrCreateRoomWithSpace(roomWithBots: boolean): Room { * Creates a new room. Starts the room physics loop. */ function createRoom(roomWithBots: boolean): Room { - const { room, controller } = roomWithBots ? makeBotsRoom() : makeNormalRoom(); + const controller = roomWithBots ? new BotsRoom() : new NormalRoom(); + const room = controller.room; world.rooms[room.id] = room; roomControllers[room.id] = controller; diff --git a/server/logic/room-controller.base.ts b/server/logic/room-controller.base.ts index 1f75e9c..3a54318 100644 --- a/server/logic/room-controller.base.ts +++ b/server/logic/room-controller.base.ts @@ -19,14 +19,28 @@ export type RoomController = { destroy(): void; }; -export function makeBaseRoomController(room: Room): RoomController { - async function joinPlayer(socket: Socket, username: string) { - await server.addToRoom(socket, room); +export class BaseRoomController implements RoomController { + static makeRoom(roomId: number): Room { + return { + id: roomId, + maxPlayers: 5, + players: {}, + size: { x: 2000, y: 2000 }, + gravity: { x: 0, y: 200 }, + maxPlayerSpeed: 500, + maxPlayerAcceleration: 400, + }; + } + + constructor(public room: Room) {} + + async joinPlayer(socket: Socket, username: string) { + await server.addToRoom(socket, this.room); - const playerPosition = divide(room.size, 2); // TODO: Find an empty position + const playerPosition = divide(this.room.size, 2); // TODO: Find an empty position const player = makePlayer( socket.id, - room.id, + this.room.id, username, playerPosition, makeFlailWeapon(playerPosition), @@ -34,12 +48,12 @@ export function makeBaseRoomController(room: Room): RoomController { socketsById[socket.id] = socket; playersById[socket.id] = player; - room.players[socket.id] = player; + this.room.players[socket.id] = player; return player; } - function disconnectPlayer(player: Player) { + disconnectPlayer(player: Player) { const room = getRoom(player); socketsById[player.id]?.disconnect(); @@ -51,22 +65,22 @@ export function makeBaseRoomController(room: Room): RoomController { server.broadcastRoom(room).emit("playerLeft", { player }); } - function updateRoom(elapsedTime: number) { + updateRoom(elapsedTime: number) { const damages: Damage[] = []; const updateBotsSpan = getLogger().measureSpan("updateBots"); - updateBots(room); + updateBots(this.room); updateBotsSpan.end(); const applyPhysicsSpan = getLogger().measureSpan("applyPhysics"); - applyPhysics(room, elapsedTime, (damage) => damages.push(damage)); + applyPhysics(this.room, elapsedTime, (damage) => damages.push(damage)); applyPhysicsSpan.end(); const deadPlayerIds = new Set(); // Apply damages for (const damage of damages) { - const damagedPlayer = room.players[damage.damagedPlayerId]; + const damagedPlayer = this.room.players[damage.damagedPlayerId]; assert(damagedPlayer, "Damaged player not found"); // TODO: Ignore damage if damaged by same source in the last N milliseconds @@ -80,27 +94,23 @@ export function makeBaseRoomController(room: Room): RoomController { // Remove dead players for (const deadPlayerId of deadPlayerIds) { - const deadPlayer = room.players[deadPlayerId]; + const deadPlayer = this.room.players[deadPlayerId]; assert(deadPlayer, "Damaged player not found"); - server.broadcastRoom(room).emit("playerDied", { player: deadPlayer }); + server + .broadcastRoom(this.room) + .emit("playerDied", { player: deadPlayer }); - disconnectPlayer(deadPlayer); + this.disconnectPlayer(deadPlayer); } - if (!Object.values(room.players).some((p) => !p.isBot)) { - delete world.rooms[room.id]; - getLogger().info(`Deleted empty room ${room.id}`); + if (!Object.values(this.room.players).some((p) => !p.isBot)) { + delete world.rooms[this.room.id]; + getLogger().info(`Deleted empty room ${this.room.id}`); } - server.broadcastRoom(room).emit("roomUpdated", { room }); + server.broadcastRoom(this.room).emit("roomUpdated", { room: this.room }); } - return { - room, - joinPlayer, - disconnectPlayer, - updateRoom, - destroy() {}, - }; + destroy() {} } diff --git a/server/logic/room-controller.bots.ts b/server/logic/room-controller.bots.ts index b5ba652..1e68153 100644 --- a/server/logic/room-controller.bots.ts +++ b/server/logic/room-controller.bots.ts @@ -1,33 +1,29 @@ import { makeBot } from "../../common/types/player"; -import { makeRoom } from "../../common/types/room"; import { makeFlailWeapon } from "../../common/types/weapon"; import { world } from "../world"; -import { makeBaseRoomController } from "./room-controller.base"; +import { BaseRoomController } from "./room-controller.base"; -export function makeBotsRoom() { - const room = makeRoom(world.nextRoomId++); - const base = makeBaseRoomController(room); +export class BotsRoom extends BaseRoomController { + constructor(botCount = 2) { + const room = BaseRoomController.makeRoom(world.nextRoomId++); - const botCount = 2; - for (let i = 0; i < botCount; i++) { - const botId = `_BOT_${i + 1}`; - const botName = `BOT ${i + 1}`; - const position = { - x: (room.size.x / (botCount + 1)) * (i + 1), - y: room.size.y / 2, - }; + for (let i = 0; i < botCount; i++) { + const botId = `_BOT_${i + 1}`; + const botName = `BOT ${i + 1}`; + const position = { + x: (room.size.x / (botCount + 1)) * (i + 1), + y: room.size.y / 2, + }; - room.players[botId] = makeBot( - botId, - room.id, - botName, - position, - makeFlailWeapon(position), - ); - } + room.players[botId] = makeBot( + botId, + room.id, + botName, + position, + makeFlailWeapon(position), + ); + } - return { - room, - controller: base, - }; + super(room); + } } diff --git a/server/logic/room-controller.load-test.ts b/server/logic/room-controller.load-test.ts new file mode 100644 index 0000000..6748ec9 --- /dev/null +++ b/server/logic/room-controller.load-test.ts @@ -0,0 +1,48 @@ +import { makeBot, Player } from "../../common/types/player"; +import { Room } from "../../common/types/room"; +import { makeFlailWeapon } from "../../common/types/weapon"; +import { world } from "../world"; +import { BaseRoomController } from "./room-controller.base"; + +export class LoadTestRoom extends BaseRoomController { + static BOT_ID_PREFIX = "_BOT_"; + + constructor(private botCount: number) { + const room = { + ...BaseRoomController.makeRoom(world.nextRoomId++), + maxPlayers: botCount + 1, + size: { x: 1000 * botCount, y: 1000 }, + }; + + for (let i = 1; i <= botCount; i++) { + LoadTestRoom.addBot(i, botCount, room); + } + + super(room); + } + + disconnectPlayer(player: Player) { + super.disconnectPlayer(player); + + const botIndex = Number(player.id.slice(LoadTestRoom.BOT_ID_PREFIX.length)); + + LoadTestRoom.addBot(botIndex, this.botCount, this.room); + } + + static addBot(botNumber: number, botCount: number, room: Room) { + const botId = `${LoadTestRoom.BOT_ID_PREFIX}${botNumber}`; + const botName = `BOT ${botNumber}`; + const position = { + x: (room.size.x / (botCount + 1)) * botNumber, + y: room.size.y / 2, + }; + + room.players[botId] = makeBot( + botId, + room.id, + botName, + position, + makeFlailWeapon(position), + ); + } +} diff --git a/server/logic/room-controller.normal.ts b/server/logic/room-controller.normal.ts index 10294e7..c9329e6 100644 --- a/server/logic/room-controller.normal.ts +++ b/server/logic/room-controller.normal.ts @@ -1,13 +1,8 @@ -import { makeRoom } from "../../common/types/room"; import { world } from "../world"; -import { makeBaseRoomController } from "./room-controller.base"; +import { BaseRoomController } from "./room-controller.base"; -export function makeNormalRoom() { - const room = makeRoom(world.nextRoomId++); - const base = makeBaseRoomController(room); - - return { - room, - controller: base, - }; +export class NormalRoom extends BaseRoomController { + constructor() { + super(BaseRoomController.makeRoom(world.nextRoomId++)); + } } diff --git a/webpack.config.js b/webpack.config.js index ecd6ff7..37460af 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -11,7 +11,7 @@ const __dirname = path.dirname(__filename); export default (env) => { let appVersion; - if (env.APP_VERSION) { + if (env?.APP_VERSION) { appVersion = env.APP_VERSION; } else { const gitCommit = childProcess.execSync("git rev-parse HEAD").toString();