Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mission rewards save #46

Merged
merged 15 commits into from
Aug 31, 2023
Merged
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
/.env
/static/data/*.bin
yarn.lock
/tmp
57 changes: 56 additions & 1 deletion src/controllers/api/missionInventoryUpdateController.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,61 @@
import { RequestHandler } from "express";
import { missionInventoryUpdate } from "@/src/services/inventoryService";
import { MissionInventoryUpdate } from "@/src/types/missionInventoryUpdateType";
/*
- [ ] crossPlaySetting
- [ ] rewardsMultiplier
- [ ] ActiveBoosters
- [x] LongGuns
- [x] Pistols
- [x] Suits
- [x] Melee
- [x] RawUpgrades
- [x] MiscItems
- [x] RegularCredits
- [ ] RandomUpgradesIdentified
- [ ] MissionFailed
- [ ] MissionStatus
- [ ] CurrentLoadOutIds
- [ ] AliveTime
- [ ] MissionTime
- [ ] Missions
- [ ] CompletedAlerts
- [ ] LastRegionPlayed
- [ ] GameModeId
- [ ] hosts
- [x] ChallengeProgress
- [ ] SeasonChallengeHistory
- [ ] PS
- [ ] ActiveDojoColorResearch
- [ ] RewardInfo
- [ ] ReceivedCeremonyMsg
- [ ] LastCeremonyResetDate
- [ ] MissionPTS
- [ ] RepHash
- [ ] EndOfMatchUpload
- [ ] ObjectiveReached
- [ ] FpsAvg
- [ ] FpsMin
- [ ] FpsMax
- [ ] FpsSamples
*/

const missionInventoryUpdateController: RequestHandler = (_req, res) => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const missionInventoryUpdateController: RequestHandler = async (req, res) => {
const [data] = String(req.body).split("\n");
const id = req.query.accountId as string;

// TODO - salt check

try {
const parsedData = JSON.parse(data) as MissionInventoryUpdate;
if (typeof parsedData !== "object" || parsedData === null) throw new Error("Invalid data format");
await missionInventoryUpdate(parsedData, id);
} catch (err) {
console.error("Error parsing JSON data:", err);
}

// TODO - get original response
res.json({});
};

Expand Down
7 changes: 7 additions & 0 deletions src/controllers/stats/viewController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { RequestHandler } from "express";

const viewController: RequestHandler = (_req, res) => {
res.json({});
};

export { viewController };
12 changes: 10 additions & 2 deletions src/models/inventoryModel.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Model, Schema, Types, model } from "mongoose";
import { FlavourItem, IInventoryDatabase } from "../types/inventoryTypes/inventoryTypes";
import { FlavourItem, RawUpgrade, MiscItem, IInventoryDatabase, Booster } from "../types/inventoryTypes/inventoryTypes";
import { Oid } from "../types/commonTypes";
import { ISuitDatabase, ISuitDocument } from "@/src/types/inventoryTypes/SuitTypes";
import { IWeaponDatabase } from "@/src/types/inventoryTypes/weaponTypes";
Expand Down Expand Up @@ -66,6 +66,11 @@ const WeaponSchema = new Schema({
UnlockLevel: Number
});

const BoosterSchema = new Schema({
ExpiryDate: Number,
ItemType: String
});

