326 lines
10 KiB
JavaScript
326 lines
10 KiB
JavaScript
"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!");
|
|
};*/
|
|
|
|
|