From eef87947ce44ae791f075d9eeacc268c8b131044 Mon Sep 17 00:00:00 2001 From: Sainan Date: Tue, 11 Mar 2025 15:57:17 +0100 Subject: [PATCH 1/5] feat: track vendor purchases --- src/models/inventoryModels/inventoryModel.ts | 32 +++++++++++++++- src/services/purchaseService.ts | 40 ++++++++++++++++++++ src/types/inventoryTypes/inventoryTypes.ts | 26 ++++++++++++- 3 files changed, 95 insertions(+), 3 deletions(-) diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index 880dd09e..c7446f41 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -76,7 +76,10 @@ import { IIncentiveState, ISongChallenge, ILibraryPersonalProgress, - ICrewShipWeaponDatabase + ICrewShipWeaponDatabase, + IRecentVendorPurchaseDatabase, + IVendorPurchaseHistoryEntryDatabase, + IVendorPurchaseHistoryEntryClient } from "../../types/inventoryTypes/inventoryTypes"; import { IOid } from "../../types/commonTypes"; import { @@ -974,6 +977,31 @@ const incentiveStateSchema = new Schema( { _id: false } ); +const vendorPurchaseHistoryEntrySchema = new Schema( + { + Expiry: Date, + NumPurchased: Number, + ItemId: String + }, + { _id: false } +); + +vendorPurchaseHistoryEntrySchema.set("toJSON", { + transform(_doc, obj) { + const db = obj as IVendorPurchaseHistoryEntryDatabase; + const client = obj as IVendorPurchaseHistoryEntryClient; + client.Expiry = toMongoDate(db.Expiry); + } +}); + +const recentVendorPurchaseSchema = new Schema( + { + VendorType: String, + PurchaseHistory: [vendorPurchaseHistoryEntrySchema] + }, + { _id: false } +); + const collectibleEntrySchema = new Schema( { CollectibleType: String, @@ -1361,7 +1389,7 @@ const inventorySchema = new Schema( RandomUpgradesIdentified: Number, BountyScore: Number, ChallengeInstanceStates: [Schema.Types.Mixed], - RecentVendorPurchases: [Schema.Types.Mixed], + RecentVendorPurchases: { type: [recentVendorPurchaseSchema], default: undefined }, Robotics: [Schema.Types.Mixed], UsedDailyDeals: [Schema.Types.Mixed], CollectibleSeries: { type: [collectibleEntrySchema], default: undefined }, diff --git a/src/services/purchaseService.ts b/src/services/purchaseService.ts index b153c86c..e300e2c5 100644 --- a/src/services/purchaseService.ts +++ b/src/services/purchaseService.ts @@ -28,6 +28,7 @@ import { import { config } from "./configService"; import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel"; import { fromStoreItem, toStoreItem } from "./itemDataService"; +import { toMongoDate } from "../helpers/inventoryHelpers"; export const getStoreItemCategory = (storeItem: string): string => { const storeItemString = getSubstringFromKeyword(storeItem, "StoreItems/"); @@ -69,6 +70,45 @@ export const handlePurchase = async ( ); } purchaseRequest.PurchaseParams.Quantity *= offer.QuantityMultiplier; + + inventory.RecentVendorPurchases ??= []; + let vendorPurchases = inventory.RecentVendorPurchases.find( + x => x.VendorType == manifest.VendorInfo.TypeName + ); + if (!vendorPurchases) { + vendorPurchases = + inventory.RecentVendorPurchases[ + inventory.RecentVendorPurchases.push({ + VendorType: manifest.VendorInfo.TypeName, + PurchaseHistory: [] + }) - 1 + ]; + } + const expiry = new Date(offer.RotatedWeekly ? Date.now() + 7 * 24 * 3600 * 1000 : 2051240400000); + const historyEntry = vendorPurchases.PurchaseHistory.find(x => x.ItemId == ItemId); + let numPurchased = purchaseRequest.PurchaseParams.Quantity; + if (historyEntry) { + numPurchased += historyEntry.NumPurchased; + historyEntry.NumPurchased += purchaseRequest.PurchaseParams.Quantity; + } else { + vendorPurchases.PurchaseHistory.push({ + ItemId: ItemId, + NumPurchased: purchaseRequest.PurchaseParams.Quantity, + Expiry: expiry + }); + } + inventoryChanges.RecentVendorPurchases = [ + { + VendorType: manifest.VendorInfo.TypeName, + PurchaseHistory: [ + { + ItemId: ItemId, + NumPurchased: numPurchased, + Expiry: toMongoDate(expiry) + } + ] + } + ]; } else if (!ExportVendors[purchaseRequest.PurchaseParams.SourceId!]) { throw new Error(`unknown vendor: ${purchaseRequest.PurchaseParams.SourceId!}`); } diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index af029a34..1e46376c 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -41,6 +41,7 @@ export interface IInventoryDatabase | "KubrowPetEggs" | "PendingCoupon" | "Drones" + | "RecentVendorPurchases" | TEquipmentKey >, InventoryDatabaseEquipment { @@ -67,6 +68,7 @@ export interface IInventoryDatabase KubrowPetEggs?: IKubrowPetEggDatabase[]; PendingCoupon?: IPendingCouponDatabase; Drones: IDroneDatabase[]; + RecentVendorPurchases?: IRecentVendorPurchaseDatabase[]; } export interface IQuestKeyDatabase { @@ -277,7 +279,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu BountyScore: number; ChallengeInstanceStates: IChallengeInstanceState[]; LoginMilestoneRewards: string[]; - RecentVendorPurchases: Array; + RecentVendorPurchases?: IRecentVendorPurchaseClient[]; NodeIntrosCompleted: string[]; GuildId?: IOid; CompletedJobChains: ICompletedJobChain[]; @@ -361,6 +363,28 @@ export interface IParam { v: string; } +export interface IRecentVendorPurchaseClient { + VendorType: string; + PurchaseHistory: IVendorPurchaseHistoryEntryClient[]; +} + +export interface IVendorPurchaseHistoryEntryClient { + Expiry: IMongoDate; + NumPurchased: number; + ItemId: string; +} + +export interface IRecentVendorPurchaseDatabase { + VendorType: string; + PurchaseHistory: IVendorPurchaseHistoryEntryDatabase[]; +} + +export interface IVendorPurchaseHistoryEntryDatabase { + Expiry: Date; + NumPurchased: number; + ItemId: string; +} + export interface IChallengeProgress { Progress: number; Name: string; -- 2.47.2 From 163aeb58ee681cd646abee2270b5695f406cb69d Mon Sep 17 00:00:00 2001 From: Sainan Date: Tue, 11 Mar 2025 16:12:06 +0100 Subject: [PATCH 2/5] feat: noVendorPurchaseLimits cheat --- config.json.example | 1 + src/services/configService.ts | 1 + src/services/purchaseService.ts | 77 +++++++++++++++++---------------- static/webui/index.html | 4 ++ static/webui/translations/de.js | 1 + static/webui/translations/en.js | 1 + static/webui/translations/fr.js | 1 + static/webui/translations/ru.js | 1 + 8 files changed, 49 insertions(+), 38 deletions(-) diff --git a/config.json.example b/config.json.example index d12270ef..8c0305fa 100644 --- a/config.json.example +++ b/config.json.example @@ -29,6 +29,7 @@ "unlockExilusEverywhere": false, "unlockArcanesEverywhere": false, "noDailyStandingLimits": false, + "noVendorPurchaseLimits": false, "instantResourceExtractorDrones": false, "noDojoRoomBuildStage": false, "fastDojoRoomDestruction": false, diff --git a/src/services/configService.ts b/src/services/configService.ts index 07860f93..717dae35 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -55,6 +55,7 @@ interface IConfig { unlockExilusEverywhere?: boolean; unlockArcanesEverywhere?: boolean; noDailyStandingLimits?: boolean; + noVendorPurchaseLimits?: boolean; instantResourceExtractorDrones?: boolean; noDojoRoomBuildStage?: boolean; fastDojoRoomDestruction?: boolean; diff --git a/src/services/purchaseService.ts b/src/services/purchaseService.ts index e300e2c5..2089c645 100644 --- a/src/services/purchaseService.ts +++ b/src/services/purchaseService.ts @@ -70,45 +70,46 @@ export const handlePurchase = async ( ); } purchaseRequest.PurchaseParams.Quantity *= offer.QuantityMultiplier; - - inventory.RecentVendorPurchases ??= []; - let vendorPurchases = inventory.RecentVendorPurchases.find( - x => x.VendorType == manifest.VendorInfo.TypeName - ); - if (!vendorPurchases) { - vendorPurchases = - inventory.RecentVendorPurchases[ - inventory.RecentVendorPurchases.push({ - VendorType: manifest.VendorInfo.TypeName, - PurchaseHistory: [] - }) - 1 - ]; - } - const expiry = new Date(offer.RotatedWeekly ? Date.now() + 7 * 24 * 3600 * 1000 : 2051240400000); - const historyEntry = vendorPurchases.PurchaseHistory.find(x => x.ItemId == ItemId); - let numPurchased = purchaseRequest.PurchaseParams.Quantity; - if (historyEntry) { - numPurchased += historyEntry.NumPurchased; - historyEntry.NumPurchased += purchaseRequest.PurchaseParams.Quantity; - } else { - vendorPurchases.PurchaseHistory.push({ - ItemId: ItemId, - NumPurchased: purchaseRequest.PurchaseParams.Quantity, - Expiry: expiry - }); - } - inventoryChanges.RecentVendorPurchases = [ - { - VendorType: manifest.VendorInfo.TypeName, - PurchaseHistory: [ - { - ItemId: ItemId, - NumPurchased: numPurchased, - Expiry: toMongoDate(expiry) - } - ] + if (!config.noVendorPurchaseLimits) { + inventory.RecentVendorPurchases ??= []; + let vendorPurchases = inventory.RecentVendorPurchases.find( + x => x.VendorType == manifest.VendorInfo.TypeName + ); + if (!vendorPurchases) { + vendorPurchases = + inventory.RecentVendorPurchases[ + inventory.RecentVendorPurchases.push({ + VendorType: manifest.VendorInfo.TypeName, + PurchaseHistory: [] + }) - 1 + ]; } - ]; + const expiry = new Date(offer.RotatedWeekly ? Date.now() + 7 * 24 * 3600 * 1000 : 2051240400000); + const historyEntry = vendorPurchases.PurchaseHistory.find(x => x.ItemId == ItemId); + let numPurchased = purchaseRequest.PurchaseParams.Quantity; + if (historyEntry) { + numPurchased += historyEntry.NumPurchased; + historyEntry.NumPurchased += purchaseRequest.PurchaseParams.Quantity; + } else { + vendorPurchases.PurchaseHistory.push({ + ItemId: ItemId, + NumPurchased: purchaseRequest.PurchaseParams.Quantity, + Expiry: expiry + }); + } + inventoryChanges.RecentVendorPurchases = [ + { + VendorType: manifest.VendorInfo.TypeName, + PurchaseHistory: [ + { + ItemId: ItemId, + NumPurchased: numPurchased, + Expiry: toMongoDate(expiry) + } + ] + } + ]; + } } else if (!ExportVendors[purchaseRequest.PurchaseParams.SourceId!]) { throw new Error(`unknown vendor: ${purchaseRequest.PurchaseParams.SourceId!}`); } diff --git a/static/webui/index.html b/static/webui/index.html index f700994d..bd5f13cc 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -517,6 +517,10 @@ +
+ + +
diff --git a/static/webui/translations/de.js b/static/webui/translations/de.js index 74ec43f4..0a329181 100644 --- a/static/webui/translations/de.js +++ b/static/webui/translations/de.js @@ -110,6 +110,7 @@ dict = { cheats_unlockExilusEverywhere: `Exilus-Adapter überall`, cheats_unlockArcanesEverywhere: `Arkana-Adapter überall`, cheats_noDailyStandingLimits: `Kein tägliches Ansehenslimit`, + cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`, cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`, cheats_noDojoRoomBuildStage: `Kein Dojo-Raum-Bauvorgang`, cheats_fastDojoRoomDestruction: `Schnelle Dojo-Raum-Zerstörung`, diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js index 484b0063..455ab2e4 100644 --- a/static/webui/translations/en.js +++ b/static/webui/translations/en.js @@ -109,6 +109,7 @@ dict = { cheats_unlockExilusEverywhere: `Exilus Adapters Everywhere`, cheats_unlockArcanesEverywhere: `Arcane Adapters Everywhere`, cheats_noDailyStandingLimits: `No Daily Standing Limits`, + cheats_noVendorPurchaseLimits: `No Vendor Purchase Limits`, cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`, cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`, cheats_fastDojoRoomDestruction: `Fast Dojo Room Destruction`, diff --git a/static/webui/translations/fr.js b/static/webui/translations/fr.js index 153aad2b..9840911a 100644 --- a/static/webui/translations/fr.js +++ b/static/webui/translations/fr.js @@ -110,6 +110,7 @@ dict = { cheats_unlockExilusEverywhere: `Adaptateurs Exilus partout`, cheats_unlockArcanesEverywhere: `Adaptateur d'Arcanes partout`, cheats_noDailyStandingLimits: `Pas de limite de réputation journalière`, + cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`, cheats_instantResourceExtractorDrones: `Ressources de drone d'extraction instantannées`, cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`, cheats_fastDojoRoomDestruction: `[UNTRANSLATED] Fast Dojo Room Destruction`, diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js index 44c6eb41..030c704b 100644 --- a/static/webui/translations/ru.js +++ b/static/webui/translations/ru.js @@ -110,6 +110,7 @@ dict = { cheats_unlockExilusEverywhere: `Адаптеры Эксилус везде`, cheats_unlockArcanesEverywhere: `Адаптеры для мистификаторов везде`, cheats_noDailyStandingLimits: `Без ежедневных ограничений репутации`, + cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`, cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`, cheats_noDojoRoomBuildStage: `Мгновенное Строительтво Комнат Додзё`, cheats_fastDojoRoomDestruction: `Мгновенные Уничтожение Комнат Додзё`, -- 2.47.2 From 8e0ff9d7f6dfad0826ecff8fc61ca624ba802a74 Mon Sep 17 00:00:00 2001 From: Sainan Date: Tue, 11 Mar 2025 16:47:51 +0100 Subject: [PATCH 3/5] fix quantity in history entry --- src/services/purchaseService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/purchaseService.ts b/src/services/purchaseService.ts index 2089c645..6a24b6c6 100644 --- a/src/services/purchaseService.ts +++ b/src/services/purchaseService.ts @@ -69,7 +69,6 @@ export const handlePurchase = async ( inventoryChanges ); } - purchaseRequest.PurchaseParams.Quantity *= offer.QuantityMultiplier; if (!config.noVendorPurchaseLimits) { inventory.RecentVendorPurchases ??= []; let vendorPurchases = inventory.RecentVendorPurchases.find( @@ -110,6 +109,7 @@ export const handlePurchase = async ( } ]; } + purchaseRequest.PurchaseParams.Quantity *= offer.QuantityMultiplier; } else if (!ExportVendors[purchaseRequest.PurchaseParams.SourceId!]) { throw new Error(`unknown vendor: ${purchaseRequest.PurchaseParams.SourceId!}`); } -- 2.47.2 From d78d32b8de7f4a48dd2bc1dca1a75dc69c7f52ce Mon Sep 17 00:00:00 2001 From: Sainan Date: Tue, 11 Mar 2025 16:54:01 +0100 Subject: [PATCH 4/5] use the expiry from the offer --- src/services/purchaseService.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/services/purchaseService.ts b/src/services/purchaseService.ts index 6a24b6c6..07d46ef5 100644 --- a/src/services/purchaseService.ts +++ b/src/services/purchaseService.ts @@ -28,7 +28,6 @@ import { import { config } from "./configService"; import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel"; import { fromStoreItem, toStoreItem } from "./itemDataService"; -import { toMongoDate } from "../helpers/inventoryHelpers"; export const getStoreItemCategory = (storeItem: string): string => { const storeItemString = getSubstringFromKeyword(storeItem, "StoreItems/"); @@ -83,7 +82,6 @@ export const handlePurchase = async ( }) - 1 ]; } - const expiry = new Date(offer.RotatedWeekly ? Date.now() + 7 * 24 * 3600 * 1000 : 2051240400000); const historyEntry = vendorPurchases.PurchaseHistory.find(x => x.ItemId == ItemId); let numPurchased = purchaseRequest.PurchaseParams.Quantity; if (historyEntry) { @@ -93,7 +91,7 @@ export const handlePurchase = async ( vendorPurchases.PurchaseHistory.push({ ItemId: ItemId, NumPurchased: purchaseRequest.PurchaseParams.Quantity, - Expiry: expiry + Expiry: new Date(parseInt(offer.Expiry.$date.$numberLong)) }); } inventoryChanges.RecentVendorPurchases = [ @@ -103,7 +101,7 @@ export const handlePurchase = async ( { ItemId: ItemId, NumPurchased: numPurchased, - Expiry: toMongoDate(expiry) + Expiry: offer.Expiry } ] } -- 2.47.2 From ab56dbb2d53be1a85ce3e55e9baaa3a903540e51 Mon Sep 17 00:00:00 2001 From: Sainan Date: Wed, 12 Mar 2025 14:35:14 +0100 Subject: [PATCH 5/5] enable noVendorPurchaseLimits by default due to lack of vendor rotations --- config.json.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json.example b/config.json.example index 8c0305fa..f1c29035 100644 --- a/config.json.example +++ b/config.json.example @@ -29,7 +29,7 @@ "unlockExilusEverywhere": false, "unlockArcanesEverywhere": false, "noDailyStandingLimits": false, - "noVendorPurchaseLimits": false, + "noVendorPurchaseLimits": true, "instantResourceExtractorDrones": false, "noDojoRoomBuildStage": false, "fastDojoRoomDestruction": false, -- 2.47.2