WeaponSchema.set("toJSON", {
transform(_document, returnedObject) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
Expand Down Expand Up @@ -213,7 +218,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
LoreFragmentScans: [Schema.Types.Mixed],
EquippedEmotes: [String],
PendingTrades: [Schema.Types.Mixed],
Boosters: [Schema.Types.Mixed],
Boosters: [BoosterSchema],
ActiveDojoColorResearch: String,
SentientSpawnChanceBoosters: Schema.Types.Mixed,
Affiliations: [Schema.Types.Mixed],
Expand Down Expand Up @@ -334,6 +339,9 @@ type InventoryDocumentProps = {
Pistols: Types.DocumentArray<IWeaponDatabase>;
Melee: Types.DocumentArray<IWeaponDatabase>;
FlavourItems: Types.DocumentArray<FlavourItem>;
RawUpgrades: Types.DocumentArray<RawUpgrade>;
MiscItems: Types.DocumentArray<MiscItem>;
Boosters: Types.DocumentArray<Booster>;
};

type InventoryModelType = Model<IInventoryDatabase, {}, InventoryDocumentProps>;
Expand Down
4 changes: 4 additions & 0 deletions src/routes/stats.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { viewController } from "../controllers/api/viewController";
import { uploadController } from "@/src/controllers/stats/uploadController";

import express from "express";

const statsRouter = express.Router();

statsRouter.get("/view.php", viewController);
statsRouter.post("/upload.php", uploadController);

export { statsRouter };
101 changes: 100 additions & 1 deletion src/services/inventoryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import { Types } from "mongoose";
import { ISuitResponse } from "@/src/types/inventoryTypes/SuitTypes";
import { SlotType } from "@/src/types/purchaseTypes";
import { IWeaponResponse } from "@/src/types/inventoryTypes/weaponTypes";
import { FlavourItem } from "@/src/types/inventoryTypes/inventoryTypes";
import { ChallengeProgress, FlavourItem, IInventoryDatabaseDocument } from "@/src/types/inventoryTypes/inventoryTypes";
import {
MissionInventoryUpdate,
MissionInventoryUpdateCard,
MissionInventoryUpdateGear,
MissionInventoryUpdateItem
} from "../types/missionInventoryUpdateType";

const createInventory = async (accountOwnerId: Types.ObjectId) => {
try {
Expand Down Expand Up @@ -106,4 +112,97 @@ export const addCustomization = async (customizatonName: string, accountId: stri
return changedInventory.FlavourItems[flavourItemIndex].toJSON(); //mongoose bug forces as FlavourItem
};

const addGearExpByCategory = (
inventory: IInventoryDatabaseDocument,
gearArray: MissionInventoryUpdateGear[] | undefined,
categoryName: "Pistols" | "LongGuns" | "Melee" | "Suits"
) => {
const category = inventory[categoryName];

gearArray?.forEach(({ ItemId, XP }) => {
const itemIndex = category.findIndex(i => i._id?.equals(ItemId.$oid));
const item = category[itemIndex];

if (itemIndex !== -1 && item.XP != undefined) {
item.XP += XP;
inventory.markModified(`${categoryName}.${itemIndex}.XP`);
}
});
};

const addItemsByCategory = (
inventory: IInventoryDatabaseDocument,
itemsArray: (MissionInventoryUpdateItem | MissionInventoryUpdateCard)[] | undefined,
categoryName: "RawUpgrades" | "MiscItems"
) => {
const category = inventory[categoryName];

itemsArray?.forEach(({ ItemCount, ItemType }) => {
const itemIndex = category.findIndex(i => i.ItemType === ItemType);

if (itemIndex !== -1) {
category[itemIndex].ItemCount += ItemCount;
inventory.markModified(`${categoryName}.${itemIndex}.ItemCount`);
} else {
category.push({ ItemCount, ItemType });
}
});
};

const addChallenges = (inventory: IInventoryDatabaseDocument, itemsArray: ChallengeProgress[] | undefined) => {
const category = inventory.ChallengeProgress;

itemsArray?.forEach(({ Name, Progress }) => {
const itemIndex = category.findIndex(i => i.Name === Name);

if (itemIndex !== -1) {
category[itemIndex].Progress += Progress;
inventory.markModified(`ChallengeProgress.${itemIndex}.ItemCount`);
} else {
category.push({ Name, Progress });
}
});
};

const gearKeys = ["Suits", "Pistols", "LongGuns", "Melee"] as const;
type GearKeysType = (typeof gearKeys)[number];

export const missionInventoryUpdate = async (data: MissionInventoryUpdate, accountId: string): Promise<void> => {
const { RawUpgrades, MiscItems, RegularCredits, ChallengeProgress } = data;
const inventory = await getInventory(accountId);

// TODO - multipliers logic
// credits
inventory.RegularCredits += RegularCredits || 0;

// gear exp
gearKeys.forEach((key: GearKeysType) => addGearExpByCategory(inventory, data[key], key));

// other
addItemsByCategory(inventory, RawUpgrades, "RawUpgrades"); // TODO - check mods fusion level
addItemsByCategory(inventory, MiscItems, "MiscItems");
addChallenges(inventory, ChallengeProgress);

await inventory.save();
};

export const addBooster = async (ItemType: string, time: number, accountId: string): Promise<void> => {
const currentTime = Math.floor(Date.now() / 1000) - 129600; // booster time getting more without 129600, probably defence logic, idk

const inventory = await getInventory(accountId);
const { Boosters } = inventory;

const itemIndex = Boosters.findIndex(i => i.ItemType === ItemType);

if (itemIndex !== -1) {
const existingBooster = Boosters[itemIndex];
existingBooster.ExpiryDate = Math.max(existingBooster.ExpiryDate, currentTime) + time;
inventory.markModified(`Boosters.${itemIndex}.ExpiryDate`);
} else {
Boosters.push({ ItemType, ExpiryDate: currentTime + time }) - 1;
}

await inventory.save();
};

export { createInventory, addPowerSuit };
39 changes: 31 additions & 8 deletions src/services/purchaseService.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import { getWeaponType } from "@/src/helpers/purchaseHelpers";
import { getSubstringFromKeyword } from "@/src/helpers/stringHelpers";
import {
addCustomization,
addPowerSuit,
addWeapon,
updateCurrency,
updateSlots
} from "@/src/services/inventoryService";
import { IPurchaseRequest, IPurchaseResponse, SlotType } from "@/src/types/purchaseTypes";
import { addBooster, addCustomization, addPowerSuit, addWeapon, updateSlots } from "@/src/services/inventoryService";
import { IPurchaseRequest, SlotType } from "@/src/types/purchaseTypes";

export const getStoreItemCategory = (storeItem: string) => {
const storeItemString = getSubstringFromKeyword(storeItem, "StoreItems/");
Expand Down Expand Up @@ -41,6 +35,9 @@ export const handlePurchase = async (purchaseRequest: IPurchaseRequest, accountI
case "Types":
purchaseResponse = await handleTypesPurchase(internalName, accountId);
break;
case "Boosters":
purchaseResponse = await handleBoostersPurchase(internalName, accountId);
break;

default:
throw new Error(`unknown store category: ${storeCategory} not implemented or new`);
Expand Down Expand Up @@ -114,3 +111,29 @@ const handleSuitCustomizationsPurchase = async (customizationName: string, accou
}
};
};

const boosterCollection = [
"/Lotus/Types/Boosters/ResourceAmountBooster",
"/Lotus/Types/Boosters/AffinityBooster",
"/Lotus/Types/Boosters/ResourceDropChanceBooster",
"/Lotus/Types/Boosters/CreditBooster"
];

const handleBoostersPurchase = async (boosterStoreName: string, accountId: string) => {
const match = boosterStoreName.match(/(\d+)Day/);
if (!match) return;

const extractedDigit = Number(match[1]);
const ItemType = boosterCollection.find(i =>
boosterStoreName.includes(i.split("/").pop()!.replace("Booster", ""))
)!;
const ExpiryDate = extractedDigit * 86400;

await addBooster(ItemType, ExpiryDate, accountId);

return {
InventoryChanges: {
Boosters: [{ ItemType, ExpiryDate }]
}
};
};
8 changes: 6 additions & 2 deletions src/types/inventoryTypes/SuitTypes.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { Oid } from "@/src/types/commonTypes";
import { AbilityOverride, Color, Polarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { Document } from "mongoose";
import { Document, Types } from "mongoose";

export interface ISuitDocument extends ISuitResponse, Document {}
// export interface ISuitDocument extends ISuitResponse, Document {}
export interface ISuitDocument extends Document, ISuitResponse {
_id: Types.ObjectId;
}

export interface ISuitResponse extends ISuitDatabase {
ItemId: Oid;
Expand All @@ -20,6 +23,7 @@ export interface ISuitDatabase {
ModSlotPurchases?: number;
FocusLens?: string;
UnlockLevel?: number;
_id: Types.ObjectId;
}

export interface SuitConfig {
Expand Down
12 changes: 11 additions & 1 deletion src/types/inventoryTypes/inventoryTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,16 @@ export interface FlavourItem {
ItemType: string;
}

export interface RawUpgrade {
ItemCount: number;
ItemType: string;
}

export interface MiscItem {
ItemCount: number;
ItemType: string;
}

export interface CrewshipWeapon {
PILOT: Pilot;
PORT_GUNS: PortGuns;
Expand Down Expand Up @@ -919,7 +929,7 @@ export interface Progress {

export interface RawUpgrade {
ItemCount: number;
LastAdded: Oid;
LastAdded?: Oid;
ItemType: string;
}

Expand Down
2 changes: 2 additions & 0 deletions src/types/inventoryTypes/weaponTypes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Oid } from "@/src/types/commonTypes";
import { Color, Polarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { Types } from "mongoose";

export interface IWeaponResponse extends IWeaponDatabase {
ItemId: Oid;
Expand All @@ -20,6 +21,7 @@ export interface IWeaponDatabase {
ItemName?: string;
ModularParts?: string[];
UnlockLevel?: number;
_id?: Types.ObjectId;
}

export interface WeaponConfig {
Expand Down
Loading