diff --git a/config.json b/config.json index 9dd254d5..24059a07 100644 --- a/config.json +++ b/config.json @@ -7,6 +7,8 @@ "skipStoryModeChoice": true, "skipTutorial": true, "unlockAllMissions": true, - "unlockAllQuests": false, - "infiniteResources": true + "unlockAllQuests": true, + "infiniteResources": true, + "unlockallShipFeatures": true, + "unlockAllShipDecorations": true } diff --git a/src/controllers/api/getShipController.ts b/src/controllers/api/getShipController.ts index b0501365..56485606 100644 --- a/src/controllers/api/getShipController.ts +++ b/src/controllers/api/getShipController.ts @@ -1,90 +1,60 @@ -import { Ship } from "@/src/models/shipModel"; -import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes"; import { RequestHandler } from "express"; +import config from "@/config.json"; +import allShipFeatures from "@/static/fixed_responses/allShipFeatures.json"; +import { parseString } from "@/src/helpers/general"; +import { getShip } from "@/src/services/shipService"; +import { PersonalRooms } from "@/src/models/personalRoomsModel"; +import { Loadout } from "@/src/models/inventoryModels/loadoutModel"; +import { logger } from "@/src/utils/logger"; +import { toOid } from "@/src/helpers/inventoryHelpers"; +import { IGetShipResponse } from "@/src/types/shipTypes"; // 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 }).populate<{ - LoadOutInventory: { LoadOutPresets: ILoadoutDatabase }; - }>("LoadOutInventory.LoadOutPresets"); +export const getShipController: RequestHandler = async (req, res) => { + const accountId = parseString(req.query.accountId); + const personalRooms = await getPersonalRooms(accountId); + const loadout = await getLoadout(accountId); + const ship = await getShip(personalRooms.activeShipId, "ShipInteriorColors ShipAttachments SkinFlavourItem"); - if (!ship) { - res.status(500).json({ error: "error finding a corresponding ship" }); - return; + const getShipResponse: IGetShipResponse = { + ShipOwnerId: accountId, + LoadOutInventory: { LoadOutPresets: loadout.toJSON() }, + Ship: { + ...personalRooms.toJSON().Ship, + ShipId: toOid(personalRooms.activeShipId), + ShipInterior: { + Colors: ship.ShipInteriorColors, + ShipAttachments: ship.ShipAttachments, + SkinFlavourItem: ship.SkinFlavourItem + } + }, + Apartment: personalRooms.Apartment + }; + + if (config.unlockallShipFeatures) { + getShipResponse.Ship.Features = allShipFeatures; } - 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); + res.json(getShipResponse); }; -export { getShipController }; +export const getLoadout = async (accountId: string) => { + const loadout = await Loadout.findOne({ loadoutOwnerId: accountId }); + + if (!loadout) { + logger.error(`loadout not found for account ${accountId}`); + throw new Error("loadout not found"); + } + + return loadout; +}; + +export const getPersonalRooms = async (accountId: string) => { + const personalRooms = await PersonalRooms.findOne({ personalRoomsOwnerId: accountId }); + + if (!personalRooms) { + logger.error(`personal rooms not found for account ${accountId}`); + throw new Error("personal rooms not found"); + } + return personalRooms; +}; diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index 8f217071..bb0f1473 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -5,7 +5,9 @@ import { Request, RequestHandler, Response } from "express"; import config from "@/config.json"; import allMissions from "@/static/fixed_responses/allMissions.json"; import allQuestKeys from "@/static/fixed_responses/allQuestKeys.json"; +import allShipDecorations from "@/static/fixed_responses/shipDecorations.json"; import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes"; +import { IShipInventory } from "@/src/types/inventoryTypes/inventoryTypes"; const inventoryController: RequestHandler = async (request: Request, response: Response) => { const accountId = request.query.accountId; @@ -15,9 +17,11 @@ const inventoryController: RequestHandler = async (request: Request, response: R return; } - const inventory = await Inventory.findOne({ accountOwnerId: accountId }).populate<{ - LoadOutPresets: ILoadoutDatabase; - }>("LoadOutPresets"); + const inventory = await Inventory.findOne({ accountOwnerId: accountId }) + .populate<{ + LoadOutPresets: ILoadoutDatabase; + }>("LoadOutPresets") + .populate<{ Ships: IShipInventory }>("Ships", "-ShipInteriorColors"); if (!inventory) { response.status(400).json({ error: "inventory was undefined" }); @@ -26,12 +30,17 @@ const inventoryController: RequestHandler = async (request: Request, response: R //TODO: make a function that converts from database representation to client const inventoryJSON = inventory.toJSON(); + console.log(inventoryJSON.Ships); const inventoryResponse = toInventoryResponse(inventoryJSON); if (config.unlockAllMissions) inventoryResponse.Missions = allMissions; if (config.unlockAllQuests) inventoryResponse.QuestKeys = allQuestKeys; + if (config.unlockAllShipDecorations) { + inventoryResponse.ShipDecorations = allShipDecorations; + } + response.json(inventoryResponse); }; diff --git a/src/controllers/api/loginController.ts b/src/controllers/api/loginController.ts index 3f25182b..7dbef077 100644 --- a/src/controllers/api/loginController.ts +++ b/src/controllers/api/loginController.ts @@ -51,7 +51,7 @@ const loginController: RequestHandler = async (request, response) => { return; } catch (error: unknown) { if (error instanceof Error) { - throw new Error("error creating account", error); + throw new Error(`error creating account ${error.message}`); } } } diff --git a/src/controllers/api/setActiveShipController.ts b/src/controllers/api/setActiveShipController.ts new file mode 100644 index 00000000..ed896b4e --- /dev/null +++ b/src/controllers/api/setActiveShipController.ts @@ -0,0 +1,15 @@ +import { getPersonalRooms } from "@/src/controllers/api/getShipController"; +import { parseString } from "@/src/helpers/general"; +import { RequestHandler } from "express"; +import { Types } from "mongoose"; + +// eslint-disable-next-line @typescript-eslint/no-misused-promises +export const setActiveShipController: RequestHandler = async (req, res) => { + const accountId = parseString(req.query.accountId); + const shipId = parseString(req.query.shipId); + + const personalRooms = await getPersonalRooms(accountId); + personalRooms.activeShipId = new Types.ObjectId(shipId); + await personalRooms.save(); + res.status(200).end(); +}; diff --git a/src/controllers/api/setShipCustomizationsController.ts b/src/controllers/api/setShipCustomizationsController.ts new file mode 100644 index 00000000..8e78b1c3 --- /dev/null +++ b/src/controllers/api/setShipCustomizationsController.ts @@ -0,0 +1,19 @@ +import { setShipCustomizations } from "@/src/services/shipCustomizationsService"; +import { ISetShipCustomizationsRequest } from "@/src/types/shipTypes"; +import { logger } from "@/src/utils/logger"; +import { RequestHandler } from "express"; + +// eslint-disable-next-line @typescript-eslint/no-misused-promises +export const setShipCustomizationsController: RequestHandler = async (req, res) => { + try { + const setShipCustomizationsRequest = JSON.parse(req.body as string) as ISetShipCustomizationsRequest; + + const setShipCustomizationsResponse = await setShipCustomizations(setShipCustomizationsRequest); + res.json(setShipCustomizationsResponse); + } catch (error: unknown) { + if (error instanceof Error) { + logger.error(`error in setShipCustomizationsController: ${error.message}`); + res.status(400).json({ error: error.message }); + } + } +}; diff --git a/src/controllers/api/shipDecorationsController.ts b/src/controllers/api/shipDecorationsController.ts new file mode 100644 index 00000000..97230d5e --- /dev/null +++ b/src/controllers/api/shipDecorationsController.ts @@ -0,0 +1,21 @@ +import { parseString } from "@/src/helpers/general"; +import { IShipDecorationsRequest } from "@/src/types/shipTypes"; +import { logger } from "@/src/utils/logger"; +import { RequestHandler } from "express"; +import { handleSetShipDecorations } from "@/src/services/shipCustomizationsService"; + +// eslint-disable-next-line @typescript-eslint/no-misused-promises +export const shipDecorationsController: RequestHandler = async (req, res) => { + const accountId = parseString(req.query.accountId); + const shipDecorationsRequest = JSON.parse(req.body as string) as IShipDecorationsRequest; + + try { + const placedDecoration = await handleSetShipDecorations(accountId, shipDecorationsRequest); + res.send(placedDecoration); + } catch (error: unknown) { + if (error instanceof Error) { + logger.error(`error in saveLoadoutController: ${error.message}`); + res.status(400).json({ error: error.message }); + } + } +}; diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index 52283fd7..d7f3ae81 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -6,7 +6,6 @@ import { IInventoryDatabase, IBooster, IInventoryResponse, - IInventoryDatabaseDocument, ISlots, IGenericItem, IMailbox, @@ -21,9 +20,7 @@ import { IChallengeProgress, IStepSequencer, IAffiliation, - IShip, INotePacks, - IShipExterior, ICompletedJobChain, ISeasonChallengeHistory, IPlayerSkills, @@ -108,7 +105,7 @@ const abilityOverrideSchema = new Schema({ Ability: String, Index: Number }); -const colorSchema = new Schema( +export const colorSchema = new Schema( { t0: Number, t1: Number, @@ -457,33 +454,6 @@ const affiliationsSchema = new Schema( { _id: false } ); -const shipExteriorSchema = new Schema( - { - SkinFlavourItem: String, - Colors: colorSchema, //TODO: perhaps too many colors here - ShipAttachments: { HOOD_ORNAMENT: String } - }, - { _id: false } -); - -const shipSchema = new Schema({ - ItemType: String, - ShipExterior: shipExteriorSchema, - AirSupportPower: String -}); - -shipSchema.virtual("ItemId").get(function () { - return { $oid: this._id.toString() }; -}); - -shipSchema.set("toJSON", { - virtuals: true, - transform(_document, returnedObject) { - delete returnedObject._id; - delete returnedObject.__v; - } -}); - const completedJobChainsSchema = new Schema( { LocationTag: String, @@ -773,7 +743,7 @@ const inventorySchema = new Schema( Horses: [GenericItemSchema], //LandingCraft like Liset - Ships: [shipSchema], + Ships: { type: [Schema.Types.ObjectId], ref: "Ships" }, // /Lotus/Types/Items/ShipDecos/ ShipDecorations: [typeCountSchema], diff --git a/src/models/inventoryModels/loadoutModel.ts b/src/models/inventoryModels/loadoutModel.ts index 37a8d104..87871138 100644 --- a/src/models/inventoryModels/loadoutModel.ts +++ b/src/models/inventoryModels/loadoutModel.ts @@ -93,4 +93,4 @@ type loadoutDocumentProps = { type loadoutModelType = Model; -export const LoadoutModel = model("Loadout", loadoutSchema); +export const Loadout = model("Loadout", loadoutSchema); diff --git a/src/models/loginModel.ts b/src/models/loginModel.ts index f1846784..b21c5906 100644 --- a/src/models/loginModel.ts +++ b/src/models/loginModel.ts @@ -46,14 +46,4 @@ databaseAccountSchema.set("toJSON", { virtuals: true }); -//databaseAccountSchema.set(""); - -// Create a virtual property `domain` that's computed from `email`. -// databaseAccountSchema.virtual("id").get(function () { -// //console.log(this); -// return this._id; -// }); - -const Account = model("Account", databaseAccountSchema); - -export { Account }; +export const Account = model("Account", databaseAccountSchema); diff --git a/src/models/personalRoomsModel.ts b/src/models/personalRoomsModel.ts new file mode 100644 index 00000000..6829932e --- /dev/null +++ b/src/models/personalRoomsModel.ts @@ -0,0 +1,60 @@ +import { toOid } from "@/src/helpers/inventoryHelpers"; +import { IOrbiter, IPersonalRooms, PersonalRoomsModelType } from "@/src/types/personalRoomsTypes"; +import { IApartment, IGardening, IPlacedDecosDatabase } from "@/src/types/shipTypes"; +import { Schema, model } from "mongoose"; + +const placedDecosSchema = new Schema( + { + Type: String, + Pos: [Number], + Rot: [Number] + }, + { id: false } +); + +placedDecosSchema.virtual("id").get(function (this: IPlacedDecosDatabase) { + return toOid(this._id); +}); + +placedDecosSchema.set("toJSON", { + virtuals: true, + transform(_document, returnedObject) { + delete returnedObject._id; + } +}); + +const roomSchema = new Schema( + { + Name: String, + MaxCapacity: Number, + PlacedDecos: [placedDecosSchema] + }, + { _id: false } +); + +const gardeningSchema = new Schema({ + Planters: [Schema.Types.Mixed] //TODO: add when implementing gardening +}); + +const apartmentSchema = new Schema( + { + Rooms: [roomSchema], + FavouriteLoadouts: [Schema.Types.Mixed], + Gardening: gardeningSchema + }, + { _id: false } +); + +const orbiterSchema = new Schema( + { Features: [String], Rooms: [roomSchema], ContentUrlSignature: String }, + { _id: false } +); + +export const personalRoomsSchema = new Schema({ + personalRoomsOwnerId: Schema.Types.ObjectId, + activeShipId: Schema.Types.ObjectId, + Ship: orbiterSchema, + Apartment: apartmentSchema +}); + +export const PersonalRooms = model("PersonalRooms", personalRoomsSchema); diff --git a/src/models/shipModel.ts b/src/models/shipModel.ts index 4b16ebd2..cf2486a4 100644 --- a/src/models/shipModel.ts +++ b/src/models/shipModel.ts @@ -1,66 +1,50 @@ -import { Schema, model } from "mongoose"; -import { IShip } from "../types/shipTypes"; -import { IOid } from "../types/commonTypes"; -import { loadoutSchema } from "@/src/models/inventoryModels/loadoutModel"; +import { Model, Schema, StringSchemaDefinition, Types, model } from "mongoose"; +import { IApartment, IPlacedDecosDatabase, IRooms, IShipDatabase } from "../types/shipTypes"; +import { toOid } from "@/src/helpers/inventoryHelpers"; +import { colorSchema } from "@/src/models/inventoryModels/inventoryModel"; +import { IShipInventory } from "@/src/types/inventoryTypes/inventoryTypes"; -const roomSchema = new Schema( +const shipSchema = new Schema( { - Name: String, - MaxCapacity: Number - }, - { _id: false } -); - -const shipSchema = new Schema( - { - Rooms: [roomSchema], - Features: [String], - ContentUrlSignature: String + ItemType: String, + ShipOwnerId: Schema.Types.ObjectId, + ShipInteriorColors: colorSchema, + ShipExteriorColors: colorSchema, + AirSupportPower: String, + ShipAttachments: { HOOD_ORNAMENT: String }, + SkinFlavourItem: String }, { id: false } ); -shipSchema.virtual("ShipId").get(function () { - return { $oid: this._id.toString() } satisfies IOid; +shipSchema.virtual("ItemId").get(function () { + return toOid(this._id); }); shipSchema.set("toJSON", { virtuals: true, transform(_document, returnedObject) { + const shipResponse = returnedObject as IShipInventory; + const shipDatabase = returnedObject as IShipDatabase; delete returnedObject._id; - } -}); + delete returnedObject.__v; + delete returnedObject.ShipOwnerId; + if (shipDatabase.ShipExteriorColors) { + shipResponse.ShipExterior = { + Colors: shipDatabase.ShipExteriorColors, + ShipAttachments: shipDatabase.ShipAttachments, + SkinFlavourItem: shipDatabase.SkinFlavourItem + }; -const apartmentSchema = new Schema({ - Rooms: [roomSchema], - FavouriteLoadouts: [Schema.Types.Mixed] -}); - -apartmentSchema.set("toJSON", { - transform(_document, returnedObject) { - delete returnedObject._id; - } -}); - -const shipDatabaseSchema = new Schema({ - ShipOwnerId: Schema.Types.ObjectId, - Ship: shipSchema, - Apartment: apartmentSchema, - LoadOutInventory: { - LoadOutPresets: { - type: Schema.Types.ObjectId, - ref: "Loadout" + delete shipDatabase.ShipExteriorColors; + delete shipDatabase.ShipAttachments; + delete shipDatabase.SkinFlavourItem; } } }); -shipDatabaseSchema.set("toJSON", { - transform(_document, returnedObject) { - delete returnedObject._id; - delete returnedObject.__v; - } +shipSchema.set("toObject", { + virtuals: true }); -const Ship = model("Ship", shipDatabaseSchema); - -export { Ship }; +export const Ship = model("Ships", shipSchema); diff --git a/src/routes/api.ts b/src/routes/api.ts index 1c9270bd..71648809 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -37,6 +37,9 @@ import { focusController } from "@/src/controllers/api/focusController"; import { inventorySlotsController } from "@/src/controllers/api/inventorySlotsController"; import { startRecipeController } from "@/src/controllers/api/startRecipeController"; import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController"; +import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController"; +import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController"; +import { setActiveShipController } from "@/src/controllers/api/setActiveShipController"; const apiRouter = express.Router(); @@ -62,9 +65,12 @@ apiRouter.get("/modularWeaponSale.php", modularWeaponSaleController); apiRouter.get("/deleteSession.php", deleteSessionController); apiRouter.get("/logout.php", logoutController); apiRouter.get("/setBootLocation.php", setBootLocationController); +apiRouter.get("/setActiveShip.php", setActiveShipController); // post // eslint-disable-next-line @typescript-eslint/no-misused-promises +apiRouter.post("/shipDecorations.php", shipDecorationsController); +apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController); apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController); apiRouter.post("/startRecipe.php", startRecipeController); apiRouter.post("/inventorySlots.php", inventorySlotsController); diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 9b74dad6..cc7fd350 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -19,12 +19,16 @@ import { IArtifactsRequest, IMissionInventoryUpdateRequest } from "../types/requ import { logger } from "@/src/utils/logger"; import { WeaponTypeInternal } from "@/src/services/itemDataService"; -export const createInventory = async (accountOwnerId: Types.ObjectId, loadOutPresetId: Types.ObjectId) => { +export const createInventory = async ( + accountOwnerId: Types.ObjectId, + defaultItemReferences: { loadOutPresetId: Types.ObjectId; ship: Types.ObjectId } +) => { try { const inventory = new Inventory({ ...new_inventory, accountOwnerId: accountOwnerId, - LoadOutPresets: loadOutPresetId + LoadOutPresets: defaultItemReferences.loadOutPresetId, + Ships: [defaultItemReferences.ship] }); if (config.skipStoryModeChoice) { inventory.StoryModeChoice = "WARFRAME"; diff --git a/src/services/loadoutService.ts b/src/services/loadoutService.ts new file mode 100644 index 00000000..37f91612 --- /dev/null +++ b/src/services/loadoutService.ts @@ -0,0 +1,13 @@ +import { Loadout } from "@/src/models/inventoryModels/loadoutModel"; +import { logger } from "@/src/utils/logger"; + +export const getLoadout = async (accountId: string) => { + const loadout = await Loadout.findOne({ loadoutOwnerId: accountId }); + + if (!loadout) { + logger.error(`loadout not found for account ${accountId}`); + throw new Error("loadout not found"); + } + + return loadout; +}; diff --git a/src/services/loginService.ts b/src/services/loginService.ts index 1753c85b..aa74732c 100644 --- a/src/services/loginService.ts +++ b/src/services/loginService.ts @@ -3,7 +3,9 @@ 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"; +import { Loadout } from "@/src/models/inventoryModels/loadoutModel"; +import { PersonalRooms } from "@/src/models/personalRoomsModel"; +import new_personal_rooms from "@/static/fixed_responses/personalRooms.json"; const isCorrectPassword = (requestPassword: string, databasePassword: string): boolean => { return requestPassword === databasePassword; @@ -14,8 +16,9 @@ const createAccount = async (accountData: IDatabaseAccount) => { try { await account.save(); const loadoutId = await createLoadout(account._id); - await createInventory(account._id, loadoutId); - await createShip(account._id, loadoutId); + const shipId = await createShip(account._id); + await createInventory(account._id, { loadOutPresetId: loadoutId, ship: shipId }); + await createPersonalRooms(account._id, shipId); return account.toJSON(); } catch (error) { if (error instanceof Error) { @@ -28,7 +31,16 @@ const createAccount = async (accountData: IDatabaseAccount) => { export { isCorrectPassword, createAccount }; export const createLoadout = async (accountId: Types.ObjectId) => { - const loadout = new LoadoutModel({ loadoutOwnerId: accountId }); + const loadout = new Loadout({ loadoutOwnerId: accountId }); const savedLoadout = await loadout.save(); return savedLoadout._id; }; + +export const createPersonalRooms = async (accountId: Types.ObjectId, shipId: Types.ObjectId) => { + const personalRooms = new PersonalRooms({ + ...new_personal_rooms, + personalRoomsOwnerId: accountId, + activeShipId: shipId + }); + await personalRooms.save(); +}; diff --git a/src/services/personalRoomsService.ts b/src/services/personalRoomsService.ts new file mode 100644 index 00000000..c2d0b629 --- /dev/null +++ b/src/services/personalRoomsService.ts @@ -0,0 +1,12 @@ +import { PersonalRooms } from "@/src/models/personalRoomsModel"; +import { logger } from "@/src/utils/logger"; + +export const getPersonalRooms = async (accountId: string) => { + const personalRooms = await PersonalRooms.findOne({ personalRoomsOwnerId: accountId }); + + if (!personalRooms) { + logger.error(`personal rooms not found for account ${accountId}`); + throw new Error("personal rooms not found"); + } + return personalRooms; +}; diff --git a/src/services/saveLoadoutService.ts b/src/services/saveLoadoutService.ts index e8f7bc5d..0b71f22f 100644 --- a/src/services/saveLoadoutService.ts +++ b/src/services/saveLoadoutService.ts @@ -5,7 +5,7 @@ import { IOperatorConfigEntry, ISaveLoadoutRequestNoUpgradeVer } from "@/src/types/saveLoadoutTypes"; -import { LoadoutModel } from "@/src/models/inventoryModels/loadoutModel"; +import { Loadout } from "@/src/models/inventoryModels/loadoutModel"; import { getInventory } from "@/src/services/inventoryService"; import { IOid } from "@/src/types/commonTypes"; import { Types } from "mongoose"; @@ -60,7 +60,7 @@ export const handleInventoryItemConfigChange = async ( } case "LoadOuts": { logger.debug("loadout received"); - const loadout = await LoadoutModel.findOne({ loadoutOwnerId: accountId }); + const loadout = await Loadout.findOne({ loadoutOwnerId: accountId }); if (!loadout) { throw new Error("loadout not found"); } diff --git a/src/services/shipCustomizationsService.ts b/src/services/shipCustomizationsService.ts new file mode 100644 index 00000000..98125e50 --- /dev/null +++ b/src/services/shipCustomizationsService.ts @@ -0,0 +1,68 @@ +import { getPersonalRooms } from "@/src/services/personalRoomsService"; +import { getShip } from "@/src/services/shipService"; +import { + ISetShipCustomizationsRequest, + IShipDatabase, + IShipDecorationsRequest, + IShipDecorationsResponse +} from "@/src/types/shipTypes"; +import { Types } from "mongoose"; + +export const setShipCustomizations = async (shipCustomization: ISetShipCustomizationsRequest) => { + const ship = await getShip(new Types.ObjectId(shipCustomization.ShipId)); + + let shipChanges: Partial; + if (shipCustomization.IsExterior) { + shipChanges = { + ShipExteriorColors: shipCustomization.Customization.Colors, + SkinFlavourItem: shipCustomization.Customization.SkinFlavourItem, + ShipAttachments: shipCustomization.Customization.ShipAttachments, + AirSupportPower: shipCustomization.AirSupportPower! + }; + } else { + shipChanges = { + ShipInteriorColors: shipCustomization.Customization.Colors + }; + } + ship.set(shipChanges); + + await ship.save(); +}; + +export const handleSetShipDecorations = async ( + accountId: string, + placedDecoration: IShipDecorationsRequest +): Promise => { + const personalRooms = await getPersonalRooms(accountId); + + const rooms = placedDecoration.IsApartment ? personalRooms.Apartment.Rooms : personalRooms.Ship.Rooms; + + const room = rooms.find(room => room.Name === placedDecoration.Room); + + //TODO: check whether to remove from shipitems + + if (placedDecoration.RemoveId) { + room?.PlacedDecos?.pull({ _id: placedDecoration.RemoveId }); + await personalRooms.save(); + return { + DecoId: placedDecoration.RemoveId, + Room: placedDecoration.Room, + IsApartment: placedDecoration.IsApartment, + MaxCapacityIncrease: 0 + }; + } + + // TODO: handle capacity + + const decoId = new Types.ObjectId(); + room?.PlacedDecos?.push({ + Type: placedDecoration.Type, + Pos: placedDecoration.Pos, + Rot: placedDecoration.Rot, + _id: decoId + }); + + await personalRooms.save(); + + return { DecoId: decoId.toString(), Room: placedDecoration.Room, IsApartment: placedDecoration.IsApartment }; +}; diff --git a/src/services/shipService.ts b/src/services/shipService.ts index 5b35cce3..ae11c9d2 100644 --- a/src/services/shipService.ts +++ b/src/services/shipService.ts @@ -1,15 +1,16 @@ import { Ship } from "@/src/models/shipModel"; -import new_ship from "@/static/fixed_responses/ship.json"; +import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes"; +import { logger } from "@/src/utils/logger"; import { Types } from "mongoose"; -const createShip = async (accountOwnerId: Types.ObjectId, loadoutId: Types.ObjectId) => { +export const createShip = async (accountOwnerId: Types.ObjectId) => { try { const ship = new Ship({ - ...new_ship, - ShipOwnerId: accountOwnerId, - LoadOutInventory: { LoadOutPresets: loadoutId } + ItemType: "/Lotus/Types/Items/Ships/DefaultShip", + ShipOwnerId: accountOwnerId }); - await ship.save(); + const newShip = await ship.save(); + return newShip._id; } catch (error) { if (error instanceof Error) { throw new Error(`error creating ship" ${error.message}`); @@ -18,4 +19,26 @@ const createShip = async (accountOwnerId: Types.ObjectId, loadoutId: Types.Objec } }; -export { createShip }; +export const getShip = async (shipId: Types.ObjectId, fieldSelection: string = "") => { + const ship = await Ship.findOne({ _id: shipId }, fieldSelection); + + if (!ship) { + logger.error(`error finding a ship for account ${shipId}`); + throw new Error(`error finding a ship for account ${shipId}`); + } + + return ship; +}; + +export const getShipLean = async (shipOwnerId: string) => { + const ship = await Ship.findOne({ ShipOwnerId: shipOwnerId }).lean().populate<{ + LoadOutInventory: { LoadOutPresets: ILoadoutDatabase }; + }>("LoadOutInventory.LoadOutPresets"); + + if (!ship) { + logger.error(`error finding a ship for account ${shipOwnerId}`); + throw new Error(`error finding a ship for account ${shipOwnerId}`); + } + + return ship; +}; diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index b7b5f1fa..71f5ebac 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -11,13 +11,21 @@ import { } from "@/src/types/inventoryTypes/commonInventoryTypes"; import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes"; import { IOperatorLoadOutSigcol, IWeaponDatabase } from "@/src/types/inventoryTypes/weaponTypes"; +import { Colour } from "warframe-items"; //Document extends will be deleted soon. TODO: delete and migrate uses to ... export interface IInventoryDatabaseDocument extends IInventoryDatabase, Document {} export interface IInventoryDatabase extends Omit< IInventoryResponse, - "TrainingDate" | "LoadOutPresets" | "Mailbox" | "PendingRecipes" | "Created" | "QuestKeys" | "BlessingCooldown" + | "TrainingDate" + | "LoadOutPresets" + | "Mailbox" + | "PendingRecipes" + | "Created" + | "QuestKeys" + | "BlessingCooldown" + | "Ships" > { accountOwnerId: Types.ObjectId; Created: Date; @@ -27,6 +35,7 @@ export interface IInventoryDatabase PendingRecipes: IPendingRecipe[]; QuestKeys: IQuestKeyDatabase[]; BlessingCooldown: Date; + Ships: Types.ObjectId[]; } export interface IInventoryResponseDocument extends IInventoryResponse, Document {} @@ -140,7 +149,7 @@ export interface IInventoryResponse { LongGuns: IWeaponDatabase[]; Pistols: IWeaponDatabase[]; Melee: IWeaponDatabase[]; - Ships: IShip[]; + Ships: IShipInventory[]; QuestKeys: IQuestKeyResponse[]; FlavourItems: IFlavourItem[]; Scoops: IGenericItem[]; @@ -449,8 +458,8 @@ export interface ICustomization { } export interface IShipExterior { - SkinFlavourItem: string; - Colors: IShipExteriorColors; + SkinFlavourItem?: string; + Colors: IColor; ShipAttachments?: IShipAttachments; } @@ -1016,7 +1025,7 @@ export interface ISettings { TradingRulesConfirmed: boolean; } -export interface IShip { +export interface IShipInventory { ItemType: string; ShipExterior: IShipExterior; AirSupportPower: string; diff --git a/src/types/personalRoomsTypes.ts b/src/types/personalRoomsTypes.ts new file mode 100644 index 00000000..7c9b91f0 --- /dev/null +++ b/src/types/personalRoomsTypes.ts @@ -0,0 +1,28 @@ +import { IApartment, IRooms } from "@/src/types/shipTypes"; +import { Model, Types } from "mongoose"; + +export interface IOrbiter { + Features: string[]; + Rooms: IRooms[]; + ContentUrlSignature: string; +} + +export interface IPersonalRooms { + personalRoomsOwnerId: Types.ObjectId; + activeShipId: Types.ObjectId; + Ship: IOrbiter; + Apartment: IApartment; +} + +export type RoomsType = { Name: string; MaxCapacity: number; PlacedDecos: Types.DocumentArray }; + +export type PersonalRoomsDocumentProps = { + Ship: Omit & { + Rooms: RoomsType[]; + }; + Apartment: Omit & { + Rooms: RoomsType[]; + }; +}; + +export type PersonalRoomsModelType = Model; diff --git a/src/types/shipTypes.ts b/src/types/shipTypes.ts index 522837e5..05ac65da 100644 --- a/src/types/shipTypes.ts +++ b/src/types/shipTypes.ts @@ -1,30 +1,108 @@ -import { Types } from "mongoose"; +import { Schema, Types } from "mongoose"; import { IOid } from "@/src/types/commonTypes"; +import { IColor } from "@/src/types/inventoryTypes/commonInventoryTypes"; -export interface IShip { - ShipOwnerId: Types.ObjectId; - Ship: IShipResponse; +export interface IGetShipResponse { + ShipOwnerId: string; + Ship: IShip; Apartment: IApartment; LoadOutInventory: { LoadOutPresets: Types.ObjectId }; } -export interface IShipResponse extends IShipDatabase { - ShipId: IOid; +export interface IShipAttachments { + HOOD_ORNAMENT: string; } -export interface IShipDatabase { - Rooms: IRooms[]; +export interface IShipInterior { + Colors?: IColor; + ShipAttachments?: IShipAttachments; + SkinFlavourItem?: string; +} + +export interface IShip { Features: string[]; + ShipId: IOid; + ShipInterior: IShipInterior; + Rooms: IRooms[]; ContentUrlSignature: string; } -// TODO: add Apartment.Gardening +export interface IShipDatabase { + ItemType: string; + ShipOwnerId: Schema.Types.ObjectId; + ShipInteriorColors?: IColor; + ShipExteriorColors?: IColor; + AirSupportPower: string; + ShipAttachments?: IShipAttachments; + SkinFlavourItem?: string; +} + export interface IRooms { Name: string; MaxCapacity: number; + PlacedDecos?: IPlacedDecosDatabase[]; } +export interface IPlants { + PlantType: string; + EndTime: IOid; + PlotIndex: number; +} +export interface IPlanters { + Name: string; + Plants: IPlants[]; +} + +export interface IGardening { + Planters: IPlanters[]; +} export interface IApartment { + Gardening: IGardening; Rooms: IRooms[]; FavouriteLoadouts: string[]; } + +export interface IPlacedDecosDatabase { + Type: string; + Pos: [number, number, number]; + Rot: [number, number, number]; + _id: Types.ObjectId; +} + +export interface IPlacedDecosClient extends Omit { + id: IOid; +} + +export interface ISetShipCustomizationsRequest { + ShipId: string; + Customization: Customization; + IsExterior: boolean; + AirSupportPower?: string; +} + +export interface Customization { + SkinFlavourItem: string; + Colors: IColor; + ShipAttachments: ShipAttachments; +} + +//TODO: check for more attachments +export interface ShipAttachments { + HOOD_ORNAMENT: string; +} + +export interface IShipDecorationsRequest { + Type: string; + Pos: [number, number, number]; + Rot: [number, number, number]; + Room: string; + IsApartment: boolean; + RemoveId: string; +} + +export interface IShipDecorationsResponse { + DecoId: string; + Room: string; + IsApartment: boolean; + MaxCapacityIncrease?: number; +} diff --git a/static/fixed_responses/allShipFeatures.json b/static/fixed_responses/allShipFeatures.json new file mode 100644 index 00000000..fdbff99f --- /dev/null +++ b/static/fixed_responses/allShipFeatures.json @@ -0,0 +1,69 @@ +[ + "/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" +] diff --git a/static/fixed_responses/ship.json b/static/fixed_responses/personalRooms.json similarity index 94% rename from static/fixed_responses/ship.json rename to static/fixed_responses/personalRooms.json index 8ed911c1..8142eb97 100644 --- a/static/fixed_responses/ship.json +++ b/static/fixed_responses/personalRooms.json @@ -8,7 +8,6 @@ "/Lotus/Types/Items/ShipFeatureItems/FoundryFeatureItem", "/Lotus/Types/Items/ShipFeatureItems/MercuryNavigationFeatureItem" ], - "ShipId": { "$oid": "removed" }, "Rooms": [ { "Name": "AlchemyRoom", "MaxCapacity": 1600 }, { "Name": "BridgeRoom", "MaxCapacity": 1600 }, @@ -27,6 +26,7 @@ { "Name": "ApartmentRoomC", "MaxCapacity": 1600 }, { "Name": "DuviriHallway", "MaxCapacity": 1600 } ], - "FavouriteLoadouts": [] + "FavouriteLoadouts": [], + "Gardening": [] } } diff --git a/static/fixed_responses/shipDecorations.json b/static/fixed_responses/shipDecorations.json new file mode 100644 index 00000000..82baf31b --- /dev/null +++ b/static/fixed_responses/shipDecorations.json @@ -0,0 +1,18 @@ +[ + { + "ItemCount": 1, + "ItemType": "/Lotus/Types/Items/ShipDecos/Vignettes/Warframes/WarframeAFItem" + }, + { + "ItemCount": 1, + "ItemType": "/Lotus/Types/Items/ShipDecos/KavatBust" + }, + { + "ItemCount": 1, + "ItemType": "/Lotus/Types/Items/ShipDecos/Plushies/PlushyTiger" + }, + { + "ItemCount": 1, + "ItemType": "/Lotus/Types/Items/ShipDecos/Venus/PrideCommunityDisplay" + } +]