saveLoadout working: missing some types

This commit is contained in:
Ordis 2023-12-07 00:42:07 +01:00
parent 36e76a9a84
commit 79c58f2558
17 changed files with 559 additions and 473 deletions

View File

@ -1,10 +1,14 @@
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;

View File

@ -31,7 +31,7 @@ const inventoryController: RequestHandler = async (request: Request, response: R
if (config.testMission) inventoryResponse.Missions = testMissions;
if (config.testQuestKey) inventoryResponse.QuestKeys = testQuestKeys;
inventoryResponse.DuviriInfo = { Seed: -5049874987509758080, NumCompletions: 0 };
inventoryResponse.DuviriInfo = { Seed: -123123123123123123, NumCompletions: 0 };
response.json(inventoryResponse);
};

View File

@ -1,147 +1,19 @@
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
import { RequestHandler } from "express";
import util from "util";
import {
EquipmentCategories,
IConfigEntry,
ILoadoutRequest,
ILoadoutKey,
ISaveLoadoutRequest,
ISaveLoadoutRequestNoUpgradeVer,
ILoadoutConfigDatabase
} from "@/src/types/saveLoadoutTypes";
import { LoadoutModel } from "@/src/models/inventoryModels/loadoutModel";
import { Types } from "mongoose";
export const isEmptyObject = (obj: unknown): boolean => {
return Boolean(obj && Object.keys(obj).length === 0 && obj.constructor === Object);
};
//setup default items on account creation or like originally in giveStartingItems.php
//export const updateLoadout = (loadout: ISaveLoadoutRequest, accountId: string) => {};
export const handleInventoryItemConfigChange = async (equipmentChanges: ISaveLoadoutRequestNoUpgradeVer) => {
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 "LoadOuts": {
console.log("loadout received");
for (const [_loadoutSlot, _loadout] of Object.entries(equipment)) {
const loadoutSlot = _loadoutSlot as keyof ILoadoutRequest;
const loadout = _loadout as ILoadoutKey;
//console.log("key", loadoutSlot, "value", loadout);
if (isEmptyObject(loadout)) {
continue;
}
// all non-empty entries are one loadout slot
for (const [loadoutId, loadoutConfig] of Object.entries(loadout)) {
// console.log("loadoutId", loadoutId, "loadoutconfig", loadoutConfig);
const loadout = await LoadoutModel.findById("656a184a9cefa0e5627689af");
if (!loadout) {
throw new Error("loadout not found");
}
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
});
await loadout.save();
continue;
}
const loadoutIndex = loadout[loadoutSlot].indexOf(oldLoadoutConfig);
if (loadoutIndex === undefined || loadoutIndex === -1) {
throw new Error("loadout index not found");
}
//console.log("parent id", oldLoadoutConfig.ownerDocument()._id);
loadout[loadoutSlot][loadoutIndex].set(loadoutConfig);
//loadout.NORMAL[loadoutIndex].overwrite(loadoutConfig);
//console.log("db", loadout[loadoutSlot][loadoutIndex].schema);
await loadout.save();
//({ _id: loadoutId }, loadoutConfig);
}
}
break;
}
case "LongGuns": {
console.log("longgun received");
console.log(equipmentName, equipment);
const longGun = equipment as IConfigEntry;
// longGun["key"].PvpUpgrades;
break;
}
case "OperatorAmps":
case "Pistols":
case "Suits":
case "Melee":
case "Sentinels":
case "SentinelWeapons":
case "KubrowPets":
case "SpaceSuits":
case "SpaceGuns":
case "SpaceMelee":
case "Scoops":
case "SpecialItems":
case "MoaPets":
case "Hoverboards":
case "DataKnives":
case "MechSuits":
case "CrewShipHarnesses":
case "Horses":
case "DrifterMelee":
case "OperatorLoadOuts":
case "AdultOperatorLoadOuts":
case "KahlLoadOuts":
case "CrewShips":
default: {
console.log("category not implemented", equipmentName);
}
}
// Object.keys(value).forEach(element => {
// console.log("name of inner objects keys", element);
// });
// for (const innerValue of Object.values(value)) {
// console.log(innerValue);
// }
// console.log(innerObjects);
// if (isObjectEmpty(innerObjects)) {
// console.log(innerObjects, "is empty");
// }
}
};
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) => {
//validate here
const accountId = parseString(req.query.accountId);
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;
handleInventoryItemConfigChange(equipmentChanges);
await handleInventoryItemConfigChange(equipmentChanges, accountId);
res.status(200).end();
};

