2024-05-21 17:59:04 +00:00
import { HandbookHelper } from "@spt/helpers/HandbookHelper" ;
import { IStaticAmmoDetails } from "@spt/models/eft/common/ILocation" ;
import { IPmcData } from "@spt/models/eft/common/IPmcData" ;
2024-07-05 09:39:01 +01:00
import { IInsuredItem } from "@spt/models/eft/common/tables/IBotBase" ;
2024-05-21 17:59:04 +00:00
import { Item , Location , Repairable , Upd } from "@spt/models/eft/common/tables/IItem" ;
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem" ;
import { BaseClasses } from "@spt/models/enums/BaseClasses" ;
import { EquipmentSlots } from "@spt/models/enums/EquipmentSlots" ;
2024-06-13 09:47:03 +01:00
import { ItemTpl } from "@spt/models/enums/ItemTpl" ;
2024-07-07 19:43:32 +01:00
import { Money } from "@spt/models/enums/Money" ;
2024-05-21 17:59:04 +00:00
import { ILogger } from "@spt/models/spt/utils/ILogger" ;
2024-05-28 22:24:52 +01:00
import { DatabaseService } from "@spt/services/DatabaseService" ;
2024-05-21 17:59:04 +00:00
import { ItemBaseClassService } from "@spt/services/ItemBaseClassService" ;
import { ItemFilterService } from "@spt/services/ItemFilterService" ;
import { LocaleService } from "@spt/services/LocaleService" ;
import { LocalisationService } from "@spt/services/LocalisationService" ;
import { CompareUtil } from "@spt/utils/CompareUtil" ;
import { HashUtil } from "@spt/utils/HashUtil" ;
import { JsonUtil } from "@spt/utils/JsonUtil" ;
import { MathUtil } from "@spt/utils/MathUtil" ;
import { ObjectId } from "@spt/utils/ObjectId" ;
import { ProbabilityObject , ProbabilityObjectArray , RandomUtil } from "@spt/utils/RandomUtil" ;
2024-07-23 11:12:53 -04:00
import { ICloner } from "@spt/utils/cloners/ICloner" ;
import { inject , injectable } from "tsyringe" ;
2023-03-03 15:23:46 +00:00
@injectable ( )
2024-07-23 11:12:53 -04:00
export class ItemHelper {
2023-10-10 11:03:20 +00:00
protected readonly defaultInvalidBaseTypes : string [ ] = [
BaseClasses . LOOT_CONTAINER ,
BaseClasses . MOB_CONTAINER ,
BaseClasses . STASH ,
BaseClasses . SORTING_TABLE ,
BaseClasses . INVENTORY ,
BaseClasses . STATIONARY_CONTAINER ,
2023-11-13 11:07:59 -05:00
BaseClasses . POCKETS ,
2023-10-10 11:03:20 +00:00
] ;
2023-03-03 15:23:46 +00:00
constructor (
2024-05-28 14:04:20 +00:00
@inject ( "PrimaryLogger" ) protected logger : ILogger ,
2023-03-03 15:23:46 +00:00
@inject ( "HashUtil" ) protected hashUtil : HashUtil ,
@inject ( "JsonUtil" ) protected jsonUtil : JsonUtil ,
@inject ( "RandomUtil" ) protected randomUtil : RandomUtil ,
@inject ( "ObjectId" ) protected objectId : ObjectId ,
@inject ( "MathUtil" ) protected mathUtil : MathUtil ,
2024-05-28 22:24:52 +01:00
@inject ( "DatabaseService" ) protected databaseService : DatabaseService ,
2023-03-03 15:23:46 +00:00
@inject ( "HandbookHelper" ) protected handbookHelper : HandbookHelper ,
@inject ( "ItemBaseClassService" ) protected itemBaseClassService : ItemBaseClassService ,
2023-11-04 10:49:52 +00:00
@inject ( "ItemFilterService" ) protected itemFilterService : ItemFilterService ,
2023-03-03 15:23:46 +00:00
@inject ( "LocalisationService" ) protected localisationService : LocalisationService ,
2023-11-13 11:07:59 -05:00
@inject ( "LocaleService" ) protected localeService : LocaleService ,
2024-05-01 20:17:09 +00:00
@inject ( "CompareUtil" ) protected compareUtil : CompareUtil ,
2024-05-28 14:04:20 +00:00
@inject ( "PrimaryCloner" ) protected cloner : ICloner ,
2024-07-23 11:12:53 -04:00
) { }
2023-03-03 15:23:46 +00:00
2024-06-13 09:47:03 +01:00
/ * *
* Does the provided pool of items contain the desired item
* @param itemPool Item collection to check
* @param item Item to look for
* @param slotId OPTIONAL - slotid of desired item
* @returns True if pool contains item
* /
2024-07-23 11:12:53 -04:00
public hasItemWithTpl ( itemPool : Item [ ] , item : ItemTpl , slotId? : string ) : boolean {
2024-06-13 09:47:03 +01:00
// Filter the pool by slotId if provided
2024-07-23 11:12:53 -04:00
const filteredPool = slotId ? itemPool . filter ( ( item ) = > item . slotId ? . startsWith ( slotId ) ) : itemPool ;
2024-06-13 09:47:03 +01:00
// Check if any item in the filtered pool matches the provided item
return filteredPool . some ( ( poolItem ) = > poolItem . _tpl === item ) ;
}
2024-06-13 10:53:07 +01:00
/ * *
2024-06-13 11:05:10 +01:00
* Get the first item from provided pool with the desired tpl
2024-06-13 10:53:07 +01:00
* @param itemPool Item collection to search
* @param item Item to look for
* @param slotId OPTIONAL - slotid of desired item
* @returns Item or undefined
* /
2024-07-23 11:12:53 -04:00
public getItemFromPoolByTpl ( itemPool : Item [ ] , item : ItemTpl , slotId? : string ) : Item | undefined {
// Filter the pool by slotId if provided
const filteredPool = slotId ? itemPool . filter ( ( item ) = > item . slotId ? . startsWith ( slotId ) ) : itemPool ;
2024-06-13 10:53:07 +01:00
// Check if any item in the filtered pool matches the provided item
return filteredPool . find ( ( poolItem ) = > poolItem . _tpl === item ) ;
}
2024-05-01 20:17:09 +00:00
/ * *
* This method will compare two items ( with all its children ) and see if the are equivalent .
* This method will NOT compare IDs on the items
* @param item1 first item with all its children to compare
* @param item2 second item with all its children to compare
* @param compareUpdProperties Upd properties to compare between the items
* @returns true if they are the same , false if they arent
* /
2024-07-23 11:12:53 -04:00
public isSameItems ( item1 : Item [ ] , item2 : Item [ ] , compareUpdProperties? : Set < string > ) : boolean {
if ( item1 . length !== item2 . length ) {
2024-05-01 20:17:09 +00:00
return false ;
}
2024-07-23 11:12:53 -04:00
for ( const itemOf1 of item1 ) {
2024-05-17 15:32:41 -04:00
const itemOf2 = item2 . find ( ( i2 ) = > i2 . _tpl === itemOf1 . _tpl ) ;
2024-07-23 11:12:53 -04:00
if ( itemOf2 === undefined ) {
2024-05-01 20:17:09 +00:00
return false ;
}
2024-07-23 11:12:53 -04:00
if ( ! this . isSameItem ( itemOf1 , itemOf2 , compareUpdProperties ) ) {
2024-05-01 20:17:09 +00:00
return false ;
}
}
return true ;
}
/ * *
* This method will compare two items and see if the are equivalent .
* This method will NOT compare IDs on the items
* @param item1 first item to compare
* @param item2 second item to compare
* @param compareUpdProperties Upd properties to compare between the items
* @returns true if they are the same , false if they arent
* /
2024-07-23 11:12:53 -04:00
public isSameItem ( item1 : Item , item2 : Item , compareUpdProperties? : Set < string > ) : boolean {
if ( item1 . _tpl !== item2 . _tpl ) {
2024-05-01 20:17:09 +00:00
return false ;
}
2024-07-23 11:12:53 -04:00
if ( compareUpdProperties ) {
2024-05-17 15:32:41 -04:00
return Array . from ( compareUpdProperties . values ( ) ) . every ( ( p ) = >
2024-05-07 23:57:08 -04:00
this . compareUtil . recursiveCompare ( item1 . upd ? . [ p ] , item2 . upd ? . [ p ] ) ,
2024-05-01 20:17:09 +00:00
) ;
}
return this . compareUtil . recursiveCompare ( item1 . upd , item2 . upd ) ;
}
/ * *
* Helper method to generate a Upd based on a template
* @param itemTemplate the item template to generate a Upd for
* @returns A Upd with all the default properties set
* /
2024-07-23 11:12:53 -04:00
public generateUpdForItem ( itemTemplate : ITemplateItem ) : Upd {
2024-05-01 20:17:09 +00:00
const itemProperties : Upd = { } ;
// armors, etc
2024-07-23 11:12:53 -04:00
if ( itemTemplate . _props . MaxDurability ) {
2024-05-01 20:17:09 +00:00
itemProperties . Repairable = {
Durability : itemTemplate._props.MaxDurability ,
MaxDurability : itemTemplate._props.MaxDurability ,
} ;
}
2024-07-23 11:12:53 -04:00
if ( itemTemplate . _props . HasHinge ) {
2024-05-01 20:17:09 +00:00
itemProperties . Togglable = { On : true } ;
}
2024-07-23 11:12:53 -04:00
if ( itemTemplate . _props . Foldable ) {
2024-05-01 20:17:09 +00:00
itemProperties . Foldable = { Folded : false } ;
}
2024-07-23 11:12:53 -04:00
if ( itemTemplate . _props . weapFireType ? . length ) {
if ( itemTemplate . _props . weapFireType . includes ( "fullauto" ) ) {
2024-05-01 20:17:09 +00:00
itemProperties . FireMode = { FireMode : "fullauto" } ;
2024-07-23 11:12:53 -04:00
} else {
2024-05-01 20:17:09 +00:00
itemProperties . FireMode = { FireMode : this.randomUtil.getArrayValue ( itemTemplate . _props . weapFireType ) } ;
}
}
2024-07-23 11:12:53 -04:00
if ( itemTemplate . _props . MaxHpResource ) {
2024-05-01 20:17:09 +00:00
itemProperties . MedKit = { HpResource : itemTemplate._props.MaxHpResource } ;
}
2024-07-23 11:12:53 -04:00
if ( itemTemplate . _props . MaxResource && itemTemplate . _props . foodUseTime ) {
2024-05-01 20:17:09 +00:00
itemProperties . FoodDrink = { HpPercent : itemTemplate._props.MaxResource } ;
}
2024-07-23 11:12:53 -04:00
if ( itemTemplate . _parent === BaseClasses . FLASHLIGHT ) {
2024-05-01 20:17:09 +00:00
itemProperties . Light = { IsActive : false , SelectedMode : 0 } ;
2024-07-23 11:12:53 -04:00
} else if ( itemTemplate . _parent === BaseClasses . TACTICAL_COMBO ) {
2024-05-01 20:17:09 +00:00
itemProperties . Light = { IsActive : false , SelectedMode : 0 } ;
}
2024-07-23 11:12:53 -04:00
if ( itemTemplate . _parent === BaseClasses . NIGHTVISION ) {
2024-05-01 20:17:09 +00:00
itemProperties . Togglable = { On : false } ;
}
// Togglable face shield
2024-07-23 11:12:53 -04:00
if ( itemTemplate . _props . HasHinge && itemTemplate . _props . FaceShieldComponent ) {
2024-05-01 20:17:09 +00:00
itemProperties . Togglable = { On : false } ;
}
return itemProperties ;
}
2023-03-03 15:23:46 +00:00
/ * *
2024-08-15 09:42:07 +01:00
* Checks if a tpl is a valid item . Valid meaning that it ' s an item that be stored in stash
* Valid means :
* Not quest item
* 'Item' type
* Not on the invalid base types array
* Price above 0 roubles
* Not on item config blacklist
2024-02-05 22:02:44 -05:00
* @param { string } tpl the template id / tpl
* @returns boolean ; true for items that may be in player possession and not quest items
2023-03-03 15:23:46 +00:00
* /
2024-07-23 11:12:53 -04:00
public isValidItem ( tpl : string , invalidBaseTypes? : string [ ] ) : boolean {
2024-02-05 22:02:44 -05:00
const baseTypes = invalidBaseTypes || this . defaultInvalidBaseTypes ;
2023-03-03 15:23:46 +00:00
const itemDetails = this . getItem ( tpl ) ;
2024-07-23 11:12:53 -04:00
if ( ! itemDetails [ 0 ] ) {
2023-03-03 15:23:46 +00:00
return false ;
}
2024-05-17 15:32:41 -04:00
return (
2024-07-23 11:12:53 -04:00
! itemDetails [ 1 ] . _props . QuestItem &&
itemDetails [ 1 ] . _type === "Item" &&
baseTypes . every ( ( x ) = > ! this . isOfBaseclass ( tpl , x ) ) &&
this . getItemPrice ( tpl ) > 0 &&
! this . itemFilterService . isItemBlacklisted ( tpl )
2024-05-17 15:32:41 -04:00
) ;
2023-03-03 15:23:46 +00:00
}
/ * *
* Check if the tpl / template Id provided is a descendent of the baseclass
*
* @param { string } tpl the item template id to check
* @param { string } baseClassTpl the baseclass to check for
* @return { boolean } is the tpl a descendent ?
* /
2024-07-23 11:12:53 -04:00
public isOfBaseclass ( tpl : string , baseClassTpl : string ) : boolean {
2023-03-03 15:23:46 +00:00
return this . itemBaseClassService . itemHasBaseClass ( tpl , [ baseClassTpl ] ) ;
}
/ * *
* Check if item has any of the supplied base classes
* @param tpl Item to check base classes of
* @param baseClassTpls base classes to check for
* @returns true if any supplied base classes match
* /
2024-07-23 11:12:53 -04:00
public isOfBaseclasses ( tpl : string , baseClassTpls : string [ ] ) : boolean {
2023-03-03 15:23:46 +00:00
return this . itemBaseClassService . itemHasBaseClass ( tpl , baseClassTpls ) ;
}
2024-01-09 16:49:59 +00:00
/ * *
* Does the provided item have the chance to require soft armor inserts
* Only applies to helmets / vest / armors .
* Not all head gear needs them
* @param itemTpl item to check
* @returns Does item have the possibility ot need soft inserts
* /
2024-07-23 11:12:53 -04:00
public armorItemCanHoldMods ( itemTpl : string ) : boolean {
2024-02-02 13:54:07 -05:00
return this . isOfBaseclasses ( itemTpl , [ BaseClasses . HEADWEAR , BaseClasses . VEST , BaseClasses . ARMOR ] ) ;
2024-01-09 16:49:59 +00:00
}
2024-03-23 11:23:29 +00:00
/ * *
* Does the provided item tpl need soft / removable inserts to function
* @param itemTpl Armor item
* @returns True if item needs some kind of insert
* /
2024-07-23 11:12:53 -04:00
public armorItemHasRemovableOrSoftInsertSlots ( itemTpl : string ) : boolean {
if ( ! this . armorItemCanHoldMods ( itemTpl ) ) {
2024-03-23 11:23:29 +00:00
return false ;
}
2024-05-07 23:57:08 -04:00
return this . armorItemHasRemovablePlateSlots ( itemTpl ) || this . itemRequiresSoftInserts ( itemTpl ) ;
2024-03-23 11:23:29 +00:00
}
2024-02-14 11:12:20 +00:00
/ * *
* Does the pased in tpl have ability to hold removable plate items
* @param itemTpl item tpl to check for plate support
* @returns True when armor can hold plates
* /
2024-07-23 11:12:53 -04:00
public armorItemHasRemovablePlateSlots ( itemTpl : string ) : boolean {
2024-02-14 11:12:20 +00:00
const itemTemplate = this . getItem ( itemTpl ) ;
const plateSlotIds = this . getRemovablePlateSlotIds ( ) ;
2024-05-17 15:32:41 -04:00
return itemTemplate [ 1 ] . _props . Slots . some ( ( slot ) = > plateSlotIds . includes ( slot . _name . toLowerCase ( ) ) ) ;
2024-02-14 11:12:20 +00:00
}
2024-01-11 17:42:58 +00:00
/ * *
* Does the provided item tpl require soft inserts to become a valid armor item
* @param itemTpl Item tpl to check
* @returns True if it needs armor inserts
* /
2024-07-23 11:12:53 -04:00
public itemRequiresSoftInserts ( itemTpl : string ) : boolean {
2024-01-11 17:42:58 +00:00
// not a slot that takes soft-inserts
2024-07-23 11:12:53 -04:00
if ( ! this . armorItemCanHoldMods ( itemTpl ) ) {
2024-01-11 17:42:58 +00:00
return false ;
}
// Check is an item
const itemDbDetails = this . getItem ( itemTpl ) ;
2024-07-23 11:12:53 -04:00
if ( ! itemDbDetails [ 0 ] ) {
2024-01-11 17:42:58 +00:00
return false ;
}
// Has no slots
2024-07-23 11:12:53 -04:00
if ( ! ( itemDbDetails [ 1 ] . _props . Slots ? ? [ ] ) . length ) {
2024-01-11 17:42:58 +00:00
return false ;
}
// Check if item has slots that match soft insert name ids
2024-02-05 09:02:58 +00:00
const softInsertIds = this . getSoftInsertSlotIds ( ) ;
2024-07-23 11:12:53 -04:00
if ( itemDbDetails [ 1 ] . _props . Slots . some ( ( slot ) = > softInsertIds . includes ( slot . _name . toLowerCase ( ) ) ) ) {
2024-01-15 12:41:54 +00:00
return true ;
}
2024-01-11 17:42:58 +00:00
return false ;
}
2024-02-29 12:24:32 +00:00
/ * *
* Get all soft insert slot ids
* @returns An array of soft insert ids ( e . g . soft_armor_back , helmet_top )
* /
2024-07-23 11:12:53 -04:00
public getSoftInsertSlotIds ( ) : string [ ] {
2024-02-04 22:41:11 +00:00
return [
"groin" ,
"groin_back" ,
"soft_armor_back" ,
"soft_armor_front" ,
"soft_armor_left" ,
"soft_armor_right" ,
"shoulder_l" ,
"shoulder_r" ,
"collar" ,
2024-02-05 09:02:58 +00:00
"helmet_top" ,
"helmet_back" ,
2024-02-29 12:24:32 +00:00
"helmet_eyes" ,
"helmet_jaw" ,
2024-02-05 09:02:58 +00:00
"helmet_ears" ,
2024-02-04 22:41:11 +00:00
] ;
}
2024-02-07 20:15:44 +00:00
/ * *
* Returns the items total price based on the handbook or as a fallback from the prices . json if the item is not
* found in the handbook . If the price can ' t be found at all return 0
* @param tpls item tpls to look up the price of
* @returns Total price in roubles
* /
2024-07-23 11:12:53 -04:00
public getItemAndChildrenPrice ( tpls : string [ ] ) : number {
2024-02-07 20:15:44 +00:00
// Run getItemPrice for each tpl in tpls array, return sum
return tpls . reduce ( ( total , tpl ) = > total + this . getItemPrice ( tpl ) , 0 ) ;
}
2023-03-03 15:23:46 +00:00
/ * *
* Returns the item price based on the handbook or as a fallback from the prices . json if the item is not
* found in the handbook . If the price can ' t be found at all return 0
2023-07-20 16:04:26 +01:00
* @param tpl Item to look price up of
* @returns Price in roubles
2023-03-03 15:23:46 +00:00
* /
2024-07-23 11:12:53 -04:00
public getItemPrice ( tpl : string ) : number {
2023-07-20 16:04:26 +01:00
const handbookPrice = this . getStaticItemPrice ( tpl ) ;
2024-07-23 11:12:53 -04:00
if ( handbookPrice >= 1 ) {
2023-07-20 16:04:26 +01:00
return handbookPrice ;
}
2023-11-04 10:28:33 +00:00
const dynamicPrice = this . getDynamicItemPrice ( tpl ) ;
2024-07-23 11:12:53 -04:00
if ( dynamicPrice ) {
2023-07-20 16:04:26 +01:00
return dynamicPrice ;
}
2023-11-07 21:13:41 +00:00
return 0 ;
2023-07-20 16:04:26 +01:00
}
2023-10-10 11:03:20 +00:00
/ * *
* Returns the item price based on the handbook or as a fallback from the prices . json if the item is not
* found in the handbook . If the price can ' t be found at all return 0
* @param tpl Item to look price up of
* @returns Price in roubles
* /
2024-07-23 11:12:53 -04:00
public getItemMaxPrice ( tpl : string ) : number {
2023-10-10 11:03:20 +00:00
const staticPrice = this . getStaticItemPrice ( tpl ) ;
const dynamicPrice = this . getDynamicItemPrice ( tpl ) ;
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
2023-10-10 11:03:20 +00:00
return Math . max ( staticPrice , dynamicPrice ) ;
}
2023-07-20 16:04:26 +01:00
/ * *
* Get the static ( handbook ) price in roubles for an item by tpl
* @param tpl Items tpl id to look up price
* @returns Price in roubles ( 0 if not found )
* /
2024-07-23 11:12:53 -04:00
public getStaticItemPrice ( tpl : string ) : number {
2023-03-03 15:23:46 +00:00
const handbookPrice = this . handbookHelper . getTemplatePrice ( tpl ) ;
2024-07-23 11:12:53 -04:00
if ( handbookPrice >= 1 ) {
2023-03-03 15:23:46 +00:00
return handbookPrice ;
}
2023-07-20 16:04:26 +01:00
return 0 ;
}
/ * *
* Get the dynamic ( flea ) price in roubles for an item by tpl
* @param tpl Items tpl id to look up price
* @returns Price in roubles ( undefined if not found )
* /
2024-07-23 11:12:53 -04:00
public getDynamicItemPrice ( tpl : string ) : number {
2024-05-28 22:24:52 +01:00
const dynamicPrice = this . databaseService . getPrices ( ) [ tpl ] ;
2024-07-23 11:12:53 -04:00
if ( dynamicPrice ) {
2023-03-03 15:23:46 +00:00
return dynamicPrice ;
}
return 0 ;
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
}
2023-03-03 15:23:46 +00:00
2023-10-10 11:03:20 +00:00
/ * *
* Update items upd . StackObjectsCount to be 1 if its upd is missing or StackObjectsCount is undefined
* @param item Item to update
* @returns Fixed item
* /
2024-07-23 11:12:53 -04:00
public fixItemStackCount ( item : Item ) : Item {
if ( item . upd === undefined ) {
2023-11-13 12:38:16 -05:00
item . upd = { StackObjectsCount : 1 } ;
2023-03-03 15:23:46 +00:00
}
2024-07-23 11:12:53 -04:00
if ( item . upd . StackObjectsCount === undefined ) {
2023-03-03 15:23:46 +00:00
item . upd . StackObjectsCount = 1 ;
}
return item ;
}
/ * *
* Get cloned copy of all item data from items . json
* @returns array of ITemplateItem objects
* /
2024-07-23 11:12:53 -04:00
public getItems ( ) : ITemplateItem [ ] {
2024-05-28 22:24:52 +01:00
return this . cloner . clone ( Object . values ( this . databaseService . getItems ( ) ) ) ;
2023-03-03 15:23:46 +00:00
}
/ * *
* Gets item data from items . json
* @param tpl items template id to look up
* @returns bool - is valid + template item object as array
* /
2024-07-23 11:12:53 -04:00
public getItem ( tpl : string ) : [ boolean , ITemplateItem ] {
2023-03-03 15:23:46 +00:00
// -> Gets item from <input: _tpl>
2024-07-23 11:12:53 -04:00
if ( tpl in this . databaseService . getItems ( ) ) {
2024-05-28 22:24:52 +01:00
return [ true , this . databaseService . getItems ( ) [ tpl ] ] ;
2023-03-03 15:23:46 +00:00
}
return [ false , undefined ] ;
}
2024-07-23 11:12:53 -04:00
public itemHasSlots ( itemTpl : string ) : boolean {
2024-02-03 11:00:30 +00:00
return this . getItem ( itemTpl ) [ 1 ] . _props . Slots ? . length > 0 ;
}
2024-07-23 11:12:53 -04:00
public isItemInDb ( tpl : string ) : boolean {
2023-05-19 17:40:06 +01:00
const itemDetails = this . getItem ( tpl ) ;
return itemDetails [ 0 ] ;
}
2024-02-06 20:44:40 +00:00
/ * *
* Calcualte the average quality of an item and its children
* @param items An offers item to process
2024-06-22 20:40:13 +01:00
* @param skipArmorItemsWithoutDurability Skip over armor items without durability
2024-02-06 20:44:40 +00:00
* @returns % quality modifer between 0 and 1
* /
2024-07-23 11:12:53 -04:00
public getItemQualityModifierForItems ( items : Item [ ] , skipArmorItemsWithoutDurability? : boolean ) : number {
if ( this . isOfBaseclass ( items [ 0 ] . _tpl , BaseClasses . WEAPON ) ) {
2024-02-11 14:59:25 +00:00
return this . getItemQualityModifier ( items [ 0 ] ) ;
}
let qualityModifier = 0 ;
2024-06-19 14:27:58 +01:00
let itemsWithQualityCount = 0 ;
2024-07-23 11:12:53 -04:00
for ( const item of items ) {
2024-06-22 20:40:13 +01:00
const result = this . getItemQualityModifier ( item , skipArmorItemsWithoutDurability ) ;
2024-07-23 11:12:53 -04:00
if ( result === - 1 ) {
2024-06-19 14:27:58 +01:00
continue ;
}
qualityModifier += result ;
itemsWithQualityCount ++ ;
2024-02-06 20:44:40 +00:00
}
2024-07-23 11:12:53 -04:00
if ( itemsWithQualityCount === 0 ) {
2024-07-01 16:37:14 +01:00
// Can happen when rigs without soft inserts or plates are listed
return 1 ;
}
2024-06-19 14:27:58 +01:00
return Math . min ( qualityModifier / itemsWithQualityCount , 1 ) ;
2024-02-06 20:44:40 +00:00
}
2023-03-03 15:23:46 +00:00
/ * *
* get normalized value ( 0 - 1 ) based on item condition
2024-06-22 20:40:13 +01:00
* Will return - 1 for base armor items with 0 durability
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
* @param item
2024-06-22 20:40:13 +01:00
* @param skipArmorItemsWithoutDurability return - 1 for armor items that have maxdurability of 0
* @returns Number between 0 and 1
2023-03-03 15:23:46 +00:00
* /
2024-07-23 11:12:53 -04:00
public getItemQualityModifier ( item : Item , skipArmorItemsWithoutDurability? : boolean ) : number {
2023-03-03 15:23:46 +00:00
// Default to 100%
let result = 1 ;
2024-06-22 20:40:13 +01:00
// Is armor and has 0 max durability
const itemDetails = this . getItem ( item . _tpl ) [ 1 ] ;
2024-07-23 11:12:53 -04:00
if (
skipArmorItemsWithoutDurability &&
this . isOfBaseclass ( item . _tpl , BaseClasses . ARMOR ) &&
itemDetails . _props . MaxDurability === 0
) {
2024-06-22 20:40:13 +01:00
return - 1 ;
}
2024-07-23 11:12:53 -04:00
if ( item . upd ) {
2024-05-27 20:06:07 +00:00
const medkit = item . upd . MedKit ? item.upd.MedKit : undefined ;
const repairable = item . upd . Repairable ? item.upd.Repairable : undefined ;
const foodDrink = item . upd . FoodDrink ? item.upd.FoodDrink : undefined ;
const key = item . upd . Key ? item.upd.Key : undefined ;
const resource = item . upd . Resource ? item.upd.Resource : undefined ;
const repairKit = item . upd . RepairKit ? item.upd.RepairKit : undefined ;
2023-03-03 15:23:46 +00:00
2024-07-23 11:12:53 -04:00
if ( medkit ) {
2023-03-03 15:23:46 +00:00
// Meds
result = medkit . HpResource / itemDetails . _props . MaxHpResource ;
2024-07-23 11:12:53 -04:00
} else if ( repairable ) {
2023-03-03 15:23:46 +00:00
result = this . getRepairableItemQualityValue ( itemDetails , repairable , item ) ;
2024-07-23 11:12:53 -04:00
} else if ( foodDrink ) {
2023-03-03 15:23:46 +00:00
// food & drink
result = foodDrink . HpPercent / itemDetails . _props . MaxResource ;
2024-07-23 11:12:53 -04:00
} else if ( key && key . NumberOfUsages > 0 && itemDetails . _props . MaximumNumberOfUsage > 0 ) {
2023-03-03 15:23:46 +00:00
// keys - keys count upwards, not down like everything else
const maxNumOfUsages = itemDetails . _props . MaximumNumberOfUsage ;
result = ( maxNumOfUsages - key . NumberOfUsages ) / maxNumOfUsages ;
2024-07-23 11:12:53 -04:00
} else if ( resource && resource . UnitsConsumed > 0 ) {
2023-03-03 15:23:46 +00:00
// Things like fuel tank
2023-10-10 11:03:20 +00:00
result = resource . Value / itemDetails . _props . MaxResource ;
2024-07-23 11:12:53 -04:00
} else if ( repairKit ) {
2023-03-03 15:23:46 +00:00
// Repair kits
result = repairKit . Resource / itemDetails . _props . MaxRepairResource ;
}
2024-07-23 11:12:53 -04:00
if ( result === 0 ) {
2023-03-03 15:23:46 +00:00
// make item non-zero but still very low
result = 0.01 ;
}
2024-02-11 14:59:25 +00:00
return result ;
2023-03-03 15:23:46 +00:00
}
2024-06-19 14:27:58 +01:00
return result ;
2023-03-03 15:23:46 +00:00
}
/ * *
* Get a quality value based on a repairable items ( weapon / armor ) current state between current and max durability
2023-10-10 11:03:20 +00:00
* @param itemDetails Db details for item we want quality value for
* @param repairable Repairable properties
* @param item Item quality value is for
* @returns A number between 0 and 1
2023-03-03 15:23:46 +00:00
* /
2024-07-23 11:12:53 -04:00
protected getRepairableItemQualityValue ( itemDetails : ITemplateItem , repairable : Repairable , item : Item ) : number {
2023-11-05 13:16:59 +00:00
// Edge case, max durability is below durability
2024-07-23 11:12:53 -04:00
if ( repairable . Durability > repairable . MaxDurability ) {
2023-11-13 11:07:59 -05:00
this . logger . warning (
2024-04-11 21:04:06 -04:00
` Max durability: ${ repairable . MaxDurability } for item id: ${ item . _id } was below durability: ${ repairable . Durability } , adjusting values to match ` ,
2023-11-13 11:07:59 -05:00
) ;
2023-11-05 13:16:59 +00:00
repairable . MaxDurability = repairable . Durability ;
}
2024-04-11 21:04:06 -04:00
// Attempt to get the max durability from _props. If not available, use Repairable max durability value instead.
2024-05-07 23:57:08 -04:00
const maxDurability = itemDetails . _props . MaxDurability
2023-11-13 12:29:16 -05:00
? itemDetails . _props . MaxDurability
: repairable . MaxDurability ;
2023-11-05 13:19:10 +00:00
const durability = repairable . Durability / maxDurability ;
2023-03-03 15:23:46 +00:00
2024-07-23 11:12:53 -04:00
if ( ! durability ) {
2023-11-05 13:19:10 +00:00
this . logger . error ( this . localisationService . getText ( "item-durability_value_invalid_use_default" , item . _tpl ) ) ;
2023-03-03 15:23:46 +00:00
2023-11-05 13:19:10 +00:00
return 1 ;
2023-03-03 15:23:46 +00:00
}
2023-11-05 13:19:10 +00:00
return Math . sqrt ( durability ) ;
2023-03-03 15:23:46 +00:00
}
/ * *
2023-04-24 12:47:19 +01:00
* Recursive function that looks at every item from parameter and gets their childrens Ids + includes parent item in results
2023-10-10 11:03:20 +00:00
* @param items Array of items ( item + possible children )
2024-01-08 23:27:18 +00:00
* @param baseItemId Parent items id
2023-03-03 15:23:46 +00:00
* @returns an array of strings
* /
2024-07-23 11:12:53 -04:00
public findAndReturnChildrenByItems ( items : Item [ ] , baseItemId : string ) : string [ ] {
2023-03-03 15:23:46 +00:00
const list : string [ ] = [ ] ;
2024-07-23 11:12:53 -04:00
for ( const childitem of items ) {
if ( childitem . parentId === baseItemId ) {
2023-03-03 15:23:46 +00:00
list . push ( . . . this . findAndReturnChildrenByItems ( items , childitem . _id ) ) ;
}
}
2024-01-08 23:27:18 +00:00
list . push ( baseItemId ) ; // Required, push original item id onto array
2023-10-10 11:03:20 +00:00
2023-03-03 15:23:46 +00:00
return list ;
}
/ * *
* A variant of findAndReturnChildren where the output is list of item objects instead of their ids .
2024-01-08 23:27:18 +00:00
* @param items Array of items ( item + possible children )
* @param baseItemId Parent items id
2024-01-23 20:00:36 +00:00
* @param modsOnly Include only mod items , exclude items stored inside root item
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
* @returns An array of Item objects
2023-03-03 15:23:46 +00:00
* /
2024-07-23 11:12:53 -04:00
public findAndReturnChildrenAsItems ( items : Item [ ] , baseItemId : string , modsOnly = false ) : Item [ ] {
2023-03-03 15:23:46 +00:00
const list : Item [ ] = [ ] ;
2024-07-23 11:12:53 -04:00
for ( const childItem of items ) {
2023-10-10 11:03:20 +00:00
// Include itself
2024-07-23 11:12:53 -04:00
if ( childItem . _id === baseItemId ) {
2023-03-03 15:23:46 +00:00
list . unshift ( childItem ) ;
continue ;
}
2024-01-23 20:00:36 +00:00
// Is stored in parent and disallowed
2024-07-23 11:12:53 -04:00
if ( modsOnly && childItem . location ) {
2024-01-23 20:00:36 +00:00
continue ;
}
// Items parentid matches root item AND returned items doesnt contain current child
2024-07-23 11:12:53 -04:00
if ( childItem . parentId === baseItemId && ! list . some ( ( item ) = > childItem . _id === item . _id ) ) {
2023-03-03 15:23:46 +00:00
list . push ( . . . this . findAndReturnChildrenAsItems ( items , childItem . _id ) ) ;
}
}
2023-10-10 11:03:20 +00:00
2023-03-03 15:23:46 +00:00
return list ;
}
/ * *
* Find children of the item in a given assort ( weapons parts for example , need recursive loop function )
* @param itemIdToFind Template id of item to check for
* @param assort Array of items to check in
* @returns Array of children of requested item
* /
2024-07-23 11:12:53 -04:00
public findAndReturnChildrenByAssort ( itemIdToFind : string , assort : Item [ ] ) : Item [ ] {
2023-03-03 15:23:46 +00:00
let list : Item [ ] = [ ] ;
2024-07-23 11:12:53 -04:00
for ( const itemFromAssort of assort ) {
if ( itemFromAssort . parentId === itemIdToFind && ! list . some ( ( item ) = > itemFromAssort . _id === item . _id ) ) {
2023-03-03 15:23:46 +00:00
list . push ( itemFromAssort ) ;
list = list . concat ( this . findAndReturnChildrenByAssort ( itemFromAssort . _id , assort ) ) ;
}
}
return list ;
}
/ * *
* Check if the passed in item has buy count restrictions
* @param itemToCheck Item to check
* @returns true if it has buy restrictions
* /
2024-07-23 11:12:53 -04:00
public hasBuyRestrictions ( itemToCheck : Item ) : boolean {
if ( itemToCheck . upd ? . BuyRestrictionCurrent !== undefined && itemToCheck . upd ? . BuyRestrictionMax !== undefined ) {
2023-03-03 15:23:46 +00:00
return true ;
}
return false ;
}
/ * *
* is the passed in template id a dog tag
* @param tpl Template id to check
* @returns true if it is a dogtag
* /
2024-07-23 11:12:53 -04:00
public isDogtag ( tpl : string ) : boolean {
2024-06-14 14:38:30 +01:00
const dogTagTpls = [
2024-06-16 08:33:01 +00:00
ItemTpl . BARTER_DOGTAG_BEAR ,
ItemTpl . BARTER_DOGTAG_BEAR_EOD ,
ItemTpl . BARTER_DOGTAG_BEAR_TUE ,
ItemTpl . BARTER_DOGTAG_USEC ,
ItemTpl . BARTER_DOGTAG_USEC_EOD ,
ItemTpl . BARTER_DOGTAG_USEC_TUE ,
2024-06-14 14:38:30 +01:00
] ;
return dogTagTpls . includes ( < any > tpl ) ;
2023-03-03 15:23:46 +00:00
}
/ * *
* Gets the identifier for a child using slotId , locationX and locationY .
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
* @param item
2023-03-03 15:23:46 +00:00
* @returns "slotId OR slotid,locationX,locationY"
* /
2024-07-23 11:12:53 -04:00
public getChildId ( item : Item ) : string {
if ( ! ( "location" in item ) ) {
2023-03-03 15:23:46 +00:00
return item . slotId ;
}
return ` ${ item . slotId } , ${ ( item . location as Location ) . x } , ${ ( item . location as Location ) . y } ` ;
}
/ * *
* Can the passed in item be stacked
* @param tpl item to check
* @returns true if it can be stacked
* /
2024-07-23 11:12:53 -04:00
public isItemTplStackable ( tpl : string ) : boolean {
2024-05-28 22:24:52 +01:00
const item = this . databaseService . getItems ( ) [ tpl ] ;
2024-07-23 11:12:53 -04:00
if ( ! item ) {
2023-11-05 12:37:17 +00:00
return undefined ;
}
return item . _props . StackMaxSize > 1 ;
2023-03-03 15:23:46 +00:00
}
/ * *
2024-02-02 15:35:02 +00:00
* Split item stack if it exceeds its items StackMaxSize property into child items of passed in parent
2023-10-10 11:03:20 +00:00
* @param itemToSplit Item to split into smaller stacks
2024-02-01 11:23:32 +00:00
* @returns Array of root item + children
2023-03-03 15:23:46 +00:00
* /
2024-07-23 11:12:53 -04:00
public splitStack ( itemToSplit : Item ) : Item [ ] {
if ( itemToSplit ? . upd ? . StackObjectsCount === undefined ) {
2023-03-21 14:19:49 +00:00
return [ itemToSplit ] ;
2023-03-03 15:23:46 +00:00
}
2024-02-01 11:23:32 +00:00
const maxStackSize = this . getItem ( itemToSplit . _tpl ) [ 1 ] . _props . StackMaxSize ;
2023-03-21 14:19:49 +00:00
let remainingCount = itemToSplit . upd . StackObjectsCount ;
2024-02-01 11:23:32 +00:00
const rootAndChildren : Item [ ] = [ ] ;
2023-03-03 15:23:46 +00:00
// If the current count is already equal or less than the max
2024-02-01 11:23:32 +00:00
// return the item as is.
2024-07-23 11:12:53 -04:00
if ( remainingCount <= maxStackSize ) {
2024-05-13 17:58:17 +00:00
rootAndChildren . push ( this . cloner . clone ( itemToSplit ) ) ;
2023-03-21 14:19:49 +00:00
2024-02-01 11:23:32 +00:00
return rootAndChildren ;
2023-03-03 15:23:46 +00:00
}
2024-07-23 11:12:53 -04:00
while ( remainingCount ) {
2023-03-21 14:19:49 +00:00
const amount = Math . min ( remainingCount , maxStackSize ) ;
2024-05-13 17:58:17 +00:00
const newStackClone = this . cloner . clone ( itemToSplit ) ;
2023-03-03 15:23:46 +00:00
2024-02-05 14:43:46 +00:00
newStackClone . _id = this . hashUtil . generate ( ) ;
newStackClone . upd . StackObjectsCount = amount ;
2023-03-21 14:19:49 +00:00
remainingCount -= amount ;
2024-02-05 14:43:46 +00:00
rootAndChildren . push ( newStackClone ) ;
2023-03-03 15:23:46 +00:00
}
2024-02-01 11:23:32 +00:00
return rootAndChildren ;
2023-03-03 15:23:46 +00:00
}
2024-02-02 15:35:02 +00:00
/ * *
* Turn items like money into separate stacks that adhere to max stack size
* @param itemToSplit Item to split into smaller stacks
2024-02-02 13:54:07 -05:00
* @returns
2024-02-02 15:35:02 +00:00
* /
2024-07-23 11:12:53 -04:00
public splitStackIntoSeparateItems ( itemToSplit : Item ) : Item [ ] [ ] {
2024-02-02 15:35:02 +00:00
const itemTemplate = this . getItem ( itemToSplit . _tpl ) [ 1 ] ;
const itemMaxStackSize = itemTemplate . _props . StackMaxSize ? ? 1 ;
// item already within bounds of stack size, return it
2024-07-23 11:12:53 -04:00
if ( itemToSplit . upd ? . StackObjectsCount <= itemMaxStackSize ) {
2024-02-02 15:35:02 +00:00
return [ [ itemToSplit ] ] ;
}
// Split items stack into chunks
const result : Item [ ] [ ] = [ ] ;
let remainingCount = itemToSplit . upd . StackObjectsCount ;
2024-07-23 11:12:53 -04:00
while ( remainingCount ) {
2024-02-02 15:35:02 +00:00
const amount = Math . min ( remainingCount , itemMaxStackSize ) ;
2024-05-13 17:58:17 +00:00
const newItemClone = this . cloner . clone ( itemToSplit ) ;
2024-02-02 15:35:02 +00:00
2024-02-05 14:43:46 +00:00
newItemClone . _id = this . hashUtil . generate ( ) ;
newItemClone . upd . StackObjectsCount = amount ;
2024-02-02 15:35:02 +00:00
remainingCount -= amount ;
2024-02-05 14:43:46 +00:00
result . push ( [ newItemClone ] ) ;
2024-02-02 15:35:02 +00:00
}
return result ;
}
2023-03-03 15:23:46 +00:00
/ * *
2023-10-10 11:03:20 +00:00
* Find Barter items from array of items
2023-03-21 14:19:49 +00:00
* @param { string } by tpl or id
2024-01-16 18:25:03 +00:00
* @param { Item [ ] } itemsToSearch Array of items to iterate over
* @param { string } desiredBarterItemIds
2023-03-03 15:23:46 +00:00
* @returns Array of Item objects
* /
2024-07-23 11:12:53 -04:00
public findBarterItems ( by : "tpl" | "id" , itemsToSearch : Item [ ] , desiredBarterItemIds : string | string [ ] ) : Item [ ] {
2024-01-16 18:25:03 +00:00
// Find required items to take after buying (handles multiple items)
2024-07-23 11:12:53 -04:00
const desiredBarterIds =
typeof desiredBarterItemIds === "string" ? [ desiredBarterItemIds ] : desiredBarterItemIds ;
2023-03-03 15:23:46 +00:00
2024-01-16 18:25:03 +00:00
const matchingItems : Item [ ] = [ ] ;
2024-07-23 11:12:53 -04:00
for ( const barterId of desiredBarterIds ) {
const filterResult = itemsToSearch . filter ( ( item ) = > {
2024-05-07 23:57:08 -04:00
return by === "tpl" ? item . _tpl === barterId : item._id === barterId ;
2023-03-03 15:23:46 +00:00
} ) ;
2024-01-19 22:49:31 +00:00
matchingItems . push ( . . . filterResult ) ;
2023-03-21 14:19:49 +00:00
}
2024-07-23 11:12:53 -04:00
if ( matchingItems . length === 0 ) {
2024-01-16 18:25:03 +00:00
this . logger . warning ( ` No items found for barter Id: ${ desiredBarterIds } ` ) ;
2023-03-03 15:23:46 +00:00
}
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
2024-01-16 18:25:03 +00:00
return matchingItems ;
2023-03-03 15:23:46 +00:00
}
2024-09-13 20:51:22 +01:00
/ * *
* Replace the _id value for base item + all children that are children of it
* REPARENTS ROOT ITEM ID , NOTHING ELSE
* @param itemWithChildren Item with mods to update
* @param newId new id to add on chidren of base item
* /
public replaceRootItemID ( itemWithChildren : Item [ ] , newId = this . objectId . generate ( ) ) : void {
// original id on base item
const oldId = itemWithChildren [ 0 ] . _id ;
// Update base item to use new id
itemWithChildren [ 0 ] . _id = newId ;
// Update all parentIds of items attached to base item to use new id
for ( const item of itemWithChildren ) {
if ( item . parentId === oldId ) {
item . parentId = newId ;
}
}
}
2023-03-03 15:23:46 +00:00
/ * *
2024-02-05 22:22:03 -05:00
* Regenerate all GUIDs with new IDs , for the exception of special item types ( e . g . quest , sorting table , etc . ) This
* function will not mutate the original items array , but will return a new array with new GUIDs .
*
* @param originalItems Items to adjust the IDs of
2023-07-13 14:20:31 +01:00
* @param pmcData Player profile
2024-02-05 22:22:03 -05:00
* @param insuredItems Insured items that should not have their IDs replaced
* @param fastPanel Quick slot panel
2023-07-13 17:32:50 +01:00
* @returns Item [ ]
2023-03-03 15:23:46 +00:00
* /
2024-02-05 22:22:03 -05:00
public replaceIDs (
originalItems : Item [ ] ,
2024-05-27 20:06:07 +00:00
pmcData? : IPmcData ,
2024-07-05 09:39:01 +01:00
insuredItems? : IInsuredItem [ ] ,
2024-05-27 20:06:07 +00:00
fastPanel? : any ,
2024-07-23 11:12:53 -04:00
) : Item [ ] {
2024-05-13 17:58:17 +00:00
let items = this . cloner . clone ( originalItems ) ; // Deep-clone the items to avoid mutation.
2023-03-03 15:23:46 +00:00
let serialisedInventory = this . jsonUtil . serialize ( items ) ;
2024-08-21 13:26:10 +01:00
const hideoutAreaStashes = Object . values ( pmcData ? . Inventory . hideoutAreaStashes ? ? { } ) ;
2023-03-03 15:23:46 +00:00
2024-07-23 11:12:53 -04:00
for ( const item of items ) {
if ( pmcData ) {
2024-02-05 22:22:03 -05:00
// Insured items should not be renamed. Only works for PMCs.
2024-07-23 11:12:53 -04:00
if ( insuredItems ? . find ( ( insuredItem ) = > insuredItem . itemId === item . _id ) ) {
2023-03-03 15:23:46 +00:00
continue ;
}
2024-02-05 22:22:03 -05:00
// Do not replace the IDs of specific types of items.
2023-11-13 11:07:59 -05:00
if (
2024-07-23 11:12:53 -04:00
item . _id === pmcData . Inventory . equipment ||
item . _id === pmcData . Inventory . questRaidItems ||
item . _id === pmcData . Inventory . questStashItems ||
item . _id === pmcData . Inventory . sortingTable ||
2024-08-21 13:26:10 +01:00
item . _id === pmcData . Inventory . stash ||
hideoutAreaStashes ? . includes ( item . _id )
2024-07-23 11:12:53 -04:00
) {
2023-03-03 15:23:46 +00:00
continue ;
}
}
2024-02-05 22:22:03 -05:00
// Replace the ID of the item in the serialised inventory using a regular expression.
2023-03-03 15:23:46 +00:00
const oldId = item . _id ;
const newId = this . hashUtil . generate ( ) ;
serialisedInventory = serialisedInventory . replace ( new RegExp ( oldId , "g" ) , newId ) ;
// Also replace in quick slot if the old ID exists.
2024-07-23 11:12:53 -04:00
if ( fastPanel ) {
for ( const itemSlot in fastPanel ) {
if ( fastPanel [ itemSlot ] === oldId ) {
2023-03-03 15:23:46 +00:00
fastPanel [ itemSlot ] = fastPanel [ itemSlot ] . replace ( new RegExp ( oldId , "g" ) , newId ) ;
}
}
}
}
items = this . jsonUtil . deserialize ( serialisedInventory ) ;
// fix duplicate id's
const dupes : Record < string , number > = { } ;
const newParents : Record < string , Item [ ] > = { } ;
const childrenMapping = { } ;
const oldToNewIds : Record < string , string [ ] > = { } ;
// Finding duplicate IDs involves scanning the item three times.
// First scan - Check which ids are duplicated.
// Second scan - Map parents to items.
// Third scan - Resolve IDs.
2024-07-23 11:12:53 -04:00
for ( const item of items ) {
2023-03-03 15:23:46 +00:00
dupes [ item . _id ] = ( dupes [ item . _id ] || 0 ) + 1 ;
}
2024-07-23 11:12:53 -04:00
for ( const item of items ) {
2023-03-03 15:23:46 +00:00
// register the parents
2024-07-23 11:12:53 -04:00
if ( dupes [ item . _id ] > 1 ) {
2023-03-03 15:23:46 +00:00
const newId = this . hashUtil . generate ( ) ;
newParents [ item . parentId ] = newParents [ item . parentId ] || [ ] ;
newParents [ item . parentId ] . push ( item ) ;
oldToNewIds [ item . _id ] = oldToNewIds [ item . _id ] || [ ] ;
oldToNewIds [ item . _id ] . push ( newId ) ;
}
}
2024-07-23 11:12:53 -04:00
for ( const item of items ) {
if ( dupes [ item . _id ] > 1 ) {
2023-03-03 15:23:46 +00:00
const oldId = item . _id ;
const newId = oldToNewIds [ oldId ] . splice ( 0 , 1 ) [ 0 ] ;
item . _id = newId ;
// Extract one of the children that's also duplicated.
2024-07-23 11:12:53 -04:00
if ( oldId in newParents && newParents [ oldId ] . length > 0 ) {
2023-03-03 15:23:46 +00:00
childrenMapping [ newId ] = { } ;
2024-07-23 11:12:53 -04:00
for ( const childIndex in newParents [ oldId ] ) {
2023-03-03 15:23:46 +00:00
// Make sure we haven't already assigned another duplicate child of
// same slot and location to this parent.
const childId = this . getChildId ( newParents [ oldId ] [ childIndex ] ) ;
2024-07-23 11:12:53 -04:00
if ( ! ( childId in childrenMapping [ newId ] ) ) {
2023-03-03 15:23:46 +00:00
childrenMapping [ newId ] [ childId ] = 1 ;
newParents [ oldId ] [ childIndex ] . parentId = newId ;
// Some very fucking sketchy stuff on this childIndex
// No clue wth was that childIndex supposed to be, but its not
newParents [ oldId ] . splice ( Number . parseInt ( childIndex ) , 1 ) ;
}
}
}
}
}
return items ;
}
2024-03-07 08:43:15 +00:00
/ * *
* Mark the passed in array of items as found in raid .
* Modifies passed in items
* @param items The list of items to mark as FiR
* /
2024-07-23 11:12:53 -04:00
public setFoundInRaid ( items : Item [ ] ) : void {
for ( const item of items ) {
if ( ! item . upd ) {
2024-03-07 08:43:15 +00:00
item . upd = { } ;
}
item . upd . SpawnedInSession = true ;
}
}
2023-03-03 15:23:46 +00:00
/ * *
* WARNING , SLOW . Recursively loop down through an items hierarchy to see if any of the ids match the supplied list , return true if any do
2023-03-03 17:53:28 +00:00
* @param { string } tpl Items tpl to check parents of
* @param { Array } tplsToCheck Tpl values to check if parents of item match
* @returns boolean Match found
2023-03-03 15:23:46 +00:00
* /
2024-07-23 11:12:53 -04:00
public doesItemOrParentsIdMatch ( tpl : string , tplsToCheck : string [ ] ) : boolean {
2023-03-03 15:23:46 +00:00
const itemDetails = this . getItem ( tpl ) ;
const itemExists = itemDetails [ 0 ] ;
const item = itemDetails [ 1 ] ;
// not an item, drop out
2024-07-23 11:12:53 -04:00
if ( ! itemExists ) {
2023-03-03 15:23:46 +00:00
return false ;
}
// no parent to check
2024-07-23 11:12:53 -04:00
if ( ! item . _parent ) {
2023-03-03 15:23:46 +00:00
return false ;
}
// Does templateId match any values in tplsToCheck array
2024-07-23 11:12:53 -04:00
if ( tplsToCheck . includes ( item . _id ) ) {
2023-03-03 15:23:46 +00:00
return true ;
}
// Does the items parent type exist in tplsToCheck array
2024-07-23 11:12:53 -04:00
if ( tplsToCheck . includes ( item . _parent ) ) {
2023-03-03 15:23:46 +00:00
return true ;
}
// check items parent with same method
return this . doesItemOrParentsIdMatch ( item . _parent , tplsToCheck ) ;
}
/ * *
2023-03-03 17:53:28 +00:00
* Check if item is quest item
* @param tpl Items tpl to check quest status of
* @returns true if item is flagged as quest item
2023-03-03 15:23:46 +00:00
* /
2024-07-23 11:12:53 -04:00
public isQuestItem ( tpl : string ) : boolean {
2023-03-03 15:23:46 +00:00
const itemDetails = this . getItem ( tpl ) ;
2024-07-23 11:12:53 -04:00
if ( itemDetails [ 0 ] && itemDetails [ 1 ] . _props . QuestItem ) {
2023-03-03 15:23:46 +00:00
return true ;
}
return false ;
}
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
/ * *
* Checks to see if the item is * actually * moddable in - raid . Checks include the items existence in the database , the
* parent items existence in the database , the existence ( and value ) of the items RaidModdable property , and that
* the parents slot - required property exists , matches that of the item , and it ' s value .
*
* Note : this function does not preform any checks to see if the item and parent are * actually * related .
*
* @param item The item to be checked
* @param parent The parent of the item to be checked
2024-05-27 20:06:07 +00:00
* @returns True if the item is actually moddable , false if it is not , and undefined if the check cannot be performed .
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
* /
2024-07-23 11:12:53 -04:00
public isRaidModdable ( item : Item , parent : Item ) : boolean | undefined {
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
// This check requires the item to have the slotId property populated.
2024-07-23 11:12:53 -04:00
if ( ! item . slotId ) {
2024-05-27 20:06:07 +00:00
return undefined ;
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
}
const itemTemplate = this . getItem ( item . _tpl ) ;
const parentTemplate = this . getItem ( parent . _tpl ) ;
// Check for RaidModdable property on the item template.
let isNotRaidModdable = false ;
2024-07-23 11:12:53 -04:00
if ( itemTemplate [ 0 ] ) {
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
isNotRaidModdable = itemTemplate [ 1 ] ? . _props ? . RaidModdable === false ;
}
// Check to see if the slot that the item is attached to is marked as required in the parent item's template.
let isRequiredSlot = false ;
2024-07-23 11:12:53 -04:00
if ( parentTemplate [ 0 ] && parentTemplate [ 1 ] ? . _props ? . Slots ) {
2024-05-17 15:32:41 -04:00
isRequiredSlot = parentTemplate [ 1 ] . _props . Slots . some (
( slot ) = > slot . _name === item . slotId && slot . _required ,
2023-11-13 11:07:59 -05:00
) ;
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
}
return itemTemplate [ 0 ] && parentTemplate [ 0 ] && ! ( isNotRaidModdable || isRequiredSlot ) ;
}
/ * *
* Retrieves the main parent item for a given attachment item .
*
* This method traverses up the hierarchy of items starting from a given ` itemId ` , until it finds the main parent
* item that is not an attached attachment itself . In other words , if you pass it an item id of a suppressor , it
* will traverse up the muzzle brake , barrel , upper receiver , and return the gun that the suppressor is ultimately
* attached to , even if that gun is located within multiple containers .
*
* It ' s important to note that traversal is expensive , so this method requires that you pass it a Map of the items
* to traverse , where the keys are the item IDs and the values are the corresponding Item objects . This alleviates
* some of the performance concerns , as it allows for quick lookups of items by ID .
*
* @param itemId - The unique identifier of the item for which to find the main parent .
* @param itemsMap - A Map containing item IDs mapped to their corresponding Item objects for quick lookup .
2024-05-27 20:06:07 +00:00
* @returns The Item object representing the top - most parent of the given item , or ` undefined ` if no such parent exists .
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
* /
2024-07-23 11:12:53 -04:00
public getAttachmentMainParent ( itemId : string , itemsMap : Map < string , Item > ) : Item | undefined {
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
let currentItem = itemsMap . get ( itemId ) ;
2024-07-23 11:12:53 -04:00
while ( currentItem && this . isAttachmentAttached ( currentItem ) ) {
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
currentItem = itemsMap . get ( currentItem . parentId ) ;
2024-07-23 11:12:53 -04:00
if ( ! currentItem ) {
2024-05-27 20:06:07 +00:00
return undefined ;
2023-11-02 01:47:28 -04:00
}
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
}
return currentItem ;
}
/ * *
* Determines if an item is an attachment that is currently attached to it ' s parent item .
*
* @param item The item to check .
* @returns true if the item is attached attachment , otherwise false .
* /
2024-07-23 11:12:53 -04:00
public isAttachmentAttached ( item : Item ) : boolean {
2024-05-17 15:32:41 -04:00
const equipmentSlots = Object . values ( EquipmentSlots ) . map ( ( value ) = > value as string ) ;
2024-02-08 15:56:45 -05:00
2024-05-17 15:32:41 -04:00
return ! (
2024-07-23 11:12:53 -04:00
[ "hideout" , "main" ] . includes ( item . slotId ) ||
equipmentSlots . includes ( item . slotId ) ||
! Number . isNaN ( Number ( item . slotId ) )
2024-05-17 15:32:41 -04:00
) ;
2024-02-08 15:56:45 -05:00
}
/ * *
* Retrieves the equipment parent item for a given item .
*
* This method traverses up the hierarchy of items starting from a given ` itemId ` , until it finds the equipment
* parent item . In other words , if you pass it an item id of a suppressor , it will traverse up the muzzle brake ,
* barrel , upper receiver , gun , nested backpack , and finally return the backpack Item that is equipped .
*
* It ' s important to note that traversal is expensive , so this method requires that you pass it a Map of the items
* to traverse , where the keys are the item IDs and the values are the corresponding Item objects . This alleviates
* some of the performance concerns , as it allows for quick lookups of items by ID .
*
* @param itemId - The unique identifier of the item for which to find the equipment parent .
* @param itemsMap - A Map containing item IDs mapped to their corresponding Item objects for quick lookup .
2024-05-27 20:06:07 +00:00
* @returns The Item object representing the equipment parent of the given item , or ` undefined ` if no such parent exists .
2024-02-08 15:56:45 -05:00
* /
2024-07-23 11:12:53 -04:00
public getEquipmentParent ( itemId : string , itemsMap : Map < string , Item > ) : Item | undefined {
2024-02-08 15:56:45 -05:00
let currentItem = itemsMap . get ( itemId ) ;
2024-05-17 15:32:41 -04:00
const equipmentSlots = Object . values ( EquipmentSlots ) . map ( ( value ) = > value as string ) ;
2024-02-08 15:56:45 -05:00
2024-07-23 11:12:53 -04:00
while ( currentItem && ! equipmentSlots . includes ( currentItem . slotId ) ) {
2024-02-08 15:56:45 -05:00
currentItem = itemsMap . get ( currentItem . parentId ) ;
2024-07-23 11:12:53 -04:00
if ( ! currentItem ) {
2024-05-27 20:06:07 +00:00
return undefined ;
2024-02-08 15:56:45 -05:00
}
}
return currentItem ;
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
}
2023-03-03 15:23:46 +00:00
/ * *
* Get the inventory size of an item
2023-03-03 17:53:28 +00:00
* @param items Item with children
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
* @param rootItemId
2023-03-03 15:23:46 +00:00
* @returns ItemSize object ( width and height )
* /
2024-07-23 11:12:53 -04:00
public getItemSize ( items : Item [ ] , rootItemId : string ) : ItemHelper . ItemSize {
2024-05-17 15:32:41 -04:00
const rootTemplate = this . getItem ( items . filter ( ( x ) = > x . _id === rootItemId ) [ 0 ] . _tpl ) [ 1 ] ;
2023-03-03 15:23:46 +00:00
const width = rootTemplate . _props . Width ;
const height = rootTemplate . _props . Height ;
let sizeUp = 0 ;
let sizeDown = 0 ;
let sizeLeft = 0 ;
let sizeRight = 0 ;
let forcedUp = 0 ;
let forcedDown = 0 ;
let forcedLeft = 0 ;
let forcedRight = 0 ;
const children = this . findAndReturnChildrenAsItems ( items , rootItemId ) ;
2024-07-23 11:12:53 -04:00
for ( const ci of children ) {
2023-03-03 15:23:46 +00:00
const itemTemplate = this . getItem ( ci . _tpl ) [ 1 ] ;
// Calculating child ExtraSize
2024-07-23 11:12:53 -04:00
if ( itemTemplate . _props . ExtraSizeForceAdd === true ) {
2023-03-03 15:23:46 +00:00
forcedUp += itemTemplate . _props . ExtraSizeUp ;
forcedDown += itemTemplate . _props . ExtraSizeDown ;
forcedLeft += itemTemplate . _props . ExtraSizeLeft ;
forcedRight += itemTemplate . _props . ExtraSizeRight ;
2024-07-23 11:12:53 -04:00
} else {
2023-03-03 15:23:46 +00:00
sizeUp = sizeUp < itemTemplate . _props . ExtraSizeUp ? itemTemplate._props.ExtraSizeUp : sizeUp ;
sizeDown = sizeDown < itemTemplate . _props . ExtraSizeDown ? itemTemplate._props.ExtraSizeDown : sizeDown ;
sizeLeft = sizeLeft < itemTemplate . _props . ExtraSizeLeft ? itemTemplate._props.ExtraSizeLeft : sizeLeft ;
2024-07-23 11:12:53 -04:00
sizeRight =
sizeRight < itemTemplate . _props . ExtraSizeRight ? itemTemplate._props.ExtraSizeRight : sizeRight ;
2023-03-03 15:23:46 +00:00
}
}
return {
width : width + sizeLeft + sizeRight + forcedLeft + forcedRight ,
2023-11-13 11:07:59 -05:00
height : height + sizeUp + sizeDown + forcedUp + forcedDown ,
2023-03-03 15:23:46 +00:00
} ;
}
/ * *
* Get a random cartridge from an items Filter property
2023-03-03 17:53:28 +00:00
* @param item Db item template to look up Cartridge filter values from
* @returns Caliber of cartridge
2023-03-03 15:23:46 +00:00
* /
2024-07-23 11:12:53 -04:00
public getRandomCompatibleCaliberTemplateId ( item : ITemplateItem ) : string | undefined {
2023-11-07 22:59:04 -05:00
const cartridges = item ? . _props ? . Cartridges [ 0 ] ? . _props ? . filters [ 0 ] ? . Filter ;
2023-03-03 15:23:46 +00:00
2024-07-23 11:12:53 -04:00
if ( ! cartridges ) {
2023-11-07 22:59:04 -05:00
this . logger . warning ( ` Failed to find cartridge for item: ${ item ? . _id } ${ item ? . _name } ` ) ;
2024-05-27 20:06:07 +00:00
return undefined ;
2023-03-03 15:23:46 +00:00
}
2023-11-07 22:59:04 -05:00
return this . randomUtil . getArrayValue ( cartridges ) ;
2023-03-03 15:23:46 +00:00
}
/ * *
* Add cartridges to the ammo box with correct max stack sizes
* @param ammoBox Box to add cartridges to
* @param ammoBoxDetails Item template from items db
* /
2024-07-23 11:12:53 -04:00
public addCartridgesToAmmoBox ( ammoBox : Item [ ] , ammoBoxDetails : ITemplateItem ) : void {
2023-03-03 15:23:46 +00:00
const ammoBoxMaxCartridgeCount = ammoBoxDetails . _props . StackSlots [ 0 ] . _max_count ;
const cartridgeTpl = ammoBoxDetails . _props . StackSlots [ 0 ] . _props . filters [ 0 ] . Filter [ 0 ] ;
const cartridgeDetails = this . getItem ( cartridgeTpl ) ;
const cartridgeMaxStackSize = cartridgeDetails [ 1 ] . _props . StackMaxSize ;
2024-04-28 23:04:37 +01:00
// Exit if ammo already exists in box
2024-07-23 11:12:53 -04:00
if ( ammoBox . some ( ( item ) = > item . _tpl === cartridgeTpl ) ) {
2024-04-28 23:04:37 +01:00
return ;
}
2023-03-03 15:23:46 +00:00
// Add new stack-size-correct items to ammo box
let currentStoredCartridgeCount = 0 ;
2023-10-10 11:03:20 +00:00
const maxPerStack = Math . min ( ammoBoxMaxCartridgeCount , cartridgeMaxStackSize ) ;
2024-02-11 17:31:52 +00:00
// Find location based on Max ammo box size
let location = Math . ceil ( ammoBoxMaxCartridgeCount / maxPerStack ) - 1 ;
2024-02-11 15:15:21 +00:00
2024-07-23 11:12:53 -04:00
while ( currentStoredCartridgeCount < ammoBoxMaxCartridgeCount ) {
2023-10-10 11:03:20 +00:00
const remainingSpace = ammoBoxMaxCartridgeCount - currentStoredCartridgeCount ;
2024-05-07 23:57:08 -04:00
const cartridgeCountToAdd = remainingSpace < maxPerStack ? remainingSpace : maxPerStack ;
2023-03-03 15:23:46 +00:00
2023-03-21 14:19:49 +00:00
// Add cartridge item into items array
2024-02-11 12:12:27 +00:00
const cartridgeItemToAdd = this . createCartridges (
ammoBox [ 0 ] . _id ,
cartridgeTpl ,
cartridgeCountToAdd ,
location ,
ammoBox [ 0 ] . upd ? . SpawnedInSession ,
2024-02-02 13:54:07 -05:00
) ;
2023-03-03 15:23:46 +00:00
2024-02-11 12:12:27 +00:00
// In live no ammo box has the first cartridge item with a location
2024-07-23 11:12:53 -04:00
if ( location === 0 ) {
2024-02-11 12:12:27 +00:00
delete cartridgeItemToAdd . location ;
}
2024-02-11 17:31:52 +00:00
ammoBox . push ( cartridgeItemToAdd ) ;
2024-02-11 12:12:27 +00:00
2023-03-03 15:23:46 +00:00
currentStoredCartridgeCount += cartridgeCountToAdd ;
2024-02-11 17:31:52 +00:00
location -- ;
2023-03-03 15:23:46 +00:00
}
}
2024-02-08 16:01:38 +00:00
/ * *
* Add a single stack of cartridges to the ammo box
* @param ammoBox Box to add cartridges to
* @param ammoBoxDetails Item template from items db
* /
2024-07-23 11:12:53 -04:00
public addSingleStackCartridgesToAmmoBox ( ammoBox : Item [ ] , ammoBoxDetails : ITemplateItem ) : void {
2024-02-08 16:01:38 +00:00
const ammoBoxMaxCartridgeCount = ammoBoxDetails . _props . StackSlots [ 0 ] . _max_count ;
const cartridgeTpl = ammoBoxDetails . _props . StackSlots [ 0 ] . _props . filters [ 0 ] . Filter [ 0 ] ;
ammoBox . push (
this . createCartridges (
ammoBox [ 0 ] . _id ,
cartridgeTpl ,
ammoBoxMaxCartridgeCount ,
0 ,
ammoBox [ 0 ] . upd ? . SpawnedInSession ,
) ,
) ;
}
2023-10-10 11:03:20 +00:00
/ * *
* Check if item is stored inside of a container
2024-08-02 15:54:39 +01:00
* @param itemToCheck Item to check is inside of container
2023-10-10 11:03:20 +00:00
* @param desiredContainerSlotId Name of slot to check item is in e . g . SecuredContainer / Backpack
* @param items Inventory with child parent items to check
* @returns True when item is in container
* /
2024-08-02 15:54:39 +01:00
public itemIsInsideContainer ( itemToCheck : Item , desiredContainerSlotId : string , items : Item [ ] ) : boolean {
2023-10-10 11:03:20 +00:00
// Get items parent
2024-08-02 15:54:39 +01:00
const parent = items . find ( ( x ) = > x . _id === itemToCheck . parentId ) ;
2024-07-23 11:12:53 -04:00
if ( ! parent ) {
2023-10-10 11:03:20 +00:00
// No parent, end of line, not inside container
return false ;
}
2024-07-23 11:12:53 -04:00
if ( parent . slotId === desiredContainerSlotId ) {
2023-10-10 11:03:20 +00:00
return true ;
}
2024-01-08 23:27:18 +00:00
return this . itemIsInsideContainer ( parent , desiredContainerSlotId , items ) ;
2023-10-10 11:03:20 +00:00
}
2023-03-03 17:53:28 +00:00
/ * *
* Add child items ( cartridges ) to a magazine
* @param magazine Magazine to add child items to
* @param magTemplate Db template of magazine
* @param staticAmmoDist Cartridge distribution
* @param caliber Caliber of cartridge to add to magazine
* @param minSizePercent % the magazine must be filled to
2024-04-30 23:23:00 +01:00
* @param defaultCartridgeTpl Cartridge to use when none found
2024-02-07 14:45:43 +00:00
* @param weapon Weapon the magazine will be used for ( if passed in uses Chamber as whitelist )
2023-03-03 17:53:28 +00:00
* /
public fillMagazineWithRandomCartridge (
magazine : Item [ ] ,
2023-03-03 15:23:46 +00:00
magTemplate : ITemplateItem ,
2023-03-03 17:53:28 +00:00
staticAmmoDist : Record < string , IStaticAmmoDetails [ ] > ,
2024-05-28 18:32:09 +01:00
caliber? : string ,
2023-11-13 11:07:59 -05:00
minSizePercent = 0.25 ,
2024-04-30 23:23:00 +01:00
defaultCartridgeTpl? : string ,
weapon? : ITemplateItem ,
2024-07-23 11:12:53 -04:00
) : void {
2024-02-05 22:02:44 -05:00
let chosenCaliber = caliber || this . getRandomValidCaliber ( magTemplate ) ;
2023-03-03 17:53:28 +00:00
2023-03-06 10:08:36 +00:00
// Edge case for the Klin pp-9, it has a typo in its ammo caliber
2024-07-23 11:12:53 -04:00
if ( chosenCaliber === "Caliber9x18PMM" ) {
2024-02-05 22:02:44 -05:00
chosenCaliber = "Caliber9x18PM" ;
2023-03-06 10:08:36 +00:00
}
2023-03-03 17:53:28 +00:00
// Chose a randomly weighted cartridge that fits
2024-02-07 14:45:43 +00:00
const cartridgeTpl = this . drawAmmoTpl (
chosenCaliber ,
staticAmmoDist ,
2024-04-30 23:23:00 +01:00
defaultCartridgeTpl ,
2024-02-07 14:45:43 +00:00
weapon ? . _props ? . Chambers [ 0 ] ? . _props ? . filters [ 0 ] ? . Filter ,
) ;
2024-07-23 11:12:53 -04:00
if ( ! cartridgeTpl ) {
this . logger . debug (
` Unable to fill item: ${ magazine [ 0 ] . _id } ${ magTemplate . _name } with cartrides as none were found. ` ,
) ;
2024-07-17 11:48:57 +01:00
2024-04-30 23:23:00 +01:00
return ;
}
2024-07-17 11:48:57 +01:00
2023-03-03 17:53:28 +00:00
this . fillMagazineWithCartridge ( magazine , magTemplate , cartridgeTpl , minSizePercent ) ;
}
/ * *
* Add child items to a magazine of a specific cartridge
2024-01-27 15:03:15 +00:00
* @param magazineWithChildCartridges Magazine to add child items to
2023-03-03 17:53:28 +00:00
* @param magTemplate Db template of magazine
* @param cartridgeTpl Cartridge to add to magazine
2024-09-15 09:59:21 +01:00
* @param minSizeMultiplier % the magazine must be filled to
2023-03-03 17:53:28 +00:00
* /
public fillMagazineWithCartridge (
2024-01-27 15:03:15 +00:00
magazineWithChildCartridges : Item [ ] ,
2023-03-03 17:53:28 +00:00
magTemplate : ITemplateItem ,
cartridgeTpl : string ,
2024-09-15 09:59:21 +01:00
minSizeMultiplier = 0.25 ,
2024-07-23 11:12:53 -04:00
) : void {
2023-11-29 11:36:20 +00:00
// Get cartridge properties and max allowed stack size
2023-03-03 17:53:28 +00:00
const cartridgeDetails = this . getItem ( cartridgeTpl ) ;
2024-07-23 11:12:53 -04:00
if ( ! cartridgeDetails [ 0 ] ) {
2024-05-26 12:17:47 +01:00
this . logger . error ( this . localisationService . getText ( "item-invalid_tpl_item" , cartridgeTpl ) ) ;
}
const cartridgeMaxStackSize = cartridgeDetails [ 1 ] . _props ? . StackMaxSize ;
2024-07-23 11:12:53 -04:00
if ( ! cartridgeMaxStackSize ) {
2024-05-26 12:17:47 +01:00
this . logger . error ( ` Item with tpl: ${ cartridgeTpl } lacks a _props or StackMaxSize property ` ) ;
}
2023-03-03 17:53:28 +00:00
// Get max number of cartridges in magazine, choose random value between min/max
2024-05-07 23:57:08 -04:00
const magazineCartridgeMaxCount = this . isOfBaseclass ( magTemplate . _id , BaseClasses . SPRING_DRIVEN_CYLINDER )
2023-12-30 18:43:17 +00:00
? magTemplate . _props . Slots . length // Edge case for rotating grenade launcher magazine
: magTemplate . _props . Cartridges [ 0 ] ? . _max_count ;
2024-07-23 11:12:53 -04:00
if ( ! magazineCartridgeMaxCount ) {
2024-02-02 13:54:07 -05:00
this . logger . warning (
` Magazine: ${ magTemplate . _id } ${ magTemplate . _name } lacks a Cartridges array, unable to fill magazine with ammo ` ,
) ;
2023-12-16 22:23:50 +00:00
return ;
}
2023-11-13 11:07:59 -05:00
const desiredStackCount = this . randomUtil . getInt (
2024-09-15 09:59:21 +01:00
Math . round ( minSizeMultiplier * magazineCartridgeMaxCount ) ,
2023-11-13 11:07:59 -05:00
magazineCartridgeMaxCount ,
) ;
2023-03-03 17:53:28 +00:00
2024-07-23 11:12:53 -04:00
if ( magazineWithChildCartridges . length > 1 ) {
2023-12-08 16:27:34 +00:00
this . logger . warning ( ` Magazine ${ magTemplate . _name } already has cartridges defined, this may cause issues ` ) ;
}
2023-03-03 17:53:28 +00:00
// Loop over cartridge count and add stacks to magazine
let currentStoredCartridgeCount = 0 ;
let location = 0 ;
2024-07-23 11:12:53 -04:00
while ( currentStoredCartridgeCount < desiredStackCount ) {
2023-03-03 17:53:28 +00:00
// Get stack size of cartridges
2024-07-23 11:12:53 -04:00
let cartridgeCountToAdd =
desiredStackCount <= cartridgeMaxStackSize ? desiredStackCount : cartridgeMaxStackSize ;
2023-03-03 17:53:28 +00:00
2023-03-06 18:17:43 +00:00
// Ensure we don't go over the max stackcount size
const remainingSpace = desiredStackCount - currentStoredCartridgeCount ;
2024-07-23 11:12:53 -04:00
if ( cartridgeCountToAdd > remainingSpace ) {
2023-03-06 18:17:43 +00:00
cartridgeCountToAdd = remainingSpace ;
}
2023-03-03 17:53:28 +00:00
// Add cartridge item object into items array
2024-01-27 15:03:15 +00:00
magazineWithChildCartridges . push (
this . createCartridges (
magazineWithChildCartridges [ 0 ] . _id ,
2024-02-02 13:54:07 -05:00
cartridgeTpl ,
cartridgeCountToAdd ,
2024-01-27 15:03:15 +00:00
location ,
2024-02-02 13:54:07 -05:00
magazineWithChildCartridges [ 0 ] . upd ? . SpawnedInSession ,
) ,
2024-01-27 15:03:15 +00:00
) ;
2023-03-03 17:53:28 +00:00
currentStoredCartridgeCount += cartridgeCountToAdd ;
2023-11-13 11:07:59 -05:00
location ++ ;
2023-03-03 17:53:28 +00:00
}
2024-01-27 15:03:15 +00:00
// Only one cartridge stack added, remove location property as its only used for 2 or more stacks
2024-07-23 11:12:53 -04:00
if ( location === 1 ) {
2024-01-27 15:03:15 +00:00
delete magazineWithChildCartridges [ 1 ] . location ;
}
2023-03-03 15:23:46 +00:00
}
2023-10-10 11:03:20 +00:00
/ * *
* Choose a random bullet type from the list of possible a magazine has
* @param magTemplate Magazine template from Db
* @returns Tpl of cartridge
* /
2024-07-23 11:12:53 -04:00
protected getRandomValidCaliber ( magTemplate : ITemplateItem ) : string {
2023-03-03 15:23:46 +00:00
const ammoTpls = magTemplate . _props . Cartridges [ 0 ] . _props . filters [ 0 ] . Filter ;
const calibers = [
. . . new Set (
2024-05-17 15:32:41 -04:00
ammoTpls
. filter ( ( x : string ) = > this . getItem ( x ) [ 0 ] )
. map ( ( x : string ) = > this . getItem ( x ) [ 1 ] . _props . Caliber ) ,
2023-11-13 11:07:59 -05:00
) ,
2023-03-03 15:23:46 +00:00
] ;
return this . randomUtil . drawRandomFromList ( calibers ) [ 0 ] ;
}
2023-10-10 11:03:20 +00:00
/ * *
* Chose a randomly weighted cartridge that fits
* @param caliber Desired caliber
* @param staticAmmoDist Cartridges and thier weights
2024-04-23 09:34:01 +01:00
* @param fallbackCartridgeTpl If a cartridge cannot be found in the above staticAmmoDist param , use this instead
2024-02-07 14:45:43 +00:00
* @param cartridgeWhitelist OPTIONAL whitelist for cartridges
2023-11-29 11:36:20 +00:00
* @returns Tpl of cartridge
2023-10-10 11:03:20 +00:00
* /
2024-02-07 14:45:43 +00:00
protected drawAmmoTpl (
caliber : string ,
staticAmmoDist : Record < string , IStaticAmmoDetails [ ] > ,
2024-04-23 09:34:01 +01:00
fallbackCartridgeTpl : string ,
2024-05-27 20:06:07 +00:00
cartridgeWhitelist? : string [ ] ,
2024-07-23 11:12:53 -04:00
) : string | undefined {
2024-01-02 15:01:27 +00:00
const ammos = staticAmmoDist [ caliber ] ;
2024-07-23 11:12:53 -04:00
if ( ! ammos && fallbackCartridgeTpl ) {
2024-04-23 09:34:01 +01:00
this . logger . error (
` Unable to pick a cartridge for caliber: ${ caliber } as staticAmmoDist has no data. using fallback value of ${ fallbackCartridgeTpl } ` ,
) ;
return fallbackCartridgeTpl ;
2024-02-20 09:07:48 +00:00
}
2024-07-23 11:12:53 -04:00
if ( ! Array . isArray ( ammos ) && fallbackCartridgeTpl ) {
2024-02-20 09:07:48 +00:00
this . logger . error (
2024-04-23 09:34:01 +01:00
` Unable to pick a cartridge for caliber: ${ caliber } , the chosen staticAmmoDist data is not an array. Using fallback value of ${ fallbackCartridgeTpl } ` ,
2024-02-20 09:07:48 +00:00
) ;
2024-04-23 09:34:01 +01:00
return fallbackCartridgeTpl ;
2024-01-02 15:01:27 +00:00
}
2024-07-23 11:12:53 -04:00
if ( ! ammos && ! fallbackCartridgeTpl ) {
2024-07-17 11:48:57 +01:00
this . logger . debug (
2024-04-30 23:23:00 +01:00
` Unable to pick a cartridge for caliber: ${ caliber } as staticAmmoDist has no data. No fallback value provided ` ,
) ;
2024-07-17 11:48:57 +01:00
2024-04-30 23:23:00 +01:00
return ;
}
2024-05-13 17:58:17 +00:00
const ammoArray = new ProbabilityObjectArray < string > ( this . mathUtil , this . cloner ) ;
2024-07-23 11:12:53 -04:00
for ( const icd of ammos ) {
2024-02-07 14:45:43 +00:00
// Whitelist exists and tpl not inside it, skip
// Fixes 9x18mm kedr issues
2024-07-23 11:12:53 -04:00
if ( cartridgeWhitelist && ! cartridgeWhitelist . includes ( icd . tpl ) ) {
2024-02-07 14:45:43 +00:00
continue ;
}
2023-11-13 12:31:52 -05:00
ammoArray . push ( new ProbabilityObject ( icd . tpl , icd . relativeProbability ) ) ;
2023-03-03 15:23:46 +00:00
}
return ammoArray . draw ( 1 ) [ 0 ] ;
}
/ * *
2023-10-10 11:03:20 +00:00
* Create a basic cartrige object
2023-03-03 15:23:46 +00:00
* @param parentId container cartridges will be placed in
* @param ammoTpl Cartridge to insert
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
* @param stackCount Count of cartridges inside parent
2023-03-03 15:23:46 +00:00
* @param location Location inside parent ( e . g . 0 , 1 )
2024-01-23 15:24:02 +00:00
* @param foundInRaid OPTIONAL - Are cartridges found in raid ( SpawnedInSession )
2023-03-03 15:23:46 +00:00
* @returns Item
* /
2024-02-02 13:54:07 -05:00
public createCartridges (
parentId : string ,
ammoTpl : string ,
stackCount : number ,
location : number ,
foundInRaid = false ,
2024-07-23 11:12:53 -04:00
) : Item {
2023-03-03 15:23:46 +00:00
return {
_id : this.objectId.generate ( ) ,
_tpl : ammoTpl ,
parentId : parentId ,
slotId : "cartridges" ,
location : location ,
2024-02-02 13:54:07 -05:00
upd : { StackObjectsCount : stackCount , SpawnedInSession : foundInRaid } ,
2023-03-03 15:23:46 +00:00
} ;
}
/ * *
* Get the size of a stack , return 1 if no stack object count property found
Refactor of InsuranceController & New ItemHelper Methods (!151)
This commit is my second go-around at refactoring the `InsuranceController`, attempting to improving the code's modularity, maintainability, and efficiency while squashing a few bugs along the way.
1. **InsuranceController.ts**
- Removed `ITemplateItem` import, as it is no longer used.
- Introduced the `adoptOrphanedItems` method to manage orphaned items in the insurance list.
- Since "normal" items are individually rolled for deletion, and can be nested within one another, there are situations where a parent item is deleted, leaving its children orphaned. This method moves those orphaned children from their missing parent into the root of the insurance container.
- Overhauled `findItemsToDelete` method to improve its efficiency and readability:
- Divided the original monolithic method into smaller, specialized methods like `populateItemsMap`, `populateParentAttachmentsMap`, `processRegularItems`, and `processAttachments`.
- Changed the return type to `Set<string>` for better performance.
- Introduced `EnrichedItem` interface (a simple extension of the `Item` interface) to add additional item data, like `name` and `maxPrice` to `Item` objects as they're processed throughout the class. This is done in place of repeatedly querying for this data, or complicating return types.
- Enhanced logging capabilities to debug the item deletion process. Due to the *current* lack of testing available I've stepped up the amount of debug logging that is done. This will hopefully help us find issues in the future.
- Modified the `rollForItemDelete` method, now renamed to `rollForDelete`, to include more detailed logging, return a boolean directly, and changed the `insuredItem` parameter to be optional.
- Added new methods for dealing with some of the particulars that arise from item adoption and creating item maps.
- Improved inline comments and documentation for better code maintainability.
2. **ItemHelper.ts**
- Added the `isRaidModdable` method to check if an item is *actually* modifiable in-raid, which takes into account not just the item, but the item that it's attached to.
- Added the `getAttachmentMainParent` method to fetch the main parent item of a given attachment, useful for item hierarchy traversal. For example, if you pass it an item ID of a suppressor, it will traverse up the muzzle brake, barrel, upper receiver, and return the gun that the suppressor is ultimately attached to, even if that gun is located within other multiple containers.
- Added the `isAttachmentAttached` method to check if an item is an attachment that is currently attached to its parent.
**Fixes:**
- Resolved an issue that caused item attachments from being property grouped together for deletion rolls. This issue prevented valuable attachments from being taken first.
- Resolved an issue that caused child items being orphaned when their parent was removed due to an insurance roll. Probable cause of the bug that made the client spaz out and send repeated insurance packages to the profile---Though I'm still unable to reproduce.
- Probably more...
Co-authored-by: Refringe <brownelltyler@gmail.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/151
Co-authored-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
Co-committed-by: Refringe <refringe@noreply.dev.sp-tarkov.com>
2023-10-14 09:05:49 +00:00
* @param item Item to get stack size of
2023-03-03 15:23:46 +00:00
* @returns size of stack
* /
2024-07-23 11:12:53 -04:00
public getItemStackSize ( item : Item ) : number {
if ( item . upd ? . StackObjectsCount ) {
2023-03-03 15:23:46 +00:00
return item . upd . StackObjectsCount ;
}
return 1 ;
}
/ * *
* Get the name of an item from the locale file using the item tpl
* @param itemTpl Tpl of item to get name of
2024-05-31 11:09:19 +01:00
* @returns Full name , short name if not found
2023-03-03 15:23:46 +00:00
* /
2024-07-23 11:12:53 -04:00
public getItemName ( itemTpl : string ) : string {
2024-05-31 11:09:19 +01:00
const localeDb = this . localeService . getLocaleDb ( ) ;
const result = localeDb [ ` ${ itemTpl } Name ` ] ;
2024-07-23 11:12:53 -04:00
if ( result ? . length > 0 ) {
2024-05-31 11:09:19 +01:00
return result ;
}
return localeDb [ ` ${ itemTpl } ShortName ` ] ;
2023-03-03 15:23:46 +00:00
}
2023-10-11 17:04:18 +01:00
2024-05-28 22:24:52 +01:00
/ * *
* Get all item tpls with a desired base type
* @param desiredBaseType Item base type wanted
* @returns Array of tpls
* /
2024-07-23 11:12:53 -04:00
public getItemTplsOfBaseType ( desiredBaseType : string ) : string [ ] {
2024-05-28 22:24:52 +01:00
return Object . values ( this . databaseService . getItems ( ) )
. filter ( ( item ) = > item . _parent === desiredBaseType )
. map ( ( item ) = > item . _id ) ;
2023-10-11 17:04:18 +01:00
}
2024-01-08 23:27:18 +00:00
/ * *
* Add child slot items to an item , chooses random child item if multiple choices exist
* @param itemToAdd array with single object ( root item )
* @param itemToAddTemplate Db tempalte for root item
* @param modSpawnChanceDict Optional dictionary of mod name + % chance mod will be included in item ( e . g . front_plate : 100 )
2024-01-09 10:30:00 +00:00
* @param requiredOnly Only add required mods
* @returns Item with children
2024-01-08 23:27:18 +00:00
* /
2024-02-02 13:54:07 -05:00
public addChildSlotItems (
itemToAdd : Item [ ] ,
itemToAddTemplate : ITemplateItem ,
2024-05-27 20:06:07 +00:00
modSpawnChanceDict? : Record < string , number > ,
2024-02-02 13:54:07 -05:00
requiredOnly = false ,
2024-07-23 11:12:53 -04:00
) : Item [ ] {
2024-01-08 23:27:18 +00:00
const result = itemToAdd ;
2024-01-09 10:30:00 +00:00
const incompatibleModTpls : Set < string > = new Set ( ) ;
2024-07-23 11:12:53 -04:00
for ( const slot of itemToAddTemplate . _props . Slots ) {
2024-01-09 10:30:00 +00:00
// If only required mods is requested, skip non-essential
2024-07-23 11:12:53 -04:00
if ( requiredOnly && ! slot . _required ) {
2024-01-09 10:30:00 +00:00
continue ;
}
2024-01-08 23:27:18 +00:00
// Roll chance for non-required slot mods
2024-07-23 11:12:53 -04:00
if ( modSpawnChanceDict && ! slot . _required ) {
2024-01-08 23:27:18 +00:00
// only roll chance to not include mod if dict exists and has value for this mod type (e.g. front_plate)
const modSpawnChance = modSpawnChanceDict [ slot . _name . toLowerCase ( ) ] ;
2024-07-23 11:12:53 -04:00
if ( modSpawnChance ) {
if ( ! this . randomUtil . getChance100 ( modSpawnChance ) ) {
2024-01-08 23:27:18 +00:00
continue ;
}
}
}
2024-02-02 13:54:07 -05:00
const itemPool = slot . _props . filters [ 0 ] . Filter ? ? [ ] ;
2024-07-28 11:42:45 +01:00
if ( itemPool . length === 0 ) {
this . logger . debug (
` Unable to choose a mod for slot: ${ slot . _name } on item: ${ itemToAddTemplate . _id } ${ itemToAddTemplate . _name } , parents' 'Filter' array is empty, skipping ` ,
) ;
continue ;
}
2024-01-09 10:30:00 +00:00
const chosenTpl = this . getCompatibleTplFromArray ( itemPool , incompatibleModTpls ) ;
2024-07-23 11:12:53 -04:00
if ( ! chosenTpl ) {
2024-02-02 13:54:07 -05:00
this . logger . debug (
2024-07-28 11:42:45 +01:00
` Unable to choose a mod for slot: ${ slot . _name } on item: ${ itemToAddTemplate . _id } ${ itemToAddTemplate . _name } , no compatible tpl found in pool of ${ itemPool . length } , skipping ` ,
2024-02-02 13:54:07 -05:00
) ;
2024-01-08 23:27:18 +00:00
continue ;
}
2024-07-28 11:42:45 +01:00
// Create basic item structure ready to add to weapon array
2024-01-21 16:40:14 +00:00
const modItemToAdd = {
2024-01-09 10:30:00 +00:00
_id : this.hashUtil.generate ( ) ,
_tpl : chosenTpl ,
parentId : result [ 0 ] . _id ,
2024-02-02 13:54:07 -05:00
slotId : slot._name ,
2024-01-09 10:30:00 +00:00
} ;
2024-07-28 11:42:45 +01:00
// Add chosen item to weapon array
2024-01-21 16:40:14 +00:00
result . push ( modItemToAdd ) ;
2024-01-09 10:30:00 +00:00
2024-01-21 16:40:14 +00:00
const modItemDbDetails = this . getItem ( modItemToAdd . _tpl ) [ 1 ] ;
2024-01-09 10:30:00 +00:00
// Include conflicting items of newly added mod in pool to be used for next mod choice
modItemDbDetails . _props . ConflictingItems . forEach ( incompatibleModTpls . add , incompatibleModTpls ) ;
}
return result ;
}
/ * *
* Get a compatible tpl from the array provided where it is not found in the provided incompatible mod tpls parameter
2024-04-22 23:43:35 -04:00
* @param possibleTpls Tpls to randomly choose from
2024-01-09 10:30:00 +00:00
* @param incompatibleModTpls Incompatible tpls to not allow
2024-05-27 20:06:07 +00:00
* @returns Chosen tpl or undefined
2024-01-09 10:30:00 +00:00
* /
2024-07-23 11:12:53 -04:00
public getCompatibleTplFromArray ( possibleTpls : string [ ] , incompatibleModTpls : Set < string > ) : string | undefined {
if ( possibleTpls . length === 0 ) {
2024-05-27 20:06:07 +00:00
return undefined ;
2024-01-09 10:30:00 +00:00
}
2024-05-27 20:06:07 +00:00
let chosenTpl : string | undefined = undefined ;
2024-01-09 10:30:00 +00:00
let count = 0 ;
2024-07-23 11:12:53 -04:00
while ( ! chosenTpl ) {
2024-01-09 10:30:00 +00:00
// Loop over choosing a random tpl until one is found or count varaible reaches the same size as the possible tpls array
const tpl = this . randomUtil . getArrayValue ( possibleTpls ) ;
2024-07-23 11:12:53 -04:00
if ( incompatibleModTpls . has ( tpl ) ) {
2024-01-09 10:30:00 +00:00
// Incompatible tpl was chosen, try again
2024-02-02 13:54:07 -05:00
count ++ ;
2024-07-23 11:12:53 -04:00
if ( count >= possibleTpls . length ) {
2024-05-27 20:06:07 +00:00
return undefined ;
2024-01-08 23:27:18 +00:00
}
2024-01-09 10:30:00 +00:00
continue ;
}
chosenTpl = tpl ;
2024-01-08 23:27:18 +00:00
}
2024-01-09 10:30:00 +00:00
return chosenTpl ;
2024-01-08 23:27:18 +00:00
}
2024-01-10 14:47:09 +00:00
/ * *
* Is the provided item . _props . Slots . _name property a plate slot
* @param slotName Name of slot ( _name ) of Items Slot array
* @returns True if its a slot that holds a removable palte
* /
2024-07-23 11:12:53 -04:00
public isRemovablePlateSlot ( slotName : string ) : boolean {
2024-01-23 11:42:47 +00:00
return this . getRemovablePlateSlotIds ( ) . includes ( slotName . toLowerCase ( ) ) ;
2024-01-10 14:47:09 +00:00
}
/ * *
* Get a list of slot names that hold removable plates
* @returns Array of slot ids ( e . g . front_plate )
* /
2024-07-23 11:12:53 -04:00
public getRemovablePlateSlotIds ( ) : string [ ] {
2024-02-08 16:53:14 +00:00
return [ "front_plate" , "back_plate" , "left_side_plate" , "right_side_plate" ] ;
2024-01-10 14:47:09 +00:00
}
2024-01-14 21:12:56 +00:00
/ * *
* Generate new unique ids for child items while preserving hierarchy
* @param rootItem Base / primary item
* @param itemWithChildren Primary item + children of primary item
* @returns Item array with updated IDs
* /
2024-07-23 11:12:53 -04:00
public reparentItemAndChildren ( rootItem : Item , itemWithChildren : Item [ ] ) : Item [ ] {
2024-01-14 21:12:56 +00:00
const oldRootId = itemWithChildren [ 0 ] . _id ;
const idMappings = { } ;
idMappings [ oldRootId ] = rootItem . _id ;
2024-07-23 11:12:53 -04:00
for ( const mod of itemWithChildren ) {
if ( idMappings [ mod . _id ] === undefined ) {
2024-01-14 21:12:56 +00:00
idMappings [ mod . _id ] = this . hashUtil . generate ( ) ;
}
// Has parentId + no remapping exists for its parent
2024-07-23 11:12:53 -04:00
if ( mod . parentId !== undefined && idMappings [ mod . parentId ] === undefined ) {
2024-01-14 21:12:56 +00:00
// Make remapping for items parentId
idMappings [ mod . parentId ] = this . hashUtil . generate ( ) ;
}
mod . _id = idMappings [ mod . _id ] ;
2024-07-23 11:12:53 -04:00
if ( mod . parentId !== undefined ) {
2024-01-14 21:12:56 +00:00
mod . parentId = idMappings [ mod . parentId ] ;
}
}
// Force item's details into first location of presetItems
2024-07-23 11:12:53 -04:00
if ( itemWithChildren [ 0 ] . _tpl !== rootItem . _tpl ) {
2024-01-14 21:12:56 +00:00
this . logger . warning ( ` Reassigning root item from ${ itemWithChildren [ 0 ] . _tpl } to ${ rootItem . _tpl } ` ) ;
}
itemWithChildren [ 0 ] = rootItem ;
return itemWithChildren ;
}
/ * *
* Update a root items _id property value to be unique
* @param itemWithChildren Item to update root items _id property
* @param newId Optional : new id to use
2024-02-03 12:15:20 +00:00
* @returns New root id
2024-01-14 21:12:56 +00:00
* /
2024-07-23 11:12:53 -04:00
public remapRootItemId ( itemWithChildren : Item [ ] , newId = this . hashUtil . generate ( ) ) : string {
2024-01-14 21:12:56 +00:00
const rootItemExistingId = itemWithChildren [ 0 ] . _id ;
2024-07-23 11:12:53 -04:00
for ( const item of itemWithChildren ) {
2024-01-14 21:12:56 +00:00
// Root, update id
2024-07-23 11:12:53 -04:00
if ( item . _id === rootItemExistingId ) {
2024-01-14 21:12:56 +00:00
item . _id = newId ;
continue ;
}
// Child with parent of root, update
2024-07-23 11:12:53 -04:00
if ( item . parentId === rootItemExistingId ) {
2024-01-14 21:12:56 +00:00
item . parentId = newId ;
}
}
2024-02-03 12:15:20 +00:00
return newId ;
2024-01-14 21:12:56 +00:00
}
2024-02-08 15:56:45 -05:00
/ * *
* Adopts orphaned items by resetting them as root "hideout" items . Helpful in situations where a parent has been
* deleted from a group of items and there are children still referencing the missing parent . This method will
* remove the reference from the children to the parent and set item properties to root values .
*
* @param rootId The ID of the "root" of the container .
* @param items Array of Items that should be adjusted .
* @returns Array of Items that have been adopted .
* /
2024-07-23 11:12:53 -04:00
public adoptOrphanedItems ( rootId : string , items : Item [ ] ) : Item [ ] {
for ( const item of items ) {
2024-02-08 15:56:45 -05:00
// Check if the item's parent exists.
2024-05-17 15:32:41 -04:00
const parentExists = items . some ( ( parentItem ) = > parentItem . _id === item . parentId ) ;
2024-02-08 15:56:45 -05:00
// If the parent does not exist and the item is not already a 'hideout' item, adopt the orphaned item by
// setting the parent ID to the PMCs inventory equipment ID, the slot ID to 'hideout', and remove the location.
2024-07-23 11:12:53 -04:00
if ( ! parentExists && item . parentId !== rootId && item . slotId !== "hideout" ) {
2024-02-08 15:56:45 -05:00
item . parentId = rootId ;
item . slotId = "hideout" ;
delete item . location ;
}
}
return items ;
}
/ * *
* Populate a Map object of items for quick lookup using their ID .
*
* @param items An array of Items that should be added to a Map .
* @returns A Map where the keys are the item IDs and the values are the corresponding Item objects .
* /
2024-07-23 11:12:53 -04:00
public generateItemsMap ( items : Item [ ] ) : Map < string , Item > {
2024-02-08 15:56:45 -05:00
const itemsMap = new Map < string , Item > ( ) ;
2024-07-23 11:12:53 -04:00
for ( const item of items ) {
2024-02-08 15:56:45 -05:00
itemsMap . set ( item . _id , item ) ;
}
return itemsMap ;
}
2024-03-07 09:18:39 +00:00
/ * *
* Add a blank upd object to passed in item if it does not exist already
* @param item item to add upd to
* @param warningMessageWhenMissing text to write to log when upd object was not found
* @returns True when upd object was added
* /
2024-07-23 11:12:53 -04:00
public addUpdObjectToItem ( item : Item , warningMessageWhenMissing? : string ) : boolean {
if ( ! item . upd ) {
2024-03-07 09:18:39 +00:00
item . upd = { } ;
2024-03-07 13:44:43 +00:00
2024-07-23 11:12:53 -04:00
if ( warningMessageWhenMissing ) {
2024-04-28 22:50:39 +01:00
this . logger . debug ( warningMessageWhenMissing ) ;
2024-03-07 13:44:43 +00:00
}
2024-03-07 09:18:39 +00:00
return true ;
}
return false ;
}
2024-07-07 19:43:32 +01:00
2024-08-26 11:17:10 +01:00
/ * *
* Return all tpls from Money enum
* @returns string tpls
* /
2024-07-23 11:12:53 -04:00
public getMoneyTpls ( ) : string [ ] {
2024-07-07 19:43:32 +01:00
return Object . values ( Money ) ;
}
2024-08-26 11:17:10 +01:00
/ * *
* Get a randomsied stack size for the passed in ammo
* @param ammoItemTemplate Ammo to get stack size for
* @param maxLimit default : Limit to 60 to prevent crazy values when players use stack increase mods
* @returns number
* /
public getRandomisedAmmoStackSize ( ammoItemTemplate : ITemplateItem , maxLimit = 60 ) : number {
return ammoItemTemplate . _props . StackMaxSize === 1
? 1
: this . randomUtil . getInt (
ammoItemTemplate . _props . StackMinRandom ,
Math . min ( ammoItemTemplate . _props . StackMaxRandom , maxLimit ) ,
) ;
}
2023-03-03 15:23:46 +00:00
}
2024-07-23 11:12:53 -04:00
namespace ItemHelper {
export interface ItemSize {
width : number ;
height : number ;
2023-03-03 15:23:46 +00:00
}
}