Files
2025-04-24 19:03:40 +02:00

250 lines
8.6 KiB
JavaScript

const Express = require("express");
const express = Express.Router();
const fs = require("fs");
const path = require("path");
const iniparser = require("ini");
const config = iniparser.parse(fs.readFileSync(path.join(__dirname, "..", "Config", "config.ini")).toString());
const functions = require("./functions.js");
const WebSocket = require('ws');
let latestServerInfo = null;
const activeConnections = new Set();
express.post("/api/v1/server-info", async (req, res) => {
try {
if (!req.body.serverAddress || !req.body.serverPort) {
return res.status(400).json({ error: "Missing required server address or port" });
}
const { serverAddress, serverPort, sessionId, matchId, region, playlistName } = req.body;
latestServerInfo = {
serverAddress,
serverPort: Number(serverPort),
matchId: matchId || functions.MakeID().replace(/-/ig, ""),
sessionId: sessionId || functions.MakeID().replace(/-/ig, ""),
region: region || "EU",
playlistName: playlistName || "Playlist_DefaultSolo",
timestamp: Date.now()
};
console.log(`[ServerInfo] Received new server info: ${serverAddress}:${serverPort}`);
broadcastToAllConnections();
return res.status(200).json({ success: true });
} catch (error) {
console.error("Error processing server info:", error);
return res.status(500).json({ error: "Internal server error" });
}
});
function broadcastToAllConnections() {
if (!latestServerInfo) {
console.log("[Matchmaking] No server info available to broadcast");
return;
}
console.log(`[Matchmaking] Broadcasting to ${activeConnections.size} active connections`);
const broadcastMatchId = functions.MakeID().replace(/-/ig, "");
const broadcastSessionId = broadcastMatchId;
activeConnections.forEach(ws => {
if (ws.readyState === WebSocket.OPEN) {
try {
console.log(`[Matchmaking] Sending SessionAssignment to client`);
ws.send(
JSON.stringify({
payload: {
matchId: broadcastMatchId,
sessionId: broadcastSessionId,
state: "SessionAssignment",
},
name: "StatusUpdate",
})
);
ws.sessionId = broadcastSessionId;
ws.matchId = broadcastMatchId;
} catch (err) {
console.error("[Matchmaking] Error sending SessionAssignment:", err);
}
}
});
setTimeout(() => {
activeConnections.forEach(ws => {
if (ws.readyState === WebSocket.OPEN) {
try {
console.log(`[Matchmaking] Sending Play message to client`);
ws.send(
JSON.stringify({
payload: {
matchId: broadcastMatchId,
sessionId: broadcastSessionId,
joinDelaySec: 1,
},
name: "Play",
})
);
} catch (err) {
console.error("[Matchmaking] Error sending Play message:", err);
}
}
});
}, 2000);
}
function registerConnection(ws) {
activeConnections.add(ws);
console.log(`[Matchmaking] New connection registered, total: ${activeConnections.size}`);
if (latestServerInfo && latestServerInfo.timestamp > Date.now() - (5 * 60 * 1000)) {
console.log("[Matchmaking] Server info already available, sending to new connection");
const newMatchId = functions.MakeID().replace(/-/ig, "");
const newSessionId = newMatchId;
setTimeout(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(
JSON.stringify({
payload: {
matchId: newMatchId,
sessionId: newSessionId,
state: "SessionAssignment",
},
name: "StatusUpdate",
})
);
ws.sessionId = newSessionId;
ws.matchId = newMatchId;
setTimeout(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(
JSON.stringify({
payload: {
matchId: newMatchId,
sessionId: newSessionId,
joinDelaySec: 1,
},
name: "Play",
})
);
}
}, 2000);
}
}, 3000);
}
}
function unregisterConnection(ws) {
activeConnections.delete(ws);
console.log(`[Matchmaking] Connection closed, total: ${activeConnections.size}`);
}
global.matchmakingFunctions = {
registerConnection,
unregisterConnection
};
express.get("/fortnite/api/matchmaking/session/findPlayer/*", async (req, res) => {
res.status(200);
res.end();
})
express.get("/fortnite/api/game/v2/matchmakingservice/ticket/player/*", async (req, res) => {
res.cookie("currentbuildUniqueId", req.query.bucketId.split(":")[0]);
res.json({
"serviceUrl": `ws://${config.MatchmakerIP || "26.36.134.252"}`,
"ticketType": "mms-player",
"payload": "69=",
"signature": "420="
})
res.end();
})
express.get("/fortnite/api/game/v2/matchmaking/account/:accountId/session/:sessionId", async (req, res) => {
res.json({
"accountId": req.params.accountId,
"sessionId": req.params.sessionId,
"key": "AOJEv8uTFmUh7XM2328kq9rlAzeQ5xzWzPIiyKn2s7s="
})
})
express.get("/fortnite/api/matchmaking/session/:session_id", async (req, res) => {
let serverAddress = config.GameServer.ip;
let serverPort = Number(config.GameServer.port);
let playlistName = "Playlist_DefaultSolo";
let region = "EU";
if (latestServerInfo) {
console.log(`[Matchmaking] Using latest server info: ${latestServerInfo.serverAddress}:${latestServerInfo.serverPort}`);
serverAddress = latestServerInfo.serverAddress;
serverPort = latestServerInfo.serverPort;
playlistName = latestServerInfo.playlistName;
region = latestServerInfo.region;
} else {
console.log(`[Matchmaking] No server info available, using defaults`);
}
res.json({
"id": req.params.session_id,
"ownerId": functions.MakeID().replace(/-/ig, "").toUpperCase(),
"ownerName": "[DS]fortnite-liveeugcec1c2e30ubrcore0a-z8hj-1968",
"serverName": "[DS]fortnite-liveeugcec1c2e30ubrcore0a-z8hj-1968",
"serverAddress": serverAddress,
"serverPort": serverPort,
"maxPublicPlayers": 220,
"openPublicPlayers": 175,
"maxPrivatePlayers": 0,
"openPrivatePlayers": 0,
"attributes": {
"REGION_s": region,
"GAMEMODE_s": "FORTATHENA",
"ALLOWBROADCASTING_b": true,
"SUBREGION_s": "GB",
"DCID_s": "FORTNITE-LIVEEUGCEC1C2E30UBRCORE0A-14840880",
"tenant_s": "Fortnite",
"MATCHMAKINGPOOL_s": "Any",
"STORMSHIELDDEFENSETYPE_i": 0,
"HOTFIXVERSION_i": 0,
"PLAYLISTNAME_s": playlistName,
"SESSIONKEY_s": functions.MakeID().replace(/-/ig, "").toUpperCase(),
"TENANT_s": "Fortnite",
"BEACONPORT_i": 15009
},
"publicPlayers": [],
"privatePlayers": [],
"totalPlayers": 45,
"allowJoinInProgress": false,
"shouldAdvertise": false,
"isDedicated": false,
"usesStats": false,
"allowInvites": false,
"usesPresence": false,
"allowJoinViaPresence": true,
"allowJoinViaPresenceFriendsOnly": false,
"buildUniqueId": req.cookies.currentbuildUniqueId || "0",
"lastUpdated": new Date().toISOString(),
"started": false
})
})
express.post("/fortnite/api/matchmaking/session/*/join", async (req, res) => {
res.status(204);
res.end();
})
express.post("/fortnite/api/matchmaking/session/matchMakingRequest", async (req, res) => {
res.json([])
})
module.exports = express;