2023-03-03 16:23:46 +01:00
import { inject , injectable } from "tsyringe" ;
2023-10-19 19:21:17 +02:00
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper" ;
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData" ;
import { InsuredItem } from "@spt-aki/models/eft/common/tables/IBotBase" ;
import { Item , Location , Repairable } from "@spt-aki/models/eft/common/tables/IItem" ;
import { IStaticAmmoDetails } from "@spt-aki/models/eft/common/tables/ILootBase" ;
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem" ;
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses" ;
import { ILogger } from "@spt-aki/models/spt/utils/ILogger" ;
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer" ;
import { ItemBaseClassService } from "@spt-aki/services/ItemBaseClassService" ;
2023-11-04 11:49:52 +01:00
import { ItemFilterService } from "@spt-aki/services/ItemFilterService" ;
2023-10-19 19:21:17 +02:00
import { LocaleService } from "@spt-aki/services/LocaleService" ;
import { LocalisationService } from "@spt-aki/services/LocalisationService" ;
import { HashUtil } from "@spt-aki/utils/HashUtil" ;
import { JsonUtil } from "@spt-aki/utils/JsonUtil" ;
import { MathUtil } from "@spt-aki/utils/MathUtil" ;
import { ObjectId } from "@spt-aki/utils/ObjectId" ;
import { ProbabilityObject , ProbabilityObjectArray , RandomUtil } from "@spt-aki/utils/RandomUtil" ;
2023-03-03 16:23:46 +01:00
@injectable ( )
2023-12-15 15:43:05 +01:00
export class ItemHelper
2023-03-03 16:23:46 +01:00
{
2023-10-10 13:03:20 +02:00
protected readonly defaultInvalidBaseTypes : string [ ] = [
BaseClasses . LOOT_CONTAINER ,
BaseClasses . MOB_CONTAINER ,
BaseClasses . STASH ,
BaseClasses . SORTING_TABLE ,
BaseClasses . INVENTORY ,
BaseClasses . STATIONARY_CONTAINER ,
2023-11-13 17:07:59 +01:00
BaseClasses . POCKETS ,
2023-10-10 13:03:20 +02:00
] ;
2023-03-03 16:23:46 +01:00
constructor (
@inject ( "WinstonLogger" ) protected logger : ILogger ,
@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 ,
@inject ( "DatabaseServer" ) protected databaseServer : DatabaseServer ,
@inject ( "HandbookHelper" ) protected handbookHelper : HandbookHelper ,
@inject ( "ItemBaseClassService" ) protected itemBaseClassService : ItemBaseClassService ,
2023-11-04 11:49:52 +01:00
@inject ( "ItemFilterService" ) protected itemFilterService : ItemFilterService ,
2023-03-03 16:23:46 +01:00
@inject ( "LocalisationService" ) protected localisationService : LocalisationService ,
2023-11-13 17:07:59 +01:00
@inject ( "LocaleService" ) protected localeService : LocaleService ,
2023-03-03 16:23:46 +01:00
)
{ }
/ * *
* Checks if an id is a valid item . Valid meaning that it ' s an item that be stored in stash
* @param { string } tpl the template id / tpl
* @returns boolean ; true for items that may be in player possession and not quest items
* /
public isValidItem ( tpl : string , invalidBaseTypes : string [ ] = null ) : boolean
{
if ( invalidBaseTypes === null )
{
2023-10-10 13:03:20 +02:00
invalidBaseTypes = this . defaultInvalidBaseTypes ;
2023-03-03 16:23:46 +01:00
}
const itemDetails = this . getItem ( tpl ) ;
if ( ! itemDetails [ 0 ] )
{
return false ;
}
// Is item valid
2023-11-13 18:29:16 +01:00
return ! itemDetails [ 1 ] . _props . QuestItem
&& itemDetails [ 1 ] . _type === "Item"
&& invalidBaseTypes . every ( ( x ) = > ! this . isOfBaseclass ( tpl , x ) )
&& this . getItemPrice ( tpl ) > 0
&& ! this . itemFilterService . isItemBlacklisted ( tpl ) ;
2023-03-03 16:23:46 +01: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 ?
* /
public isOfBaseclass ( tpl : string , baseClassTpl : string ) : boolean
{
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
* /
public isOfBaseclasses ( tpl : string , baseClassTpls : string [ ] ) : boolean
{
return this . itemBaseClassService . itemHasBaseClass ( tpl , baseClassTpls ) ;
}
2024-01-09 17:49:59 +01: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-01-11 18:42:58 +01:00
public armorItemCanHoldMods ( itemTpl : string ) : boolean
2024-01-09 17:49:59 +01:00
{
return this . isOfBaseclasses ( itemTpl , [ BaseClasses . HEADWEAR , BaseClasses . VEST , BaseClasses . ARMOR ] ) ;
}
2024-01-11 18:42:58 +01: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
* /
public itemRequiresSoftInserts ( itemTpl : string ) : boolean
{
// not a slot that takes soft-inserts
if ( ! this . armorItemCanHoldMods ( itemTpl ) )
{
return false ;
}
// Check is an item
const itemDbDetails = this . getItem ( itemTpl ) ;
if ( ! itemDbDetails [ 0 ] )
{
return false ;
}
// Has no slots
if ( ! ( itemDbDetails [ 1 ] . _props . Slots ? ? [ ] ) . length )
{
return false ;
}
// Check if item has slots that match soft insert name ids
const softInsertSlotIds = [ "groin" , "soft_armor_back" , "soft_armor_front" , "soft_armor_left" , "soft_armor_right" , "shoulder_l" , "shoulder_r" , "collar" ] ;
if ( itemDbDetails [ 1 ] . _props . Slots . find ( slot = > softInsertSlotIds . includes ( slot . _name . toLowerCase ( ) ) ) )
{
return true ;
}
2024-01-15 13:41:54 +01:00
// Also classified as BUILT_IN_INSERTS
const helmetInsertSlotIds = [ "helmet_top" , "helmet_back" , "helmet_ears" ]
if ( itemDbDetails [ 1 ] . _props . Slots . find ( slot = > helmetInsertSlotIds . includes ( slot . _name . toLowerCase ( ) ) ) )
{
return true ;
}
2024-01-11 18:42:58 +01:00
return false ;
}
2023-03-03 16:23:46 +01: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 17:04:26 +02:00
* @param tpl Item to look price up of
* @returns Price in roubles
2023-03-03 16:23:46 +01:00
* /
public getItemPrice ( tpl : string ) : number
2023-07-20 17:04:26 +02:00
{
const handbookPrice = this . getStaticItemPrice ( tpl ) ;
if ( handbookPrice >= 1 )
{
return handbookPrice ;
}
2023-11-04 11:28:33 +01:00
const dynamicPrice = this . getDynamicItemPrice ( tpl ) ;
2023-07-20 17:04:26 +02:00
if ( dynamicPrice )
{
return dynamicPrice ;
}
2023-11-07 22:13:41 +01:00
return 0 ;
2023-07-20 17:04:26 +02:00
}
2023-10-10 13:03:20 +02: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
* /
public getItemMaxPrice ( tpl : string ) : number
{
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 11:05:49 +02:00
2023-10-10 13:03:20 +02:00
return Math . max ( staticPrice , dynamicPrice ) ;
}
2023-07-20 17:04:26 +02: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 )
* /
public getStaticItemPrice ( tpl : string ) : number
2023-03-03 16:23:46 +01:00
{
const handbookPrice = this . handbookHelper . getTemplatePrice ( tpl ) ;
2023-07-20 17:04:26 +02:00
if ( handbookPrice >= 1 )
2023-03-03 16:23:46 +01:00
{
return handbookPrice ;
}
2023-07-20 17:04:26 +02: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 )
* /
public getDynamicItemPrice ( tpl : string ) : number
{
2023-03-03 16:23:46 +01:00
const dynamicPrice = this . databaseServer . getTables ( ) . templates . prices [ tpl ] ;
if ( dynamicPrice )
{
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 11:05:49 +02:00
}
2023-03-03 16:23:46 +01:00
2023-10-10 13:03:20 +02: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
* /
2023-03-03 16:23:46 +01:00
public fixItemStackCount ( item : Item ) : Item
{
if ( item . upd === undefined )
{
2023-11-13 18:38:16 +01:00
item . upd = { StackObjectsCount : 1 } ;
2023-03-03 16:23:46 +01:00
}
if ( item . upd . StackObjectsCount === undefined )
{
item . upd . StackObjectsCount = 1 ;
}
return item ;
}
/ * *
* Get cloned copy of all item data from items . json
* @returns array of ITemplateItem objects
* /
public getItems ( ) : ITemplateItem [ ]
{
return this . jsonUtil . clone ( Object . values ( this . databaseServer . getTables ( ) . templates . items ) ) ;
}
/ * *
* Gets item data from items . json
* @param tpl items template id to look up
* @returns bool - is valid + template item object as array
* /
public getItem ( tpl : string ) : [ boolean , ITemplateItem ]
{
// -> Gets item from <input: _tpl>
if ( tpl in this . databaseServer . getTables ( ) . templates . items )
{
return [ true , this . databaseServer . getTables ( ) . templates . items [ tpl ] ] ;
}
return [ false , undefined ] ;
}
2023-05-19 18:40:06 +02:00
public isItemInDb ( tpl : string ) : boolean
{
const itemDetails = this . getItem ( tpl ) ;
return itemDetails [ 0 ] ;
}
2023-03-03 16:23:46 +01:00
/ * *
* get normalized value ( 0 - 1 ) based on item condition
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 11:05:49 +02:00
* @param item
2023-03-03 16:23:46 +01:00
* @returns number between 0 and 1
* /
public getItemQualityModifier ( item : Item ) : number
{
// Default to 100%
let result = 1 ;
if ( item . upd )
{
const medkit = ( item . upd . MedKit ) ? item.upd.MedKit : null ;
const repairable = ( item . upd . Repairable ) ? item.upd.Repairable : null ;
const foodDrink = ( item . upd . FoodDrink ) ? item.upd.FoodDrink : null ;
const key = ( item . upd . Key ) ? item.upd.Key : null ;
const resource = ( item . upd . Resource ) ? item.upd.Resource : null ;
const repairKit = ( item . upd . RepairKit ) ? item.upd.RepairKit : null ;
const itemDetails = this . getItem ( item . _tpl ) [ 1 ] ;
if ( medkit )
{
// Meds
result = medkit . HpResource / itemDetails . _props . MaxHpResource ;
}
else if ( repairable )
{
result = this . getRepairableItemQualityValue ( itemDetails , repairable , item ) ;
}
else if ( foodDrink )
{
// food & drink
result = foodDrink . HpPercent / itemDetails . _props . MaxResource ;
}
else if ( key && key . NumberOfUsages > 0 )
{
// keys - keys count upwards, not down like everything else
const maxNumOfUsages = itemDetails . _props . MaximumNumberOfUsage ;
result = ( maxNumOfUsages - key . NumberOfUsages ) / maxNumOfUsages ;
}
else if ( resource && resource . UnitsConsumed > 0 )
{
// Things like fuel tank
2023-10-10 13:03:20 +02:00
result = resource . Value / itemDetails . _props . MaxResource ;
2023-03-03 16:23:46 +01:00
}
else if ( repairKit )
{
// Repair kits
result = repairKit . Resource / itemDetails . _props . MaxRepairResource ;
}
if ( result === 0 )
{
// make item non-zero but still very low
result = 0.01 ;
}
}
return result ;
}
/ * *
* Get a quality value based on a repairable items ( weapon / armor ) current state between current and max durability
2023-10-10 13:03:20 +02: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 16:23:46 +01:00
* /
protected getRepairableItemQualityValue ( itemDetails : ITemplateItem , repairable : Repairable , item : Item ) : number
{
2023-11-05 14:16:59 +01:00
// Edge case, max durability is below durability
2023-11-06 10:24:13 +01:00
if ( repairable . Durability > repairable . MaxDurability )
2023-11-05 14:16:59 +01:00
{
2023-11-13 17:07:59 +01:00
this . logger . warning (
` Max durability: ${ repairable . MaxDurability } for item id: ${ item . _id } was below Durability: ${ repairable . Durability } , adjusting values to match ` ,
) ;
2023-11-05 14:16:59 +01:00
repairable . MaxDurability = repairable . Durability ;
}
2023-03-03 16:23:46 +01:00
// Armor
if ( itemDetails . _props . armorClass )
{
return repairable . Durability / itemDetails . _props . MaxDurability ;
}
2023-11-05 14:19:10 +01:00
// Weapon
// Get max dura from props, if it isnt there use repairable max dura value
2023-11-13 18:29:16 +01:00
const maxDurability = ( itemDetails . _props . MaxDurability )
? itemDetails . _props . MaxDurability
: repairable . MaxDurability ;
2023-11-05 14:19:10 +01:00
const durability = repairable . Durability / maxDurability ;
2023-03-03 16:23:46 +01:00
2023-11-05 14:19:10 +01:00
if ( ! durability )
{
this . logger . error ( this . localisationService . getText ( "item-durability_value_invalid_use_default" , item . _tpl ) ) ;
2023-03-03 16:23:46 +01:00
2023-11-05 14:19:10 +01:00
return 1 ;
2023-03-03 16:23:46 +01:00
}
2023-11-05 14:19:10 +01:00
return Math . sqrt ( durability ) ;
2023-03-03 16:23:46 +01:00
}
/ * *
2023-04-24 13:47:19 +02:00
* Recursive function that looks at every item from parameter and gets their childrens Ids + includes parent item in results
2023-10-10 13:03:20 +02:00
* @param items Array of items ( item + possible children )
2024-01-09 00:27:18 +01:00
* @param baseItemId Parent items id
2023-03-03 16:23:46 +01:00
* @returns an array of strings
* /
2024-01-09 00:27:18 +01:00
public findAndReturnChildrenByItems ( items : Item [ ] , baseItemId : string ) : string [ ]
2023-03-03 16:23:46 +01:00
{
const list : string [ ] = [ ] ;
for ( const childitem of items )
{
2024-01-09 00:27:18 +01:00
if ( childitem . parentId === baseItemId )
2023-03-03 16:23:46 +01:00
{
list . push ( . . . this . findAndReturnChildrenByItems ( items , childitem . _id ) ) ;
}
}
2024-01-09 00:27:18 +01:00
list . push ( baseItemId ) ; // Required, push original item id onto array
2023-10-10 13:03:20 +02:00
2023-03-03 16:23:46 +01:00
return list ;
}
/ * *
* A variant of findAndReturnChildren where the output is list of item objects instead of their ids .
2024-01-09 00:27:18 +01:00
* @param items Array of items ( item + possible children )
* @param baseItemId Parent items id
2024-01-23 21:00:36 +01: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 11:05:49 +02:00
* @returns An array of Item objects
2023-03-03 16:23:46 +01:00
* /
2024-01-23 21:00:36 +01:00
public findAndReturnChildrenAsItems ( items : Item [ ] , baseItemId : string , modsOnly = false ) : Item [ ]
2023-03-03 16:23:46 +01:00
{
const list : Item [ ] = [ ] ;
for ( const childItem of items )
{
2023-10-10 13:03:20 +02:00
// Include itself
2023-03-03 16:23:46 +01:00
if ( childItem . _id === baseItemId )
{
list . unshift ( childItem ) ;
continue ;
}
2024-01-23 21:00:36 +01:00
// Is stored in parent and disallowed
if ( modsOnly && childItem . location )
{
continue ;
}
// Items parentid matches root item AND returned items doesnt contain current child
2023-11-13 17:07:59 +01:00
if ( childItem . parentId === baseItemId && ! list . find ( ( item ) = > childItem . _id === item . _id ) )
2023-03-03 16:23:46 +01:00
{
list . push ( . . . this . findAndReturnChildrenAsItems ( items , childItem . _id ) ) ;
}
}
2023-10-10 13:03:20 +02:00
2023-03-03 16:23:46 +01: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
* /
public findAndReturnChildrenByAssort ( itemIdToFind : string , assort : Item [ ] ) : Item [ ]
{
let list : Item [ ] = [ ] ;
for ( const itemFromAssort of assort )
{
2024-01-20 17:20:39 +01:00
if ( itemFromAssort . parentId === itemIdToFind
&& ! list . find ( ( item ) = > itemFromAssort . _id === item . _id ) )
2023-03-03 16:23:46 +01: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
* /
public hasBuyRestrictions ( itemToCheck : Item ) : boolean
{
2023-11-13 18:31:52 +01:00
if ( itemToCheck . upd ? . BuyRestrictionCurrent !== undefined && itemToCheck . upd ? . BuyRestrictionMax !== undefined )
2023-03-03 16:23:46 +01: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
* /
public isDogtag ( tpl : string ) : boolean
{
return tpl === BaseClasses . DOG_TAG_BEAR || tpl === BaseClasses . DOG_TAG_USEC ;
}
/ * *
* 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 11:05:49 +02:00
* @param item
2023-03-03 16:23:46 +01:00
* @returns "slotId OR slotid,locationX,locationY"
* /
public getChildId ( item : Item ) : string
{
if ( ! ( "location" in item ) )
{
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
* /
public isItemTplStackable ( tpl : string ) : boolean
{
2023-11-05 13:37:17 +01:00
const item = this . databaseServer . getTables ( ) . templates . items [ tpl ] ;
if ( ! item )
{
return undefined ;
}
return item . _props . StackMaxSize > 1 ;
2023-03-03 16:23:46 +01:00
}
/ * *
2023-10-10 13:03:20 +02:00
* split item stack if it exceeds its items StackMaxSize property
* @param itemToSplit Item to split into smaller stacks
2023-03-21 15:19:49 +01:00
* @returns Array of split items
2023-03-03 16:23:46 +01:00
* /
2023-03-21 15:19:49 +01:00
public splitStack ( itemToSplit : Item ) : Item [ ]
2023-03-03 16:23:46 +01:00
{
2023-03-21 15:19:49 +01:00
if ( ! ( itemToSplit ? . upd ? . StackObjectsCount != null ) )
2023-03-03 16:23:46 +01:00
{
2023-03-21 15:19:49 +01:00
return [ itemToSplit ] ;
2023-03-03 16:23:46 +01:00
}
2023-03-21 15:19:49 +01:00
const maxStackSize = this . databaseServer . getTables ( ) . templates . items [ itemToSplit . _tpl ] . _props . StackMaxSize ;
let remainingCount = itemToSplit . upd . StackObjectsCount ;
2023-03-03 16:23:46 +01:00
const stacks : Item [ ] = [ ] ;
// If the current count is already equal or less than the max
// then just return the item as is.
2023-03-21 15:19:49 +01:00
if ( remainingCount <= maxStackSize )
2023-03-03 16:23:46 +01:00
{
2023-03-21 15:19:49 +01:00
stacks . push ( this . jsonUtil . clone ( itemToSplit ) ) ;
2023-03-03 16:23:46 +01:00
return stacks ;
}
2023-03-21 15:19:49 +01:00
while ( remainingCount )
2023-03-03 16:23:46 +01:00
{
2023-03-21 15:19:49 +01:00
const amount = Math . min ( remainingCount , maxStackSize ) ;
const newStack = this . jsonUtil . clone ( itemToSplit ) ;
2023-03-03 16:23:46 +01:00
newStack . _id = this . hashUtil . generate ( ) ;
newStack . upd . StackObjectsCount = amount ;
2023-03-21 15:19:49 +01:00
remainingCount -= amount ;
2023-03-03 16:23:46 +01:00
stacks . push ( newStack ) ;
}
return stacks ;
}
/ * *
2023-10-10 13:03:20 +02:00
* Find Barter items from array of items
2023-03-21 15:19:49 +01:00
* @param { string } by tpl or id
2024-01-16 19:25:03 +01:00
* @param { Item [ ] } itemsToSearch Array of items to iterate over
* @param { string } desiredBarterItemIds
2023-03-03 16:23:46 +01:00
* @returns Array of Item objects
* /
2024-01-16 19:25:03 +01:00
public findBarterItems ( by : "tpl" | "id" , itemsToSearch : Item [ ] , desiredBarterItemIds : string | string [ ] ) : 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 11:05:49 +02:00
{
2024-01-16 19:25:03 +01:00
// Find required items to take after buying (handles multiple items)
const desiredBarterIds = typeof desiredBarterItemIds === "string"
? [ desiredBarterItemIds ]
: desiredBarterItemIds ;
2023-03-03 16:23:46 +01:00
2024-01-16 19:25:03 +01:00
const matchingItems : Item [ ] = [ ] ;
for ( const barterId of desiredBarterIds )
2023-03-03 16:23:46 +01:00
{
2024-01-16 19:25:03 +01:00
const filterResult = itemsToSearch . filter ( ( item ) = >
2023-03-03 16:23:46 +01:00
{
2024-01-16 19:25:03 +01:00
return by === "tpl"
? ( item . _tpl === barterId )
: ( item . _id === barterId ) ;
2023-03-03 16:23:46 +01:00
} ) ;
2024-01-19 23:49:31 +01:00
matchingItems . push ( . . . filterResult ) ;
2023-03-21 15:19:49 +01:00
}
2024-01-16 19:25:03 +01:00
if ( matchingItems . length === 0 )
2023-03-21 15:19:49 +01:00
{
2024-01-16 19:25:03 +01:00
this . logger . warning ( ` No items found for barter Id: ${ desiredBarterIds } ` ) ;
2023-03-03 16:23:46 +01: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 11:05:49 +02:00
2024-01-16 19:25:03 +01:00
return matchingItems ;
2023-03-03 16:23:46 +01:00
}
/ * *
2023-07-13 15:20:31 +02:00
* Regenerate all guids with new ids , exceptions are for items that cannot be altered ( e . g . stash / sorting table )
* @param pmcData Player profile
* @param items Items to adjust ID values of
2023-03-03 16:23:46 +01:00
* @param insuredItems insured items to not replace ids for
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 11:05:49 +02:00
* @param fastPanel
2023-07-13 18:32:50 +02:00
* @returns Item [ ]
2023-03-03 16:23:46 +01:00
* /
2023-07-13 15:20:31 +02:00
public replaceIDs ( pmcData : IPmcData , items : Item [ ] , insuredItems : InsuredItem [ ] = null , fastPanel = null ) : Item [ ]
2023-03-03 16:23:46 +01:00
{
// replace bsg shit long ID with proper one
let serialisedInventory = this . jsonUtil . serialize ( items ) ;
for ( const item of items )
{
if ( pmcData !== null )
{
// Insured items shouldn't be renamed
// only works for pmcs.
2023-11-13 17:07:59 +01:00
if ( insuredItems ? . find ( ( insuredItem ) = > insuredItem . itemId === item . _id ) )
2023-03-03 16:23:46 +01:00
{
continue ;
}
// Do not replace important ID's
2023-11-13 17:07:59 +01:00
if (
2023-11-13 18:29:16 +01:00
item . _id === pmcData . Inventory . equipment
|| item . _id === pmcData . Inventory . questRaidItems
|| item . _id === pmcData . Inventory . questStashItems
|| item . _id === pmcData . Inventory . sortingTable
|| item . _id === pmcData . Inventory . stash
2023-11-13 17:07:59 +01:00
)
2023-03-03 16:23:46 +01:00
{
continue ;
}
}
// replace id
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.
if ( fastPanel !== null )
{
for ( const itemSlot in fastPanel )
{
if ( fastPanel [ itemSlot ] === oldId )
{
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.
for ( const item of items )
{
dupes [ item . _id ] = ( dupes [ item . _id ] || 0 ) + 1 ;
}
for ( const item of items )
{
// register the parents
if ( dupes [ item . _id ] > 1 )
{
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 ) ;
}
}
for ( const item of items )
{
if ( dupes [ item . _id ] > 1 )
{
const oldId = item . _id ;
const newId = oldToNewIds [ oldId ] . splice ( 0 , 1 ) [ 0 ] ;
item . _id = newId ;
// Extract one of the children that's also duplicated.
if ( oldId in newParents && newParents [ oldId ] . length > 0 )
{
childrenMapping [ newId ] = { } ;
for ( const childIndex in newParents [ oldId ] )
{
// 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 ] ) ;
if ( ! ( childId in childrenMapping [ newId ] ) )
{
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 ;
}
/ * *
* 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 18:53:28 +01: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 16:23:46 +01:00
* /
public doesItemOrParentsIdMatch ( tpl : string , tplsToCheck : string [ ] ) : boolean
{
const itemDetails = this . getItem ( tpl ) ;
const itemExists = itemDetails [ 0 ] ;
const item = itemDetails [ 1 ] ;
// not an item, drop out
if ( ! itemExists )
{
return false ;
}
// no parent to check
if ( ! item . _parent )
{
return false ;
}
// Does templateId match any values in tplsToCheck array
if ( tplsToCheck . includes ( item . _id ) )
{
return true ;
}
// Does the items parent type exist in tplsToCheck array
if ( tplsToCheck . includes ( item . _parent ) )
{
return true ;
}
// check items parent with same method
return this . doesItemOrParentsIdMatch ( item . _parent , tplsToCheck ) ;
}
/ * *
2023-03-03 18:53:28 +01: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 16:23:46 +01:00
* /
public isQuestItem ( tpl : string ) : boolean
{
const itemDetails = this . getItem ( tpl ) ;
if ( itemDetails [ 0 ] && itemDetails [ 1 ] . _props . QuestItem )
{
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 11:05:49 +02: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
* @returns True if the item is actually moddable , false if it is not , and null if the check cannot be performed .
* /
public isRaidModdable ( item : Item , parent : Item ) : boolean | null
{
// This check requires the item to have the slotId property populated.
if ( ! item . slotId )
{
return null ;
}
const itemTemplate = this . getItem ( item . _tpl ) ;
const parentTemplate = this . getItem ( parent . _tpl ) ;
// Check for RaidModdable property on the item template.
let isNotRaidModdable = false ;
if ( itemTemplate [ 0 ] )
{
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 ;
if ( parentTemplate [ 0 ] && parentTemplate [ 1 ] ? . _props ? . Slots )
{
2023-11-13 17:07:59 +01:00
isRequiredSlot = parentTemplate [ 1 ] . _props . Slots . some ( ( slot ) = >
slot . _name === item . slotId && slot . _required
) ;
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 11:05:49 +02: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 .
*
* To generate the map :
* ` ` `
* const itemsMap = new Map < string , Item > ( ) ;
* items . forEach ( item = > itemsMap . set ( item . _id , item ) ) ;
* ` ` `
*
* @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 .
* @returns The Item object representing the top - most parent of the given item , or ` null ` if no such parent exists .
* /
public getAttachmentMainParent ( itemId : string , itemsMap : Map < string , Item > ) : Item | null
{
let currentItem = itemsMap . get ( itemId ) ;
while ( currentItem && this . isAttachmentAttached ( currentItem ) )
{
currentItem = itemsMap . get ( currentItem . parentId ) ;
2023-11-02 06:47:28 +01:00
if ( ! currentItem )
{
return null ;
}
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 11:05:49 +02: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 .
* /
public isAttachmentAttached ( item : Item ) : boolean
{
2023-10-31 23:54:59 +01:00
return item . slotId !== "hideout" && item . slotId !== "main" && Number . isNaN ( Number ( item . slotId ) ) ;
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 11:05:49 +02:00
}
2023-03-03 16:23:46 +01:00
/ * *
* Get the inventory size of an item
2023-03-03 18:53:28 +01: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 11:05:49 +02:00
* @param rootItemId
2023-03-03 16:23:46 +01:00
* @returns ItemSize object ( width and height )
* /
public getItemSize ( items : Item [ ] , rootItemId : string ) : ItemHelper . ItemSize
{
2023-11-13 17:07:59 +01:00
const rootTemplate = this . getItem ( items . filter ( ( x ) = > x . _id === rootItemId ) [ 0 ] . _tpl ) [ 1 ] ;
2023-03-03 16:23:46 +01: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 ) ;
for ( const ci of children )
{
const itemTemplate = this . getItem ( ci . _tpl ) [ 1 ] ;
// Calculating child ExtraSize
if ( itemTemplate . _props . ExtraSizeForceAdd === true )
{
forcedUp += itemTemplate . _props . ExtraSizeUp ;
forcedDown += itemTemplate . _props . ExtraSizeDown ;
forcedLeft += itemTemplate . _props . ExtraSizeLeft ;
forcedRight += itemTemplate . _props . ExtraSizeRight ;
}
else
{
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 ;
2023-11-13 18:29:16 +01:00
sizeRight = sizeRight < itemTemplate . _props . ExtraSizeRight
? itemTemplate . _props . ExtraSizeRight
: sizeRight ;
2023-03-03 16:23:46 +01:00
}
}
return {
width : width + sizeLeft + sizeRight + forcedLeft + forcedRight ,
2023-11-13 17:07:59 +01:00
height : height + sizeUp + sizeDown + forcedUp + forcedDown ,
2023-03-03 16:23:46 +01:00
} ;
}
/ * *
* Get a random cartridge from an items Filter property
2023-03-03 18:53:28 +01:00
* @param item Db item template to look up Cartridge filter values from
* @returns Caliber of cartridge
2023-03-03 16:23:46 +01:00
* /
2023-11-08 04:59:04 +01:00
public getRandomCompatibleCaliberTemplateId ( item : ITemplateItem ) : string | null
2023-03-03 16:23:46 +01:00
{
2023-11-08 04:59:04 +01:00
const cartridges = item ? . _props ? . Cartridges [ 0 ] ? . _props ? . filters [ 0 ] ? . Filter ;
2023-03-03 16:23:46 +01:00
if ( ! cartridges )
{
2023-11-08 04:59:04 +01:00
this . logger . warning ( ` Failed to find cartridge for item: ${ item ? . _id } ${ item ? . _name } ` ) ;
2023-03-03 16:23:46 +01:00
return null ;
}
2023-11-08 04:59:04 +01:00
return this . randomUtil . getArrayValue ( cartridges ) ;
2023-03-03 16:23:46 +01: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
* /
public addCartridgesToAmmoBox ( ammoBox : Item [ ] , ammoBoxDetails : ITemplateItem ) : void
{
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 ;
// Add new stack-size-correct items to ammo box
let currentStoredCartridgeCount = 0 ;
2023-03-21 15:19:49 +01:00
// Location in ammoBox cartridges will be placed
2023-03-03 16:23:46 +01:00
let location = 0 ;
2023-10-10 13:03:20 +02:00
const maxPerStack = Math . min ( ammoBoxMaxCartridgeCount , cartridgeMaxStackSize ) ;
2023-03-03 16:23:46 +01:00
while ( currentStoredCartridgeCount < ammoBoxMaxCartridgeCount )
{
2023-10-10 13:03:20 +02:00
const remainingSpace = ammoBoxMaxCartridgeCount - currentStoredCartridgeCount ;
2023-11-13 18:31:52 +01:00
const cartridgeCountToAdd = ( remainingSpace < maxPerStack ) ? remainingSpace : maxPerStack ;
2023-03-03 16:23:46 +01:00
2023-03-21 15:19:49 +01:00
// Add cartridge item into items array
2024-01-23 16:24:02 +01:00
ammoBox . push ( this . createCartridges ( ammoBox [ 0 ] . _id , cartridgeTpl , cartridgeCountToAdd , location , ammoBox [ 0 ] . upd ? . SpawnedInSession ) ) ;
2023-03-03 16:23:46 +01:00
currentStoredCartridgeCount += cartridgeCountToAdd ;
2023-11-13 17:07:59 +01:00
location ++ ;
2023-03-03 16:23:46 +01:00
}
}
2023-10-10 13:03:20 +02:00
/ * *
* Check if item is stored inside of a container
* @param item Item to check is inside of container
* @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
* /
public itemIsInsideContainer ( item : Item , desiredContainerSlotId : string , items : Item [ ] ) : boolean
{
// Get items parent
2023-11-13 17:07:59 +01:00
const parent = items . find ( ( x ) = > x . _id === item . parentId ) ;
2023-10-10 13:03:20 +02:00
if ( ! parent )
{
// No parent, end of line, not inside container
return false ;
}
if ( parent . slotId === desiredContainerSlotId )
{
return true ;
}
2024-01-09 00:27:18 +01:00
return this . itemIsInsideContainer ( parent , desiredContainerSlotId , items ) ;
2023-10-10 13:03:20 +02:00
}
2023-03-03 18:53:28 +01: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
* /
public fillMagazineWithRandomCartridge (
magazine : Item [ ] ,
2023-03-03 16:23:46 +01:00
magTemplate : ITemplateItem ,
2023-03-03 18:53:28 +01:00
staticAmmoDist : Record < string , IStaticAmmoDetails [ ] > ,
caliber : string = undefined ,
2023-11-13 17:07:59 +01:00
minSizePercent = 0.25 ,
2023-03-03 18:53:28 +01:00
) : void
2023-03-03 16:23:46 +01:00
{
2023-03-21 15:19:49 +01:00
// no caliber defined, choose one at random
2023-03-03 16:23:46 +01:00
if ( ! caliber )
{
caliber = this . getRandomValidCaliber ( magTemplate ) ;
}
2023-03-03 18:53:28 +01:00
2023-03-06 11:08:36 +01:00
// Edge case for the Klin pp-9, it has a typo in its ammo caliber
if ( caliber === "Caliber9x18PMM" )
{
caliber = "Caliber9x18PM" ;
}
2023-03-03 18:53:28 +01:00
// Chose a randomly weighted cartridge that fits
const cartridgeTpl = this . drawAmmoTpl ( caliber , staticAmmoDist ) ;
this . fillMagazineWithCartridge ( magazine , magTemplate , cartridgeTpl , minSizePercent ) ;
}
/ * *
* Add child items to a magazine of a specific cartridge
2024-01-27 16:03:15 +01:00
* @param magazineWithChildCartridges Magazine to add child items to
2023-03-03 18:53:28 +01:00
* @param magTemplate Db template of magazine
* @param cartridgeTpl Cartridge to add to magazine
* @param minSizePercent % the magazine must be filled to
* /
public fillMagazineWithCartridge (
2024-01-27 16:03:15 +01:00
magazineWithChildCartridges : Item [ ] ,
2023-03-03 18:53:28 +01:00
magTemplate : ITemplateItem ,
cartridgeTpl : string ,
2023-11-13 17:07:59 +01:00
minSizePercent = 0.25 ,
2023-03-03 18:53:28 +01:00
) : void
{
2023-11-29 12:36:20 +01:00
// Get cartridge properties and max allowed stack size
2023-03-03 18:53:28 +01:00
const cartridgeDetails = this . getItem ( cartridgeTpl ) ;
const cartridgeMaxStackSize = cartridgeDetails [ 1 ] . _props . StackMaxSize ;
// Get max number of cartridges in magazine, choose random value between min/max
2023-12-30 19:43:17 +01:00
const magazineCartridgeMaxCount = ( this . isOfBaseclass ( magTemplate . _id , BaseClasses . SPRING_DRIVEN_CYLINDER ) )
? magTemplate . _props . Slots . length // Edge case for rotating grenade launcher magazine
: magTemplate . _props . Cartridges [ 0 ] ? . _max_count ;
2023-12-16 23:23:50 +01:00
if ( ! magazineCartridgeMaxCount )
{
this . logger . warning ( ` Magazine: ${ magTemplate . _id } ${ magTemplate . _name } lacks a Cartridges array, unable to fill magazine with ammo ` ) ;
return ;
}
2023-11-13 17:07:59 +01:00
const desiredStackCount = this . randomUtil . getInt (
Math . round ( minSizePercent * magazineCartridgeMaxCount ) ,
magazineCartridgeMaxCount ,
) ;
2023-03-03 18:53:28 +01:00
2024-01-27 16:03:15 +01:00
if ( magazineWithChildCartridges . length > 1 )
2023-12-08 17:27:34 +01:00
{
this . logger . warning ( ` Magazine ${ magTemplate . _name } already has cartridges defined, this may cause issues ` ) ;
}
2023-03-03 18:53:28 +01:00
// Loop over cartridge count and add stacks to magazine
let currentStoredCartridgeCount = 0 ;
let location = 0 ;
2023-03-06 19:17:43 +01:00
while ( currentStoredCartridgeCount < desiredStackCount )
2023-03-03 18:53:28 +01:00
{
// Get stack size of cartridges
2023-11-13 18:29:16 +01:00
let cartridgeCountToAdd = ( desiredStackCount <= cartridgeMaxStackSize )
? desiredStackCount
: cartridgeMaxStackSize ;
2023-03-03 18:53:28 +01:00
2023-03-06 19:17:43 +01:00
// Ensure we don't go over the max stackcount size
const remainingSpace = desiredStackCount - currentStoredCartridgeCount ;
if ( cartridgeCountToAdd > remainingSpace )
{
cartridgeCountToAdd = remainingSpace ;
}
2023-03-03 18:53:28 +01:00
// Add cartridge item object into items array
2024-01-27 16:03:15 +01:00
magazineWithChildCartridges . push (
this . createCartridges (
magazineWithChildCartridges [ 0 ] . _id ,
cartridgeTpl , cartridgeCountToAdd ,
location ,
magazineWithChildCartridges [ 0 ] . upd ? . SpawnedInSession
)
) ;
2023-03-03 18:53:28 +01:00
currentStoredCartridgeCount += cartridgeCountToAdd ;
2023-11-13 17:07:59 +01:00
location ++ ;
2023-03-03 18:53:28 +01:00
}
2024-01-27 16:03:15 +01:00
// Only one cartridge stack added, remove location property as its only used for 2 or more stacks
if ( location === 1 )
{
delete magazineWithChildCartridges [ 1 ] . location ;
}
2023-03-03 16:23:46 +01:00
}
2023-10-10 13:03:20 +02:00
/ * *
* Choose a random bullet type from the list of possible a magazine has
* @param magTemplate Magazine template from Db
* @returns Tpl of cartridge
* /
2023-03-03 16:23:46 +01:00
protected getRandomValidCaliber ( magTemplate : ITemplateItem ) : string
{
const ammoTpls = magTemplate . _props . Cartridges [ 0 ] . _props . filters [ 0 ] . Filter ;
const calibers = [
. . . new Set (
2023-11-13 18:31:52 +01:00
ammoTpls . filter ( ( x : string ) = > this . getItem ( x ) [ 0 ] ) . map ( ( x : string ) = >
this . getItem ( x ) [ 1 ] . _props . Caliber
2023-11-13 17:07:59 +01:00
) ,
) ,
2023-03-03 16:23:46 +01:00
] ;
return this . randomUtil . drawRandomFromList ( calibers ) [ 0 ] ;
}
2023-10-10 13:03:20 +02:00
/ * *
* Chose a randomly weighted cartridge that fits
* @param caliber Desired caliber
* @param staticAmmoDist Cartridges and thier weights
2023-11-29 12:36:20 +01:00
* @returns Tpl of cartridge
2023-10-10 13:03:20 +02:00
* /
2023-03-03 16:23:46 +01:00
protected drawAmmoTpl ( caliber : string , staticAmmoDist : Record < string , IStaticAmmoDetails [ ] > ) : string
{
2023-08-09 12:49:45 +02:00
const ammoArray = new ProbabilityObjectArray < string > ( this . mathUtil , this . jsonUtil ) ;
2024-01-02 16:01:27 +01:00
const ammos = staticAmmoDist [ caliber ] ;
if ( ! ammos )
{
this . logger . error ( ` missing caliber data for: ${ caliber } ` ) ;
}
for ( const icd of ammos )
2023-03-03 16:23:46 +01:00
{
2023-11-13 18:31:52 +01:00
ammoArray . push ( new ProbabilityObject ( icd . tpl , icd . relativeProbability ) ) ;
2023-03-03 16:23:46 +01:00
}
return ammoArray . draw ( 1 ) [ 0 ] ;
}
/ * *
2023-10-10 13:03:20 +02:00
* Create a basic cartrige object
2023-03-03 16:23:46 +01: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 11:05:49 +02:00
* @param stackCount Count of cartridges inside parent
2023-03-03 16:23:46 +01:00
* @param location Location inside parent ( e . g . 0 , 1 )
2024-01-23 16:24:02 +01:00
* @param foundInRaid OPTIONAL - Are cartridges found in raid ( SpawnedInSession )
2023-03-03 16:23:46 +01:00
* @returns Item
* /
2024-01-23 16:24:02 +01:00
public createCartridges ( parentId : string , ammoTpl : string , stackCount : number , location : number , foundInRaid = false ) : Item
2023-03-03 16:23:46 +01:00
{
return {
_id : this.objectId.generate ( ) ,
_tpl : ammoTpl ,
parentId : parentId ,
slotId : "cartridges" ,
location : location ,
2024-01-23 16:24:02 +01:00
upd : {
StackObjectsCount : stackCount ,
SpawnedInSession : foundInRaid
} ,
2023-03-03 16:23:46 +01: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 11:05:49 +02:00
* @param item Item to get stack size of
2023-03-03 16:23:46 +01:00
* @returns size of stack
* /
public getItemStackSize ( item : Item ) : number
{
if ( item . upd ? . StackObjectsCount )
{
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
* @returns Name of item
* /
public getItemName ( itemTpl : string ) : string
{
return this . localeService . getLocaleDb ( ) [ ` ${ itemTpl } Name ` ] ;
}
2023-10-11 18:04:18 +02:00
public getItemTplsOfBaseType ( desiredBaseType : string ) : string [ ]
{
2023-11-13 17:07:59 +01:00
return Object . values ( this . databaseServer . getTables ( ) . templates . items ) . filter ( ( x ) = >
x . _parent === desiredBaseType
) . map ( ( x ) = > x . _id ) ;
2023-10-11 18:04:18 +02:00
}
2024-01-09 00:27:18 +01: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 11:30:00 +01:00
* @param requiredOnly Only add required mods
* @returns Item with children
2024-01-09 00:27:18 +01:00
* /
2024-01-09 11:30:00 +01:00
public addChildSlotItems ( itemToAdd : Item [ ] , itemToAddTemplate : ITemplateItem , modSpawnChanceDict : Record < string , number > = null , requiredOnly = false ) : Item [ ]
2024-01-09 00:27:18 +01:00
{
const result = itemToAdd ;
2024-01-09 11:30:00 +01:00
const incompatibleModTpls : Set < string > = new Set ( ) ;
2024-01-09 00:27:18 +01:00
for ( const slot of itemToAddTemplate . _props . Slots )
{
2024-01-09 11:30:00 +01:00
// If only required mods is requested, skip non-essential
if ( requiredOnly && ! slot . _required )
{
continue ;
}
2024-01-09 00:27:18 +01:00
// Roll chance for non-required slot mods
if ( modSpawnChanceDict && ! slot . _required )
{
// 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 ( ) ] ;
if ( modSpawnChance )
{
2024-01-23 22:33:24 +01:00
if ( ! this . randomUtil . getChance100 ( modSpawnChance ) )
2024-01-09 00:27:18 +01:00
{
continue ;
}
}
}
2024-01-09 11:30:00 +01:00
const itemPool = slot . _props . filters [ 0 ] . Filter ? ? [ ] ;
const chosenTpl = this . getCompatibleTplFromArray ( itemPool , incompatibleModTpls ) ;
if ( ! chosenTpl )
2024-01-09 00:27:18 +01:00
{
2024-01-09 11:30:00 +01:00
this . logger . debug ( ` Unable to add mod to item: ${ itemToAddTemplate . _id } ${ itemToAddTemplate . _name } slot: ${ slot . _name } as no compatible tpl could be found in pool of ${ itemPool . length } , skipping ` ) ;
2024-01-09 00:27:18 +01:00
continue ;
}
2024-01-21 17:40:14 +01:00
const modItemToAdd = {
2024-01-09 11:30:00 +01:00
_id : this.hashUtil.generate ( ) ,
_tpl : chosenTpl ,
parentId : result [ 0 ] . _id ,
slotId : slot._name
} ;
2024-01-21 17:40:14 +01:00
result . push ( modItemToAdd ) ;
2024-01-09 11:30:00 +01:00
2024-01-21 17:40:14 +01:00
const modItemDbDetails = this . getItem ( modItemToAdd . _tpl ) [ 1 ] ;
2024-01-09 11:30:00 +01:00
// Include conflicting items of newly added mod in pool to be used for next mod choice
// biome-ignore lint/complexity/noForEach: <explanation>
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
* @param possibleTpls Tpls to randomply choose from
* @param incompatibleModTpls Incompatible tpls to not allow
* @returns Chosen tpl or null
* /
public getCompatibleTplFromArray ( possibleTpls : string [ ] , incompatibleModTpls : Set < string > ) : string
{
if ( possibleTpls . length === 0 )
{
return null ;
}
let chosenTpl = null ;
let count = 0 ;
while ( ! chosenTpl )
{
// 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 ) ;
if ( incompatibleModTpls . has ( tpl ) )
{
// Incompatible tpl was chosen, try again
count ++
if ( count >= possibleTpls . length )
2024-01-09 00:27:18 +01:00
{
2024-01-09 11:30:00 +01:00
return null ;
2024-01-09 00:27:18 +01:00
}
2024-01-09 11:30:00 +01:00
continue ;
}
chosenTpl = tpl ;
2024-01-09 00:27:18 +01:00
}
2024-01-09 11:30:00 +01:00
return chosenTpl ;
2024-01-09 00:27:18 +01:00
}
2024-01-10 15:47:09 +01: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
* /
public isRemovablePlateSlot ( slotName : string ) : boolean
{
2024-01-23 12:42:47 +01:00
return this . getRemovablePlateSlotIds ( ) . includes ( slotName . toLowerCase ( ) ) ;
2024-01-10 15:47:09 +01:00
}
/ * *
* Get a list of slot names that hold removable plates
* @returns Array of slot ids ( e . g . front_plate )
* /
2024-01-23 12:42:47 +01:00
public getRemovablePlateSlotIds ( ) : string [ ]
2024-01-10 15:47:09 +01:00
{
return [ "front_plate" , "back_plate" , "side_plate" , "left_side_plate" , "right_side_plate" ] ;
}
2024-01-14 22:12:56 +01: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
* /
public reparentItemAndChildren ( rootItem : Item , itemWithChildren : Item [ ] ) : Item [ ]
{
const oldRootId = itemWithChildren [ 0 ] . _id ;
const idMappings = { } ;
idMappings [ oldRootId ] = rootItem . _id ;
for ( const mod of itemWithChildren )
{
if ( idMappings [ mod . _id ] === undefined )
{
idMappings [ mod . _id ] = this . hashUtil . generate ( ) ;
}
// Has parentId + no remapping exists for its parent
if ( mod . parentId !== undefined && idMappings [ mod . parentId ] === undefined )
{
// Make remapping for items parentId
idMappings [ mod . parentId ] = this . hashUtil . generate ( ) ;
}
mod . _id = idMappings [ mod . _id ] ;
if ( mod . parentId !== undefined )
{
mod . parentId = idMappings [ mod . parentId ] ;
}
}
// Force item's details into first location of presetItems
if ( itemWithChildren [ 0 ] . _tpl !== rootItem . _tpl )
{
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
* /
public remapRootItemId ( itemWithChildren : Item [ ] , newId = this . hashUtil . generate ( ) ) : void
{
const rootItemExistingId = itemWithChildren [ 0 ] . _id ;
for ( const item of itemWithChildren )
{
// Root, update id
if ( item . _id === rootItemExistingId )
{
item . _id = newId ;
continue ;
}
// Child with parent of root, update
if ( item . parentId === rootItemExistingId )
{
item . parentId = newId ;
}
}
}
2023-03-03 16:23:46 +01:00
}
namespace ItemHelper
{
export interface ItemSize
{
2023-11-13 17:07:59 +01:00
width : number ;
height : number ;
2023-03-03 16:23:46 +01:00
}
}