forked from OpenWF/SpaceNinjaServer
		
	chore: auto-generate palladino's vendor manifest (#2160)
A bit ugly, but having the self test forces correctness. Reviewed-on: OpenWF/SpaceNinjaServer#2160 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									f448d03880
								
							
						
					
					
						commit
						3053112428
					
				@ -6,7 +6,7 @@ import { mixSeeds, SRng } from "@/src/services/rngService";
 | 
				
			|||||||
import { IMongoDate } from "@/src/types/commonTypes";
 | 
					import { IMongoDate } from "@/src/types/commonTypes";
 | 
				
			||||||
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
 | 
					import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
import { ExportVendors, IRange, IVendor } from "warframe-public-export-plus";
 | 
					import { ExportVendors, IRange, IVendor, IVendorOffer } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
 | 
					import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
 | 
				
			||||||
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
 | 
					import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
 | 
				
			||||||
@ -21,7 +21,6 @@ import DeimosProspectorVendorManifest from "@/static/fixed_responses/getVendorIn
 | 
				
			|||||||
import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json";
 | 
					import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json";
 | 
				
			||||||
import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json";
 | 
					import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json";
 | 
				
			||||||
import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.json";
 | 
					import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.json";
 | 
				
			||||||
import HubsIronwakeDondaVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsIronwakeDondaVendorManifest.json";
 | 
					 | 
				
			||||||
import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
 | 
					import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
 | 
				
			||||||
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
 | 
					import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
 | 
				
			||||||
import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
 | 
					import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
 | 
				
			||||||
