diff --git a/Libraries/SPTarkov.Server.Core/Callbacks/BtrDeliveryCallbacks.cs b/Libraries/SPTarkov.Server.Core/Callbacks/BtrDeliveryCallbacks.cs
index a935e9ed..492af49f 100644
--- a/Libraries/SPTarkov.Server.Core/Callbacks/BtrDeliveryCallbacks.cs
+++ b/Libraries/SPTarkov.Server.Core/Callbacks/BtrDeliveryCallbacks.cs
@@ -1,5 +1,6 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.DI;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Profile;
using SPTarkov.Server.Core.Models.Spt.Config;
@@ -114,7 +115,7 @@ public class BtrDeliveryCallbacks(
var rootItemParentId = _hashUtil.Generate();
// Update the delivery items to have the new root parent ID for root/orphaned items
- package.Items = _itemHelper.AdoptOrphanedItems(rootItemParentId, package.Items);
+ package.Items = package.Items.AdoptOrphanedItems(rootItemParentId);
_btrDeliveryService.SendBTRDelivery(sessionId, package.Items);
diff --git a/Libraries/SPTarkov.Server.Core/Controllers/GameController.cs b/Libraries/SPTarkov.Server.Core/Controllers/GameController.cs
index 7b91e529..97c8c744 100644
--- a/Libraries/SPTarkov.Server.Core/Controllers/GameController.cs
+++ b/Libraries/SPTarkov.Server.Core/Controllers/GameController.cs
@@ -305,7 +305,7 @@ public class GameController(
/// Player profile
protected void WarnOnActiveBotReloadSkill(PmcData pmcProfile)
{
- var botReloadSkill = _profileHelper.GetSkillFromProfile(pmcProfile, SkillTypes.BotReload);
+ var botReloadSkill = pmcProfile.GetSkillFromProfile(SkillTypes.BotReload);
if (botReloadSkill?.Progress > 0)
{
_logger.Warning(
diff --git a/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs b/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs
index 4ab43697..c892a0a9 100644
--- a/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs
+++ b/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs
@@ -1,4 +1,5 @@
using SPTarkov.DI.Annotations;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -123,7 +124,7 @@ public class InsuranceController(
var rootItemParentId = _hashUtil.Generate();
// Update the insured items to have the new root parent ID for root/orphaned items
- insured.Items = _itemHelper.AdoptOrphanedItems(rootItemParentId, insured.Items);
+ insured.Items = insured.Items.AdoptOrphanedItems(rootItemParentId);
var simulateItemsBeingTaken = _insuranceConfig.SimulateItemsBeingTaken;
if (simulateItemsBeingTaken)
@@ -135,7 +136,7 @@ public class InsuranceController(
RemoveItemsFromInsurance(insured, itemsToDelete);
// There's a chance we've orphaned weapon attachments, so adopt any orphaned items again
- insured.Items = _itemHelper.AdoptOrphanedItems(rootItemParentId, insured.Items);
+ insured.Items = insured.Items.AdoptOrphanedItems(rootItemParentId);
}
SendMail(sessionId, insured);
@@ -192,7 +193,7 @@ public class InsuranceController(
// Populate a Map object of items for quick lookup by their ID and use it to populate a Map of main-parent items
// and each of their attachments. For example, a gun mapped to each of its attachments.
- var itemsMap = _itemHelper.GenerateItemsMap(insured.Items);
+ var itemsMap = insured.Items.GenerateItemsMap();
var parentAttachmentsMap = PopulateParentAttachmentsMap(
rootItemParentId,
insured,
diff --git a/Libraries/SPTarkov.Server.Core/Controllers/RepeatableQuestController.cs b/Libraries/SPTarkov.Server.Core/Controllers/RepeatableQuestController.cs
index 0c3f737e..6c9136d0 100644
--- a/Libraries/SPTarkov.Server.Core/Controllers/RepeatableQuestController.cs
+++ b/Libraries/SPTarkov.Server.Core/Controllers/RepeatableQuestController.cs
@@ -1,4 +1,5 @@
using SPTarkov.DI.Annotations;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Generators.RepeatableQuestGeneration;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -222,8 +223,7 @@ public class RepeatableQuestController(
var traderOfReplacedQuest = pmcData.TradersInfo[replacedQuestTraderId];
traderOfReplacedQuest.Standing -= previousChangeRequirement.ChangeStandingCost;
- var charismaBonus =
- _profileHelper.GetSkillFromProfile(pmcData, SkillTypes.Charisma)?.Progress ?? 0;
+ var charismaBonus = pmcData.GetSkillFromProfile(SkillTypes.Charisma)?.Progress ?? 0;
foreach (var cost in previousChangeRequirement.ChangeCost)
{
// Not free, Charge player + apply charisma bonus to cost of replacement
diff --git a/Libraries/SPTarkov.Server.Core/Extensions/ItemExtensions.cs b/Libraries/SPTarkov.Server.Core/Extensions/ItemExtensions.cs
new file mode 100644
index 00000000..7be8b784
--- /dev/null
+++ b/Libraries/SPTarkov.Server.Core/Extensions/ItemExtensions.cs
@@ -0,0 +1,195 @@
+using SPTarkov.Server.Core.Models.Eft.Common.Tables;
+
+namespace SPTarkov.Server.Core.Extensions
+{
+ public static class ItemExtensions
+ {
+ ///
+ /// This method will compare two items and see if they are equivalent
+ /// This method will NOT compare IDs on the items
+ ///
+ /// first item to compare
+ /// second item to compare
+ /// Upd properties to compare between the items
+ /// true if they are the same
+ public static bool IsSameItem(
+ this Item item1,
+ Item item2,
+ HashSet? compareUpdProperties = null
+ )
+ {
+ // Different tpl == different item
+ if (item1.Template != item2.Template)
+ {
+ return false;
+ }
+
+ // Both lack upd object + same tpl = same
+ if (item1.Upd is null && item2.Upd is null)
+ {
+ return true;
+ }
+
+ // item1 lacks upd, item2 has one
+ if (item1.Upd is null && item2.Upd is not null)
+ {
+ return false;
+ }
+
+ // item1 has upd, item2 lacks one
+ if (item1.Upd is not null && item2.Upd is null)
+ {
+ return false;
+ }
+
+ // key = Upd property Type as string, value = comparison function that returns bool
+ var comparers = new Dictionary>
+ {
+ { "Key", (upd1, upd2) => upd1.Key?.NumberOfUsages == upd2.Key?.NumberOfUsages },
+ {
+ "Buff",
+ (upd1, upd2) =>
+ upd1.Buff?.Value == upd2.Buff?.Value
+ && upd1.Buff?.BuffType == upd2.Buff?.BuffType
+ },
+ {
+ "CultistAmulet",
+ (upd1, upd2) =>
+ upd1.CultistAmulet?.NumberOfUsages == upd2.CultistAmulet?.NumberOfUsages
+ },
+ { "Dogtag", (upd1, upd2) => upd1.Dogtag?.ProfileId == upd2.Dogtag?.ProfileId },
+ { "FaceShield", (upd1, upd2) => upd1.FaceShield?.Hits == upd2.FaceShield?.Hits },
+ {
+ "Foldable",
+ (upd1, upd2) =>
+ upd1.Foldable?.Folded.GetValueOrDefault(false)
+ == upd2.Foldable?.Folded.GetValueOrDefault(false)
+ },
+ {
+ "FoodDrink",
+ (upd1, upd2) => upd1.FoodDrink?.HpPercent == upd2.FoodDrink?.HpPercent
+ },
+ { "MedKit", (upd1, upd2) => upd1.MedKit?.HpResource == upd2.MedKit?.HpResource },
+ {
+ "RecodableComponent",
+ (upd1, upd2) =>
+ upd1.RecodableComponent?.IsEncoded == upd2.RecodableComponent?.IsEncoded
+ },
+ {
+ "RepairKit",
+ (upd1, upd2) => upd1.RepairKit?.Resource == upd2.RepairKit?.Resource
+ },
+ {
+ "Resource",
+ (upd1, upd2) => upd1.Resource?.UnitsConsumed == upd2.Resource?.UnitsConsumed
+ },
+ };
+
+ // Choose above keys or passed in keys to compare items with
+ var valuesToCompare =
+ compareUpdProperties?.Count > 0 ? compareUpdProperties : comparers.Keys.ToHashSet();
+ foreach (var propertyName in valuesToCompare)
+ {
+ if (!comparers.TryGetValue(propertyName, out var comparer))
+ // Key not found, skip
+ {
+ continue;
+ }
+
+ if (!comparer(item1.Upd, item2.Upd))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ ///
+ /// Check if item is stored inside a container
+ ///
+ /// Item to check is inside of container
+ /// Name of slot to check item is in e.g. SecuredContainer/Backpack
+ /// Inventory with child parent items to check
+ /// True when item is in container
+ public static bool ItemIsInsideContainer(
+ this Item itemToCheck,
+ string desiredContainerSlotId,
+ IEnumerable- items
+ )
+ {
+ // Get items parent
+ var parent = items.FirstOrDefault(item =>
+ item.Id.Equals(itemToCheck.ParentId, StringComparison.OrdinalIgnoreCase)
+ );
+ if (parent is null)
+ // No parent, end of line, not inside container
+ {
+ return false;
+ }
+
+ if (parent.SlotId == desiredContainerSlotId)
+ {
+ return true;
+ }
+
+ return parent.ItemIsInsideContainer(desiredContainerSlotId, items);
+ }
+
+ ///
+ /// Get the size of a stack, return 1 if no stack object count property found
+ ///
+ /// Item to get stack size of
+ /// size of stack
+ public static int GetItemStackSize(this Item item)
+ {
+ if (item.Upd?.StackObjectsCount is not null)
+ {
+ return (int)item.Upd.StackObjectsCount;
+ }
+
+ return 1;
+ }
+
+ ///
+ /// Create a dictionary from a collection of items, keyed by item id
+ ///
+ /// Collection of items
+ /// Dictionary of items
+ public static Dictionary GenerateItemsMap(this IEnumerable
- items)
+ {
+ // Convert list to dictionary, keyed by items Id
+ return items.ToDictionary(item => item.Id);
+ }
+
+ ///
+ /// Adopts orphaned items by resetting them as root "hideout" items. Helpful in situations where a parent has been
+ /// deleted from a group of items and there are children still referencing the missing parent. This method will
+ /// remove the reference from the children to the parent and set item properties to root values.
+ ///
+ /// The ID of the "root" of the container
+ /// Array of Items that should be adjusted
+ /// Returns Array of Items that have been adopted
+ public static List
- AdoptOrphanedItems(this List
- items, string rootId)
+ {
+ foreach (var item in items)
+ {
+ // Check if the item's parent exists.
+ var parentExists = items.Any(parentItem =>
+ parentItem.Id.Equals(item.ParentId, StringComparison.OrdinalIgnoreCase)
+ );
+
+ // If the parent does not exist and the item is not already a 'hideout' item, adopt the orphaned item by
+ // setting the parent ID to the PMCs inventory equipment ID, the slot ID to 'hideout', and remove the location.
+ if (!parentExists && item.ParentId != rootId && item.SlotId != "hideout")
+ {
+ item.ParentId = rootId;
+ item.SlotId = "hideout";
+ item.Location = null;
+ }
+ }
+
+ return items;
+ }
+ }
+}
diff --git a/Libraries/SPTarkov.Server.Core/Extensions/ProfileExtensions.cs b/Libraries/SPTarkov.Server.Core/Extensions/ProfileExtensions.cs
index 70e11eb7..97a9daef 100644
--- a/Libraries/SPTarkov.Server.Core/Extensions/ProfileExtensions.cs
+++ b/Libraries/SPTarkov.Server.Core/Extensions/ProfileExtensions.cs
@@ -62,5 +62,16 @@ namespace SPTarkov.Server.Core.Extensions
return profile.TaskConditionCounters.Count > 0;
}
+
+ ///
+ /// Get a specific common skill from supplied profile
+ ///
+ /// Player profile
+ /// Skill to look up and return value from
+ /// Common skill object from desired profile
+ public static CommonSkill? GetSkillFromProfile(this PmcData profile, SkillTypes skill)
+ {
+ return profile?.Skills?.Common?.FirstOrDefault(s => s.Id == skill);
+ }
}
}
diff --git a/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs
index eb4c5251..909ce837 100644
--- a/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs
+++ b/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs
@@ -1,4 +1,5 @@
using SPTarkov.DI.Annotations;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Hideout;
@@ -1349,10 +1350,7 @@ public class HideoutHelper(
/// Consumption bonus
protected double? GetHideoutManagementConsumptionBonus(PmcData pmcData)
{
- var hideoutManagementSkill = _profileHelper.GetSkillFromProfile(
- pmcData,
- SkillTypes.HideoutManagement
- );
+ var hideoutManagementSkill = pmcData.GetSkillFromProfile(SkillTypes.HideoutManagement);
if (hideoutManagementSkill is null || hideoutManagementSkill.Progress == 0)
{
return 0;
@@ -1384,7 +1382,7 @@ public class HideoutHelper(
double valuePerLevel
)
{
- var profileSkill = _profileHelper.GetSkillFromProfile(pmcData, skill);
+ var profileSkill = pmcData.GetSkillFromProfile(skill);
if (profileSkill is null || profileSkill.Progress == 0)
{
return 0;
@@ -1563,10 +1561,7 @@ public class HideoutHelper(
.ToList();
// Calculate bonus percent (apply hideoutManagement bonus)
- var hideoutManagementSkill = _profileHelper.GetSkillFromProfile(
- pmcData,
- SkillTypes.HideoutManagement
- );
+ var hideoutManagementSkill = pmcData.GetSkillFromProfile(SkillTypes.HideoutManagement);
var hideoutManagementSkillBonusPercent = 1 + hideoutManagementSkill.Progress / 10000; // 5100 becomes 0.51, add 1 to it, 1.51
var bonus =
GetDogtagCombatSkillBonusPercent(pmcData, activeDogtags)
diff --git a/Libraries/SPTarkov.Server.Core/Helpers/InRaidHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/InRaidHelper.cs
index d22008c1..1bbdc3a7 100644
--- a/Libraries/SPTarkov.Server.Core/Helpers/InRaidHelper.cs
+++ b/Libraries/SPTarkov.Server.Core/Helpers/InRaidHelper.cs
@@ -1,5 +1,6 @@
using SPTarkov.Common.Extensions;
using SPTarkov.DI.Annotations;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Spt.Config;
@@ -25,8 +26,9 @@ public class InRaidHelper(
"pocket3",
"pocket4",
];
- protected InRaidConfig _inRaidConfig = _configServer.GetConfig();
- protected LostOnDeathConfig _lostOnDeathConfig = _configServer.GetConfig();
+ protected readonly InRaidConfig _inRaidConfig = _configServer.GetConfig();
+ protected readonly LostOnDeathConfig _lostOnDeathConfig =
+ _configServer.GetConfig();
///
/// Deprecated. Reset the skill points earned in a raid to 0, ready for next raid.
@@ -116,7 +118,7 @@ public class InRaidHelper(
&& !(dbItems[item.Template].Properties.QuestItem ?? false)
&& !(
_inRaidConfig.KeepFiRSecureContainerOnDeath
- && _itemHelper.ItemIsInsideContainer(item, "SecuredContainer", items)
+ && item.ItemIsInsideContainer("SecuredContainer", items)
);
});
@@ -201,13 +203,7 @@ public class InRaidHelper(
)
)
{
- if (
- _itemHelper.ItemIsInsideContainer(
- inventoryItem,
- secureContainerSlotId,
- pmcData.Inventory.Items
- )
- )
+ if (inventoryItem.ItemIsInsideContainer(secureContainerSlotId, pmcData.Inventory.Items))
{
itemsInsideContainer.Add(inventoryItem);
}
diff --git a/Libraries/SPTarkov.Server.Core/Helpers/InventoryHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/InventoryHelper.cs
index a7a029ac..e3fdacf3 100644
--- a/Libraries/SPTarkov.Server.Core/Helpers/InventoryHelper.cs
+++ b/Libraries/SPTarkov.Server.Core/Helpers/InventoryHelper.cs
@@ -3,6 +3,7 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using SPTarkov.Common.Extensions;
using SPTarkov.DI.Annotations;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Inventory;
@@ -27,7 +28,6 @@ public class InventoryHelper(
HttpResponseUtil _httpResponseUtil,
DialogueHelper _dialogueHelper,
ContainerHelper _containerHelper,
- DatabaseServer _databaseServer,
EventOutputHolder _eventOutputHolder,
ProfileHelper _profileHelper,
ItemHelper _itemHelper,
@@ -42,7 +42,8 @@ public class InventoryHelper(
BaseClasses.FUNCTIONAL_MOD,
BaseClasses.MOD,
];
- protected InventoryConfig _inventoryConfig = _configServer.GetConfig();
+ protected readonly InventoryConfig _inventoryConfig =
+ _configServer.GetConfig();
///
/// Add multiple items to player stash (assuming they all fit)
@@ -655,7 +656,7 @@ public class InventoryHelper(
var remainingCount = countToRemove;
foreach (var itemToReduce in itemsToReduce)
{
- var itemStackSize = _itemHelper.GetItemStackSize(itemToReduce);
+ var itemStackSize = itemToReduce.GetItemStackSize();
// Remove whole stack
if (remainingCount >= itemStackSize)
diff --git a/Libraries/SPTarkov.Server.Core/Helpers/ItemHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/ItemHelper.cs
index cb08b267..76b811d1 100644
--- a/Libraries/SPTarkov.Server.Core/Helpers/ItemHelper.cs
+++ b/Libraries/SPTarkov.Server.Core/Helpers/ItemHelper.cs
@@ -1,5 +1,6 @@
using System.Collections.Frozen;
using SPTarkov.DI.Annotations;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
@@ -178,98 +179,7 @@ public class ItemHelper(
return false;
}
- if (!IsSameItem(itemOf1, itemOf2, compareUpdProperties))
- {
- return false;
- }
- }
-
- return true;
- }
-
- ///
- /// This method will compare two items and see if they are equivalent
- /// This method will NOT compare IDs on the items
- ///
- /// first item to compare
- /// second item to compare
- /// Upd properties to compare between the items
- /// true if they are the same
- public bool IsSameItem(Item item1, Item item2, HashSet? compareUpdProperties = null)
- {
- // Different tpl == different item
- if (item1.Template != item2.Template)
- {
- return false;
- }
-
- // Both lack upd object + same tpl = same
- if (item1.Upd is null && item2.Upd is null)
- {
- return true;
- }
-
- // item1 lacks upd, item2 has one
- if (item1.Upd is null && item2.Upd is not null)
- {
- return false;
- }
-
- // item1 has upd, item2 lacks one
- if (item1.Upd is not null && item2.Upd is null)
- {
- return false;
- }
-
- // key = Upd property Type as string, value = comparison function that returns bool
- var comparers = new Dictionary>
- {
- { "Key", (upd1, upd2) => upd1.Key?.NumberOfUsages == upd2.Key?.NumberOfUsages },
- {
- "Buff",
- (upd1, upd2) =>
- upd1.Buff?.Value == upd2.Buff?.Value
- && upd1.Buff?.BuffType == upd2.Buff?.BuffType
- },
- {
- "CultistAmulet",
- (upd1, upd2) =>
- upd1.CultistAmulet?.NumberOfUsages == upd2.CultistAmulet?.NumberOfUsages
- },
- { "Dogtag", (upd1, upd2) => upd1.Dogtag?.ProfileId == upd2.Dogtag?.ProfileId },
- { "FaceShield", (upd1, upd2) => upd1.FaceShield?.Hits == upd2.FaceShield?.Hits },
- {
- "Foldable",
- (upd1, upd2) =>
- upd1.Foldable?.Folded.GetValueOrDefault(false)
- == upd2.Foldable?.Folded.GetValueOrDefault(false)
- },
- { "FoodDrink", (upd1, upd2) => upd1.FoodDrink?.HpPercent == upd2.FoodDrink?.HpPercent },
- { "MedKit", (upd1, upd2) => upd1.MedKit?.HpResource == upd2.MedKit?.HpResource },
- {
- "RecodableComponent",
- (upd1, upd2) =>
- upd1.RecodableComponent?.IsEncoded == upd2.RecodableComponent?.IsEncoded
- },
- { "RepairKit", (upd1, upd2) => upd1.RepairKit?.Resource == upd2.RepairKit?.Resource },
- {
- "Resource",
- (upd1, upd2) => upd1.Resource?.UnitsConsumed == upd2.Resource?.UnitsConsumed
- },
- };
-
- // Choose above keys or passed in keys to compare items with
- var valuesToCompare =
- compareUpdProperties?.Count > 0 ? compareUpdProperties : comparers.Keys.ToHashSet();
- foreach (var propertyName in valuesToCompare)
- {
- if (!comparers.TryGetValue(propertyName, out var comparer))
- // Key not found, skip
- {
- continue;
- }
-
- if (!comparer(item1.Upd, item2.Upd))
+ if (!itemOf1.IsSameItem(itemOf2, compareUpdProperties))
{
return false;
}
@@ -1709,37 +1619,6 @@ public class ItemHelper(
);
}
- ///
- /// Check if item is stored inside a container
- ///
- /// Item to check is inside of container
- /// Name of slot to check item is in e.g. SecuredContainer/Backpack
- /// Inventory with child parent items to check
- /// True when item is in container
- public bool ItemIsInsideContainer(
- Item itemToCheck,
- string desiredContainerSlotId,
- List
- items
- )
- {
- // Get items parent
- var parent = items.FirstOrDefault(item =>
- item.Id.Equals(itemToCheck.ParentId, StringComparison.OrdinalIgnoreCase)
- );
- if (parent is null)
- // No parent, end of line, not inside container
- {
- return false;
- }
-
- if (parent.SlotId == desiredContainerSlotId)
- {
- return true;
- }
-
- return ItemIsInsideContainer(parent, desiredContainerSlotId, items);
- }
-
///
/// Add child items (cartridges) to a magazine
///
@@ -1987,21 +1866,6 @@ public class ItemHelper(
};
}
- ///
- /// Get the size of a stack, return 1 if no stack object count property found
- ///
- /// Item to get stack size of
- /// size of stack
- public int GetItemStackSize(Item item)
- {
- if (item.Upd?.StackObjectsCount is not null)
- {
- return (int)item.Upd.StackObjectsCount;
- }
-
- return 1;
- }
-
///
/// Get the name of an item from the locale file using the item tpl
///
@@ -2256,45 +2120,6 @@ public class ItemHelper(
return newId;
}
- // Adopts orphaned items by resetting them as root "hideout" items. Helpful in situations where a parent has been
- // deleted from a group of items and there are children still referencing the missing parent. This method will
- // remove the reference from the children to the parent and set item properties to root values.
- //
- // The ID of the "root" of the container.
- // Array of Items that should be adjusted.
- // Returns Array of Items that have been adopted.
- public List
- AdoptOrphanedItems(string rootId, List
- items)
- {
- foreach (var item in items)
- {
- // Check if the item's parent exists.
- var parentExists = items.Any(parentItem =>
- parentItem.Id.Equals(item.ParentId, StringComparison.OrdinalIgnoreCase)
- );
-
- // If the parent does not exist and the item is not already a 'hideout' item, adopt the orphaned item by
- // setting the parent ID to the PMCs inventory equipment ID, the slot ID to 'hideout', and remove the location.
- if (!parentExists && item.ParentId != rootId && item.SlotId != "hideout")
- {
- item.ParentId = rootId;
- item.SlotId = "hideout";
- item.Location = null;
- }
- }
-
- return items;
- }
-
- // Populate a Map object of items for quick lookup using their ID.
- //
- // An array of Items that should be added to a Map.
- // Returns A Map where the keys are the item IDs and the values are the corresponding Item objects.
- public Dictionary GenerateItemsMap(List
- items)
- {
- // Convert list to dictionary, keyed by items Id
- return items.ToDictionary(item => item.Id);
- }
-
// Add a blank upd object to passed in item if it does not exist already
// item to add upd to
// text to write to log when upd object was not found
@@ -2372,19 +2197,6 @@ public class ItemHelper(
return null;
}
- // Remove FiR status from passed in items
- // Items to update FiR status of
- public void RemoveSpawnedInSessionPropertyFromItems(List
- items)
- {
- foreach (var item in items)
- {
- if (item.Upd is not null)
- {
- item.Upd.SpawnedInSession = null;
- }
- }
- }
-
///
/// Get a 2D grid of a container's item slots
///
diff --git a/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs
index ed2ed23e..889578f8 100644
--- a/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs
+++ b/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs
@@ -565,25 +565,6 @@ public class ProfileHelper(
profileSkill.LastAccess = _timeUtil.GetTimeStamp();
}
- ///
- /// Get a specific common skill from supplied profile
- ///
- /// Player profile
- /// Skill to look up and return value from
- /// Common skill object from desired profile
- public CommonSkill? GetSkillFromProfile(PmcData pmcData, SkillTypes skill)
- {
- var skillToReturn = pmcData?.Skills?.Common.FirstOrDefault(s => s.Id == skill);
- if (skillToReturn == null)
- {
- _logger.Warning(
- $"Profile {pmcData.SessionId} does not have a skill named: {skill.ToString()}"
- );
- }
-
- return skillToReturn;
- }
-
///
/// Is the provided session id for a developer account
///
diff --git a/Libraries/SPTarkov.Server.Core/Helpers/QuestRewardHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/QuestRewardHelper.cs
index b2562bf2..bb2cef75 100644
--- a/Libraries/SPTarkov.Server.Core/Helpers/QuestRewardHelper.cs
+++ b/Libraries/SPTarkov.Server.Core/Helpers/QuestRewardHelper.cs
@@ -1,14 +1,12 @@
using SPTarkov.Common.Extensions;
using SPTarkov.DI.Annotations;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Models.Enums;
-using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Models.Utils;
-using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
-using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
namespace SPTarkov.Server.Core.Helpers;
@@ -16,23 +14,14 @@ namespace SPTarkov.Server.Core.Helpers;
[Injectable]
public class QuestRewardHelper(
ISptLogger _logger,
- HashUtil _hashUtil,
- TimeUtil _timeUtil,
- ItemHelper _itemHelper,
PaymentHelper _paymentHelper,
- TraderHelper _traderHelper,
DatabaseService _databaseService,
- QuestConditionHelper _questConditionHelper,
ProfileHelper _profileHelper,
- PresetHelper _presetHelper,
RewardHelper _rewardHelper,
LocalisationService _localisationService,
- ICloner _cloner,
- ConfigServer _configServer
+ ICloner _cloner
)
{
- protected QuestConfig _questConfig = _configServer.GetConfig();
-
///
/// Value for in game reward traders to not duplicate quest rewards.
/// Value can be modified by modders by overriding this value with new traders.
@@ -161,10 +150,7 @@ public class QuestRewardHelper(
);
// Calculate hideout management bonus as a percentage (up to 51% bonus)
- var hideoutManagementSkill = _profileHelper.GetSkillFromProfile(
- pmcData,
- SkillTypes.HideoutManagement
- );
+ var hideoutManagementSkill = pmcData.GetSkillFromProfile(SkillTypes.HideoutManagement);
// 5100 becomes 0.51, add 1 to it, 1.51
// We multiply the money reward bonuses by the hideout management skill multiplier, giving the new result
diff --git a/Libraries/SPTarkov.Server.Core/Services/CircleOfCultistService.cs b/Libraries/SPTarkov.Server.Core/Services/CircleOfCultistService.cs
index 1ec06090..117dc3b0 100644
--- a/Libraries/SPTarkov.Server.Core/Services/CircleOfCultistService.cs
+++ b/Libraries/SPTarkov.Server.Core/Services/CircleOfCultistService.cs
@@ -1,5 +1,6 @@
using SPTarkov.Common.Extensions;
using SPTarkov.DI.Annotations;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -42,7 +43,7 @@ public class CircleOfCultistService(
)
{
protected const string CircleOfCultistSlotId = "CircleOfCultistsGrid1";
- protected HideoutConfig _hideoutConfig = _configServer.GetConfig();
+ protected readonly HideoutConfig _hideoutConfig = _configServer.GetConfig();
///
/// Start a sacrifice event
@@ -176,10 +177,7 @@ public class CircleOfCultistService(
);
// Adjust value generated by the players hideout management skill
- var hideoutManagementSkill = _profileHelper.GetSkillFromProfile(
- pmcData,
- SkillTypes.HideoutManagement
- );
+ var hideoutManagementSkill = pmcData.GetSkillFromProfile(SkillTypes.HideoutManagement);
if (hideoutManagementSkill is not null)
{
rewardAmountMultiplier *= (float)(1 + hideoutManagementSkill.Progress / 10000); // 5100 becomes 0.51, add 1 to it, 1.51, multiply the bonus by it (e.g. 1.2 x 1.51)
diff --git a/Libraries/SPTarkov.Server.Core/Services/InsuranceService.cs b/Libraries/SPTarkov.Server.Core/Services/InsuranceService.cs
index a466bd28..bdc3f741 100644
--- a/Libraries/SPTarkov.Server.Core/Services/InsuranceService.cs
+++ b/Libraries/SPTarkov.Server.Core/Services/InsuranceService.cs
@@ -1,4 +1,5 @@
using SPTarkov.DI.Annotations;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -21,7 +22,6 @@ public class InsuranceService(
DatabaseService _databaseService,
RandomUtil _randomUtil,
ItemHelper _itemHelper,
- HashUtil _hashUtil,
TimeUtil _timeUtil,
SaveServer _saveServer,
TraderHelper _traderHelper,
@@ -32,7 +32,8 @@ public class InsuranceService(
ICloner _cloner
)
{
- protected InsuranceConfig _insuranceConfig = _configServer.GetConfig();
+ protected readonly InsuranceConfig _insuranceConfig =
+ _configServer.GetConfig();
protected Dictionary>?> _insured = new();
///
@@ -302,13 +303,13 @@ public class InsuranceService(
/// True if item
protected bool ItemCannotBeLostOnDeath(Item lostItem, List
- inventoryItems)
{
- if (lostItem.SlotId?.ToLower().StartsWith("specialslot") ?? false)
+ if (lostItem.SlotId?.StartsWith("specialslot", StringComparison.OrdinalIgnoreCase) ?? false)
{
return true;
}
// We check secure container items even tho they are omitted from lostInsuredItems, just in case
- if (_itemHelper.ItemIsInsideContainer(lostItem, "SecuredContainer", inventoryItems))
+ if (lostItem.ItemIsInsideContainer("SecuredContainer", inventoryItems))
{
return true;
}
diff --git a/Libraries/SPTarkov.Server.Core/Services/MailSendService.cs b/Libraries/SPTarkov.Server.Core/Services/MailSendService.cs
index fe6cfe0c..a21b82da 100644
--- a/Libraries/SPTarkov.Server.Core/Services/MailSendService.cs
+++ b/Libraries/SPTarkov.Server.Core/Services/MailSendService.cs
@@ -1,4 +1,5 @@
using SPTarkov.DI.Annotations;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Profile;
@@ -195,7 +196,7 @@ public class MailSendService(
{
var rootItemParentId = _hashUtil.Generate();
- details.Items.AddRange(_itemHelper.AdoptOrphanedItems(rootItemParentId, items));
+ details.Items.AddRange(items.AdoptOrphanedItems(rootItemParentId));
details.ItemsMaxStorageLifetimeSeconds = maxStorageTimeSeconds;
}
diff --git a/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs b/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs
index 0416461d..d89d8e14 100644
--- a/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs
+++ b/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs
@@ -1,5 +1,6 @@
using System.Text.RegularExpressions;
using SPTarkov.DI.Annotations;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -88,10 +89,7 @@ public class ProfileFixerService(
// Otherwise we need to generate a new unique stash ID for this message's attachments
message.Items.Stash = _hashUtil.Generate();
- message.Items.Data = _itemHelper.AdoptOrphanedItems(
- message.Items.Stash,
- message.Items.Data
- );
+ message.Items.Data = message.Items.Data.AdoptOrphanedItems(message.Items.Stash);
// Because `adoptOrphanedItems` sets the slotId to `hideout`, we need to re-set it to `main` to work with mail
foreach (var item in message.Items.Data.Where(item => item.SlotId == "hideout"))
diff --git a/Libraries/SPTarkov.Server.Core/Services/RepairService.cs b/Libraries/SPTarkov.Server.Core/Services/RepairService.cs
index 441f4952..5534b4b1 100644
--- a/Libraries/SPTarkov.Server.Core/Services/RepairService.cs
+++ b/Libraries/SPTarkov.Server.Core/Services/RepairService.cs
@@ -1,6 +1,7 @@
using System.Text.Json.Serialization;
using SPTarkov.Common.Extensions;
using SPTarkov.DI.Annotations;
+using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -420,7 +421,7 @@ public class RepairService(
.Intellect
.RepairPointsCostReduction;
var profileIntellectLevel =
- _profileHelper.GetSkillFromProfile(pmcData, SkillTypes.Intellect)?.Progress ?? 0;
+ pmcData.GetSkillFromProfile(SkillTypes.Intellect)?.Progress ?? 0;
var intellectPointReduction =
intellectRepairPointsPerLevel * Math.Truncate(profileIntellectLevel / 100);
@@ -629,8 +630,7 @@ public class RepairService(
// Skill < level 10 + repairing weapon
if (
itemSkillType == SkillTypes.WeaponTreatment
- && _profileHelper.GetSkillFromProfile(pmcData, SkillTypes.WeaponTreatment)?.Progress
- < 1000
+ && pmcData.GetSkillFromProfile(SkillTypes.WeaponTreatment)?.Progress < 1000
)
{
return false;
@@ -641,7 +641,7 @@ public class RepairService(
new HashSet { SkillTypes.LightVests, SkillTypes.HeavyVests }.Contains(
itemSkillType.Value
)
- && _profileHelper.GetSkillFromProfile(pmcData, itemSkillType.Value)?.Progress < 1000
+ && pmcData.GetSkillFromProfile(itemSkillType.Value)?.Progress < 1000
)
{
return false;
@@ -670,7 +670,7 @@ public class RepairService(
var receivedDurabilityMaxPercent = buffSettings.ReceivedDurabilityMaxPercent;
var skillLevel = Math.Truncate(
- (_profileHelper.GetSkillFromProfile(pmcData, itemSkillType.Value)?.Progress ?? 0) / 100
+ (pmcData.GetSkillFromProfile(itemSkillType.Value)?.Progress ?? 0) / 100
);
if (repairDetails.RepairPoints is null)