feat: HarvestAll
All checks were successful
Build / build (pull_request) Successful in 44s
Build / build (push) Successful in 1m36s

This commit is contained in:
Sainan 2025-04-26 01:31:14 +02:00
parent bb5b242cf6
commit 804e920bbf
5 changed files with 118 additions and 2 deletions

View File

@ -0,0 +1,84 @@
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { addMiscItem, getInventory } from "@/src/services/inventoryService";
import { toStoreItem } from "@/src/services/itemDataService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { createGarden, getPersonalRooms } from "@/src/services/personalRoomsService";
import { IMongoDate } from "@/src/types/commonTypes";
import { IMissionReward } from "@/src/types/missionTypes";
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
import { IInventoryChanges } from "@/src/types/purchaseTypes";
import { IGardeningClient } from "@/src/types/shipTypes";
import { RequestHandler } from "express";
import { dict_en, ExportResources } from "warframe-public-export-plus";
export const gardeningController: RequestHandler = async (req, res) => {
const data = getJSONfromString<IGardeningRequest>(String(req.body));
if (data.Mode != "HarvestAll") {
throw new Error(`unexpected gardening mode: ${data.Mode}`);
}
const accountId = await getAccountIdForRequest(req);
const [inventory, personalRooms] = await Promise.all([
getInventory(accountId, "MiscItems"),
getPersonalRooms(accountId, "Apartment")
]);
// Harvest plants
const inventoryChanges: IInventoryChanges = {};
const rewards: Record<string, IMissionReward[][]> = {};
for (const planter of personalRooms.Apartment.Gardening.Planters) {
rewards[planter.Name] = [];
for (const plant of planter.Plants) {
const itemType =
"/Lotus/Types/Gameplay/Duviri/Resource/DuviriPlantItem" +
plant.PlantType.substring(plant.PlantType.length - 1);
const itemCount = Math.random() < 0.775 ? 2 : 4;
addMiscItem(inventory, itemType, itemCount, inventoryChanges);
rewards[planter.Name].push([
{
StoreItem: toStoreItem(itemType),
TypeName: itemType,
ItemCount: itemCount,
DailyCooldown: false,
Rarity: itemCount == 2 ? 0.7743589743589744 : 0.22564102564102564,
TweetText: `${itemCount}x ${dict_en[ExportResources[itemType].name]} (Resource)`,
ProductCategory: "MiscItems"
}
]);
}
}
// Refresh garden
personalRooms.Apartment.Gardening = createGarden();
await Promise.all([inventory.save(), personalRooms.save()]);
const planter = personalRooms.Apartment.Gardening.Planters[personalRooms.Apartment.Gardening.Planters.length - 1];
const plant = planter.Plants[planter.Plants.length - 1];
res.json({
GardenTagName: planter.Name,
PlantType: plant.PlantType,
PlotIndex: plant.PlotIndex,
EndTime: toMongoDate(plant.EndTime),
InventoryChanges: inventoryChanges,
Gardening: personalRooms.toJSON<IPersonalRoomsClient>().Apartment.Gardening,
Rewards: rewards
} satisfies IGardeningResponse);
};
interface IGardeningRequest {
Mode: string;
}
interface IGardeningResponse {
GardenTagName: string;
PlantType: string;
PlotIndex: number;
EndTime: IMongoDate;
InventoryChanges: IInventoryChanges;
Gardening: IGardeningClient;
Rewards: Record<string, IMissionReward[][]>;
}

View File

@ -48,6 +48,7 @@ import { findSessionsController } from "@/src/controllers/api/findSessionsContro
import { fishmongerController } from "@/src/controllers/api/fishmongerController";
import { focusController } from "@/src/controllers/api/focusController";
import { fusionTreasuresController } from "@/src/controllers/api/fusionTreasuresController";
import { gardeningController } from "@/src/controllers/api/gardeningController";
import { genericUpdateController } from "@/src/controllers/api/genericUpdateController";
import { getAllianceController } from "@/src/controllers/api/getAllianceController";
import { getDailyDealStockLevelsController } from "@/src/controllers/api/getDailyDealStockLevelsController";
@ -240,6 +241,7 @@ apiRouter.post("/findSessions.php", findSessionsController);
apiRouter.post("/fishmonger.php", fishmongerController);
apiRouter.post("/focus.php", focusController);
apiRouter.post("/fusionTreasures.php", fusionTreasuresController);
apiRouter.post("/gardening.php", gardeningController);
apiRouter.post("/genericUpdate.php", genericUpdateController);
apiRouter.post("/getAlliance.php", getAllianceController);
apiRouter.post("/getFriends.php", getFriendsController);

View File

@ -213,6 +213,15 @@ export const combineInventoryChanges = (InventoryChanges: IInventoryChanges, del
for (const key in delta) {
if (!(key in InventoryChanges)) {
InventoryChanges[key] = delta[key];
} else if (key == "MiscItems") {
for (const deltaItem of delta[key]!) {
const existing = InventoryChanges[key]!.find(x => x.ItemType == deltaItem.ItemType);
if (existing) {
existing.ItemCount += deltaItem.ItemCount;
} else {
InventoryChanges[key]!.push(deltaItem);
}
}
} else if (Array.isArray(delta[key])) {
const left = InventoryChanges[key] as object[];
const right: object[] = delta[key];
@ -1468,6 +1477,22 @@ export const addGearExpByCategory = (
});
};
export const addMiscItem = (
inventory: TInventoryDatabaseDocument,
type: string,
count: number,
inventoryChanges: IInventoryChanges
): void => {
const miscItemChanges: IMiscItem[] = [
{
ItemType: type,
ItemCount: count
}
];
addMiscItems(inventory, miscItemChanges);
combineInventoryChanges(inventoryChanges, { MiscItems: miscItemChanges });
};
export const addMiscItems = (inventory: TInventoryDatabaseDocument, itemsArray: IMiscItem[]): void => {
const { MiscItems } = inventory;

View File

@ -4,8 +4,11 @@ import { TPersonalRoomsDatabaseDocument } from "../types/personalRoomsTypes";
import { IGardeningDatabase } from "../types/shipTypes";
import { getRandomElement } from "./rngService";
export const getPersonalRooms = async (accountId: string): Promise<TPersonalRoomsDatabaseDocument> => {
const personalRooms = await PersonalRooms.findOne({ personalRoomsOwnerId: accountId });
export const getPersonalRooms = async (
accountId: string,
projection?: string
): Promise<TPersonalRoomsDatabaseDocument> => {
const personalRooms = await PersonalRooms.findOne({ personalRoomsOwnerId: accountId }, projection);
if (!personalRooms) {
throw new Error(`personal rooms not found for account ${accountId}`);

View File

@ -8,6 +8,8 @@ export interface IMissionReward {
TypeName?: string;
UpgradeLevel?: number;
ItemCount: number;
DailyCooldown?: boolean;
Rarity?: number;
TweetText?: string;
ProductCategory?: string;
FromEnemyCache?: boolean;