Various micro-optimisations

This commit is contained in:
Chomp
2025-07-18 16:05:29 +01:00
parent 80624ece4d
commit 38fb2454c7
26 changed files with 144 additions and 142 deletions
@@ -292,7 +292,7 @@ public class BotController(
);
}
var maxThreads = botGenerationDetails.BotCountToGenerate.Value;
var maxThreads = botGenerationDetails.BotCountToGenerate;
#if DEBUG
// Make debugging bot gen easier
@@ -250,9 +250,12 @@ public class InventoryController(
}
case "ExamineAllItems":
{
var itemsToInspect = itemHelper.GetItems().Where(x => x.Type != "Node");
FlagItemsAsInspectedAndRewardXp(itemsToInspect.Select(x => x.Id), fullProfile);
logger.Success($"Flagged {itemsToInspect.Count()} items as examined");
var itemIds = databaseService
.GetItems()
.Where(x => x.Value.Type != "Node")
.Select(x => x.Key);
FlagItemsAsInspectedAndRewardXp(itemIds, fullProfile);
logger.Success($"Flagged {itemIds.Count()} items as examined");
break;
}
@@ -1020,7 +1020,8 @@ public class RagfairController(
formattedRequirements.ToList(),
loyalLevel,
(int?)items.FirstOrDefault()?.Upd?.StackObjectsCount ?? 1,
sellInOnePiece
sellInOnePiece,
true
);
}
@@ -207,13 +207,7 @@ namespace SPTarkov.Server.Core.Extensions
foreach (var childItem in items)
{
if (
string.Equals(
childItem.ParentId,
baseItemId,
StringComparison.OrdinalIgnoreCase
)
)
if (childItem.ParentId == baseItemId.ToString())
{
list.AddRange(FindAndReturnChildrenByItems(items, childItem.Id));
}
@@ -292,8 +286,9 @@ namespace SPTarkov.Server.Core.Extensions
)
{
// Use dictionary to make key lookup faster, convert to list before being returned
var itemList = items.ToList();
OrderedDictionary<MongoId, Item> result = [];
foreach (var childItem in items)
foreach (var childItem in itemList)
{
// Include itself
if (childItem.Id == baseItemId)
@@ -403,9 +398,7 @@ namespace SPTarkov.Server.Core.Extensions
item.Id = newId;
// Find all children of item and update their parent ids to match
var childItems = items.Where(x =>
string.Equals(x.ParentId, originalId, StringComparison.OrdinalIgnoreCase)
);
var childItems = items.Where(item => item.ParentId == originalId.ToString());
foreach (var childItem in childItems)
{
childItem.ParentId = newId;
@@ -12,7 +12,7 @@ namespace SPTarkov.Server.Core.Extensions
/// <returns>True - offer is stale</returns>
public static bool IsStale(this RagfairOffer offer, long time)
{
return offer.EndTime < time || (offer.Quantity ?? 0) < 1;
return offer.EndTime < time || (offer.Quantity) < 1;
}
}
}
@@ -55,7 +55,7 @@ namespace SPTarkov.Server.Core.Extensions
/// <param name="armorItem">Item to look up default plate</param>
/// <param name="modSlot">front/back</param>
/// <returns>Tpl of plate</returns>
public static string? GetDefaultPlateTpl(this TemplateItem armorItem, string modSlot)
public static MongoId? GetDefaultPlateTpl(this TemplateItem armorItem, string modSlot)
{
var relatedItemDbModSlot = armorItem.Properties.Slots?.FirstOrDefault(slot =>
string.Equals(slot.Name, modSlot, StringComparison.OrdinalIgnoreCase)
@@ -197,7 +197,8 @@ public class BotEquipmentModGenerator(
);
switch (plateSlotFilteringOutcome.Result)
{
case Result.UNKNOWN_FAILURE or Result.NO_DEFAULT_FILTER:
case Result.UNKNOWN_FAILURE
or Result.NO_DEFAULT_FILTER:
if (logger.IsLogEnabled(LogLevel.Debug))
{
logger.Debug(
@@ -421,9 +422,9 @@ public class BotEquipmentModGenerator(
var defaultPlate = armorItem.GetDefaultPlateTpl(modSlot);
if (defaultPlate is not null)
{
// Return Default Plates cause couldn't get lowest level available from original selection
// Return Default Plates cause couldn't get the lowest level available from original selection
result.Result = Result.SUCCESS;
result.PlateModTemplates = [defaultPlate];
result.PlateModTemplates = [defaultPlate.Value];
return result;
}
@@ -37,22 +37,27 @@ public class FenceBaseAssortGenerator(
var blockedSeasonalItems = seasonalEventService.GetInactiveSeasonalEventItems();
var baseFenceAssort = databaseService.GetTrader(Traders.FENCE).Assort;
foreach (var rootItemDb in itemHelper.GetItems().Where(IsValidFenceItem))
foreach (var (itemId, rootItemDb) in databaseService.GetItems())
{
if (!string.Equals(rootItemDb.Type, "Item", StringComparison.OrdinalIgnoreCase))
{
continue;
}
// Skip blacklisted items
if (itemFilterService.IsItemBlacklisted(rootItemDb.Id))
if (itemFilterService.IsItemBlacklisted(itemId))
{
continue;
}
// Skip reward item blacklist
if (itemFilterService.IsItemRewardBlacklisted(rootItemDb.Id))
if (itemFilterService.IsItemRewardBlacklisted(itemId))
{
continue;
}
// Invalid
if (!itemHelper.IsValidItem(rootItemDb.Id))
if (!itemHelper.IsValidItem(itemId))
{
continue;
}
@@ -61,8 +66,8 @@ public class FenceBaseAssortGenerator(
if (traderConfig.Fence.Blacklist.Count > 0)
{
if (
traderConfig.Fence.Blacklist.Contains(rootItemDb.Id)
|| itemHelper.IsOfBaseclasses(rootItemDb.Id, traderConfig.Fence.Blacklist)
traderConfig.Fence.Blacklist.Contains(itemId)
|| itemHelper.IsOfBaseclasses(itemId, traderConfig.Fence.Blacklist)
)
{
continue;
@@ -71,7 +76,7 @@ public class FenceBaseAssortGenerator(
// Only allow rigs with no slots (carrier rigs)
if (
itemHelper.IsOfBaseclass(rootItemDb.Id, BaseClasses.VEST)
itemHelper.IsOfBaseclass(itemId, BaseClasses.VEST)
&& (rootItemDb.Properties?.Slots?.Count ?? 0) > 0
)
{
@@ -79,10 +84,7 @@ public class FenceBaseAssortGenerator(
}
// Skip seasonal event items when not in seasonal event
if (
traderConfig.Fence.BlacklistSeasonalItems
&& blockedSeasonalItems.Contains(rootItemDb.Id)
)
if (traderConfig.Fence.BlacklistSeasonalItems && blockedSeasonalItems.Contains(itemId))
{
continue;
}
@@ -93,7 +95,7 @@ public class FenceBaseAssortGenerator(
new()
{
Id = new MongoId(),
Template = rootItemDb.Id,
Template = itemId,
ParentId = "hideout",
SlotId = "hideout",
Upd = new Upd { StackObjectsCount = 9999999 },
@@ -101,7 +103,7 @@ public class FenceBaseAssortGenerator(
};
// Ensure ammo is not above penetration limit value
if (itemHelper.IsOfBaseclasses(rootItemDb.Id, [BaseClasses.AMMO_BOX, BaseClasses.AMMO]))
if (itemHelper.IsOfBaseclasses(itemId, [BaseClasses.AMMO_BOX, BaseClasses.AMMO]))
{
if (IsAmmoAbovePenetrationLimit(rootItemDb))
{
@@ -109,7 +111,7 @@ public class FenceBaseAssortGenerator(
}
}
if (itemHelper.IsOfBaseclass(rootItemDb.Id, BaseClasses.AMMO_BOX))
if (itemHelper.IsOfBaseclass(itemId, BaseClasses.AMMO_BOX))
// Only add cartridges to box if box has no children
{
if (itemWithChildrenToAdd.Count == 1)
@@ -130,7 +132,7 @@ public class FenceBaseAssortGenerator(
var barterSchemeToAdd = new BarterScheme
{
Count = Math.Round(
(double)fenceService.GetItemPrice(rootItemDb.Id, itemWithChildrenToAdd)
(double)fenceService.GetItemPrice(itemId, itemWithChildrenToAdd)
),
Template = Money.ROUBLES,
};
@@ -185,8 +187,8 @@ public class FenceBaseAssortGenerator(
var itemQualityModifier = itemHelper.GetItemQualityModifierForItems(itemAndChildren);
// Multiply weapon+mods rouble price by quality modifier
baseFenceAssort.BarterScheme[itemAndChildren[0].Id] = new List<List<BarterScheme>>
{
baseFenceAssort.BarterScheme[itemAndChildren[0].Id] =
[
new()
{
new BarterScheme
@@ -195,7 +197,7 @@ public class FenceBaseAssortGenerator(
Count = Math.Round(price * itemQualityModifier),
},
},
};
];
baseFenceAssort.LoyalLevelItems[itemAndChildren[0].Id] = 1;
}
@@ -49,7 +49,7 @@ public class LootGenerator(
if (sealedWeaponCrateCount > 0)
{
// Get list of all sealed containers from db - they're all the same, just for flavor
var itemsDb = itemHelper.GetItems();
var itemsDb = databaseService.GetItems().Values;
var sealedWeaponContainerPool = itemsDb.Where(item =>
item.Name.Contains("event_container_airdrop")
);
@@ -55,7 +55,7 @@ public class RagfairAssortGenerator(
// Get cloned items from db
var dbItemsClone = itemHelper
.GetItems()
.GetItemsClone()
.Where(item => !string.Equals(item.Type, "Node", StringComparison.OrdinalIgnoreCase));
// Store processed preset tpls so we don't add them when processing non-preset items
@@ -136,7 +136,7 @@ public class RagfairAssortGenerator(
/// <returns> Hydrated Item object </returns>
protected Item CreateRagfairAssortRootItem(MongoId tplId, MongoId? id = null)
{
if (string.IsNullOrEmpty(id))
if (id == null || id.Value.IsEmpty())
{
id = new MongoId();
}
@@ -58,6 +58,7 @@ public class RagfairOfferGenerator(
/// <param name="loyalLevel">Loyalty level needed to buy item</param>
/// <param name="quantity">Amount of item being listed</param>
/// <param name="sellInOnePiece">Flags sellInOnePiece to be true</param>
/// <param name="isPlayerOffer">Offer to create is for a player</param>
/// <returns>RagfairOffer</returns>
public RagfairOffer CreateAndAddFleaOffer(
MongoId userId,
@@ -66,7 +67,8 @@ public class RagfairOfferGenerator(
List<BarterScheme> barterScheme,
int loyalLevel,
int quantity,
bool sellInOnePiece = false
bool sellInOnePiece = false,
bool isPlayerOffer = false
)
{
var offer = CreateOffer(
@@ -76,8 +78,13 @@ public class RagfairOfferGenerator(
barterScheme,
loyalLevel,
quantity,
sellInOnePiece
sellInOnePiece,
isPlayerOffer
);
offer.ExtensionData ??= new Dictionary<string, object>();
offer.ExtensionData.Add("isPlayerOffer", isPlayerOffer);
ragfairOfferService.AddOffer(offer);
return offer;
@@ -93,6 +100,7 @@ public class RagfairOfferGenerator(
/// <param name="loyalLevel">Loyalty level needed to buy item</param>
/// <param name="quantity">Amount of item being listed</param>
/// <param name="isPackOffer">Is offer being created flagged as a pack</param>
/// <param name="isPlayerOffer">Offer is from a player</param>
/// <returns>RagfairOffer</returns>
protected RagfairOffer CreateOffer(
MongoId userId,
@@ -101,7 +109,8 @@ public class RagfairOfferGenerator(
List<BarterScheme> barterScheme,
int loyalLevel,
int quantity,
bool isPackOffer = false
bool isPackOffer = false,
bool isPlayerOffer = false
)
{
var offerRequirements = barterScheme
@@ -132,8 +141,8 @@ public class RagfairOfferGenerator(
// Hydrate ammo boxes with cartridges + ensure only 1 item is present (ammo box)
// On offer refresh don't re-add cartridges to ammo box that already has cartridges
if (
itemHelper.IsOfBaseclass(itemsClone[0].Template, BaseClasses.AMMO_BOX)
&& itemsClone.Count == 1
itemsClone.Count == 1
&& itemHelper.IsOfBaseclass(itemsClone[0].Template, BaseClasses.AMMO_BOX)
)
{
itemHelper.AddCartridgesToAmmoBox(
@@ -151,7 +160,9 @@ public class RagfairOfferGenerator(
{
Id = new MongoId(),
InternalId = offerCounter,
User = CreateUserDataForFleaOffer(userId, ragfairServerHelper.IsTrader(userId)),
User = isPlayerOffer
? CreatePlayerUserDataForFleaOffer(userId)
: CreateUserDataForFleaOffer(userId, ragfairServerHelper.IsTrader(userId)),
Root = rootItem.Id,
Items = itemsClone,
ItemsCost = Math.Round(handbookHelper.GetTemplatePrice(rootItem.Template)), // Handbook price
@@ -185,23 +196,6 @@ public class RagfairOfferGenerator(
return new RagfairOfferUser { Id = userId, MemberType = MemberCategory.Trader };
}
var isPlayerOffer = profileHelper.IsPlayer(userId);
if (isPlayerOffer)
{
var playerProfile = profileHelper.GetPmcProfile(userId);
return new RagfairOfferUser
{
Id = playerProfile.Id.Value,
MemberType = playerProfile.Info.MemberCategory,
SelectedMemberCategory = playerProfile.Info.SelectedMemberCategory,
Nickname = playerProfile.Info.Nickname,
Rating = playerProfile.RagfairInfo.Rating ?? 0,
IsRatingGrowing = playerProfile.RagfairInfo.IsRatingGrowing,
Avatar = null,
Aid = playerProfile.Aid,
};
}
// 'Fake' pmc offer
return new RagfairOfferUser
{
@@ -218,6 +212,27 @@ public class RagfairOfferGenerator(
};
}
/// <summary>
/// Create the user object stored inside each flea offer object
/// </summary>
/// <param name="userId">Player id</param>
/// <returns>OfferUser object</returns>
protected RagfairOfferUser CreatePlayerUserDataForFleaOffer(MongoId userId)
{
var playerProfile = profileHelper.GetPmcProfile(userId);
return new RagfairOfferUser
{
Id = playerProfile.Id.Value,
MemberType = playerProfile.Info.MemberCategory,
SelectedMemberCategory = playerProfile.Info.SelectedMemberCategory,
Nickname = playerProfile.Info.Nickname,
Rating = playerProfile.RagfairInfo.Rating ?? 0,
IsRatingGrowing = playerProfile.RagfairInfo.IsRatingGrowing,
Avatar = null,
Aid = playerProfile.Aid,
};
}
/// <summary>
/// Calculate the offer price that's listed on the flea listing
/// </summary>
@@ -1083,15 +1098,15 @@ public class RagfairOfferGenerator(
// Filter possible barters to items that match the price range + not itself
var min = desiredItemCostRouble - offerCostVarianceRoubles;
var max = desiredItemCostRouble + offerCostVarianceRoubles;
var itemsInsidePriceBounds = itemFleaPrices.Where(itemAndPrice =>
itemAndPrice.Price >= min
&& itemAndPrice.Price <= max
&& !string.Equals(
itemAndPrice.Tpl,
offerItems[0].Template,
StringComparison.OrdinalIgnoreCase
) // Don't allow the item being sold to be chosen
);
var rootOfferItem = offerItems.FirstOrDefault();
var itemsInsidePriceBounds = itemFleaPrices
.Where(itemAndPrice =>
itemAndPrice.Price >= min
&& itemAndPrice.Price <= max
&& itemAndPrice.Tpl != rootOfferItem.Template // Don't allow the item being sold to be chosen
)
.ToList();
// No items on flea have a matching price, fall back to currency
if (!itemsInsidePriceBounds.Any())
@@ -1100,7 +1115,7 @@ public class RagfairOfferGenerator(
}
// Choose random item from price-filtered flea items
var randomItem = randomUtil.GetArrayValue(itemsInsidePriceBounds.ToList());
var randomItem = randomUtil.GetArrayValue(itemsInsidePriceBounds);
return [new BarterScheme { Count = barterItemCount, Template = randomItem.Tpl }];
}
@@ -152,7 +152,7 @@ public class GiveSptCommand(
localizedGlobal = GetGlobalsLocale(locale);
var allAllowedItemNames = _itemHelper
.GetItems()
.GetItemsClone()
.Where(IsItemAllowed)
.Select(i =>
localizedGlobal
@@ -207,7 +207,7 @@ public class GiveSptCommand(
// item is just the tplId.
MongoId tplId = isItemName
? _itemHelper
.GetItems()
.GetItemsClone()
.Where(IsItemAllowed)
.FirstOrDefault(i =>
(localizedGlobal[$"{i?.Id} Name"]?.ToLowerInvariant() ?? i.Properties.Name)
@@ -47,7 +47,7 @@ public class DialogueHelper(ISptLogger<DialogueHelper> logger, ProfileHelper pro
/// <param name="sessionID">Session/player id</param>
/// <param name="itemId">Item being moved to inventory</param>
/// <returns>Collection of items from message</returns>
public List<Item> GetMessageItemContents(string messageID, MongoId sessionID, MongoId itemId)
public List<Item> GetMessageItemContents(MongoId messageID, MongoId sessionID, MongoId itemId)
{
var fullProfile = profileHelper.GetFullProfile(sessionID);
var dialogueData = fullProfile.DialogueRecords;
@@ -1013,7 +1013,7 @@ public class InventoryHelper(
{
// Split requests don't use 'use' but 'splitItem' property
fromInventoryItems = dialogueHelper.GetMessageItemContents(
request.FromOwner.Id,
request.FromOwner.Id.Value,
sessionId,
itemId
);
@@ -121,9 +121,7 @@ public class ItemHelper(
);
// Check if any item in the filtered pool matches the provided item
return filteredPool.Any(poolItem =>
string.Equals(poolItem.Template, itemTpl, StringComparison.OrdinalIgnoreCase)
);
return filteredPool.Any(poolItem => poolItem.Template == itemTpl);
}
/// <summary>
@@ -283,7 +281,7 @@ public class ItemHelper(
/// <param name="tpl">Template id to check</param>
/// <param name="invalidBaseTypes">OPTIONAL - Base types deemed invalid</param>
/// <returns>true for items that may be in player possession and not quest items</returns>
public bool IsValidItem(MongoId tpl, ICollection<MongoId>? invalidBaseTypes = null)
public bool IsValidItem(MongoId tpl, ISet<MongoId>? invalidBaseTypes = null)
{
var baseTypes = invalidBaseTypes ?? _defaultInvalidBaseTypes;
var itemDetails = GetItem(tpl);
@@ -295,9 +293,9 @@ public class ItemHelper(
return !(itemDetails.Value.Properties.QuestItem ?? false)
&& string.Equals(itemDetails.Value.Type, "Item", StringComparison.OrdinalIgnoreCase)
&& baseTypes.All(x => !IsOfBaseclass(tpl, x))
&& GetItemPrice(tpl) > 0
&& !itemFilterService.IsItemBlacklisted(tpl);
&& !itemFilterService.IsItemBlacklisted(tpl)
&& baseTypes.All(x => !IsOfBaseclass(tpl, x));
}
/// <summary>
@@ -502,7 +500,7 @@ public class ItemHelper(
/// Get cloned copy of all item data from items.json
/// </summary>
/// <returns>List of TemplateItem objects</returns>
public List<TemplateItem> GetItems()
public List<TemplateItem> GetItemsClone()
{
return cloner.Clone(databaseService.GetItems().Values.ToList());
}
@@ -724,14 +722,8 @@ public class ItemHelper(
{
// Parent matches desired item + all items in list do not match
if (
string.Equals(
itemFromAssort.ParentId,
itemIdToFind,
StringComparison.OrdinalIgnoreCase
)
&& list.All(item =>
!string.Equals(itemFromAssort.Id, item.Id, StringComparison.Ordinal)
)
itemFromAssort.ParentId == itemIdToFind
&& list.All(item => itemFromAssort.Id != item.Id)
)
{
list.Add(itemFromAssort);
@@ -937,7 +929,7 @@ public class ItemHelper(
// Update all parentIds of items attached to base item to use new id
foreach (var item in itemWithChildren)
{
if (string.Equals(item.ParentId, oldId, StringComparison.OrdinalIgnoreCase))
if (item.ParentId == oldId)
{
item.ParentId = newId;
}
@@ -992,9 +984,7 @@ public class ItemHelper(
item.Id = newId;
// Find all children of item and update their parent ids to match
var childItems = inventory.Items.Where(x =>
string.Equals(x.ParentId, originalId, StringComparison.OrdinalIgnoreCase)
);
var childItems = inventory.Items.Where(x => x.ParentId == originalId);
foreach (var childItem in childItems)
{
childItem.ParentId = newId;
@@ -1072,9 +1062,7 @@ public class ItemHelper(
item.Id = newId;
// Find all children of item and update their parent ids to match
var childItems = originalItems.Where(x =>
string.Equals(x.ParentId, originalId, StringComparison.OrdinalIgnoreCase)
);
var childItems = originalItems.Where(x => x.ParentId == originalId);
foreach (var childItem in childItems)
{
childItem.ParentId = newId;
@@ -1482,14 +1482,7 @@ public class QuestHelper(
return true;
}
if (
condition.Target.IsItem
&& string.Equals(
condition.Target.Item,
completedQuestId,
StringComparison.InvariantCultureIgnoreCase
)
)
if (condition.Target.IsItem && condition.Target.Item == completedQuestId)
{
// Not a list, plain string
return true;
@@ -92,7 +92,7 @@ public class RagfairOfferHelper(
CheckAndLockOfferFromPlayerTieredFlea(
tieredFlea,
offer,
tieredFleaLimitTypes.Keys.ToList(),
tieredFleaLimitTypes.Keys.ToHashSet(),
pmcData.Info.Level.Value
);
}
@@ -112,7 +112,7 @@ public class RagfairOfferHelper(
protected void CheckAndLockOfferFromPlayerTieredFlea(
TieredFlea tieredFlea,
RagfairOffer offer,
List<MongoId> tieredFleaLimitTypes,
HashSet<MongoId> tieredFleaLimitTypes,
int playerLevel
)
{
@@ -199,7 +199,7 @@ public class RagfairOfferHelper(
CheckAndLockOfferFromPlayerTieredFlea(
tieredFlea,
offer,
tieredFleaLimitTypes.Keys.ToList(),
tieredFleaLimitTypes.Keys.ToHashSet(),
pmcData.Info.Level.Value
);
}
@@ -296,7 +296,7 @@ public class RagfairOfferHelper(
CheckAndLockOfferFromPlayerTieredFlea(
tieredFlea,
offer,
tieredFleaLimitTypes.Keys.ToList(),
tieredFleaLimitTypes.Keys.ToHashSet(),
pmcData.Info.Level.Value
);
@@ -74,7 +74,7 @@ public readonly struct MongoId : IEquatable<MongoId>
{
if (other is null)
{
return other == this;
return false;
}
return other.ToString().Equals(ToString(), StringComparison.InvariantCultureIgnoreCase);
@@ -142,7 +142,7 @@ public readonly struct MongoId : IEquatable<MongoId>
public bool IsEmpty()
{
if (_stringId == "000000000000000000000000" || string.IsNullOrEmpty(_stringId))
if (string.IsNullOrEmpty(_stringId) || _stringId == "000000000000000000000000")
{
return true;
}
@@ -138,11 +138,11 @@ public record ItemBuyData
// MongoId
[JsonPropertyName("category")]
public required List<MongoId> Category { get; set; }
public required HashSet<MongoId> Category { get; set; }
// MongoId
[JsonPropertyName("id_list")]
public required List<MongoId> IdList { get; set; }
public required HashSet<MongoId> IdList { get; set; }
}
public record ItemSellData
@@ -151,10 +151,10 @@ public record ItemSellData
public Dictionary<string, object>? ExtensionData { get; set; }
[JsonPropertyName("category")]
public required List<MongoId> Category { get; set; }
public required HashSet<MongoId> Category { get; set; }
[JsonPropertyName("id_list")]
public required List<MongoId> IdList { get; set; }
public required HashSet<MongoId> IdList { get; set; }
}
public record TraderInsurance
@@ -88,7 +88,7 @@ public record RagfairOffer
/// Tightly bound to offer.items[0].upd.stackObjectsCount
/// </summary>
[JsonPropertyName("quantity")]
public int? Quantity { get; set; }
public int Quantity { get; set; }
}
public record OfferRequirement
@@ -106,7 +106,7 @@ public record FenceConfig
/// Prevent duplicate offers of items of specific categories by parentId
/// </summary>
[JsonPropertyName("preventDuplicateOffersOfCategory")]
public required List<MongoId> PreventDuplicateOffersOfCategory { get; set; }
public required HashSet<MongoId> PreventDuplicateOffersOfCategory { get; set; }
[JsonPropertyName("regenerateAssortsOnRefresh")]
public bool RegenerateAssortsOnRefresh { get; set; }
@@ -242,8 +242,8 @@ public class AirdropService(
// Get all items that match the blacklisted types and fold into item blacklist
var itemTypeBlacklist = _itemFilterService.GetItemRewardBaseTypeBlacklist();
var itemsMatchingTypeBlacklist = _itemHelper
.GetItems()
.Where(templateItem => !string.IsNullOrEmpty(templateItem.Parent))
.GetItemsClone()
.Where(templateItem => !templateItem.Parent.IsEmpty())
.Where(templateItem =>
_itemHelper.IsOfBaseclasses(templateItem.Parent, itemTypeBlacklist)
)
@@ -901,7 +901,7 @@ public class CircleOfCultistService(
bool itemsShouldBeHighValue
)
{
var allItems = itemHelper.GetItems();
var allItems = itemHelper.GetItemsClone();
var currentItemCount = 0;
var attempts = 0;
// `currentItemCount` var will look for the correct number of items, `attempts` var will keep this from never stopping if the highValueThreshold is too high
@@ -814,7 +814,7 @@ public class FenceService(
var childItemsAndSingleRoot = baseFenceAssortClone
.Items.Where(item =>
!string.Equals(item.ParentId, "hideout", StringComparison.Ordinal)
|| string.Equals(item.Id, chosenBaseAssortRoot.Id, StringComparison.Ordinal)
|| item.Id == chosenBaseAssortRoot.Id
)
.ToList();
@@ -89,25 +89,28 @@ public class ItemBaseClassService(
return false;
}
if (_itemBaseClassesCache.TryGetValue(itemTpl, out var baseClassList))
var existsInCache = _itemBaseClassesCache.TryGetValue(itemTpl, out var baseClassList);
if (!existsInCache)
{
// Not found
if (logger.IsLogEnabled(LogLevel.Debug))
{
logger.Debug(
serverLocalisationService.GetText("baseclass-item_not_found", itemTpl)
);
}
// Not found in cache, Hydrate again - some mods add items late in server startup lifecycle
HydrateItemBaseClassCache();
existsInCache = _itemBaseClassesCache.TryGetValue(itemTpl, out baseClassList);
}
if (existsInCache)
{
return baseClassList.Overlaps(baseClasses);
}
if (logger.IsLogEnabled(LogLevel.Debug))
{
logger.Debug(serverLocalisationService.GetText("baseclass-item_not_found", itemTpl));
}
// Not found in cache, Hydrate again - some mods add items late
HydrateItemBaseClassCache();
// Check for item again, return false if item not found a second time
if (_itemBaseClassesCache.TryGetValue(itemTpl, out var value))
{
return value.Any(baseClasses.Contains);
}
logger.Warning(
serverLocalisationService.GetText("baseclass-item_not_found_failed", itemTpl)
);
@@ -146,8 +146,11 @@ public class RagfairOfferHolder(
var sellerIsTrader = _ragfairServerHelper.IsTrader(sellerId);
var itemSoldTemplate = _itemHelper.GetItem(itemTpl);
if (
!string.IsNullOrEmpty(itemTpl)
&& !(sellerIsTrader || _profileHelper.IsPlayer(sellerId))
!itemTpl.IsEmpty()
&& !(
sellerIsTrader
|| (bool)offer.ExtensionData.GetValueOrDefault("isPlayerOffer", false)
)
&& _offersByTemplate.TryGetValue(itemTpl, out var offers)
&& offers?.Count
>= _ragfairServerHelper.GetOfferCountByBaseType(itemSoldTemplate.Value.Parent)