Initial commit

This commit is contained in:
2026-08-24 22:20:36 +02:00
commit 62f7b1278a
251 changed files with 16670 additions and 0 deletions
+325
View File
@@ -0,0 +1,325 @@
"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!");
};*/