@ -47,7 +46,6 @@ const rawVendorManifests: IVendorManifest[] = [
 | 
				
			|||||||
    DuviriAcrithisVendorManifest,
 | 
					    DuviriAcrithisVendorManifest,
 | 
				
			||||||
    EntratiLabsEntratiLabsCommisionsManifest,
 | 
					    EntratiLabsEntratiLabsCommisionsManifest,
 | 
				
			||||||
    EntratiLabsEntratiLabVendorManifest,
 | 
					    EntratiLabsEntratiLabVendorManifest,
 | 
				
			||||||
    HubsIronwakeDondaVendorManifest, // uses preprocessing
 | 
					 | 
				
			||||||
    HubsRailjackCrewMemberVendorManifest,
 | 
					    HubsRailjackCrewMemberVendorManifest,
 | 
				
			||||||
    MaskSalesmanManifest,
 | 
					    MaskSalesmanManifest,
 | 
				
			||||||
    Nova1999ConquestShopManifest,
 | 
					    Nova1999ConquestShopManifest,
 | 
				
			||||||
@ -83,10 +81,6 @@ const generatableVendors: IGeneratableVendorInfo[] = [
 | 
				
			|||||||
        cycleOffset: 1744934400_000,
 | 
					        cycleOffset: 1744934400_000,
 | 
				
			||||||
        cycleDuration: 4 * unixTimesInMs.day
 | 
					        cycleDuration: 4 * unixTimesInMs.day
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // {
 | 
					 | 
				
			||||||
    //     _id: { $oid: "5dbb4c41e966f7886c3ce939" },
 | 
					 | 
				
			||||||
    //     TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest"
 | 
					 | 
				
			||||||
    // }
 | 
					 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getVendorOid = (typeName: string): string => {
 | 
					const getVendorOid = (typeName: string): string => {
 | 
				
			||||||
@ -261,13 +255,8 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
 | 
				
			|||||||
        const cycleIndex = Math.trunc((Date.now() - cycleOffset) / cycleDuration);
 | 
					        const cycleIndex = Math.trunc((Date.now() - cycleOffset) / cycleDuration);
 | 
				
			||||||
        const rng = new SRng(mixSeeds(vendorSeed, cycleIndex));
 | 
					        const rng = new SRng(mixSeeds(vendorSeed, cycleIndex));
 | 
				
			||||||
        const manifest = ExportVendors[vendorInfo.TypeName];
 | 
					        const manifest = ExportVendors[vendorInfo.TypeName];
 | 
				
			||||||
        const offersToAdd = [];
 | 
					        const offersToAdd: IVendorOffer[] = [];
 | 
				
			||||||
        if (
 | 
					        if (!manifest.isOneBinPerCycle) {
 | 
				
			||||||
            manifest.numItems &&
 | 
					 | 
				
			||||||
            (manifest.numItems.minValue != manifest.numItems.maxValue ||
 | 
					 | 
				
			||||||
                manifest.items.length != manifest.numItems.minValue) &&
 | 
					 | 
				
			||||||
            !manifest.isOneBinPerCycle
 | 
					 | 
				
			||||||
        ) {
 | 
					 | 
				
			||||||
            const remainingItemCapacity: Record<string, number> = {};
 | 
					            const remainingItemCapacity: Record<string, number> = {};
 | 
				
			||||||
            for (const item of manifest.items) {
 | 
					            for (const item of manifest.items) {
 | 
				
			||||||
                remainingItemCapacity[item.storeItem] = 1 + item.duplicates;
 | 
					                remainingItemCapacity[item.storeItem] = 1 + item.duplicates;
 | 
				
			||||||
@ -275,6 +264,7 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
 | 
				
			|||||||
            for (const offer of info.ItemManifest) {
 | 
					            for (const offer of info.ItemManifest) {
 | 
				
			||||||
                remainingItemCapacity[offer.StoreItem] -= 1;
 | 
					                remainingItemCapacity[offer.StoreItem] -= 1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            if (manifest.numItems && manifest.items.length != manifest.numItems.minValue) {
 | 
				
			||||||
                const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue);
 | 
					                const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue);
 | 
				
			||||||
                while (info.ItemManifest.length + offersToAdd.length < numItemsTarget) {
 | 
					                while (info.ItemManifest.length + offersToAdd.length < numItemsTarget) {
 | 
				
			||||||
                    // TODO: Consider per-bin item limits
 | 
					                    // TODO: Consider per-bin item limits
 | 
				
			||||||
@ -286,20 +276,36 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
            let binThisCycle;
 | 
					                for (const item of manifest.items) {
 | 
				
			||||||
            if (manifest.isOneBinPerCycle) {
 | 
					                    if (!item.alwaysOffered && remainingItemCapacity[item.storeItem] != 0) {
 | 
				
			||||||
                binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now.
 | 
					                        remainingItemCapacity[item.storeItem] -= 1;
 | 
				
			||||||
 | 
					                        offersToAdd.push(item);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                for (const e of Object.entries(remainingItemCapacity)) {
 | 
				
			||||||
 | 
					                    const item = manifest.items.find(x => x.storeItem == e[0])!;
 | 
				
			||||||
 | 
					                    if (!item.alwaysOffered) {
 | 
				
			||||||
 | 
					                        while (e[1] != 0) {
 | 
				
			||||||
 | 
					                            e[1] -= 1;
 | 
				
			||||||
 | 
					                            offersToAdd.push(item);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                for (const item of manifest.items) {
 | 
				
			||||||
 | 
					                    if (item.alwaysOffered && remainingItemCapacity[item.storeItem] != 0) {
 | 
				
			||||||
 | 
					                        remainingItemCapacity[item.storeItem] -= 1;
 | 
				
			||||||
 | 
					                        offersToAdd.push(item);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                offersToAdd.reverse();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            const binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now.
 | 
				
			||||||
            for (const rawItem of manifest.items) {
 | 
					            for (const rawItem of manifest.items) {
 | 
				
			||||||
                if (!manifest.isOneBinPerCycle || rawItem.bin == binThisCycle) {
 | 
					                if (rawItem.bin == binThisCycle) {
 | 
				
			||||||
                    offersToAdd.push(rawItem);
 | 
					                    offersToAdd.push(rawItem);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            // For most vendors, the offers seem to roughly be in reverse order from the manifest. Coda weapons are an odd exception.
 | 
					 | 
				
			||||||
            if (!manifest.isOneBinPerCycle) {
 | 
					 | 
				
			||||||
                offersToAdd.reverse();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const cycleStart = cycleOffset + cycleIndex * cycleDuration;
 | 
					        const cycleStart = cycleOffset + cycleIndex * cycleDuration;
 | 
				
			||||||
        for (const rawItem of offersToAdd) {
 | 
					        for (const rawItem of offersToAdd) {
 | 
				
			||||||
@ -388,4 +394,17 @@ if (isDev) {
 | 
				
			|||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest`);
 | 
					        logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest`);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const pall = getVendorManifestByTypeName("/Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest")!
 | 
				
			||||||
 | 
					        .VendorInfo.ItemManifest;
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					        pall.length != 5 ||
 | 
				
			||||||
 | 
					        pall[0].StoreItem != "/Lotus/StoreItems/Types/Items/ShipDecos/HarrowQuestKeyOrnament" ||
 | 
				
			||||||
 | 
					        pall[1].StoreItem != "/Lotus/StoreItems/Types/BoosterPacks/RivenModPack" ||
 | 
				
			||||||
 | 
					        pall[2].StoreItem != "/Lotus/StoreItems/Types/StoreItems/CreditBundles/150000Credits" ||
 | 
				
			||||||
 | 
					        pall[3].StoreItem != "/Lotus/StoreItems/Types/Items/MiscItems/Kuva" ||
 | 
				
			||||||
 | 
					        pall[4].StoreItem != "/Lotus/StoreItems/Types/BoosterPacks/RivenModPack"
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,125 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "VendorInfo": {
 | 
					 | 
				
			||||||
    "_id": {
 | 
					 | 
				
			||||||
      "$oid": "5dbb4c41e966f7886c3ce939"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "TypeName": "/Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest",
 | 
					 | 
				
			||||||
    "ItemManifest": [
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/HarrowQuestKeyOrnament",
 | 
					 | 
				
			||||||
        "ItemPrices": [
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            "ItemCount": 25,
 | 
					 | 
				
			||||||
            "ItemType": "/Lotus/Types/Items/MiscItems/PrimeBucks",
 | 
					 | 
				
			||||||
            "ProductCategory": "MiscItems"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        "Bin": "BIN_0",
 | 
					 | 
				
			||||||
        "QuantityMultiplier": 1,
 | 
					 | 
				
			||||||
        "Expiry": {
 | 
					 | 
				
			||||||
          "$date": {
 | 
					 | 
				
			||||||
            "$numberLong": "604800000"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        "AllowMultipurchase": true,
 | 
					 | 
				
			||||||
        "Id": {
 | 
					 | 
				
			||||||
          "$oid": "66fd60b20ba592c4c95e945f"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        "StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/RivenModPack",
 | 
					 | 
				
			||||||
        "ItemPrices": [
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            "ItemCount": 10,
 | 
					 | 
				
			||||||
            "ItemType": "/Lotus/Types/Items/MiscItems/RivenFragment",
 | 
					 | 
				
			||||||
            "ProductCategory": "MiscItems"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        "Bin": "BIN_0",
 | 
					 | 
				
			||||||
        "QuantityMultiplier": 1,
 | 
					 | 
				
			||||||
        "Expiry": {
 | 
					 | 
				
			||||||
          "$date": {
 | 
					 | 
				
			||||||
            "$numberLong": "604800000"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        "PurchaseQuantityLimit": 1,
 | 
					 | 
				
			||||||
        "AllowMultipurchase": false,
 | 
					 | 
				
			||||||
        "Id": {
 | 
					 | 
				
			||||||
          "$oid": "66fd60b20ba592c4c95e9468"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        "StoreItem": "/Lotus/StoreItems/Types/StoreItems/CreditBundles/150000Credits",
 | 
					 | 
				
			||||||
        "ItemPrices": [
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            "ItemCount": 5,
 | 
					 | 
				
			||||||
            "ItemType": "/Lotus/Types/Items/MiscItems/RivenFragment",
 | 
					 | 
				
			||||||
            "ProductCategory": "MiscItems"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        "Bin": "BIN_0",
 | 
					 | 
				
			||||||
        "QuantityMultiplier": 1,
 | 
					 | 
				
			||||||
        "Expiry": {
 | 
					 | 
				
			||||||
          "$date": {
 | 
					 | 
				
			||||||
            "$numberLong": "604800000"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        "PurchaseQuantityLimit": 1,
 | 
					 | 
				
			||||||
        "AllowMultipurchase": false,
 | 
					 | 
				
			||||||
        "Id": {
 | 
					 | 
				
			||||||
          "$oid": "66fd60b20ba592c4c95e9469"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Kuva",
 | 
					 | 
				
			||||||
        "ItemPrices": [
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            "ItemCount": 10,
 | 
					 | 
				
			||||||
            "ItemType": "/Lotus/Types/Items/MiscItems/RivenFragment",
 | 
					 | 
				
			||||||
            "ProductCategory": "MiscItems"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        "Bin": "BIN_0",
 | 
					 | 
				
			||||||
        "QuantityMultiplier": 35000,
 | 
					 | 
				
			||||||
        "Expiry": {
 | 
					 | 
				
			||||||
          "$date": {
 | 
					 | 
				
			||||||
            "$numberLong": "604800000"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        "PurchaseQuantityLimit": 1,
 | 
					 | 
				
			||||||
        "AllowMultipurchase": false,
 | 
					 | 
				
			||||||
        "Id": {
 | 
					 | 
				
			||||||
          "$oid": "66fd60b20ba592c4c95e946a"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        "StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/RivenModPack",
 | 
					 | 
				
			||||||
        "ItemPrices": [
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            "ItemCount": 10,
 | 
					 | 
				
			||||||
            "ItemType": "/Lotus/Types/Items/MiscItems/RivenFragment",
 | 
					 | 
				
			||||||
            "ProductCategory": "MiscItems"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        "Bin": "BIN_0",
 | 
					 | 
				
			||||||
        "QuantityMultiplier": 1,
 | 
					 | 
				
			||||||
        "Expiry": {
 | 
					 | 
				
			||||||
          "$date": {
 | 
					 | 
				
			||||||
            "$numberLong": "604800000"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        "PurchaseQuantityLimit": 1,
 | 
					 | 
				
			||||||
        "AllowMultipurchase": false,
 | 
					 | 
				
			||||||
        "Id": {
 | 
					 | 
				
			||||||
          "$oid": "66fd60b20ba592c4c95e946b"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "PropertyTextHash": "62B64A8065B7C0FA345895D4BC234621",
 | 
					 | 
				
			||||||
    "Expiry": {
 | 
					 | 
				
			||||||
      "$date": {
 | 
					 | 
				
			||||||
        "$numberLong": "604800000"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user