diff --git a/.gitignore b/.gitignore index 70556674..23c4cd81 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,7 @@ /.env /static/data/*.bin yarn.lock -/tmp \ No newline at end of file +/tmp + +# JetBrains/webstorm configs +.idea/ diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..9de22568 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +lts/iron diff --git a/package-lock.json b/package-lock.json index b3e60e77..de59907c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "dotenv": "^16.1.3", "express": "^5.0.0-beta.1", - "mongoose": "^7.4.1", + "mongoose": "^8.0.2", "warframe-items": "1.1260.121" }, "devDependencies": { @@ -214,6 +214,14 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz", + "integrity": "sha512-t7c5K033joZZMspnHg/gWPE4kandgc2OxE74aYOtGKfgB9VPuVJPix0H6fhmm2erj5PBJ21mqcx34lpIGtUCsQ==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -319,9 +327,9 @@ } }, "node_modules/@types/express": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.20.tgz", - "integrity": "sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, "dependencies": { "@types/body-parser": "*", @@ -419,9 +427,9 @@ "dev": true }, "node_modules/@types/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" }, "node_modules/@types/whatwg-url": { "version": "8.2.2", @@ -1140,11 +1148,11 @@ } }, "node_modules/bson": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.4.0.tgz", - "integrity": "sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.2.0.tgz", + "integrity": "sha512-ID1cI+7bazPDyL9wYy9GaQ8gEEohWvcUl/Yf0dIdutJxnmInEEyCsb4awy/OiBfall7zBA179Pahi3vCdFze3Q==", "engines": { - "node": ">=14.20.1" + "node": ">=16.20.1" } }, "node_modules/buffer-from": { @@ -2136,11 +2144,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -2397,8 +2400,7 @@ "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" }, "node_modules/merge-descriptors": { "version": "1.0.1", @@ -2506,26 +2508,25 @@ } }, "node_modules/mongodb": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.7.0.tgz", - "integrity": "sha512-zm82Bq33QbqtxDf58fLWBwTjARK3NSvKYjyz997KSy6hpat0prjeX/kxjbPVyZY60XYPDNETaHkHJI2UCzSLuw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.2.0.tgz", + "integrity": "sha512-d7OSuGjGWDZ5usZPqfvb36laQ9CPhnWkAGHT61x5P95p/8nMVeH8asloMwW6GcYFeB0Vj4CB/1wOTDG2RA9BFA==", "dependencies": { - "bson": "^5.4.0", - "mongodb-connection-string-url": "^2.6.0", - "socks": "^2.7.1" + "@mongodb-js/saslprep": "^1.1.0", + "bson": "^6.2.0", + "mongodb-connection-string-url": "^2.6.0" }, "engines": { - "node": ">=14.20.1" - }, - "optionalDependencies": { - "saslprep": "^1.0.3" + "node": ">=16.20.1" }, "peerDependencies": { - "@aws-sdk/credential-providers": "^3.201.0", + "@aws-sdk/credential-providers": "^3.188.0", "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=2.3.0 <3", - "snappy": "^7.2.2" + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" }, "peerDependenciesMeta": { "@aws-sdk/credential-providers": { @@ -2534,6 +2535,9 @@ "@mongodb-js/zstd": { "optional": true }, + "gcp-metadata": { + "optional": true + }, "kerberos": { "optional": true }, @@ -2542,6 +2546,9 @@ }, "snappy": { "optional": true + }, + "socks": { + "optional": true } } }, @@ -2555,20 +2562,20 @@ } }, "node_modules/mongoose": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.4.1.tgz", - "integrity": "sha512-o3E5KHHiHdaiwCJG3+9r70sncRKki71Ktf/TfXdW6myu+53rtZ56uLl5ylkQiCf60V3COJuOeekcxXVsjQ7cBA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.0.2.tgz", + "integrity": "sha512-Vsi9GzTXjdBVzheT1HZOZ2jHNzzR9Xwb5OyLz/FvDEAhlwrRnXnuqJf0QHINUOQSm7aoyvnPks0q85HJkd6yDw==", "dependencies": { - "bson": "^5.4.0", + "bson": "^6.2.0", "kareem": "2.5.1", - "mongodb": "5.7.0", + "mongodb": "6.2.0", "mpath": "0.9.0", "mquery": "5.0.0", "ms": "2.1.3", "sift": "16.0.1" }, "engines": { - "node": ">=14.20.1" + "node": ">=16.20.1" }, "funding": { "type": "opencollective", @@ -3223,18 +3230,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/saslprep": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", - "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, - "dependencies": { - "sparse-bitfield": "^3.0.3" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -3350,28 +3345,6 @@ "node": ">=8" } }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -3395,7 +3368,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "optional": true, "dependencies": { "memory-pager": "^1.0.2" } diff --git a/package.json b/package.json index 7c971d7a..7416d812 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "dependencies": { "dotenv": "^16.1.3", "express": "^5.0.0-beta.1", - "mongoose": "^7.4.1", + "mongoose": "^8.0.2", "warframe-items": "1.1260.121" }, "devDependencies": { diff --git a/src/controllers/api/focusController.ts b/src/controllers/api/focusController.ts new file mode 100644 index 00000000..f5d945fc --- /dev/null +++ b/src/controllers/api/focusController.ts @@ -0,0 +1,6 @@ +import { Handler } from "express"; + +export const focusController: Handler = (_req, _res) => { + //console.log("focusController", req.query); + _res.sendStatus(400); +}; diff --git a/src/controllers/api/genericUpdateController.ts b/src/controllers/api/genericUpdateController.ts index 63453c94..f77e366f 100644 --- a/src/controllers/api/genericUpdateController.ts +++ b/src/controllers/api/genericUpdateController.ts @@ -3,26 +3,24 @@ import { IGenericUpdate } from "@/src/types/genericUpdate"; import { RequestHandler } from "express"; // TODO: Nightwave evidence submission support is the only thing missing. -// TODO: Also, you might want to test this, because I definitely didn't. -const genericUpdateController: RequestHandler = async (request, response) => { - const accountId = request.query.accountId as string; +// TODO: this was added by someone without testing. It may not work. +// eslint-disable-next-line @typescript-eslint/no-misused-promises +const genericUpdateController: RequestHandler = async (_request, response) => { + // const accountId = request.query.accountId as string; - const [body] = String(request.body).split("\n"); + // const [body] = String(request.body).split("\n"); - let reply = {}; - try { - const update = JSON.parse(body) as IGenericUpdate; - if (typeof update !== "object") { - throw new Error("Invalid data format"); - } + // let reply = {}; + // try { + // const update = JSON.parse(body) as IGenericUpdate; + // if (typeof update !== "object") { + // throw new Error("Invalid data format"); + // } - reply = await updateGeneric(update, accountId); - } catch (err) { - console.error("Error parsing JSON data:", err); - } - - // Response support added for when Nightwave is supported below. - // response.json(reply); + // reply = await updateGeneric(update, accountId); + // } catch (err) { + // console.error("Error parsing JSON data:", err); + // } response.json({}); }; diff --git a/src/controllers/api/getShipController.ts b/src/controllers/api/getShipController.ts index 7439acf1..b0501365 100644 --- a/src/controllers/api/getShipController.ts +++ b/src/controllers/api/getShipController.ts @@ -1,14 +1,89 @@ import { Ship } from "@/src/models/shipModel"; +import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes"; import { RequestHandler } from "express"; // eslint-disable-next-line @typescript-eslint/no-misused-promises const getShipController: RequestHandler = async (req, res) => { const accountId = req.query.accountId; - const ship = await Ship.findOne({ ShipOwnerId: accountId }); + const ship = await Ship.findOne({ ShipOwnerId: accountId }).populate<{ + LoadOutInventory: { LoadOutPresets: ILoadoutDatabase }; + }>("LoadOutInventory.LoadOutPresets"); + if (!ship) { res.status(500).json({ error: "error finding a corresponding ship" }); return; } + + ship.Ship.Features = [ + "/Lotus/Types/Items/ShipFeatureItems/AdvancedOrdisFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/AlchemyRoomFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/AlertsFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/ArsenalFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/CeresNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/ClanFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/EarthNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/EidolonArchwingFoundryUpgradeFeatureBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/EidolonArchwingFoundryUpgradeFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/ErisNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/EuropaNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/FoundryConcurrentBuildFormaFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/FoundryFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/FoundryVesselUpgradeFeatureBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/FoundryVesselUpgradeFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/GeneticFoundryCatbrowUpgradeFeatureBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/GeneticFoundryCatbrowUpgradeFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/GeneticFoundryFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/GeneticFoundryUpgradeFeatureBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/GeneticFoundryUpgradeFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/InfestedFoundryArchonShardBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/InfestedFoundryArchonShardFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/InfestedFoundryBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/InfestedFoundryItem", + "/Lotus/Types/Items/ShipFeatureItems/InfestedFoundryUpgradeBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/InfestedFoundryUpgradeFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/JupiterNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/MarketTierOneFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/MarketTierTwoFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/MarsNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/MercuryNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/ModsFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/ModsFusionFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/ModsTransmuteFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/NeptuneNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/PersonalQuartersFeatureBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/PersonalQuartersFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/PhobosNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/PlutoNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/DamagedRailjackHoodBraceFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/DamagedRailjackHoodFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/DamagedRailjackHullFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/DamagedRailjackNacelleLeftFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/DamagedRailjackNacelleRightFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/DamagedRailjackTailFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/RailjackHoodBraceFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/RailjackHoodBraceFeatureItemBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/RailjackHoodFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/RailjackHoodFeatureItemBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/RailjackHullFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/RailjackHullFeatureItemBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/RailjackNacelleLeftFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/RailjackNacelleLeftFeatureItemBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/RailjackNacelleRightFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/RailjackNacelleRightFeatureItemBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/RailjackTailFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/Railjack/RailjackTailFeatureItemBlueprint", + "/Lotus/Types/Items/ShipFeatureItems/RailjackCephalonShipFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/RailjackKeyShipFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/SaturnNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/SednaNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/ShipFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/SocialMenuFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/SolarChartFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/UranusNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/VenusNavigationFeatureItem", + "/Lotus/Types/Items/ShipFeatureItems/VoidProjectionFeatureItem" + ]; + res.json(ship); }; diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index 078532dc..c12387a9 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -1,10 +1,11 @@ /* eslint-disable @typescript-eslint/no-misused-promises */ import { toInventoryResponse } from "@/src/helpers/inventoryHelpers"; -import { Inventory } from "@/src/models/inventoryModel"; +import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; import { Request, RequestHandler, Response } from "express"; import config from "@/config.json"; import testMissions from "@/static/fixed_responses/testMissions.json"; import testQuestKeys from "@/static/fixed_responses/testQuestKeys.json"; +import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes"; const inventoryController: RequestHandler = async (request: Request, response: Response) => { const accountId = request.query.accountId; @@ -14,7 +15,9 @@ const inventoryController: RequestHandler = async (request: Request, response: R return; } - const inventory = await Inventory.findOne({ accountOwnerId: accountId }); + const inventory = await Inventory.findOne({ accountOwnerId: accountId }).populate<{ + LoadOutPresets: ILoadoutDatabase; + }>("LoadOutPresets"); if (!inventory) { response.status(400).json({ error: "inventory was undefined" }); diff --git a/src/controllers/api/loginController.ts b/src/controllers/api/loginController.ts index e48e6df0..e488f080 100644 --- a/src/controllers/api/loginController.ts +++ b/src/controllers/api/loginController.ts @@ -50,7 +50,7 @@ const loginController: RequestHandler = async (request, response) => { return; } catch (error: unknown) { if (error instanceof Error) { - throw new Error("error creating account"); + throw new Error("error creating account", error); } } } diff --git a/src/controllers/api/saveLoadout.ts b/src/controllers/api/saveLoadout.ts index b83ad6b1..31431798 100644 --- a/src/controllers/api/saveLoadout.ts +++ b/src/controllers/api/saveLoadout.ts @@ -1,13 +1,27 @@ -import { Inventory } from "@/src/models/inventoryModel"; import { RequestHandler } from "express"; import util from "util"; +import { ISaveLoadoutRequest } from "@/src/types/saveLoadoutTypes"; +import { handleInventoryItemConfigChange } from "@/src/services/saveLoadoutService"; +import { parseString } from "@/src/helpers/general"; // eslint-disable-next-line @typescript-eslint/no-misused-promises const saveLoadoutController: RequestHandler = async (req, res) => { - const body = JSON.parse(req.body); - console.log(util.inspect(body, { showHidden: false, depth: null, colors: true })); + //validate here + const accountId = parseString(req.query.accountId); - res.sendStatus(200); + try { + const body: ISaveLoadoutRequest = JSON.parse(req.body as string) as ISaveLoadoutRequest; + // console.log(util.inspect(body, { showHidden: false, depth: null, colors: true })); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { UpgradeVer, ...equipmentChanges } = body; + await handleInventoryItemConfigChange(equipmentChanges, accountId); + res.status(200).end(); + } catch (error: unknown) { + if (error instanceof Error) { + res.status(400).json({ error: error.message }); + } + } }; export { saveLoadoutController }; diff --git a/src/controllers/api/setBootLocationController.ts b/src/controllers/api/setBootLocationController.ts new file mode 100644 index 00000000..a2e745bc --- /dev/null +++ b/src/controllers/api/setBootLocationController.ts @@ -0,0 +1,6 @@ +import { Request, Response } from "express"; + +export const setBootLocationController = (req: Request, res: Response) => { + console.log("setBootLocationController", req.query); + res.end(); +}; diff --git a/src/controllers/api/trainingResultController.ts b/src/controllers/api/trainingResultController.ts index 9feffe38..db2965bf 100644 --- a/src/controllers/api/trainingResultController.ts +++ b/src/controllers/api/trainingResultController.ts @@ -1,6 +1,6 @@ import { parseString } from "@/src/helpers/general"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; -import { Inventory } from "@/src/models/inventoryModel"; +import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; import { getInventory } from "@/src/services/inventoryService"; import { IMongoDate } from "@/src/types/commonTypes"; import { RequestHandler } from "express"; diff --git a/src/controllers/api/viewController.ts b/src/controllers/api/viewController.ts deleted file mode 100644 index e63d3b1a..00000000 --- a/src/controllers/api/viewController.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { RequestHandler } from "express"; -import view from "@/static/fixed_responses/view.json"; - -const viewController: RequestHandler = (_req, res) => { - res.json(view); -}; - -export { viewController }; diff --git a/src/controllers/stats/viewController.ts b/src/controllers/stats/viewController.ts index 4e988ccc..e63d3b1a 100644 --- a/src/controllers/stats/viewController.ts +++ b/src/controllers/stats/viewController.ts @@ -1,7 +1,8 @@ import { RequestHandler } from "express"; +import view from "@/static/fixed_responses/view.json"; const viewController: RequestHandler = (_req, res) => { - res.json({}); + res.json(view); }; export { viewController }; diff --git a/src/helpers/general.ts b/src/helpers/general.ts index 8aa19a1a..cc13e4ec 100644 --- a/src/helpers/general.ts +++ b/src/helpers/general.ts @@ -55,4 +55,12 @@ const parseBoolean = (booleanCandidate: unknown): boolean => { return booleanCandidate; }; +export const isObject = (objectCandidate: unknown): objectCandidate is Record => { + return ( + (typeof objectCandidate === "object" || objectCandidate instanceof Object) && + objectCandidate !== null && + !Array.isArray(objectCandidate) + ); +}; + export { isString, isNumber, parseString, parseNumber, parseDateNumber, parseBoolean, parseEmail }; diff --git a/src/helpers/inventoryHelpers.ts b/src/helpers/inventoryHelpers.ts index 45b6ff14..92c1726f 100644 --- a/src/helpers/inventoryHelpers.ts +++ b/src/helpers/inventoryHelpers.ts @@ -1,10 +1,14 @@ +import { IOid } from "@/src/types/commonTypes"; import { IInventoryDatabase, IInventoryResponse } from "@/src/types/inventoryTypes/inventoryTypes"; +import { Types } from "mongoose"; -// a schema's toJSON is responsible for changing Oid and Date to their corresponding Response versions __id to "ItemId":{"$oid":"6450f720bc562ebf030222d4"}, and a Date to "date":{"$date":{"$numberLong":"unix timestamp"}) -const toInventoryResponse = (inventoryDatabase: IInventoryDatabase): IInventoryResponse => { +//TODO: this needs to be addressed: a schema's toJSON is responsible for changing Oid and Date to their corresponding Response versions __id to "ItemId":{"$oid":"6450f720bc562ebf030222d4"}, and a Date to "date":{"$date":{"$numberLong":"unix timestamp"}) +export const toInventoryResponse = (inventoryDatabase: IInventoryDatabase): IInventoryResponse => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { accountOwnerId, ...inventoryResponse } = inventoryDatabase; return inventoryResponse as unknown as IInventoryResponse; }; -export { toInventoryResponse }; +export const toOid = (objectId: Types.ObjectId) => { + return { $oid: objectId.toString() } satisfies IOid; +}; diff --git a/src/models/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts similarity index 53% rename from src/models/inventoryModel.ts rename to src/models/inventoryModels/inventoryModel.ts index 5c753b86..deb3d10f 100644 --- a/src/models/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -7,182 +7,229 @@ import { IBooster, IInventoryResponse, IInventoryDatabaseDocument, - IInventoryResponseDocument -} from "../types/inventoryTypes/inventoryTypes"; -import { IMongoDate, IOid } from "../types/commonTypes"; -import { ISuitDatabase, ISuitDocument } from "@/src/types/inventoryTypes/SuitTypes"; + ISlots, + IGenericItem, + IMailbox, + IDuviriInfo +} from "../../types/inventoryTypes/inventoryTypes"; +import { IMongoDate, IOid } from "../../types/commonTypes"; +import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes"; import { IWeaponDatabase } from "@/src/types/inventoryTypes/weaponTypes"; +import { + IAbilityOverride, + IColor, + IItemConfig, + IOperatorConfigClient, + IOperatorConfigDatabase, + IPolarity +} from "@/src/types/inventoryTypes/commonInventoryTypes"; +import { toOid } from "@/src/helpers/inventoryHelpers"; -const abilityOverrideSchema = new Schema({ +const polaritySchema = new Schema({ + Slot: Number, + Value: String +}); + +const abilityOverrideSchema = new Schema({ Ability: String, Index: Number }); -const colorSchema = new Schema({ - t0: Number, - t1: Number, - t2: Number, - t3: Number, - en: Number, - e1: Number, - m0: Number, - m1: Number +const colorSchema = new Schema( + { + t0: Number, + t1: Number, + t2: Number, + t3: Number, + en: Number, + e1: Number, + m0: Number, + m1: Number + }, + { _id: false } +); + +const operatorConfigSchema = new Schema( + { + Skins: [String], + pricol: colorSchema, + attcol: colorSchema, + sigcol: colorSchema, + eyecol: colorSchema, + facial: colorSchema, + syancol: colorSchema, + cloth: colorSchema, + Upgrades: [String], + Name: String, // not sure if possible in operator + ugly: Boolean // not sure if possible in operator + }, + { id: false } +); + +operatorConfigSchema.virtual("ItemId").get(function () { + return { $oid: this._id.toString() } satisfies IOid; }); -const weaponConfigSchema = new Schema({ - Skins: [String], - pricol: colorSchema, - attcol: colorSchema, - eyecol: colorSchema, - sigcol: colorSchema, - Upgrades: [String], - Songs: [ - { - m: String, - b: String, - p: String, - s: String - } - ], - Name: String, - AbilityOverride: abilityOverrideSchema, - PvpUpgrades: [String], - ugly: Boolean -}); - -// longGunConfigSchema.set("toJSON", { -// transform(_document, returnedObject: ISuitDocument) { -// // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call -// returnedObject.ItemId = { $oid: returnedObject._id.toString() } satisfies Oid; -// delete returnedObject._id; -// delete returnedObject.__v; -// } -// }); - -const WeaponSchema = new Schema({ - ItemType: String, - Configs: [weaponConfigSchema], - UpgradeVer: Number, - XP: Number, - Features: Number, - Polarized: Number, - Polarity: Schema.Types.Mixed, //todo - FocusLens: String, - ModSlotPurchases: Number, - UpgradeType: Schema.Types.Mixed, //todo - UpgradeFingerprint: String, - ItemName: String, - ModularParts: [String], - UnlockLevel: Number -}); - -const BoosterSchema = new Schema({ - ExpiryDate: Number, - ItemType: String -}); - -const RawUpgrades = new Schema({ - ItemType: String, - ItemCount: Number -}); - -RawUpgrades.set("toJSON", { +operatorConfigSchema.set("toJSON", { + virtuals: true, transform(_document, returnedObject) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call - returnedObject.LastAdded = { $oid: returnedObject._id.toString() } satisfies IOid; delete returnedObject._id; delete returnedObject.__v; } }); +///TODO: clearly seperate the different config schemas. (suit and weapon and so on) +const ItemConfigSchema = new Schema( + { + Skins: [String], + pricol: colorSchema, + attcol: colorSchema, + sigcol: colorSchema, + eyecol: colorSchema, + facial: colorSchema, + syancol: colorSchema, + Upgrades: [String], + Songs: [ + { + m: String, + b: String, + p: String, + s: String + } + ], + Name: String, + AbilityOverride: abilityOverrideSchema, + PvpUpgrades: [String], + ugly: Boolean + }, + { _id: false } +); + +ItemConfigSchema.set("toJSON", { + transform(_document, returnedObject) { + delete returnedObject.__v; + } +}); + +//TODO: migrate to one schema for weapons and suits.. and possibly others +const WeaponSchema = new Schema( + { + ItemType: String, + Configs: [ItemConfigSchema], + UpgradeVer: Number, + XP: Number, + Features: Number, + Polarized: Number, + Polarity: [polaritySchema], + FocusLens: String, + ModSlotPurchases: Number, + UpgradeType: Schema.Types.Mixed, //todo + UpgradeFingerprint: String, + ItemName: String, + ModularParts: [String], + UnlockLevel: Number + }, + { id: false } +); + +WeaponSchema.virtual("ItemId").get(function () { + return { $oid: this._id.toString() } satisfies IOid; +}); + +WeaponSchema.set("toJSON", { + virtuals: true, + transform(_document, returnedObject) { + delete returnedObject._id; + delete returnedObject.__v; + } +}); + +const BoosterSchema = new Schema({ + ExpiryDate: Number, + ItemType: String +}); + +const RawUpgrades = new Schema( + { + ItemType: String, + ItemCount: Number + }, + { id: false } +); + +RawUpgrades.virtual("LastAdded").get(function () { + return { $oid: this._id.toString() } satisfies IOid; +}); + +RawUpgrades.set("toJSON", { + virtuals: true, + transform(_document, returnedObject) { + delete returnedObject._id; + delete returnedObject.__v; + } +}); + +//TODO: find out what this is const Upgrade = new Schema({ UpgradeFingerprint: String, ItemType: String }); +Upgrade.virtual("ItemId").get(function () { + return { $oid: this._id.toString() } satisfies IOid; +}); + Upgrade.set("toJSON", { - transform(_document, returnedObject) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call - returnedObject.ItemId = { $oid: returnedObject._id.toString() } satisfies IOid; - delete returnedObject._id; - delete returnedObject.__v; - } -}); - -WeaponSchema.set("toJSON", { - transform(_document, returnedObject) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call - returnedObject.ItemId = { $oid: returnedObject._id.toString() } satisfies IOid; - delete returnedObject._id; - delete returnedObject.__v; - } -}); - -const polaritySchema = new Schema({ - Slot: Number, - Value: String -}); - -const suitConfigSchema = new Schema({ - Skins: [String], - pricol: colorSchema, - attcol: colorSchema, - eyecol: colorSchema, - sigcol: colorSchema, - Upgrades: [String], - Songs: [ - { - m: String, - b: String, - p: String, - s: String - } - ], - Name: String, - AbilityOverride: abilityOverrideSchema, - PvpUpgrades: [String], - ugly: Boolean -}); - -suitConfigSchema.set("toJSON", { + virtuals: true, transform(_document, returnedObject) { delete returnedObject._id; delete returnedObject.__v; } }); -const suitSchema = new Schema({ - ItemType: String, - Configs: [suitConfigSchema], - UpgradeVer: Number, - XP: Number, - InfestationDate: Date, - Features: Number, - Polarity: [polaritySchema], - Polarized: Number, - ModSlotPurchases: Number, - FocusLens: String, - UnlockLevel: Number +//TODO: reduce weapon and suit schemas to one schema if reasonable +const suitSchema = new Schema( + { + ItemType: String, + Configs: [ItemConfigSchema], + UpgradeVer: Number, + XP: Number, + InfestationDate: Date, + Features: Number, + Polarity: [polaritySchema], + Polarized: Number, + ModSlotPurchases: Number, + FocusLens: String, + UnlockLevel: Number + }, + { id: false } +); + +suitSchema.virtual("ItemId").get(function () { + return { $oid: this._id.toString() } satisfies IOid; }); suitSchema.set("toJSON", { + virtuals: true, transform(_document, returnedObject) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call - returnedObject.ItemId = { $oid: returnedObject._id.toString() } satisfies IOid; delete returnedObject._id; delete returnedObject.__v; } }); -const slotsBinSchema = new Schema( +const slotsBinSchema = new Schema( { - Slots: Number + Slots: Number, + Extra: Number }, { _id: false } ); -const FlavourItemSchema = new Schema({ - ItemType: String -}); +const FlavourItemSchema = new Schema( + { + ItemType: String + }, + { _id: false } +); FlavourItemSchema.set("toJSON", { transform(_document, returnedObject) { @@ -191,7 +238,70 @@ FlavourItemSchema.set("toJSON", { } }); -const inventorySchema = new Schema({ +const GenericItemSchema = new Schema( + { + ItemType: String, + Configs: [ItemConfigSchema], + UpgradeVer: Number //this is probably just __v + }, + { id: false } +); + +GenericItemSchema.virtual("ItemId").get(function () { + return { $oid: this._id.toString() } satisfies IOid; +}); + +GenericItemSchema.set("toJSON", { + virtuals: true, + transform(_document, returnedObject) { + delete returnedObject._id; + delete returnedObject.__v; + } +}); + +// "Mailbox": { "LastInboxId": { "$oid": "123456780000000000000000" } } +const MailboxSchema = new Schema( + { + LastInboxId: { + type: Schema.Types.ObjectId, + set: (v: IMailbox["LastInboxId"]) => v.$oid.toString() + } + }, + { id: false, _id: false } +); + +MailboxSchema.set("toJSON", { + transform(_document, returnedObject) { + delete returnedObject.__v; + //TODO: there is a lot of any here + returnedObject.LastInboxId = toOid(returnedObject.LastInboxId as Types.ObjectId); + } +}); + +const DuviriInfoSchema = new Schema( + { + Seed: Number, + NumCompletions: Number + }, + { + _id: false, + id: false + } +); + +DuviriInfoSchema.set("toJSON", { + transform(_document, returnedObject) { + delete returnedObject.__v; + } +}); + +const inventorySchema = new Schema({ + Horses: [GenericItemSchema], + DrifterMelee: [GenericItemSchema], + DrifterGuns: [GenericItemSchema], + DuviriInfo: DuviriInfoSchema, + Mailbox: MailboxSchema, + KahlLoadOuts: [Schema.Types.Mixed], accountOwnerId: Schema.Types.ObjectId, SubscribedToEmails: Number, Created: Schema.Types.Mixed, @@ -203,11 +313,15 @@ const inventorySchema = new Schema; MiscItems: Types.DocumentArray; Boosters: Types.DocumentArray; + OperatorLoadOuts: Types.DocumentArray; + AdultOperatorLoadOuts: Types.DocumentArray; + MechSuits: Types.DocumentArray; + Scoops: Types.DocumentArray; + DataKnives: Types.DocumentArray; + DrifterMelee: Types.DocumentArray; + Sentinels: Types.DocumentArray; + Horses: Types.DocumentArray; }; -type InventoryModelType = Model; +type InventoryModelType = Model; const Inventory = model("Inventory", inventorySchema); diff --git a/src/models/inventoryModels/loadoutModel.ts b/src/models/inventoryModels/loadoutModel.ts new file mode 100644 index 00000000..37a8d104 --- /dev/null +++ b/src/models/inventoryModels/loadoutModel.ts @@ -0,0 +1,96 @@ +import { IOid } from "@/src/types/commonTypes"; +import { ILoadoutConfigDatabase, ILoadoutDatabase, IEquipmentSelection } from "@/src/types/saveLoadoutTypes"; +import { Model, Schema, Types, model } from "mongoose"; + +const oidSchema = new Schema( + { + $oid: String + }, + { + _id: false + } +); + +//create a mongoose schema based on interface M +const EquipmentSelectionSchema = new Schema( + { + ItemId: { + type: oidSchema, + default: { $oid: "000000000000000000000000" } + }, + mod: Number, + cus: Number + }, + { + _id: false + } +); + +const loadoutConfigSchema = new Schema( + { + PresetIcon: String, + Favorite: Boolean, + n: String, + s: EquipmentSelectionSchema, + p: EquipmentSelectionSchema, + l: EquipmentSelectionSchema, + m: EquipmentSelectionSchema + }, + { + id: false + } +); + +loadoutConfigSchema.virtual("ItemId").get(function () { + return { $oid: this._id.toString() } satisfies IOid; +}); + +loadoutConfigSchema.set("toJSON", { + virtuals: true, + transform(_doc, ret, _options) { + delete ret._id; + delete ret.__v; + } +}); + +export const loadoutSchema = new Schema({ + NORMAL: [loadoutConfigSchema], + SENTINEL: [loadoutConfigSchema], + ARCHWING: [loadoutConfigSchema], + NORMAL_PVP: [loadoutConfigSchema], + LUNARO: [loadoutConfigSchema], + OPERATOR: [loadoutConfigSchema], + KDRIVE: [loadoutConfigSchema], + DATAKNIFE: [loadoutConfigSchema], + MECH: [loadoutConfigSchema], + OPERATOR_ADULT: [loadoutConfigSchema], + DRIFTER: [loadoutConfigSchema], + loadoutOwnerId: Schema.Types.ObjectId +}); + +loadoutSchema.set("toJSON", { + transform(_doc, ret, _options) { + delete ret._id; + delete ret.__v; + delete ret.loadoutOwnerId; + } +}); + +//create database typefor ILoadoutConfig +type loadoutDocumentProps = { + NORMAL: Types.DocumentArray; + SENTINEL: Types.DocumentArray; + ARCHWING: Types.DocumentArray; + NORMAL_PVP: Types.DocumentArray; + LUNARO: Types.DocumentArray; + OPERATOR: Types.DocumentArray; + KDRIVE: Types.DocumentArray; + DATAKNIFE: Types.DocumentArray; + MECH: Types.DocumentArray; + OPERATOR_ADULT: Types.DocumentArray; + DRIFTER: Types.DocumentArray; +}; + +type loadoutModelType = Model; + +export const LoadoutModel = model("Loadout", loadoutSchema); diff --git a/src/models/shipModel.ts b/src/models/shipModel.ts index bd56d933..4b16ebd2 100644 --- a/src/models/shipModel.ts +++ b/src/models/shipModel.ts @@ -1,6 +1,7 @@ import { Schema, model } from "mongoose"; import { IShip } from "../types/shipTypes"; import { IOid } from "../types/commonTypes"; +import { loadoutSchema } from "@/src/models/inventoryModels/loadoutModel"; const roomSchema = new Schema( { @@ -10,16 +11,22 @@ const roomSchema = new Schema( { _id: false } ); -const shipSchema = new Schema({ - Rooms: [roomSchema], - Features: [String], - ContentUrlSignature: String +const shipSchema = new Schema( + { + Rooms: [roomSchema], + Features: [String], + ContentUrlSignature: String + }, + { id: false } +); + +shipSchema.virtual("ShipId").get(function () { + return { $oid: this._id.toString() } satisfies IOid; }); shipSchema.set("toJSON", { + virtuals: true, transform(_document, returnedObject) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call - returnedObject.ShipId = { $oid: returnedObject._id.toString() } satisfies IOid; delete returnedObject._id; } }); @@ -35,10 +42,16 @@ apartmentSchema.set("toJSON", { } }); -const shipDatabaseSchema = new Schema({ +const shipDatabaseSchema = new Schema({ ShipOwnerId: Schema.Types.ObjectId, Ship: shipSchema, - Apartment: apartmentSchema + Apartment: apartmentSchema, + LoadOutInventory: { + LoadOutPresets: { + type: Schema.Types.ObjectId, + ref: "Loadout" + } + } }); shipDatabaseSchema.set("toJSON", { diff --git a/src/routes/api.ts b/src/routes/api.ts index de269c34..66f55d0f 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -26,13 +26,14 @@ import { setActiveQuestController } from "@/src/controllers/api/setActiveQuestCo import { surveysController } from "@/src/controllers/api/surveysController"; import { updateChallengeProgressController } from "@/src/controllers/api/updateChallengeProgressController"; import { updateSessionGetController, updateSessionPostController } from "@/src/controllers/api/updateSessionController"; -import { viewController } from "@/src/controllers/api/viewController"; import { joinSessionController } from "@/src/controllers/api/joinSessionController"; import { saveLoadoutController } from "@/src/controllers/api/saveLoadout"; import { trainingResultController } from "@/src/controllers/api/trainingResultController"; import { artifactsController } from "../controllers/api/artifactsController"; import express from "express"; +import { setBootLocationController } from "@/src/controllers/api/setBootLocationController"; +import { focusController } from "@/src/controllers/api/focusController"; const apiRouter = express.Router(); @@ -46,7 +47,6 @@ apiRouter.get("/loginRewards.php", loginRewardsController); apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController); apiRouter.get("/inbox.php", inboxController); apiRouter.get("/getShip.php", getShipController); -apiRouter.get("/view.php", viewController); apiRouter.get("/drones.php", dronesController); apiRouter.get("/getIgnoredUsers.php", getIgnoredUsersController); apiRouter.get("/getNewRewardSeed.php", getNewRewardSeedController); @@ -58,8 +58,10 @@ apiRouter.get("/hub", hubController); apiRouter.get("/modularWeaponSale.php", modularWeaponSaleController); apiRouter.get("/deleteSession.php", deleteSessionController); apiRouter.get("/logout.php", logoutController); +apiRouter.get("/setBootLocation.php", setBootLocationController); // post +apiRouter.post("/focus.php", focusController); apiRouter.post("/artifacts.php", artifactsController); apiRouter.post("/findSessions.php", findSessionsController); // eslint-disable-next-line @typescript-eslint/no-misused-promises diff --git a/src/routes/stats.ts b/src/routes/stats.ts index a0df739f..59290675 100644 --- a/src/routes/stats.ts +++ b/src/routes/stats.ts @@ -1,4 +1,4 @@ -import { viewController } from "../controllers/api/viewController"; +import { viewController } from "../controllers/stats/viewController"; import { uploadController } from "@/src/controllers/stats/uploadController"; import express from "express"; diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 035881bd..93d62603 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -1,10 +1,10 @@ -import { Inventory } from "@/src/models/inventoryModel"; +import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; import new_inventory from "@/static/fixed_responses/postTutorialInventory.json"; import config from "@/config.json"; import { Types } from "mongoose"; -import { ISuitDatabase, ISuitResponse } from "@/src/types/inventoryTypes/SuitTypes"; +import { ISuitDatabase, ISuitClient } from "@/src/types/inventoryTypes/SuitTypes"; import { SlotType } from "@/src/types/purchaseTypes"; -import { IWeaponDatabase, IWeaponResponse } from "@/src/types/inventoryTypes/weaponTypes"; +import { IWeaponDatabase, IWeaponClient } from "@/src/types/inventoryTypes/weaponTypes"; import { IChallengeProgress, IConsumable, @@ -17,9 +17,13 @@ import { import { IGenericUpdate } from "../types/genericUpdate"; import { IArtifactsRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes"; -const createInventory = async (accountOwnerId: Types.ObjectId) => { +export const createInventory = async (accountOwnerId: Types.ObjectId, loadOutPresetId: Types.ObjectId) => { try { - const inventory = new Inventory({ ...new_inventory, accountOwnerId: accountOwnerId }); + const inventory = new Inventory({ + ...new_inventory, + accountOwnerId: accountOwnerId, + LoadOutPresets: loadOutPresetId + }); if (config.skipStoryModeChoice) { inventory.StoryModeChoice = "WARFRAME"; } @@ -27,6 +31,7 @@ const createInventory = async (accountOwnerId: Types.ObjectId) => { inventory.PlayedParkourTutorial = true; inventory.ReceivedStartingGear = true; } + await inventory.save(); } catch (error) { if (error instanceof Error) { @@ -48,13 +53,28 @@ export const getInventory = async (accountOwnerId: string) => { return inventory; }; -const addPowerSuit = async (powersuitName: string, accountId: string): Promise => { +//TODO: genericMethod for all the add methods, they share a lot of logic +export const addSentinel = async (sentinelName: string, accountId: string) => { + const inventory = await getInventory(accountId); + const sentinelIndex = inventory.Sentinels.push({ ItemType: sentinelName, Configs: [], XP: 0 }); + const changedInventory = await inventory.save(); + return changedInventory.Sentinels[sentinelIndex - 1].toJSON(); +}; + +export const addPowerSuit = async (powersuitName: string, accountId: string): Promise => { const inventory = await getInventory(accountId); const suitIndex = inventory.Suits.push({ ItemType: powersuitName, Configs: [], UpgradeVer: 101, XP: 0 }); const changedInventory = await inventory.save(); return changedInventory.Suits[suitIndex - 1].toJSON(); }; +export const addMechSuit = async (mechsuitName: string, accountId: string) => { + const inventory = await getInventory(accountId); + const suitIndex = inventory.MechSuits.push({ ItemType: mechsuitName, Configs: [], UpgradeVer: 101, XP: 0 }); + const changedInventory = await inventory.save(); + return changedInventory.MechSuits[suitIndex - 1].toJSON(); +}; + export const updateSlots = async (slotType: SlotType, accountId: string, slots: number) => { const inventory = await getInventory(accountId); @@ -65,6 +85,9 @@ export const updateSlots = async (slotType: SlotType, accountId: string, slots: case SlotType.WEAPON: inventory.WeaponBin.Slots += slots; break; + case SlotType.MECHSUIT: + inventory.MechBin.Slots += slots; + break; default: throw new Error("invalid slot type"); } @@ -107,7 +130,7 @@ export const addWeapon = async ( weaponType: WeaponTypeInternal, weaponName: string, accountId: string -): Promise => { +): Promise => { const inventory = await getInventory(accountId); let weaponIndex; @@ -139,7 +162,7 @@ export const addCustomization = async (customizatonName: string, accountId: stri const addGearExpByCategory = ( inventory: IInventoryDatabaseDocument, - gearArray: ISuitDatabase[] | IWeaponDatabase[] | undefined, + gearArray: ISuitClient[] | IWeaponClient[] | undefined, categoryName: "Pistols" | "LongGuns" | "Melee" | "Suits" ) => { const category = inventory[categoryName]; @@ -242,7 +265,6 @@ const addMissionComplete = (inventory: IInventoryDatabaseDocument, { Tag, Comple }; const gearKeys = ["Suits", "Pistols", "LongGuns", "Melee"] as const; -type GearKeysType = (typeof gearKeys)[number]; export const missionInventoryUpdate = async (data: IMissionInventoryUpdateRequest, accountId: string) => { const { RawUpgrades, MiscItems, RegularCredits, ChallengeProgress, FusionPoints, Consumables, Recipes, Missions } = @@ -256,7 +278,7 @@ export const missionInventoryUpdate = async (data: IMissionInventoryUpdateReques inventory.FusionPoints += FusionPoints || 0; // Gear XP - gearKeys.forEach((key: GearKeysType) => addGearExpByCategory(inventory, data[key], key)); + gearKeys.forEach(key => addGearExpByCategory(inventory, data[key], key)); // other addMods(inventory, RawUpgrades); @@ -339,5 +361,3 @@ export const upgradeMod = async (artifactsData: IArtifactsRequest, accountId: st throw error; } }; - -export { createInventory, addPowerSuit }; diff --git a/src/services/loginService.ts b/src/services/loginService.ts index 9e7959f0..1753c85b 100644 --- a/src/services/loginService.ts +++ b/src/services/loginService.ts @@ -2,6 +2,8 @@ import { Account } from "@/src/models/loginModel"; import { createInventory } from "@/src/services/inventoryService"; import { IDatabaseAccount } from "@/src/types/loginTypes"; import { createShip } from "./shipService"; +import { Types } from "mongoose"; +import { LoadoutModel } from "@/src/models/inventoryModels/loadoutModel"; const isCorrectPassword = (requestPassword: string, databasePassword: string): boolean => { return requestPassword === databasePassword; @@ -11,8 +13,9 @@ const createAccount = async (accountData: IDatabaseAccount) => { const account = new Account(accountData); try { await account.save(); - await createInventory(account._id); - await createShip(account._id); + const loadoutId = await createLoadout(account._id); + await createInventory(account._id, loadoutId); + await createShip(account._id, loadoutId); return account.toJSON(); } catch (error) { if (error instanceof Error) { @@ -23,3 +26,9 @@ const createAccount = async (accountData: IDatabaseAccount) => { }; export { isCorrectPassword, createAccount }; + +export const createLoadout = async (accountId: Types.ObjectId) => { + const loadout = new LoadoutModel({ loadoutOwnerId: accountId }); + const savedLoadout = await loadout.save(); + return savedLoadout._id; +}; diff --git a/src/services/purchaseService.ts b/src/services/purchaseService.ts index 8b88cd86..b6d80c21 100644 --- a/src/services/purchaseService.ts +++ b/src/services/purchaseService.ts @@ -1,6 +1,14 @@ import { getWeaponType } from "@/src/helpers/purchaseHelpers"; import { getSubstringFromKeyword } from "@/src/helpers/stringHelpers"; -import { addBooster, addCustomization, addPowerSuit, addWeapon, updateSlots } from "@/src/services/inventoryService"; +import { + addBooster, + addCustomization, + addMechSuit, + addPowerSuit, + addSentinel, + addWeapon, + updateSlots +} from "@/src/services/inventoryService"; import { IPurchaseRequest, SlotType } from "@/src/types/purchaseTypes"; export const getStoreItemCategory = (storeItem: string) => { @@ -72,8 +80,25 @@ const handleWeaponsPurchase = async (weaponName: string, accountId: string) => { }; const handlePowersuitPurchase = async (powersuitName: string, accountId: string) => { + if (powersuitName.includes("EntratiMech")) { + const mechSuit = await addMechSuit(powersuitName, accountId); + await updateSlots(SlotType.MECHSUIT, accountId, -1); + console.log("mech suit", mechSuit); + + return { + InventoryChanges: { + MechBin: { + count: 1, + platinum: 0, + Slots: -1 + }, + MechSuits: [mechSuit] + } + }; + } + const suit = await addPowerSuit(powersuitName, accountId); - await updateSlots(SlotType.WEAPON, accountId, -1); + await updateSlots(SlotType.SUIT, accountId, -1); return { InventoryChanges: { @@ -95,13 +120,24 @@ const handleTypesPurchase = async (typesName: string, accountId: string) => { return await handleSuitCustomizationsPurchase(typesName, accountId); // case "Recipes": // break; - // case "Sentinels": - // break; + case "Sentinels": + return await handleSentinelPurchase(typesName, accountId); default: throw new Error(`unknown Types category: ${typeCategory} not implemented or new`); } }; +const handleSentinelPurchase = async (sentinelName: string, accountId: string) => { + const sentinel = await addSentinel(sentinelName, accountId); + + return { + InventoryChanges: { + SentinelBin: { count: 1, platinum: 0, Slots: -1 }, + Sentinels: [sentinel] + } + }; +}; + const handleSuitCustomizationsPurchase = async (customizationName: string, accountId: string) => { const customization = await addCustomization(customizationName, accountId); diff --git a/src/services/saveLoadoutService.ts b/src/services/saveLoadoutService.ts new file mode 100644 index 00000000..43006cc9 --- /dev/null +++ b/src/services/saveLoadoutService.ts @@ -0,0 +1,160 @@ +import { + IItemEntry, + ILoadoutClient, + ILoadoutEntry, + IOperatorConfigEntry, + ISaveLoadoutRequestNoUpgradeVer +} from "@/src/types/saveLoadoutTypes"; +import { LoadoutModel } from "@/src/models/inventoryModels/loadoutModel"; +import { getInventory } from "@/src/services/inventoryService"; +import { IOid } from "@/src/types/commonTypes"; + +export const isEmptyObject = (obj: unknown): boolean => { + return Boolean(obj && Object.keys(obj).length === 0 && obj.constructor === Object); +}; + +//TODO: setup default items on account creation or like originally in giveStartingItems.php + +//TODO: change update functions to only add and not save perhaps, functions that add and return inventory perhaps + +/* loadouts has loadoutconfigs +operatorloadouts has itemconfig, but no multiple config ids +itemconfig has multiple config ids +*/ +export const handleInventoryItemConfigChange = async ( + equipmentChanges: ISaveLoadoutRequestNoUpgradeVer, + accountId: string +) => { + const inventory = await getInventory(accountId); + + for (const [_equipmentName, _equipment] of Object.entries(equipmentChanges)) { + const equipment = _equipment as ISaveLoadoutRequestNoUpgradeVer[keyof ISaveLoadoutRequestNoUpgradeVer]; + const equipmentName = _equipmentName as keyof ISaveLoadoutRequestNoUpgradeVer; + + if (isEmptyObject(equipment)) { + continue; + } + // non-empty is a change in loadout(or suit...) + switch (equipmentName) { + case "OperatorLoadOuts": + case "AdultOperatorLoadOuts": { + const operatorConfig = equipment as IOperatorConfigEntry; + const operatorLoadout = inventory[equipmentName]; + //console.log("loadout received", equipmentName, operatorConfig); + // all non-empty entries are one loadout slot + for (const [loadoutId, loadoutConfig] of Object.entries(operatorConfig)) { + // console.log("loadoutId", loadoutId, "loadoutconfig", loadoutConfig); + const loadout = operatorLoadout.find(loadout => loadout._id?.toString() === loadoutId); + + // if no config with this id exists, create a new one + if (!loadout) { + const { ItemId, ...loadoutConfigItemIdRemoved } = loadoutConfig; + operatorLoadout.push({ + _id: ItemId.$oid, + ...loadoutConfigItemIdRemoved + }); + continue; + } + loadout.set(loadoutConfig); + } + break; + } + case "LoadOuts": { + //console.log("loadout received"); + const loadout = await LoadoutModel.findOne({ loadoutOwnerId: accountId }); + if (!loadout) { + throw new Error("loadout not found"); + } + + for (const [_loadoutSlot, _loadout] of Object.entries(equipment)) { + const loadoutSlot = _loadoutSlot as keyof ILoadoutClient; + const newLoadout = _loadout as ILoadoutEntry; + + // empty loadout slot like: "NORMAL": {} + if (isEmptyObject(newLoadout)) { + continue; + } + + // all non-empty entries are one loadout slot + for (const [loadoutId, loadoutConfig] of Object.entries(newLoadout)) { + const oldLoadoutConfig = loadout[loadoutSlot].find( + loadout => loadout._id.toString() === loadoutId + ); + + // if no config with this id exists, create a new one + if (!oldLoadoutConfig) { + const { ItemId, ...loadoutConfigItemIdRemoved } = loadoutConfig; + loadout[loadoutSlot].push({ + _id: ItemId.$oid, + ...loadoutConfigItemIdRemoved + }); + continue; + } + + const loadoutIndex = loadout[loadoutSlot].indexOf(oldLoadoutConfig); + if (loadoutIndex === undefined || loadoutIndex === -1) { + throw new Error("loadout index not found"); + } + + //perhaps .overwrite() is better + loadout[loadoutSlot][loadoutIndex].set(loadoutConfig); + } + } + await loadout.save(); + break; + } + case "LongGuns": + case "Pistols": + case "Suits": + case "Melee": + case "Scoops": + case "DataKnives": + case "DrifterMelee": + case "Sentinels": + case "Horses": { + //console.log("general Item config saved", equipmentName, equipment); + + const itemEntries = equipment as IItemEntry; + for (const [itemId, itemConfigEntries] of Object.entries(itemEntries)) { + const inventoryItem = inventory[equipmentName].find(item => item._id?.toString() === itemId); + + if (!inventoryItem) { + throw new Error(`inventory item ${equipmentName} not found with id ${itemId}`); + } + + //config ids are 0,1,2 can there be a 3? + for (const [configId, config] of Object.entries(itemConfigEntries)) { + inventoryItem.Configs[parseInt(configId)] = config; + } + } + break; + } + case "CurrentLoadOutIds": { + const loadoutIds = equipment as IOid[]; // TODO: Check for more than just an array of oids, I think i remember one instance + inventory.CurrentLoadOutIds = loadoutIds; + break; + } + case "EquippedGear": { + inventory.EquippedGear = equipment as string[]; + break; + } + default: { + console.log("category not implemented", equipmentName, equipment); + } + //case "OperatorAmps": + // case "SentinelWeapons": + // case "KubrowPets": + // case "SpaceSuits": + // case "SpaceGuns": + // case "SpaceMelee": + // case "SpecialItems": + // case "MoaPets": + // case "Hoverboards": + // case "MechSuits": + // case "CrewShipHarnesses": + // case "CrewShips": + //case "KahlLoadOuts": not sure yet how to handle kahl: it is not sent in inventory + } + } + await inventory.save(); +}; diff --git a/src/services/shipService.ts b/src/services/shipService.ts index bce95805..5b35cce3 100644 --- a/src/services/shipService.ts +++ b/src/services/shipService.ts @@ -2,9 +2,13 @@ import { Ship } from "@/src/models/shipModel"; import new_ship from "@/static/fixed_responses/ship.json"; import { Types } from "mongoose"; -const createShip = async (accountOwnerId: Types.ObjectId) => { +const createShip = async (accountOwnerId: Types.ObjectId, loadoutId: Types.ObjectId) => { try { - const ship = new Ship({ ...new_ship, ShipOwnerId: accountOwnerId }); + const ship = new Ship({ + ...new_ship, + ShipOwnerId: accountOwnerId, + LoadOutInventory: { LoadOutPresets: loadoutId } + }); await ship.save(); } catch (error) { if (error instanceof Error) { diff --git a/src/types/inventoryTypes/SuitTypes.ts b/src/types/inventoryTypes/SuitTypes.ts index 7e1f6825..f075587c 100644 --- a/src/types/inventoryTypes/SuitTypes.ts +++ b/src/types/inventoryTypes/SuitTypes.ts @@ -1,19 +1,15 @@ import { IOid } from "@/src/types/commonTypes"; -import { IAbilityOverride, IColor, IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes"; -import { Document, Types } from "mongoose"; +import { IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes"; +import { Types } from "mongoose"; +import { IItemConfig } from "./commonInventoryTypes"; -// export interface ISuitDocument extends ISuitResponse, Document {} -export interface ISuitDocument extends Document, ISuitResponse { - _id: Types.ObjectId; -} - -export interface ISuitResponse extends ISuitDatabase { +export interface ISuitClient extends ISuitDatabase { ItemId: IOid; } export interface ISuitDatabase { ItemType: string; - Configs: SuitConfig[]; + Configs: IItemConfig[]; UpgradeVer?: number; XP?: number; InfestationDate?: Date; @@ -24,26 +20,5 @@ export interface ISuitDatabase { FocusLens?: string; UnlockLevel?: number; _id: Types.ObjectId; - ItemId?: IOid; -} - -export interface SuitConfig { - Skins?: string[]; - pricol?: IColor; - attcol?: IColor; - eyecol?: IColor; - sigcol?: IColor; - Upgrades?: string[]; - Songs?: Song[]; - Name?: string; - AbilityOverride?: IAbilityOverride; - PvpUpgrades?: string[]; - ugly?: boolean; -} - -export interface Song { - m?: string; - b?: string; - p?: string; - s: string; + ItemId?: IOid; // only in response } diff --git a/src/types/inventoryTypes/commonInventoryTypes.ts b/src/types/inventoryTypes/commonInventoryTypes.ts index 0664407f..b86cb719 100644 --- a/src/types/inventoryTypes/commonInventoryTypes.ts +++ b/src/types/inventoryTypes/commonInventoryTypes.ts @@ -1,3 +1,6 @@ +import { IOid } from "@/src/types/commonTypes"; +import { Types } from "mongoose"; + export interface IPolarity { Slot: number; Value: FocusSchool; @@ -41,3 +44,44 @@ export interface Isigcol { t1: number; en: number; } + +interface IItemConfigBase { + Skins: string[]; + pricol?: IColor; + attcol?: IColor; + sigcol?: IColor; + eyecol?: IColor; + facial?: IColor; + syancol?: IColor; + cloth?: IColor; + Upgrades?: string[]; + Name?: string; + ugly?: boolean; +} + +//TODO: Proper names for the different config types, this should be something like +//IItemConfigPlayable +export interface IItemConfig extends IItemConfigBase { + Songs?: ISong[]; + AbilityOverride?: IAbilityOverride; + PvpUpgrades?: string[]; + ugly?: boolean; +} + +export interface ISong { + m?: string; + b?: string; + p?: string; + s: string; +} + +//TODO: Consider renaming it to loadout instead of config +export interface IOperatorConfigDatabase extends IItemConfigBase { + _id: Types.ObjectId; + AbilityOverride?: IAbilityOverride; // not present in adultOperator + OperatorAmp?: IOid; // not present in adultOperator +} + +export interface IOperatorConfigClient extends Omit { + ItemId: IOid; +} diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index 760b8659..2674599a 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -1,19 +1,53 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Document, Types } from "mongoose"; import { IOid, IMongoDate } from "../commonTypes"; -import { IAbilityOverride, IColor, FocusSchool, IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes"; +import { + IAbilityOverride, + IColor, + FocusSchool, + IPolarity, + IItemConfig, + IOperatorConfigClient +} from "@/src/types/inventoryTypes/commonInventoryTypes"; import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes"; import { IOperatorLoadOutSigcol, IWeaponDatabase } from "@/src/types/inventoryTypes/weaponTypes"; +//Document extends will be deleted soon. TODO: delete and migrate uses to ... export interface IInventoryDatabaseDocument extends IInventoryDatabase, Document {} -export interface IInventoryDatabase extends Omit { +export interface IInventoryDatabase extends Omit { accountOwnerId: Types.ObjectId; - TrainingDate: Date; + TrainingDate: Date; // TrainingDate changed from IMongoDate to Date + LoadOutPresets: Types.ObjectId; // LoadOutPresets changed from ILoadOutPresets to Types.ObjectId for population + Mailbox: Types.ObjectId; // Mailbox changed from IMailbox to Types.ObjectId } export interface IInventoryResponseDocument extends IInventoryResponse, Document {} +export interface IGenericItem { + ItemType: string; + XP?: number; + Configs: IItemConfig[]; + UpgradeVer: number; + ItemId: IOid; + Features?: number; //space suit has this +} + +export interface IDuviriInfo { + Seed: number; + NumCompletions: number; +} + +export interface IMailbox { + LastInboxId: IOid; +} + export interface IInventoryResponse { + Horses: IGenericItem[]; + DrifterMelee: IGenericItem[]; + DrifterGuns: IGenericItem[]; + DuviriInfo: IDuviriInfo; + Mailbox: IMailbox; + KahlLoadOuts: IGenericItem[]; SubscribedToEmails: number; Created: IMongoDate; RewardSeed: number; @@ -21,14 +55,18 @@ export interface IInventoryResponse { PremiumCredits: number; PremiumCreditsFree: number; FusionPoints: number; - SuitBin: ICrewShipSalvageBinClass; - WeaponBin: ICrewShipSalvageBinClass; - SentinelBin: ICrewShipSalvageBinClass; - SpaceSuitBin: ICrewShipSalvageBinClass; - SpaceWeaponBin: ICrewShipSalvageBinClass; - PvpBonusLoadoutBin: ICrewMemberBinClass; - PveBonusLoadoutBin: ICrewShipSalvageBinClass; - RandomModBin: ICrewShipSalvageBinClass; + SuitBin: ISlots; + WeaponBin: ISlots; + SentinelBin: ISlots; + SpaceSuitBin: ISlots; + SpaceWeaponBin: ISlots; + PvpBonusLoadoutBin: ISlots; + PveBonusLoadoutBin: ISlots; + RandomModBin: ISlots; + MechBin: ISlots; + CrewMemberBin: ISlots; + OperatorAmpBin: ISlots; + CrewShipSalvageBin: ISlots; TradesRemaining: number; DailyAffiliation: number; DailyAffiliationPvp: number; @@ -48,7 +86,7 @@ export interface IInventoryResponse { Ships: IShip[]; QuestKeys: IQuestKey[]; FlavourItems: IFlavourItem[]; - Scoops: IScoop[]; + Scoops: IGenericItem[]; TrainingRetriesLeft: number; LoadOutPresets: ILoadOutPresets; CurrentLoadOutIds: Array; @@ -82,14 +120,14 @@ export interface IInventoryResponse { Affiliations: IAffiliation[]; QualifyingInvasions: any[]; FactionScores: number[]; - SpaceSuits: ISpace[]; - SpaceMelee: ISpace[]; + SpaceSuits: IGenericItem[]; + SpaceMelee: IGenericItem[]; SpaceGuns: ISpaceGun[]; ArchwingEnabled: boolean; PendingSpectreLoadouts: any[]; SpectreLoadouts: ISpectreLoadout[]; - SentinelWeapons: ISentinelWeapon[]; - Sentinels: ISentinel[]; + SentinelWeapons: IWeaponDatabase[]; + Sentinels: IWeaponDatabase[]; EmailItems: IEmailItem[]; CompletedSyndicates: string[]; FocusXP: IFocusXP; @@ -102,7 +140,6 @@ export interface IInventoryResponse { ActiveAvatarImageType: string; KubrowPets: IKubrowPet[]; ShipDecorations: IConsumable[]; - OperatorAmpBin: ICrewShipSalvageBinClass; DailyAffiliationCetus: number; DailyAffiliationQuills: number; DiscoveredMarkers: IDiscoveredMarker[]; @@ -123,7 +160,7 @@ export interface IInventoryResponse { BountyScore: number; ChallengeInstanceStates: IChallengeInstanceState[]; LoginMilestoneRewards: string[]; - OperatorLoadOuts: IOperatorLoadOut[]; + OperatorLoadOuts: IOperatorConfigClient[]; DailyAffiliationVentkids: number; DailyAffiliationVox: number; RecentVendorPurchases: Array; @@ -134,13 +171,12 @@ export interface IInventoryResponse { MoaPets: IMoaPet[]; EquippedInstrument: string; InvasionChainProgress: IInvasionChainProgress[]; - DataKnives: IDataKnife[]; + DataKnives: IGenericItem[]; NemesisHistory: INemesisHistory[]; LastNemesisAllySpawnTime: IMongoDate; Settings: ISettings; PersonalTechProjects: IPersonalTechProject[]; CrewShips: ICrewShip[]; - CrewShipSalvageBin: ICrewShipSalvageBinClass; PlayerSkills: IPlayerSkills; CrewShipAmmo: IConsumable[]; CrewShipSalvagedWeaponSkins: ICrewShipSalvagedWeaponSkin[]; @@ -150,17 +186,15 @@ export interface IInventoryResponse { TradeBannedUntil: IMongoDate; PlayedParkourTutorial: boolean; SubscribedToEmailsPersonalized: number; - MechBin: ICrewMemberBinClass; DailyAffiliationEntrati: number; DailyAffiliationNecraloid: number; - MechSuits: IMechSuit[]; + MechSuits: ISuitDatabase[]; InfestedFoundry: IInfestedFoundry; BlessingCooldown: IMongoDate; - CrewMemberBin: ICrewMemberBinClass; CrewShipHarnesses: ICrewShipHarness[]; CrewShipRawSalvage: IConsumable[]; CrewMembers: ICrewMember[]; - AdultOperatorLoadOuts: IAdultOperatorLoadOut[]; + AdultOperatorLoadOuts: IOperatorConfigClient[]; LotusCustomization: ILotusCustomization; UseAdultOperatorLoadout: boolean; DailyAffiliationZariman: number; @@ -260,10 +294,6 @@ export interface IConsumable { ItemType: string; } -export interface ICrewMemberBinClass { - Slots: number; -} - export interface ICrewMember { ItemType: string; NemesisFingerprint: number; @@ -310,8 +340,8 @@ export interface ICrewShipHarnessConfig { Upgrades?: string[]; } -export interface ICrewShipSalvageBinClass { - Extra: number; +export interface ISlots { + Extra?: number; Slots: number; } @@ -403,22 +433,6 @@ export interface IPortGuns { PRIMARY_A: IL; } -export interface IDataKnife { - ItemType: string; - XP: number; - Configs: IDataKnifeConfig[]; - UpgradeVer: number; - ItemId: IOid; -} - -export interface IDataKnifeConfig { - Upgrades?: string[]; - pricol?: IColor; - Skins: string[]; - attcol?: IColor; - sigcol?: IColor; -} - export interface IDiscoveredMarker { tag: string; discoveryState: number[]; @@ -623,6 +637,7 @@ export interface ILibraryPersonalProgress { Completed: boolean; } +//this needs to be checked against ILoadoutDatabase export interface ILoadOutPresets { NORMAL: INormal[]; NORMAL_PVP: IArchwing[]; @@ -717,17 +732,6 @@ export interface ILotusCustomization { Persona: string; } -export interface IMechSuit { - ItemType: string; - Configs: IDataKnifeConfig[]; - Features: number; - UpgradeVer: number; - XP: number; - Polarity: IPolarity[]; - Polarized: number; - ItemId: IOid; -} - export interface IMission { Completes: number; Tier?: number; @@ -870,7 +874,7 @@ export enum GivingSlotOrderInfo { LotusUpgradesModsPistolDualStatElectEventPistolMod = "/Lotus/Upgrades/Mods/Pistol/DualStat/ElectEventPistolMod" } -export interface PeriodicMissionCompletion { +export interface IPeriodicMissionCompletion { date: IMongoDate; tag: string; count?: number; @@ -916,6 +920,7 @@ export interface IQuestKey { Progress?: IProgress[]; unlock?: boolean; Completed?: boolean; + CustomData?: string; ItemType: string; CompletionDate?: IMongoDate; } @@ -933,17 +938,6 @@ export interface IRawUpgrade { LastAdded?: IOid; } -export interface IScoop { - ItemType: string; - Configs: IScoopConfig[]; - UpgradeVer: number; - ItemId: IOid; -} - -export interface IScoopConfig { - pricol?: IColor; -} - export interface ISeasonChallengeHistory { challenge: string; id: string; @@ -953,40 +947,6 @@ export interface ISentientSpawnChanceBoosters { numOceanMissionsCompleted: number; } -export interface ISentinelWeapon { - ItemType: string; - Configs: ISentinelWeaponConfig[]; - UpgradeVer?: number; - XP?: number; - ItemId: IOid; - Features?: number; - Polarity?: IPolarity[]; - Polarized?: number; -} - -export interface ISentinelWeaponConfig { - Skins?: FluffySkin[]; - Upgrades?: string[]; -} - -export enum FluffySkin { - Empty = "", - LotusUpgradesSkinsHolsterCustomizationsGlaiveInPlace = "/Lotus/Upgrades/Skins/HolsterCustomizations/GlaiveInPlace", - LotusUpgradesSkinsHolsterCustomizationsPistolHipsR = "/Lotus/Upgrades/Skins/HolsterCustomizations/PistolHipsR", - LotusUpgradesSkinsHolsterCustomizationsRifleUpperBack = "/Lotus/Upgrades/Skins/HolsterCustomizations/RifleUpperBack" -} - -export interface ISentinel { - ItemType: string; - Configs: IKubrowPetConfig[]; - UpgradeVer: number; - XP: number; - Features?: number; - Polarity?: IPolarity[]; - Polarized?: number; - ItemId: IOid; -} - export interface ISettings { FriendInvRestriction: string; GiftMode: string; @@ -1022,15 +982,6 @@ export interface ISpaceGunConfig { Upgrades?: string[]; } -export interface ISpace { - ItemType: string; - Configs: IKubrowPetConfig[]; - XP: number; - UpgradeVer: number; - ItemId: IOid; - Features?: number; -} - export interface ISpecialItem { ItemType: string; Configs: ISpecialItemConfig[]; diff --git a/src/types/inventoryTypes/weaponTypes.ts b/src/types/inventoryTypes/weaponTypes.ts index 365c869b..7cc390f3 100644 --- a/src/types/inventoryTypes/weaponTypes.ts +++ b/src/types/inventoryTypes/weaponTypes.ts @@ -1,14 +1,15 @@ import { IOid } from "@/src/types/commonTypes"; -import { IColor, IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes"; +import { IItemConfig } from "./commonInventoryTypes"; +import { IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes"; import { Types } from "mongoose"; -export interface IWeaponResponse extends IWeaponDatabase { +export interface IWeaponClient extends Omit { ItemId: IOid; } export interface IWeaponDatabase { ItemType: string; - Configs: WeaponConfig[]; + Configs: IItemConfig[]; UpgradeVer?: number; XP?: number; Features?: number; @@ -21,18 +22,7 @@ export interface IWeaponDatabase { ItemName?: string; ModularParts?: string[]; UnlockLevel?: number; - _id?: Types.ObjectId; - ItemId?: IOid; -} - -export interface WeaponConfig { - Skins?: string[]; - pricol?: IColor; - Upgrades?: string[]; - attcol?: IColor; - eyecol?: IOperatorLoadOutSigcol; - Name?: string; - PvpUpgrades?: string[]; + _id: Types.ObjectId; } export interface IOperatorLoadOutSigcol { diff --git a/src/types/purchaseTypes.ts b/src/types/purchaseTypes.ts index 6df9719d..ce1e6270 100644 --- a/src/types/purchaseTypes.ts +++ b/src/types/purchaseTypes.ts @@ -1,6 +1,6 @@ import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes"; import { IFlavourItem } from "@/src/types/inventoryTypes/inventoryTypes"; -import { IWeaponResponse } from "@/src/types/inventoryTypes/weaponTypes"; +import { IWeaponClient } from "@/src/types/inventoryTypes/weaponTypes"; export interface IPurchaseRequest { PurchaseParams: IPurchaseParams; @@ -23,9 +23,9 @@ export interface IPurchaseResponse { SuitBin?: IBinChanges; WeaponBin?: IBinChanges; Suits?: ISuitDatabase[]; - LongGuns?: IWeaponResponse[]; - Pistols?: IWeaponResponse[]; - Melee?: IWeaponResponse[]; + LongGuns?: IWeaponClient[]; + Pistols?: IWeaponClient[]; + Melee?: IWeaponClient[]; PremiumCredits?: number; RegularCredits?: number; FlavourItems?: IFlavourItem[]; @@ -40,5 +40,6 @@ export type IBinChanges = { export enum SlotType { SUIT = "SuitBin", - WEAPON = "WeaponBin" + WEAPON = "WeaponBin", + MECHSUIT = "MechBin" } diff --git a/src/types/requestTypes.ts b/src/types/requestTypes.ts index 050955d9..ecbd35e0 100644 --- a/src/types/requestTypes.ts +++ b/src/types/requestTypes.ts @@ -7,8 +7,8 @@ import { IMission, IRawUpgrade } from "./inventoryTypes/inventoryTypes"; -import { IWeaponDatabase } from "./inventoryTypes/weaponTypes"; -import { ISuitDatabase } from "./inventoryTypes/SuitTypes"; +import { IWeaponClient } from "./inventoryTypes/weaponTypes"; +import { ISuitClient } from "./inventoryTypes/SuitTypes"; interface IArtifactsRequest { Upgrade: ICrewShipSalvagedWeaponSkin; @@ -20,10 +20,10 @@ interface IArtifactsRequest { interface IMissionInventoryUpdateRequest { rewardsMultiplier?: number; ActiveBoosters?: IBooster[]; - LongGuns?: IWeaponDatabase[]; - Pistols?: IWeaponDatabase[]; - Suits?: ISuitDatabase[]; - Melee?: IWeaponDatabase[]; + LongGuns?: IWeaponClient[]; + Pistols?: IWeaponClient[]; + Suits?: ISuitClient[]; + Melee?: IWeaponClient[]; RawUpgrades?: IRawUpgrade[]; MiscItems?: IMiscItem[]; Consumables?: IConsumable[]; diff --git a/src/types/saveLoadoutTypes.ts b/src/types/saveLoadoutTypes.ts new file mode 100644 index 00000000..61020029 --- /dev/null +++ b/src/types/saveLoadoutTypes.ts @@ -0,0 +1,92 @@ +import { IOid } from "@/src/types/commonTypes"; +import { IItemConfig, IOperatorConfigClient } from "@/src/types/inventoryTypes/commonInventoryTypes"; +import { Types } from "mongoose"; + +export interface ISaveLoadoutRequest { + LoadOuts: ILoadoutClient; + LongGuns: IItemEntry; + OperatorAmps: IItemEntry; + Pistols: IItemEntry; + Suits: IItemEntry; + Melee: IItemEntry; + Sentinels: IItemEntry; + SentinelWeapons: IItemEntry; + KubrowPets: IItemEntry; + SpaceSuits: IItemEntry; + SpaceGuns: IItemEntry; + SpaceMelee: IItemEntry; + Scoops: IItemEntry; + SpecialItems: IItemEntry; + MoaPets: IItemEntry; + Hoverboards: IItemEntry; + DataKnives: IItemEntry; + MechSuits: IItemEntry; + CrewShipHarnesses: IItemEntry; + Horses: IItemEntry; + DrifterMelee: IItemEntry; + UpgradeVer: number; + OperatorLoadOuts: IOperatorConfigEntry; + AdultOperatorLoadOuts: IOperatorConfigEntry; + KahlLoadOuts: IItemEntry; + CrewShips: IItemEntry; + CurrentLoadOutIds: IOid[]; + ValidNewLoadoutId: string; + EquippedGear: string[]; +} + +export interface ISaveLoadoutRequestNoUpgradeVer extends Omit {} + +export interface IOperatorConfigEntry { + [configId: string]: IOperatorConfigClient; +} + +export interface IItemEntry { + [itemId: string]: IConfigEntry; +} + +export interface IConfigEntry { + [configId: string]: IItemConfig; +} + +export interface ILoadoutClient extends Omit {} + +export interface ILoadoutDatabase { + NORMAL: ILoadoutEntry; + SENTINEL: ILoadoutEntry; + ARCHWING: ILoadoutEntry; + NORMAL_PVP: ILoadoutEntry; + LUNARO: ILoadoutEntry; + OPERATOR: ILoadoutEntry; + KDRIVE: ILoadoutEntry; + DATAKNIFE: ILoadoutEntry; + MECH: ILoadoutEntry; + OPERATOR_ADULT: ILoadoutEntry; + DRIFTER: ILoadoutEntry; + _id: Types.ObjectId; + loadoutOwnerId: Types.ObjectId; +} + +export interface ILoadoutEntry { + [key: string]: ILoadoutConfigClient; +} +export interface ILoadoutConfigDatabase extends Omit { + _id: Types.ObjectId; +} + +// for request and response from and to client +export interface ILoadoutConfigClient { + ItemId: IOid; + n: string; + PresetIcon: string; + Favorite: boolean; + s: IEquipmentSelection; + p: IEquipmentSelection; + l: IEquipmentSelection; + m: IEquipmentSelection; +} + +export interface IEquipmentSelection { + ItemId: IOid; + mod: number; + cus: number; +} diff --git a/src/types/shipTypes.ts b/src/types/shipTypes.ts index aac1ef27..522837e5 100644 --- a/src/types/shipTypes.ts +++ b/src/types/shipTypes.ts @@ -3,26 +3,28 @@ import { IOid } from "@/src/types/commonTypes"; export interface IShip { ShipOwnerId: Types.ObjectId; - Ship: IShipClassResponse; - Apartment: IApartmentClass; + Ship: IShipResponse; + Apartment: IApartment; + LoadOutInventory: { LoadOutPresets: Types.ObjectId }; } -export interface IShipClassResponse extends IShipClassDatabase { +export interface IShipResponse extends IShipDatabase { ShipId: IOid; } -export interface IShipClassDatabase { - Rooms: IRoomsClass[]; +export interface IShipDatabase { + Rooms: IRooms[]; Features: string[]; ContentUrlSignature: string; } -export interface IRoomsClass { +// TODO: add Apartment.Gardening +export interface IRooms { Name: string; MaxCapacity: number; } -export interface IApartmentClass { - Rooms: IRoomsClass[]; +export interface IApartment { + Rooms: IRooms[]; FavouriteLoadouts: string[]; } diff --git a/static/fixed_responses/postTutorialInventory.json b/static/fixed_responses/postTutorialInventory.json index 31d9a61f..9bcab784 100644 --- a/static/fixed_responses/postTutorialInventory.json +++ b/static/fixed_responses/postTutorialInventory.json @@ -5,7 +5,7 @@ "RewardSeed": -5604904486637265640, "CrewMemberBin": { "Slots": 3 }, "CrewShipSalvageBin": { "Slots": 8 }, - "DrifterMelee": [{ "ItemType": "/Lotus/Types/Friendly/PlayerControllable/Weapons/DuviriDualSwords", "ItemId": { "$oid": "647bd268c547fe5b2909e715" } }], + "DrifterMelee": [{ "ItemType": "/Lotus/Types/Friendly/PlayerControllable/Weapons/DuviriDualSwords", "ItemId": { "$oid": "647bd27cf856530b4f3bf343" } }], "FusionPoints": 0, "MechBin": { "Slots": 4 }, "OperatorAmpBin": { "Slots": 8 }, @@ -84,7 +84,24 @@ "CrewShipWeaponSkins": [], "DrifterGuns": [], "Drones": [], - "Horses": [], + "Horses": [ + { + "ItemType": "/Lotus/Types/NeutralCreatures/ErsatzHorse/ErsatzHorsePowerSuit", + "Configs": [ + { + "Skins": ["", "", "/Lotus/Upgrades/Skins/Horse/ErsatzHorseTailDefault"] + }, + { + "Skins": ["", "", "/Lotus/Upgrades/Skins/Horse/ErsatzHorseTailDefault"] + }, + { + "Skins": ["", "", "/Lotus/Upgrades/Skins/Horse/ErsatzHorseTailDefault"] + } + ], + "UpgradeVer": 101, + "ItemId": { "$oid": "647bd27cf856530b4f3bf343" } + } + ], "Hoverboards": [], "KubrowPets": [], "KubrowPetEggs": [], diff --git a/static/fixed_responses/testQuestKeys.json b/static/fixed_responses/testQuestKeys.json index df32ed3d..1a822001 100644 --- a/static/fixed_responses/testQuestKeys.json +++ b/static/fixed_responses/testQuestKeys.json @@ -7,5 +7,35 @@ }, { "ItemType": "/Lotus/Types/Keys/DuviriQuest/DuviriQuestKeyChain" + }, + { + "ItemType": "/Lotus/Types/Keys/WarWithinQuest/WarWithinQuestKeyChain" + }, + { + "ItemType": "/Lotus/Types/Keys/SacrificeQuest/SacrificeQuestKeyChain" + }, + { + "ItemType": "/Lotus/Types/Keys/NewWarIntroQuest/NewWarIntroKeyChain" + }, + { + "ItemType": "/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain" + }, + { + "ItemType": "/Lotus/Types/Keys/ApostasyQuest/ApostasyKeyChain" + }, + { + "ItemType": "/Lotus/Types/Keys/WarWithinQuest/WarWithinQuestKeyChain" + }, + { + "ItemType": "/Lotus/Types/Keys/OrokinMoonQuest/OrokinMoonQuestKeyChain" + }, + { + "ItemType": "/Lotus/Types/Keys/ZarimanQuest/ZarimanQuestKeyChain" + }, + { + "ItemType": "/Lotus/Types/Keys/DuviriQuest/DuviriQuestKeyChain" + }, + { + "ItemType": "/Lotus/Types/Keys/ArchwingQuest/ArchwingQuestKeyChain" } ]