const Express = require("express"); const express = Express(); const fs = require("fs"); const crypto = require("crypto"); const path = require("path"); const iniparser = require("ini"); const config = iniparser.parse(fs.readFileSync(path.join(__dirname, "Config", "config.ini")).toString()); const memory = require("./memory.json"); const friendslist = require("./responses/friendslist.json"); const friendslist2 = require("./responses/friendslist2.json"); const keychain = require("./responses/keychain.json"); const privacy = require("./responses/privacy.json"); const catalog = getItemShop(); var Memory_CurrentAccountID = makeid().replace(/-/ig, ""); express.use(function(req, res, next) { // Getting the raw body of a request for client saving if (req.originalUrl.includes('/fortnite/api/cloudstorage/user/')) { req.rawBody = ''; req.setEncoding('latin1'); req.on('data', function(chunk) { req.rawBody += chunk; }); req.on('end', function() { next(); }); } else { return next(); } }); express.use(Express.json()); express.use(Express.urlencoded({ extended: true })); express.use(Express.static('public')); const port = process.env.PORT || 3551; express.listen(port, console.log("Started listening on port", port)); if (!fs.existsSync(path.join(process.env.LOCALAPPDATA, "LawinServer"))) { fs.mkdirSync(path.join(process.env.LOCALAPPDATA, "LawinServer")); } express.get("/clearitemsforshop", async (req, res) => { res.set("Content-Type", "text/plain"); const athena = require("./profiles/athena.json"); const CatalogConfig = require("./Config/catalog_config.json"); var StatChanged = false; for (var value in CatalogConfig) { for (var key in athena.items) { if (typeof CatalogConfig[value].templateId == "string") { if (CatalogConfig[value].templateId.length != 0) { if (CatalogConfig[value].templateId.toLowerCase() == athena.items[key].templateId.toLowerCase()) { delete athena.items[key] StatChanged = true; } } } } } if (StatChanged == true) { athena.rvn += 1; athena.commandRevision += 1; fs.writeFileSync("./profiles/athena.json", JSON.stringify(athena, null, 2)); } res.send('Success') }) express.get("/fortnite/api/storefront/v2/catalog", async (req, res) => { if (req.headers["user-agent"].includes("2870186")) { return res.status(404).end(); } res.json(catalog); }); express.get("/purchase", async (req, res) => { res.json({}); }) express.get("/lightswitch/api/service/Fortnite/status", async (req, res) => { res.json({ "serviceInstanceId": "fortnite", "status": "UP", "message": "Fortnite is online", "maintenanceUri": null, "overrideCatalogIds": [ "a7f138b2e51945ffbfdacc1af0541053" ], "allowedActions": [], "banned": false, "launcherInfoDTO": { "appName": "Fortnite", "catalogItemId": "4fe75bbc5a674f4f9b356b5c90567da5", "namespace": "fn" } }); }) express.get("/fortnite/api/version", async (req, res) => { res.json({ "app": "fortnite", "serverDate": new Date().toISOString(), "overridePropertiesVersion": "unknown", "cln": "17951730", "build": "444", "moduleName": "Fortnite-Core", "buildDate": "2021-10-27T21:00:51.697Z", "version": "18.30", "branch": "Release-18.30", "modules": { "Epic-LightSwitch-AccessControlCore": { "cln": "17237679", "build": "b2130", "buildDate": "2021-08-19T18:56:08.144Z", "version": "1.0.0", "branch": "trunk" }, "epic-xmpp-api-v1-base": { "cln": "5131a23c1470acbd9c94fae695ef7d899c1a41d6", "build": "b3595", "buildDate": "2019-07-30T09:11:06.587Z", "version": "0.0.1", "branch": "master" }, "epic-common-core": { "cln": "17909521", "build": "3217", "buildDate": "2021-10-25T18:41:12.486Z", "version": "3.0", "branch": "TRUNK" } } }); }) express.get("/launcher/api/public/distributionpoints/", async (req, res) => { res.json({ "distributions": [ "https://download.epicgames.com/", "https://download2.epicgames.com/", "https://download3.epicgames.com/", "https://download4.epicgames.com/", "https://epicgames-download1.akamaized.net/" ] }); }) express.post("/fortnite/api/game/v2/tryPlayOnPlatform/account/*", async (req, res) => { res.setHeader("Content-Type", "text/plain"); res.send(true); }) express.post("/fortnite/api/game/v2/grant_access/*", async (req, res) => { res.json({}); res.status(204); }) express.post("/api/v1/user/setting", async (req, res) => { res.json([]); }) express.get("/waitingroom/api/waitingroom", async (req, res) => { res.status(204); res.end(); }) express.get("/socialban/api/public/v1/*", async (req, res) => { res.json({ "bans": [], "warnings": [] }); }) express.get("/affiliate/api/public/affiliates/slug/:slug", async (req, res) => { const SupportedCodes = require("./responses/SAC.json"); SupportedCodes.forEach(code => { if (req.params.slug.toLowerCase() == code.toLowerCase()) { return res.json({ "id": code, "slug": code, "displayName": code, "status": "ACTIVE", "verified": false }); } }) res.status(404); res.json({}); }) express.get("/party/api/v1/Fortnite/user/*", async (req, res) => { res.json({ "current": [], "pending": [], "invites": [], "pings": [] }); }) express.post("/party/api/v1/Fortnite/user/*/current/*", async (req, res) => { res.json({}); }) express.post("/party/api/v1/Fortnite/user/*/pending/*", async (req, res) => { res.json({}); }) express.post("/party/api/v1/Fortnite/user/*/invites/*", async (req, res) => { res.json({}); }) express.post("/party/api/v1/Fortnite/user/*/pings/*", async (req, res) => { res.json({}); }) express.get("/fortnite/api/game/v2/events/tournamentandhistory/*/EU/WindowsClient", async (req, res) => { res.json({}); }) express.get("/catalog/api/shared/bulk/offers", async (req, res) => { res.json({}); }) express.get("/fortnite/api/game/v2/events/tournamentandhistory/*/EU/WindowsClient", async (req, res) => { res.json({}); }) express.get("/fortnite/api/matchmaking/session/findPlayer/*", async (req, res) => { res.status(200); res.end(); }) express.get("/fortnite/api/game/v2/privacy/account/:accountId", async (req, res) => { privacy.accountId = req.params.accountId; res.json(privacy); }); express.post("/fortnite/api/game/v2/privacy/account/:accountId", async (req, res) => { privacy.accountId = req.params.accountId; privacy.optOutOfPublicLeaderboards = req.body.optOutOfPublicLeaderboards; fs.writeFileSync("./responses/privacy.json", JSON.stringify(privacy, null, 2)); res.json(privacy); res.end(); }); express.get("/fortnite/api/statsv2/account/:accountId", async (req, res) => { res.json({ "startTime": 0, "endTime": 0, "stats": {}, "accountId": req.params.accountId }); }); express.get("/statsproxy/api/statsv2/account/:accountId", async (req, res) => { res.json({ "startTime": 0, "endTime": 0, "stats": {}, "accountId": req.params.accountId }); }); express.post("/fortnite/api/feedback/*", async (req, res) => { res.status(200); res.end(); }); express.post("/fortnite/api/statsv2/query", async (req, res) => { res.json([]); }); express.post("/statsproxy/api/statsv2/query", async (req, res) => { res.json([]); }); express.post("/fortnite/api/game/v2/events/v2/setSubgroup/*", async (req, res) => { res.status(204); res.end(); }); express.get("/fortnite/api/game/v2/enabled_features", async (req, res) => { res.json([]) }) express.get("/api/v1/events/Fortnite/download/*", async (req, res) => { res.json({}) }) express.get("/lightswitch/api/service/bulk/status", async (req, res) => { res.json( [{ "serviceInstanceId": "fortnite", "status": "UP", "message": "fortnite is up.", "maintenanceUri": null, "overrideCatalogIds": [ "a7f138b2e51945ffbfdacc1af0541053" ], "allowedActions": [ "PLAY", "DOWNLOAD" ], "banned": false, "launcherInfoDTO": { "appName": "Fortnite", "catalogItemId": "4fe75bbc5a674f4f9b356b5c90567da5", "namespace": "fn" } }] ) }) express.get("/account/api/public/account", async (req, res) => { var displayName = config.Config.displayName; if (config.Config.bUseConfigDisplayName == false) { displayName = req.query.accountId; } res.json( [ { "id": req.query.accountId, "displayName": displayName, "externalAuths": {} }, { "id": "SubtoLawin_LOL123", "displayName": "Subscribe to Lawin on YouTube!", "externalAuths": { "xbl": { "type": "xbl", "externalAuthIdType": "xuid", "accountId": "SubtoLawin_LOL123", "externalDisplayName": "YouTube-Lawin", "authIds": [{ "id": "0", "type": "xuid" }] }, "psn": { "type": "psn", "externalAuthId": "0", "externalAuthIdType": "psn_user_id", "accountId": "SubtoLawin_LOL123", "externalDisplayName": "YouTube-Lawin", "authIds": [{ "id": "0", "type": "psn_user_id" }] } } }, { "id": "Followlawin_LOL123", "displayName": "Follow @lawin_010 on twitter!", "externalAuths": { "xbl": { "type": "xbl", "externalAuthIdType": "xuid", "accountId": "Followlawin_LOL123", "externalDisplayName": "Twitter-lawin_010", "authIds": [{ "id": "0", "type": "xuid" }] }, "psn": { "type": "psn", "externalAuthId": "0", "externalAuthIdType": "psn_user_id", "accountId": "Followlawin_LOL123", "externalDisplayName": "Twitter-lawin_010", "authIds": [{ "id": "0", "type": "psn_user_id" }] } } }, { "id": "NINJALOL_1238", "displayName": "Ninja", "externalAuths": { "xbl": { "type": "xbl", "externalAuthIdType": "xuid", "accountId": "NINJALOL_1238", "externalDisplayName": "Ninja", "authIds": [{ "id": "0", "type": "xuid" }] }, "psn": { "type": "psn", "externalAuthId": "0", "externalAuthIdType": "psn_user_id", "accountId": "NINJALOL_1238", "externalDisplayName": "Ninja", "authIds": [{ "id": "0", "type": "psn_user_id" }] } } }, { "id": "TFUELOL_1238", "displayName": "Tfue", "externalAuths": { "xbl": { "type": "xbl", "externalAuthIdType": "xuid", "accountId": "TFUELOL_1238", "externalDisplayName": "Tfue", "authIds": [{ "id": "0", "type": "xuid" }] }, "psn": { "type": "psn", "externalAuthId": "0", "externalAuthIdType": "psn_user_id", "accountId": "TFUELOL_1238", "externalDisplayName": "Tfue", "authIds": [{ "id": "0", "type": "psn_user_id" }] } } }, { "id": "ALIALOL_1238", "displayName": "Ali-A", "externalAuths": { "xbl": { "type": "xbl", "externalAuthIdType": "xuid", "accountId": "ALIALOL_1238", "externalDisplayName": "Ali-A", "authIds": [{ "id": "0", "type": "xuid" }] }, "psn": { "type": "psn", "externalAuthId": "0", "externalAuthIdType": "psn_user_id", "accountId": "ALIALOL_1238", "externalDisplayName": "Ali-A", "authIds": [{ "id": "0", "type": "psn_user_id" }] } } }, { "id": "DAKOTAZLOL_1238", "displayName": "Dark", "externalAuths": { "xbl": { "type": "xbl", "externalAuthIdType": "xuid", "accountId": "DAKOTAZLOL_1238", "externalDisplayName": "Dark", "authIds": [{ "id": "0", "type": "xuid" }] }, "psn": { "type": "psn", "externalAuthId": "0", "externalAuthIdType": "psn_user_id", "accountId": "DAKOTAZLOL_1238", "externalDisplayName": "Dark", "authIds": [{ "id": "0", "type": "psn_user_id" }] } } }, { "id": "SYPHERPKLOL_1238", "displayName": "SypherPK", "externalAuths": { "xbl": { "type": "xbl", "externalAuthIdType": "xuid", "accountId": "SYPHERPKLOL_1238", "externalDisplayName": "SypherPK", "authIds": [{ "id": "0", "type": "xuid" }] }, "psn": { "type": "psn", "externalAuthId": "0", "externalAuthIdType": "psn_user_id", "accountId": "SYPHERPKLOL_1238", "externalDisplayName": "SypherPK", "authIds": [{ "id": "0", "type": "psn_user_id" }] } } }, { "id": "NICKEH30LOLL_2897669", "displayName": "Nick Eh 30", "externalAuths": { "xbl": { "type": "xbl", "externalAuthIdType": "xuid", "accountId": "NICKEH30LOLL_2897669", "externalDisplayName": "Nick Eh 30", "authIds": [{ "id": "0", "type": "xuid" }] }, "psn": { "type": "psn", "externalAuthId": "0", "externalAuthIdType": "psn_user_id", "accountId": "NICKEH30LOLL_2897669", "externalDisplayName": "Nick Eh 30", "authIds": [{ "id": "0", "type": "psn_user_id" }] } } } ] ) }) express.get("/account/api/public/account/:accountId", async (req, res) => { var displayName = config.Config.displayName; if (config.Config.bUseConfigDisplayName == false) { displayName = req.params.accountId; } res.json({ "id": req.params.accountId, "displayName": displayName, "name": "Lawin", "email": displayName + "@lawin.com", "failedLoginAttempts": 0, "lastLogin": new Date().toISOString(), "numberOfDisplayNameChanges": 0, "ageGroup": "UNKNOWN", "headless": false, "country": "US", "lastName": "Server", "preferredLanguage": "en", "canUpdateDisplayName": false, "tfaEnabled": false, "emailVerified": true, "minorVerified": false, "minorExpected": false, "minorStatus": "UNKNOWN" }) }) express.get("/fortnite/api/v2/versioncheck/*", async (req, res) => { res.json({ "type": "NO_UPDATE" }) }) express.get("/fortnite/api/v2/versioncheck*", async (req, res) => { res.json({ "type": "NO_UPDATE" }) }) express.get("/fortnite/api/versioncheck*", async (req, res) => { res.json({ "type": "NO_UPDATE" }) }) express.get("/eulatracking/api/shared/agreements/fn*", async (req, res) => { res.json({}) }) express.get("/fortnite/api/game/v2/friendcodes/*/epic", async (req, res) => { res.json([]) }) express.get("/account/api/epicdomains/ssodomains", async (req, res) => { res.json([ "unrealengine.com", "unrealtournament.com", "fortnite.com", "epicgames.com" ]) }) express.get("/fortnite/api/game/v2/matchmakingservice/ticket/player/*", async (req, res) => { memory.currentbuildUniqueId = req.query.bucketId.split(":")[0]; fs.writeFileSync("./memory.json", JSON.stringify(memory, null, 2)); res.json({ "serviceUrl": "ws://lawinservermatchmaker.herokuapp.com", "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) => { res.json({ "id": req.params.session_id, "ownerId": crypto.createHash('md5').update(`1${Math.random().toString()}`).digest('hex').toUpperCase(), "ownerName": "[DS]fortnite-liveeugcec1c2e30ubrcore0a-z8hj-1968", "serverName": "[DS]fortnite-liveeugcec1c2e30ubrcore0a-z8hj-1968", "serverAddress": config.GameServer.ip, "serverPort": Number(config.GameServer.port), "maxPublicPlayers": 220, "openPublicPlayers": 175, "maxPrivatePlayers": 0, "openPrivatePlayers": 0, "attributes": { "REGION_s": "EU", "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": "Playlist_DefaultSolo", "SESSIONKEY_s": crypto.createHash('md5').update(`2${Math.random().toString()}`).digest('hex').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": memory.currentbuildUniqueId, // buildUniqueId is different for every build, this uses the netver of the version you're currently using "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([]) }) express.get("/account/api/public/account/*/externalAuths", async (req, res) => { res.json([]) }) express.get("/fortnite/api/game/v2/twitch/*", async (req, res) => { res.status(200); res.end(); }) express.get("/fortnite/api/stats/accountId/:accountId/bulk/window/alltime", async (req, res) => { res.json({ "startTime": 0, "endTime": 0, "stats": {}, "accountId": req.params.accountId }) }) express.delete("/account/api/oauth/sessions/kill", async (req, res) => { res.status(204); res.end(); }) express.delete("/account/api/oauth/sessions/kill/*", async (req, res) => { res.status(204); res.end(); }) express.post("/fortnite/api/game/v2/chat/*/recommendGeneralChatRooms/pc", async (req, res) => { res.json({}) }) express.get("/friends/api/v1/*/settings", async (req, res) => { res.json({}) }) express.get("/friends/api/v1/*/blocklist", async (req, res) => { res.json([]) }) express.get("/presence/api/v1/_/*/last-online", async (req, res) => { res.json({}) }) express.get("/fortnite/api/receipts/v1/account/*/receipts", async (req, res) => { res.json([]) }) express.get("/fortnite/api/cloudstorage/system", async (req, res) => { // patch 9.40 if (req.headers["user-agent"].includes("7315705")) { return res .status(404) .json() } // patch 9.41 if (req.headers["user-agent"].includes("7463579")) { return res .status(404) .json() } // patch 9.41 (2) if (req.headers["user-agent"].includes("7609292")) { return res .status(404) .json() } const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); if (seasondata.season == 10) { return res.status(404).json(); } const dir = path.join(__dirname, 'CloudStorage') var CloudFiles = []; fs.readdirSync(dir).forEach(name => { if (name.toLowerCase().endsWith(".ini")) { const ParsedFile = fs.readFileSync(path.join(__dirname, 'CloudStorage', name), 'utf-8'); const ParsedStats = fs.statSync(path.join(__dirname, 'CloudStorage', name)); CloudFiles.push({ "uniqueFilename": name, "filename": name, "hash": crypto.createHash('sha1').update(ParsedFile).digest('hex'), "hash256": crypto.createHash('sha256').update(ParsedFile).digest('hex'), "length": ParsedFile.length, "contentType": "application/octet-stream", "uploaded": ParsedStats.mtime, "storageType": "S3", "storageIds": {}, "doNotCache": true }) } }); res.json(CloudFiles) }) express.get("/fortnite/api/cloudstorage/system/:file", async (req, res) => { const file = path.join(__dirname, 'CloudStorage', req.params.file); if (fs.existsSync(file)) { const ParsedFile = fs.readFileSync(file); return res.status(200).send(ParsedFile).end(); } res.status(200); res.end(); }) express.get("/fortnite/api/cloudstorage/user/*/:file", async (req, res) => { if (!fs.existsSync(path.join(process.env.LOCALAPPDATA, "LawinServer", "ClientSettings"))) { fs.mkdirSync(path.join(process.env.LOCALAPPDATA, "LawinServer", "ClientSettings")); } res.set("Content-Type", "application/octet-stream") if (req.params.file.toLowerCase() != "clientsettings.sav") { return res.status(404).json({ "error": "file not found" }); } const seasonchecker = require("./seasonchecker.js") const seasondata = require("./memory.json"); seasonchecker(req, seasondata); var currentBuildID = seasondata.CL; const file = path.join(process.env.LOCALAPPDATA, "LawinServer", "ClientSettings", `ClientSettings-${currentBuildID}.Sav`); if (fs.existsSync(file)) { const ParsedFile = fs.readFileSync(file); return res.status(200).send(ParsedFile).end(); } res.status(200); res.end(); }) express.get("/fortnite/api/cloudstorage/user/:accountId", async (req, res) => { if (!fs.existsSync(path.join(process.env.LOCALAPPDATA, "LawinServer", "ClientSettings"))) { fs.mkdirSync(path.join(process.env.LOCALAPPDATA, "LawinServer", "ClientSettings")); } res.set("Content-Type", "application/json") const seasonchecker = require("./seasonchecker.js") const seasondata = require("./memory.json"); seasonchecker(req, seasondata); var currentBuildID = seasondata.CL; const file = path.join(process.env.LOCALAPPDATA, "LawinServer", "ClientSettings", `ClientSettings-${currentBuildID}.Sav`); if (fs.existsSync(file)) { const ParsedFile = fs.readFileSync(file, 'utf-8'); const ParsedStats = fs.statSync(file); return res.json([{ "uniqueFilename": "ClientSettings.Sav", "filename": "ClientSettings.Sav", "hash": crypto.createHash('sha1').update(ParsedFile).digest('hex'), "hash256": crypto.createHash('sha256').update(ParsedFile).digest('hex'), "length": Buffer.byteLength(ParsedFile), "contentType": "application/octet-stream", "uploaded": ParsedStats.mtime, "storageType": "S3", "storageIds": {}, "accountId": req.params.accountId, "doNotCache": true }]); } else { return res.json([]); } }) express.put("/fortnite/api/cloudstorage/user/*/*", async (req, res) => { if (!fs.existsSync(path.join(process.env.LOCALAPPDATA, "LawinServer", "ClientSettings"))) { fs.mkdirSync(path.join(process.env.LOCALAPPDATA, "LawinServer", "ClientSettings")); } const seasonchecker = require("./seasonchecker.js") const seasondata = require("./memory.json"); seasonchecker(req, seasondata); var currentBuildID = seasondata.CL; const file = path.join(process.env.LOCALAPPDATA, "LawinServer", "ClientSettings", `ClientSettings-${currentBuildID}.Sav`); fs.writeFileSync(file, req.rawBody, 'latin1'); res.status(204).end(); }) express.get("/fortnite/api/game/v2/leaderboards/cohort/*", async (req, res) => { res.json([]) }) express.get("/friends/api/public/list/fortnite/*/recentPlayers", async (req, res) => { res.json([]) }) express.get("/friends/api/public/friends/*", async (req, res) => { res.json(friendslist) }) express.get("/friends/api/v1/*/summary", async (req, res) => { res.json(friendslist2) }) express.get("/fortnite/api/calendar/v1/timeline", async (req, res) => { const seasonchecker = require("./seasonchecker.js") const seasondata = require("./memory.json"); seasonchecker(req, seasondata); var activeEvents = [ { "eventType": `EventFlag.Season${seasondata.season}`, "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": `EventFlag.${seasondata.lobby}`, "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }]; if (seasondata.season == 3) { activeEvents.push( { "eventType": "EventFlag.Spring2018Phase1", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Spring2018Phase2", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Spring2018Phase3", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Spring2018Phase4", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.season == 4) { activeEvents.push( { "eventType": "EventFlag.Blockbuster2018", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Blockbuster2018Phase1", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Blockbuster2018Phase2", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Blockbuster2018Phase3", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Blockbuster2018Phase4", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.season == 5) { activeEvents.push( { "eventType": "EventFlag.RoadTrip2018", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Horde", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTM_Heist", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.build == 5.10) { activeEvents.push( { "eventType": "EventFlag.BirthdayBattleBus", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.season == 6) { activeEvents.push( { "eventType": "EventFlag.Fortnitemares", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.FortnitemaresPhase1", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.FortnitemaresPhase2", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTM_Fortnitemares", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTM_LilKevin", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.build == 6.20 || seasondata.build == 6.21) { activeEvents.push( { "eventType": "EventFlag.LobbySeason6Halloween", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.HalloweenBattleBus", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.season == 7) { activeEvents.push( { "eventType": "EventFlag.Frostnite", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTM_14DaysOfFortnite", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_Festivus", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTM_WinterDeimos", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_S7_OverTime", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.season == 8) { activeEvents.push( { "eventType": "EventFlag.Spring2019", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Spring2019.Phase1", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Spring2019.Phase2", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTM_Ashton", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTM_Goose", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTM_HighStakes", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_BootyBay", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.season == 9) { activeEvents.push( { "eventType": "EventFlag.Season9.Phase1", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Season9.Phase2", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Anniversary2019_BR", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTM_14DaysOfSummer", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTM_Mash", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTM_Wax", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.season == 10) { activeEvents.push( { "eventType": "EventFlag.Season10.Phase2", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Season10.Phase3", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_BlackMonday", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.S10_Oak", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EEventFlag.S10_Mystery", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.season == 11) { activeEvents.push( { "eventType": "EventFlag.LTE_CoinCollectXP", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_Fortnitemares2019", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_Galileo_Feats", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_Galileo", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_WinterFest2019", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) if (Number(seasondata.build.toString().split(".")[1].split("")[0]) >= 2) { activeEvents.push( { "eventType": "EventFlag.Starlight", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (Number(seasondata.build.toString().split(".")[1].split("")[0]) < 3) { activeEvents.push( { "eventType": "EventFlag.Season11.Fortnitemares.Quests.Phase1", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Season11.Fortnitemares.Quests.Phase2", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Season11.Fortnitemares.Quests.Phase3", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Season11.Fortnitemares.Quests.Phase4", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.StormKing.Landmark", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } else { activeEvents.push( { "eventType": "EventFlag.HolidayDeco", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Season11.WinterFest.Quests.Phase1", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Season11.WinterFest.Quests.Phase2", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Season11.WinterFest.Quests.Phase3", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Season11.Frostnite", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } // Credits to Silas for these BR Winterfest event flags if (seasondata.build == 11.31 || seasondata.build == 11.40) { activeEvents.push( { "eventType": "EventFlag.Winterfest.Tree", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_WinterFest", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_WinterFest2019", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } } if (seasondata.season == 12) { activeEvents.push( { "eventType": "EventFlag.LTE_SpyGames", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_JerkyChallenges", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_Oro", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTE_StormTheAgency", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.season == 14) { activeEvents.push( { "eventType": "EventFlag.LTE_Fortnitemares_2020", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.season == 15) { activeEvents.push( { "eventType": "EventFlag.LTQ_S15_Legendary_Week_01", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_02", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_03", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_04", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_05", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_06", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_07", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_08", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_09", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_10", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_11", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_12", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_13", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_14", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.LTQ_S15_Legendary_Week_15", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Event_HiddenRole", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Event_OperationSnowdown", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "EventFlag.Event_PlumRetro", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } if (seasondata.build == 19.01) { activeEvents.push( { "eventType": "EventFlag.LTE_WinterFest", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }, { "eventType": "WF_IG_AVAIL", "activeUntil": "9999-01-01T00:00:00.000Z", "activeSince": "2020-01-01T00:00:00.000Z" }) } res.json({ "channels": { "client-matchmaking": { "states": [], "cacheExpire": "9999-01-01T22:28:47.830Z" }, "client-events": { "states": [{ "validFrom": "2020-01-01T20:28:47.830Z", "activeEvents": activeEvents, "state": { "activeStorefronts": [], "eventNamedWeights": {}, "seasonNumber": seasondata.season, "seasonTemplateId": `AthenaSeason:athenaseason${seasondata.season}`, "matchXpBonusPoints": 0, "seasonBegin": "2020-01-01T13:00:00Z", "seasonEnd": "9999-01-01T14:00:00Z", "seasonDisplayedEnd": "9999-01-01T07:30:00Z", "weeklyStoreEnd": "9999-01-01T00:00:00Z", "stwEventStoreEnd": "9999-01-01T00:00:00.000Z", "stwWeeklyStoreEnd": "9999-01-01T00:00:00.000Z", "dailyStoreEnd": "9999-01-01T00:00:00Z" } }], "cacheExpire": "9999-01-01T22:28:47.830Z" } }, "eventsTimeOffsetHrs": 0, "cacheIntervalMins": 10, "currentTime": new Date().toISOString() }); res.status(200); res.end(); }) express.get("/friends/api/public/blocklist/*", async (req, res) => { res.json({ "blockedUsers": [] }) }) express.get("/content/api/pages/*", async (req, res) => { const contentpages = getContentPages(req); res.json(contentpages) }) express.get("/fortnite/api/game/v2/world/info", async (req, res) => { const worldstw = getTheater(req); res.json(worldstw) }) express.get("/fortnite/api/storefront/v2/keychain", async (req, res) => { res.json(keychain) }) express.get("/account/api/oauth/verify", async (req, res) => { var displayName = config.Config.displayName; if (config.Config.bUseConfigDisplayName == false) { displayName = Memory_CurrentAccountID } res.json({ "token": "lawinstokenlol", "session_id": "3c3662bcb661d6de679c636744c66b62", "token_type": "bearer", "client_id": "lawinsclientidlol", "internal_client": true, "client_service": "fortnite", "account_id": Memory_CurrentAccountID, "expires_in": 28800, "expires_at": "9999-12-02T01:12:01.100Z", "auth_method": "exchange_code", "display_name": displayName, "app": "fortnite", "in_app_id": Memory_CurrentAccountID, "device_id": "lawinsdeviceidlol" }) }) express.post("/datarouter/api/v1/public/data", async (req, res) => { res.status(204); res.end(); }) express.post("/account/api/oauth/token", async (req, res) => { var displayName = config.Config.displayName; if (config.Config.bUseConfigDisplayName == false) { Memory_CurrentAccountID = req.body.username || "LawinServer" displayName = req.body.username || "LawinServer" } res.json({ "access_token": "lawinstokenlol", "expires_in": 28800, "expires_at": "9999-12-02T01:12:01.100Z", "token_type": "bearer", "refresh_token": "lawinstokenlol", "refresh_expires": 86400, "refresh_expires_at": "9999-12-02T01:12:01.100Z", "account_id": Memory_CurrentAccountID, "client_id": "lawinsclientidlol", "internal_client": true, "client_service": "fortnite", "displayName": displayName, "app": "fortnite", "in_app_id": Memory_CurrentAccountID, "device_id": "lawinsdeviceidlol" }) }) // MCP BELOW // Set support a creator code express.post("/fortnite/api/game/v2/profile/*/client/SetAffiliateName", async (req, res) => { const profile = require("./profiles/common_core.json"); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; const SupportedCodes = require("./responses/SAC.json"); SupportedCodes.forEach(code => { if (req.body.affiliateName.toLowerCase() == code.toLowerCase() || req.body.affiliateName == "") { profile.stats.attributes.mtx_affiliate_set_time = new Date().toISOString(); profile.stats.attributes.mtx_affiliate = req.body.affiliateName; StatChanged = true; } }) if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "statModified", "name": "mtx_affiliate_set_time", "value": profile.stats.attributes.mtx_affiliate_set_time }) ApplyProfileChanges.push({ "changeType": "statModified", "name": "mtx_affiliate", "value": profile.stats.attributes.mtx_affiliate }) fs.writeFileSync("./profiles/common_core.json", JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": "common_core", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Set STW banner express.post("/fortnite/api/game/v2/profile/*/client/SetHomebaseBanner", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "profile0"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.homebaseBannerIconId && req.body.homebaseBannerColorId) { switch (req.query.profileId) { case "profile0": profile.stats.attributes.homebase.bannerIconId = req.body.homebaseBannerIconId; profile.stats.attributes.homebase.bannerColorId = req.body.homebaseBannerColorId; StatChanged = true; break; case "common_public": profile.stats.attributes.banner_icon = req.body.homebaseBannerIconId; profile.stats.attributes.banner_color = req.body.homebaseBannerColorId; StatChanged = true; break; } } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; if (req.query.profileId == "profile0") { ApplyProfileChanges.push({ "changeType": "statModified", "name": "homebase", "value": profile.stats.attributes.homebase }) } if (req.query.profileId == "common_public") { ApplyProfileChanges.push({ "changeType": "statModified", "name": "banner_icon", "value": profile.stats.attributes.banner_icon }) ApplyProfileChanges.push({ "changeType": "statModified", "name": "banner_color", "value": profile.stats.attributes.banner_color }) } fs.writeFileSync(`./profiles/${req.query.profileId || "profile0"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "profile0", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Buy skill tree perk STW express.post("/fortnite/api/game/v2/profile/*/client/PurchaseHomebaseNode", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "profile0"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; const ID = makeid(); if (req.body.nodeId) { profile.items[ID] = { "templateId": `HomebaseNode:${req.body.nodeId}`, "attributes": { "item_seen": true }, "quantity": 1 } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": profile.items[ID] }) fs.writeFileSync(`./profiles/${req.query.profileId || "profile0"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "profile0", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Open Winterfest presents (11.31 & 19.01) express.post("/fortnite/api/game/v2/profile/*/client/UnlockRewardNode", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "athena"}.json`); const common_core = require("./profiles/common_core.json"); const WinterFestIDS = require("./responses/winterfestrewards.json"); const seasondata = require("./memory.json"); const seasonchecker = require("./seasonchecker.js"); seasonchecker(req, seasondata); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var MultiUpdate = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; var Season = "Season" + seasondata.season; const ID = makeid(); const GiftID = makeid(); if (req.body.nodeId && req.body.rewardGraphId) { if (WinterFestIDS[Season][req.body.nodeId].toLowerCase().startsWith("homebasebannericon:")) { MultiUpdate.push({ "profileRevision": common_core.rvn || 0, "profileId": "common_core", "profileChangesBaseRevision": common_core.rvn || 0, "profileChanges": [], "profileCommandRevision": common_core.commandRevision || 0, }) common_core.items[ID] = { "templateId": WinterFestIDS[Season][req.body.nodeId], "attributes": { "max_level_bonus": 0, "level": 1, "item_seen": false, "xp": 0, "variants": [], "favorite": false }, "quantity": 1 }; MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": common_core.items[ID] }) common_core.rvn += 1; common_core.commandRevision += 1; MultiUpdate[0].profileRevision = common_core.rvn || 0; MultiUpdate[0].profileCommandRevision = common_core.commandRevision || 0; } if (!WinterFestIDS[Season][req.body.nodeId].toLowerCase().startsWith("homebasebannericon:")) { profile.items[ID] = { "templateId": WinterFestIDS[Season][req.body.nodeId], "attributes": { "max_level_bonus": 0, "level": 1, "item_seen": false, "xp": 0, "variants": [], "favorite": false }, "quantity": 1 }; ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": profile.items[ID] }) } profile.items[GiftID] = {"templateId":"GiftBox:gb_winterfestreward","attributes":{"max_level_bonus":0,"fromAccountId":"","lootList":[{"itemType":WinterFestIDS[Season][req.body.nodeId],"itemGuid":ID,"itemProfile":"athena","attributes":{"creation_time":new Date().toISOString()},"quantity":1}],"level":1,"item_seen":false,"xp":0,"giftedOn":new Date().toISOString(),"params":{"SubGame":"Athena","winterfestGift":"true"},"favorite":false},"quantity":1}; profile.items[req.body.rewardGraphId].attributes.reward_keys[0].unlock_keys_used += 1; profile.items[req.body.rewardGraphId].attributes.reward_nodes_claimed.push(req.body.nodeId); StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": GiftID, "item": profile.items[GiftID] }) ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.rewardGraphId, "attributeName": "reward_keys", "attributeValue": profile.items[req.body.rewardGraphId].attributes.reward_keys }) ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.rewardGraphId, "attributeName": "reward_nodes_claimed", "attributeValue": profile.items[req.body.rewardGraphId].attributes.reward_nodes_claimed }) fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2)); fs.writeFileSync("./profiles/common_core.json", JSON.stringify(common_core, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "multiUpdate": MultiUpdate, "responseVersion": 1 }) res.end(); }); // Remove gift box express.post("/fortnite/api/game/v2/profile/*/client/RemoveGiftBox", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "athena"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; // Gift box ID on 11.31 if (req.body.giftBoxItemId) { var id = req.body.giftBoxItemId; delete profile.items[id]; ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": id }) StatChanged = true; } // Gift box ID on 19.01 if (req.body.giftBoxItemIds) { for (var i in req.body.giftBoxItemIds) { var id = req.body.giftBoxItemIds[i]; delete profile.items[id]; ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": id }) } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Set pinned STW quests express.post("/fortnite/api/game/v2/profile/*/client/SetPinnedQuests", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.pinnedQuestIds) { profile.stats.attributes.client_settings.pinnedQuestInstances = req.body.pinnedQuestIds; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "statModified", "name": "client_settings", "value": profile.stats.attributes.client_settings }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Replace Daily Quests express.post("/fortnite/api/game/v2/profile/*/client/FortRerollDailyQuest", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "athena"}.json`); var DailyQuestIDS = JSON.parse(JSON.stringify(require("./responses/quests.json"))); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var Notifications = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.query.profileId == "profile0" || req.query.profileId == "campaign") { DailyQuestIDS = DailyQuestIDS.SaveTheWorld.Daily } if (req.query.profileId == "athena") { DailyQuestIDS = DailyQuestIDS.BattleRoyale.Daily } const NewQuestID = makeid(); var randomNumber = Math.floor(Math.random() * DailyQuestIDS.length); for (var key in profile.items) { while (DailyQuestIDS[randomNumber].templateId.toLowerCase() == profile.items[key].templateId.toLowerCase()) { randomNumber = Math.floor(Math.random() * DailyQuestIDS.length); } } if (req.body.questId && profile.stats.attributes.quest_manager.dailyQuestRerolls >= 1) { profile.stats.attributes.quest_manager.dailyQuestRerolls -= 1; delete profile.items[req.body.questId]; profile.items[NewQuestID] = { "templateId": DailyQuestIDS[randomNumber].templateId, "attributes": { "creation_time": new Date().toISOString(), "level": -1, "item_seen": false, "playlists": [], "sent_new_notification": false, "challenge_bundle_id": "", "xp_reward_scalar": 1, "challenge_linked_quest_given": "", "quest_pool": "", "quest_state": "Active", "bucket": "", "last_state_change_time": new Date().toISOString(), "challenge_linked_quest_parent": "", "max_level_bonus": 0, "xp": 0, "quest_rarity": "uncommon", "favorite": false }, "quantity": 1 }; for (var i in DailyQuestIDS[randomNumber].objectives) { profile.items[NewQuestID].attributes[`completion_${DailyQuestIDS[randomNumber].objectives[i]}`] = 0 } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "statModified", "name": "quest_manager", "value": profile.stats.attributes.quest_manager }) ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": NewQuestID, "item": profile.items[NewQuestID] }) ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": req.body.questId }) Notifications.push({ "type": "dailyQuestReroll", "primary": true, "newQuestId": DailyQuestIDS[randomNumber].templateId }) fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "notifications": Notifications, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Mark New Quest Notification Sent express.post("/fortnite/api/game/v2/profile/*/client/MarkNewQuestNotificationSent", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "athena"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.itemIds) { for (var i in req.body.itemIds) { var id = req.body.itemIds[i]; profile.items[id].attributes.sent_new_notification = true ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": id, "attributeName": "sent_new_notification", "attributeValue": true }) } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Check for new quests express.post("/fortnite/api/game/v2/profile/*/client/ClientQuestLogin", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "athena"}.json`); var QuestIDS = JSON.parse(JSON.stringify(require("./responses/quests.json"))); const seasondata = require("./memory.json"); const seasonchecker = require("./seasonchecker.js"); seasonchecker(req, seasondata); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; var QuestCount = 0; var ShouldGiveQuest = true; var DateFormat = (new Date().toISOString()).split("T")[0]; var DailyQuestIDS; var SeasonQuestIDS; try { if (req.query.profileId == "profile0" || req.query.profileId == "campaign") { DailyQuestIDS = QuestIDS.SaveTheWorld.Daily for (var key in profile.items) { if (profile.items[key].templateId.toLowerCase().startsWith("quest:daily")) { QuestCount += 1; } } } if (req.query.profileId == "athena") { DailyQuestIDS = QuestIDS.BattleRoyale.Daily if (QuestIDS.BattleRoyale.hasOwnProperty(`Season${seasondata.season}`)) { SeasonQuestIDS = QuestIDS.BattleRoyale[`Season${seasondata.season}`] } for (var key in profile.items) { if (profile.items[key].templateId.toLowerCase().startsWith("quest:athenadaily")) { QuestCount += 1; } if (key.split("")[0] == "S" && (Number.isInteger(Number(key.split("")[1]))) && (key.split("")[2] == "-" || (Number.isInteger(Number(key.split("")[2])) && key.split("")[3] == "-"))) { if (!key.startsWith(`S${seasondata.season}-`)) { delete profile.items[key]; ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": key }) StatChanged = true; } } } } if (profile.stats.attributes.hasOwnProperty("quest_manager")) { if (profile.stats.attributes.quest_manager.hasOwnProperty("dailyLoginInterval")) { if (profile.stats.attributes.quest_manager.dailyLoginInterval.includes("T")) { var DailyLoginDate = (profile.stats.attributes.quest_manager.dailyLoginInterval).split("T")[0]; if (DailyLoginDate == DateFormat) { ShouldGiveQuest = false; } else { ShouldGiveQuest = true; if (profile.stats.attributes.quest_manager.dailyQuestRerolls <= 0) { profile.stats.attributes.quest_manager.dailyQuestRerolls += 1; } } } } } if (QuestCount < 3 && ShouldGiveQuest == true) { const NewQuestID = makeid(); var randomNumber = Math.floor(Math.random() * DailyQuestIDS.length); for (var key in profile.items) { while (DailyQuestIDS[randomNumber].templateId.toLowerCase() == profile.items[key].templateId.toLowerCase()) { randomNumber = Math.floor(Math.random() * DailyQuestIDS.length); } } profile.items[NewQuestID] = { "templateId": DailyQuestIDS[randomNumber].templateId, "attributes": { "creation_time": new Date().toISOString(), "level": -1, "item_seen": false, "playlists": [], "sent_new_notification": false, "challenge_bundle_id": "", "xp_reward_scalar": 1, "challenge_linked_quest_given": "", "quest_pool": "", "quest_state": "Active", "bucket": "", "last_state_change_time": new Date().toISOString(), "challenge_linked_quest_parent": "", "max_level_bonus": 0, "xp": 0, "quest_rarity": "uncommon", "favorite": false }, "quantity": 1 }; for (var i in DailyQuestIDS[randomNumber].objectives) { profile.items[NewQuestID].attributes[`completion_${DailyQuestIDS[randomNumber].objectives[i]}`] = 0 } profile.stats.attributes.quest_manager.dailyLoginInterval = new Date().toISOString(); ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": NewQuestID, "item": profile.items[NewQuestID] }) ApplyProfileChanges.push({ "changeType": "statModified", "name": "quest_manager", "value": profile.stats.attributes.quest_manager }) StatChanged = true; } } catch (err) {} if (SeasonQuestIDS) { for (var ChallengeBundleSchedule in SeasonQuestIDS.ChallengeBundleSchedules) { if (profile.items.hasOwnProperty(ChallengeBundleSchedule.itemGuid)) { ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": ChallengeBundleSchedule.itemGuid }) } ChallengeBundleSchedule = SeasonQuestIDS.ChallengeBundleSchedules[ChallengeBundleSchedule]; profile.items[ChallengeBundleSchedule.itemGuid] = { "templateId": ChallengeBundleSchedule.templateId, "attributes": { "unlock_epoch": "2018-01-31T00:00:00.000Z", "max_level_bonus": 0, "level": 1, "item_seen": true, "xp": 0, "favorite": false, "granted_bundles": ChallengeBundleSchedule.granted_bundles }, "quantity": 1 } ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ChallengeBundleSchedule.itemGuid, "item": profile.items[ChallengeBundleSchedule.itemGuid] }) StatChanged = true; } for (var ChallengeBundle in SeasonQuestIDS.ChallengeBundles) { if (profile.items.hasOwnProperty(ChallengeBundle.itemGuid)) { ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": ChallengeBundle.itemGuid }) } ChallengeBundle = SeasonQuestIDS.ChallengeBundles[ChallengeBundle]; if (config.Profile.bCompletedSeasonalQuests == true && ChallengeBundle.hasOwnProperty("questStages")) { ChallengeBundle.grantedquestinstanceids = ChallengeBundle.grantedquestinstanceids.concat(ChallengeBundle.questStages); } profile.items[ChallengeBundle.itemGuid] = { "templateId": ChallengeBundle.templateId, "attributes": { "has_unlock_by_completion": false, "num_quests_completed": 0, "level": 0, "grantedquestinstanceids": ChallengeBundle.grantedquestinstanceids, "item_seen": true, "max_allowed_bundle_level": 0, "num_granted_bundle_quests": 0, "max_level_bonus": 0, "challenge_bundle_schedule_id": ChallengeBundle.challenge_bundle_schedule_id, "num_progress_quests_completed": 0, "xp": 0, "favorite": false }, "quantity": 1 } profile.items[ChallengeBundle.itemGuid].attributes.num_granted_bundle_quests = ChallengeBundle.grantedquestinstanceids.length; if (config.Profile.bCompletedSeasonalQuests == true) { profile.items[ChallengeBundle.itemGuid].attributes.num_quests_completed = ChallengeBundle.grantedquestinstanceids.length; profile.items[ChallengeBundle.itemGuid].attributes.num_progress_quests_completed = ChallengeBundle.grantedquestinstanceids.length; } ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ChallengeBundle.itemGuid, "item": profile.items[ChallengeBundle.itemGuid] }) StatChanged = true; } for (var Quest in SeasonQuestIDS.Quests) { if (profile.items.hasOwnProperty(Quest.itemGuid)) { ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": Quest.itemGuid }) } Quest = SeasonQuestIDS.Quests[Quest]; profile.items[Quest.itemGuid] = { "templateId": Quest.templateId, "attributes": { "creation_time": "2018-01-31T00:00:00.000Z", "level": -1, "item_seen": true, "playlists": [], "sent_new_notification": true, "challenge_bundle_id": Quest.challenge_bundle_id, "xp_reward_scalar": 1, "challenge_linked_quest_given": "", "quest_pool": "", "quest_state": "Active", "bucket": "", "last_state_change_time": "2018-01-31T00:00:00.000Z", "challenge_linked_quest_parent": "", "max_level_bonus": 0, "xp": 0, "quest_rarity": "uncommon", "favorite": false }, "quantity": 1 } if (config.Profile.bCompletedSeasonalQuests == true) { profile.items[Quest.itemGuid].attributes.quest_state = "Claimed"; } for (var i in Quest.objectives) { if (config.Profile.bCompletedSeasonalQuests == true) { profile.items[Quest.itemGuid].attributes[`completion_${Quest.objectives[i].name}`] = Quest.objectives[i].count; } else { profile.items[Quest.itemGuid].attributes[`completion_${Quest.objectives[i].name}`] = 0; } } ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": Quest.itemGuid, "item": profile.items[Quest.itemGuid] }) StatChanged = true; } } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Refund V-Bucks purchase express.post("/fortnite/api/game/v2/profile/*/client/RefundMtxPurchase", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "common_core"}.json`); const ItemProfile = require("./profiles/athena.json"); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var MultiUpdate = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; var ItemGuids = []; if (req.body.purchaseId) { MultiUpdate.push({ "profileRevision": ItemProfile.rvn || 0, "profileId": "athena", "profileChangesBaseRevision": ItemProfile.rvn || 0, "profileChanges": [], "profileCommandRevision": ItemProfile.commandRevision || 0, }) profile.stats.attributes.mtx_purchase_history.refundsUsed += 1; profile.stats.attributes.mtx_purchase_history.refundCredits -= 1; for (var i in profile.stats.attributes.mtx_purchase_history.purchases) { if (profile.stats.attributes.mtx_purchase_history.purchases[i].purchaseId == req.body.purchaseId) { for (var x in profile.stats.attributes.mtx_purchase_history.purchases[i].lootResult) { ItemGuids.push(profile.stats.attributes.mtx_purchase_history.purchases[i].lootResult[x].itemGuid) } profile.stats.attributes.mtx_purchase_history.purchases[i].refundDate = new Date().toISOString(); } } for (var i in ItemGuids) { delete ItemProfile.items[ItemGuids[i]] MultiUpdate[0].profileChanges.push({ "changeType": "itemRemoved", "itemId": ItemGuids[i] }) } ItemProfile.rvn += 1; ItemProfile.commandRevision += 1; profile.rvn += 1; profile.commandRevision += 1; StatChanged = true; } if (StatChanged == true) { ApplyProfileChanges.push({ "changeType": "statModified", "name": "mtx_purchase_history", "value": profile.stats.attributes.mtx_purchase_history }) MultiUpdate[0].profileRevision = ItemProfile.rvn || 0; MultiUpdate[0].profileCommandRevision = ItemProfile.commandRevision || 0; fs.writeFileSync(`./profiles/${req.query.profileId || "common_core"}.json`, JSON.stringify(profile, null, 2)); fs.writeFileSync(`./profiles/athena.json`, JSON.stringify(ItemProfile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "common_core", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "multiUpdate": MultiUpdate, "responseVersion": 1 }) res.end(); }); // Claim STW daily reward express.post("/fortnite/api/game/v2/profile/*/client/ClaimLoginReward", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; var DateFormat = (new Date().toISOString()).split("T")[0] + "T00:00:00.000Z"; if (profile.stats.attributes.daily_rewards.lastClaimDate != DateFormat) { profile.stats.attributes.daily_rewards.nextDefaultReward += 1; profile.stats.attributes.daily_rewards.totalDaysLoggedIn += 1; profile.stats.attributes.daily_rewards.lastClaimDate = DateFormat; profile.stats.attributes.daily_rewards.additionalSchedules.founderspackdailyrewardtoken.rewardsClaimed += 1; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "statModified", "name": "daily_rewards", "value": profile.stats.attributes.daily_rewards }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Equip team perk STW express.post("/fortnite/api/game/v2/profile/*/client/AssignTeamPerkToLoadout", async (req, res) => { const profile = require("./profiles/campaign.json"); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.loadoutId) { profile.items[req.body.loadoutId].attributes.team_perk = req.body.teamPerkId || ""; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.loadoutId, "attributeName": "team_perk", "attributeValue": profile.items[req.body.loadoutId].attributes.team_perk }) fs.writeFileSync("./profiles/campaign.json", JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Equip gadget STW express.post("/fortnite/api/game/v2/profile/*/client/AssignGadgetToLoadout", async (req, res) => { const profile = require("./profiles/campaign.json"); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.loadoutId) { switch (req.body.slotIndex) { case 0: if (req.body.gadgetId.toLowerCase() == profile.items[req.body.loadoutId].attributes.gadgets[1].gadget.toLowerCase()) { profile.items[req.body.loadoutId].attributes.gadgets[1].gadget = ""; } profile.items[req.body.loadoutId].attributes.gadgets[req.body.slotIndex].gadget = req.body.gadgetId || ""; StatChanged = true; break; case 1: if (req.body.gadgetId.toLowerCase() == profile.items[req.body.loadoutId].attributes.gadgets[0].gadget.toLowerCase()) { profile.items[req.body.loadoutId].attributes.gadgets[0].gadget = ""; } profile.items[req.body.loadoutId].attributes.gadgets[req.body.slotIndex].gadget = req.body.gadgetId || ""; StatChanged = true; break; } } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.loadoutId, "attributeName": "gadgets", "attributeValue": profile.items[req.body.loadoutId].attributes.gadgets }) fs.writeFileSync("./profiles/campaign.json", JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Assign worker to squad STW express.post("/fortnite/api/game/v2/profile/*/client/AssignWorkerToSquad", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "profile0"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.characterId) { for (var key in profile.items) { if (profile.items[key].hasOwnProperty('attributes')) { if (profile.items[key].attributes.hasOwnProperty('squad_id') && profile.items[key].attributes.hasOwnProperty('squad_slot_idx')) { if (profile.items[key].attributes.squad_id != "" && profile.items[key].attributes.squad_slot_idx != -1) { if (profile.items[key].attributes.squad_id.toLowerCase() == req.body.squadId.toLowerCase() && profile.items[key].attributes.squad_slot_idx == req.body.slotIndex) { profile.items[key].attributes.squad_id = ""; profile.items[key].attributes.squad_slot_idx = 0; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": key, "attributeName": "squad_id", "attributeValue": profile.items[key].attributes.squad_id }) ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": key, "attributeName": "squad_slot_idx", "attributeValue": profile.items[key].attributes.squad_slot_idx }) } } } } } } if (req.body.characterId) { profile.items[req.body.characterId].attributes.squad_id = req.body.squadId || ""; profile.items[req.body.characterId].attributes.squad_slot_idx = req.body.slotIndex || 0; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.characterId, "attributeName": "squad_id", "attributeValue": profile.items[req.body.characterId].attributes.squad_id }) ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.characterId, "attributeName": "squad_slot_idx", "attributeValue": profile.items[req.body.characterId].attributes.squad_slot_idx }) fs.writeFileSync(`./profiles/${req.query.profileId || "profile0"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "profile0", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Assign multiple workers to squad STW express.post("/fortnite/api/game/v2/profile/*/client/AssignWorkerToSquadBatch", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "profile0"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.characterIds && req.body.squadIds && req.body.slotIndices) { for (var i in req.body.characterIds) { for (var key in profile.items) { if (profile.items[key].hasOwnProperty('attributes')) { if (profile.items[key].attributes.hasOwnProperty('squad_id') && profile.items[key].attributes.hasOwnProperty('squad_slot_idx')) { if (profile.items[key].attributes.squad_id != "" && profile.items[key].attributes.squad_slot_idx != -1) { if (profile.items[key].attributes.squad_id.toLowerCase() == req.body.squadIds[i].toLowerCase() && profile.items[key].attributes.squad_slot_idx == req.body.slotIndices[i]) { profile.items[key].attributes.squad_id = ""; profile.items[key].attributes.squad_slot_idx = 0; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": key, "attributeName": "squad_id", "attributeValue": profile.items[key].attributes.squad_id }) ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": key, "attributeName": "squad_slot_idx", "attributeValue": profile.items[key].attributes.squad_slot_idx }) } } } } } profile.items[req.body.characterIds[i]].attributes.squad_id = req.body.squadIds[i] || ""; profile.items[req.body.characterIds[i]].attributes.squad_slot_idx = req.body.slotIndices[i] || 0; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.characterIds[i], "attributeName": "squad_id", "attributeValue": profile.items[req.body.characterIds[i]].attributes.squad_id }) ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.characterIds[i], "attributeName": "squad_slot_idx", "attributeValue": profile.items[req.body.characterIds[i]].attributes.squad_slot_idx }) } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "profile0"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "profile0", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Claim STW quest reward express.post("/fortnite/api/game/v2/profile/*/client/ClaimQuestReward", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.questId) { profile.items[req.body.questId].attributes.quest_state = "Claimed"; profile.items[req.body.questId].attributes.last_state_change_time = new Date().toISOString(); StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.questId, "attributeName": "quest_state", "attributeValue": profile.items[req.body.questId].attributes.quest_state }) ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.questId, "attributeName": "last_state_change_time", "attributeValue": profile.items[req.body.questId].attributes.last_state_change_time }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Level item up STW 1 express.post("/fortnite/api/game/v2/profile/*/client/UpgradeItem", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.targetItemId) { profile.items[req.body.targetItemId].attributes.level += 1; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.targetItemId, "attributeName": "level", "attributeValue": profile.items[req.body.targetItemId].attributes.level }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Level slotted item up STW express.post("/fortnite/api/game/v2/profile/*/client/UpgradeSlottedItem", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "collection_book_people0"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.targetItemId) { if (req.body.desiredLevel) { var new_level = Number(req.body.desiredLevel); profile.items[req.body.targetItemId].attributes.level = new_level; } else { profile.items[req.body.targetItemId].attributes.level += 1; } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.targetItemId, "attributeName": "level", "attributeValue": profile.items[req.body.targetItemId].attributes.level }) fs.writeFileSync(`./profiles/${req.query.profileId || "collection_book_people0"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "collection_book_people0", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Level item up STW 2 express.post("/fortnite/api/game/v2/profile/*/client/UpgradeItemBulk", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.targetItemId) { var new_level = Number(req.body.desiredLevel); profile.items[req.body.targetItemId].attributes.level = new_level; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.targetItemId, "attributeName": "level", "attributeValue": profile.items[req.body.targetItemId].attributes.level }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Evolve item STW express.post("/fortnite/api/game/v2/profile/*/client/ConvertItem", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var Notifications = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.targetItemId) { if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t04")) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t04/ig, "T05"); } if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t03")) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t03/ig, "T04"); } if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t02")) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t02/ig, "T03"); } if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t01")) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t01/ig, "T02"); } // Conversion Index: 0 = Ore, 1 = Crystal if (req.body.conversionIndex == 1) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/ore/ig, "Crystal"); } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; const ID = makeid(); profile.items[ID] = profile.items[req.body.targetItemId]; ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": profile.items[ID] }) delete profile.items[req.body.targetItemId] ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": req.body.targetItemId }) Notifications.push({ "type": "conversionResult", "primary": true, "itemsGranted": [ { "itemType": profile.items[ID].templateId, "itemGuid": ID, "itemProfile": req.query.profileId || "campaign", "attributes": { "level": profile.items[ID].attributes.level, "alterations": profile.items[ID].attributes.alterations || [] }, "quantity": 1 } ] }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "notifications": Notifications, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Evolve slotted item STW express.post("/fortnite/api/game/v2/profile/*/client/ConvertSlottedItem", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "collection_book_people0"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var Notifications = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.targetItemId) { if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t04")) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t04/ig, "T05"); } if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t03")) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t03/ig, "T04"); } if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t02")) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t02/ig, "T03"); } if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("t01")) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/t01/ig, "T02"); } // Conversion Index: 0 = Ore, 1 = Crystal if (req.body.conversionIndex == 1) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/ore/ig, "Crystal"); } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; const ID = makeid(); profile.items[ID] = profile.items[req.body.targetItemId]; ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": profile.items[ID] }) delete profile.items[req.body.targetItemId] ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": req.body.targetItemId }) Notifications.push({ "type": "conversionResult", "primary": true, "itemsGranted": [ { "itemType": profile.items[ID].templateId, "itemGuid": ID, "itemProfile": req.query.profileId || "collection_book_people0", "attributes": { "level": profile.items[ID].attributes.level, "alterations": profile.items[ID].attributes.alterations || [] }, "quantity": 1 } ] }) fs.writeFileSync(`./profiles/${req.query.profileId || "collection_book_people0"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "collection_book_people0", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "notifications": Notifications, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Upgrade item rarity STW express.post("/fortnite/api/game/v2/profile/*/client/UpgradeItemRarity", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var Notifications = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.targetItemId) { if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("_vr_")) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/_vr_/ig, "_SR_"); } if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("_r_")) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/_r_/ig, "_VR_"); } if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("_uc_")) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/_uc_/ig, "_R_"); } if (profile.items[req.body.targetItemId].templateId.toLowerCase().includes("_c_")) { profile.items[req.body.targetItemId].templateId = profile.items[req.body.targetItemId].templateId.replace(/_c_/ig, "_UC_"); } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; const ID = makeid(); profile.items[ID] = profile.items[req.body.targetItemId]; ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": profile.items[ID] }) delete profile.items[req.body.targetItemId] ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": req.body.targetItemId }) Notifications.push([{ "type": "upgradeItemRarityNotification", "primary": true, "itemsGranted": [ { "itemType": profile.items[ID].templateId, "itemGuid": ID, "itemProfile": req.query.profileId || "campaign", "attributes": { "level": profile.items[ID].attributes.level, "alterations": profile.items[ID].attributes.alterations || [] }, "quantity": 1 } ] }]) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "notifications": Notifications, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Super charge item STW express.post("/fortnite/api/game/v2/profile/*/client/PromoteItem", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.targetItemId) { profile.items[req.body.targetItemId].attributes.level += 2; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.targetItemId, "attributeName": "level", "attributeValue": profile.items[req.body.targetItemId].attributes.level }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Craft item STW (Guns, melees and traps only) express.post("/fortnite/api/game/v2/profile/*/client/CraftWorldItem", async (req, res) => { const seasondata = require("./memory.json"); const seasonchecker = require("./seasonchecker.js"); seasonchecker(req, seasondata); const profile = require(`./profiles/${req.query.profileId || "theater0"}.json`); var schematic_profile; // do not change this var chosen_profile = false; if (4 <= seasondata.season || seasondata.build == 3.5 || seasondata.build == 3.6 && chosen_profile == false) { schematic_profile = require("./profiles/campaign.json"); chosen_profile = true; } if (3 >= seasondata.season && chosen_profile == false) { schematic_profile = require("./profiles/profile0.json"); chosen_profile = true; } // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var Notifications = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; var Item; const ID = makeid(); if (req.body.targetSchematicItemId) { var Body = ''; Body += JSON.stringify(schematic_profile.items[req.body.targetSchematicItemId]); Item = JSON.parse(Body); var ItemType = 'Weapon:'; var ItemIDType = 'WID'; if (Item.templateId.split("_")[1].split("_")[0].toLowerCase() == "wall") { ItemType = "Trap:"; ItemIDType = "TID"; } if (Item.templateId.split("_")[1].split("_")[0].toLowerCase() == "floor") { ItemType = "Trap:"; ItemIDType = "TID"; } if (Item.templateId.split("_")[1].split("_")[0].toLowerCase() == "ceiling") { ItemType = "Trap:"; ItemIDType = "TID"; } Item.quantity = req.body.numTimesToCraft || 1; Item.templateId = Item.templateId.replace(/schematic:/ig, ItemType); Item.templateId = Item.templateId.replace(/sid/ig, ItemIDType); if (req.body.targetSchematicTier) { switch (req.body.targetSchematicTier.toLowerCase()) { case "i": if (!Item.templateId.toLowerCase().includes("t01")) { Item.attributes.level = 10; } Item.templateId = Item.templateId.substring(0, Item.templateId.length-3) + "T01" Item.templateId = Item.templateId.replace(/crystal/ig, "Ore") break; case "ii": if (!Item.templateId.toLowerCase().includes("t02")) { Item.attributes.level = 20; } Item.templateId = Item.templateId.substring(0, Item.templateId.length-3) + "T02" Item.templateId = Item.templateId.replace(/crystal/ig, "Ore") break; case "iii": if (!Item.templateId.toLowerCase().includes("t03")) { Item.attributes.level = 30; } Item.templateId = Item.templateId.substring(0, Item.templateId.length-3) + "T03" Item.templateId = Item.templateId.replace(/crystal/ig, "Ore") break; case "iv": if (!Item.templateId.toLowerCase().includes("t04")) { Item.attributes.level = 40; } Item.templateId = Item.templateId.substring(0, Item.templateId.length-3) + "T04" break; case "v": Item.templateId = Item.templateId.substring(0, Item.templateId.length-3) + "T05" break; } } Item.attributes = { "clipSizeScale": 0, "loadedAmmo": 999, "level": Item.attributes.level || 1, "alterationDefinitions": Item.attributes.alterations || [], "baseClipSize": 999, "durability": 375, "itemSource": "" }; profile.items[ID] = Item; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": profile.items[ID] }); Notifications.push({ "type": "craftingResult", "primary": true, "itemsCrafted": [ { "itemType": profile.items[ID].templateId, "itemGuid": ID, "itemProfile": req.query.profileId || "theater0", "attributes": { "loadedAmmo": profile.items[ID].attributes.loadedAmmo, "level": profile.items[ID].attributes.level, "alterationDefinitions": profile.items[ID].attributes.alterationDefinitions, "durability": profile.items[ID].attributes.durability }, "quantity": profile.items[ID].quantity } ] }) fs.writeFileSync(`./profiles/${req.query.profileId || "theater0"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "theater0", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "notifications": Notifications, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Destroy item STW express.post("/fortnite/api/game/v2/profile/*/client/DestroyWorldItems", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "theater0"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.itemIds) { for (var i in req.body.itemIds) { var id = req.body.itemIds[i]; delete profile.items[id] ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": id }) } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "theater0"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "theater0", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Disassemble items STW express.post("/fortnite/api/game/v2/profile/*/client/DisassembleWorldItems", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "theater0"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.targetItemIdAndQuantityPairs) { for (var i in req.body.targetItemIdAndQuantityPairs) { var id = req.body.targetItemIdAndQuantityPairs[i].itemId; var quantity = Number(req.body.targetItemIdAndQuantityPairs[i].quantity); var orig_quantity = Number(profile.items[id].quantity); if (quantity >= orig_quantity) { delete profile.items[id] ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": id }) } if (quantity < orig_quantity) { profile.items[id].quantity -= quantity; ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": profile.items[id].quantity }) } } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "theater0"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "theater0", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Storage transfer STW express.post("/fortnite/api/game/v2/profile/*/client/StorageTransfer", async (req, res) => { const theater0 = require("./profiles/theater0.json"); const outpost0 = require("./profiles/outpost0.json"); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var MultiUpdate = []; var BaseRevision = theater0.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.transferOperations) { MultiUpdate.push({ "profileRevision": outpost0.rvn || 0, "profileId": "outpost0", "profileChangesBaseRevision": outpost0.rvn || 0, "profileChanges": [], "profileCommandRevision": outpost0.commandRevision || 0, }) for (var i in req.body.transferOperations) { if (req.body.transferOperations[i].toStorage == false) { let id = req.body.transferOperations[i].itemId; let body_quantity = Number(req.body.transferOperations[i].quantity); if (outpost0.items[id]) { var outpost0_quantity = Number(outpost0.items[id].quantity); } else { var outpost0_quantity = "Unknown"; } if (theater0.items[id]) { var theater0_quantity = Number(theater0.items[id].quantity); } else { var theater0_quantity = "Unknown"; } if (theater0.items[id] && outpost0.items[id]) { if (outpost0_quantity > body_quantity) { theater0.items[id].quantity += body_quantity; outpost0.items[id].quantity -= body_quantity; ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": theater0.items[id].quantity }); MultiUpdate[0].profileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": outpost0.items[id].quantity }) } if (outpost0_quantity <= body_quantity) { theater0.items[id].quantity += body_quantity; delete outpost0.items[id] ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": theater0.items[id].quantity }); MultiUpdate[0].profileChanges.push({ "changeType": "itemRemoved", "itemId": id }); } } if (!theater0.items[id] && outpost0.items[id]) { const Item = JSON.parse(JSON.stringify(outpost0.items[id])); if (outpost0_quantity > body_quantity) { outpost0.items[id].quantity -= body_quantity; Item.quantity = body_quantity; theater0.items[id] = Item; ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": id, "item": Item }) MultiUpdate[0].profileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": outpost0.items[id].quantity }); } if (outpost0_quantity <= body_quantity) { theater0.items[id] = Item; delete outpost0.items[id] ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": id, "item": Item }) MultiUpdate[0].profileChanges.push({ "changeType": "itemRemoved", "itemId": id }) } } } if (req.body.transferOperations[i].toStorage == true) { let id = req.body.transferOperations[i].itemId; let body_quantity = Number(req.body.transferOperations[i].quantity); if (outpost0.items[id]) { var outpost0_quantity = Number(outpost0.items[id].quantity); } else { var outpost0_quantity = "Unknown"; } if (theater0.items[id]) { var theater0_quantity = Number(theater0.items[id].quantity); } else { var theater0_quantity = "Unknown"; } if (outpost0.items[id] && theater0.items[id]) { if (theater0_quantity > body_quantity) { outpost0.items[id].quantity += body_quantity; theater0.items[id].quantity -= body_quantity; ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": theater0.items[id].quantity }); MultiUpdate[0].profileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": outpost0.items[id].quantity }) } if (theater0_quantity <= body_quantity) { outpost0.items[id].quantity += body_quantity; delete theater0.items[id] MultiUpdate[0].profileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": outpost0.items[id].quantity }); ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": id }); } } if (!outpost0.items[id] && theater0.items[id]) { const Item = JSON.parse(JSON.stringify(theater0.items[id])); if (theater0_quantity > body_quantity) { theater0.items[id].quantity -= body_quantity; Item.quantity = body_quantity; outpost0.items[id] = Item; MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": id, "item": Item }) ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": theater0.items[id].quantity }); } if (theater0_quantity <= body_quantity) { outpost0.items[id] = Item; delete theater0.items[id] MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": id, "item": Item }) ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": id, }) } } } } StatChanged = true; } if (req.body.theaterToOutpostItems && req.body.outpostToTheaterItems) { MultiUpdate.push({ "profileRevision": outpost0.rvn || 0, "profileId": "outpost0", "profileChangesBaseRevision": outpost0.rvn || 0, "profileChanges": [], "profileCommandRevision": outpost0.commandRevision || 0, }) for (var i in req.body.theaterToOutpostItems) { let id = req.body.theaterToOutpostItems[i].itemId; let body_quantity = Number(req.body.theaterToOutpostItems[i].quantity); if (outpost0.items[id]) { var outpost0_quantity = Number(outpost0.items[id].quantity); } else { var outpost0_quantity = "Unknown"; } if (theater0.items[id]) { var theater0_quantity = Number(theater0.items[id].quantity); } else { var theater0_quantity = "Unknown"; } if (outpost0.items[id] && theater0.items[id]) { if (theater0_quantity > body_quantity) { outpost0.items[id].quantity += body_quantity; theater0.items[id].quantity -= body_quantity; ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": theater0.items[id].quantity }); MultiUpdate[0].profileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": outpost0.items[id].quantity }) } if (theater0_quantity <= body_quantity) { outpost0.items[id].quantity += body_quantity; delete theater0.items[id] MultiUpdate[0].profileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": outpost0.items[id].quantity }); ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": id }); } } if (!outpost0.items[id] && theater0.items[id]) { const Item = JSON.parse(JSON.stringify(theater0.items[id])); if (theater0_quantity > body_quantity) { theater0.items[id].quantity -= body_quantity; Item.quantity = body_quantity; outpost0.items[id] = Item; MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": id, "item": Item }) ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": theater0.items[id].quantity }); } if (theater0_quantity <= body_quantity) { outpost0.items[id] = Item; delete theater0.items[id] MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": id, "item": Item }) ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": id, }) } } } for (var i in req.body.outpostToTheaterItems) { let id = req.body.outpostToTheaterItems[i].itemId; let body_quantity = Number(req.body.outpostToTheaterItems[i].quantity); if (outpost0.items[id]) { var outpost0_quantity = Number(outpost0.items[id].quantity); } else { var outpost0_quantity = "Unknown"; } if (theater0.items[id]) { var theater0_quantity = Number(theater0.items[id].quantity); } else { var theater0_quantity = "Unknown"; } if (theater0.items[id] && outpost0.items[id]) { if (outpost0_quantity > body_quantity) { theater0.items[id].quantity += body_quantity; outpost0.items[id].quantity -= body_quantity; ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": theater0.items[id].quantity }); MultiUpdate[0].profileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": outpost0.items[id].quantity }) } if (outpost0_quantity <= body_quantity) { theater0.items[id].quantity += body_quantity; delete outpost0.items[id] ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": theater0.items[id].quantity }); MultiUpdate[0].profileChanges.push({ "changeType": "itemRemoved", "itemId": id }); } } if (!theater0.items[id] && outpost0.items[id]) { const Item = JSON.parse(JSON.stringify(outpost0.items[id])); if (outpost0_quantity > body_quantity) { outpost0.items[id].quantity -= body_quantity; Item.quantity = body_quantity; theater0.items[id] = Item; ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": id, "item": Item }) MultiUpdate[0].profileChanges.push({ "changeType": "itemQuantityChanged", "itemId": id, "quantity": outpost0.items[id].quantity }); } if (outpost0_quantity <= body_quantity) { theater0.items[id] = Item; delete outpost0.items[id] ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": id, "item": Item }) MultiUpdate[0].profileChanges.push({ "changeType": "itemRemoved", "itemId": id }) } } } StatChanged = true; } if (StatChanged == true) { theater0.rvn += 1; theater0.commandRevision += 1; outpost0.rvn += 1; outpost0.commandRevision += 1; MultiUpdate[0].profileRevision = outpost0.rvn || 0; MultiUpdate[0].profileCommandRevision = outpost0.commandRevision || 0; fs.writeFileSync("./profiles/theater0.json", JSON.stringify(theater0, null, 2)); fs.writeFileSync("./profiles/outpost0.json", JSON.stringify(outpost0, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": theater0 }]; } res.json({ "profileRevision": theater0.rvn || 0, "profileId": "theater0", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": theater0.commandRevision || 0, "serverTime": new Date().toISOString(), "multiUpdate": MultiUpdate, "responseVersion": 1 }) res.end(); }); // Modify quickbar STW express.post("/fortnite/api/game/v2/profile/*/client/ModifyQuickbar", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "theater0"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.primaryQuickbarChoices) { for (var i in req.body.primaryQuickbarChoices) { let a = Number(i) + 1; var value = [req.body.primaryQuickbarChoices[i].replace(/-/ig, "").toUpperCase()]; if (req.body.primaryQuickbarChoices[i] == "") { value = []; } profile.stats.attributes.player_loadout.primaryQuickBarRecord.slots[a].items = value; } StatChanged = true; } if (typeof req.body.secondaryQuickbarChoice == "string") { var value = [req.body.secondaryQuickbarChoice.replace(/-/ig, "").toUpperCase()]; if (req.body.secondaryQuickbarChoice == "") { value = []; } profile.stats.attributes.player_loadout.secondaryQuickBarRecord.slots[5].items = value; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "statModified", "name": "player_loadout", "value": profile.stats.attributes.player_loadout }) fs.writeFileSync(`./profiles/${req.query.profileId || "theater0"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "theater0", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Hero equipping STW express.post("/fortnite/api/game/v2/profile/*/client/AssignHeroToLoadout", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.loadoutId && req.body.slotName) { switch (req.body.slotName) { case "CommanderSlot": if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot1.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot1 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot2.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot2 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot3.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot3 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot4.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot4 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot5.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot5 = ""; } profile.items[req.body.loadoutId].attributes.crew_members.commanderslot = req.body.heroId || ""; StatChanged = true; break; case "FollowerSlot1": if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.commanderslot.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.commanderslot = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot2.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot2 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot3.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot3 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot4.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot4 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot5.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot5 = ""; } profile.items[req.body.loadoutId].attributes.crew_members.followerslot1 = req.body.heroId || ""; StatChanged = true; break; case "FollowerSlot2": if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot1.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot1 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.commanderslot.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.commanderslot = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot3.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot3 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot4.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot4 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot5.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot5 = ""; } profile.items[req.body.loadoutId].attributes.crew_members.followerslot2 = req.body.heroId || ""; StatChanged = true; break; case "FollowerSlot3": if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot1.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot1 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot2.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot2 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.commanderslot.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.commanderslot = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot4.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot4 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot5.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot5 = ""; } profile.items[req.body.loadoutId].attributes.crew_members.followerslot3 = req.body.heroId || ""; StatChanged = true; break; case "FollowerSlot4": if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot1.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot1 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot2.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot2 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot3.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot3 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.commanderslot.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.commanderslot = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot5.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot5 = ""; } profile.items[req.body.loadoutId].attributes.crew_members.followerslot4 = req.body.heroId || ""; StatChanged = true; break; case "FollowerSlot5": if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot1.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot1 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot2.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot2 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot3.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot3 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.followerslot4.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.followerslot4 = ""; } if (req.body.heroId.toLowerCase() == profile.items[req.body.loadoutId].attributes.crew_members.commanderslot.toLowerCase()) { profile.items[req.body.loadoutId].attributes.crew_members.commanderslot = ""; } profile.items[req.body.loadoutId].attributes.crew_members.followerslot5 = req.body.heroId || ""; StatChanged = true; break; } } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.loadoutId, "attributeName": "crew_members", "attributeValue": profile.items[req.body.loadoutId].attributes.crew_members }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Clear hero loadout STW express.post("/fortnite/api/game/v2/profile/*/client/ClearHeroLoadout", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.loadoutId) { profile.items[req.body.loadoutId].attributes = { "team_perk": "", "loadout_name": profile.items[req.body.loadoutId].attributes.loadout_name, "crew_members": { "followerslot5": "", "followerslot4": "", "followerslot3": "", "followerslot2": "", "followerslot1": "", "commanderslot": profile.items[req.body.loadoutId].attributes.crew_members.commanderslot }, "loadout_index": profile.items[req.body.loadoutId].attributes.loadout_index, "gadgets": [ { "gadget": "", "slot_index": 0 }, { "gadget": "", "slot_index": 1 } ] } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.loadoutId, "attributeName": "team_perk", "attributeValue": profile.items[req.body.loadoutId].attributes.team_perk }) ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.loadoutId, "attributeName": "crew_members", "attributeValue": profile.items[req.body.loadoutId].attributes.crew_members }) ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.loadoutId, "attributeName": "gadgets", "attributeValue": profile.items[req.body.loadoutId].attributes.gadgets }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Recycle items STW express.post("/fortnite/api/game/v2/profile/*/client/RecycleItemBatch", async (req, res) => { const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var MultiUpdate = []; var Notifications = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; var ItemExists = false; if (req.body.targetItemIds) { for (var i in req.body.targetItemIds) { let id = req.body.targetItemIds[i]; if (seasondata.season > 11 || seasondata.build == 11.30 || seasondata.build == 11.31 || seasondata.build == 11.40 || seasondata.build == 11.50) { var collection_book_profile = require("./profiles/collection_book_people0.json"); if (profile.items[id].templateId.toLowerCase().startsWith("schematic:")) { collection_book_profile = require("./profiles/collection_book_schematics0.json"); } if (MultiUpdate.length == 0) { MultiUpdate.push({ "profileRevision": collection_book_profile.rvn || 0, "profileId": collection_book_profile.profileId || "collection_book_people0", "profileChangesBaseRevision": collection_book_profile.rvn || 0, "profileChanges": [], "profileCommandRevision": collection_book_profile.commandRevision || 0, }) } for (var key in collection_book_profile.items) { const Template1 = profile.items[id].templateId; const Template2 = collection_book_profile.items[key].templateId; if (Template1.substring(0, Template1.length - 4).toLowerCase() == Template2.substring(0, Template2.length - 4).toLowerCase()) { if (Template1.toLowerCase().startsWith("worker:") && Template2.toLowerCase().startsWith("worker:")) { if (profile.items[id].attributes.hasOwnProperty("personality") && collection_book_profile.items[key].attributes.hasOwnProperty("personality")) { const Personality1 = profile.items[id].attributes.personality; const Personality2 = collection_book_profile.items[key].attributes.personality; if (Personality1.toLowerCase() == Personality2.toLowerCase()) { if (profile.items[id].attributes.level > collection_book_profile.items[key].attributes.level) { delete collection_book_profile.items[key]; MultiUpdate[0].profileChanges.push({ "changeType": "itemRemoved", "itemId": key }) ItemExists = false; } else { ItemExists = true; } } } } else { if (profile.items[id].attributes.level > collection_book_profile.items[key].attributes.level) { delete collection_book_profile.items[key]; MultiUpdate[0].profileChanges.push({ "changeType": "itemRemoved", "itemId": key }) ItemExists = false; } else { ItemExists = true; } } } } if (ItemExists == false) { collection_book_profile.items[id] = profile.items[id]; MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": id, "item": collection_book_profile.items[id] }) Notifications.push({ "type": "slotItemResult", "primary": true, "slottedItemId": id }) } delete profile.items[id]; ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": id }) collection_book_profile.rvn += 1; collection_book_profile.commandRevision += 1; MultiUpdate[0].profileRevision = collection_book_profile.rvn; MultiUpdate[0].profileCommandRevision = collection_book_profile.commandRevision; fs.writeFileSync(`./profiles/${collection_book_profile.profileId || "collection_book_people0"}.json`, JSON.stringify(collection_book_profile, null, 2)); } else { delete profile.items[id]; ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": id }) } } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "notifications": Notifications, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "multiUpdate": MultiUpdate, "responseVersion": 1 }) res.end(); }); // Add item from collection book STW express.post("/fortnite/api/game/v2/profile/*/client/ResearchItemFromCollectionBook", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; const ID = makeid(); if (req.body.templateId) { profile.items[ID] = { "templateId": req.body.templateId, "attributes": { "last_state_change_time": "2017-08-29T21:05:57.087Z", "max_level_bonus": 0, "level": 1, "item_seen": false, "xp": 0, "sent_new_notification": true, "favorite": false }, "quantity": 1 } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": profile.items[ID] }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Slot item in collection book STW express.post("/fortnite/api/game/v2/profile/*/client/SlotItemInCollectionBook", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var MultiUpdate = []; var Notifications = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; var collection_book_profile = require("./profiles/collection_book_people0.json"); if (profile.items[req.body.itemId].templateId.toLowerCase().startsWith("schematic:")) { collection_book_profile = require("./profiles/collection_book_schematics0.json"); } if (req.body.itemId) { MultiUpdate.push({ "profileRevision": collection_book_profile.rvn || 0, "profileId": collection_book_profile.profileId || "collection_book_people0", "profileChangesBaseRevision": collection_book_profile.rvn || 0, "profileChanges": [], "profileCommandRevision": collection_book_profile.commandRevision || 0, }) for (var key in collection_book_profile.items) { const Template1 = profile.items[req.body.itemId].templateId; const Template2 = collection_book_profile.items[key].templateId; if (Template1.substring(0, Template1.length-4).toLowerCase() == Template2.substring(0, Template2.length-4).toLowerCase()) { if (Template1.toLowerCase().startsWith("worker:") && Template2.toLowerCase().startsWith("worker:")) { if (profile.items[req.body.itemId].attributes.hasOwnProperty("personality") && collection_book_profile.items[key].attributes.hasOwnProperty("personality")) { const Personality1 = profile.items[req.body.itemId].attributes.personality; const Personality2 = collection_book_profile.items[key].attributes.personality; if (Personality1.toLowerCase() == Personality2.toLowerCase()) { delete collection_book_profile.items[key]; MultiUpdate[0].profileChanges.push({ "changeType": "itemRemoved", "itemId": key }) } } } else { delete collection_book_profile.items[key]; MultiUpdate[0].profileChanges.push({ "changeType": "itemRemoved", "itemId": key }) } } } collection_book_profile.items[req.body.itemId] = profile.items[req.body.itemId]; delete profile.items[req.body.itemId]; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; collection_book_profile.rvn += 1; collection_book_profile.commandRevision += 1; MultiUpdate[0].profileRevision = collection_book_profile.rvn || 0; MultiUpdate[0].profileCommandRevision = collection_book_profile.commandRevision || 0; ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": req.body.itemId }) MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": req.body.itemId, "item": collection_book_profile.items[req.body.itemId] }) Notifications.push({ "type": "slotItemResult", "primary": true, "slottedItemId": req.body.itemId }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); fs.writeFileSync(`./profiles/${collection_book_profile.profileId || "collection_book_people0"}.json`, JSON.stringify(collection_book_profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "notifications": Notifications, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "multiUpdate": MultiUpdate, "responseVersion": 1 }) res.end(); }); // Unslot item from collection book STW express.post("/fortnite/api/game/v2/profile/*/client/UnslotItemFromCollectionBook", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var MultiUpdate = []; var Notifications = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; var collection_book_profile = require("./profiles/collection_book_people0.json"); if (req.body.templateId.toLowerCase().startsWith("schematic:")) { collection_book_profile = require("./profiles/collection_book_schematics0.json"); } const ID = makeid(); MultiUpdate.push({ "profileRevision": collection_book_profile.rvn || 0, "profileId": collection_book_profile.profileId || "collection_book_people0", "profileChangesBaseRevision": collection_book_profile.rvn || 0, "profileChanges": [], "profileCommandRevision": collection_book_profile.commandRevision || 0, }) if (profile.items[req.body.itemId]) { profile.items[ID] = collection_book_profile.items[req.body.itemId]; ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": profile.items[ID] }) delete collection_book_profile.items[req.body.itemId]; MultiUpdate[0].profileChanges.push({ "changeType": "itemRemoved", "itemId": req.body.itemId }) StatChanged = true; } if (!profile.items[req.body.itemId]) { profile.items[req.body.itemId] = collection_book_profile.items[req.body.itemId]; ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": req.body.itemId, "item": profile.items[req.body.itemId] }) delete collection_book_profile.items[req.body.itemId]; MultiUpdate[0].profileChanges.push({ "changeType": "itemRemoved", "itemId": req.body.itemId }) StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; collection_book_profile.rvn += 1; collection_book_profile.commandRevision += 1; MultiUpdate[0].profileRevision = collection_book_profile.rvn || 0; MultiUpdate[0].profileCommandRevision = collection_book_profile.commandRevision || 0; fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); fs.writeFileSync(`./profiles/${collection_book_profile.profileId || "collection_book_people0"}.json`, JSON.stringify(collection_book_profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "notifications": Notifications, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "multiUpdate": MultiUpdate, "responseVersion": 1 }) res.end(); }); // Claim collection book rewards STW express.post("/fortnite/api/game/v2/profile/*/client/ClaimCollectionBookRewards", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.requiredXp) { profile.stats.attributes.collection_book.maxBookXpLevelAchieved += 1; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "statModified", "name": "collection_book", "value": profile.stats.attributes.collection_book }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Modify schematic perk STW express.post("/fortnite/api/game/v2/profile/*/client/RespecAlteration", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.targetItemId && req.body.alterationId) { if (!profile.items[req.body.targetItemId].attributes.alterations) { profile.items[req.body.targetItemId].attributes.alterations = ["","","","","",""]; } profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot] = req.body.alterationId; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.targetItemId, "attributeName": "alterations", "attributeValue": profile.items[req.body.targetItemId].attributes.alterations }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Upgrade schematic perk STW express.post("/fortnite/api/game/v2/profile/*/client/UpgradeAlteration", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.targetItemId) { if (profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].toLowerCase().includes("t04")) { profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot] = profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].replace(/t04/ig, "T05"); } if (profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].toLowerCase().includes("t03")) { profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot] = profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].replace(/t03/ig, "T04"); } if (profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].toLowerCase().includes("t02")) { profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot] = profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].replace(/t02/ig, "T03"); } if (profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].toLowerCase().includes("t01")) { profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot] = profile.items[req.body.targetItemId].attributes.alterations[req.body.alterationSlot].replace(/t01/ig, "T02"); } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.targetItemId, "attributeName": "alterations", "attributeValue": profile.items[req.body.targetItemId].attributes.alterations }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Reset research levels STW express.post("/fortnite/api/game/v2/profile/*/client/RespecResearch", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (profile.stats.attributes.research_levels) { profile.stats.attributes.research_levels.technology = 0; profile.stats.attributes.research_levels.fortitude = 0; profile.stats.attributes.research_levels.offense = 0; profile.stats.attributes.research_levels.resistance = 0; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "statModified", "name": "research_levels", "value": profile.stats.attributes.research_levels }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Reset upgrade levels STW express.post("/fortnite/api/game/v2/profile/*/client/RespecUpgrades", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; for (var key in profile.items) { if (profile.items[key].templateId.toLowerCase().startsWith("homebasenode:skilltree_")) { profile.items[key].quantity = 0; ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": key, "quantity": profile.items[key].quantity }) } } StatChanged = true; if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Upgrade research levels STW express.post("/fortnite/api/game/v2/profile/*/client/PurchaseResearchStatUpgrade", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (profile.stats.attributes.research_levels && req.body.statId) { profile.stats.attributes.research_levels[req.body.statId] += 1; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "statModified", "name": "research_levels", "value": profile.stats.attributes.research_levels }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Upgrade levels STW express.post("/fortnite/api/game/v2/profile/*/client/PurchaseOrUpgradeHomebaseNode", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; var CreateHomebaseNode = true; if (req.body.nodeId) { for (var key in profile.items) { if (profile.items[key].templateId.toLowerCase() == req.body.nodeId.toLowerCase()) { profile.items[key].quantity += 1; ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": key, "quantity": profile.items[key].quantity }) CreateHomebaseNode = false; } } if (CreateHomebaseNode == true) { const ID = makeid(); profile.items[ID] = { "templateId": req.body.nodeId, "attributes": { "item_seen": false }, "quantity": 1 } ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": profile.items[ID] }) } } StatChanged = true; if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Set active hero loadout STW express.post("/fortnite/api/game/v2/profile/*/client/SetActiveHeroLoadout", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.selectedLoadout) { profile.stats.attributes.selected_hero_loadout = req.body.selectedLoadout; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "statModified", "name": "selected_hero_loadout", "value": profile.stats.attributes.selected_hero_loadout }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Activate consumable STW express.post("/fortnite/api/game/v2/profile/*/client/ActivateConsumable", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; var XPBoost; if (req.body.targetItemId) { profile.items[req.body.targetItemId].quantity -= 1; for (var key in profile.items) { if (profile.items[key].templateId == "Token:xpboost") { var randomNumber = Math.floor(Math.random() * 1250000); if (randomNumber < 1000000) { randomNumber += 1000000 } profile.items[key].quantity += randomNumber; XPBoost = key; } } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": req.body.targetItemId, "quantity": profile.items[req.body.targetItemId].quantity }) if (XPBoost) { ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": XPBoost, "quantity": profile.items[XPBoost].quantity }) } fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Unassign all squads STW express.post("/fortnite/api/game/v2/profile/*/client/UnassignAllSquads", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.squadIds) { for (var i in req.body.squadIds) { let id = req.body.squadIds[i]; for (var key in profile.items) { if (profile.items[key].attributes.hasOwnProperty('squad_id')) { if (profile.items[key].attributes.squad_id.toLowerCase() == id.toLowerCase()) { profile.items[key].attributes.squad_id = ""; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": key, "attributeName": "squad_id", "attributeValue": profile.items[key].attributes.squad_id }) } } } } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Open llama STW express.post("/fortnite/api/game/v2/profile/*/client/OpenCardPack", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); const ItemIDS = require("./responses/ItemIDS.json"); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var Notifications = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.cardPackItemId) { Notifications.push({ "type": "cardPackResult", "primary": true, "lootGranted": { "tierGroupName": profile.items[req.body.cardPackItemId].templateId.split(":")[1], "items": [] }, "displayLevel": 0 }) for (var i = 0; i < 10; i++) { const randomNumber = Math.floor(Math.random() * ItemIDS.length); const ID = makeid(); var Item = {"templateId":ItemIDS[randomNumber],"attributes":{"legacy_alterations":[],"max_level_bonus":0,"level":1,"refund_legacy_item":false,"item_seen":false,"alterations":["","","","","",""],"xp":0,"refundable":false,"alteration_base_rarities":[],"favorite":false},"quantity":1}; profile.items[ID] = Item ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": Item }) Notifications[0].lootGranted.items.push({ "itemType": ItemIDS[randomNumber], "itemGuid": ID, "itemProfile": req.query.profileId, "attributes": Item.attributes, "quantity": 1 }) } if (profile.items[req.body.cardPackItemId].quantity <= 1) { delete profile.items[req.body.cardPackItemId] ApplyProfileChanges.push({ "changeType": "itemRemoved", "itemId": req.body.cardPackItemId }) } try { profile.items[req.body.cardPackItemId].quantity -= 1; ApplyProfileChanges.push({ "changeType": "itemQuantityChanged", "itemId": req.body.cardPackItemId, "quantity": profile.items[req.body.cardPackItemId].quantity }) } catch (err) {} StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "notifications": Notifications, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Add items to StW X-Ray Llamas express.post("/fortnite/api/game/v2/profile/*/client/PopulatePrerolledOffers", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); const ItemIDS = require("./responses/ItemIDS.json"); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var Notifications = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; var date = new Date().toISOString(); for (var key in profile.items) { if (profile.items[key].templateId.toLowerCase() == "prerolldata:preroll_basic") { if (date > profile.items[key].attributes.expiration) { profile.items[key].attributes.items = []; for (var i = 0; i < 10; i++) { const randomNumber = Math.floor(Math.random() * ItemIDS.length); profile.items[key].attributes.items.push({"itemType":ItemIDS[randomNumber],"attributes":{"legacy_alterations":[],"max_level_bonus":0,"level":1,"refund_legacy_item":false,"item_seen":false,"alterations":["","","","","",""],"xp":0,"refundable":false,"alteration_base_rarities":[],"favorite":false},"quantity":1}) } ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": key, "attributeName": "items", "attributeValue": profile.items[key].attributes.items }) profile.items[key].attributes.expiration = new Date().toISOString().split("T")[0] + "T23:59:59.999Z"; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": key, "attributeName": "expiration", "attributeValue": profile.items[key].attributes.expiration }) StatChanged = true; } } } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "notifications": Notifications, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Purchase item express.post("/fortnite/api/game/v2/profile/*/client/PurchaseCatalogEntry", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "profile0"}.json`); const campaign = require("./profiles/campaign.json"); const athena = require("./profiles/athena.json"); const ItemIDS = require("./responses/ItemIDS.json"); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var MultiUpdate = []; var Notifications = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var PurchasedLlama = false; var AthenaModified = false; var ItemExists = false; if (req.body.offerId && profile.profileId == "profile0" && PurchasedLlama == false) { catalog.storefronts.forEach(function(value, a) { if (value.name.toLowerCase().startsWith("cardpack")) { catalog.storefronts[a].catalogEntries.forEach(function(value, b) { if (value.offerId == req.body.offerId) { catalog.storefronts[a].catalogEntries[b].itemGrants.forEach(function(value, c) { var Quantity = req.body.purchaseQuantity || 1; const Item = { "templateId": value.templateId, "attributes": { "is_loot_tier_overridden": false, "max_level_bonus": 0, "level": 1391, "pack_source": "Schedule", "item_seen": false, "xp": 0, "favorite": false, "override_loot_tier": 0 }, "quantity": 1 }; for (var i = 0; i < Quantity; i++) { var ID = makeid(); profile.items[ID] = Item ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": profile.items[ID] }) } }) } }) } if (value.name.startsWith("BR")) { catalog.storefronts[a].catalogEntries.forEach(function(value, b) { if (value.offerId == req.body.offerId) { catalog.storefronts[a].catalogEntries[b].itemGrants.forEach(function(value, c) { const ID = value.templateId; for (var key in athena.items) { if (value.templateId.toLowerCase() == athena.items[key].templateId.toLowerCase()) { ItemExists = true; } } if (ItemExists == false) { if (MultiUpdate.length == 0) { MultiUpdate.push({ "profileRevision": athena.rvn || 0, "profileId": "athena", "profileChangesBaseRevision": athena.rvn || 0, "profileChanges": [], "profileCommandRevision": athena.commandRevision || 0, }) } if (Notifications.length == 0) { Notifications.push({ "type": "CatalogPurchase", "primary": true, "lootResult": { "items": [] } }) } const Item = { "templateId": value.templateId, "attributes": { "max_level_bonus": 0, "level": 1, "item_seen": false, "xp": 0, "variants": [], "favorite": false }, "quantity": 1 }; athena.items[ID] = Item; MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": athena.items[ID] }) Notifications[0].lootResult.items.push({ "itemType": value.templateId, "itemGuid": ID, "itemProfile": "athena", "quantity": value.quantity }) AthenaModified = true; } ItemExists = false; }) } }) } }) PurchasedLlama = true; if (AthenaModified == true) { athena.rvn += 1; athena.commandRevision += 1; MultiUpdate[0].profileRevision = athena.rvn || 0; MultiUpdate[0].profileCommandRevision = athena.commandRevision || 0; fs.writeFileSync("./profiles/athena.json", JSON.stringify(athena, null, 2)); } if (AthenaModified == false) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "profile0"}.json`, JSON.stringify(profile, null, 2)); } } if (req.body.offerId && profile.profileId == "common_core") { catalog.storefronts.forEach(function(value, a) { if (value.name.toLowerCase().startsWith("cardpack")) { catalog.storefronts[a].catalogEntries.forEach(function(value, b) { if (value.offerId == req.body.offerId) { catalog.storefronts[a].catalogEntries[b].itemGrants.forEach(function(value, c) { const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); if (4 >= seasondata.season && PurchasedLlama == false) { if (MultiUpdate.length == 0) { MultiUpdate.push({ "profileRevision": campaign.rvn || 0, "profileId": "campaign", "profileChangesBaseRevision": campaign.rvn || 0, "profileChanges": [], "profileCommandRevision": campaign.commandRevision || 0, }) } var Quantity = req.body.purchaseQuantity || 1; const Item = { "templateId": value.templateId, "attributes": { "is_loot_tier_overridden": false, "max_level_bonus": 0, "level": 1391, "pack_source": "Schedule", "item_seen": false, "xp": 0, "favorite": false, "override_loot_tier": 0 }, "quantity": 1 }; for (var i = 0; i < Quantity; i++) { var ID = makeid(); campaign.items[ID] = Item MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": campaign.items[ID] }) } PurchasedLlama = true; } if (seasondata.build >= 5 && seasondata.build <= 7.20 && PurchasedLlama == false) { if (MultiUpdate.length == 0) { MultiUpdate.push({ "profileRevision": campaign.rvn || 0, "profileId": "campaign", "profileChangesBaseRevision": campaign.rvn || 0, "profileChanges": [], "profileCommandRevision": campaign.commandRevision || 0, }) } var Quantity = req.body.purchaseQuantity || 1; const Item = { "templateId": value.templateId, "attributes": { "is_loot_tier_overridden": false, "max_level_bonus": 0, "level": 1391, "pack_source": "Schedule", "item_seen": false, "xp": 0, "favorite": false, "override_loot_tier": 0 }, "quantity": 1 }; for (var i = 0; i < Quantity; i++) { var ID = makeid(); campaign.items[ID] = Item MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": campaign.items[ID] }) } Notifications.push({ "type": "cardPackResult", "primary": true, "lootGranted": { "tierGroupName": "", "items": [] }, "displayLevel": 0 }) PurchasedLlama = true; } if (6 < seasondata.season && PurchasedLlama == false) { if (MultiUpdate.length == 0) { MultiUpdate.push({ "profileRevision": campaign.rvn || 0, "profileId": "campaign", "profileChangesBaseRevision": campaign.rvn || 0, "profileChanges": [], "profileCommandRevision": campaign.commandRevision || 0, }) } var Quantity = req.body.purchaseQuantity || 1; var LlamaItemIDS = []; var Item = { "templateId": value.templateId, "attributes": { "is_loot_tier_overridden": false, "max_level_bonus": 0, "level": 1391, "pack_source": "Schedule", "item_seen": false, "xp": 0, "favorite": false, "override_loot_tier": 0 }, "quantity": 1 }; for (var i = 0; i < Quantity; i++) { var ID = makeid(); campaign.items[ID] = Item MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": campaign.items[ID] }) LlamaItemIDS.push(ID); } Notifications.push({ "type": "CatalogPurchase", "primary": true, "lootResult": { "items": [] } }) if (req.body.currencySubType.toLowerCase() == "accountresource:voucher_basicpack") { Notifications[0].lootResult.items.push({ "itemType": value.templateId, "itemGuid": ID, "itemProfile": "campaign", "attributes": { "pack_source": "Store" }, "quantity": 1 }) } else { for (var x = 0; x < Quantity; x++) { for (var key in campaign.items) { if (campaign.items[key].templateId.toLowerCase() == "prerolldata:preroll_basic") { if (campaign.items[key].attributes.offerId == req.body.offerId) { for (var item in campaign.items[key].attributes.items) { const id = makeid(); var Item = {"templateId":campaign.items[key].attributes.items[item].itemType,"attributes":campaign.items[key].attributes.items[item].attributes,"quantity":campaign.items[key].attributes.items[item].quantity}; campaign.items[id] = Item; MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": id, "item": Item }) Notifications[0].lootResult.items.push({ "itemType": campaign.items[key].attributes.items[item].itemType, "itemGuid": id, "itemProfile": "campaign", "attributes": Item.attributes, "quantity": 1 }) } campaign.items[key].attributes.items = []; for (var i = 0; i < 10; i++) { const randomNumber = Math.floor(Math.random() * ItemIDS.length); campaign.items[key].attributes.items.push({"itemType":ItemIDS[randomNumber],"attributes":{"legacy_alterations":[],"max_level_bonus":0,"level":1,"refund_legacy_item":false,"item_seen":false,"alterations":["","","","","",""],"xp":0,"refundable":false,"alteration_base_rarities":[],"favorite":false},"quantity":1}) } MultiUpdate[0].profileChanges.push({ "changeType": "itemAttrChanged", "itemId": key, "attributeName": "items", "attributeValue": campaign.items[key].attributes.items }) } } } } } try { for (var i in LlamaItemIDS) { var id = LlamaItemIDS[i]; delete campaign.items[id]; MultiUpdate[0].profileChanges.push({ "changeType": "itemRemoved", "itemId": id }) } } catch (err) {} PurchasedLlama = true; } }) } }) } if (value.name.startsWith("BR")) { catalog.storefronts[a].catalogEntries.forEach(function(value, b) { if (value.offerId == req.body.offerId) { catalog.storefronts[a].catalogEntries[b].itemGrants.forEach(function(value, c) { const ID = value.templateId; for (var key in athena.items) { if (value.templateId.toLowerCase() == athena.items[key].templateId.toLowerCase()) { ItemExists = true; } } if (ItemExists == false) { if (MultiUpdate.length == 0) { MultiUpdate.push({ "profileRevision": athena.rvn || 0, "profileId": "athena", "profileChangesBaseRevision": athena.rvn || 0, "profileChanges": [], "profileCommandRevision": athena.commandRevision || 0, }) } if (Notifications.length == 0) { Notifications.push({ "type": "CatalogPurchase", "primary": true, "lootResult": { "items": [] } }) } const Item = { "templateId": value.templateId, "attributes": { "max_level_bonus": 0, "level": 1, "item_seen": false, "xp": 0, "variants": [], "favorite": false }, "quantity": 1 }; athena.items[ID] = Item; MultiUpdate[0].profileChanges.push({ "changeType": "itemAdded", "itemId": ID, "item": Item }) Notifications[0].lootResult.items.push({ "itemType": value.templateId, "itemGuid": ID, "itemProfile": "athena", "quantity": value.quantity }) AthenaModified = true; } ItemExists = false; }) } }) } }) if (AthenaModified == true) { athena.rvn += 1; athena.commandRevision += 1; MultiUpdate[0].profileRevision = athena.rvn || 0; MultiUpdate[0].profileCommandRevision = athena.commandRevision || 0; fs.writeFileSync("./profiles/athena.json", JSON.stringify(athena, null, 2)); } if (AthenaModified == false) { campaign.rvn += 1; campaign.commandRevision += 1; MultiUpdate[0].profileRevision = campaign.rvn || 0; MultiUpdate[0].profileCommandRevision = campaign.commandRevision || 0; fs.writeFileSync("./profiles/campaign.json", JSON.stringify(campaign, null, 2)); } } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "profile0", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "notifications": Notifications, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "multiUpdate": MultiUpdate, "responseVersion": 1 }) res.end(); }); // Set multiple items favorite express.post("/fortnite/api/game/v2/profile/*/client/SetItemFavoriteStatusBatch", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "athena"}.json`); if (profile.profileId == "athena") { const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); profile.stats.attributes.season_num = seasondata.season; if (seasondata.season == 2) { profile.stats.attributes.book_level = 70; } else { profile.stats.attributes.book_level = 100; } } // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.itemIds) { for (var i in req.body.itemIds) { profile.items[req.body.itemIds[i]].attributes.favorite = req.body.itemFavStatus[i] || false; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.itemIds[i], "attributeName": "favorite", "attributeValue": profile.items[req.body.itemIds[i]].attributes.favorite }) } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Set favorite on item express.post("/fortnite/api/game/v2/profile/*/client/SetItemFavoriteStatus", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "athena"}.json`); if (profile.profileId == "athena") { const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); profile.stats.attributes.season_num = seasondata.season; if (seasondata.season == 2) { profile.stats.attributes.book_level = 70; } else { profile.stats.attributes.book_level = 100; } } // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.targetItemId) { profile.items[req.body.targetItemId].attributes.favorite = req.body.bFavorite || false; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.targetItemId, "attributeName": "favorite", "attributeValue": profile.items[req.body.targetItemId].attributes.favorite }) fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Mark item as seen express.post("/fortnite/api/game/v2/profile/*/client/MarkItemSeen", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "athena"}.json`); if (profile.profileId == "athena") { const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); profile.stats.attributes.season_num = seasondata.season; if (seasondata.season == 2) { profile.stats.attributes.book_level = 70; } else { profile.stats.attributes.book_level = 100; } } // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.itemIds) { for (var i in req.body.itemIds) { profile.items[req.body.itemIds[i]].attributes.item_seen = true; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.itemIds[i], "attributeName": "item_seen", "attributeValue": profile.items[req.body.itemIds[i]].attributes.item_seen }) } StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Equip BR Locker 1 express.post("/fortnite/api/game/v2/profile/*/client/EquipBattleRoyaleCustomization", async (req, res) => { const profile = require("./profiles/athena.json"); const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); profile.stats.attributes.season_num = seasondata.season; if (seasondata.season == 2) { profile.stats.attributes.book_level = 70; } else { profile.stats.attributes.book_level = 100; } try { if (!profile.stats.attributes.favorite_dance) { profile.stats.attributes.favorite_dance = ["","","","","",""]; } if (!profile.stats.attributes.favorite_itemwraps) { profile.stats.attributes.favorite_itemwraps = ["","","","","","",""]; } } catch (err) {} // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; var VariantChanged = false; try { const ReturnVariantsAsString = JSON.stringify(req.body.variantUpdates || []) if (ReturnVariantsAsString.includes("active")) { if (profile.items[req.body.itemToSlot].attributes.variants.length == 0) { profile.items[req.body.itemToSlot].attributes.variants = req.body.variantUpdates || []; } for (var i in profile.items[req.body.itemToSlot].attributes.variants) { profile.items[req.body.itemToSlot].attributes.variants[i].active = req.body.variantUpdates[i].active || ""; } VariantChanged = true; } } catch (err) {} if (req.body.slotName) { switch (req.body.slotName) { case "Character": profile.stats.attributes.favorite_character = req.body.itemToSlot || ""; StatChanged = true; break; case "Backpack": profile.stats.attributes.favorite_backpack = req.body.itemToSlot || ""; StatChanged = true; break; case "Pickaxe": profile.stats.attributes.favorite_pickaxe = req.body.itemToSlot || ""; StatChanged = true; break; case "Glider": profile.stats.attributes.favorite_glider = req.body.itemToSlot || ""; StatChanged = true; break; case "SkyDiveContrail": profile.stats.attributes.favorite_skydivecontrail = req.body.itemToSlot || ""; StatChanged = true; break; case "MusicPack": profile.stats.attributes.favorite_musicpack = req.body.itemToSlot || ""; StatChanged = true; break; case "LoadingScreen": profile.stats.attributes.favorite_loadingscreen = req.body.itemToSlot || ""; StatChanged = true; break; case "Dance": var indexwithinslot = req.body.indexWithinSlot || 0; if (Math.sign(indexwithinslot) == 1 || Math.sign(indexwithinslot) == 0) { profile.stats.attributes.favorite_dance[indexwithinslot] = req.body.itemToSlot || ""; } StatChanged = true; break; case "ItemWrap": var indexwithinslot = req.body.indexWithinSlot || 0; switch (Math.sign(indexwithinslot)) { case 0: profile.stats.attributes.favorite_itemwraps[indexwithinslot] = req.body.itemToSlot || ""; break; case 1: profile.stats.attributes.favorite_itemwraps[indexwithinslot] = req.body.itemToSlot || ""; break; case -1: for (var i = 0; i < 7; i++) { profile.stats.attributes.favorite_itemwraps[i] = req.body.itemToSlot || ""; } break; } StatChanged = true; break; } } if (StatChanged == true) { var Category = (`favorite_${req.body.slotName || "character"}`).toLowerCase() if (Category == "favorite_itemwrap") { Category += "s" } profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "statModified", "name": Category, "value": profile.stats.attributes[Category] }) if (VariantChanged == true) { ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.itemToSlot, "attributeName": "variants", "attributeValue": profile.items[req.body.itemToSlot].attributes.variants }) } fs.writeFileSync("./profiles/athena.json", JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Set BR Banner 1 express.post("/fortnite/api/game/v2/profile/*/client/SetBattleRoyaleBanner", async (req, res) => { const profile = require("./profiles/athena.json"); const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); profile.stats.attributes.season_num = seasondata.season; if (seasondata.season == 2) { profile.stats.attributes.book_level = 70; } else { profile.stats.attributes.book_level = 100; } // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.homebaseBannerIconId && req.body.homebaseBannerColorId) { profile.stats.attributes.banner_icon = req.body.homebaseBannerIconId; profile.stats.attributes.banner_color = req.body.homebaseBannerColorId; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "statModified", "name": "banner_icon", "value": profile.stats.attributes.banner_icon }) ApplyProfileChanges.push({ "changeType": "statModified", "name": "banner_color", "value": profile.stats.attributes.banner_color }) fs.writeFileSync("./profiles/athena.json", JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Set BR Banner 2 express.post("/fortnite/api/game/v2/profile/*/client/SetCosmeticLockerBanner", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "athena"}.json`); if (profile.profileId == "athena") { const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); profile.stats.attributes.season_num = seasondata.season; if (seasondata.season == 2) { profile.stats.attributes.book_level = 70; } else { profile.stats.attributes.book_level = 100; } } // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.bannerIconTemplateName && req.body.bannerColorTemplateName && req.body.lockerItem) { profile.items[req.body.lockerItem].attributes.banner_icon_template = req.body.bannerIconTemplateName; profile.items[req.body.lockerItem].attributes.banner_color_template = req.body.bannerColorTemplateName; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.lockerItem, "attributeName": "banner_icon_template", "attributeValue": profile.items[req.body.lockerItem].attributes.banner_icon_template }) ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.lockerItem, "attributeName": "banner_color_template", "attributeValue": profile.items[req.body.lockerItem].attributes.banner_color_template }) fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Set BR Locker 2 express.post("/fortnite/api/game/v2/profile/*/client/SetCosmeticLockerSlot", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "athena"}.json`); if (profile.profileId == "athena") { const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); profile.stats.attributes.season_num = seasondata.season; if (seasondata.season == 2) { profile.stats.attributes.book_level = 70; } else { profile.stats.attributes.book_level = 100; } } // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; try { const ReturnVariantsAsString = JSON.stringify(req.body.variantUpdates || []) if (ReturnVariantsAsString.includes("active")) { var new_variants = [ { "variants": [] } ]; if (profile.profileId == "athena") { if (profile.items[req.body.itemToSlot].attributes.variants.length == 0) { profile.items[req.body.itemToSlot].attributes.variants = req.body.variantUpdates || []; } for (var i in profile.items[req.body.itemToSlot].attributes.variants) { profile.items[req.body.itemToSlot].attributes.variants[i].active = req.body.variantUpdates[i].active || ""; } } for (var i in req.body.variantUpdates) { new_variants[0].variants.push({ "channel": req.body.variantUpdates[i].channel, "active": req.body.variantUpdates[i].active }) profile.items[req.body.lockerItem].attributes.locker_slots_data.slots[req.body.category].activeVariants = new_variants; } } } catch (err) {} if (req.body.category && req.body.lockerItem) { switch (req.body.category) { case "Character": profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.Character.items = [req.body.itemToSlot || ""]; StatChanged = true; break; case "Backpack": profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.Backpack.items = [req.body.itemToSlot || ""]; StatChanged = true; break; case "Pickaxe": profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.Pickaxe.items = [req.body.itemToSlot || ""]; StatChanged = true; break; case "Glider": profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.Glider.items = [req.body.itemToSlot || ""]; StatChanged = true; break; case "SkyDiveContrail": profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.SkyDiveContrail.items = [req.body.itemToSlot || ""]; StatChanged = true; break; case "MusicPack": profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.MusicPack.items = [req.body.itemToSlot || ""]; StatChanged = true; break; case "LoadingScreen": profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.LoadingScreen.items = [req.body.itemToSlot || ""]; StatChanged = true; break; case "Dance": var indexwithinslot = req.body.slotIndex || 0; if (Math.sign(indexwithinslot) == 1 || Math.sign(indexwithinslot) == 0) { profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.Dance.items[indexwithinslot] = req.body.itemToSlot || ""; } StatChanged = true; break; case "ItemWrap": var indexwithinslot = req.body.slotIndex || 0; switch (Math.sign(indexwithinslot)) { case 0: profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.ItemWrap.items[indexwithinslot] = req.body.itemToSlot || ""; break; case 1: profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.ItemWrap.items[indexwithinslot] = req.body.itemToSlot || ""; break; case -1: for (var i = 0; i < 7; i++) { profile.items[req.body.lockerItem].attributes.locker_slots_data.slots.ItemWrap.items[i] = req.body.itemToSlot || ""; } break; } StatChanged = true; break; } } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.lockerItem, "attributeName": "locker_slots_data", "attributeValue": profile.items[req.body.lockerItem].attributes.locker_slots_data }) fs.writeFileSync(`./profiles/${req.query.profileId || "athena"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // Set hero variants STW express.post("/fortnite/api/game/v2/profile/*/client/SetHeroCosmeticVariants", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "campaign"}.json`); // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; var StatChanged = false; if (req.body.outfitVariants && req.body.backblingVariants && req.body.heroItem) { profile.items[req.body.heroItem].attributes.outfitvariants = req.body.outfitVariants; profile.items[req.body.heroItem].attributes.backblingvariants = req.body.backblingVariants; StatChanged = true; } if (StatChanged == true) { profile.rvn += 1; profile.commandRevision += 1; ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.heroItem, "attributeName": "outfitvariants", "attributeValue": profile.items[req.body.heroItem].attributes.outfitvariants }) ApplyProfileChanges.push({ "changeType": "itemAttrChanged", "itemId": req.body.heroItem, "attributeName": "backblingvariants", "attributeValue": profile.items[req.body.heroItem].attributes.backblingvariants }) fs.writeFileSync(`./profiles/${req.query.profileId || "campaign"}.json`, JSON.stringify(profile, null, 2)); } // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "campaign", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // any mcp request that doesn't have something assigned to it express.post("/fortnite/api/game/v2/profile/*/client/*", async (req, res) => { const profile = require(`./profiles/${req.query.profileId || "athena"}.json`); if (profile.profileId == "athena") { const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); profile.stats.attributes.season_num = seasondata.season; if (seasondata.season == 2) { profile.stats.attributes.book_level = 70; } else { profile.stats.attributes.book_level = 100; } } // do not change any of these or you will end up breaking it var ApplyProfileChanges = []; var BaseRevision = profile.rvn || 0; var QueryRevision = req.query.rvn || -1; // this doesn't work properly on version v12.20 and above but whatever if (QueryRevision != BaseRevision) { ApplyProfileChanges = [{ "changeType": "fullProfileUpdate", "profile": profile }]; } res.json({ "profileRevision": profile.rvn || 0, "profileId": req.query.profileId || "athena", "profileChangesBaseRevision": BaseRevision, "profileChanges": ApplyProfileChanges, "profileCommandRevision": profile.commandRevision || 0, "serverTime": new Date().toISOString(), "responseVersion": 1 }) res.end(); }); // keep this at the end of the code thanks express.all("*", async (req, res) => { var XEpicErrorName = "errors.com.lawinserver.common.not_found"; var XEpicErrorCode = 1004; res.set({ 'X-Epic-Error-Name': XEpicErrorName, 'X-Epic-Error-Code': XEpicErrorCode }); res.status(404); res.json({ "errorCode": XEpicErrorName, "errorMessage": "Sorry the resource you were trying to find could not be found", "numericErrorCode": XEpicErrorCode, "originatingService": "any", "intent": "prod" }); res.end(); }); function getItemShop() { const catalog = JSON.parse(JSON.stringify(require("./responses/catalog.json"))); const CatalogConfig = require("./Config/catalog_config.json"); try { for (var value in CatalogConfig) { if (typeof CatalogConfig[value].templateId == "string") { if (CatalogConfig[value].templateId.length != 0) { const CatalogEntry = {"devName":"","offerId":"","fulfillmentIds":[],"dailyLimit":-1,"weeklyLimit":-1,"monthlyLimit":-1,"categories":[],"prices":[{"currencyType":"MtxCurrency","currencySubType":"","regularPrice":0,"finalPrice":0,"saleExpiration":"9999-12-02T01:12:00Z","basePrice":0}],"matchFilter":"","filterWeight":0,"appStoreId":[],"requirements":[{"requirementType":"DenyOnItemOwnership","requiredId":"","minQuantity":1}],"offerType":"StaticPrice","giftInfo":{"bIsEnabled":false,"forcedGiftBoxTemplateId":"","purchaseRequirements":[],"giftRecordIds":[]},"refundable":true,"metaInfo":[],"displayAssetPath":"","itemGrants":[{"templateId":"","quantity":1}],"sortPriority":0,"catalogGroupPriority":0}; if (value.toLowerCase().startsWith("daily")) { catalog.storefronts.forEach((storefront, i) => { if (storefront.name == "BRDailyStorefront") { CatalogEntry.devName = CatalogConfig[value].templateId CatalogEntry.offerId = CatalogConfig[value].templateId CatalogEntry.requirements[0].requiredId = CatalogConfig[value].templateId CatalogEntry.itemGrants[0].templateId = CatalogConfig[value].templateId CatalogEntry.prices[0].basePrice = CatalogConfig[value].price CatalogEntry.prices[0].regularPrice = CatalogConfig[value].price CatalogEntry.prices[0].finalPrice = CatalogConfig[value].price catalog.storefronts[i].catalogEntries.push(CatalogEntry); } }) } if (value.toLowerCase().startsWith("featured")) { catalog.storefronts.forEach((storefront, i) => { if (storefront.name == "BRWeeklyStorefront") { CatalogEntry.devName = CatalogConfig[value].templateId CatalogEntry.offerId = CatalogConfig[value].templateId CatalogEntry.requirements[0].requiredId = CatalogConfig[value].templateId CatalogEntry.itemGrants[0].templateId = CatalogConfig[value].templateId CatalogEntry.prices[0].basePrice = CatalogConfig[value].price CatalogEntry.prices[0].regularPrice = CatalogConfig[value].price CatalogEntry.prices[0].finalPrice = CatalogConfig[value].price catalog.storefronts[i].catalogEntries.push(CatalogEntry); } }) } } } } } catch (err) {} return catalog; } function getTheater(req) { const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); var theater = JSON.stringify(require("./responses/worldstw.json")); try { if (seasondata.build >= 15.30) { theater = theater.replace(/\/Game\//ig, "\/SaveTheWorld\/"); theater = theater.replace(/\"DataTable\'\/SaveTheWorld\//ig, "\"DataTable\'\/Game\/"); } var date = new Date().toISOString() // Set the 24-hour StW mission refresh date for version season 9 and above if (seasondata.season >= 9) { date = date.split("T")[0] + "T23:59:59.999Z"; } else { // Set the 6-hour StW mission refresh date for versions below season 9 if (date < (date.split("T")[0] + "T05:59:59.999Z")) { date = date.split("T")[0] + "T05:59:59.999Z"; } else if (date < (date.split("T")[0] + "T11:59:59.999Z")) { date = date.split("T")[0] + "T11:59:59.999Z"; } else if (date < (date.split("T")[0] + "T17:59:59.999Z")) { date = date.split("T")[0] + "T17:59:59.999Z"; } else if (date < (date.split("T")[0] + "T23:59:59.999Z")) { date = date.split("T")[0] + "T23:59:59.999Z"; } } theater = theater.replace(/2017-07-25T23:59:59.999Z/ig, date); } catch (err) {} theater = JSON.parse(theater) return theater; } function getContentPages(req) { const seasonchecker = require("./seasonchecker.js"); const seasondata = require("./memory.json"); seasonchecker(req, seasondata); const contentpages = JSON.parse(JSON.stringify(require("./responses/contentpages.json"))); var Language = "en"; if (req.headers["accept-language"]) { if (req.headers["accept-language"].includes("-") && req.headers["accept-language"] != "es-419") { Language = req.headers["accept-language"].split("-")[0]; } else { Language = req.headers["accept-language"]; } } const modes = ["saveTheWorldUnowned", "battleRoyale", "creative", "saveTheWorld"]; const news = ["savetheworldnews", "battleroyalenews"] try { modes.forEach(mode => { contentpages.subgameselectdata[mode].message.title = contentpages.subgameselectdata[mode].message.title[Language] contentpages.subgameselectdata[mode].message.body = contentpages.subgameselectdata[mode].message.body[Language] }) } catch (err) {} try { if (seasondata.season < 5 || (seasondata.season == 5 && Number(seasondata.build.toString().split(".")[1]) < 30)) { news.forEach(mode => { contentpages[mode].news.messages[0].image = "https://cdn.discordapp.com/attachments/927739901540188200/930879507496308736/discord.png"; contentpages[mode].news.messages[1].image = "https://cdn.discordapp.com/attachments/927739901540188200/930879519882088508/lawin.png"; }) } } catch (err) {} try { contentpages.dynamicbackgrounds.backgrounds.backgrounds[0].stage = `season${seasondata.season}`; contentpages.dynamicbackgrounds.backgrounds.backgrounds[1].stage = `season${seasondata.season}`; if (seasondata.season == 10) { contentpages.dynamicbackgrounds.backgrounds.backgrounds[0].stage = "seasonx"; contentpages.dynamicbackgrounds.backgrounds.backgrounds[1].stage = "seasonx"; } if (seasondata.build == 11.31 || seasondata.build == 11.40) { contentpages.dynamicbackgrounds.backgrounds.backgrounds[0].stage = "Winter19"; contentpages.dynamicbackgrounds.backgrounds.backgrounds[1].stage = "Winter19"; } if (seasondata.build == 19.01) { contentpages.dynamicbackgrounds.backgrounds.backgrounds[0].stage = "winter2021"; contentpages.dynamicbackgrounds.backgrounds.backgrounds[0].backgroundimage = "https://cdn.discordapp.com/attachments/927739901540188200/930880158167085116/t-bp19-lobby-xmas-2048x1024-f85d2684b4af.png"; contentpages.subgameinfo.battleroyale.image = "https://cdn.discordapp.com/attachments/927739901540188200/930880421514846268/19br-wf-subgame-select-512x1024-16d8bb0f218f.jpg"; contentpages.specialoffervideo.bSpecialOfferEnabled = "true"; } } catch (err) {} return contentpages; } function makeid() { let CurrentDate = (new Date()).valueOf().toString(); let RandomFloat = Math.random().toString(); let ID = crypto.createHash('md5').update(CurrentDate + RandomFloat).digest('hex'); let FinishedID = ID.slice(0, 8) + "-" + ID.slice(8, 12) + "-" + ID.slice(12, 16) + "-" + ID.slice(16, 20) + "-" + ID.slice(20, 32); return FinishedID; }