From 0a4a04e3ddde253446ac7f326a4e83a7baa257c7 Mon Sep 17 00:00:00 2001 From: chainrez <186519033+chainrez@users.noreply.github.com> Date: Wed, 5 Feb 2025 01:50:34 -0800 Subject: [PATCH 1/5] Fix: Guess armor Guardian Class --- src/app/inventory/store/d2-item-factory.ts | 44 +++++++++++++++++++--- src/app/search/d2-known-values.ts | 44 +++++++++++++++++++++- 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/src/app/inventory/store/d2-item-factory.ts b/src/app/inventory/store/d2-item-factory.ts index ef312f7d5c..876b734fc7 100644 --- a/src/app/inventory/store/d2-item-factory.ts +++ b/src/app/inventory/store/d2-item-factory.ts @@ -7,6 +7,8 @@ import { SOME_OTHER_DUMMY_BUCKET, THE_FORBIDDEN_BUCKET, d2MissingIcon, + infusionCategoryHashToClass, + plugCategoryHashToClass, uniqueEquipBuckets, } from 'app/search/d2-known-values'; import { lightStats } from 'app/search/search-filter-values'; @@ -27,6 +29,7 @@ import { DestinyItemResponse, DestinyItemSubType, DestinyItemTooltipNotification, + DestinyItemType, DestinyObjectiveProgress, DestinyProfileResponse, DestinyVendorSaleItemComponent, @@ -434,17 +437,46 @@ export function makeItem( } } - // we cannot trust the claimed class of redacted items. they all say Titan - const classType = itemDef.redacted - ? normalBucket.inArmor + let classType = itemDef.classType; + + // we cannot trust the claimed class of redacted items + if (itemDef.redacted) { + classType = normalBucket.inArmor ? itemInstanceData?.isEquipped && owner ? // equipped armor gets marked as that character's class owner.classType : // unequipped armor gets marked "no class" DestinyClass.Classified : // other items are marked "any class" - DestinyClass.Unknown - : itemDef.classType; + DestinyClass.Unknown; + } else if ( + // This whole elseif can go, eventually. + itemDef.classType === DestinyClass.Unknown && + (itemDef.itemType === DestinyItemType.Armor || + // Festival masks are head armor in traits but not types. + (itemDef.itemType === DestinyItemType.None && + itemDef.traitHashes?.includes(TraitHashes.ItemArmorHead))) + ) { + // This identifies 4591 armors by infusion category. + classType = + infusionCategoryHashToClass[itemDef.quality!.infusionCategoryHash] ?? DestinyClass.Unknown; + + // This identifies the remaining 413 by what class' ornament they are (or look like). + if (classType === DestinyClass.Unknown) { + // If this item has a plug, it can be an ornament (and be identified). If not, find a visually matching ornament. + let plugCheckItem: DestinyInventoryItemDefinition | undefined = itemDef; + if (!itemDef.plug) { + plugCheckItem = Object.values(defs.InventoryItem.getAll()).find( + (i) => i.plug && i.displayProperties.icon === itemDef.displayProperties.icon, + ); + } + + if (plugCheckItem) { + classType = + plugCategoryHashToClass[plugCheckItem.plug!.plugCategoryHash] ?? DestinyClass.Unknown; + } + } + } const createdItem: DimItem = { owner: owner?.id || 'unknown', @@ -486,7 +518,7 @@ export function makeItem( maxStackSize: Math.max(itemDef.inventory!.maxStackSize, 1), uniqueStack: Boolean(itemDef.inventory!.stackUniqueLabel?.length), classType, - classTypeNameLocalized: getClassTypeNameLocalized(defs)(itemDef.classType), + classTypeNameLocalized: getClassTypeNameLocalized(defs)(classType), element, energy: itemInstanceData.energy ?? null, lockable: normalBucket.hash !== BucketHashes.Finishers ? item.lockable : true, diff --git a/src/app/search/d2-known-values.ts b/src/app/search/d2-known-values.ts index ad812da0eb..c88adeec19 100644 --- a/src/app/search/d2-known-values.ts +++ b/src/app/search/d2-known-values.ts @@ -1,6 +1,6 @@ import { CustomStatWeights } from '@destinyitemmanager/dim-api-types'; import { HashLookup } from 'app/utils/util-types'; -import { TierType } from 'bungie-api-ts/destiny2'; +import { DestinyClass, TierType } from 'bungie-api-ts/destiny2'; import { BreakerTypeHashes, @@ -318,3 +318,45 @@ export const enum ModsWithConditionalStats { } export const ARTIFICE_PERK_HASH = 3727270518; // InventoryItem "Artifice Armor" + +/** Most armor's Guardian Class can be determined by what it can be infused into */ +export const infusionCategoryHashToClass: Record = { + 3301232851: DestinyClass.Hunter, // hunter head + 3853570272: DestinyClass.Hunter, // hunter arms + 1814923096: DestinyClass.Hunter, // hunter chest + 2542340350: DestinyClass.Hunter, // hunter legs + 821835303: DestinyClass.Hunter, // hunter class + + 3548569221: DestinyClass.Titan, // titan head + 3647016162: DestinyClass.Titan, // titan arms + 2858080654: DestinyClass.Titan, // titan chest + 1462658336: DestinyClass.Titan, // titan legs + 4159907129: DestinyClass.Titan, // titan class + + 1046741990: DestinyClass.Warlock, // warlock head + 673964473: DestinyClass.Warlock, // warlock arms + 3312934999: DestinyClass.Warlock, // warlock chest + 3441938495: DestinyClass.Warlock, // warlock legs + 2278270520: DestinyClass.Warlock, // warlock class +}; + +/** Most remaining armor's Guardian Class can be determined by its ornament category */ +export const plugCategoryHashToClass: Record = { + 1608828634: DestinyClass.Hunter, // armor_skins_hunter_legs + 4147546868: DestinyClass.Hunter, // armor_skins_hunter_chest + 3952105943: DestinyClass.Hunter, // armor_skins_hunter_head + 1392996619: DestinyClass.Hunter, // armor_skins_hunter_class + 4060972748: DestinyClass.Hunter, // armor_skins_hunter_arms + + 454950060: DestinyClass.Hunter, // armor_skins_warlock_head + 3281006437: DestinyClass.Hunter, // armor_skins_warlock_legs + 3934361071: DestinyClass.Hunter, // armor_skins_warlock_arms + 1509135441: DestinyClass.Hunter, // armor_skins_warlock_chest + 505602046: DestinyClass.Hunter, // armor_skins_warlock_class + + 3955281547: DestinyClass.Hunter, // armor_skins_titan_head + 3945759584: DestinyClass.Hunter, // armor_skins_titan_chest + 2112278838: DestinyClass.Hunter, // armor_skins_titan_legs + 3386643992: DestinyClass.Hunter, // armor_skins_titan_arms + 2415787951: DestinyClass.Hunter, // armor_skins_titan_class +}; From fbf9b5c5e86c72cf386b22531435b985188d46fa Mon Sep 17 00:00:00 2001 From: chainrez <186519033+chainrez@users.noreply.github.com> Date: Wed, 5 Feb 2025 02:19:35 -0800 Subject: [PATCH 2/5] guess class: missing known-value commit --- src/app/search/d2-known-values.ts | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/app/search/d2-known-values.ts b/src/app/search/d2-known-values.ts index c88adeec19..928f7bf9dc 100644 --- a/src/app/search/d2-known-values.ts +++ b/src/app/search/d2-known-values.ts @@ -342,21 +342,21 @@ export const infusionCategoryHashToClass: Record = { - 1608828634: DestinyClass.Hunter, // armor_skins_hunter_legs - 4147546868: DestinyClass.Hunter, // armor_skins_hunter_chest - 3952105943: DestinyClass.Hunter, // armor_skins_hunter_head - 1392996619: DestinyClass.Hunter, // armor_skins_hunter_class - 4060972748: DestinyClass.Hunter, // armor_skins_hunter_arms - - 454950060: DestinyClass.Hunter, // armor_skins_warlock_head - 3281006437: DestinyClass.Hunter, // armor_skins_warlock_legs - 3934361071: DestinyClass.Hunter, // armor_skins_warlock_arms - 1509135441: DestinyClass.Hunter, // armor_skins_warlock_chest - 505602046: DestinyClass.Hunter, // armor_skins_warlock_class - - 3955281547: DestinyClass.Hunter, // armor_skins_titan_head - 3945759584: DestinyClass.Hunter, // armor_skins_titan_chest - 2112278838: DestinyClass.Hunter, // armor_skins_titan_legs - 3386643992: DestinyClass.Hunter, // armor_skins_titan_arms - 2415787951: DestinyClass.Hunter, // armor_skins_titan_class + [PlugCategoryHashes.ArmorSkinsHunterLegs]: DestinyClass.Hunter, + [PlugCategoryHashes.ArmorSkinsHunterChest]: DestinyClass.Hunter, + [PlugCategoryHashes.ArmorSkinsHunterHead]: DestinyClass.Hunter, + [PlugCategoryHashes.ArmorSkinsHunterClass]: DestinyClass.Hunter, + [PlugCategoryHashes.ArmorSkinsHunterArms]: DestinyClass.Hunter, + + [PlugCategoryHashes.ArmorSkinsWarlockHead]: DestinyClass.Warlock, + [PlugCategoryHashes.ArmorSkinsWarlockLegs]: DestinyClass.Warlock, + [PlugCategoryHashes.ArmorSkinsWarlockArms]: DestinyClass.Warlock, + [PlugCategoryHashes.ArmorSkinsWarlockChest]: DestinyClass.Warlock, + [PlugCategoryHashes.ArmorSkinsWarlockClass]: DestinyClass.Warlock, + + [PlugCategoryHashes.ArmorSkinsTitanHead]: DestinyClass.Titan, + [PlugCategoryHashes.ArmorSkinsTitanChest]: DestinyClass.Titan, + [PlugCategoryHashes.ArmorSkinsTitanLegs]: DestinyClass.Titan, + [PlugCategoryHashes.ArmorSkinsTitanArms]: DestinyClass.Titan, + [PlugCategoryHashes.ArmorSkinsTitanClass]: DestinyClass.Titan, }; From 1bd44897f6bab36cd8c8885fe98117100fe59437 Mon Sep 17 00:00:00 2001 From: chainrez <186519033+chainrez@users.noreply.github.com> Date: Wed, 5 Feb 2025 02:34:14 -0800 Subject: [PATCH 3/5] guess class: cleanup / clarity --- src/app/inventory/store/d2-item-factory.ts | 27 +++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/app/inventory/store/d2-item-factory.ts b/src/app/inventory/store/d2-item-factory.ts index 876b734fc7..ed747ed935 100644 --- a/src/app/inventory/store/d2-item-factory.ts +++ b/src/app/inventory/store/d2-item-factory.ts @@ -439,37 +439,38 @@ export function makeItem( let classType = itemDef.classType; - // we cannot trust the claimed class of redacted items + // We cannot trust the defined class of redacted items, + // and adjust their claimed classType based on their status in the user's inventory. if (itemDef.redacted) { classType = normalBucket.inArmor ? itemInstanceData?.isEquipped && owner ? // equipped armor gets marked as that character's class owner.classType - : // unequipped armor gets marked "no class" + : // unequipped armor gets marked "no class" (assume/allow nothing) DestinyClass.Classified - : // other items are marked "any class" + : // other items are marked "any class"/unknown DestinyClass.Unknown; } else if ( - // This whole elseif can go, eventually. + // This whole elseif can be removed once Bungie addresses https://github.com/Bungie-net/api/issues/1937 and restores item class information. + // However, the heuristics are strict, and this only adjusts Unknown armor, so there's no rush to remove it. itemDef.classType === DestinyClass.Unknown && (itemDef.itemType === DestinyItemType.Armor || // Festival masks are head armor in traits but not types. (itemDef.itemType === DestinyItemType.None && itemDef.traitHashes?.includes(TraitHashes.ItemArmorHead))) ) { - // This identifies 4591 armors by infusion category. + // This identifies most armors (90%+) by infusion category. classType = infusionCategoryHashToClass[itemDef.quality!.infusionCategoryHash] ?? DestinyClass.Unknown; - // This identifies the remaining 413 by what class' ornament they are (or look like). + // This identifies the remaining armors by what class' armor they can act as an ornament for. if (classType === DestinyClass.Unknown) { - // If this item has a plug, it can be an ornament (and be identified). If not, find a visually matching ornament. - let plugCheckItem: DestinyInventoryItemDefinition | undefined = itemDef; - if (!itemDef.plug) { - plugCheckItem = Object.values(defs.InventoryItem.getAll()).find( - (i) => i.plug && i.displayProperties.icon === itemDef.displayProperties.icon, - ); - } + // If this item has a plug, it can be an ornament. If not, find a visually matching ornament item. + const plugCheckItem = itemDef.plug + ? itemDef + : Object.values(defs.InventoryItem.getAll()).find( + (i) => i.plug && i.displayProperties.icon === itemDef.displayProperties.icon, + ); if (plugCheckItem) { classType = From f399339845befaccec49512e37597c3b798d8f45 Mon Sep 17 00:00:00 2001 From: chainrez <186519033+chainrez@users.noreply.github.com> Date: Wed, 5 Feb 2025 03:05:15 -0800 Subject: [PATCH 4/5] Guess subclass Classes too --- src/app/inventory/store/d2-item-factory.ts | 46 ++++++++++++---------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/app/inventory/store/d2-item-factory.ts b/src/app/inventory/store/d2-item-factory.ts index ed747ed935..af84550e7b 100644 --- a/src/app/inventory/store/d2-item-factory.ts +++ b/src/app/inventory/store/d2-item-factory.ts @@ -450,32 +450,36 @@ export function makeItem( DestinyClass.Classified : // other items are marked "any class"/unknown DestinyClass.Unknown; - } else if ( + } else if (itemDef.classType === DestinyClass.Unknown) { // This whole elseif can be removed once Bungie addresses https://github.com/Bungie-net/api/issues/1937 and restores item class information. // However, the heuristics are strict, and this only adjusts Unknown armor, so there's no rush to remove it. - itemDef.classType === DestinyClass.Unknown && - (itemDef.itemType === DestinyItemType.Armor || + if ( + itemDef.itemType === DestinyItemType.Armor || // Festival masks are head armor in traits but not types. (itemDef.itemType === DestinyItemType.None && - itemDef.traitHashes?.includes(TraitHashes.ItemArmorHead))) - ) { - // This identifies most armors (90%+) by infusion category. - classType = - infusionCategoryHashToClass[itemDef.quality!.infusionCategoryHash] ?? DestinyClass.Unknown; - - // This identifies the remaining armors by what class' armor they can act as an ornament for. - if (classType === DestinyClass.Unknown) { - // If this item has a plug, it can be an ornament. If not, find a visually matching ornament item. - const plugCheckItem = itemDef.plug - ? itemDef - : Object.values(defs.InventoryItem.getAll()).find( - (i) => i.plug && i.displayProperties.icon === itemDef.displayProperties.icon, - ); - - if (plugCheckItem) { - classType = - plugCategoryHashToClass[plugCheckItem.plug!.plugCategoryHash] ?? DestinyClass.Unknown; + itemDef.traitHashes?.includes(TraitHashes.ItemArmorHead)) + ) { + // This identifies most armors (90%+) by infusion category. + classType = + infusionCategoryHashToClass[itemDef.quality!.infusionCategoryHash] ?? DestinyClass.Unknown; + + // This identifies the remaining armors by what class' armor they can act as an ornament for. + if (classType === DestinyClass.Unknown) { + // If this item has a plug, it can be an ornament. If not, find a visually matching ornament item. + const plugCheckItem = itemDef.plug + ? itemDef + : Object.values(defs.InventoryItem.getAll()).find( + (i) => i.plug && i.displayProperties.icon === itemDef.displayProperties.icon, + ); + + if (plugCheckItem) { + classType = + plugCategoryHashToClass[plugCheckItem.plug!.plugCategoryHash] ?? DestinyClass.Unknown; + } } + } else if (itemDef.itemType === DestinyItemType.Subclass && owner) { + // Obviously a subclass is compatible with the Guardian holding it. + classType = owner.classType; } } From d2feaae88e531299d0814efd7beef98752ac8048 Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Wed, 5 Feb 2025 09:28:51 -0800 Subject: [PATCH 5/5] Fix tests --- docs/CHANGELOG.md | 2 + .../__snapshots__/d2-stores.test.ts.snap | 90 +++++++++---------- src/app/inventory/store/d2-item-factory.ts | 3 +- .../loadout-drawer-reducer.test.ts | 19 ++-- 4 files changed, 59 insertions(+), 55 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 7ce601375f..2adbf8c91c 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,7 @@ ## Next +* Worked around a bug in the Bungie data that had all armor as "unknown" class instead of Hunter/Titan/Warlock. + ## 8.57.1 (2025-02-03) * DIM Sync data is now loaded incrementally, instead of being completely refreshed every time. This should result in faster updates, but otherwise nothing should be different. If you notice things are out of sync, you can click the "Reload remote data from DIM sync" button in Settings, but please let us know if you needed to do that. diff --git a/src/app/inventory/__snapshots__/d2-stores.test.ts.snap b/src/app/inventory/__snapshots__/d2-stores.test.ts.snap index 8e6d75c6c2..972edc35a6 100644 --- a/src/app/inventory/__snapshots__/d2-stores.test.ts.snap +++ b/src/app/inventory/__snapshots__/d2-stores.test.ts.snap @@ -36,7 +36,7 @@ exports[`process stores generates a correct armor CSV export 1`] = ` "Seasonal Mod": [ "lastwish", ], - "Source": "lastwish", + "Source": "", "Strength": 4, "Strength (Base)": 2, "Tag": undefined, @@ -2160,7 +2160,7 @@ exports[`process stores generates a correct armor CSV export 1`] = ` "Resilience (Base)": 12, "Season": 4, "Seasonal Mod": "", - "Source": "campaign", + "Source": "", "Strength": 0, "Strength (Base)": 0, "Tag": undefined, @@ -2349,7 +2349,7 @@ exports[`process stores generates a correct armor CSV export 1`] = ` "Resilience (Base)": 8, "Season": 4, "Seasonal Mod": "", - "Source": "campaign", + "Source": "", "Strength": 0, "Strength (Base)": 0, "Tag": undefined, @@ -2898,7 +2898,7 @@ exports[`process stores generates a correct armor CSV export 1`] = ` "Resilience (Base)": 34, "Season": 4, "Seasonal Mod": "", - "Source": "campaign", + "Source": "", "Strength": 0, "Strength (Base)": 0, "Tag": undefined, @@ -6469,7 +6469,7 @@ exports[`process stores generates a correct armor CSV export 1`] = ` "Resilience (Base)": 13, "Season": 11, "Seasonal Mod": "", - "Source": "legendaryengram", + "Source": "", "Strength": 2, "Strength (Base)": 2, "Tag": undefined, @@ -7539,7 +7539,7 @@ exports[`process stores generates a correct armor CSV export 1`] = ` "Resilience (Base)": 12, "Season": 4, "Seasonal Mod": "", - "Source": "campaign", + "Source": "", "Strength": 7, "Strength (Base)": 7, "Tag": undefined, @@ -7611,7 +7611,7 @@ exports[`process stores generates a correct armor CSV export 1`] = ` "Resilience (Base)": 13, "Season": 4, "Seasonal Mod": "", - "Source": "campaign", + "Source": "", "Strength": 2, "Strength (Base)": 2, "Tag": undefined, @@ -7683,7 +7683,7 @@ exports[`process stores generates a correct armor CSV export 1`] = ` "Resilience (Base)": 6, "Season": 4, "Seasonal Mod": "", - "Source": "campaign", + "Source": "", "Strength": 2, "Strength (Base)": 2, "Tag": undefined, @@ -10723,7 +10723,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 0, "Loadouts": "", "Locked": true, - "Mag": 36, + "Mag": 35, "Masterwork Tier": 3, "Masterwork Type": "Stability", "Name": "Extraordinary Rendition", @@ -11295,7 +11295,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Void", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "field-forged", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 69, @@ -12264,7 +12264,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Reload": 44, "Season": 15, "Shield Duration": 0, - "Source": "ironbanner", + "Source": "", "Stability": 95, "Swing Speed": 0, "Tag": undefined, @@ -12463,7 +12463,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Kinetic", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "tex-mechanica", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 66, @@ -12753,7 +12753,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Kinetic", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "field-forged", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 77, @@ -13170,7 +13170,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 381, "Loadouts": "", "Locked": true, - "Mag": 5, + "Mag": 6, "Masterwork Tier": 10, "Masterwork Type": "Handling", "Name": "The Enigma", @@ -14016,7 +14016,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Reload": 29, "Season": 16, "Shield Duration": 0, - "Source": "ironbanner", + "Source": "", "Stability": 80, "Swing Speed": 0, "Tag": undefined, @@ -14572,7 +14572,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Kinetic", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "tex-mechanica", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 66, @@ -14699,7 +14699,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 502, "Loadouts": "", "Locked": true, - "Mag": 7, + "Mag": 8, "Masterwork Tier": 1, "Masterwork Type": "Handling", "Name": "Nezarec's Whisper", @@ -15011,7 +15011,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Reload": 32, "Season": 16, "Shield Duration": 0, - "Source": "ironbanner", + "Source": "", "Stability": 79, "Swing Speed": 0, "Tag": undefined, @@ -15267,7 +15267,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Arc", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "field-forged", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 47, @@ -16622,7 +16622,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 568, "Loadouts": "", "Locked": true, - "Mag": 4, + "Mag": 5, "Masterwork Tier": 1, "Masterwork Type": "Shield Duration", "Name": "Judgment of Kelgorath", @@ -16737,7 +16737,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 0, "Loadouts": "", "Locked": true, - "Mag": 45, + "Mag": 44, "Masterwork Tier": undefined, "Masterwork Type": undefined, "Name": "The Manticore", @@ -17552,7 +17552,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Kinetic", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "field-forged", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 63, @@ -17800,7 +17800,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 0, "Loadouts": "", "Locked": true, - "Mag": 39, + "Mag": 38, "Masterwork Tier": 2, "Masterwork Type": "Stability", "Name": "Pizzicato-22", @@ -18266,7 +18266,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Kinetic", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "field-forged", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 76, @@ -18561,7 +18561,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Void", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "field-forged", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 81, @@ -18918,7 +18918,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 335, "Loadouts": "", "Locked": true, - "Mag": 6, + "Mag": 7, "Masterwork Tier": 10, "Masterwork Type": undefined, "Name": "Vexcalibur", @@ -20322,7 +20322,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 19, "Loadouts": "", "Locked": true, - "Mag": 37, + "Mag": 45, "Masterwork Tier": undefined, "Masterwork Type": undefined, "Name": "Centrifuse", @@ -20956,7 +20956,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Kinetic", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "field-forged", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 33, @@ -21730,7 +21730,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 0, "Loadouts": "", "Locked": false, - "Mag": 39, + "Mag": 38, "Masterwork Tier": 2, "Masterwork Type": "Stability", "Name": "Pizzicato-22", @@ -22307,7 +22307,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 0, "Loadouts": "", "Locked": true, - "Mag": 74, + "Mag": 194, "Masterwork Tier": undefined, "Masterwork Type": undefined, "Name": "Divinity", @@ -23568,7 +23568,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 0, "Loadouts": "", "Locked": false, - "Mag": 6, + "Mag": 7, "Masterwork Tier": 10, "Masterwork Type": undefined, "Name": "Edge of Concurrence", @@ -24198,7 +24198,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Charge Time": 0, "Crafted": false, "Crafted Level": 0, - "Draw Time": 540, + "Draw Time": 500, "Element": "Void", "Equipped": false, "Event": "", @@ -25013,7 +25013,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Kinetic", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "tex-mechanica", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 51, @@ -25972,7 +25972,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 0, "Loadouts": "", "Locked": true, - "Mag": 3, + "Mag": 4, "Masterwork Tier": undefined, "Masterwork Type": undefined, "Name": "Winterbite", @@ -26323,7 +26323,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 4, "Loadouts": "", "Locked": true, - "Mag": 41, + "Mag": 42, "Masterwork Tier": 2, "Masterwork Type": "Range", "Name": "Subjunctive", @@ -27356,7 +27356,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Solar", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "field-forged", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 59, @@ -27537,7 +27537,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Solar", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "suros", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 63, @@ -27772,7 +27772,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Arc", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "field-forged", "Guard Endurance": 40, "Guard Resistance": 40, "Handling": 0, @@ -28009,7 +28009,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Arc", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "field-forged", "Guard Endurance": 0, "Guard Resistance": 0, "Handling": 27, @@ -28078,7 +28078,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 0, "Loadouts": "", "Locked": false, - "Mag": 5, + "Mag": 6, "Masterwork Tier": 4, "Masterwork Type": "Reload Speed", "Name": "Greasy Luck", @@ -28717,7 +28717,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Element": "Arc", "Equipped": false, "Event": "", - "Foundry": undefined, + "Foundry": "field-forged", "Guard Endurance": 0, "Guard Resistance": 80, "Handling": 0, @@ -28967,7 +28967,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 0, "Loadouts": "", "Locked": false, - "Mag": 45, + "Mag": 44, "Masterwork Tier": 1, "Masterwork Type": "Range", "Name": "The Recluse", @@ -29279,7 +29279,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` ], "Power": 1923, "ROF": 100, - "Range": 30, + "Range": 0, "Recoil": 75, "Reload": 45, "Season": 24, @@ -29428,7 +29428,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 0, "Loadouts": "", "Locked": true, - "Mag": 41, + "Mag": 42, "Masterwork Tier": 3, "Masterwork Type": "Stability", "Name": "Parabellum", @@ -29828,7 +29828,7 @@ exports[`process stores generates a correct weapon CSV export 1`] = ` "Kill Tracker": 0, "Loadouts": "", "Locked": false, - "Mag": 39, + "Mag": 38, "Masterwork Tier": 1, "Masterwork Type": "Reload Speed", "Name": "Pizzicato-22", diff --git a/src/app/inventory/store/d2-item-factory.ts b/src/app/inventory/store/d2-item-factory.ts index af84550e7b..14bfc98bb4 100644 --- a/src/app/inventory/store/d2-item-factory.ts +++ b/src/app/inventory/store/d2-item-factory.ts @@ -452,7 +452,8 @@ export function makeItem( DestinyClass.Unknown; } else if (itemDef.classType === DestinyClass.Unknown) { // This whole elseif can be removed once Bungie addresses https://github.com/Bungie-net/api/issues/1937 and restores item class information. - // However, the heuristics are strict, and this only adjusts Unknown armor, so there's no rush to remove it. + // However, the heuristics are strict, and this only adjusts Unknown armor, so there's no rush to remove it. We also need to re-enable the + // test in loadout-drawer-reducer.test.ts. if ( itemDef.itemType === DestinyItemType.Armor || // Festival masks are head armor in traits but not types. diff --git a/src/app/loadout-drawer/loadout-drawer-reducer.test.ts b/src/app/loadout-drawer/loadout-drawer-reducer.test.ts index 413c652e35..1a7f44c080 100644 --- a/src/app/loadout-drawer/loadout-drawer-reducer.test.ts +++ b/src/app/loadout-drawer/loadout-drawer-reducer.test.ts @@ -21,7 +21,7 @@ import { toggleEquipped, updateMods, } from './loadout-drawer-reducer'; -import { filterLoadoutToAllowedItems, newLoadout } from './loadout-utils'; +import { newLoadout } from './loadout-utils'; let defs: D2ManifestDefinitions; let store: DimStore; @@ -217,16 +217,17 @@ describe('addItem', () => { expect(loadout.items).toEqual([]); }); - it('removes class-specific items when saving as "any class"', () => { - const hunterItem = allItems.find((i) => i.classType === DestinyClass.Hunter)!; - expect(hunterItem).toBeDefined(); + // TODO: reenable after https://github.com/Bungie-net/api/issues/1937 is fixed + // it('removes class-specific items when saving as "any class"', () => { + // const hunterItem = allItems.find((i) => i.classType === DestinyClass.Hunter)!; + // expect(hunterItem).toBeDefined(); - let loadout = addItem(defs, hunterItem)(emptyLoadout); - loadout = setClassType(DestinyClass.Unknown)(loadout); - loadout = filterLoadoutToAllowedItems(defs, loadout); + // let loadout = addItem(defs, hunterItem)(emptyLoadout); + // loadout = setClassType(DestinyClass.Unknown)(loadout); + // loadout = filterLoadoutToAllowedItems(defs, loadout); - expect(loadout.items).toEqual([]); - }); + // expect(loadout.items).toEqual([]); + // }); it('does nothing if the bucket is already at capacity', () => { const weapons = items.filter((i) => i.bucket.hash === BucketHashes.KineticWeapons);