diff --git a/Libraries/SPTarkov.Server.Core/Generators/LootGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/LootGenerator.cs
index 49298738..58afe175 100644
--- a/Libraries/SPTarkov.Server.Core/Generators/LootGenerator.cs
+++ b/Libraries/SPTarkov.Server.Core/Generators/LootGenerator.cs
@@ -36,9 +36,10 @@ public class LootGenerator(
///
/// parameters to adjust how loot is generated
/// An array of loot items
- public List> CreateRandomLoot(LootRequest options)
+ public IEnumerable> CreateRandomLoot(LootRequest options)
{
var result = new List>();
+
var itemTypeCounts = InitItemLimitCounter(options.ItemLimits);
// Handle sealed weapon containers
@@ -81,7 +82,7 @@ public class LootGenerator(
);
// Pool has items we could add as loot, proceed
- if (rewardPoolResults.ItemPool.Count > 0)
+ if (rewardPoolResults.ItemPool.Any())
{
var randomisedItemCount = randomUtil.GetInt(
options.ItemCount.Min,
@@ -113,11 +114,9 @@ public class LootGenerator(
);
if (randomisedWeaponPresetCount > 0)
{
- var weaponDefaultPresets = globalDefaultPresets
- .Where(preset =>
- itemHelper.IsOfBaseclass(preset.Encyclopedia.Value, BaseClasses.WEAPON)
- )
- .ToList();
+ var weaponDefaultPresets = globalDefaultPresets.Where(preset =>
+ itemHelper.IsOfBaseclass(preset.Encyclopedia.Value, BaseClasses.WEAPON)
+ );
if (weaponDefaultPresets.Any())
{
@@ -149,9 +148,9 @@ public class LootGenerator(
var armorDefaultPresets = globalDefaultPresets.Where(preset =>
itemHelper.ArmorItemCanHoldMods(preset.Encyclopedia.Value)
);
- var levelFilteredArmorPresets = armorDefaultPresets
- .Where(armor => IsArmorOfDesiredProtectionLevel(armor, options))
- .ToList();
+ var levelFilteredArmorPresets = armorDefaultPresets.Where(armor =>
+ IsArmorOfDesiredProtectionLevel(armor, options)
+ );
// Add some armors to rewards
if (levelFilteredArmorPresets.Any())
@@ -245,7 +244,7 @@ public class LootGenerator(
/// results of filtering + blacklist used
protected ItemRewardPoolResults GetItemRewardPool(
HashSet itemTplBlacklist,
- List itemTypeWhitelist,
+ HashSet itemTypeWhitelist,
bool useRewardItemBlacklist,
bool allowBossItems,
bool blockSeasonalItemsOutOfSeason
@@ -281,14 +280,12 @@ public class LootGenerator(
itemBlacklist.UnionWith(seasonalEventService.GetInactiveSeasonalEventItems());
}
- var items = itemsDb
- .Where(item =>
- !itemBlacklist.Contains(item.Id)
- && string.Equals(item.Type, "item", StringComparison.OrdinalIgnoreCase)
- && !item.Properties.QuestItem.GetValueOrDefault(false)
- && itemTypeWhitelist.Contains(item.Parent)
- )
- .ToList();
+ var items = itemsDb.Where(item =>
+ !itemBlacklist.Contains(item.Id)
+ && string.Equals(item.Type, "item", StringComparison.OrdinalIgnoreCase)
+ && !item.Properties.QuestItem.GetValueOrDefault(false)
+ && itemTypeWhitelist.Contains(item.Parent)
+ );
return new ItemRewardPoolResults { ItemPool = items, Blacklist = itemBlacklist };
}
@@ -348,7 +345,7 @@ public class LootGenerator(
/// array to add found item to
/// true if item was valid and added to pool
protected bool FindAndAddRandomItemToLoot(
- List items,
+ IEnumerable items,
Dictionary itemTypeCounts,
LootRequest options,
List> result
@@ -426,13 +423,13 @@ public class LootGenerator(
/// List to add chosen preset to
/// true if preset was valid and added to pool
protected bool FindAndAddRandomPresetToLoot(
- List presetPool,
+ IEnumerable presetPool,
Dictionary itemTypeCounts,
HashSet itemBlacklist,
List> result
)
{
- if (presetPool.Count == 0)
+ if (!presetPool.Any())
{
logger.Warning(serverLocalisationService.GetText("loot-preset_pool_is_empty"));
@@ -732,10 +729,10 @@ public class LootGenerator(
// Find a random item of the desired type and add as reward
for (var index = 0; index < rewardCount; index++)
{
- var chosenItem = randomUtil.DrawRandomFromList(relatedItems.ToList());
+ var chosenItem = randomUtil.GetArrayValue(relatedItems);
var reward = new List-
{
- new() { Id = new MongoId(), Template = chosenItem[0].Id },
+ new() { Id = new MongoId(), Template = chosenItem.Id },
};
modRewards.Add(reward);
@@ -785,7 +782,7 @@ public class LootGenerator(
///
///
/// Single tpl
- protected string PickRewardItem(RewardDetails rewardContainerDetails)
+ protected MongoId PickRewardItem(RewardDetails rewardContainerDetails)
{
if (
rewardContainerDetails.RewardTplPool is not null
@@ -803,7 +800,7 @@ public class LootGenerator(
protected record ItemRewardPoolResults
{
- public List ItemPool { get; set; }
+ public IEnumerable ItemPool { get; set; }
public HashSet Blacklist { get; set; }
}
diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Location/GetAirdropLootResponse.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Location/GetAirdropLootResponse.cs
index 89607980..d03bf129 100644
--- a/Libraries/SPTarkov.Server.Core/Models/Eft/Location/GetAirdropLootResponse.cs
+++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Location/GetAirdropLootResponse.cs
@@ -13,8 +13,8 @@ public record GetAirdropLootResponse
/// The type of airdrop
///
[JsonPropertyName("icon")]
- public AirdropTypeEnum? Icon { get; set; }
+ public AirdropTypeEnum Icon { get; set; }
[JsonPropertyName("container")]
- public List
- ? Container { get; set; }
+ public IEnumerable
- Container { get; set; }
}
diff --git a/Libraries/SPTarkov.Server.Core/Models/Spt/Config/AirdropConfig.cs b/Libraries/SPTarkov.Server.Core/Models/Spt/Config/AirdropConfig.cs
index 38e4ce2f..683b3c39 100644
--- a/Libraries/SPTarkov.Server.Core/Models/Spt/Config/AirdropConfig.cs
+++ b/Libraries/SPTarkov.Server.Core/Models/Spt/Config/AirdropConfig.cs
@@ -68,7 +68,7 @@ public record AirdropLoot
/// Item type (parentId) to allow inside crate
///
[JsonPropertyName("itemTypeWhitelist")]
- public required List ItemTypeWhitelist { get; set; }
+ public required HashSet ItemTypeWhitelist { get; set; }
///
/// Item type/ item tpls to limit count of inside crate - key: item base type: value: max count
diff --git a/Libraries/SPTarkov.Server.Core/Models/Spt/Config/InventoryConfig.cs b/Libraries/SPTarkov.Server.Core/Models/Spt/Config/InventoryConfig.cs
index 61e967ed..f52014a9 100644
--- a/Libraries/SPTarkov.Server.Core/Models/Spt/Config/InventoryConfig.cs
+++ b/Libraries/SPTarkov.Server.Core/Models/Spt/Config/InventoryConfig.cs
@@ -51,7 +51,7 @@ public record RewardDetails
public Dictionary? RewardTplPool { get; set; }
[JsonPropertyName("rewardTypePool")]
- public List? RewardTypePool { get; set; }
+ public HashSet? RewardTypePool { get; set; }
}
public record SealedAirdropContainerSettings
diff --git a/Libraries/SPTarkov.Server.Core/Models/Spt/Services/LootRequest.cs b/Libraries/SPTarkov.Server.Core/Models/Spt/Services/LootRequest.cs
index 20f3e892..e5864c65 100644
--- a/Libraries/SPTarkov.Server.Core/Models/Spt/Services/LootRequest.cs
+++ b/Libraries/SPTarkov.Server.Core/Models/Spt/Services/LootRequest.cs
@@ -43,7 +43,7 @@ public record LootRequest
/// Item tpl whitelist to pick from
///
[JsonPropertyName("itemTypeWhitelist")]
- public List? ItemTypeWhitelist { get; set; }
+ public HashSet? ItemTypeWhitelist { get; set; }
///
/// key: item base type: value: max count
diff --git a/Libraries/SPTarkov.Server.Core/Services/AirdropService.cs b/Libraries/SPTarkov.Server.Core/Services/AirdropService.cs
index fcdbf5e0..3ab1c736 100644
--- a/Libraries/SPTarkov.Server.Core/Services/AirdropService.cs
+++ b/Libraries/SPTarkov.Server.Core/Services/AirdropService.cs
@@ -16,8 +16,8 @@ namespace SPTarkov.Server.Core.Services;
[Injectable]
public class AirdropService(
- ConfigServer configServer,
ISptLogger _logger,
+ ConfigServer configServer,
LootGenerator _lootGenerator,
DatabaseService databaseService,
WeightedRandomHelper _weightedRandomHelper,
@@ -80,14 +80,12 @@ public class AirdropService(
// Filter loot pool to just items that fit crate
var crateLoot = GetLootThatFitsContainer(airdropCrateItem, crateLootPool);
- // Flatten loot into single array ready to be returned
- var flattenedCrateLoot = crateLoot.SelectMany(x => x).ToList();
+ // Create new array with crate at front + loot behind
+ var containerWithLoot = Enumerable.Empty
- ().Append(airdropCrateItem);
+ containerWithLoot = containerWithLoot.Union(crateLoot.SelectMany(x => x));
- // Add crate to front of loot rewards
- flattenedCrateLoot.Insert(0, airdropCrateItem);
-
- // Re-parent loot items to crate we just added
- foreach (var item in flattenedCrateLoot)
+ // Re-parent root loot items to have crate as parent
+ foreach (var item in containerWithLoot)
{
if (item.Id == airdropCrateItem.Id)
// Crate itself, skip
@@ -105,8 +103,8 @@ public class AirdropService(
return new GetAirdropLootResponse
{
- Icon = airdropConfig.Icon,
- Container = flattenedCrateLoot,
+ Icon = airdropConfig.Icon.Value,
+ Container = containerWithLoot,
};
}
@@ -116,9 +114,9 @@ public class AirdropService(
/// Crate item to fit items into
/// Item pool to try and fit into container
/// Items that will fit container
- protected List
> GetLootThatFitsContainer(
+ protected IEnumerable> GetLootThatFitsContainer(
Item container,
- List> crateLootPool
+ IEnumerable> crateLootPool
)
{
// list of root item + children in list
diff --git a/Libraries/SPTarkov.Server.Core/Services/LocationLifecycleService.cs b/Libraries/SPTarkov.Server.Core/Services/LocationLifecycleService.cs
index 44fc663a..cf0d9c5f 100644
--- a/Libraries/SPTarkov.Server.Core/Services/LocationLifecycleService.cs
+++ b/Libraries/SPTarkov.Server.Core/Services/LocationLifecycleService.cs
@@ -447,7 +447,7 @@ public class LocationLifecycleService(
}
// Flatten
- List- mailableLoot = [.. loot.SelectMany(x => x)];
+ IEnumerable
- mailableLoot = [.. loot.SelectMany(x => x)];
// Send message from fence giving player reward generated above
mailSendService.SendLocalisedNpcMessageToPlayer(