From 9a0fce0fbe8d0ffdf258287e56436af7ecf1562f Mon Sep 17 00:00:00 2001 From: Benjamin Kraft Date: Mon, 14 Nov 2022 17:49:16 +0100 Subject: [PATCH] rename from ts to src --- src/client.js | 152 ++++++++++++++++++++++ {ts => src}/client.ts | 0 {ts => src}/definitions/serialized.d.ts | 0 {ts => src}/definitions/settings.d.ts | 0 src/games/chainreact.js | 113 ++++++++++++++++ {ts => src}/games/chainreact.ts | 0 src/games/game_standard.js | 49 +++++++ {ts => src}/games/game_standard.ts | 0 src/games/global_draw.js | 151 ++++++++++++++++++++++ {ts => src}/games/global_draw.ts | 0 src/games/memory.js | 44 +++++++ {ts => src}/games/memory.ts | 0 src/games/pong.js | 27 ++++ {ts => src}/games/pong.ts | 0 src/lib/vector.js | 76 +++++++++++ {ts => src}/lib/vector.ts | 0 src/logger.js | 97 ++++++++++++++ {ts => src}/logger.ts | 0 src/manager.js | 126 ++++++++++++++++++ {ts => src}/manager.ts | 1 - src/room.js | 164 ++++++++++++++++++++++++ {ts => src}/room.ts | 0 src/server.js | 27 ++++ src/server.ts | 39 ++++++ ts/server.ts | 35 ----- tsconfig.json | 18 +-- 26 files changed, 1072 insertions(+), 47 deletions(-) create mode 100644 src/client.js rename {ts => src}/client.ts (100%) rename {ts => src}/definitions/serialized.d.ts (100%) rename {ts => src}/definitions/settings.d.ts (100%) create mode 100644 src/games/chainreact.js rename {ts => src}/games/chainreact.ts (100%) create mode 100644 src/games/game_standard.js rename {ts => src}/games/game_standard.ts (100%) create mode 100644 src/games/global_draw.js rename {ts => src}/games/global_draw.ts (100%) create mode 100644 src/games/memory.js rename {ts => src}/games/memory.ts (100%) create mode 100644 src/games/pong.js rename {ts => src}/games/pong.ts (100%) create mode 100644 src/lib/vector.js rename {ts => src}/lib/vector.ts (100%) create mode 100644 src/logger.js rename {ts => src}/logger.ts (100%) create mode 100644 src/manager.js rename {ts => src}/manager.ts (99%) create mode 100644 src/room.js rename {ts => src}/room.ts (100%) create mode 100644 src/server.js create mode 100644 src/server.ts delete mode 100644 ts/server.ts diff --git a/src/client.js b/src/client.js new file mode 100644 index 0000000..8f06f95 --- /dev/null +++ b/src/client.js @@ -0,0 +1,152 @@ +"use strict"; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +exports.__esModule = true; +exports.Client = void 0; +var room_1 = require("./room"); +var manager_1 = require("./manager"); +var logger_1 = require("./logger"); +var Client = /** @class */ (function () { + function Client(socket, manager) { + this.socket = socket; + // @ts-ignore + this.name = socket.handshake.query.name; + // @ts-ignore + this.game = socket.handshake.query.game; + this.id = socket.id; + this.setEvents(manager); + } + Object.defineProperty(Client.prototype, "serialized", { + get: function () { + return { + id: this.id, + name: this.name, + game: this.game, + isReady: this.isReady, + isPlayer: this.isPlayer, + isSpectator: this.isSpectator + }; + }, + enumerable: false, + configurable: true + }); + Client.prototype.setEvents = function (mng) { + var _this = this; + var s = this.socket; + s.on('room-list', function () { return _this.sendRoomList(); }); + s.on('client-list', function () { return _this.sendClientList(); }); + s.on('set-ready', function (ready) { return _this.setReady(ready); }); + s.on('game-settings', function (settings) { return _this.setGameSettings(settings); }); + s.on('create-lobby', function (settings, name) { return _this.createRoom(settings, name); }); + s.on('join-lobby', function (roomId) { return _this.joinRoom(roomId); }); + s.on('leave-lobby', function (roomId) { return _this.leaveRoom(roomId); }); + s.on('join-spectators', function () { return _this.joinSpectators(); }); + s.on('join-players', function () { return _this.joinPlayers(); }); + s.on('start-game', function (lobbyId) { return mng.startGame(_this, lobbyId); }); + s.on('stop-game', function (lobbyId) { return mng.stopGame(_this, lobbyId); }); + s.on('feedback', function (content) { return mng.saveFeedbackToFile(_this, content); }); + s.on('disconnect', function () { return mng.disconnected(_this); }); + this.send('connected'); + }; + Client.prototype.sendRoomList = function () { + var rooms = manager_1.ConnectionManager.RoomListByGame(this.game); + this.send('room-list', rooms); + }; + Client.prototype.sendClientList = function () { + var clients = manager_1.ConnectionManager.ClientListByClientId(this.id); + this.send('client-list', clients); + }; + Client.prototype.setReady = function (ready) { + var room = room_1.Room.getByClientId(this.id, manager_1.ConnectionManager.Instance.rooms); + if (room) { + this.isReady = ready; + room.toAll('client-list', room.clients); + } + }; + Client.prototype.setGameSettings = function (settings) { + var room = room_1.Room.getByClientId(this.id, manager_1.ConnectionManager.Instance.rooms); + if (room) { + room.gameSettings = settings; + room.toAll('game-settings', settings); + } + }; + Client.prototype.createRoom = function (settings, name) { + var room = manager_1.ConnectionManager.Instance.createRoom(settings, name); + room.add(this); + this.send('created-lobby', room); + (0, logger_1.log)('lobby-created', this, room); + }; + Client.prototype.joinRoom = function (roomId) { + var room = room_1.Room.getByRoomId(roomId, manager_1.ConnectionManager.Instance.rooms); + if (!room) { + this.send('join-failed', 'Room does not exist!'); + (0, logger_1.log)('join-non-existent', this, new room_1.Room('not-existent', roomId)); + } + else if (room.hasStarted && !room.settings.spectators) { + this.send('join-failed', 'Game has started yet!'); + (0, logger_1.log)('join-started', this, room); + } + else { + room.add(this); + (0, logger_1.log)('member-joined', this, room); + } + return room; + }; + Client.prototype.leaveRoom = function (_roomId) { + var room = room_1.Room.getByClientId(this.id, manager_1.ConnectionManager.Instance.rooms); + if (!room) + return; + this.leave(room.id); + if (room.runningGame) + room.runningGame.removeClient(this); + room.clients.splice(room.clients.indexOf(this), 1); + room.toAll('member-left', this.id, this.name); + room.toAll('client-list', room.clients); + this.send('left-lobby'); + (0, logger_1.log)('member-left', this, room); + if (room.isEmpty && !room.settings.always) { + manager_1.ConnectionManager.Instance.deleteRoom(room); + } + }; + Client.prototype.joinSpectators = function () { + var room = room_1.Room.getByClientId(this.id, manager_1.ConnectionManager.Instance.rooms); + if (!room) + return; + this.isSpectator = true; + this.isPlayer = false; + room.toAll('client-list', room.clients); + }; + Client.prototype.joinPlayers = function () { + var room = room_1.Room.getByClientId(this.id, manager_1.ConnectionManager.Instance.rooms); + if (!room) + return; + if (room.hasStarted) + return; + this.isSpectator = false; + this.isPlayer = true; + room.toAll('client-list', room.clients); + }; + Client.prototype.send = function (event) { + var _a; + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + (_a = this.socket).emit.apply(_a, __spreadArray([event], (0, manager_1.serializeObject)(args), false)); + }; + Client.prototype.join = function (roomId) { + this.socket.join(roomId); + }; + Client.prototype.leave = function (roomId) { + this.socket.leave(roomId); + }; + return Client; +}()); +exports.Client = Client; diff --git a/ts/client.ts b/src/client.ts similarity index 100% rename from ts/client.ts rename to src/client.ts diff --git a/ts/definitions/serialized.d.ts b/src/definitions/serialized.d.ts similarity index 100% rename from ts/definitions/serialized.d.ts rename to src/definitions/serialized.d.ts diff --git a/ts/definitions/settings.d.ts b/src/definitions/settings.d.ts similarity index 100% rename from ts/definitions/settings.d.ts rename to src/definitions/settings.d.ts diff --git a/src/games/chainreact.js b/src/games/chainreact.js new file mode 100644 index 0000000..92e46ad --- /dev/null +++ b/src/games/chainreact.js @@ -0,0 +1,113 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +exports.Chainreact = void 0; +var game_standard_1 = require("./game_standard"); +var Chainreact = /** @class */ (function (_super) { + __extends(Chainreact, _super); + function Chainreact(room, settings) { + var _this = _super.call(this, room, settings) || this; + _this.readyForTurn = []; + return _this; + } + Chainreact.prototype.setEvents = function (client) { + var _this = this; + var socket = client.socket; + socket.on('ready-for-turn', function (isDead) { + if (isDead) { + client.isPlayer = false; + client.isSpectator = true; + _this.room.toAll('client-list', _this.room.clients); + } + else { + _this.readyForTurn.push(client); + } + var allReady = true; + _this.room.players.forEach(function (c) { + if (_this.readyForTurn.find(function (r) { return r.id === c.id; }) == null) { + allReady = false; + } + }); + if (allReady) { + _this.nextTurn(); + _this.readyForTurn = []; + } + }); + socket.on('set-slot', function (fieldsIndex, slotsIndex) { + _this.room.toAll('set-slot', fieldsIndex, slotsIndex, socket.id); + }); + socket.on('game-data', function (data) { return _this.currentGameData = data; }); + }; + Chainreact.prototype.addClient = function (client) { + _super.prototype.addClient.call(this, client); + if (client.isSpectator) { + var room = this.room; + var data = this.currentGameData; + var hues = this.colorHues; + var turnId = ''; + if (this.room.players[this.currentTurnIndex]) + turnId = this.room.players[this.currentTurnIndex].id; + client.send('start-spectate', room, data, hues, turnId); + } + }; + Chainreact.prototype.removeClient = function (client) { + _super.prototype.removeClient.call(this, client); + if (this.room.players.indexOf(client) === this.currentTurnIndex) + this.nextTurn(true); + var s = client.socket; + s.removeAllListeners('set-slot'); + s.removeAllListeners('ready-for-turn'); + s.removeAllListeners('game-data'); + }; + Chainreact.prototype.nextTurn = function (skip) { + if (this.currentTurnIndex != null && !skip) { + this.currentTurnIndex++; + if (this.currentTurnIndex >= this.room.players.length) { + this.currentTurnIndex = 0; + } + } + else if (!skip) { + this.setTurnAndColors(); + } + var index = this.currentTurnIndex; + if (skip) { + index = this.currentTurnIndex + 1; + if (index >= this.room.players.length) { + index = 0; + this.currentTurnIndex = 0; + } + } + if (this.room.players.length) { + this.room.toAll('current-turn', this.room.players[index].id); + } + }; + Chainreact.prototype.setTurnAndColors = function () { + this.currentTurnIndex = Math.floor(Math.random() * this.room.players.length); + var colorHues = [0, 60, 120, 240]; + this.colorHues = {}; + for (var _i = 0, _a = this.room.players; _i < _a.length; _i++) { + var c = _a[_i]; + var index = Math.floor(Math.random() * colorHues.length); + var hue = colorHues[index]; + colorHues.splice(index, 1); + this.colorHues[c.id] = hue; + } + this.room.toAll('player-colors', this.colorHues); + }; + return Chainreact; +}(game_standard_1.ServerGame)); +exports.Chainreact = Chainreact; diff --git a/ts/games/chainreact.ts b/src/games/chainreact.ts similarity index 100% rename from ts/games/chainreact.ts rename to src/games/chainreact.ts diff --git a/src/games/game_standard.js b/src/games/game_standard.js new file mode 100644 index 0000000..a833fa5 --- /dev/null +++ b/src/games/game_standard.js @@ -0,0 +1,49 @@ +"use strict"; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +exports.__esModule = true; +exports.ServerGame = void 0; +var ServerGame = /** @class */ (function () { + function ServerGame(room, settings) { + var _this = this; + this.settings = settings; + this.room = room; + this.room.clients.forEach(function (c) { return _this.addClient(c); }); + } + ServerGame.prototype.addClient = function (client) { + this.setEvents(client); + }; + ServerGame.prototype.removeClient = function (client) { + this.removeEvents(client); + }; + ServerGame.prototype.gameAction = function (action) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + }; + ServerGame.prototype.setEvents = function (client) { + var _this = this; + var socket = client.socket; + socket.on('game-action', function (action) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + return _this.gameAction.apply(_this, __spreadArray([action], args, false)); + }); + }; + ServerGame.prototype.removeEvents = function (client) { + var socket = client.socket; + socket.removeAllListeners('game-action'); + }; + return ServerGame; +}()); +exports.ServerGame = ServerGame; diff --git a/ts/games/game_standard.ts b/src/games/game_standard.ts similarity index 100% rename from ts/games/game_standard.ts rename to src/games/game_standard.ts diff --git a/src/games/global_draw.js b/src/games/global_draw.js new file mode 100644 index 0000000..ce8abea --- /dev/null +++ b/src/games/global_draw.js @@ -0,0 +1,151 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +exports.GlobalDraw = void 0; +var game_standard_1 = require("./game_standard"); +var logger_1 = require("../logger"); +var fs = require("fs"); +var GlobalDraw = /** @class */ (function (_super) { + __extends(GlobalDraw, _super); + function GlobalDraw(lobby, settings) { + var _this = _super.call(this, lobby, settings) || this; + _this.linesPath = "json_data/global_draw/lines.json"; + _this.pixelsPath = "json_data/global_draw/pixels.json"; + _this.pixelCount = 1000; + _this.lines = []; + _this.pixels = []; + for (var x = 0; x < _this.pixelCount; x++) { + var column = []; + for (var y = 0; y < _this.pixelCount; y++) { + column.push({ x: x, y: y, c: "#ffffff" }); + } + _this.pixels.push(column); + } + var linesLoaded = false; + var pixelsLoaded = false; + _this.loadDrawingsFromFile(_this.linesPath, function (data) { + _this.lines = data; + }, function () { + linesLoaded = true; + if (pixelsLoaded) { + _this.startSaveInterval(); + } + }); + _this.loadDrawingsFromFile(_this.pixelsPath, function (data) { + for (var x = 0; x < _this.pixelCount; x++) { + for (var y = 0; y < _this.pixelCount; y++) { + if (data[x]) + if (data[x][y]) + _this.pixels[x][y].c = data[x][y].c; + } + } + }, function () { + pixelsLoaded = true; + if (linesLoaded) { + _this.startSaveInterval(); + } + }); + return _this; + } + GlobalDraw.prototype.startSaveInterval = function () { + var _this = this; + this.saveAllDrawingsToFile(); + //Saves once every day + setInterval(function () { return _this.saveAllDrawingsToFile(); }, 1000 * 60 * 60 * 24); + }; + GlobalDraw.prototype.addLine = function (line) { + this.lines.push(line); + this.room.toAll('add-line', line); + }; + GlobalDraw.prototype.fillPixel = function (pixel) { + this.pixels[pixel.x][pixel.y].c = pixel.c; + this.room.toAll('fill-pixel', pixel); + }; + GlobalDraw.prototype.loadDrawingsFromFile = function (drawingsPath, successs, done) { + var _this = this; + fs.readFile(drawingsPath, 'utf8', function (err, data) { + if (err) + (0, logger_1.log)('load-error', null, _this.room, err.message); + else { + try { + var parsed = JSON.parse(data); + (0, logger_1.log)('load-success', null, _this.room); + successs(parsed); + } + catch (e) { + (0, logger_1.log)('parse-error', null, _this.room, e.message); + } + } + done(); + }); + }; + GlobalDraw.prototype.saveDrawingsToFile = function (drawings, drawingsPath, callback) { + var splits = drawingsPath.split('/'); + var path = splits.slice(0, splits.length - 1).reduce(function (prev, curr) { return prev + '/' + curr; }); + var name = splits[splits.length - 1]; + if (!fs.existsSync(path)) { + fs.mkdirSync(path, { recursive: true }); + } + fs.writeFile(drawingsPath, JSON.stringify(drawings), callback); + }; + GlobalDraw.prototype.saveAllDrawingsToFile = function () { + var _this = this; + var linesSaved = false; + var pixelsSaved = false; + this.saveDrawingsToFile(this.lines, this.linesPath, function (err) { + if (err) + (0, logger_1.log)('save-error', null, _this.room, err.message); + else { + linesSaved = true; + if (pixelsSaved) { + _this.room.toAll('all-saved'); + linesSaved = false; + pixelsSaved = false; + } + (0, logger_1.log)('save-success', null, _this.room, 'Successfully saved lines to file'); + } + }); + this.saveDrawingsToFile(this.pixels, this.pixelsPath, function (err) { + if (err) + (0, logger_1.log)('save-error', null, _this.room, err.message); + else { + pixelsSaved = true; + if (linesSaved) { + _this.room.toAll('all-saved'); + pixelsSaved = false; + linesSaved = false; + } + (0, logger_1.log)('save-success', null, _this.room, 'Successfully saved pixels to file'); + } + }); + }; + GlobalDraw.prototype.addClient = function (client) { + this.setEvents(client); + }; + GlobalDraw.prototype.setEvents = function (client) { + var _this = this; + _super.prototype.setEvents.call(this, client); + var socket = client.socket; + socket.on('add-line', function (line) { return _this.addLine(line); }); + socket.on('fill-pixel', function (pixel) { return _this.fillPixel(pixel); }); + socket.on('request-all-lines', function () { return socket.emit('add-all', _this.lines); }); + socket.on('request-all-pixels', function () { return socket.emit('fill-all', _this.pixels); }); + socket.on('save-all', function () { return _this.saveAllDrawingsToFile(); }); + }; + return GlobalDraw; +}(game_standard_1.ServerGame)); +exports.GlobalDraw = GlobalDraw; diff --git a/ts/games/global_draw.ts b/src/games/global_draw.ts similarity index 100% rename from ts/games/global_draw.ts rename to src/games/global_draw.ts diff --git a/src/games/memory.js b/src/games/memory.js new file mode 100644 index 0000000..81277ca --- /dev/null +++ b/src/games/memory.js @@ -0,0 +1,44 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +exports.__esModule = true; +exports.Memory = void 0; +var game_standard_1 = require("./game_standard"); +var Memory = /** @class */ (function (_super) { + __extends(Memory, _super); + function Memory(room, settings) { + return _super.call(this, room, settings) || this; + } + Memory.prototype.gameAction = function (action) { + var _a; + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + (_a = this.room).toAll.apply(_a, __spreadArray(['game-action', action], args, false)); + }; + return Memory; +}(game_standard_1.ServerGame)); +exports.Memory = Memory; diff --git a/ts/games/memory.ts b/src/games/memory.ts similarity index 100% rename from ts/games/memory.ts rename to src/games/memory.ts diff --git a/src/games/pong.js b/src/games/pong.js new file mode 100644 index 0000000..8da799f --- /dev/null +++ b/src/games/pong.js @@ -0,0 +1,27 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +exports.Pong = void 0; +var game_standard_1 = require("./game_standard"); +var Pong = /** @class */ (function (_super) { + __extends(Pong, _super); + function Pong(lobby, settings) { + return _super.call(this, lobby, settings) || this; + } + return Pong; +}(game_standard_1.ServerGame)); +exports.Pong = Pong; diff --git a/ts/games/pong.ts b/src/games/pong.ts similarity index 100% rename from ts/games/pong.ts rename to src/games/pong.ts diff --git a/src/lib/vector.js b/src/lib/vector.js new file mode 100644 index 0000000..f7880a7 --- /dev/null +++ b/src/lib/vector.js @@ -0,0 +1,76 @@ +"use strict"; +exports.__esModule = true; +exports.p = exports.Vector = void 0; +var Vector = /** @class */ (function () { + function Vector(x, y) { + this.x = x; + this.y = y; + } + Vector.fromAngle = function (angle) { + return new Vector(Math.cos(angle), Math.sin(angle)); + }; + Vector.sub = function (v1, v2) { + return new Vector(v1.x - v2.x, v1.y - v2.y); + }; + Vector.div = function (v1, divider) { + return new Vector(v1.x / divider, v1.y / divider); + }; + Vector.prototype.add = function (other) { + this.x += other.x; + this.y += other.y; + return this; + }; + Vector.prototype.mult = function (scalar) { + this.x *= scalar; + this.y *= scalar; + return this; + }; + Vector.prototype.addMag = function (length) { + this.setMag(this.mag() + length); + return this; + }; + Vector.prototype.setMag = function (length) { + var mag = this.mag(); + this.x /= mag; + this.y /= mag; + this.x *= length; + this.y *= length; + return this; + }; + Vector.prototype.rotate = function (rad) { + var r = this.rotated(rad); + this.x = r.x; + this.y = r.y; + return this; + }; + Vector.prototype.copy = function () { + return new Vector(this.x, this.y); + }; + Vector.prototype.heading = function () { + var r = this.rotated(Math.PI / -2); + return Math.atan2(r.x, -r.y); + }; + Vector.prototype.mag = function () { + return Math.sqrt(this.x * this.x + this.y * this.y); + }; + Vector.prototype.serialized = function () { + return { + x: this.x, + y: this.y + }; + }; + Vector.prototype.rotated = function (rad) { + var x = Math.cos(rad) * this.x - Math.sin(rad) * this.y, y = Math.sin(rad) * this.x + Math.cos(rad) * this.y; + return new Vector(x, y); + }; + return Vector; +}()); +exports.Vector = Vector; +exports.p = { + createVector: function (x, y) { + return new Vector(x, y); + }, + dist: function (x1, y1, x2, y2) { + return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); + } +}; diff --git a/ts/lib/vector.ts b/src/lib/vector.ts similarity index 100% rename from ts/lib/vector.ts rename to src/lib/vector.ts diff --git a/src/logger.js b/src/logger.js new file mode 100644 index 0000000..b9207d1 --- /dev/null +++ b/src/logger.js @@ -0,0 +1,97 @@ +"use strict"; +exports.__esModule = true; +exports.log = void 0; +var fs = require("fs"); +var util = require("util"); +var logFolder = "./logs"; +if (!fs.existsSync(logFolder)) { + fs.mkdirSync(logFolder); +} +var logFile = fs.createWriteStream(logFolder + '/' + new Date().getTime() + '.log', { flags: 'a' }); +var logStdout = process.stdout; +console.log = function () { + logFile.write(util.format.apply(null, arguments) + '\n'); + logStdout.write(util.format.apply(null, arguments) + '\n'); +}; +console.error = console.log; +process.on('uncaughtException', function (err) { + console.error('Uncaught error: ', err); + process.exit(1); +}); +process.stdin.pipe(logFile); +function log(type, client, lobby, msg) { + var now = new Date(Date.now()).toString(), message, name, game; + var date = '[' + now.substring(0, now.indexOf('GMT') - 1) + ']'; + if (client) { + game = '[' + client.game + ']'; + var short = client.id.substring(0, Math.round(client.id.length / 3)); + name = '"' + client.name + '(' + short + '...)"'; + } + else { + if (type === 'lobby-deleted') { + game = '[' + lobby.gameName + ']'; + } + else { + game = '[undefined]'; + } + name = 'UNKNOWN'; + } + if (lobby) { + game = '[' + lobby.gameName + ']'; + } + switch (type) { + case 'join-non-existent': + message = name + ' tried to join non-existent lobby "' + lobby.id + '"'; + break; + case 'join-started': + message = name + ' tried to join the started game "' + lobby.id + '"'; + break; + case 'lobby-created': + message = name + ' created new lobby: "' + lobby.id + '"'; + break; + case 'game-started': + message = name + ' started the game: "' + lobby.id + '"'; + break; + case 'game-stopped': + message = name + ' stopped the game: "' + lobby.id + '"'; + break; + case 'member-joined': + message = name + ' joined the lobby "' + lobby.id + '"'; + break; + case 'member-left': + message = name + ' left the lobby "' + lobby.id + '"'; + break; + case 'lobby-deleted': + message = 'Lobby "' + lobby.id + '" was deleted'; + break; + case 'save-success': + message = msg; + break; + case 'save-error': + message = 'Failed to save contents to file: ' + msg; + break; + case 'load-success': + message = 'Successfully loaded and parsed file contents'; + break; + case 'load-error': + message = 'Failed to load file: ' + msg; + break; + case 'parse-error': + message = 'Failed to parse contents: ' + msg; + break; + case 'feedback': + message = 'Saved feedback to file: ' + msg; + break; + case 'connection': + message = name + ' connected'; + break; + case 'disconnection': + message = name + ' disconnected'; + break; + case 'startup': + message = msg; + break; + } + console.log(date + game + ' ---> {' + message + '}'); +} +exports.log = log; diff --git a/ts/logger.ts b/src/logger.ts similarity index 100% rename from ts/logger.ts rename to src/logger.ts diff --git a/src/manager.js b/src/manager.js new file mode 100644 index 0000000..1424602 --- /dev/null +++ b/src/manager.js @@ -0,0 +1,126 @@ +"use strict"; +exports.__esModule = true; +exports.serializeObject = exports.ConnectionManager = void 0; +var room_1 = require("./room"); +var client_1 = require("./client"); +var logger_1 = require("./logger"); +var fs = require("fs"); +var ConnectionManager = /** @class */ (function () { + function ConnectionManager(io) { + ConnectionManager.Instance = this; + this.io = io; + this.rooms = []; + var drawSettings = { + project: { + name: 'global-draw', + playerCounts: null + }, + always: true, + spectators: true + }; + var drawRoom = this.createRoom(drawSettings, ''); + drawRoom.id = 'global-draw-room'; + drawRoom.startGame(); + this.rooms.push(drawRoom); + } + ConnectionManager.RoomListByGame = function (game) { + return this.Instance.rooms.filter(function (l) { return l.gameName === game; }); + }; + ConnectionManager.ClientListByClientId = function (clientId) { + var room = room_1.Room.getByClientId(clientId, this.Instance.rooms); + return room.clients; + }; + ConnectionManager.prototype.newSocket = function (socket) { + var client = new client_1.Client(socket, this); + (0, logger_1.log)('connection', client); + }; + ConnectionManager.prototype.roomListUpdate = function () { + this.io.sockets.emit('room-list', serializeObject(this.rooms)); + }; + ConnectionManager.prototype.createRoom = function (settings, name) { + var roomId = room_1.Room.generateCode(10); + // @ts-ignore + var room = new room_1.Room(name, roomId, settings, this.io); + this.rooms.push(room); + this.roomListUpdate(); + return room; + }; + ConnectionManager.prototype.deleteRoom = function (room) { + this.rooms.splice(this.rooms.indexOf(room), 1); + this.roomListUpdate(); + (0, logger_1.log)('lobby-deleted', null, room); + }; + //Starts the game of a room with given id + ConnectionManager.prototype.startGame = function (client, _roomId) { + var lobby = room_1.Room.getByClientId(client.id, this.rooms); + if (!lobby) + return; + if (!lobby.hasStarted) { + lobby.startGame(); + (0, logger_1.log)('game-started', client, lobby); + } + this.io.sockets.emit('room-list', serializeObject(this.rooms)); + }; + //Stops the game of a lobby with given id + ConnectionManager.prototype.stopGame = function (client, lobbyId) { + var lobby = room_1.Room.getByRoomId(lobbyId, this.rooms); + if (!lobby) + return; + lobby.stopGame(client); + (0, logger_1.log)('game-stopped', client, lobby); + }; + //Saves user feedback to a file + ConnectionManager.prototype.saveFeedbackToFile = function (client, content) { + var date = new Date(Date.now()).toString(); + var path = "feedback/" + client.game + '.txt'; + var saveToFile = function (content) { + fs.writeFile(path, content, function (err) { + if (err) + (0, logger_1.log)('save-error', client, null, err.message); + else + (0, logger_1.log)('feedback', client, null, path); + }); + }; + if (fs.existsSync(path)) { + fs.readFile(path, 'utf8', function (err, data) { + if (err) + (0, logger_1.log)('load-error', client, null, err.message); + else { + (0, logger_1.log)('load-success', client, null); + var newContent = data + '\n\n\n\n' + date + '\n\n' + content; + saveToFile(newContent); + } + }); + } + else { + saveToFile(date + '\n' + content); + } + }; + //Removes a disconnected client from all references + ConnectionManager.prototype.disconnected = function (client) { + var room = room_1.Room.getByClientId(client.id, this.rooms); + if (room) + client.leaveRoom(room.id); + (0, logger_1.log)('disconnection', client); + }; + return ConnectionManager; +}()); +exports.ConnectionManager = ConnectionManager; +function serializeObject(object) { + function serialize(obj) { + if (!obj) + return obj; + if (obj.serialized) + return obj.serialized; + else if (obj instanceof Array) { + var content_1 = []; + obj.forEach(function (o) { + content_1.push(serialize(o)); + }); + return content_1; + } + return obj; + } + return serialize(object); +} +exports.serializeObject = serializeObject; diff --git a/ts/manager.ts b/src/manager.ts similarity index 99% rename from ts/manager.ts rename to src/manager.ts index 85252b8..a7ba4af 100644 --- a/ts/manager.ts +++ b/src/manager.ts @@ -51,7 +51,6 @@ export class ConnectionManager { createRoom(settings: Settings.Global | any, name: string): Room { let roomId = Room.generateCode(10); - // @ts-ignore let room = new Room(name, roomId, settings, this.io); this.rooms.push(room); diff --git a/src/room.js b/src/room.js new file mode 100644 index 0000000..feefd00 --- /dev/null +++ b/src/room.js @@ -0,0 +1,164 @@ +"use strict"; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +exports.__esModule = true; +exports.Room = void 0; +var memory_1 = require("./games/memory"); +var pong_1 = require("./games/pong"); +var global_draw_1 = require("./games/global_draw"); +var chainreact_1 = require("./games/chainreact"); +var manager_1 = require("./manager"); +var Room = /** @class */ (function () { + function Room(name, id, settings, io) { + this.id = id; + this.name = name; + if (!io || !settings) + return; + this.settings = settings; + this.gameName = settings.project.name; + this.clientCounts = settings.project.playerCounts; + this.io = io; + this.clients = []; + this.gameSettings = {}; + } + Object.defineProperty(Room.prototype, "leader", { + get: function () { + return this.players[0]; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Room.prototype, "players", { + get: function () { + return this.clients.filter(function (c) { return c.isPlayer; }); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Room.prototype, "spectators", { + get: function () { + return this.clients.filter(function (c) { return c.isSpectator; }); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Room.prototype, "serialized", { + get: function () { + return { + id: this.id, + name: this.name, + game: this.gameName, + clientCounts: this.clientCounts, + clients: (0, manager_1.serializeObject)(this.clients), + hasStarted: this.hasStarted + }; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Room.prototype, "isEmpty", { + get: function () { + return !(this.clients.length); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Room.prototype, "hasStarted", { + get: function () { + return this.runningGame != null; + }, + enumerable: false, + configurable: true + }); + Room.getByRoomId = function (id, lobbies) { + for (var _i = 0, lobbies_1 = lobbies; _i < lobbies_1.length; _i++) { + var l = lobbies_1[_i]; + if (l.id === id) + return l; + } + return null; + }; + Room.getByClientId = function (id, lobbies) { + for (var _i = 0, lobbies_2 = lobbies; _i < lobbies_2.length; _i++) { + var l = lobbies_2[_i]; + for (var _a = 0, _b = l.clients; _a < _b.length; _a++) { + var c = _b[_a]; + if (c.id === id) + return l; + } + } + return null; + }; + Room.generateCode = function (elements) { + var code = ''; + var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + while (elements--) { + code += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return code; + }; + Room.prototype.startGame = function () { + var seed = Math.random() * 10000; + this.toAll('start-game', seed); + this.runGame(); + }; + Room.prototype.stopGame = function (client) { + this.toAll('stop-game', client); + this.runningGame = null; + }; + Room.prototype.add = function (client) { + this.clients.push(client); + var isPlayer = !this.hasStarted && this.hasValidPlayerCount(); + client.isPlayer = isPlayer; + client.isSpectator = !isPlayer; + client.isReady = false; + client.join(this.id); + this.toAll('member-joined', client.id, client.name); + this.toAll('client-list', this.clients); + this.toAll('game-settings', this.gameSettings); + if (this.hasStarted) + this.runningGame.addClient(client); + }; + Room.prototype.hasValidPlayerCount = function () { + var _this = this; + var valid = false; + this.clientCounts.forEach(function (c) { + if (c === _this.clients.length) + valid = true; + }); + return valid; + }; + Room.prototype.runGame = function () { + switch (this.gameName) { + case 'memory': + this.runningGame = new memory_1.Memory(this, this.settings); + break; + case 'pong': + this.runningGame = new pong_1.Pong(this, this.settings); + break; + case 'global-draw': + this.runningGame = new global_draw_1.GlobalDraw(this, this.settings); + break; + case 'chainreact': + this.runningGame = new chainreact_1.Chainreact(this, this.settings); + break; + } + }; + Room.prototype.toAll = function (event) { + var _a; + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + (_a = this.io.to(this.id)).emit.apply(_a, __spreadArray([event, (0, manager_1.serializeObject)(this)], (0, manager_1.serializeObject)(args), false)); + }; + return Room; +}()); +exports.Room = Room; diff --git a/ts/room.ts b/src/room.ts similarity index 100% rename from ts/room.ts rename to src/room.ts diff --git a/src/server.js b/src/server.js new file mode 100644 index 0000000..586050a --- /dev/null +++ b/src/server.js @@ -0,0 +1,27 @@ +'use strict'; +exports.__esModule = true; +var logger_1 = require("./logger"); +var manager_1 = require("./manager"); +var https = require("https"); +var socket_io_1 = require("socket.io"); +var fs = require("fs"); +var ini = require("ini"); +function GameServer() { + var p2p = require('socket.io-p2p-server').Server; + var rootDir = __dirname + '/..'; + var httpsPort = ini.parse(fs.readFileSync(rootDir + '/env_config.ini', 'utf-8'))['nodejs_port']; + var cert = fs.readFileSync(rootDir + '/ssl_certificate/cert.pem'); + var key = fs.readFileSync(rootDir + '/ssl_certificate/key.pem'); + var httpsServer = https.createServer({ key: key, cert: cert }); + var sIO = new socket_io_1.Server(httpsServer, { + cors: { + origin: ["https://play.benjamin-kraft.local", "https://dev.play.benjamin-kraft.eu", "https://play.benjamin-kraft.eu"] + } + }); + sIO.use(p2p); + httpsServer.listen(httpsPort); + var connectionManager = new manager_1.ConnectionManager(sIO); + // On new connection + sIO.on('connection', function (socket) { return connectionManager.newSocket(socket); }); + (0, logger_1.log)('startup', null, null, 'Server is listening on port ' + httpsPort); +} diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 0000000..33c2bd4 --- /dev/null +++ b/src/server.ts @@ -0,0 +1,39 @@ +'use strict'; + + +import {log} from "./logger"; +import {ConnectionManager} from "./manager"; + +import https = require('https'); +import {Server} from 'socket.io'; +import fs = require('fs'); +import ini = require('ini'); + +function GameServer(){ + const p2p = require('socket.io-p2p-server').Server; + + let rootDir = __dirname + '/..'; + + let httpsPort = ini.parse(fs.readFileSync(rootDir + '/env_config.ini', 'utf-8'))['nodejs_port']; + + let cert = fs.readFileSync(rootDir + '/ssl_certificate/cert.pem'); + let key = fs.readFileSync(rootDir + '/ssl_certificate/key.pem'); + + let httpsServer = https.createServer({key: key, cert: cert}); + + let sIO = new Server(httpsServer, { + cors: { + origin: ["https://play.benjamin-kraft.local", "https://dev.play.benjamin-kraft.eu", "https://play.benjamin-kraft.eu"] + } + }); + sIO.use(p2p); + + httpsServer.listen(httpsPort); + + let connectionManager = new ConnectionManager(sIO); + + // On new connection + sIO.on('connection', socket => connectionManager.newSocket(socket)); + + log('startup', null, null, 'Server is listening on port ' + httpsPort); +} diff --git a/ts/server.ts b/ts/server.ts deleted file mode 100644 index 6dda44b..0000000 --- a/ts/server.ts +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -import {log} from "./logger"; -import {ConnectionManager} from "./manager"; - -import https = require('https'); -import {Server} from 'socket.io'; -const p2p = require('socket.io-p2p-server').Server; -import fs = require('fs'); -import ini = require('ini'); - -let rootDir = __dirname + '/..'; - -let httpsPort = ini.parse(fs.readFileSync(rootDir + '/env_config.ini', 'utf-8'))['nodejs_port']; - -let cert = fs.readFileSync(rootDir + '/ssl_certificate/cert.pem'); -let key = fs.readFileSync(rootDir + '/ssl_certificate/key.pem'); - -let httpsServer = https.createServer({key: key, cert: cert}); - -let sIO = new Server(httpsServer, { - cors: { - origin: ["https://play.benjamin-kraft.local", "https://dev.play.benjamin-kraft.eu", "https://play.benjamin-kraft.eu"] - } -}); -sIO.use(p2p); - -httpsServer.listen(httpsPort); - -let connectionManager = new ConnectionManager(sIO); - -// On new connection -sIO.on('connection', socket => connectionManager.newSocket(socket)); - -log('startup', null, null, 'Server is listening on port ' + httpsPort); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 60b7f14..ee01b53 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,13 +1,9 @@ { - "compilerOptions": { - "target": "es6", - "module": "commonjs", - "sourceMap": true, - "alwaysStrict": true, - "outDir": "./js", - "removeComments": true - }, - "include": [ - "./ts" - ] + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "sourceMap": true, + "alwaysStrict": true, + "removeComments": true + } } \ No newline at end of file