diff --git a/CloudStorage/readme.txt b/CloudStorage/readme.txt deleted file mode 100644 index f4497b4..0000000 --- a/CloudStorage/readme.txt +++ /dev/null @@ -1 +0,0 @@ -Place all your cloudstorage files in this directory. \ No newline at end of file diff --git a/index.js b/index.js index 3d2e94a..ce033e7 100644 --- a/index.js +++ b/index.js @@ -1,17 +1,8 @@ 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/')) { @@ -30,6864 +21,27 @@ express.use(function(req, res, next) { } }); express.use(Express.json()); -express.use(Express.urlencoded({ - extended: true -})); +express.use(Express.urlencoded({ extended: true })); express.use(Express.static('public')); +express.use(require("./structure/privacy.js")); +express.use(require("./structure/timeline.js")); +express.use(require("./structure/user.js")); +express.use(require("./structure/contentpages.js")); +express.use(require("./structure/friends.js")); +express.use(require("./structure/main.js")); +express.use(require("./structure/storefront.js")); +express.use(require("./structure/version.js")); +express.use(require("./structure/lightswitch.js")); +express.use(require("./structure/affiliate.js")); +express.use(require("./structure/matchmaking.js")); +express.use(require("./structure/cloudstorage.js")); +express.use(require("./structure/mcp.js")); + 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(); -}); +if (!fs.existsSync(path.join(process.env.LOCALAPPDATA, "LawinServer"))) fs.mkdirSync(path.join(process.env.LOCALAPPDATA, "LawinServer")); // keep this at the end of the code thanks express.all("*", async (req, res) => { @@ -6908,163 +62,4 @@ express.all("*", async (req, res) => { "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; -} +}); \ No newline at end of file diff --git a/profiles/campaign.json b/profiles/campaign.json index d1f988c..e063c77 100644 --- a/profiles/campaign.json +++ b/profiles/campaign.json @@ -1,7 +1,7 @@ { "_id": "LawinServer", - "created": "2020-01-01T11:10:13.470Z", - "updated": "2020-08-04T19:30:07.409Z", + "created": "0001-01-01T00:00:00.000Z", + "updated": "0001-01-01T00:00:00.000Z", "rvn": 0, "wipeNumber": 1, "accountId": "LawinServer", @@ -63254,7 +63254,7 @@ "CollectionBookPage:pagespecial_shadowops_heroes", "CollectionBookPage:pagespecial_wildwest_heroes" ], - "maxBookXpLevelAchieved": 100 + "maxBookXpLevelAchieved": 0 }, "mfa_reward_claimed": true, "quest_manager": { diff --git a/profiles/collection_book_people0.json b/profiles/collection_book_people0.json index 527fbdd..88b1ccf 100644 --- a/profiles/collection_book_people0.json +++ b/profiles/collection_book_people0.json @@ -1,7 +1,7 @@ { "_id": "LawinServer", - "created": "2020-01-01T17:22:28.023Z", - "updated": "2020-03-24T00:25:49.087Z", + "created": "0001-01-01T00:00:00.000Z", + "updated": "0001-01-01T00:00:00.000Z", "rvn": 0, "wipeNumber": 1, "accountId": "LawinServer", @@ -175,4 +175,4 @@ } }, "commandRevision": 0 -} +} \ No newline at end of file diff --git a/profiles/collection_book_schematics0.json b/profiles/collection_book_schematics0.json index d1fcf98..cf39f35 100644 --- a/profiles/collection_book_schematics0.json +++ b/profiles/collection_book_schematics0.json @@ -1,7 +1,7 @@ { "_id": "LawinServer", - "created": "2020-01-01T17:22:28.023Z", - "updated": "2020-03-24T00:25:49.087Z", + "created": "0001-01-01T00:00:00.000Z", + "updated": "0001-01-01T00:00:00.000Z", "rvn": 0, "wipeNumber": 1, "accountId": "LawinServer", diff --git a/profiles/collections.json b/profiles/collections.json index 9f1f9ab..eaafa44 100644 --- a/profiles/collections.json +++ b/profiles/collections.json @@ -1,7 +1,7 @@ { "_id": "LawinServer", - "created": "2020-01-01T17:22:28.023Z", - "updated": "2020-03-24T00:25:49.087Z", + "created": "0001-01-01T00:00:00.000Z", + "updated": "0001-01-01T00:00:00.000Z", "rvn": 0, "wipeNumber": 1, "accountId": "LawinServer", diff --git a/profiles/common_core.json b/profiles/common_core.json index 4a355b5..36257cc 100644 --- a/profiles/common_core.json +++ b/profiles/common_core.json @@ -1,6 +1,6 @@ { - "created": "2020-01-01T17:22:28.023Z", - "updated": "2020-06-21T19:06:31.519Z", + "created": "0001-01-01T00:00:00.000Z", + "updated": "0001-01-01T00:00:00.000Z", "rvn": 0, "wipeNumber": 1, "accountId": "LawinServer", diff --git a/profiles/common_public.json b/profiles/common_public.json index bf3cc2f..84cd8b0 100644 --- a/profiles/common_public.json +++ b/profiles/common_public.json @@ -1,6 +1,6 @@ { - "created": "2020-01-01T17:22:28.023Z", - "updated": "2020-07-11T19:06:31.519Z", + "created": "0001-01-01T00:00:00.000Z", + "updated": "0001-01-01T00:00:00.000Z", "rvn": 0, "wipeNumber": 1, "accountId": "LawinServer", diff --git a/profiles/creative.json b/profiles/creative.json index 404df06..75340a8 100644 --- a/profiles/creative.json +++ b/profiles/creative.json @@ -1,7 +1,7 @@ { "_id": "LawinServer", - "created": "2020-01-01T17:22:28.023Z", - "updated": "2020-03-24T00:25:49.087Z", + "created": "0001-01-01T00:00:00.000Z", + "updated": "0001-01-01T00:00:00.000Z", "rvn": 0, "wipeNumber": 1, "accountId": "LawinServer", diff --git a/profiles/metadata.json b/profiles/metadata.json index 0c85e4c..043af7c 100644 --- a/profiles/metadata.json +++ b/profiles/metadata.json @@ -1,7 +1,7 @@ { "_id": "LawinServer", - "created": "2017-11-24T18:39:56.363Z", - "updated": "2019-07-26T17:25:56.784Z", + "created": "0001-01-01T00:00:00.000Z", + "updated": "0001-01-01T00:00:00.000Z", "rvn": 0, "wipeNumber": 1, "accountId": "LawinServer", diff --git a/profiles/outpost0.json b/profiles/outpost0.json index 8ae226b..0044785 100644 --- a/profiles/outpost0.json +++ b/profiles/outpost0.json @@ -1,7 +1,7 @@ { "_id": "LawinServer", - "created": "2020-01-01T17:22:28.023Z", - "updated": "2020-03-24T00:25:49.087Z", + "created": "0001-01-01T00:00:00.000Z", + "updated": "0001-01-01T00:00:00.000Z", "rvn": 0, "wipeNumber": 1, "accountId": "LawinServer", diff --git a/profiles/profile0.json b/profiles/profile0.json index 1469a9f..62832ea 100644 --- a/profiles/profile0.json +++ b/profiles/profile0.json @@ -1,7 +1,7 @@ { "_id": "LawinServer", - "created": "2017-08-29T20:38:59.824Z", - "updated": "2017-12-25T02:08:43.518Z", + "created": "0001-01-01T00:00:00.000Z", + "updated": "0001-01-01T00:00:00.000Z", "rvn": 0, "wipeNumber": 1, "accountId": "LawinServer", diff --git a/profiles/theater0.json b/profiles/theater0.json index 4b27923..9276f2d 100644 --- a/profiles/theater0.json +++ b/profiles/theater0.json @@ -1,7 +1,7 @@ { "_id": "LawinServer", - "created": "2018-04-25T18:39:56.467Z", - "updated": "2020-02-05T22:45:21.455Z", + "created": "0001-01-01T00:00:00.000Z", + "updated": "0001-01-01T00:00:00.000Z", "rvn": 0, "wipeNumber": 1, "accountId": "LawinServer", diff --git a/seasonchecker.js b/seasonchecker.js deleted file mode 100644 index cfe2f62..0000000 --- a/seasonchecker.js +++ /dev/null @@ -1,54 +0,0 @@ -function CheckLobbyAndSeason(req, seasondata) { - if (req.headers["user-agent"]) - { - var CL = ""; - - if (req.headers["user-agent"]) { - try { - var BuildID = req.headers["user-agent"].split("-")[3].split(",")[0] - if (!Number.isNaN(Number(BuildID))) { - CL = BuildID; - } - - if (Number.isNaN(Number(BuildID))) { - var BuildID = req.headers["user-agent"].split("-")[3].split(" ")[0] - if (!Number.isNaN(Number(BuildID))) { - CL = BuildID; - } - } - } catch (err) { - try { - var BuildID = req.headers["user-agent"].split("-")[1].split("+")[0] - if (!Number.isNaN(Number(BuildID))) { - CL = BuildID; - } - } catch (err) {} - } - } - - try { - var Build = req.headers["user-agent"].split("Release-")[1].split("-")[0]; - - if (Build.split(".").length == 3) { - Value = Build.split("."); - Build = Value[0] + "." + Value[1] + Value[2]; - } - - seasondata.season = Number(Build.split(".")[0]); - seasondata.build = Number(Build); - seasondata.CL = CL; - seasondata.lobby = `LobbySeason${seasondata.season}`; - - if (Number.isNaN(seasondata.season)) { - throw new Error(); - } - } catch (err) { - seasondata.season = 2; - seasondata.build = 2.0; - seasondata.CL = CL; - seasondata.lobby = "LobbyWinterDecor"; - } - } -} - -module.exports = CheckLobbyAndSeason; \ No newline at end of file diff --git a/structure/affiliate.js b/structure/affiliate.js new file mode 100644 index 0000000..7055ee8 --- /dev/null +++ b/structure/affiliate.js @@ -0,0 +1,27 @@ +const Express = require("express"); +const express = Express.Router(); + +express.get("/affiliate/api/public/affiliates/slug/:slug", async (req, res) => { + const SupportedCodes = require("./../responses/SAC.json"); + var ValidCode = false; + + SupportedCodes.forEach(code => { + if (req.params.slug.toLowerCase() == code.toLowerCase()) { + ValidCode = true; + return res.json({ + "id": code, + "slug": code, + "displayName": code, + "status": "ACTIVE", + "verified": false + }); + } + }) + + if (ValidCode == false) { + res.status(404); + res.json({}); + } +}) + +module.exports = express; \ No newline at end of file diff --git a/structure/cloudstorage.js b/structure/cloudstorage.js new file mode 100644 index 0000000..099ff76 --- /dev/null +++ b/structure/cloudstorage.js @@ -0,0 +1,131 @@ +const Express = require("express"); +const express = Express.Router(); +const crypto = require("crypto"); +const fs = require("fs"); +const path = require("path"); +const functions = require("./functions.js"); +const memory = require("./../memory.json"); + +express.get("/fortnite/api/cloudstorage/system", async (req, res) => { + functions.GetVersionInfo(req, memory); + + if (memory.build >= 9.40 && memory.build <= 10.40) { + return res.status(404).end(); + } + + const dir = path.join(__dirname, "..", "CloudStorage") + var CloudFiles = []; + + fs.readdirSync(dir).forEach(name => { + if (name.toLowerCase().endsWith(".ini")) { + const ParsedFile = fs.readFileSync(path.join(dir, name), 'utf-8'); + const ParsedStats = fs.statSync(path.join(dir, 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(); + } else { + 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" + }); + } + + functions.GetVersionInfo(req, memory); + + var currentBuildID = memory.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(); + } else { + 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") + + functions.GetVersionInfo(req, memory); + + var currentBuildID = memory.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")); + } + + functions.GetVersionInfo(req, memory); + + var currentBuildID = memory.CL; + const file = path.join(process.env.LOCALAPPDATA, "LawinServer", "ClientSettings", `ClientSettings-${currentBuildID}.Sav`); + + fs.writeFileSync(file, req.rawBody, 'latin1'); + res.status(204).end(); +}) + +module.exports = express; \ No newline at end of file diff --git a/structure/contentpages.js b/structure/contentpages.js new file mode 100644 index 0000000..4411db7 --- /dev/null +++ b/structure/contentpages.js @@ -0,0 +1,11 @@ +const Express = require("express"); +const express = Express.Router(); +const functions = require("./functions.js"); + +express.get("/content/api/pages/*", async (req, res) => { + const contentpages = functions.getContentPages(req); + + res.json(contentpages) +}) + +module.exports = express; \ No newline at end of file diff --git a/structure/friends.js b/structure/friends.js new file mode 100644 index 0000000..06af54e --- /dev/null +++ b/structure/friends.js @@ -0,0 +1,32 @@ +const Express = require("express"); +const express = Express.Router(); +const friendslist = require("./../responses/friendslist.json"); +const friendslist2 = require("./../responses/friendslist2.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("/friends/api/public/friends/*", async (req, res) => { + res.json(friendslist) +}) + +express.get("/friends/api/v1/*/summary", async (req, res) => { + res.json(friendslist2) +}) + +express.get("/friends/api/public/list/fortnite/*/recentPlayers", async (req, res) => { + res.json([]) +}) + +express.get("/friends/api/public/blocklist/*", async (req, res) => { + res.json({ + "blockedUsers": [] + }) +}) + +module.exports = express; \ No newline at end of file diff --git a/structure/functions.js b/structure/functions.js new file mode 100644 index 0000000..0783543 --- /dev/null +++ b/structure/functions.js @@ -0,0 +1,218 @@ +const crypto = require("crypto"); +const memory = require("./../memory.json"); + +function GetVersionInfo(req, memory) { + if (req.headers["user-agent"]) + { + var CL = ""; + + if (req.headers["user-agent"]) { + try { + var BuildID = req.headers["user-agent"].split("-")[3].split(",")[0] + if (!Number.isNaN(Number(BuildID))) { + CL = BuildID; + } + + if (Number.isNaN(Number(BuildID))) { + var BuildID = req.headers["user-agent"].split("-")[3].split(" ")[0] + if (!Number.isNaN(Number(BuildID))) { + CL = BuildID; + } + } + } catch (err) { + try { + var BuildID = req.headers["user-agent"].split("-")[1].split("+")[0] + if (!Number.isNaN(Number(BuildID))) { + CL = BuildID; + } + } catch (err) {} + } + } + + try { + var Build = req.headers["user-agent"].split("Release-")[1].split("-")[0]; + + if (Build.split(".").length == 3) { + Value = Build.split("."); + Build = Value[0] + "." + Value[1] + Value[2]; + } + + memory.season = Number(Build.split(".")[0]); + memory.build = Number(Build); + memory.CL = CL; + memory.lobby = `LobbySeason${memory.season}`; + + if (Number.isNaN(memory.season)) { + throw new Error(); + } + } catch (err) { + memory.season = 2; + memory.build = 2.0; + memory.CL = CL; + memory.lobby = "LobbyWinterDecor"; + } + } +} + +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) { + GetVersionInfo(req, memory); + + var theater = JSON.stringify(require("./../responses/worldstw.json")); + + try { + if (memory.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 (memory.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) { + GetVersionInfo(req, memory); + + 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 (memory.season < 5 || (memory.season == 5 && Number(memory.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${memory.season}`; + contentpages.dynamicbackgrounds.backgrounds.backgrounds[1].stage = `season${memory.season}`; + + if (memory.season == 10) { + contentpages.dynamicbackgrounds.backgrounds.backgrounds[0].stage = "seasonx"; + contentpages.dynamicbackgrounds.backgrounds.backgrounds[1].stage = "seasonx"; + } + + if (memory.build == 11.31 || memory.build == 11.40) { + contentpages.dynamicbackgrounds.backgrounds.backgrounds[0].stage = "Winter19"; + contentpages.dynamicbackgrounds.backgrounds.backgrounds[1].stage = "Winter19"; + } + + if (memory.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; +} + +module.exports = { + GetVersionInfo, + getItemShop, + getTheater, + getContentPages, + MakeID +} \ No newline at end of file diff --git a/structure/lightswitch.js b/structure/lightswitch.js new file mode 100644 index 0000000..1ebd3dc --- /dev/null +++ b/structure/lightswitch.js @@ -0,0 +1,47 @@ +const Express = require("express"); +const express = Express.Router(); + +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("/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" + } + }] + ) +}) + +module.exports = express; \ No newline at end of file diff --git a/structure/main.js b/structure/main.js new file mode 100644 index 0000000..997cbc5 --- /dev/null +++ b/structure/main.js @@ -0,0 +1,197 @@ +const Express = require("express"); +const express = Express.Router(); +const functions = require("./functions.js"); + +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'); + } else { + res.send('Failed, there are no items to remove') + } +}) + +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("/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/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("/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.get("/fortnite/api/game/v2/events/tournamentandhistory/*/EU/WindowsClient", 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("/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.get("/fortnite/api/stats/accountId/:accountId/bulk/window/alltime", 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("/fortnite/api/game/v2/twitch/*", async (req, res) => { + res.status(200); + res.end(); +}) + +express.get("/fortnite/api/game/v2/world/info", async (req, res) => { + const worldstw = functions.getTheater(req); + + res.json(worldstw) +}) + +express.post("/fortnite/api/game/v2/chat/*/recommendGeneralChatRooms/pc", 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/game/v2/leaderboards/cohort/*", async (req, res) => { + res.json([]) +}) + +express.post("/datarouter/api/v1/public/data", async (req, res) => { + res.status(204); + res.end(); +}) + +module.exports = express; \ No newline at end of file diff --git a/structure/matchmaking.js b/structure/matchmaking.js new file mode 100644 index 0000000..93beaac --- /dev/null +++ b/structure/matchmaking.js @@ -0,0 +1,90 @@ +const Express = require("express"); +const express = Express.Router(); +const fs = require("fs"); +const path = require("path"); +const iniparser = require("ini"); +const config = iniparser.parse(fs.readFileSync(path.join(__dirname, "..", "Config", "config.ini")).toString()); +const functions = require("./functions.js"); +const memory = require("./../memory.json"); + +express.get("/fortnite/api/matchmaking/session/findPlayer/*", async (req, res) => { + res.status(200); + res.end(); +}) + +express.get("/fortnite/api/game/v2/matchmakingservice/ticket/player/*", async (req, res) => { + 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": functions.MakeID().replace(/-/ig, "").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": functions.MakeID().replace(/-/ig, "").toUpperCase(), + "TENANT_s": "Fortnite", + "BEACONPORT_i": 15009 + }, + "publicPlayers": [], + "privatePlayers": [], + "totalPlayers": 45, + "allowJoinInProgress": false, + "shouldAdvertise": false, + "isDedicated": false, + "usesStats": false, + "allowInvites": false, + "usesPresence": false, + "allowJoinViaPresence": true, + "allowJoinViaPresenceFriendsOnly": false, + "buildUniqueId": 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([]) +}) + +module.exports = express; \ No newline at end of file diff --git a/structure/mcp.js b/structure/mcp.js new file mode 100644 index 0000000..ecc9653 --- /dev/null +++ b/structure/mcp.js @@ -0,0 +1,5339 @@ +const Express = require("express"); +const express = Express.Router(); +const fs = require("fs"); +const path = require("path"); +const iniparser = require("ini"); +const config = iniparser.parse(fs.readFileSync(path.join(__dirname, "..", "Config", "config.ini")).toString()); +const functions = require("./functions.js"); +const catalog = functions.getItemShop(); +const memory = require("./../memory.json"); + +// 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 = functions.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"); + functions.GetVersionInfo(req, memory); + + // 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" + memory.season; + + const ID = functions.MakeID(); + const GiftID = functions.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 = functions.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"))); + functions.GetVersionInfo(req, memory); + + // 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${memory.season}`)) { + SeasonQuestIDS = QuestIDS.BattleRoyale[`Season${memory.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${memory.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 = functions.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 = functions.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 = functions.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 = functions.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) => { + functions.GetVersionInfo(req, memory); + + const profile = require(`./../profiles/${req.query.profileId || "theater0"}.json`); + var schematic_profile; + // do not change this + var chosen_profile = false; + + if (4 <= memory.season || memory.build == 3.5 || memory.build == 3.6 && chosen_profile == false) { + schematic_profile = require("./../profiles/campaign.json"); + chosen_profile = true; + } + + if (3 >= memory.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 = functions.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) => { + functions.GetVersionInfo(req, memory); + + 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 (memory.season > 11 || memory.build == 11.30 || memory.build == 11.31 || memory.build == 11.40 || memory.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 = functions.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 = functions.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 = functions.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 = functions.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 = functions.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) { + functions.GetVersionInfo(req, memory); + + if (4 >= memory.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 = functions.MakeID(); + + campaign.items[ID] = Item + + MultiUpdate[0].profileChanges.push({ + "changeType": "itemAdded", + "itemId": ID, + "item": campaign.items[ID] + }) + } + + PurchasedLlama = true; + } + + if (memory.build >= 5 && memory.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 = functions.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 < memory.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 = functions.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 = functions.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") { + functions.GetVersionInfo(req, memory); + + profile.stats.attributes.season_num = memory.season; + + if (memory.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") { + functions.GetVersionInfo(req, memory); + + profile.stats.attributes.season_num = memory.season; + + if (memory.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") { + functions.GetVersionInfo(req, memory); + + profile.stats.attributes.season_num = memory.season; + + if (memory.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"); + functions.GetVersionInfo(req, memory); + + profile.stats.attributes.season_num = memory.season; + + if (memory.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"); + functions.GetVersionInfo(req, memory); + + profile.stats.attributes.season_num = memory.season; + + if (memory.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") { + functions.GetVersionInfo(req, memory); + + profile.stats.attributes.season_num = memory.season; + + if (memory.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") { + functions.GetVersionInfo(req, memory); + + profile.stats.attributes.season_num = memory.season; + + if (memory.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") { + functions.GetVersionInfo(req, memory); + + profile.stats.attributes.season_num = memory.season; + + if (memory.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(); +}); + +module.exports = express; \ No newline at end of file diff --git a/structure/privacy.js b/structure/privacy.js new file mode 100644 index 0000000..a3f53e4 --- /dev/null +++ b/structure/privacy.js @@ -0,0 +1,22 @@ +const Express = require("express"); +const express = Express.Router(); +const fs = require("fs"); +const privacy = require("./../responses/privacy.json"); + +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(); +}) + +module.exports = express; \ No newline at end of file diff --git a/structure/storefront.js b/structure/storefront.js new file mode 100644 index 0000000..572c306 --- /dev/null +++ b/structure/storefront.js @@ -0,0 +1,23 @@ +const Express = require("express"); +const express = Express.Router(); +const functions = require("./functions.js"); +const catalog = functions.getItemShop(); +const keychain = require("./../responses/keychain.json"); + +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("/fortnite/api/storefront/v2/keychain", async (req, res) => { + res.json(keychain) +}) + +express.get("/catalog/api/shared/bulk/offers", async (req, res) => { + res.json({}); +}) + +module.exports = express; \ No newline at end of file diff --git a/structure/timeline.js b/structure/timeline.js new file mode 100644 index 0000000..7813c3f --- /dev/null +++ b/structure/timeline.js @@ -0,0 +1,567 @@ +const Express = require("express"); +const express = Express.Router(); +const functions = require("./functions.js"); +const memory = require("./../memory.json"); + +express.get("/fortnite/api/calendar/v1/timeline", async (req, res) => { + functions.GetVersionInfo(req, memory); + + var activeEvents = [ + { + "eventType": `EventFlag.Season${memory.season}`, + "activeUntil": "9999-01-01T00:00:00.000Z", + "activeSince": "2020-01-01T00:00:00.000Z" + }, + { + "eventType": `EventFlag.${memory.lobby}`, + "activeUntil": "9999-01-01T00:00:00.000Z", + "activeSince": "2020-01-01T00:00:00.000Z" + }]; + + if (memory.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 (memory.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 (memory.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 (memory.build == 5.10) { + activeEvents.push( + { + "eventType": "EventFlag.BirthdayBattleBus", + "activeUntil": "9999-01-01T00:00:00.000Z", + "activeSince": "2020-01-01T00:00:00.000Z" + }) + } + + if (memory.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 (memory.build == 6.20 || memory.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 (memory.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 (memory.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 (memory.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 (memory.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 (memory.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(memory.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(memory.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 (memory.build == 11.31 || memory.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 (memory.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 (memory.season == 14) { + activeEvents.push( + { + "eventType": "EventFlag.LTE_Fortnitemares_2020", + "activeUntil": "9999-01-01T00:00:00.000Z", + "activeSince": "2020-01-01T00:00:00.000Z" + }) + } + + if (memory.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 (memory.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": memory.season, + "seasonTemplateId": `AthenaSeason:athenaseason${memory.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.end(); +}) + +module.exports = express; \ No newline at end of file diff --git a/structure/user.js b/structure/user.js new file mode 100644 index 0000000..56a2f0d --- /dev/null +++ b/structure/user.js @@ -0,0 +1,357 @@ +const Express = require("express"); +const express = Express.Router(); +const fs = require("fs"); +const path = require("path"); +const iniparser = require("ini"); +const config = iniparser.parse(fs.readFileSync(path.join(__dirname, "..", "Config", "config.ini")).toString()); +const functions = require("./functions.js"); +var Memory_CurrentAccountID = functions.MakeID().replace(/-/ig, ""); + +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("/account/api/public/account/*/externalAuths", async (req, res) => { + res.json([]) +}) + +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.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("/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" + }) +}) + +express.post("/account/api/oauth/exchange", 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.post("/fortnite/api/game/v2/tryPlayOnPlatform/account/*", async (req, res) => { + res.setHeader("Content-Type", "text/plain"); + res.send(true); +}) + +module.exports = express; \ No newline at end of file diff --git a/structure/version.js b/structure/version.js new file mode 100644 index 0000000..35e5126 --- /dev/null +++ b/structure/version.js @@ -0,0 +1,59 @@ +const Express = require("express"); +const express = Express.Router(); + +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("/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" + }) +}) + +module.exports = express; \ No newline at end of file