From 8b323d396c668eb90bdbb1c2070f7cf3e2ecfa56 Mon Sep 17 00:00:00 2001 From: Chomp Date: Thu, 12 Jun 2025 16:45:45 +0100 Subject: [PATCH] Refactored `PrioritiseStashSort` Take into account money in secure and prioritise Better handle money stacks being both in containers --- .../Services/PaymentService.cs | 148 +++++++++++------- 1 file changed, 95 insertions(+), 53 deletions(-) diff --git a/Libraries/SPTarkov.Server.Core/Services/PaymentService.cs b/Libraries/SPTarkov.Server.Core/Services/PaymentService.cs index 58ccd095..8078e9d2 100644 --- a/Libraries/SPTarkov.Server.Core/Services/PaymentService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/PaymentService.cs @@ -403,20 +403,22 @@ public class PaymentService( /// Inventory items to check /// Id of players stash /// Dictionary - protected IReadOnlyDictionary GetItemInStashCache(List items, string playerStashId) + protected IReadOnlyDictionary GetItemInStashCache(List items, string playerStashId) { - var itemsInStashCache = new Dictionary(); + var itemsInStashCache = new Dictionary(); foreach (var inventoryItem in items) { - itemsInStashCache.TryAdd(inventoryItem.Id, IsInStash(inventoryItem.Id, items, playerStashId)); + itemsInStashCache.TryAdd(inventoryItem.Id, GetItemLocation(inventoryItem.Id, items, playerStashId)); } return itemsInStashCache; } /// - /// Prioritise player stash first over player inventory. - /// Post-raid healing would often take money out of the players pockets/secure container. + /// Get stacks of money from player inventory, ordered by priority to use from + /// Post-raid healing would often take money out of the players pockets/secure container. + /// Return money stacks in root of stash first, with the smallest stacks taking priority + /// Stacks inside secure are returned last /// /// First money stack item /// Second money stack item @@ -427,69 +429,97 @@ public class PaymentService( Item a, Item b, List inventoryItems, - IReadOnlyDictionary itemInStashCache) + IReadOnlyDictionary itemInStashCache) { - itemInStashCache.TryGetValue(a.Id, out var aInStash); - itemInStashCache.TryGetValue(b.Id, out var bInStash); + // Get the location of A and B + itemInStashCache.TryGetValue(a.Id, out var aLocation); + itemInStashCache.TryGetValue(b.Id, out var bLocation); - // A in root of stash, B not, prioritise A - if (aInStash && !bInStash) - { - return -1; - } + // Helper fields + var aInStash = aLocation == InventoryLocation.Stash; + var bInStash = bLocation == InventoryLocation.Stash; + var aInSecure = aLocation == InventoryLocation.Secure; + var bInSecure = bLocation == InventoryLocation.Secure; + var onlyAInStash = aInStash && !bInStash; + var onlyBInStash = !aInStash && bInStash; + var bothInStash = aInStash && bInStash; - // B in root stash, A not, prioritise B - if (!aInStash && bInStash) + if (bothInStash) { - return 1; - } + // Determine if they're in containers + var aInContainer = string.Equals(a.SlotId, "main", StringComparison.InvariantCultureIgnoreCase); + var bInContainer = string.Equals(b.SlotId, "main", StringComparison.InvariantCultureIgnoreCase); - // Both in root stash, prioritise the smallest sized - if (aInStash && bInStash) - { - return GetPriorityBySmallestStackSize(a, b); - } - - // Both in containers - if (a.SlotId == "main" && b.SlotId == "main") - { - // A container in stash, B not, prioritise A - if (aInStash && !bInStash) + // Return item not in container + var compare = aInContainer.CompareTo(bInContainer); + if (compare != 0) { - return -1; + return compare; } - // B container in stash, A not, prioritise B - if (!aInStash && bInStash) - { - return 1; - } - - // Both containers in stash - if (aInStash && bInStash) + // Both in containers, deprioritized item in 'bad' container + if (aInContainer + && bInContainer) { // Containers where taking money from would inconvenience player var aImmediateParent = inventoryItems.FirstOrDefault(item => item.Id == a.ParentId); var bImmediateParent = inventoryItems.FirstOrDefault(item => item.Id == b.ParentId); - // A is not a deprioritized container, B is + var aInDeprioContainer = _inventoryConfig.DeprioritisedMoneyContainers.Contains(aImmediateParent.Template); + var bInDeprioContainer = _inventoryConfig.DeprioritisedMoneyContainers.Contains(bImmediateParent.Template); + + // Prioritize B if ( - !_inventoryConfig.DeprioritisedMoneyContainers.Contains(aImmediateParent.Template) && - _inventoryConfig.DeprioritisedMoneyContainers.Contains(bImmediateParent.Template) + !aInDeprioContainer + && bInDeprioContainer ) { return -1; } - // B is not a deprioritized container, A is + // Prioritize A if ( - _inventoryConfig.DeprioritisedMoneyContainers.Contains(aImmediateParent.Template) && - !_inventoryConfig.DeprioritisedMoneyContainers.Contains(bImmediateParent.Template) + aInDeprioContainer + && !bInDeprioContainer ) { return 1; } + + // Both in bad containers, fall out of IF and run GetPriorityBySmallestStackSize } + + return GetPriorityBySmallestStackSize(a, b); + } + + // Prioritise A + if (onlyAInStash) + { + return -1; + } + + // Prioritise B + if (onlyBInStash) + { + return 1; + } + + // A in secure, B not, prioritise B + if (aInSecure && !bInSecure) + { + return 1; + } + + // B in secure, A not, prioritise A + if (!aInSecure && bInSecure) + { + return -1; + } + + // Both in secure + if (aInSecure && bInSecure) + { + return 0; } // They match / we don't know @@ -518,28 +548,40 @@ public class PaymentService( /// Player inventory /// Players stash ID /// True if it's in inventory - protected bool IsInStash(string itemId, List inventoryItems, string playerStashId) + protected InventoryLocation GetItemLocation(string itemId, List inventoryItems, string playerStashId) { - var itemParent = inventoryItems.FirstOrDefault(item => item.Id == itemId); - if (itemParent is null) + var inventoryItem = inventoryItems.FirstOrDefault(item => item.Id == itemId); + if (inventoryItem is null) { - // Needs parent id be in stash - return false; + // Doesn't exist + return InventoryLocation.Other; } // is root item and its parent is the player stash - if (itemParent.Id == playerStashId) + if (inventoryItem.Id == playerStashId) { - return true; + return InventoryLocation.Stash; } // is child item and its parent is a root item - if (itemParent.SlotId == "hideout") + if (inventoryItem.SlotId == "hideout") { - return true; + return InventoryLocation.Stash; + } + + if (inventoryItem.SlotId == "SecuredContainer") + { + return InventoryLocation.Secure; } // Recursive call for parentId - return IsInStash(itemParent.ParentId, inventoryItems, playerStashId); + return GetItemLocation(inventoryItem.ParentId, inventoryItems, playerStashId); + } + + protected enum InventoryLocation + { + Other = 0, + Stash = 1, + Secure = 2 } }