View File

@ -7,176 +7,206 @@ import {
IBooster,
IInventoryResponse,
IInventoryDatabaseDocument,
IInventoryResponseDocument
ISlots
} from "../../types/inventoryTypes/inventoryTypes";
import { IMongoDate, IOid } from "../../types/commonTypes";
import { ISuitDatabase, ISuitDocument } from "@/src/types/inventoryTypes/SuitTypes";
import {
IItemConfig,
ISuitDatabase,
IOperatorConfigClient,
IOperatorConfigDatabase
} from "@/src/types/inventoryTypes/SuitTypes";
import { IWeaponDatabase } from "@/src/types/inventoryTypes/weaponTypes";
import { IAbilityOverride, IColor, IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
const abilityOverrideSchema = new Schema({
const polaritySchema = new Schema<IPolarity>({
Slot: Number,
Value: String
});
const abilityOverrideSchema = new Schema<IAbilityOverride>({
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<IColor>(
{
t0: Number,
t1: Number,
t2: Number,
t3: Number,
en: Number,
e1: Number,
m0: Number,
m1: Number
},
{ _id: false }
);
const operatorConfigSchema = new Schema<IOperatorConfigDatabase>(
{
Skins: [String],
pricol: colorSchema,
attcol: colorSchema,
sigcol: colorSchema,
eyecol: colorSchema,
facial: colorSchema,
syancol: 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<IItemConfig>(
{
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<IWeaponDatabase>(
{
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<IBooster>({
ExpiryDate: Number,
ItemType: String
});
const RawUpgrades = new Schema<IRawUpgrade>({
ItemType: String,
ItemCount: Number
});
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: validate 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<ISuitDatabase>({
ItemType: String,
Configs: {
type: [suitConfigSchema],
default: [{}, {}, {}]
//TODO: reduce weapon and suit schemas to one schema if reasonable
const suitSchema = new Schema<ISuitDatabase>(
{
ItemType: String,
Configs: [ItemConfigSchema],
UpgradeVer: Number,
XP: Number,
InfestationDate: Date,
Features: Number,
Polarity: [polaritySchema],
Polarized: Number,
ModSlotPurchases: Number,
FocusLens: String,
UnlockLevel: Number
},
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<ISlots>(
{
Slots: Number
},
@ -305,7 +335,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
BountyScore: Number,
ChallengeInstanceStates: [Schema.Types.Mixed],
LoginMilestoneRewards: [String],
OperatorLoadOuts: [Schema.Types.Mixed],
OperatorLoadOuts: [operatorConfigSchema],
DailyAffiliationVentkids: Number,
DailyAffiliationVox: Number,
RecentVendorPurchases: [Schema.Types.Mixed],
@ -342,7 +372,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
CrewShipHarnesses: [Schema.Types.Mixed],
CrewShipRawSalvage: [Schema.Types.Mixed],
CrewMembers: [Schema.Types.Mixed],
AdultOperatorLoadOuts: [Schema.Types.Mixed],
AdultOperatorLoadOuts: [operatorConfigSchema],
LotusCustomization: Schema.Types.Mixed,
UseAdultOperatorLoadout: Boolean,
DailyAffiliationZariman: Number,
@ -363,7 +393,10 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
HasResetAccount: Boolean,
PendingCoupon: Schema.Types.Mixed,
Harvestable: Boolean,
DeathSquadable: Boolean
DeathSquadable: Boolean,
Horses: [Schema.Types.Mixed],
DrifterMelee: [Schema.Types.Mixed],
KahlLoadOuts: [Schema.Types.Mixed]
});
inventorySchema.set("toJSON", {
@ -390,9 +423,11 @@ type InventoryDocumentProps = {
RawUpgrades: Types.DocumentArray<IRawUpgrade>;
MiscItems: Types.DocumentArray<IMiscItem>;
Boosters: Types.DocumentArray<IBooster>;
OperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>;
AdultOperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>;
};
type InventoryModelType = Model<IInventoryDatabase, object, InventoryDocumentProps>;
type InventoryModelType = Model<IInventoryDatabase, {}, InventoryDocumentProps>;
const Inventory = model<IInventoryDatabase, InventoryModelType>("Inventory", inventorySchema);

View File

@ -53,7 +53,7 @@ loadoutConfigSchema.set("toJSON", {
}
});
const loadoutSchema = new Schema<ILoadoutDatabase, loadoutModelType>({
export const loadoutSchema = new Schema<ILoadoutDatabase, loadoutModelType>({
NORMAL: [loadoutConfigSchema],
SENTINEL: [loadoutConfigSchema],
ARCHWING: [loadoutConfigSchema],
@ -64,18 +64,15 @@ const loadoutSchema = new Schema<ILoadoutDatabase, loadoutModelType>({
DATAKNIFE: [loadoutConfigSchema],
MECH: [loadoutConfigSchema],
OPERATOR_ADULT: [loadoutConfigSchema],
DRIFTER: [loadoutConfigSchema]
});
loadoutSchema.virtual("ItemId").get(function (): string {
return this._id.toString();
DRIFTER: [loadoutConfigSchema],
loadoutOwnerId: Schema.Types.ObjectId
});
loadoutSchema.set("toJSON", {
virtuals: true,
transform(_doc, ret, _options) {
delete ret._id;
delete ret.__v;
delete ret.loadoutOwnerId;
}
});

View File

@ -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<IShip>({
ShipOwnerId: Schema.Types.ObjectId,
Ship: shipSchema,
Apartment: apartmentSchema
Apartment: apartmentSchema,
LoadOutInventory: {
LoadOutPresets: {
type: Schema.Types.ObjectId,
ref: "Loadout"
}
}
});
shipDatabaseSchema.set("toJSON", {

View File

@ -2,9 +2,9 @@ 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) => {
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,7 +53,7 @@ export const getInventory = async (accountOwnerId: string) => {
return inventory;
};
const addPowerSuit = async (powersuitName: string, accountId: string): Promise<ISuitResponse> => {
const addPowerSuit = async (powersuitName: string, accountId: string): Promise<ISuitClient> => {
const inventory = await getInventory(accountId);
const suitIndex = inventory.Suits.push({ ItemType: powersuitName, Configs: [], UpgradeVer: 101, XP: 0 });
const changedInventory = await inventory.save();
@ -107,7 +112,7 @@ export const addWeapon = async (
weaponType: WeaponTypeInternal,
weaponName: string,
accountId: string
): Promise<IWeaponResponse> => {
): Promise<IWeaponClient> => {
const inventory = await getInventory(accountId);
let weaponIndex;
@ -139,7 +144,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 +247,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 +260,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);

View File

@ -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;
};

View File

@ -0,0 +1,179 @@
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);
};
//setup default items on account creation or like originally in giveStartingItems.php
//export const updateLoadout = (loadout: ISaveLoadoutRequest, accountId: string) => {};
//support multiple loadouts and multiple items and multiple configs per item
export const handleInventoryItemConfigChange = async (
equipmentChanges: ISaveLoadoutRequestNoUpgradeVer,
accountId: string
) => {
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": {
console.log("loadout received", equipmentName);
const inventory = await getInventory(accountId);
const operatorConfig = equipment as IOperatorConfigEntry;
const operatorLoadout = inventory[equipmentName];
// 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
});
await inventory.save();
continue;
}
loadout.set(loadoutConfig);
//({ _id: loadoutId }, loadoutConfig);
}
await inventory.save();
break;
}
case "LoadOuts": {
console.log("loadout received");
for (const [_loadoutSlot, _loadout] of Object.entries(equipment)) {
const loadoutSlot = _loadoutSlot as keyof ILoadoutClient;
const newLoadout = _loadout as ILoadoutEntry;
//console.log("key", loadoutSlot, "value", loadout);
// empty loadout slot like: "NORMAL": {}
if (isEmptyObject(newLoadout)) {
continue;
}
const loadout = await LoadoutModel.findOne({ loadoutOwnerId: accountId });
//const {, ...loadout } = loadoutWithLoadoutOwnerId;
if (!loadout) {
throw new Error("loadout not found");
}
// all non-empty entries are one loadout slot
for (const [loadoutId, loadoutConfig] of Object.entries(newLoadout)) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
//const { loadoutOwnerId, ...loadout } = loadoutWithLoadoutOwnerId;
// console.log("loadoutId", loadoutId, "loadoutconfig", loadoutConfig);
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
});
await loadout.save();
continue;
}
const loadoutIndex = loadout[loadoutSlot].indexOf(oldLoadoutConfig);
if (loadoutIndex === undefined || loadoutIndex === -1) {
throw new Error("loadout index not found");
}
//console.log("parent id", oldLoadoutConfig.ownerDocument()._id);
loadout[loadoutSlot][loadoutIndex].set(loadoutConfig);
//loadout.NORMAL[loadoutIndex].overwrite(loadoutConfig);
//console.log("db", loadout[loadoutSlot][loadoutIndex].schema);
await loadout.save();
//({ _id: loadoutId }, loadoutConfig);
}
}
break;
}
case "LongGuns":
case "Pistols":
case "Suits":
case "Melee": {
console.log("? ???? ?", equipmentName, equipment);
const itemEntry = equipment as IItemEntry;
const inventory = await getInventory(accountId);
for (const [itemId, itemConfig] of Object.entries(itemEntry)) {
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(itemConfig)) {
inventoryItem.Configs[parseInt(configId)] = config;
}
}
await inventory.save();
break;
}
case "CurrentLoadOutIds": {
//TODO: remove duplicate getInventory after finding out when currentloadOutId is sent
const loadoutIds = equipment as IOid[];
const inventory = await getInventory(accountId);
inventory.CurrentLoadOutIds = loadoutIds;
await inventory.save();
break;
}
default: {
console.log("category not implemented", equipmentName);
}
}
//case "OperatorAmps":
// case "Sentinels":
// case "SentinelWeapons":
// case "KubrowPets":
// case "SpaceSuits":
// case "SpaceGuns":
// case "SpaceMelee":
// case "Scoops":
// case "SpecialItems":
// case "MoaPets":
// case "Hoverboards":
// case "DataKnives":
// case "MechSuits":
// case "CrewShipHarnesses":
// case "Horses":
// case "DrifterMelee":
// case "CrewShips":
//case "KahlLoadOuts": not sure yet how to handle kahl: it is not sent in inventory
}
};

View File

@ -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) {

View File

@ -1,20 +1,14 @@
import { IOid } from "@/src/types/commonTypes";
import { IAbilityOverride, IColor, IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { Document, Types } from "mongoose";
import { Types } from "mongoose";
// 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;
//should omit _id which is not present in response
}
export interface ISuitDatabase {
ItemType: string;
Configs: SuitConfig[];
Configs: IItemConfig[];
UpgradeVer?: number;
XP?: number;
InfestationDate?: Date;
@ -25,26 +19,43 @@ export interface ISuitDatabase {
FocusLens?: string;
UnlockLevel?: number;
_id: Types.ObjectId;
ItemId?: IOid;
}
export interface SuitConfig {
Skins?: string[];
interface IItemConfigBase {
Skins: string[];
pricol?: IColor;
attcol?: IColor;
eyecol?: IColor;
sigcol?: IColor;
eyecol?: IColor;
facial?: IColor;
syancol?: IColor;
cloth?: IColor;
Upgrades?: string[];
Songs?: Song[];
Name?: string;
ugly?: boolean;
}
export interface IItemConfig extends IItemConfigBase {
Songs?: ISong[];
AbilityOverride?: IAbilityOverride;
PvpUpgrades?: string[];
ugly?: boolean;
}
export interface Song {
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<IOperatorConfigDatabase, "_id"> {
ItemId: IOid;
}

View File

@ -2,19 +2,33 @@
import { Document, Types } from "mongoose";
import { IOid, IMongoDate } from "../commonTypes";
import { IAbilityOverride, IColor, FocusSchool, IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes";
import { IOperatorConfigClient, ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes";
import { IOperatorLoadOutSigcol, IWeaponDatabase } from "@/src/types/inventoryTypes/weaponTypes";
import { IItemConfig } from "@/src/types/saveLoadoutTypes";
//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"> {
export interface IInventoryDatabase extends Omit<IInventoryResponse, "TrainingDate" | "LoadOutPresets"> {
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
}
export interface IInventoryResponseDocument extends IInventoryResponse, Document {}
export interface IGenericItem {
ItemType: string;
XP?: number;
Configs: IItemConfig[];
UpgradeVer: number;
ItemId: IOid;
}
export interface IInventoryResponse {
DuviriInfo: { Seed: number; NumCompletions: number };
KahlLoadOuts: IGenericItem[];
DrifterMelee: IGenericItem[];
Horses: IGenericItem[];
DuviriInfo: { Seed: number; NumCompletions: number }; // TODO: add to schema
SubscribedToEmails: number;
Created: IMongoDate;
RewardSeed: number;
@ -22,14 +36,14 @@ export interface IInventoryResponse {
PremiumCredits: number;
PremiumCreditsFree: number;
FusionPoints: number;
SuitBin: ICrewShipSalvageBinClass;
WeaponBin: ICrewShipSalvageBinClass;
SentinelBin: ICrewShipSalvageBinClass;
SpaceSuitBin: ICrewShipSalvageBinClass;
SpaceWeaponBin: ICrewShipSalvageBinClass;
SuitBin: ISlots;
WeaponBin: ISlots;
SentinelBin: ISlots;
SpaceSuitBin: ISlots;
SpaceWeaponBin: ISlots;
PvpBonusLoadoutBin: ICrewMemberBinClass;
PveBonusLoadoutBin: ICrewShipSalvageBinClass;
RandomModBin: ICrewShipSalvageBinClass;
PveBonusLoadoutBin: ISlots;
RandomModBin: ISlots;
TradesRemaining: number;
DailyAffiliation: number;
DailyAffiliationPvp: number;
@ -103,7 +117,7 @@ export interface IInventoryResponse {
ActiveAvatarImageType: string;
KubrowPets: IKubrowPet[];
ShipDecorations: IConsumable[];
OperatorAmpBin: ICrewShipSalvageBinClass;
OperatorAmpBin: ISlots;
DailyAffiliationCetus: number;
DailyAffiliationQuills: number;
DiscoveredMarkers: IDiscoveredMarker[];
@ -124,7 +138,7 @@ export interface IInventoryResponse {
BountyScore: number;
ChallengeInstanceStates: IChallengeInstanceState[];
LoginMilestoneRewards: string[];
OperatorLoadOuts: IOperatorLoadOut[];
OperatorLoadOuts: IOperatorConfigClient[];
DailyAffiliationVentkids: number;
DailyAffiliationVox: number;
RecentVendorPurchases: Array<number | string>;
@ -141,7 +155,7 @@ export interface IInventoryResponse {
Settings: ISettings;
PersonalTechProjects: IPersonalTechProject[];
CrewShips: ICrewShip[];
CrewShipSalvageBin: ICrewShipSalvageBinClass;
CrewShipSalvageBin: ISlots;
PlayerSkills: IPlayerSkills;
CrewShipAmmo: IConsumable[];
CrewShipSalvagedWeaponSkins: ICrewShipSalvagedWeaponSkin[];
@ -161,7 +175,7 @@ export interface IInventoryResponse {
CrewShipHarnesses: ICrewShipHarness[];
CrewShipRawSalvage: IConsumable[];
CrewMembers: ICrewMember[];
AdultOperatorLoadOuts: IAdultOperatorLoadOut[];
AdultOperatorLoadOuts: IOperatorConfigClient[];
LotusCustomization: ILotusCustomization;
UseAdultOperatorLoadout: boolean;
DailyAffiliationZariman: number;
@ -311,8 +325,8 @@ export interface ICrewShipHarnessConfig {
Upgrades?: string[];
}
export interface ICrewShipSalvageBinClass {
Extra: number;
export interface ISlots {
Extra?: number;
Slots: number;
}
@ -624,6 +638,7 @@ export interface ILibraryPersonalProgress {
Completed: boolean;
}
//this needs to be checked against ILoadoutDatabase
export interface ILoadOutPresets {
NORMAL: INormal[];
NORMAL_PVP: IArchwing[];
@ -871,7 +886,7 @@ export enum GivingSlotOrderInfo {
LotusUpgradesModsPistolDualStatElectEventPistolMod = "/Lotus/Upgrades/Mods/Pistol/DualStat/ElectEventPistolMod"
}
export interface PeriodicMissionCompletion {
export interface IPeriodicMissionCompletion {
date: IMongoDate;
tag: string;
count?: number;

View File

@ -1,14 +1,15 @@
import { IOid } from "@/src/types/commonTypes";
import { IColor, IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { IItemConfig } from "@/src/types/inventoryTypes/SuitTypes";
import { IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { Types } from "mongoose";
export interface IWeaponResponse extends IWeaponDatabase {
export interface IWeaponClient extends Omit<IWeaponDatabase, "_id"> {
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 {

View File

@ -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[];

View File

@ -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[];

View File

@ -1,64 +1,76 @@
import { IOid } from "@/src/types/commonTypes";
import { Document, Mongoose, Types } from "mongoose";
import { IItemConfig, IOperatorConfigClient } from "@/src/types/inventoryTypes/SuitTypes";
import { Types } from "mongoose";
export interface ISaveLoadoutRequest {
LoadOuts: ILoadoutRequest;
LongGuns: IConfigEntry;
OperatorAmps: IConfigEntry;
Pistols: IConfigEntry;
Suits: IConfigEntry;
Melee: IConfigEntry;
Sentinels: IConfigEntry;
SentinelWeapons: IConfigEntry;
KubrowPets: IConfigEntry;
SpaceSuits: IConfigEntry;
SpaceGuns: IConfigEntry;
SpaceMelee: IConfigEntry;
Scoops: IConfigEntry;
SpecialItems: IConfigEntry;
MoaPets: IConfigEntry;
Hoverboards: IConfigEntry;
DataKnives: IConfigEntry;
MechSuits: IConfigEntry;
CrewShipHarnesses: IConfigEntry;
Horses: IConfigEntry;
DrifterMelee: IConfigEntry;
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: IConfigEntry;
AdultOperatorLoadOuts: IConfigEntry;
KahlLoadOuts: IConfigEntry;
CrewShips: IConfigEntry;
OperatorLoadOuts: IOperatorConfigEntry;
AdultOperatorLoadOuts: IOperatorConfigEntry;
KahlLoadOuts: IItemEntry;
CrewShips: IItemEntry;
CurrentLoadOutIds: IOid[];
ValidNewLoadoutId: string;
}
export interface ISaveLoadoutRequestNoUpgradeVer extends Omit<ISaveLoadoutRequest, "UpgradeVer"> {}
export interface IOperatorConfigEntry {
[configId: string]: IOperatorConfigClient;
}
export interface IItemEntry {
[itemId: string]: IConfigEntry;
}
export interface IConfigEntry {
[key: string]: Config;
[configId: string]: IItemConfig;
}
export interface ILoadoutRequest extends Omit<ILoadoutDatabase, "_id"> {}
export interface ILoadoutResponse extends ILoadoutDatabase {
ItemId: IOid;
}
export interface ILoadoutClient extends Omit<ILoadoutDatabase, "_id" | "loadoutOwnerId"> {}
export interface ILoadoutDatabase {
NORMAL: ILoadoutConfigDatabase;
SENTINEL: ILoadoutConfigDatabase;
ARCHWING: ILoadoutConfigDatabase;
NORMAL_PVP: ILoadoutConfigDatabase;
LUNARO: ILoadoutConfigDatabase;
OPERATOR: ILoadoutConfigDatabase;
KDRIVE: ILoadoutConfigDatabase;
DATAKNIFE: ILoadoutConfigDatabase;
MECH: ILoadoutConfigDatabase;
OPERATOR_ADULT: ILoadoutConfigDatabase;
DRIFTER: ILoadoutConfigDatabase;
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 ILoadoutKey {
export interface ILoadoutEntry {
[key: string]: ILoadoutConfigClient;
}
export interface ILoadoutConfigDatabase extends Omit<ILoadoutConfigClient, "ItemId"> {
_id: Types.ObjectId;
}
// for request and response from and to client
export interface ILoadoutConfigClient {
@ -72,70 +84,9 @@ export interface ILoadoutConfigClient {
m: IEquipmentSelection;
}
export interface ILoadoutConfigDatabase extends Omit<ILoadoutConfigClient, "ItemId"> {
_id: Types.ObjectId;
}
export interface IEquipmentSelection {
ItemId: IOid;
mod: number;
cus: number;
}
export interface Config {
Upgrades: any[];
PvpUpgrades: any[];
Skins: string[];
pricol: Pricol;
attcol: Pricol;
sigcol: Sigcol;
eyecol: Pricol;
facial: Pricol;
cloth: Pricol;
syancol: Pricol;
Songs: any[];
}
export interface Pricol {
t0: number;
t1: number;
t2: number;
t3: number;
m0: number;
m1: number;
en: number;
}
export interface Sigcol {
t0: number;
t1: number;
m0: number;
en: number;
}
export interface Col {
t0: number;
t1: number;
t2: number;
t3: number;
m0?: number;
m1?: number;
en: number;
e1?: number;
}
export type EquipmentCategories =
| { LoadOuts: { [key in keyof ILoadoutRequest]: LoadOut } }
| { LongGuns: Config }
| { OperatorAmps: Config } // Replace 'any' with the actual type
| { Pistols: Config } // Replace 'any' with the actual type
| { Suits: { [key: string]: Config } }
| { Melee: Config } // Replace 'any' with the actual type
| { Sentinels: Config } // Replace 'any' with the actual type
| { SentinelWeapons: Config } // Replace 'any' with the actual type
// Add other categories based on your needs
| { UpgradeVer: number }
| { OperatorLoadOuts: Config } // Replace 'any' with the actual type
| { AdultOperatorLoadOuts: Config } // Replace 'any' with the actual type
| { KahlLoadOuts: Config } // Replace 'any' with the actual type
| { CrewShips: Config }; // Replace 'any' with the actual type
export { IItemConfig };

View File

@ -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[];
}