"use strict"; // console.info = () => null; // console.trace = () => null; console.log = () => null; global.socket = require("uWebSockets.js"); global.app = socket.App(); global.playerBehaviourContext = []; socket.sockets = {}; const { register } = require("./metrics"); require("./Routes/Routes"); require("./Utility/setTimer"); require("./Miscellaneous/mysql"); const MainLoop = require("./Core"); const LeaderboardLoop = require("./Timers/Leaderboard"); const BehaviourLoop = require("./Timers/Behaviour"); const ResourceLoop = require("./Timers/Resource"); const { Worker } = require("worker_threads"); global.PlayerWorker = new Worker("./Worker/Player.js"); global.NPCWorker = new Worker("./Worker/NPC.js"); global.StatisticsWorker = new Worker("./Worker/Statistics.js"); const messageHandler = require("./Events/message"); const closeHandler = require("./Events/close"); const openHandler = require("./Events/open"); const drainHandler = require("./Events/drain"); const upgradeHandler = require("./Events/upgrade"); const Game = require("./Game/Game"); const Guild = require("./Game/Guild"); const GuildIsland = require("./Game/GuildIsland"); const leaderboards = require("./Data/leaderboard"); const queries = require("./Data/queries"); const BASE_SHOP = require("./Data/shop"); const { SHOP } = BASE_SHOP; const formatMemoryUsage = data => `${Math.round(data / 1024 / 1024 * 100) / 100} MB`; function log(level, message) { const LOG_LEVELS = { "OK": "32", "FATAL": "31" }; console.info(`[\x1b[33m%s\x1b[0m] \x1b[${LOG_LEVELS[level]}m%s\x1b[0m`, level, message); }; function scheduleGc() { setTimeout(() => { let pn = performance.now(); global.gc(); console.info(performance.now() - pn); /* const memoryData = process.memoryUsage(); const memoryUsage = { rss: `${formatMemoryUsage(memoryData.rss)} -> Resident Set Size - total memory allocated for the process execution`, heapTotal: `${formatMemoryUsage(memoryData.heapTotal)} -> total size of the allocated heap`, heapUsed: `${formatMemoryUsage(memoryData.heapUsed)} -> actual memory used during the execution`, external: `${formatMemoryUsage(memoryData.external)} -> V8 external memory`, arrayBuffers: `${formatMemoryUsage(memoryData.arrayBuffers)} -> arraybuffers`, };*/ // process.exit(1); scheduleGc(); }, 600000); }; scheduleGc(); const promise = new Promise(async (resolve, reject) => { leaderboards.forEach(async (leaderboard, i) => { const databaseName = `leaderboard_${i + 1}`; const leaderboardSizeFromDB = await execute(`SELECT COUNT(*) AS count FROM ${databaseName}`); if (!leaderboardSizeFromDB.data) return reject(leaderboardSizeFromDB.message); // I don't think this is good leaderboard.size = leaderboardSizeFromDB.data[0].count; }); const shopEntries = await execute(queries.QUERY_FETCH_SHOP_ENTRIES); if (!shopEntries.data) return reject(shopEntries.error); shopEntries.data.forEach(entry => { const shopEntry = { id: entry.id, itemID: entry.itemID, categoryID: entry.categoryID, currencyType: entry.currencyType, currencyAmount: entry.currencyAmount, unit: entry.unit, shopCategoryID: 2, isAvailable: () => true }; SHOP.push(shopEntry); }); console.info(SHOP) const guildResources = await execute(queries.QUERY_FETCH_GUILD_RESOURCES); if (!guildResources.data) return reject(guildResources.error); const guildDiplomacies = await execute(queries.QUERY_FETCH_GUILD_DIPLOMACIES); if (!guildDiplomacies.data) return reject(guildDiplomacies.error); const guildRequests = await execute(queries.QUERY_FETCH_GUILD_REQUESTS); if (!guildRequests.data) return reject(guildRequests.error); const guildMembers = await execute(queries.QUERY_FETCH_GUILD_MEMBERS); if (!guildMembers.data) return reject(guildMembers.error); const guildIslandsFromDB = await execute(queries.QUERY_FETCH_GUILD_ISLANDS); if (!guildIslandsFromDB.data) return reject(guildIslandsFromDB.error); const guildIslandDamagesFromDB = await execute(queries.QUERY_FETCH_GUILD_ISLAND_DAMAGES); if (!guildIslandDamagesFromDB.data) return reject(guildIslandDamagesFromDB.error); const islands = guildIslandsFromDB.data.reduce((acc, cur) => { if (acc[cur.guildID]) acc[cur.guildID].push(cur); else acc[cur.guildID] = [cur]; return acc; }, {}) guildMembers.data.forEach(entry => { let guild = Game.guilds[entry.id]; if (!guild) { console.info("Guild", entry.id, entry.name, entry.tag) guild = Game.guilds[entry.id] = new Guild({ id: entry.id, name: entry.name, tag: entry.tag, description: entry.description, ownerID: entry.createdBy, experiencePoints: entry.experiencePoints, taxRates: [entry.taxRateGold, entry.taxRateEmerald], timestamps: { taxRatesEditedAt: new Date(entry.taxRatesEditedAt).getTime() / 1000, tagEditedAt: new Date(entry.tagEditedAt).getTime() / 1000, nameEditedAt: new Date(entry.nameEditedAt).getTime() / 1000, descriptionEditedAt: new Date(entry.descriptionEditedAt).getTime() / 1000 } }); const currentGuildIslands = islands[entry.id]; if (currentGuildIslands) { for (let i = 0, length = currentGuildIslands.length; i < length; i++) { const currentIsland = currentGuildIslands[i]; const island = new GuildIsland({ id: currentIsland.id, locationMapID: currentIsland.mapID, index: currentIsland.gindex, position: { x: currentIsland.positionX, y: currentIsland.positionY }, guild }); Game.guildIslands.push(island); const islandCaptureProgress = guildIslandDamagesFromDB.data.find(e => e.guildIslandID === currentIsland.id); if (islandCaptureProgress) island.updateReceivedDamage(islandCaptureProgress.guildID, islandCaptureProgress.damage); }; }; }; const member = { id: entry.playerID, permission: entry.permission }; guild.addMember(member); }); guildResources.data.forEach(entry => { const guild = Game.guilds[entry.guildID]; switch (entry.categoryID) { case 1: console.info("guild resource startup", entry) guild.bank.depositTax(entry); break; case 6: if (entry.id === 1) { guild.levelUpdate(entry.amount); console.info("LEVEL UPDATE", entry, guild.level, guild.experiencePoints) }; break; }; }); guildDiplomacies.data.forEach(entry => { // console.info(entry, Game.guilds[entry.guildID]) const guild = Game.guilds[entry.guildID]; guild.diplomacy[entry.targetGuildID] = entry.color; }); guildRequests.data.forEach(entry => { const guild = Game.guilds[entry.id]; const arrayBufferMessage = new ArrayBuffer(entry.message.length); const convertedMessage = new Uint8Array(arrayBufferMessage); for (let i = 0, strLen = entry.message.length; i < strLen; i++) { arrayBufferMessage[i] = entry.message.charCodeAt(i); }; guild.addRequest(entry.playerID, arrayBufferMessage); }); resolve(); }); promise.then(() => { app.ws("/ws", { idleTimeout: 50, maxBackpressure: 1024, maxPayloadLength: 512, compression: socket.DISABLED, upgrade: upgradeHandler, close: closeHandler, open: openHandler, drain: drainHandler, message: messageHandler }); app.get("/selection/:playerID", async (res, req) => { const playerID = req.getParameter(0); res.onAborted(() => { console.info("ABORTED!!!"); }); const playerQuery = await execute("SELECT designID, globalRank, levelRank, mapID FROM playerdata WHERE playerID = ?", [playerID]) console.info(playerQuery) if (!playerQuery.success) { console.info("t", playerQuery) res.cork(() => res.end(JSON.stringify({ ok: false }))); return; }; if (!playerQuery.data[0]) playerQuery.data[0] = { server: process.env.GAME_SERVER }; else playerQuery.data[0].server = process.env.GAME_SERVER; res.cork(() => res.end(JSON.stringify(playerQuery.data[0]))); }); app.get("/metrics", async (res, req) => { res.writeHeader("Content-Type", register.contentType); const metrics = await register.metrics(); res.end(metrics); }); app.listen("0.0.0.0", 9001, listenSocket => { if (!listenSocket) { log("FATAL", "Coudln't initialize listening to connections!"); process.exit(); }; require("./Handlers/Map"); MainLoop(); LeaderboardLoop(); BehaviourLoop(); ResourceLoop(); Game.listeningServer = listenSocket; log("OK", "Server is successfully initialized and is listening on *:9001!"); if (Game.state === 0) log("OK", `Game is running in restricted mode. To let players in, set game state to be 1.`); }); }).catch(e => { log("FATAL", "Couldn't initialize server, application error!", e); console.info(e); process.exit(); }); /* process.on("exit", function (code) { console.log("exit", code) }); ["beforeExit", "uncaughtException", "unhandledRejection", "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT" ,"SIGBUS", "SIGFPE", "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGTERM"] .forEach(sig => { process.on(sig, function (reason) { if (sig === "uncaughtException" || sig === "unhandledRejection") console.log(reason); terminator(sig); console.log("signal: " + sig); }); }); function terminator(sig) { if (typeof sig === "string") { socket.us_listen_socket_close(listeningServer); listeningServer = null; Game.disconnectAll(); setTimeout(() => { console.log(process.argv[0], process.argv.slice(1)) process.exit(1); }, 5000); }; console.log("Server has been stopped!"); };*/