diff --git a/dist/env.js b/dist/env.js new file mode 100644 index 0000000..b4c6537 --- /dev/null +++ b/dist/env.js @@ -0,0 +1 @@ +export const port = 8082; diff --git a/dist/game.js b/dist/game.js new file mode 100644 index 0000000..1c62fcf --- /dev/null +++ b/dist/game.js @@ -0,0 +1,38 @@ +import { Player } from "./player.js"; +import { roomManager } from "./roomManager.js"; +import { World } from "./world/world.js"; +export class Game { + constructor(id, options) { + this.id = id; + this.players = []; + this.oldWorld = []; + this.world = new World(options); + } + addPlayer(id, name, color) { + if (this.getAllNames().includes(name)) + return false; + const player = new Player(id, name, color); + this.players.push(player); + return player; + } + removePlayerByID(id) { + this.players = this.players.filter(obj => obj.id != id); + if (this.players.length < 1) { + roomManager.removeGameByID(this.id); + } + } + getAllIDs() { + let ids = []; + for (let i = 0; i < this.players.length; i++) { + ids.push(this.players[i].id); + } + return ids; + } + getAllNames() { + let names = []; + for (let i = 0; i < this.players.length; i++) { + names.push(this.players[i].name); + } + return names; + } +} diff --git a/dist/log.js b/dist/log.js new file mode 100644 index 0000000..1ee067d --- /dev/null +++ b/dist/log.js @@ -0,0 +1,115 @@ +import * as os from "os"; +var mode = 0; +var logs = []; +var rightView = [0, 1, 2, 3, 4, 5, 6]; +var info = [[], []]; +export function setMode(type) { + mode = type; +} +export function updateLog() { + if (mode) + return; + let templogs = logs; + console.clear(); + const columns = process.stdout.columns; + const rows = process.stdout.rows; + const vertSplit = Math.round(rows / 4); + for (var i = 0; i < vertSplit; i++) { + process.stdout.cursorTo(Math.round(columns / 2), i); + process.stdout.clearLine(); + process.stdout.write(`|`); + } + for (var i = 0; i < columns; i++) { + process.stdout.cursorTo(i + 1, vertSplit); + process.stdout.write(`=`); + } + process.stdout.cursorTo(0, 0); + process.stdout.write("Players:"); + const games = info[0]; + var pointer = 0; + for (i = 0; i < games.length; i++) { + process.stdout.cursorTo(0, pointer + 1); + process.stdout.write(`\x1b[46mGameName: \x1b[1m${games[i].name}\x1b[0m`); + const players = games[i].players; + for (var j = 0; j < players.length; j++) { + process.stdout.cursorTo(0, pointer + 2); + process.stdout.write(`--Name: \x1b[1m${players[j].name}\x1b[0m -\x1b[1m ID:${players[j].id}\x1b[0m`); + pointer++; + } + pointer++; + } + if (templogs.length > Math.round(3 * rows / 4) - 3) { + templogs.splice(0, logs.length - Math.round(3 * rows / 4) + 2); + } + for (var i = 0; i < templogs.length; i++) { + process.stdout.cursorTo(0, vertSplit + 1 + i); + process.stdout.write(`${templogs[i]}${os.EOL}`); + } +} +export function log(string, color) { + if (mode) + return console.log(string); + if (string == undefined) + return; + var prefix = ''; + switch (color) { + case "reset": + prefix = "\x1b[0m"; + break; + case "bright": + prefix = "\x1b[1m"; + break; + case "dim": + prefix = "\x1b[2m"; + break; + case "underscore": + prefix = "\x1b[4m"; + break; + case "reverse": + prefix = "\x1b[7m"; + break; + case "FgBlack": + prefix = "\x1b[30m"; + break; + case "FgRed": + prefix = "\x1b[31m"; + break; + case "FgGreen": + prefix = "\x1b[32m"; + break; + case "FgYellow": + prefix = "\x1b[33m"; + break; + case "FgBlue": + prefix = "\x1b[34m"; + break; + case "FgMagenta": + prefix = "\x1b[35m"; + break; + case "FgCyan": + prefix = "\x1b[36m"; + break; + case "FgWhite": + prefix = "\x1b[37m"; + break; + } + // BgBlack = "\x1b[40m" + // BgRed = "\x1b[41m" + // BgGreen = "\x1b[42m" + // BgYellow = "\x1b[43m" + // BgBlue = "\x1b[44m" + // BgMagenta = "\x1b[45m" + // BgCyan = "\x1b[46m" + // BgWhite = "\x1b[47m" + const newString = prefix + string + "\x1b[0m"; + logs.push(newString); + updateLog(); +} +export function setInfo(players) { + if (mode) + return false; + if (players != undefined) { + info[0] = players; + updateLog(); + } +} diff --git a/dist/main.js b/dist/main.js new file mode 100644 index 0000000..18dffa6 --- /dev/null +++ b/dist/main.js @@ -0,0 +1,6 @@ +import "./roomManager.js"; +import "./server/netcode.js"; +setInterval(function () { updateInfo(); }, 5000); +function updateInfo() { + console.log("running..."); +} diff --git a/dist/player.js b/dist/player.js new file mode 100644 index 0000000..6c58d1f --- /dev/null +++ b/dist/player.js @@ -0,0 +1,7 @@ +export class Player { + constructor(id, name, color) { + this.id = id; + this.name = name; + this.color = color; + } +} diff --git a/dist/roomManager.js b/dist/roomManager.js new file mode 100644 index 0000000..3ada5a3 --- /dev/null +++ b/dist/roomManager.js @@ -0,0 +1,67 @@ +import { Game } from "./game.js"; +import * as util from "./util.js"; +import { IllegalAction } from "./server/illegalAction.js"; +class RoomManager { + constructor() { + this.games = []; + } + getGameByID(id) { + const game = this.games.filter(obj => obj.id == id)[0]; + if (game === undefined) { + return false; + } + return game; + } + addGame(id, options) { + const game = new Game(id, options); + this.games.push(game); + return game; + } + removeGameByID(id) { + this.games = this.games.filter(obj => obj.id != id); + } + getAllPlayerIDs() { + let ids = []; + for (let i = 0; i < this.games.length; i++) { + for (let j = 0; j < this.games[i].players.length; j++) { + ids.push(this.games[i].players[j].id); + } + } + return ids; + } + getAllGameIDs() { + let ids = []; + for (let i = 0; i < this.games.length; i++) { + ids.push(this.games[i].id); + } + return ids; + } + playerJoinGame(roomCode, playerName, playerID) { + // See if the client is already in a game + if (this.getAllPlayerIDs().includes(playerID)) { + return new IllegalAction(id, 22); + } + if (!this.getAllGameIDs().includes(roomCode)) { + return new IllegalAction(id, 30); + } + const game = this.getGameByID(roomCode); + const player = game.addPlayer(playerID, playerName); + // See if player name is taken already + if (player === false) { + this.removeGame(game); + return new IllegalAction(id, 20); + } + return [game, player]; + } + playerCreateGame(options, playerName, playerColor, playerID) { + if (this.getAllPlayerIDs().includes(playerID)) { + return new IllegalAction(id, 22); + } + console.log(options); + const id = util.createCode(); + const game = this.addGame(id, options); + const player = game.addPlayer(playerID, playerName, playerColor); + return [game, player]; + } +} +export var roomManager = new RoomManager(); diff --git a/dist/server/illegalAction.js b/dist/server/illegalAction.js new file mode 100644 index 0000000..066450b --- /dev/null +++ b/dist/server/illegalAction.js @@ -0,0 +1,11 @@ +import { io } from "./io.js"; +export class IllegalAction { + constructor(id, action) { + this.action = action; + this.id = id; + this.sendIllegalAction(); + } + sendIllegalAction() { + io.to(this.id).emit('illegalAction', this.action); + } +} diff --git a/dist/server/io.js b/dist/server/io.js new file mode 100644 index 0000000..a5e1ec3 --- /dev/null +++ b/dist/server/io.js @@ -0,0 +1,3 @@ +import { webServer } from "./server.js"; +import { Server } from "socket.io"; +export const io = new Server(webServer, {}); diff --git a/dist/server/netcode.js b/dist/server/netcode.js new file mode 100644 index 0000000..cee1009 --- /dev/null +++ b/dist/server/netcode.js @@ -0,0 +1,55 @@ +import { IllegalAction } from "./illegalAction.js"; +import { roomManager } from "../roomManager.js"; +import { io } from "./io.js"; +io.on('connection', function (client) { + connected(client); +}); +function connected(client) { + client.sync = function () { + const tempWorld = client.game.world.obfuscate(); + io.to(client.game.id).emit('sync', { world: tempWorld }); + }; + client.sendMeta = function () { + const roomID = client.game.id; + const roomPlayers = client.game.players; // Dont send client id's to everyone, TODO + const metadata = { players: roomPlayers, roomID: roomID }; + io.to(client.game.id).emit('metadata', metadata); + const id = client.game.id; + client.emit('message', id); + }; + client.game = ""; + client.player = ""; + client.on('disconnect', function () { + if (!roomManager.getAllPlayerIDs().includes(client.id)) + return new IllegalAction(client.id, 22); + client.game.removePlayerByID(client.id); + client.sendMeta(); + }); + client.on('joinGame', function (data) { + const info = roomManager.playerJoinGame(data.room, data.name, client.id); + client.join(info[0].id); + client.game = info[0]; + client.player = info[1]; + client.sync(); + client.emit('inGame', true); + client.sendMeta(); + }); + client.on('createGame', function (data) { + const info = roomManager.playerCreateGame(data.options, data.name, data.color, client.id); + client.join(info[0].id); + client.game = info[0]; + client.player = info[1]; + client.emit('inGame', true); + client.sync(); + client.sendMeta(); + }); + client.on('leaveGame', function (data) { + client.game.removePlayerByID(client.id); + }); + client.on('clickCanvas', function (data) { + if (!roomManager.getAllPlayerIDs().includes(client.id)) + return new IllegalAction(client.id, 1); + client.game.world.click(data.tilePosition[0], data.tilePosition[1], data.mode, client.player); + client.sync(); + }); +} diff --git a/dist/server/server.js b/dist/server/server.js new file mode 100644 index 0000000..2d3a67d --- /dev/null +++ b/dist/server/server.js @@ -0,0 +1,9 @@ +import path from 'path'; +import express from "express"; +import { port } from "../env.js"; +var app = express(); +const __dirname = path.resolve(path.dirname('')); +app.use(express.static(__dirname + '/www/')); +export var webServer = app.listen(port, function () { + var port = webServer.address().port; +}); diff --git a/dist/util.js b/dist/util.js new file mode 100644 index 0000000..cb302c3 --- /dev/null +++ b/dist/util.js @@ -0,0 +1,11 @@ +import crypto from "crypto"; +export function randomNumber(min, max) { + return Math.floor(Math.random() * (max - min) + min); +} +export function clamp(number, min, max) { + return Math.max(min, Math.min(number, max)); +} +export function createCode() { + const randomString = crypto.randomBytes(3).toString("hex").toUpperCase(); + return randomString; +} diff --git a/dist/world/flagger.js b/dist/world/flagger.js new file mode 100644 index 0000000..1cd456a --- /dev/null +++ b/dist/world/flagger.js @@ -0,0 +1,20 @@ +export function flag(x, y, data, player) { + let tile = data[x][y]; + if (!tile.mask || tile.color === 0) + return data; + const color = player.color * 1; + console.log(player); + switch (tile.flag) { + case (0): + tile.flag = color; + break; + case (color): + tile.flag = color + 16; + break; + default: + tile.flag = 0; + } + console.log(tile.flag); + data[x][y] = tile; + return data; +} diff --git a/dist/world/generator.js b/dist/world/generator.js new file mode 100644 index 0000000..10022c3 --- /dev/null +++ b/dist/world/generator.js @@ -0,0 +1,42 @@ +import * as util from "../util.js"; +const searchLoc = +// [ +// [0, 2], +// [-1, 1], [0, 1], [1, 1], +// [-2,0], [-1, 0],/*Start*/[1, 0], [2,0], +// [-1,-1], [0,-1], [1,-1], +// [0,-2] +// +// ] +[ + [-1, 1], [0, 1], [1, 1], + [-1, 0], [1, 0], + [-1, -1], [0, -1], [1, -1] +]; +export function generate(avoidX, avoidY, world) { + var minesPlanted = 0; + while (minesPlanted < world.mines || !(minesPlanted <= world.width * world.height - 15)) { + const x = util.randomNumber(0, world.width); + const y = util.randomNumber(0, world.height); + var suitable = true; + searchLoc.forEach(loc => { + const tempx = x + loc[0]; + const tempy = y + loc[1]; + if (tempx === avoidX && tempy === avoidX) { + suitable = false; + } + }); + if (x == avoidX && y == avoidY) { + suitable = false; + } + if (world.data[x][y].type == 5) { + suitable = false; + } + if (suitable) { + world.data[x][y].type = 5; + minesPlanted++; + } + } + world.isGenerated = true; + return world; +} diff --git a/dist/world/marker.js b/dist/world/marker.js new file mode 100644 index 0000000..1a504ce --- /dev/null +++ b/dist/world/marker.js @@ -0,0 +1,29 @@ +const searchLoc = [ + [-1, 1], [0, 1], [1, 1], + [-1, 0], [1, 0], + [-1, -1], [0, -1], [1, -1] +]; +// Place Numbers +export function mark(world) { + for (let x = 0; x < world.width; x++) { + for (let y = 0; y < world.height; y++) { + if (world.data[x][y].type === 1) { + var counter = 0; + searchLoc.forEach(location => { + const tempx = x + location[0]; + const tempy = y + location[1]; + if (tempx >= 0 && tempy >= 0 && tempx < world.width && tempy < world.height) { + if (world.data[tempx][tempy].type === 5) { + counter++; + } + } + }); + if (counter !== 0) { + world.data[x][y].type = 15 + counter; + } + } + } + } + world.isMarked = true; + return world; +} diff --git a/dist/world/obfuscator.js b/dist/world/obfuscator.js new file mode 100644 index 0000000..fa71b7b --- /dev/null +++ b/dist/world/obfuscator.js @@ -0,0 +1,13 @@ +export function obfuscate(world) { + let tempWorld = world; + for (let x = 0; x < tempWorld.width; x++) { + for (let y = 0; y < tempWorld.height; y++) { + if (tempWorld.data[x][y].mask === true) { + tempWorld.data[x][y].type = 0; + } + ; + tempWorld.isObfuscated = true; + } + } + return tempWorld; +} diff --git a/dist/world/placer.js b/dist/world/placer.js new file mode 100644 index 0000000..d92b7d1 --- /dev/null +++ b/dist/world/placer.js @@ -0,0 +1,12 @@ +import * as revealer from "./revealer.js"; +export function place(x, y, data) { + let tile = data[x][y]; + if (tile.mask === true) { + if (tile.mask && tile.flag === 0) { + tile.mask = false; + } + data[x][y] = tile; + revealer.reveal(x, y, data); + } + return data; +} diff --git a/dist/world/revealer.js b/dist/world/revealer.js new file mode 100644 index 0000000..7351f4f --- /dev/null +++ b/dist/world/revealer.js @@ -0,0 +1,35 @@ +const searchLoc = [ + [-1, 1], [0, 1], [1, 1], + [-1, 0], [1, 0], + [-1, -1], [0, -1], [1, -1] +]; +export function reveal(x, y, data) { + if (data[x][y].type !== 5) { + var toSearch = []; + var searchedLocations = []; + toSearch.push([x, y]); + if (data[x][y].type === 1) { + while (toSearch.length > 0) { + const x = toSearch[0][0]; + const y = toSearch[0][1]; + searchedLocations.push(toSearch[0]); + toSearch.shift(); + searchLoc.forEach(loc => { + const tempx = x + loc[0]; + const tempy = y + loc[1]; + if (tempx >= 0 && tempy >= 0 && tempx < data.length && tempy < data[0].length) { + if (data[tempx][tempy].type === 1 && data[tempx][tempy].mask === true) { + if (!toSearch.includes([tempx, tempy]) && !searchedLocations.includes([tempx, tempy])) { + toSearch.push([tempx, tempy]); + } + } + if (data[tempx][tempy].type !== 5) { + data[tempx][tempy].mask = false; + } + } + }); + } + } + return data; + } +} diff --git a/dist/world/world.js b/dist/world/world.js new file mode 100644 index 0000000..53a74d7 --- /dev/null +++ b/dist/world/world.js @@ -0,0 +1,53 @@ +import * as obfuscater from "./obfuscator.js"; +import * as generator from "./generator.js"; +import * as marker from "./marker.js"; +import * as log from "../log.js"; +import * as flagger from "./flagger.js"; +import * as placer from "./placer.js"; +export class World { + constructor(options) { + this.mines = options.mines; + this.width = options.width * 1; + this.height = options.height * 1; + this.isGenerated = false; + this.isObfuscated = false; + this.isMarked = false; + this.data = Array.from(Array(this.width), () => new Array(this.height)); + for (let x = 0; x < this.width; x++) { + for (let y = 0; y < this.height; y++) { + this.data[x][y] = { type: 1, flag: 0, mask: true }; + } + } + } + click(x, y, mode, player) { + if (this.isGenerated) { + if (mode === 2) { + this.data = flagger.flag(x, y, this.data, player); + } + if (mode === 0) { + this.data = placer.place(x, y, this.data, player); + } + } + else { + this.generate(x, y).mark(); + this.data = placer.place(x, y, this.data, player); + } + } + generate(x, y) { + if (this.isGenerated) + return log.log("Already Generated"); + return generator.generate(x, y, this); + } + mark() { + if (this.isMarked) + return log.log("Already Marked!"); + return marker.mark(this); + } + obfuscate() { + if (this.isObfuscated) + return log.log("already done"); + const tempWorld = JSON.parse(JSON.stringify(this)); + ; + return obfuscater.obfuscate(tempWorld); + } +} diff --git a/index.mjs b/index.mjs deleted file mode 100644 index 94fa5ca..0000000 --- a/index.mjs +++ /dev/null @@ -1,10 +0,0 @@ -import * as log from "./scripts/log.mjs" -import "./scripts/roomManager.mjs" -import "./scripts/server/netcode.mjs" -import {roomManager} from "./scripts/roomManager.mjs" -log.setMode(1); -setInterval(function(){ updateInfo()},5000) - -function updateInfo() { - log.setInfo(roomManager.games) -} diff --git a/package-lock.json b/package-lock.json index 4cd7f2e..8c0f6c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "empires", + "name": "MultiplayerMinesweeper", "version": "1.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "empires", + "name": "MultiplayerMinesweeper", "version": "1.0.0", "license": "UNLICENSED", "dependencies": { @@ -13,23 +13,92 @@ "sass": "^1.52.3", "socket.io": "^4.5.0", "socket.js": "^0.1.4", + "ts-node": "^10.8.1", "typescript": "^4.7.4" }, "devDependencies": { - "@tsconfig/node16": "^1.0.3" + "@tsconfig/node16": "^1.0.3", + "@types/express": "^4.17.13", + "@types/node": "^18.0.0" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, "node_modules/@tsconfig/node16": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } }, "node_modules/@types/component-emitter": { "version": "1.2.11", "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==" }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -40,11 +109,62 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.29", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz", + "integrity": "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, "node_modules/@types/node": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==" }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -57,6 +177,25 @@ "node": ">= 0.6" } }, + "node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -69,6 +208,11 @@ "node": ">= 8" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -219,6 +363,11 @@ "node": ">= 0.10" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -244,6 +393,14 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -558,6 +715,11 @@ "node": ">=0.12.0" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -956,6 +1118,48 @@ "node": ">=0.6" } }, + "node_modules/ts-node": { + "version": "10.8.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz", + "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -996,6 +1200,11 @@ "node": ">= 0.4.0" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -1023,20 +1232,88 @@ "optional": true } } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "engines": { + "node": ">=6" + } } }, "dependencies": { + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==" + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, "@tsconfig/node16": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } }, "@types/component-emitter": { "version": "1.2.11", "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==" }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -1047,11 +1324,62 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.29", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz", + "integrity": "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, "@types/node": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==" }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -1061,6 +1389,16 @@ "negotiator": "0.6.3" } }, + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + }, "anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -1070,6 +1408,11 @@ "picomatch": "^2.0.4" } }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -1178,6 +1521,11 @@ "vary": "^1" } }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1196,6 +1544,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1431,6 +1784,11 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1712,6 +2070,26 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "ts-node": { + "version": "10.8.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz", + "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==", + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -1736,6 +2114,11 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -1746,6 +2129,11 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", "requires": {} + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" } } } diff --git a/package.json b/package.json index 939e5d6..1575e90 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,30 @@ { - "name": "empires", + "name": "MultiplayerMinesweeper", "version": "1.0.0", "description": "", - "main": "index.mjs", + "main": "", + "type": "module", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "build": "" }, "repository": { "type": "git", "url": "empires" }, - "author": "", + "author": "Alexander Bass", "license": "UNLICENSED", "dependencies": { "express": "^4.18.1", "sass": "^1.52.3", "socket.io": "^4.5.0", "socket.js": "^0.1.4", + "ts-node": "^10.8.1", "typescript": "^4.7.4" }, "devDependencies": { - "@tsconfig/node16": "^1.0.3" + "@tsconfig/node16": "^1.0.3", + "@types/express": "^4.17.13", + "@types/node": "^18.0.0" } } diff --git a/src/env.ts b/src/env.ts new file mode 100644 index 0000000..b4c6537 --- /dev/null +++ b/src/env.ts @@ -0,0 +1 @@ +export const port = 8082; diff --git a/src/game.ts b/src/game.ts new file mode 100644 index 0000000..a9b64f9 --- /dev/null +++ b/src/game.ts @@ -0,0 +1,42 @@ +import {Player} from "./player.js" +import * as log from "./log.js" +import {roomManager} from "./roomManager.js" +import { World} from "./world/world.js" + +export class Game { + constructor(id, options) { + this.id = id; + this.players = []; + this.oldWorld = [] + this.world = new World(options) + } + + addPlayer(id, name, color) { + if (this.getAllNames().includes(name)) return false + const player = new Player(id, name, color); + this.players.push(player); + return player + } + + removePlayerByID(id) { + this.players = this.players.filter(obj => obj.id != id); + if (this.players.length < 1) { + roomManager.removeGameByID(this.id); + } + } + + getAllIDs() { + let ids = [] + for (let i = 0; i < this.players.length; i++) { + ids.push(this.players[i].id) + } + return ids + } + getAllNames() { + let names = [] + for (let i = 0; i < this.players.length; i++) { + names.push(this.players[i].name) + } + return names + } +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..b9a2a7c --- /dev/null +++ b/src/main.ts @@ -0,0 +1,8 @@ +import "./roomManager.js" +import "./server/netcode.js" +import {roomManager} from "./roomManager.js" + +setInterval(function(){ updateInfo()},5000) +function updateInfo() { + console.log("running...") +} diff --git a/src/player.ts b/src/player.ts new file mode 100644 index 0000000..2720897 --- /dev/null +++ b/src/player.ts @@ -0,0 +1,7 @@ +export class Player { + constructor(id, name, color) { + this.id = id; + this.name = name; + this.color = color; + } +} diff --git a/src/roomManager.ts b/src/roomManager.ts new file mode 100644 index 0000000..cf1cb2c --- /dev/null +++ b/src/roomManager.ts @@ -0,0 +1,77 @@ +import {Game} from "./game.js" +import * as util from "./util.js" +import {IllegalAction} from "./server/illegalAction.js" +class RoomManager { + constructor(){ + this.games = []; + } + getGameByID(id) { + const game = this.games.filter(obj => obj.id == id)[0] + if (game === undefined) { + return false + } + return game + } + + addGame(id, options) { + const game = new Game(id, options); + this.games.push(game); + return game + } + removeGameByID(id) { + this.games = this.games.filter(obj => obj.id != id); + + } + + getAllPlayerIDs() { + let ids = [] + for (let i = 0; i < this.games.length; i++) { + for (let j = 0; j < this.games[i].players.length; j++) { + ids.push(this.games[i].players[j].id) + } + } + return ids + } + + getAllGameIDs() { + let ids = [] + for (let i = 0; i < this.games.length; i++) { + ids.push(this.games[i].id) + } + return ids + } + + playerJoinGame(roomCode, playerName, playerID) { + // See if the client is already in a game + if (this.getAllPlayerIDs().includes(playerID)) { + return new IllegalAction(id, 22) + } + if (!this.getAllGameIDs().includes(roomCode)) { + return new IllegalAction(id, 30) + } + const game = this.getGameByID(roomCode); + const player = game.addPlayer(playerID, playerName); + // See if player name is taken already + if (player === false) { + this.removeGame(game) + return new IllegalAction(id, 20) + } + return [game, player] + } + + playerCreateGame(options, playerName, playerColor, playerID) { + if (this.getAllPlayerIDs().includes(playerID)) { + return new IllegalAction(id, 22) + } + console.log(options) + const id = util.createCode() + const game = this.addGame(id, options) + const player = game.addPlayer(playerID, playerName, playerColor); + return [game, player] + + } + +} + + +export var roomManager = new RoomManager(); diff --git a/src/server/illegalAction.ts b/src/server/illegalAction.ts new file mode 100644 index 0000000..d0876ae --- /dev/null +++ b/src/server/illegalAction.ts @@ -0,0 +1,11 @@ +import {io} from "./io.js" +export class IllegalAction { + constructor(id, action){ + this.action = action + this.id = id + this.sendIllegalAction(); + } + sendIllegalAction() { + io.to(this.id).emit('illegalAction', this.action) + } +} diff --git a/src/server/io.ts b/src/server/io.ts new file mode 100644 index 0000000..ace2584 --- /dev/null +++ b/src/server/io.ts @@ -0,0 +1,4 @@ +import {webServer} from "./server.js" +import { Server } from "socket.io"; + +export const io = new Server(webServer, {}); diff --git a/src/server/netcode.ts b/src/server/netcode.ts new file mode 100644 index 0000000..d726c9d --- /dev/null +++ b/src/server/netcode.ts @@ -0,0 +1,64 @@ +import {IllegalAction} from "./illegalAction.js" +import * as log from "../log.js" +import {roomManager} from "../roomManager.js" +import {io} from "./io.js" + +io.on('connection', function(client){ + connected(client) +}); + + +function connected(client) { + client.sync = function() { + const tempWorld = client.game.world.obfuscate(); + io.to(client.game.id).emit('sync',{world: tempWorld}) + } + + client.sendMeta = function() { + const roomID = client.game.id + const roomPlayers = client.game.players; // Dont send client id's to everyone, TODO + const metadata = {players: roomPlayers, roomID: roomID} + io.to(client.game.id).emit('metadata', metadata) + const id = client.game.id + client.emit('message', id) + } + + client.game = ""; + client.player = ""; + + client.on('disconnect', function(){ + if (!roomManager.getAllPlayerIDs().includes(client.id)) return new IllegalAction(client.id, 22) + client.game.removePlayerByID(client.id) + client.sendMeta(); + }) + + client.on('joinGame', function(data){ + const info = roomManager.playerJoinGame(data.room, data.name, client.id) + client.join(info[0].id) + client.game = info[0]; + client.player = info[1] + client.sync() + client.emit('inGame', true) + client.sendMeta() + }) + + client.on('createGame', function(data){ + const info = roomManager.playerCreateGame(data.options, data.name, data.color, client.id) + client.join(info[0].id) + client.game = info[0]; + client.player = info[1] + client.emit('inGame', true) + client.sync() + client.sendMeta() + }) + + client.on('leaveGame', function(data){ + client.game.removePlayerByID(client.id) + }) + + client.on('clickCanvas', function(data){ + if (!roomManager.getAllPlayerIDs().includes(client.id)) return new IllegalAction(client.id, 1) + client.game.world.click(data.tilePosition[0],data.tilePosition[1], data.mode, client.player) + client.sync() + }) +} diff --git a/src/server/server.ts b/src/server/server.ts new file mode 100644 index 0000000..8f8e610 --- /dev/null +++ b/src/server/server.ts @@ -0,0 +1,10 @@ +import path from 'path'; +import express from "express" +import { port } from "../env.js" +var app = express() + +const __dirname = path.resolve(path.dirname('')); +app.use(express.static(__dirname + '/www/')); +export var webServer = app.listen(port, function () { + var port = webServer.address().port; +}); diff --git a/src/util.ts b/src/util.ts new file mode 100644 index 0000000..c49079d --- /dev/null +++ b/src/util.ts @@ -0,0 +1,12 @@ +import crypto from "crypto"; +export function randomNumber(min, max) { + return Math.floor(Math.random() * (max - min) + min); +} +export function clamp(number, min, max) { + return Math.max(min, Math.min(number, max)); +} + +export function createCode() { + const randomString = crypto.randomBytes(3).toString("hex").toUpperCase() + return randomString +} diff --git a/src/world/flagger.ts b/src/world/flagger.ts new file mode 100644 index 0000000..7fd95f1 --- /dev/null +++ b/src/world/flagger.ts @@ -0,0 +1,22 @@ + +export function flag(x, y, data, player) { + let tile = data[x][y] + + if (!tile.mask || tile.color === 0) return data + const color = player.color * 1 + console.log(player) + + switch (tile.flag) { + case (0): + tile.flag = color; + break; + case (color): + tile.flag = color + 16; + break; + default: + tile.flag = 0; + } + console.log(tile.flag) + data[x][y] = tile + return data; +} diff --git a/src/world/generator.ts b/src/world/generator.ts new file mode 100644 index 0000000..7af0462 --- /dev/null +++ b/src/world/generator.ts @@ -0,0 +1,42 @@ +import * as util from "../util.js" +const searchLoc = +// [ +// [0, 2], +// [-1, 1], [0, 1], [1, 1], +// [-2,0], [-1, 0],/*Start*/[1, 0], [2,0], +// [-1,-1], [0,-1], [1,-1], +// [0,-2] +// +// ] +[ + [-1,1], [0,1], [1,1], + [-1,0], [1,0], + [-1,-1],[0,-1],[1,-1] +] + +export function generate(avoidX, avoidY, world){ + var minesPlanted = 0; + while (minesPlanted < world.mines || !(minesPlanted <= world.width*world.height-15)) { + const x = util.randomNumber(0,world.width) + const y = util.randomNumber(0,world.height) + var suitable = true; + searchLoc.forEach(loc => { + const tempx = x + loc[0] + const tempy = y + loc[1] + if (tempx === avoidX && tempy === avoidX) { + suitable = false; + } + }) + + if (x == avoidX && y == avoidY) { suitable = false } + if (world.data[x][y].type == 5) { suitable = false } + + if (suitable) { + world.data[x][y].type = 5 + minesPlanted++; + } + } + + world.isGenerated = true; + return world; +} diff --git a/src/world/marker.ts b/src/world/marker.ts new file mode 100644 index 0000000..7bff182 --- /dev/null +++ b/src/world/marker.ts @@ -0,0 +1,32 @@ +const searchLoc = +[ + [-1,1], [0,1], [1,1], + [-1,0], [1,0], + [-1,-1],[0,-1],[1,-1] +] +// Place Numbers +export function mark(world) { + +for(let x = 0; x < world.width; x++){ + for(let y = 0; y < world.height; y++){ + if (world.data[x][y].type === 1) { + var counter = 0; + searchLoc.forEach(location => { + const tempx = x + location[0] + const tempy = y + location[1] + if (tempx >= 0 && tempy >= 0 && tempx < world.width && tempy < world.height) { + if (world.data[tempx][tempy].type === 5) { + counter++; + } + } + }); + if (counter !== 0) { + world.data[x][y].type = 15 + counter + } + } + } +} + world.isMarked = true; + return world; + +} diff --git a/src/world/obfuscator.ts b/src/world/obfuscator.ts new file mode 100644 index 0000000..d1cb45f --- /dev/null +++ b/src/world/obfuscator.ts @@ -0,0 +1,16 @@ + +export function obfuscate(world) { + let tempWorld = world; + for(let x = 0; x < tempWorld.width; x++){ + for(let y = 0; y < tempWorld.height; y++){ + + if (tempWorld.data[x][y].mask === true) { + + tempWorld.data[x][y].type = 0; + }; + tempWorld.isObfuscated = true; + + } + } + return tempWorld; +} diff --git a/src/world/placer.ts b/src/world/placer.ts new file mode 100644 index 0000000..59bc1ed --- /dev/null +++ b/src/world/placer.ts @@ -0,0 +1,14 @@ +import * as log from "../log.js" +import * as revealer from "./revealer.js" +export function place(x, y, data) { + let tile = data[x][y]; + if (tile.mask === true) { + if (tile.mask && tile.flag === 0) { + tile.mask = false; + } + + data[x][y] = tile; + revealer.reveal(x, y, data) + } + return data; +} diff --git a/src/world/revealer.ts b/src/world/revealer.ts new file mode 100644 index 0000000..91442f3 --- /dev/null +++ b/src/world/revealer.ts @@ -0,0 +1,43 @@ + +const searchLoc = +[ + [-1,1], [0,1], [1,1], + [-1,0], [1,0], + [-1,-1],[0,-1],[1,-1] +] + +export function reveal(x, y, data) { + if (data[x][y].type !== 5) { + + var toSearch = []; + var searchedLocations = []; + toSearch.push([x, y]) + + if (data[x][y].type === 1) { + while (toSearch.length > 0) { + const x = toSearch[0][0] + const y = toSearch[0][1] + searchedLocations.push(toSearch[0]) + toSearch.shift() + searchLoc.forEach(loc => { + const tempx = x + loc[0] + const tempy = y + loc[1] + if (tempx >= 0 && tempy >= 0 && tempx < data.length && tempy < data[0].length) { + + if (data[tempx][tempy].type === 1 && data[tempx][tempy].mask === true) { + + if (!toSearch.includes([tempx,tempy]) && !searchedLocations.includes([tempx,tempy])) { + toSearch.push([tempx,tempy]) + } + } + if (data[tempx][tempy].type !== 5) { + data[tempx][tempy].mask = false; + } + } + }) + + } + } + return data + } +} diff --git a/src/world/world.ts b/src/world/world.ts new file mode 100644 index 0000000..5e7ab26 --- /dev/null +++ b/src/world/world.ts @@ -0,0 +1,56 @@ +import * as obfuscater from "./obfuscator.js"; +import * as generator from "./generator.js" +import * as marker from "./marker.js" +import * as log from "../log.js" +import * as flagger from "./flagger.js" +import * as placer from "./placer.js" + +export class World { + constructor(options) { + this.mines = options.mines + this.width = options.width*1 + this.height = options.height*1 + this.isGenerated = false; + this.isObfuscated = false; + this.isMarked = false; + this.data = Array.from(Array(this.width), () => new Array(this.height)); + for (let x = 0; x < this.width; x++){ + for (let y = 0; y < this.height; y++){ + this.data[x][y] = {type: 1, flag: 0, mask: true} + } + } + } + + click (x, y, mode, player) { + if (this.isGenerated) { + if (mode === 2) { + this.data = flagger.flag(x, y, this.data, player) + } + + if (mode === 0) { + this.data = placer.place(x, y, this.data, player) + } + } else { + this.generate(x, y).mark(); + this.data = placer.place(x, y, this.data, player) + } + + } + + generate(x, y) { + if (this.isGenerated) return log.log("Already Generated"); + return generator.generate(x, y, this); + } + + mark() { + if (this.isMarked) return log.log("Already Marked!"); + return marker.mark(this); + } + + obfuscate() { + if (this.isObfuscated) return log.log("already done") + const tempWorld = JSON.parse(JSON.stringify(this));; + return obfuscater.obfuscate(tempWorld); + } + +} diff --git a/tsconfig.json b/tsconfig.json index 2538fc9..275a6bc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,13 @@ { "extends": "@tsconfig/node16/tsconfig.json", - "compilerOptions": {}, + "compilerOptions": { + "module": "es2015", + "target": "es6", + "rootDir": "src", + "outDir": "dist", + "sourceMap": false, + "strict": true + }, "include": ["src"], "exclude": ["node_modules"] }