diff --git a/Libraries/SPTarkov.Server.Core/Helpers/PaymentHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/PaymentHelper.cs index e94e9508..06447f70 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/PaymentHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/PaymentHelper.cs @@ -5,23 +5,28 @@ using SPTarkov.Server.Core.Servers; namespace SPTarkov.Server.Core.Helpers; -[Injectable] -public class PaymentHelper(ConfigServer _configServer) +[Injectable(InjectionType.Singleton)] +public class PaymentHelper(ConfigServer configServer) { protected bool _addedCustomMoney; - protected InventoryConfig _inventoryConfig = _configServer.GetConfig(); - protected List _moneyTpls = [Money.DOLLARS, Money.EUROS, Money.ROUBLES, Money.GP]; + protected readonly InventoryConfig _inventoryConfig = configServer.GetConfig(); + protected readonly HashSet _moneyTpls = [Money.DOLLARS, Money.EUROS, Money.ROUBLES, Money.GP]; /// /// Is the passed in tpl money (also checks custom currencies in inventoryConfig.customMoneyTpls) /// - /// + /// Item Tpl to check /// public bool IsMoneyTpl(string tpl) { + // Add custom currency first time this method is accessed if (!_addedCustomMoney) { - _moneyTpls.AddRange(_inventoryConfig.CustomMoneyTpls); + foreach (var customMoney in _inventoryConfig.CustomMoneyTpls) + { + _moneyTpls.Add(customMoney); + } + _addedCustomMoney = true; } @@ -32,7 +37,7 @@ public class PaymentHelper(ConfigServer _configServer) /// Gets currency TPL from TAG /// /// - /// + /// Tpl of currency public string GetCurrency(CurrencyType? currency) { return currency switch @@ -41,7 +46,7 @@ public class PaymentHelper(ConfigServer _configServer) CurrencyType.USD => Money.DOLLARS, CurrencyType.RUB => Money.ROUBLES, CurrencyType.GP => Money.GP, - _ => "" + _ => string.Empty }; } } diff --git a/Libraries/SPTarkov.Server.Core/Helpers/RagfairOfferHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/RagfairOfferHelper.cs index 7d0f42bd..c177ad52 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/RagfairOfferHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/RagfairOfferHelper.cs @@ -168,31 +168,30 @@ public class RagfairOfferHelper( public List GetOffersThatRequireItem(SearchRequestData searchRequest, PmcData pmcData) { // Get all offers that require the desired item and filter out offers from non traders if player below ragfair unlock - var requiredOffers = _ragfairRequiredItemsService.GetRequiredItemsById(searchRequest.NeededSearchId); + var offerIDsForItem = _ragfairRequiredItemsService.GetRequiredOffersById(searchRequest.NeededSearchId); var tieredFlea = _ragfairConfig.TieredFlea; var tieredFleaLimitTypes = tieredFlea.UnlocksType; - return requiredOffers.Where(offer => - { - if (!PassesSearchFilterCriteria(searchRequest, offer, pmcData)) - { - return false; - } - if (tieredFlea.Enabled && !OfferIsFromTrader(offer)) - { - CheckAndLockOfferFromPlayerTieredFlea( - tieredFlea, - offer, - tieredFleaLimitTypes.Keys.ToList(), - pmcData.Info.Level.Value - ); - } + var result = new List(); + foreach (var offer in offerIDsForItem + .Select(_ragfairOfferService.GetOfferByOfferId) + .Where(offer => PassesSearchFilterCriteria(searchRequest, offer, pmcData))) + { + if (tieredFlea.Enabled && !OfferIsFromTrader(offer)) + { + CheckAndLockOfferFromPlayerTieredFlea( + tieredFlea, + offer, + tieredFleaLimitTypes.Keys.ToList(), + pmcData.Info.Level.Value + ); + } - return true; - } - ) - .ToList(); + result.Add(offer); + } + + return result; } /// diff --git a/Libraries/SPTarkov.Server.Core/Servers/RagfairServer.cs b/Libraries/SPTarkov.Server.Core/Servers/RagfairServer.cs index 1915b599..004b1e3c 100644 --- a/Libraries/SPTarkov.Server.Core/Servers/RagfairServer.cs +++ b/Libraries/SPTarkov.Server.Core/Servers/RagfairServer.cs @@ -57,11 +57,13 @@ public class RagfairServer( // Must occur BEFORE "RemoveExpiredOffers" var expiredAssortsWithChildren = _ragfairOfferHolder.GetExpiredOfferItems(); + _ragfairOfferService.RemoveExpiredOffers(); + + // Force a cleanup+compact now all the expired offers are gone + GC.Collect(GC.MaxGeneration, GCCollectionMode.Optimized, true, true); + // Replace the expired offers with new ones _ragfairOfferGenerator.GenerateDynamicOffers(expiredAssortsWithChildren); - - _ragfairOfferService.RemoveExpiredOffers(); - GC.Collect(GC.MaxGeneration, GCCollectionMode.Optimized, true, true); } _ragfairRequiredItemsService.BuildRequiredItemTable(); diff --git a/Libraries/SPTarkov.Server.Core/Services/RagfairRequiredItemsService.cs b/Libraries/SPTarkov.Server.Core/Services/RagfairRequiredItemsService.cs index 518e7e29..3252813f 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RagfairRequiredItemsService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RagfairRequiredItemsService.cs @@ -1,34 +1,44 @@ using System.Collections.Concurrent; using SPTarkov.DI.Annotations; using SPTarkov.Server.Core.Helpers; -using SPTarkov.Server.Core.Models.Eft.Ragfair; namespace SPTarkov.Server.Core.Services; [Injectable(InjectionType.Singleton)] public class RagfairRequiredItemsService( - RagfairOfferService _ragfairOfferService, - PaymentHelper _paymentHelper) + RagfairOfferService ragfairOfferService, + PaymentHelper paymentHelper) { - protected ConcurrentDictionary> _requiredItemsCache = new(); + /// + /// Key = tpl + /// + protected readonly ConcurrentDictionary> _requiredItemsCache = new(); - public List GetRequiredItemsById(string searchId) + /// + /// Get the offerId of offers that require the supplied tpl + /// + /// Tpl to find offers ids for + /// + public HashSet GetRequiredOffersById(string tpl) { - if (_requiredItemsCache.TryGetValue(searchId, out var list)) + if (_requiredItemsCache.TryGetValue(tpl, out var offerIds)) { - return list; + return offerIds; } return []; } + /// + /// Create a cache of requirements to purchase item + /// public void BuildRequiredItemTable() { _requiredItemsCache.Clear(); - foreach (var offer in _ragfairOfferService.GetOffers()) + foreach (var offer in ragfairOfferService.GetOffers()) foreach (var requirement in offer.Requirements) { - if (_paymentHelper.IsMoneyTpl(requirement.Template)) + if (paymentHelper.IsMoneyTpl(requirement.Template)) // This would just be too noisy { continue; @@ -38,7 +48,7 @@ public class RagfairRequiredItemsService( _requiredItemsCache.TryAdd(requirement.Template, []); // Add matching offer - _requiredItemsCache.GetValueOrDefault(requirement.Template)?.Add(offer); + _requiredItemsCache.GetValueOrDefault(requirement.Template)?.Add(offer.Id); } } } diff --git a/Libraries/SPTarkov.Server.Core/Utils/RagfairOfferHolder.cs b/Libraries/SPTarkov.Server.Core/Utils/RagfairOfferHolder.cs index e742fc11..4124d570 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/RagfairOfferHolder.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/RagfairOfferHolder.cs @@ -42,7 +42,10 @@ public class RagfairOfferHolder( /// RagfairOffer public HashSet GetStaleOfferIds() { - return _expiredOfferIds; + lock (_expiredOfferIdsLock) + { + return _expiredOfferIds; + } } /// @@ -90,7 +93,7 @@ public class RagfairOfferHolder( /// RagfairOffer list public List GetOffers() { - if (_offersById.Count > 0) + if (!_offersById.IsEmpty) { return _offersById.Values.ToList(); } @@ -342,7 +345,7 @@ public class RagfairOfferHolder( } /// - /// Flag offers with an expiry before the passed in timestamp + /// Flag offers with a end date set before the passed in timestamp /// /// Timestamp at point offer is 'expired' public void FlagExpiredOffersAfterDate(long timestamp)