Convert TemplateItem to MongoId (#436)

* Convert TemplateItem to MongoId

* Push new extensions

* Handle null mongoid's being passed to regex

* Handle null strings, fixes item events

* Updated loot generation to work with new property `composedKey`

Fixed typo in `SlotId`

* Fix missing method after merge

* Remove duplicately named MongoIDExtensions?

* Fixed location loot generation to handle impending loot json changes

* Updated location JSONs with new properties (excluding lighthouse loose loot)

* Fixed build issue with ItemTplGenerator

* use correct handing for new mongo ids

* Added helper method to improve readability

---------

Co-authored-by: Chomp <dev@dev.sp-tarkov.com>
This commit is contained in:
Jesse
2025-07-02 11:14:04 +02:00
committed by GitHub
parent 46989aa19e
commit 54f0d0779c
89 changed files with 529 additions and 413 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,6 +1,7 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Inventory;
@@ -300,7 +301,7 @@ public class InventoryController(
/// <param name="itemTpls">Inspected item tpls</param>
/// <param name="fullProfile">Profile to add xp to</param>
protected void FlagItemsAsInspectedAndRewardXp(
IEnumerable<string> itemTpls,
IEnumerable<MongoId> itemTpls,
SptProfile fullProfile
)
{
@@ -1,4 +1,5 @@
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
namespace SPTarkov.Server.Core.Extensions
@@ -320,5 +321,26 @@ namespace SPTarkov.Server.Core.Extensions
return result.Values.ToList();
}
/// <summary>
/// Convert an Item to SptLootItem
/// </summary>
/// <param name="item">Item to convert</param>
/// <returns>Converted SptLootItem</returns>
public static SptLootItem ToLootItem(this Item item)
{
return new SptLootItem
{
ComposedKey = null,
Id = item.Id,
Template = item.Template,
Upd = item.Upd,
ParentId = item.ParentId,
SlotId = item.SlotId,
Location = item.Location,
Desc = item.Desc,
ExtensionData = item.ExtensionData,
};
}
}
}
@@ -2,8 +2,14 @@
namespace SPTarkov.Server.Core.Extensions
{
public static class MongoIDExtensions
public static class MongoIdExtensions
{
//Temporary, but necessary
public static IEnumerable<MongoId> ToMongoIds(this IEnumerable<string> source)
{
return source.Select(s => (MongoId)s);
}
/// <summary>
/// Determines whether the specified <see cref="MongoId"/> is a valid 24-character hexadecimal string,
/// which is the standard format for MongoDB ObjectIds.
@@ -1,21 +1,22 @@
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
namespace SPTarkov.Server.Core.Extensions
{
public static class TemplateItemExtensions
{
public static IEnumerable<TemplateItem> OfClass(
this Dictionary<string, TemplateItem> templates,
params string[] baseClasses
this Dictionary<MongoId, TemplateItem> templates,
params MongoId[] baseClasses
)
{
return templates.Where(x => baseClasses.Contains(x.Value.Parent)).Select(x => x.Value);
}
public static IEnumerable<TemplateItem> OfClass(
this Dictionary<string, TemplateItem> templates,
this Dictionary<MongoId, TemplateItem> templates,
Func<TemplateItem, bool> pred,
params string[] baseClasses
params MongoId[] baseClasses
)
{
return templates
@@ -301,7 +301,7 @@ public class BotEquipmentModGenerator(
public FilterPlateModsForSlotByLevelResult FilterPlateModsForSlotByLevel(
GenerateEquipmentProperties settings,
string modSlot,
HashSet<string> existingPlateTplPool,
HashSet<MongoId> existingPlateTplPool,
TemplateItem armorItem
)
{
@@ -1282,9 +1282,9 @@ public class BotEquipmentModGenerator(
/// <param name="modSpawnRequest">Request data</param>
/// <param name="modPool">Pool of magazine tpls to filter</param>
/// <returns>Filtered pool of magazine tpls</returns>
public IEnumerable<string> GetFilteredMagazinePoolByCapacity(
public IEnumerable<MongoId> GetFilteredMagazinePoolByCapacity(
ModToSpawnRequest modSpawnRequest,
HashSet<string> modPool
HashSet<MongoId> modPool
)
{
var weaponTpl = modSpawnRequest.Weapon.FirstOrDefault().Template;
@@ -1325,7 +1325,7 @@ public class BotEquipmentModGenerator(
/// <returns>Chosen weapon details</returns>
public ChooseRandomCompatibleModResult GetCompatibleWeaponModTplForSlotFromPool(
ModToSpawnRequest request,
HashSet<string> modPool,
HashSet<MongoId> modPool,
Slot parentSlot,
ModSpawn? choiceTypeEnum,
List<Item> weapon,
@@ -1369,7 +1369,7 @@ public class BotEquipmentModGenerator(
/// <param name="weapon">Weapon mods at current time</param>
/// <returns>IChooseRandomCompatibleModResult</returns>
public ChooseRandomCompatibleModResult GetCompatibleModFromPool(
HashSet<string> modPool,
HashSet<MongoId> modPool,
ModSpawn? modSpawnType,
List<Item> weapon
)
@@ -1469,7 +1469,10 @@ public class BotEquipmentModGenerator(
/// <param name="modPool"></param>
/// <param name="tplBlacklist">Tpls that are incompatible and should not be used</param>
/// <returns>string array of compatible mod tpls with weapon</returns>
public HashSet<string> GetFilteredModPool(HashSet<string> modPool, HashSet<string> tplBlacklist)
public HashSet<MongoId> GetFilteredModPool(
HashSet<MongoId> modPool,
HashSet<MongoId> tplBlacklist
)
{
return modPool.Where(tpl => !tplBlacklist.Contains(tpl)).ToHashSet();
}
@@ -1483,7 +1486,7 @@ public class BotEquipmentModGenerator(
/// <param name="request"></param>
/// <param name="weaponTemplate">Mods root parent (weapon/equipment)</param>
/// <returns>Array of mod tpls</returns>
public HashSet<string>? GetModPoolForSlot(
public HashSet<MongoId>? GetModPoolForSlot(
ModToSpawnRequest request,
TemplateItem weaponTemplate
)
@@ -1518,7 +1521,7 @@ public class BotEquipmentModGenerator(
/// <param name="request"></param>
/// <param name="weaponTemplate"></param>
/// <returns>Hashset of mods keyed by slot</returns>
public HashSet<string> GetModPoolForDefaultSlot(
public HashSet<MongoId> GetModPoolForDefaultSlot(
ModToSpawnRequest request,
TemplateItem weaponTemplate
)
@@ -1821,7 +1824,7 @@ public class BotEquipmentModGenerator(
public void AddCompatibleModsForProvidedMod(
string desiredSlotName,
TemplateItem modTemplate,
IDictionary<string, Dictionary<string, HashSet<string>>> modPool,
IDictionary<string, Dictionary<string, HashSet<MongoId>>> modPool,
EquipmentFilterDetails botEquipBlacklist
)
{
@@ -1853,7 +1856,7 @@ public class BotEquipmentModGenerator(
);
}
modPool.TryAdd(modTemplate.Id, new Dictionary<string, HashSet<string>>());
modPool.TryAdd(modTemplate.Id, new Dictionary<string, HashSet<MongoId>>());
modPool[modTemplate.Id][desiredSlotObject.Name] = supportedSubModsSet;
}
@@ -1865,7 +1868,7 @@ public class BotEquipmentModGenerator(
/// <param name="modSlot">Slot item should fit in</param>
/// <param name="botEquipBlacklist">Equipment that should not be picked</param>
/// <returns>Array of compatible items for that slot</returns>
public HashSet<string> GetDynamicModPool(
public HashSet<MongoId> GetDynamicModPool(
string parentItemId,
string modSlot,
EquipmentFilterDetails botEquipBlacklist
@@ -1905,8 +1908,8 @@ public class BotEquipmentModGenerator(
/// <param name="botEquipBlacklist">Equipment blacklist details for bot level range</param>
/// <param name="modSlot">Mod slot mods belong to</param>
/// <returns>New set of tpls not in blacklist(s)</returns>
public HashSet<string> FilterModsByBlacklist(
HashSet<string> modTplPool,
public HashSet<MongoId> FilterModsByBlacklist(
HashSet<MongoId> modTplPool,
EquipmentFilterDetails? botEquipBlacklist,
string modSlot
)
@@ -1947,7 +1950,7 @@ public class BotEquipmentModGenerator(
/// <param name="cylinderMagTemplate">The CylinderMagazine's template</param>
public void FillCamora(
List<Item> items,
Dictionary<string, Dictionary<string, HashSet<string>>> modPool,
Dictionary<string, Dictionary<string, HashSet<MongoId>>> modPool,
string cylinderMagParentId,
TemplateItem cylinderMagTemplate
)
@@ -1965,7 +1968,7 @@ public class BotEquipmentModGenerator(
);
// Attempt to generate camora slots for item
modPool[cylinderMagTemplate.Id] = new Dictionary<string, HashSet<string>>();
modPool[cylinderMagTemplate.Id] = new Dictionary<string, HashSet<MongoId>>();
foreach (var camora in camoraSlots)
{
modPool[cylinderMagTemplate.Id][camora.Name] = camora.Props.Filters?[
@@ -1976,7 +1979,7 @@ public class BotEquipmentModGenerator(
itemModPool = modPool[cylinderMagTemplate.Id];
}
ExhaustableArray<string>? exhaustableModPool = null;
ExhaustableArray<MongoId>? exhaustableModPool = null;
var modSlot = "cartridges";
const string camoraFirstSlot = "camora_000";
if (itemModPool.TryGetValue(modSlot, out var value))
@@ -2046,7 +2049,7 @@ public class BotEquipmentModGenerator(
/// </summary>
/// <param name="camorasWithShells">Dictionary of camoras we want to merge into one array</param>
/// <returns>String array of shells for multiple camora sources</returns>
public HashSet<string> MergeCamoraPools(Dictionary<string, HashSet<string>> camorasWithShells)
public HashSet<MongoId> MergeCamoraPools(Dictionary<string, HashSet<MongoId>> camorasWithShells)
{
return camorasWithShells.SelectMany(shellKvP => shellKvP.Value).Distinct().ToHashSet();
}
@@ -2060,9 +2063,9 @@ public class BotEquipmentModGenerator(
/// <param name="scopes">Full scope pool</param>
/// <param name="botWeaponSightWhitelist">Whitelist of scope types by weapon base type</param>
/// <returns>Array of scope tpls that have been filtered to just ones allowed for that weapon type</returns>
public HashSet<string> FilterSightsByWeaponType(
public HashSet<MongoId> FilterSightsByWeaponType(
Item weapon,
HashSet<string> scopes,
HashSet<MongoId> scopes,
Dictionary<string, List<string>> botWeaponSightWhitelist
)
{
@@ -2087,7 +2090,7 @@ public class BotEquipmentModGenerator(
}
// Filter items that are not directly scopes OR mounts that do not hold the type of scope we allow for this weapon type
HashSet<string> filteredScopesAndMods = [];
HashSet<MongoId> filteredScopesAndMods = [];
foreach (var item in scopes)
{
// Mods is a scope, check base class is allowed
@@ -1,6 +1,7 @@
using System.Collections.Frozen;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Match;
using SPTarkov.Server.Core.Models.Enums;
@@ -645,9 +646,9 @@ public class BotInventoryGenerator(
/// <param name="itemTpl">Item mod pool is being retrieved and filtered</param>
/// <param name="equipmentBlacklist">Blacklist to filter mod pool with</param>
/// <returns>Filtered pool of mods</returns>
public Dictionary<string, HashSet<string>> GetFilteredDynamicModsForItem(
public Dictionary<string, HashSet<MongoId>> GetFilteredDynamicModsForItem(
string itemTpl,
Dictionary<string, HashSet<string>> equipmentBlacklist
Dictionary<string, HashSet<MongoId>> equipmentBlacklist
)
{
var modPool = _botEquipmentModPoolService.GetModsForGearSlot(itemTpl);
@@ -2,6 +2,7 @@ using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Generators.WeaponGen;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
@@ -753,7 +754,9 @@ public class BotWeaponGenerator(
/// </summary>
/// <param name="weaponTemplate">Weapon db template to get cartridges for</param>
/// <returns>List of cartridge tpls</returns>
protected HashSet<string> GetCompatibleCartridgesFromWeaponTemplate(TemplateItem weaponTemplate)
protected HashSet<MongoId> GetCompatibleCartridgesFromWeaponTemplate(
TemplateItem weaponTemplate
)
{
ArgumentNullException.ThrowIfNull(weaponTemplate);
@@ -775,7 +778,7 @@ public class BotWeaponGenerator(
/// <param name="weaponTemplate">Weapon db template to get magazine cartridges for</param>
/// <returns>Hashset of cartridge tpls</returns>
/// <exception cref="ArgumentNullException">Thrown when weaponTemplate is null.</exception>
protected HashSet<string> GetCompatibleCartridgesFromMagazineTemplate(
protected HashSet<MongoId> GetCompatibleCartridgesFromMagazineTemplate(
TemplateItem weaponTemplate
)
{
@@ -21,7 +21,6 @@ namespace SPTarkov.Server.Core.Generators;
public class LocationLootGenerator(
ISptLogger<LocationLootGenerator> _logger,
RandomUtil _randomUtil,
MathUtil _mathUtil,
HashUtil _hashUtil,
ItemHelper _itemHelper,
DatabaseService _databaseService,
@@ -198,15 +197,12 @@ public class LocationLootGenerator(
}
// Randomisation is turned off for location / globally
if (
!_locationConfig.ContainerRandomisationSettings.Enabled
|| !_locationConfig.ContainerRandomisationSettings.Maps.ContainsKey(locationId)
)
if (!LocationRandomisationEnabled(locationId))
{
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
$"Container randomisation disabled, Adding {staticRandomisableContainersOnMap.Count} containers to: {locationId}"
$"Container randomisation disabled, Adding: {staticRandomisableContainersOnMap.Count} containers to: {locationId}"
);
}
@@ -339,6 +335,12 @@ public class LocationLootGenerator(
return result;
}
protected bool LocationRandomisationEnabled(string locationId)
{
return _locationConfig.ContainerRandomisationSettings.Enabled
&& _locationConfig.ContainerRandomisationSettings.Maps.ContainsKey(locationId);
}
/// <summary>
/// Get containers with a non-100% chance to spawn OR are NOT on the container type randomistion blacklist
/// </summary>
@@ -639,7 +641,9 @@ public class LocationLootGenerator(
};
// Add loot to container before returning
containerClone.Template.Items.AddRange(items);
containerClone.Template.Items.AddRange(
items.Select(item => item.ToLootItem()).ToList() // Convert into correct output type first
);
}
return containerClone;
@@ -975,10 +979,21 @@ public class LocationLootGenerator(
continue;
}
// Draw a random item from spawn points possible items
// Draw a random item from the spawn points possible items
var chosenComposedKey = itemArray.Draw().FirstOrDefault();
var chosenItem = spawnPoint.Template.Items.FirstOrDefault(item =>
item.ComposedKey == chosenComposedKey
);
if (chosenItem is null)
{
_logger.Warning(
$"Unable to find item with composed key: {chosenComposedKey}, skipping spawn point: {spawnPoint.LocationId} "
);
continue;
}
var createItemResult = CreateDynamicLootItem(
chosenComposedKey,
chosenItem,
spawnPoint.Template.Items,
staticAmmoDist
);
@@ -996,8 +1011,11 @@ public class LocationLootGenerator(
// Root id can change when generating a weapon, ensure ids match
spawnPoint.Template.Root = createItemResult.Items.FirstOrDefault().Id;
// Convert the processed items into the correct output type
var convertedItems = createItemResult.Items.Select(item => item.ToLootItem()).ToList();
// Overwrite entire pool with chosen item
spawnPoint.Template.Items = createItemResult.Items;
spawnPoint.Template.Items = convertedItems;
loot.Add(spawnPoint.Template);
}
@@ -1039,15 +1057,22 @@ public class LocationLootGenerator(
continue;
}
var chosenItem = forcedLootLocation.Template.Items.FirstOrDefault(item =>
item.Id == rootItem.Id
);
var createItemResult = CreateDynamicLootItem(
rootItem.Id,
chosenItem,
forcedLootLocation.Template.Items,
staticAmmoDist
);
// Update root ID with the above dynamically generated ID
forcedLootLocation.Template.Root = createItemResult.Items.FirstOrDefault().Id;
forcedLootLocation.Template.Items = createItemResult.Items;
// Convert the processed items into the correct output type
var convertedItems = createItemResult.Items.Select(item => item.ToLootItem()).ToList();
forcedLootLocation.Template.Items = convertedItems;
// Push forced location into array as long as it doesn't exist already
var existingLocation = result.Any(spawnPoint =>
@@ -1074,28 +1099,20 @@ public class LocationLootGenerator(
/// <summary>
/// Create array of item (with child items) and return
/// </summary>
/// <param name="chosenComposedKey"> Key we want to look up items for </param>
/// <param name="items"> Location loot Template </param>
/// <param name="chosenItem"> Item we want to spawn in the position </param>
/// <param name="lootItems"> Location loot Template </param>
/// <param name="staticAmmoDist"> Ammo distributions </param>
/// <returns> ContainerItem object </returns>
protected ContainerItem CreateDynamicLootItem(
string? chosenComposedKey,
List<Item> items,
SptLootItem chosenItem,
List<SptLootItem> lootItems,
Dictionary<string, List<StaticAmmoDetails>> staticAmmoDist
)
{
var chosenItem = items.FirstOrDefault(item => item.Id == chosenComposedKey);
MongoId chosenTpl = chosenItem?.Template ?? MongoId.Empty();
var chosenTpl = chosenItem.Template;
if (chosenTpl == null)
{
throw new Exception(
$"Item for tpl {chosenComposedKey} was not found in the spawn point"
);
}
var itemTemplate = _itemHelper.GetItem(chosenTpl).Value;
if (itemTemplate is null)
var itemDbTemplate = _itemHelper.GetItem(chosenTpl).Value;
if (itemDbTemplate is null)
{
_logger.Error($"Item tpl: {chosenTpl} cannot be found in database");
}
@@ -1107,11 +1124,11 @@ public class LocationLootGenerator(
if (_itemHelper.IsOfBaseclasses(chosenTpl, [BaseClasses.MONEY, BaseClasses.AMMO]))
{
var stackCount =
itemTemplate.Properties.StackMaxSize == 1
itemDbTemplate.Properties.StackMaxSize == 1
? 1
: _randomUtil.GetInt(
itemTemplate.Properties.StackMinRandom.Value,
itemTemplate.Properties.StackMaxRandom.Value
itemDbTemplate.Properties.StackMinRandom.Value,
itemDbTemplate.Properties.StackMaxRandom.Value
);
itemWithMods.Add(
@@ -1126,21 +1143,21 @@ public class LocationLootGenerator(
else if (_itemHelper.IsOfBaseclass(chosenTpl, BaseClasses.AMMO_BOX))
{
// Fill with cartridges
List<Item> ammoBoxItem = [new() { Id = _hashUtil.Generate(), Template = chosenTpl }];
_itemHelper.AddCartridgesToAmmoBox(ammoBoxItem, itemTemplate);
List<Item> ammoBoxItem = [new() { Id = new MongoId(), Template = chosenTpl }];
_itemHelper.AddCartridgesToAmmoBox(ammoBoxItem, itemDbTemplate);
itemWithMods.AddRange(ammoBoxItem);
}
else if (_itemHelper.IsOfBaseclass(chosenTpl, BaseClasses.MAGAZINE))
{
// Create array with just magazine
List<Item> magazineItem = [new() { Id = _hashUtil.Generate(), Template = chosenTpl }];
List<Item> magazineItem = [new() { Id = new MongoId(), Template = chosenTpl }];
if (_randomUtil.GetChance100(_locationConfig.StaticMagazineLootHasAmmoChancePercent))
// Add randomised amount of cartridges
{
_itemHelper.FillMagazineWithRandomCartridge(
magazineItem,
itemTemplate, // Magazine template
itemDbTemplate, // Magazine template
staticAmmoDist,
null,
_locationConfig.MinFillLooseMagazinePercent / 100d
@@ -1153,7 +1170,7 @@ public class LocationLootGenerator(
{
// Also used by armors to get child mods
// Get item + children and add into array we return
var itemWithChildren = items.FindAndReturnChildrenAsItems(chosenItem.Id);
var itemWithChildren = lootItems.FindAndReturnChildrenAsItems(chosenItem.Id);
// Ensure all IDs are unique
itemWithChildren = _itemHelper.ReplaceIDs(_cloner.Clone(itemWithChildren));
@@ -1195,7 +1212,7 @@ public class LocationLootGenerator(
var width = itemTemplate.Properties.Width;
var height = itemTemplate.Properties.Height;
List<Item> items = [new() { Id = _hashUtil.Generate(), Template = chosenTpl }];
List<Item> items = [new() { Id = new MongoId(), Template = chosenTpl }];
var rootItem = items.FirstOrDefault();
// Use passed in parentId as override for new item
@@ -241,15 +241,15 @@ public class LootGenerator(
/// <param name="blockSeasonalItemsOutOfSeason">Prevent seasonal items appearing outside their defined season</param>
/// <returns>results of filtering + blacklist used</returns>
protected ItemRewardPoolResults GetItemRewardPool(
HashSet<string> itemTplBlacklist,
List<string> itemTypeWhitelist,
HashSet<MongoId> itemTplBlacklist,
List<MongoId> itemTypeWhitelist,
bool useRewardItemBlacklist,
bool allowBossItems,
bool blockSeasonalItemsOutOfSeason
)
{
var itemsDb = _databaseService.GetItems().Values;
var itemBlacklist = new HashSet<string>();
var itemBlacklist = new HashSet<MongoId>();
itemBlacklist.UnionWith([.. _itemFilterService.GetBlacklistedItems(), .. itemTplBlacklist]);
if (useRewardItemBlacklist)
@@ -321,9 +321,9 @@ public class LootGenerator(
/// </summary>
/// <param name="limits">limits as defined in config</param>
/// <returns>record, key: item tplId, value: current/max item count allowed</returns>
protected Dictionary<string, ItemLimit> InitItemLimitCounter(Dictionary<string, int> limits)
protected Dictionary<MongoId, ItemLimit> InitItemLimitCounter(Dictionary<MongoId, int> limits)
{
var itemTypeCounts = new Dictionary<string, ItemLimit>();
var itemTypeCounts = new Dictionary<MongoId, ItemLimit>();
foreach (var itemTypeId in limits)
{
itemTypeCounts[itemTypeId.Key] = new ItemLimit
@@ -346,7 +346,7 @@ public class LootGenerator(
/// <returns>true if item was valid and added to pool</returns>
protected bool FindAndAddRandomItemToLoot(
List<TemplateItem> items,
Dictionary<string, ItemLimit> itemTypeCounts,
Dictionary<MongoId, ItemLimit> itemTypeCounts,
LootRequest options,
List<List<Item>> result
)
@@ -424,8 +424,8 @@ public class LootGenerator(
/// <returns>true if preset was valid and added to pool</returns>
protected bool FindAndAddRandomPresetToLoot(
List<Preset> presetPool,
Dictionary<string, ItemLimit> itemTypeCounts,
HashSet<string> itemBlacklist,
Dictionary<MongoId, ItemLimit> itemTypeCounts,
HashSet<MongoId> itemBlacklist,
List<List<Item>> result
)
{
@@ -807,7 +807,7 @@ public class LootGenerator(
{
public List<TemplateItem> ItemPool { get; set; }
public HashSet<string> Blacklist { get; set; }
public HashSet<MongoId> Blacklist { get; set; }
}
}
@@ -1,5 +1,6 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Spt.Config;
@@ -138,8 +139,8 @@ public class PMCLootGenerator(
/// <returns>Dictionary of items and weights inversely tied to the items price</returns>
protected Dictionary<string, double> GenerateLootPool(
string pmcRole,
HashSet<string> allowedItemTypeWhitelist,
HashSet<string> itemTplAndParentBlacklist,
HashSet<MongoId> allowedItemTypeWhitelist,
HashSet<MongoId> itemTplAndParentBlacklist,
Func<TemplateItem, bool>? genericItemCheck
)
{
@@ -188,9 +189,9 @@ public class PMCLootGenerator(
/// Get a generic all-container blacklist
/// </summary>
/// <returns>Hashset of blacklisted items</returns>
protected HashSet<string> GetContainerLootBlacklist()
protected HashSet<MongoId> GetContainerLootBlacklist()
{
var blacklist = new HashSet<string>();
var blacklist = new HashSet<MongoId>();
blacklist.UnionWith(_pmcConfig.PocketLoot.Blacklist);
blacklist.UnionWith(_pmcConfig.GlobalLootBlacklist);
blacklist.UnionWith(itemFilterService.GetBlacklistedItems());
@@ -835,7 +835,8 @@ public class RagfairOfferGenerator(
// Add hits to visor
var visorMod = itemWithMods.FirstOrDefault(item =>
item.ParentId == BaseClasses.ARMORED_EQUIPMENT && item.SlotId == "mod_equipment_000"
item.ParentId == BaseClasses.ARMORED_EQUIPMENT.ToString()
&& item.SlotId == "mod_equipment_000"
);
if (randomUtil.GetChance100(25) && visorMod != null)
{
@@ -1,5 +1,6 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Spt.Config;
@@ -134,9 +135,9 @@ public class CompletionQuestGenerator(
/// <param name="completionConfig">Completion quest type config</param>
/// <param name="itemTplBlacklist">Item tpls to not add to pool</param>
/// <returns>Set of item tpls</returns>
protected HashSet<string> GetItemsToRetrievePool(
protected HashSet<MongoId> GetItemsToRetrievePool(
Completion completionConfig,
HashSet<string> itemTplBlacklist
HashSet<MongoId> itemTplBlacklist
)
{
// Get seasonal items that should not be added to pool as seasonal event is not active
@@ -178,11 +179,11 @@ public class CompletionQuestGenerator(
/// <param name="roublesConfig">Roubles config</param>
/// <param name="itemsToRetrievePool">Item pool</param>
/// <returns>Filtered items and roubles budget</returns>
protected (HashSet<string>, double) GetItemsWithinBudget(
protected (HashSet<MongoId>, double) GetItemsWithinBudget(
int pmcLevel,
List<double> levelsConfig,
List<double> roublesConfig,
HashSet<string> itemsToRetrievePool
HashSet<MongoId> itemsToRetrievePool
)
{
// Be fair, don't value the items be more expensive than the reward
@@ -208,8 +209,8 @@ public class CompletionQuestGenerator(
/// <param name="itemSelection">Item selection to filter</param>
/// <param name="pmcLevel">Level of pmc</param>
/// <returns>Filtered selection, or original if null or empty</returns>
protected HashSet<string> GetWhitelistedItemSelection(
HashSet<string> itemSelection,
protected HashSet<MongoId> GetWhitelistedItemSelection(
HashSet<MongoId> itemSelection,
int pmcLevel
)
{
@@ -251,8 +252,8 @@ public class CompletionQuestGenerator(
/// <param name="itemSelection">Item selection to filter</param>
/// <param name="pmcLevel">Level of pmc</param>
/// <returns>Filtered selection, or original if null or empty</returns>
protected HashSet<string> GetBlacklistedItemSelection(
HashSet<string> itemSelection,
protected HashSet<MongoId> GetBlacklistedItemSelection(
HashSet<MongoId> itemSelection,
int pmcLevel
)
{
@@ -296,7 +297,7 @@ public class CompletionQuestGenerator(
RepeatableQuest quest,
Completion completionConfig,
RepeatableQuestConfig repeatableConfig,
List<string> itemSelection,
List<MongoId> itemSelection,
double roublesBudget
)
{
@@ -1,5 +1,6 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
@@ -818,8 +819,8 @@ public class RepeatableQuestRewardGenerator(
/// <returns> True if item is valid reward </returns>
public bool IsValidRewardItem(
string tpl,
HashSet<string> itemTplBlacklist,
HashSet<string> itemTypeBlacklist,
HashSet<MongoId> itemTplBlacklist,
HashSet<MongoId> itemTypeBlacklist,
List<string>? itemBaseWhitelist = null
)
{
@@ -496,12 +496,20 @@ public class ScavCaseRewardGenerator(
/// <returns>value to set stack count to</returns>
protected int GetRandomAmountRewardForScavCase(TemplateItem itemToCalculate, string rarity)
{
return itemToCalculate.Parent switch
var parentId = itemToCalculate.Parent;
if (parentId == BaseClasses.AMMO)
{
BaseClasses.AMMO => GetRandomisedAmmoRewardStackSize(itemToCalculate),
BaseClasses.MONEY => GetRandomisedMoneyRewardStackSize(itemToCalculate, rarity),
_ => 1,
};
return GetRandomisedAmmoRewardStackSize(itemToCalculate);
}
else if (parentId == BaseClasses.MONEY)
{
return GetRandomisedMoneyRewardStackSize(itemToCalculate, rarity);
}
else
{
return 1;
}
}
/// <summary>
@@ -525,26 +533,40 @@ public class ScavCaseRewardGenerator(
/// <returns>value to set stack count to</returns>
protected int GetRandomisedMoneyRewardStackSize(TemplateItem itemToCalculate, string rarity)
{
return itemToCalculate.Id switch
var id = itemToCalculate.Id;
if (id == Money.ROUBLES)
{
Money.ROUBLES => _randomUtil.GetInt(
return _randomUtil.GetInt(
_scavCaseConfig.MoneyRewards.RubCount.GetByJsonProp<MinMax<int>>(rarity).Min,
_scavCaseConfig.MoneyRewards.RubCount.GetByJsonProp<MinMax<int>>(rarity).Max
),
Money.EUROS => _randomUtil.GetInt(
);
}
else if (id == Money.EUROS)
{
return _randomUtil.GetInt(
_scavCaseConfig.MoneyRewards.EurCount.GetByJsonProp<MinMax<int>>(rarity).Min,
_scavCaseConfig.MoneyRewards.EurCount.GetByJsonProp<MinMax<int>>(rarity).Max
),
Money.DOLLARS => _randomUtil.GetInt(
);
}
else if (id == Money.DOLLARS)
{
return _randomUtil.GetInt(
_scavCaseConfig.MoneyRewards.UsdCount.GetByJsonProp<MinMax<int>>(rarity).Min,
_scavCaseConfig.MoneyRewards.UsdCount.GetByJsonProp<MinMax<int>>(rarity).Max
),
Money.GP => _randomUtil.GetInt(
);
}
else if (id == Money.GP)
{
return _randomUtil.GetInt(
_scavCaseConfig.MoneyRewards.GpCount.GetByJsonProp<MinMax<int>>(rarity).Min,
_scavCaseConfig.MoneyRewards.GpCount.GetByJsonProp<MinMax<int>>(rarity).Max
),
_ => 1,
};
);
}
else
{
return 1;
}
}
}
@@ -3,6 +3,7 @@ using System.Text.RegularExpressions;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers.Dialog.Commando.SptCommands;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Dialog;
using SPTarkov.Server.Core.Models.Eft.Profile;
@@ -207,7 +208,7 @@ public class GiveSptCommand(
localizedGlobal ??= GetGlobalsLocale(locale ?? "en");
// If item is an item name, we need to search using that item name and the locale which one we want otherwise
// item is just the tplId.
var tplId = isItemName
MongoId tplId = isItemName
? _itemHelper
.GetItems()
.Where(IsItemAllowed)
@@ -48,10 +48,7 @@ public class HandbookHelper(
}
itemToUpdate.Price = priceOverride.Price;
if (priceOverride.ParentId is not null)
{
itemToUpdate.ParentId = priceOverride.ParentId;
}
itemToUpdate.ParentId = priceOverride.ParentId;
}
var handbookDbClone = _cloner.Clone(handbook);
@@ -1679,7 +1679,7 @@ public class ItemHelper(
string caliber,
Dictionary<string, List<StaticAmmoDetails>> staticAmmoDist,
string? fallbackCartridgeTpl = null,
ICollection<string>? cartridgeWhitelist = null
ICollection<MongoId>? cartridgeWhitelist = null
)
{
var ammos = staticAmmoDist.GetValueOrDefault(caliber, []);
@@ -1766,7 +1766,7 @@ public class ItemHelper(
/// </summary>
/// <param name="desiredBaseType">Item base type wanted</param>
/// <returns>Array of tpls</returns>
public List<string> GetItemTplsOfBaseType(string desiredBaseType)
public List<MongoId> GetItemTplsOfBaseType(string desiredBaseType)
{
return _databaseService
.GetItems()
@@ -1791,7 +1791,7 @@ public class ItemHelper(
)
{
var result = itemToAdd;
HashSet<string> incompatibleModTpls = [];
HashSet<MongoId> incompatibleModTpls = [];
foreach (var slot in itemToAddTemplate.Properties.Slots)
{
// If only required mods is requested, skip non-essential
@@ -1867,8 +1867,8 @@ public class ItemHelper(
/// <param name="incompatibleModTpls">Incompatible tpls to not allow</param>
/// <returns>Chosen tpl or undefined</returns>
public string? GetCompatibleTplFromArray(
HashSet<string> possibleTpls,
HashSet<string> incompatibleModTpls
HashSet<MongoId> possibleTpls,
HashSet<MongoId> incompatibleModTpls
)
{
if (!possibleTpls.Any())
@@ -2062,7 +2062,7 @@ public class ItemHelper(
return currentItem.Id;
}
if (currentItem.Parent is null)
if (currentItem.Parent.IsEmpty())
// No parent, reached root
{
return currentItem.Id;
@@ -30,18 +30,25 @@ public class RagfairHelper(
/// <returns>Currency tag, e.g. RUB</returns>
public string GetCurrencyTag(string currencyTpl)
{
switch (currencyTpl)
if (currencyTpl == Money.EUROS)
{
case Money.EUROS:
return "EUR";
case Money.DOLLARS:
return "USD";
case Money.ROUBLES:
return "RUB";
case Money.GP:
return "GP";
default:
return "";
return "EUR";
}
else if (currencyTpl == Money.DOLLARS)
{
return "USD";
}
else if (currencyTpl == Money.ROUBLES)
{
return "RUB";
}
else if (currencyTpl == Money.GP)
{
return "GP";
}
else
{
return "";
}
}
@@ -190,11 +197,8 @@ public class RagfairHelper(
*/
public string GetCurrencySymbol(string currencyTpl)
{
return currencyTpl switch
{
Money.EUROS => "",
Money.DOLLARS => "$",
_ => "₽",
};
return currencyTpl == Money.EUROS ? "€"
: currencyTpl == Money.DOLLARS ? "$"
: "";
}
}
@@ -9,7 +9,13 @@ public readonly partial struct MongoId : IEquatable<MongoId>
public MongoId(string id)
{
if (string.IsNullOrWhiteSpace(id) || id.Length != 24)
// This is temporary, otherwise item buying is broken as when LINQ searches for string id's it's possible null is passed
if (id == null)
{
id = string.Empty;
}
if (id.Length != 24)
{
// TODO: Items.json root item has an empty parentId property
Console.WriteLine($"Critical MongoId error: Incorrect length. id: {id}");
@@ -125,7 +131,7 @@ public readonly partial struct MongoId : IEquatable<MongoId>
public bool IsEmpty()
{
if (_stringId == "000000000000000000000000")
if (_stringId == "000000000000000000000000" || string.IsNullOrEmpty(_stringId))
{
return true;
}
@@ -72,7 +72,13 @@ public record SpawnpointTemplate
}
[JsonPropertyName("Items")]
public List<Item>? Items { get; set; }
public List<SptLootItem>? Items { get; set; }
}
public record SptLootItem : Item
{
[JsonPropertyName("composedKey")]
public string? ComposedKey { get; set; }
}
public record GroupPosition
@@ -4,5 +4,8 @@ global using GlobalAmmo = System.Collections.Generic.Dictionary<
>;
global using GlobalMods = System.Collections.Generic.Dictionary<
string,
System.Collections.Generic.Dictionary<string, System.Collections.Generic.HashSet<string>>
System.Collections.Generic.Dictionary<
string,
System.Collections.Generic.HashSet<SPTarkov.Server.Core.Models.Common.MongoId>
>
>;
@@ -12,11 +12,11 @@ public record Item
private string? _parentId;
private string? _SlotId;
private string? _slotId;
// MongoId
[JsonPropertyName("_id")]
public required MongoId Id { get; set; }
public virtual required MongoId Id { get; set; }
[JsonPropertyName("_tpl")]
// MongoId
@@ -32,8 +32,8 @@ public record Item
[JsonPropertyName("slotId")]
public string? SlotId
{
get { return _SlotId; }
set { _SlotId = value == null ? null : string.Intern(value); }
get { return _slotId; }
set { _slotId = value == null ? null : string.Intern(value); }
}
[JsonPropertyName("location")]
@@ -1,5 +1,6 @@
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Constants;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Utils.Json.Converters;
@@ -12,8 +13,6 @@ public record TemplateItem
private Dictionary<string, bool>? _blocks;
private string? _id;
private string? _name;
private string? _parent;
@@ -23,11 +22,7 @@ public record TemplateItem
private string? _type;
[JsonPropertyName("_id")]
public string? Id
{
get { return _id; }
set { _id = string.Intern(value); }
}
public MongoId Id { get; set; }
[JsonPropertyName("_name")]
public string? Name
@@ -37,11 +32,7 @@ public record TemplateItem
}
[JsonPropertyName("_parent")]
public string? Parent
{
get { return _parent; }
set { _parent = string.Intern(value); }
}
public MongoId Parent { get; set; }
[JsonPropertyName("_type")]
public string? Type
@@ -309,7 +300,7 @@ public record Props
public bool? CanRequireOnRagfair { get; set; }
[JsonPropertyName("ConflictingItems")]
public HashSet<string>? ConflictingItems { get; set; }
public HashSet<MongoId>? ConflictingItems { get; set; }
[JsonPropertyName("Unlootable")]
public bool? Unlootable { get; set; }
@@ -1235,7 +1226,7 @@ public record Props
// Confirmed on client - MongoId
[JsonPropertyName("TargetItemFilter")]
public List<string>? TargetItemFilter { get; set; }
public List<MongoId>? TargetItemFilter { get; set; }
[JsonPropertyName("RepairQuality")]
public double? RepairQuality { get; set; }
@@ -1815,7 +1806,7 @@ public record SlotFilter
public List<string>? ArmorPlateColliders { get; set; }
[JsonPropertyName("Filter")]
public HashSet<string>? Filter { get; set; }
public HashSet<MongoId>? Filter { get; set; }
[JsonPropertyName("AnimationIndex")]
public double? AnimationIndex { get; set; }
@@ -276,7 +276,7 @@ public record BarterScheme
public double? Count { get; set; }
[JsonPropertyName("_tpl")]
public string? Template { get; set; }
public MongoId Template { get; set; }
[JsonPropertyName("onlyFunctional")]
public bool? OnlyFunctional { get; set; }
@@ -1,115 +1,117 @@
using SPTarkov.Server.Core.Models.Common;
namespace SPTarkov.Server.Core.Models.Enums;
public static class BaseClasses
{
public const string WEAPON = "5422acb9af1c889c16000029";
public const string UBGL = "55818b014bdc2ddc698b456b";
public const string ARMOR = "5448e54d4bdc2dcc718b4568";
public const string ARMORED_EQUIPMENT = "57bef4c42459772e8d35a53b";
public const string REPAIR_KITS = "616eb7aea207f41933308f46";
public const string HEADWEAR = "5a341c4086f77401f2541505";
public const string FACECOVER = "5a341c4686f77469e155819e";
public const string VEST = "5448e5284bdc2dcb718b4567";
public const string BACKPACK = "5448e53e4bdc2d60728b4567";
public const string COMPOUND = "566162e44bdc2d3f298b4573";
public const string VISORS = "5448e5724bdc2ddf718b4568";
public const string FOOD = "5448e8d04bdc2ddf718b4569";
public const string GAS_BLOCK = "56ea9461d2720b67698b456f";
public const string RAIL_COVER = "55818b1d4bdc2d5b648b4572";
public const string DRINK = "5448e8d64bdc2dce718b4568";
public const string BARTER_ITEM = "5448eb774bdc2d0a728b4567";
public const string INFO = "5448ecbe4bdc2d60728b4568";
public const string MEDKIT = "5448f39d4bdc2d0a728b4568";
public const string DRUGS = "5448f3a14bdc2d27728b4569";
public const string STIMULATOR = "5448f3a64bdc2d60728b456a";
public const string MEDICAL = "5448f3ac4bdc2dce718b4569";
public const string MEDICAL_SUPPLIES = "57864c8c245977548867e7f1";
public const string MOD = "5448fe124bdc2da5018b4567";
public const string FUNCTIONAL_MOD = "550aa4154bdc2dd8348b456b";
public const string FUEL = "5d650c3e815116009f6201d2";
public const string GEAR_MOD = "55802f3e4bdc2de7118b4584";
public const string STOCK = "55818a594bdc2db9688b456a";
public const string FOREGRIP = "55818af64bdc2d5b648b4570";
public const string MASTER_MOD = "55802f4a4bdc2ddb688b4569";
public const string MOUNT = "55818b224bdc2dde698b456f";
public const string MUZZLE = "5448fe394bdc2d0d028b456c";
public const string SIGHTS = "5448fe7a4bdc2d6f028b456b";
public const string MEDS = "543be5664bdc2dd4348b4569";
public const string MAP = "567849dd4bdc2d150f8b456e";
public const string MONEY = "543be5dd4bdc2deb348b4569";
public const string NIGHTVISION = "5a2c3a9486f774688b05e574";
public const string THERMAL_VISION = "5d21f59b6dbe99052b54ef83";
public const string KEY = "543be5e94bdc2df1348b4568";
public const string KEY_MECHANICAL = "5c99f98d86f7745c314214b3";
public const string KEYCARD = "5c164d2286f774194c5e69fa";
public const string EQUIPMENT = "543be5f84bdc2dd4348b456a";
public const string THROW_WEAPON = "543be6564bdc2df4348b4568";
public const string FOOD_DRINK = "543be6674bdc2df1348b4569";
public const string PISTOL = "5447b5cf4bdc2d65278b4567";
public const string REVOLVER = "617f1ef5e8b54b0998387733";
public const string SMG = "5447b5e04bdc2d62278b4567";
public const string ASSAULT_RIFLE = "5447b5f14bdc2d61278b4567";
public const string ASSAULT_CARBINE = "5447b5fc4bdc2d87278b4567";
public const string SHOTGUN = "5447b6094bdc2dc3278b4567";
public const string MARKSMAN_RIFLE = "5447b6194bdc2d67278b4567";
public const string SNIPER_RIFLE = "5447b6254bdc2dc3278b4568";
public const string MACHINE_GUN = "5447bed64bdc2d97278b4568";
public const string GRENADE_LAUNCHER = "5447bedf4bdc2d87278b4568";
public const string SPECIAL_WEAPON = "5447bee84bdc2dc3278b4569";
public const string SPEC_ITEM = "5447e0e74bdc2d3c308b4567";
public const string SPRING_DRIVEN_CYLINDER = "627a137bf21bc425b06ab944";
public const string KNIFE = "5447e1d04bdc2dff2f8b4567";
public const string AMMO = "5485a8684bdc2da71d8b4567";
public const string AMMO_BOX = "543be5cb4bdc2deb348b4568";
public const string LOOT_CONTAINER = "566965d44bdc2d814c8b4571";
public const string MOB_CONTAINER = "5448bf274bdc2dfc2f8b456a";
public const string SEARCHABLE_ITEM = "566168634bdc2d144c8b456c";
public const string STASH = "566abbb64bdc2d144c8b457d";
public const string SORTING_TABLE = "6050cac987d3f925bf016837";
public const string LOCKABLE_CONTAINER = "5671435f4bdc2d96058b4569";
public const string SIMPLE_CONTAINER = "5795f317245977243854e041";
public const string INVENTORY = "55d720f24bdc2d88028b456d";
public const string STATIONARY_CONTAINER = "567583764bdc2d98058b456e";
public const string POCKETS = "557596e64bdc2dc2118b4571";
public const string ARMBAND = "5b3f15d486f77432d0509248";
public const string JEWELRY = "57864a3d24597754843f8721";
public const string ELECTRONICS = "57864a66245977548f04a81f";
public const string BUILDING_MATERIAL = "57864ada245977548638de91";
public const string TOOL = "57864bb7245977548b3b66c2";
public const string HOUSEHOLD_GOODS = "57864c322459775490116fbf";
public const string LUBRICANT = "57864e4c24597754843f8723";
public const string BATTERY = "57864ee62459775490116fc1";
public const string ASSAULT_SCOPE = "55818add4bdc2d5b648b456f";
public const string TACTICAL_COMBO = "55818b164bdc2ddc698b456c";
public const string FLASHLIGHT = "55818b084bdc2d5b648b4571";
public const string MAGAZINE = "5448bc234bdc2d3c308b4569";
public const string LIGHT_LASER_DESIGNATOR = "55818b0e4bdc2dde698b456e";
public const string FLASH_HIDER = "550aa4bf4bdc2dd6348b456b";
public const string COLLIMATOR = "55818ad54bdc2ddc698b4569";
public const string IRON_SIGHT = "55818ac54bdc2d5b648b456e";
public const string COMPACT_COLLIMATOR = "55818acf4bdc2dde698b456b";
public const string COMPENSATOR = "550aa4af4bdc2dd4348b456e";
public const string OPTIC_SCOPE = "55818ae44bdc2dde698b456c";
public const string SPECIAL_SCOPE = "55818aeb4bdc2ddc698b456a";
public const string OTHER = "590c745b86f7743cc433c5f2";
public const string SILENCER = "550aa4cd4bdc2dd8348b456c";
public const string PORTABLE_RANGE_FINDER = "61605ddea09d851a0a0c1bbc";
public const string ITEM = "54009119af1c881c07000029";
public const string CYLINDER_MAGAZINE = "610720f290b75a49ff2e5e25";
public const string AUXILIARY_MOD = "5a74651486f7744e73386dd1";
public const string BIPOD = "55818afb4bdc2dde698b456d";
public const string HEADPHONES = "5645bcb74bdc2ded0b8b4578";
public const string RANDOM_LOOT_CONTAINER = "62f109593b54472778797866";
public const string STACKABLE_ITEM = "5661632d4bdc2d903d8b456b";
public const string BUILT_IN_INSERTS = "65649eb40bf0ed77b8044453";
public const string ARMOR_PLATE = "644120aa86ffbe10ee032b6f";
public const string CULTIST_AMULET = "64b69b0c8f3be32ed22682f8";
public const string RADIO_TRANSMITTER = "62e9103049c018f425059f38";
public const string HANDGUARD = "55818a104bdc2db9688b4569";
public const string PISTOL_GRIP = "55818a684bdc2ddd698b456d";
public const string RECEIVER = "55818a304bdc2db5418b457d";
public const string BARREL = "555ef6e44bdc2de9068b457e";
public const string CHARGING_HANDLE = "55818a6f4bdc2db9688b456b";
public const string COMB_MUZZLE_DEVICE = "550aa4dd4bdc2dc9348b4569 ";
public const string HIDEOUT_AREA_CONTAINER = "63da6da4784a55176c018dba";
public static readonly MongoId WEAPON = new MongoId("5422acb9af1c889c16000029");
public static readonly MongoId UBGL = new MongoId("55818b014bdc2ddc698b456b");
public static readonly MongoId ARMOR = new MongoId("5448e54d4bdc2dcc718b4568");
public static readonly MongoId ARMORED_EQUIPMENT = new MongoId("57bef4c42459772e8d35a53b");
public static readonly MongoId REPAIR_KITS = new MongoId("616eb7aea207f41933308f46");
public static readonly MongoId HEADWEAR = new MongoId("5a341c4086f77401f2541505");
public static readonly MongoId FACECOVER = new MongoId("5a341c4686f77469e155819e");
public static readonly MongoId VEST = new MongoId("5448e5284bdc2dcb718b4567");
public static readonly MongoId BACKPACK = new MongoId("5448e53e4bdc2d60728b4567");
public static readonly MongoId COMPOUND = new MongoId("566162e44bdc2d3f298b4573");
public static readonly MongoId VISORS = new MongoId("5448e5724bdc2ddf718b4568");
public static readonly MongoId FOOD = new MongoId("5448e8d04bdc2ddf718b4569");
public static readonly MongoId GAS_BLOCK = new MongoId("56ea9461d2720b67698b456f");
public static readonly MongoId RAIL_COVER = new MongoId("55818b1d4bdc2d5b648b4572");
public static readonly MongoId DRINK = new MongoId("5448e8d64bdc2dce718b4568");
public static readonly MongoId BARTER_ITEM = new MongoId("5448eb774bdc2d0a728b4567");
public static readonly MongoId INFO = new MongoId("5448ecbe4bdc2d60728b4568");
public static readonly MongoId MEDKIT = new MongoId("5448f39d4bdc2d0a728b4568");
public static readonly MongoId DRUGS = new MongoId("5448f3a14bdc2d27728b4569");
public static readonly MongoId STIMULATOR = new MongoId("5448f3a64bdc2d60728b456a");
public static readonly MongoId MEDICAL = new MongoId("5448f3ac4bdc2dce718b4569");
public static readonly MongoId MEDICAL_SUPPLIES = new MongoId("57864c8c245977548867e7f1");
public static readonly MongoId MOD = new MongoId("5448fe124bdc2da5018b4567");
public static readonly MongoId FUNCTIONAL_MOD = new MongoId("550aa4154bdc2dd8348b456b");
public static readonly MongoId FUEL = new MongoId("5d650c3e815116009f6201d2");
public static readonly MongoId GEAR_MOD = new MongoId("55802f3e4bdc2de7118b4584");
public static readonly MongoId STOCK = new MongoId("55818a594bdc2db9688b456a");
public static readonly MongoId FOREGRIP = new MongoId("55818af64bdc2d5b648b4570");
public static readonly MongoId MASTER_MOD = new MongoId("55802f4a4bdc2ddb688b4569");
public static readonly MongoId MOUNT = new MongoId("55818b224bdc2dde698b456f");
public static readonly MongoId MUZZLE = new MongoId("5448fe394bdc2d0d028b456c");
public static readonly MongoId SIGHTS = new MongoId("5448fe7a4bdc2d6f028b456b");
public static readonly MongoId MEDS = new MongoId("543be5664bdc2dd4348b4569");
public static readonly MongoId MAP = new MongoId("567849dd4bdc2d150f8b456e");
public static readonly MongoId MONEY = new MongoId("543be5dd4bdc2deb348b4569");
public static readonly MongoId NIGHTVISION = new MongoId("5a2c3a9486f774688b05e574");
public static readonly MongoId THERMAL_VISION = new MongoId("5d21f59b6dbe99052b54ef83");
public static readonly MongoId KEY = new MongoId("543be5e94bdc2df1348b4568");
public static readonly MongoId KEY_MECHANICAL = new MongoId("5c99f98d86f7745c314214b3");
public static readonly MongoId KEYCARD = new MongoId("5c164d2286f774194c5e69fa");
public static readonly MongoId EQUIPMENT = new MongoId("543be5f84bdc2dd4348b456a");
public static readonly MongoId THROW_WEAPON = new MongoId("543be6564bdc2df4348b4568");
public static readonly MongoId FOOD_DRINK = new MongoId("543be6674bdc2df1348b4569");
public static readonly MongoId PISTOL = new MongoId("5447b5cf4bdc2d65278b4567");
public static readonly MongoId REVOLVER = new MongoId("617f1ef5e8b54b0998387733");
public static readonly MongoId SMG = new MongoId("5447b5e04bdc2d62278b4567");
public static readonly MongoId ASSAULT_RIFLE = new MongoId("5447b5f14bdc2d61278b4567");
public static readonly MongoId ASSAULT_CARBINE = new MongoId("5447b5fc4bdc2d87278b4567");
public static readonly MongoId SHOTGUN = new MongoId("5447b6094bdc2dc3278b4567");
public static readonly MongoId MARKSMAN_RIFLE = new MongoId("5447b6194bdc2d67278b4567");
public static readonly MongoId SNIPER_RIFLE = new MongoId("5447b6254bdc2dc3278b4568");
public static readonly MongoId MACHINE_GUN = new MongoId("5447bed64bdc2d97278b4568");
public static readonly MongoId GRENADE_LAUNCHER = new MongoId("5447bedf4bdc2d87278b4568");
public static readonly MongoId SPECIAL_WEAPON = new MongoId("5447bee84bdc2dc3278b4569");
public static readonly MongoId SPEC_ITEM = new MongoId("5447e0e74bdc2d3c308b4567");
public static readonly MongoId SPRING_DRIVEN_CYLINDER = new MongoId("627a137bf21bc425b06ab944");
public static readonly MongoId KNIFE = new MongoId("5447e1d04bdc2dff2f8b4567");
public static readonly MongoId AMMO = new MongoId("5485a8684bdc2da71d8b4567");
public static readonly MongoId AMMO_BOX = new MongoId("543be5cb4bdc2deb348b4568");
public static readonly MongoId LOOT_CONTAINER = new MongoId("566965d44bdc2d814c8b4571");
public static readonly MongoId MOB_CONTAINER = new MongoId("5448bf274bdc2dfc2f8b456a");
public static readonly MongoId SEARCHABLE_ITEM = new MongoId("566168634bdc2d144c8b456c");
public static readonly MongoId STASH = new MongoId("566abbb64bdc2d144c8b457d");
public static readonly MongoId SORTING_TABLE = new MongoId("6050cac987d3f925bf016837");
public static readonly MongoId LOCKABLE_CONTAINER = new MongoId("5671435f4bdc2d96058b4569");
public static readonly MongoId SIMPLE_CONTAINER = new MongoId("5795f317245977243854e041");
public static readonly MongoId INVENTORY = new MongoId("55d720f24bdc2d88028b456d");
public static readonly MongoId STATIONARY_CONTAINER = new MongoId("567583764bdc2d98058b456e");
public static readonly MongoId POCKETS = new MongoId("557596e64bdc2dc2118b4571");
public static readonly MongoId ARMBAND = new MongoId("5b3f15d486f77432d0509248");
public static readonly MongoId JEWELRY = new MongoId("57864a3d24597754843f8721");
public static readonly MongoId ELECTRONICS = new MongoId("57864a66245977548f04a81f");
public static readonly MongoId BUILDING_MATERIAL = new MongoId("57864ada245977548638de91");
public static readonly MongoId TOOL = new MongoId("57864bb7245977548b3b66c2");
public static readonly MongoId HOUSEHOLD_GOODS = new MongoId("57864c322459775490116fbf");
public static readonly MongoId LUBRICANT = new MongoId("57864e4c24597754843f8723");
public static readonly MongoId BATTERY = new MongoId("57864ee62459775490116fc1");
public static readonly MongoId ASSAULT_SCOPE = new MongoId("55818add4bdc2d5b648b456f");
public static readonly MongoId TACTICAL_COMBO = new MongoId("55818b164bdc2ddc698b456c");
public static readonly MongoId FLASHLIGHT = new MongoId("55818b084bdc2d5b648b4571");
public static readonly MongoId MAGAZINE = new MongoId("5448bc234bdc2d3c308b4569");
public static readonly MongoId LIGHT_LASER_DESIGNATOR = new MongoId("55818b0e4bdc2dde698b456e");
public static readonly MongoId FLASH_HIDER = new MongoId("550aa4bf4bdc2dd6348b456b");
public static readonly MongoId COLLIMATOR = new MongoId("55818ad54bdc2ddc698b4569");
public static readonly MongoId IRON_SIGHT = new MongoId("55818ac54bdc2d5b648b456e");
public static readonly MongoId COMPACT_COLLIMATOR = new MongoId("55818acf4bdc2dde698b456b");
public static readonly MongoId COMPENSATOR = new MongoId("550aa4af4bdc2dd4348b456e");
public static readonly MongoId OPTIC_SCOPE = new MongoId("55818ae44bdc2dde698b456c");
public static readonly MongoId SPECIAL_SCOPE = new MongoId("55818aeb4bdc2ddc698b456a");
public static readonly MongoId OTHER = new MongoId("590c745b86f7743cc433c5f2");
public static readonly MongoId SILENCER = new MongoId("550aa4cd4bdc2dd8348b456c");
public static readonly MongoId PORTABLE_RANGE_FINDER = new MongoId("61605ddea09d851a0a0c1bbc");
public static readonly MongoId ITEM = new MongoId("54009119af1c881c07000029");
public static readonly MongoId CYLINDER_MAGAZINE = new MongoId("610720f290b75a49ff2e5e25");
public static readonly MongoId AUXILIARY_MOD = new MongoId("5a74651486f7744e73386dd1");
public static readonly MongoId BIPOD = new MongoId("55818afb4bdc2dde698b456d");
public static readonly MongoId HEADPHONES = new MongoId("5645bcb74bdc2ded0b8b4578");
public static readonly MongoId RANDOM_LOOT_CONTAINER = new MongoId("62f109593b54472778797866");
public static readonly MongoId STACKABLE_ITEM = new MongoId("5661632d4bdc2d903d8b456b");
public static readonly MongoId BUILT_IN_INSERTS = new MongoId("65649eb40bf0ed77b8044453");
public static readonly MongoId ARMOR_PLATE = new MongoId("644120aa86ffbe10ee032b6f");
public static readonly MongoId CULTIST_AMULET = new MongoId("64b69b0c8f3be32ed22682f8");
public static readonly MongoId RADIO_TRANSMITTER = new MongoId("62e9103049c018f425059f38");
public static readonly MongoId HANDGUARD = new MongoId("55818a104bdc2db9688b4569");
public static readonly MongoId PISTOL_GRIP = new MongoId("55818a684bdc2ddd698b456d");
public static readonly MongoId RECEIVER = new MongoId("55818a304bdc2db5418b457d");
public static readonly MongoId BARREL = new MongoId("555ef6e44bdc2de9068b457e");
public static readonly MongoId CHARGING_HANDLE = new MongoId("55818a6f4bdc2db9688b456b");
public static readonly MongoId COMB_MUZZLE_DEVICE = new MongoId("550aa4dd4bdc2dc9348b4569");
public static readonly MongoId HIDEOUT_AREA_CONTAINER = new MongoId("63da6da4784a55176c018dba");
}
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Models.Common;
namespace SPTarkov.Server.Core.Models.Enums;
@@ -7,10 +8,10 @@ public record Money
[JsonExtensionData]
public Dictionary<string, object>? ExtensionData { get; set; }
public const string ROUBLES = "5449016a4bdc2d6f028b456f";
public const string EUROS = "569668774bdc2da2298b4568";
public const string DOLLARS = "5696686a4bdc2da3298b456a";
public const string GP = "5d235b4d86f7742e017bc88a";
public static readonly MongoId ROUBLES = new MongoId("5449016a4bdc2d6f028b456f");
public static readonly MongoId EUROS = new MongoId("569668774bdc2da2298b4568");
public static readonly MongoId DOLLARS = new MongoId("5696686a4bdc2da3298b456a");
public static readonly MongoId GP = new MongoId("5d235b4d86f7742e017bc88a");
public static HashSet<string> GetMoneyTpls()
{
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Models.Common;
namespace SPTarkov.Server.Core.Models.Spt.Bots;
@@ -11,7 +12,7 @@ public record FilterPlateModsForSlotByLevelResult
public Result? Result { get; set; }
[JsonPropertyName("plateModTpls")]
public HashSet<string>? PlateModTemplates { get; set; }
public HashSet<MongoId>? PlateModTemplates { get; set; }
}
public enum Result
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
namespace SPTarkov.Server.Core.Models.Spt.Bots;
@@ -66,7 +67,7 @@ public record GenerateWeaponRequest
/// Array of item tpls the weapon does not support
/// </summary>
[JsonPropertyName("conflictingItemTpls")]
public HashSet<string>? ConflictingItemTpls { get; set; }
public HashSet<MongoId>? ConflictingItemTpls { get; set; }
}
public record BotData
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Spt.Config;
@@ -41,7 +42,7 @@ public record ModToSpawnRequest
/// Pool of items to pick from
/// </summary>
[JsonPropertyName("itemModPool")]
public Dictionary<string, HashSet<string>>? ItemModPool { get; set; }
public Dictionary<string, HashSet<MongoId>>? ItemModPool { get; set; }
/// <summary>
/// List with only weapon tpl in it, ready for mods to be added
@@ -77,7 +78,7 @@ public record ModToSpawnRequest
/// List of item tpls the weapon does not support
/// </summary>
[JsonPropertyName("conflictingItemTpls")]
public HashSet<string>? ConflictingItemTpls { get; set; }
public HashSet<MongoId>? ConflictingItemTpls { get; set; }
[JsonPropertyName("botData")]
public BotData? BotData { get; set; }
@@ -62,25 +62,25 @@ public record AirdropLoot
/// Items to never allow - tpls
/// </summary>
[JsonPropertyName("itemBlacklist")]
public required List<string> ItemBlacklist { get; set; }
public required List<MongoId> ItemBlacklist { get; set; }
/// <summary>
/// Item type (parentId) to allow inside crate
/// </summary>
[JsonPropertyName("itemTypeWhitelist")]
public required List<string> ItemTypeWhitelist { get; set; }
public required List<MongoId> ItemTypeWhitelist { get; set; }
/// <summary>
/// Item type/ item tpls to limit count of inside crate - key: item base type: value: max count
/// </summary>
[JsonPropertyName("itemLimits")]
public required Dictionary<string, int> ItemLimits { get; set; }
public required Dictionary<MongoId, int> ItemLimits { get; set; }
/// <summary>
/// Items to limit stack size of key: item tpl value: min/max stack size
/// </summary>
[JsonPropertyName("itemStackLimits")]
public required Dictionary<string, MinMax<int>> ItemStackLimits { get; set; }
public required Dictionary<MongoId, MinMax<int>> ItemStackLimits { get; set; }
/// <summary>
/// Armor levels to allow inside crate e.g. [4,5,6]
@@ -553,19 +553,19 @@ public record EquipmentFilterDetails
/// Key: mod slot name e.g. mod_magazine, value: item tpls
/// </summary>
[JsonPropertyName("equipment")]
public Dictionary<string, HashSet<string>>? Equipment { get; set; }
public Dictionary<string, HashSet<MongoId>>? Equipment { get; set; }
/// <summary>
/// Key: equipment slot name e.g. FirstPrimaryWeapon, value: item tpls
/// </summary>
[JsonPropertyName("gear")]
public Dictionary<EquipmentSlots, HashSet<string>>? Gear { get; set; }
public Dictionary<EquipmentSlots, HashSet<MongoId>>? Gear { get; set; }
/// <summary>
/// Key: cartridge type e.g. Caliber23x75, value: item tpls
/// </summary>
[JsonPropertyName("cartridge")]
public Dictionary<string, HashSet<string>>? Cartridge { get; set; }
public Dictionary<string, HashSet<MongoId>>? Cartridge { get; set; }
}
public record WeightingAdjustmentDetails
@@ -133,7 +133,7 @@ public record CultistCircleSettings
/// Item tpls to exclude from the reward pool
/// </summary>
[JsonPropertyName("rewardItemBlacklist")]
public required List<string> RewardItemBlacklist { get; set; }
public required List<MongoId> RewardItemBlacklist { get; set; }
/// <summary>
/// Item tpls to include in the reward pool
@@ -142,7 +142,7 @@ public record CultistCircleSettings
public required List<string> AdditionalRewardItemPool { get; set; }
[JsonPropertyName("currencyRewards")]
public required Dictionary<string, MinMax<int>> CurrencyRewards { get; set; }
public required Dictionary<MongoId, MinMax<int>> CurrencyRewards { get; set; }
}
public record CraftTimeThreshold : MinMax<int>
@@ -57,7 +57,7 @@ public record RewardDetails
public Dictionary<string, double>? RewardTplPool { get; set; }
[JsonPropertyName("rewardTypePool")]
public List<string>? RewardTypePool { get; set; }
public List<MongoId>? RewardTypePool { get; set; }
}
public record SealedAirdropContainerSettings
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
namespace SPTarkov.Server.Core.Models.Spt.Config;
@@ -12,34 +13,34 @@ public record ItemConfig : BaseConfig
/// Items that should be globally blacklisted
/// </summary>
[JsonPropertyName("blacklist")]
public required HashSet<string> Blacklist { get; set; }
public required HashSet<MongoId> Blacklist { get; set; }
/// <summary>
/// Items that should not be lootable from any location
/// </summary>
[JsonPropertyName("lootableItemBlacklist")]
public required HashSet<string> LootableItemBlacklist { get; set; }
public required HashSet<MongoId> LootableItemBlacklist { get; set; }
/// <summary>
/// items that should not be given as rewards
/// </summary>
[JsonPropertyName("rewardItemBlacklist")]
public required HashSet<string> RewardItemBlacklist { get; set; }
public required HashSet<MongoId> RewardItemBlacklist { get; set; }
/// <summary>
/// Item base types that should not be given as rewards
/// </summary>
[JsonPropertyName("rewardItemTypeBlacklist")]
public required HashSet<string> RewardItemTypeBlacklist { get; set; }
public required HashSet<MongoId> RewardItemTypeBlacklist { get; set; }
/// <summary>
/// Items that can only be found on bosses
/// </summary>
[JsonPropertyName("bossItems")]
public required HashSet<string> BossItems { get; set; }
public required HashSet<MongoId> BossItems { get; set; }
[JsonPropertyName("handbookPriceOverride")]
public required Dictionary<string, HandbookPriceOverride> HandbookPriceOverride { get; set; }
public required Dictionary<MongoId, HandbookPriceOverride> HandbookPriceOverride { get; set; }
/// <summary>
/// Presets to add to the globals.json `ItemPresets` dictionary on server start
@@ -63,5 +64,5 @@ public record HandbookPriceOverride
/// NOT parentId from items.json, but handbook.json
/// </summary>
[JsonPropertyName("parentId")]
public string? ParentId { get; set; } = string.Empty;
public MongoId ParentId { get; set; } = MongoId.Empty();
}
@@ -41,7 +41,7 @@ public record PmcConfig : BaseConfig
public required SlotLootSettings BackpackLoot { get; set; }
[JsonPropertyName("globalLootBlacklist")]
public required List<string> GlobalLootBlacklist { get; set; }
public required List<MongoId> GlobalLootBlacklist { get; set; }
/// <summary>
/// Use difficulty defined in config/bot.json/difficulty instead of chosen difficulty dropdown value
@@ -206,13 +206,13 @@ public record SlotLootSettings
/// Item Type whitelist
/// </summary>
[JsonPropertyName("whitelist")]
public HashSet<string> Whitelist { get; set; } = [];
public HashSet<MongoId> Whitelist { get; set; } = [];
/// <summary>
/// Item tpl blacklist
/// </summary>
[JsonPropertyName("blacklist")]
public HashSet<string> Blacklist { get; set; } = [];
public HashSet<MongoId> Blacklist { get; set; } = [];
}
public record MinMaxLootValue : MinMax<int>
@@ -206,13 +206,13 @@ public record RepeatableQuestConfig
/// Item base types to block when generating rewards
/// </summary>
[JsonPropertyName("rewardBaseTypeBlacklist")]
public required HashSet<string> RewardBaseTypeBlacklist { get; set; }
public required HashSet<MongoId> RewardBaseTypeBlacklist { get; set; }
/// <summary>
/// Item tplIds to ignore when generating rewards
/// </summary>
[JsonPropertyName("rewardBlacklist")]
public required HashSet<string> RewardBlacklist { get; set; }
public required HashSet<MongoId> RewardBlacklist { get; set; }
/// <summary>
/// Minimum stack size that an ammo reward should be generated with
@@ -476,7 +476,7 @@ public record Completion : BaseQuestConfig
/// Blacklisted item types to not collect
/// </summary>
[JsonPropertyName("requiredItemTypeBlacklist")]
public HashSet<string>? RequiredItemTypeBlacklist { get; set; }
public HashSet<MongoId>? RequiredItemTypeBlacklist { get; set; }
}
public record Pickup : BaseQuestConfig
@@ -37,22 +37,22 @@ public record LootRequest
/// Item tpl blacklist to exclude
/// </summary>
[JsonPropertyName("itemBlacklist")]
public HashSet<string>? ItemBlacklist { get; set; }
public HashSet<MongoId>? ItemBlacklist { get; set; }
/// <summary>
/// Item tpl whitelist to pick from
/// </summary>
[JsonPropertyName("itemTypeWhitelist")]
public List<string>? ItemTypeWhitelist { get; set; }
public List<MongoId>? ItemTypeWhitelist { get; set; }
/// <summary>
/// key: item base type: value: max count
/// </summary>
[JsonPropertyName("itemLimits")]
public Dictionary<string, int>? ItemLimits { get; set; }
public Dictionary<MongoId, int>? ItemLimits { get; set; }
[JsonPropertyName("itemStackLimits")]
public Dictionary<string, MinMax<int>>? ItemStackLimits { get; set; }
public Dictionary<MongoId, MinMax<int>>? ItemStackLimits { get; set; }
/// <summary>
/// Allowed armor plate levels 2/3/4/5/6 for armor generated
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Profile;
@@ -16,7 +17,7 @@ public record Templates
public List<CustomisationStorage>? CustomisationStorage { get; set; }
[JsonPropertyName("items")]
public Dictionary<string, TemplateItem>? Items { get; set; }
public Dictionary<MongoId, TemplateItem>? Items { get; set; }
[JsonPropertyName("prestige")]
public Prestige? Prestige { get; set; }
@@ -1,6 +1,7 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Location;
using SPTarkov.Server.Core.Models.Enums;
@@ -255,7 +256,7 @@ public class AirdropService(
)
.Select(templateItem => templateItem.Id)
.ToHashSet();
var itemBlacklist = new HashSet<string>();
var itemBlacklist = new HashSet<MongoId>();
itemBlacklist.UnionWith(lootSettingsByType.ItemBlacklist);
itemBlacklist.UnionWith(_itemFilterService.GetItemRewardBlacklist());
itemBlacklist.UnionWith(_itemFilterService.GetBossItems());
@@ -1,6 +1,7 @@
using System.Collections.Concurrent;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Utils;
@@ -19,11 +20,11 @@ public class BotEquipmentModPoolService(
private ConcurrentDictionary<
string,
ConcurrentDictionary<string, HashSet<string>>
ConcurrentDictionary<string, HashSet<MongoId>>
>? _gearModPool;
protected ConcurrentDictionary<
string,
ConcurrentDictionary<string, HashSet<string>>
ConcurrentDictionary<string, HashSet<MongoId>>
> GearModPool
{
get
@@ -37,11 +38,11 @@ public class BotEquipmentModPoolService(
private ConcurrentDictionary<
string,
ConcurrentDictionary<string, HashSet<string>>
ConcurrentDictionary<string, HashSet<MongoId>>
>? _weaponModPool;
protected ConcurrentDictionary<
string,
ConcurrentDictionary<string, HashSet<string>>
ConcurrentDictionary<string, HashSet<MongoId>>
> WeaponModPool
{
get
@@ -60,7 +61,7 @@ public class BotEquipmentModPoolService(
/// <param name="poolType"> Mod pool to choose from e.g. "weapon" for weaponModPool </param>
protected ConcurrentDictionary<
string,
ConcurrentDictionary<string, HashSet<string>>
ConcurrentDictionary<string, HashSet<MongoId>>
> GeneratePool(IEnumerable<TemplateItem>? inputItems, string poolType)
{
if (inputItems is null || !inputItems.Any())
@@ -73,7 +74,7 @@ public class BotEquipmentModPoolService(
}
var pool =
new ConcurrentDictionary<string, ConcurrentDictionary<string, HashSet<string>>>();
new ConcurrentDictionary<string, ConcurrentDictionary<string, HashSet<MongoId>>>();
foreach (var item in inputItems)
{
if (item.Properties is null)
@@ -95,7 +96,7 @@ public class BotEquipmentModPoolService(
}
// Add base item (weapon/armor) to pool
pool.TryAdd(item.Id, new ConcurrentDictionary<string, HashSet<string>>());
pool.TryAdd(item.Id, new ConcurrentDictionary<string, HashSet<MongoId>>());
// Iterate over each items mod slots e.g. mod_muzzle
foreach (var slot in item.Properties.Slots)
@@ -134,7 +135,7 @@ public class BotEquipmentModPoolService(
return pool;
}
private bool SetContainsTpl(HashSet<string> itemSet, string tpl)
private bool SetContainsTpl(HashSet<MongoId> itemSet, string tpl)
{
lock (_lockObject)
{
@@ -142,7 +143,7 @@ public class BotEquipmentModPoolService(
}
}
private bool AddTplToSet(HashSet<string> itemSet, string itemToAddTpl)
private bool AddTplToSet(HashSet<MongoId> itemSet, string itemToAddTpl)
{
lock (_lockObject)
{
@@ -151,7 +152,7 @@ public class BotEquipmentModPoolService(
}
private bool InitSetInDict(
ConcurrentDictionary<string, HashSet<string>> dictionary,
ConcurrentDictionary<string, HashSet<MongoId>> dictionary,
string slotName
)
{
@@ -175,7 +176,7 @@ public class BotEquipmentModPoolService(
/// <param name="itemTpl"> Item to look up </param>
/// <param name="slotName"> Slot to get compatible mods for </param>
/// <returns> Hashset of tpls that fit the slot </returns>
public HashSet<string> GetCompatibleModsForWeaponSlot(string itemTpl, string slotName)
public HashSet<MongoId> GetCompatibleModsForWeaponSlot(string itemTpl, string slotName)
{
if (WeaponModPool.TryGetValue(itemTpl, out var value))
{
@@ -194,7 +195,7 @@ public class BotEquipmentModPoolService(
/// </summary>
/// <param name="itemTpl"> Items tpl to look up mods for </param>
/// <returns> Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value </returns>
public ConcurrentDictionary<string, HashSet<string>> GetModsForGearSlot(string itemTpl)
public ConcurrentDictionary<string, HashSet<MongoId>> GetModsForGearSlot(string itemTpl)
{
return GearModPool.TryGetValue(itemTpl, out var value) ? value : [];
}
@@ -204,7 +205,7 @@ public class BotEquipmentModPoolService(
/// </summary>
/// <param name="itemTpl"> Weapons tpl to look up mods for </param>
/// <returns> Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value </returns>
public ConcurrentDictionary<string, HashSet<string>> GetModsForWeaponSlot(string itemTpl)
public ConcurrentDictionary<string, HashSet<MongoId>> GetModsForWeaponSlot(string itemTpl)
{
return WeaponModPool.TryGetValue(itemTpl, out var value) ? value : [];
}
@@ -214,9 +215,9 @@ public class BotEquipmentModPoolService(
/// </summary>
/// <param name="itemTpl"> Weapons tpl to look up mods for </param>
/// <returns> Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value </returns>
public Dictionary<string, HashSet<string>>? GetRequiredModsForWeaponSlot(string itemTpl)
public Dictionary<string, HashSet<MongoId>>? GetRequiredModsForWeaponSlot(string itemTpl)
{
var result = new Dictionary<string, HashSet<string>>();
var result = new Dictionary<string, HashSet<MongoId>>();
// Get item from db
var itemDb = itemHelper.GetItem(itemTpl).Value;
@@ -248,7 +249,7 @@ public class BotEquipmentModPoolService(
/// </summary>
protected ConcurrentDictionary<
string,
ConcurrentDictionary<string, HashSet<string>>
ConcurrentDictionary<string, HashSet<MongoId>>
> GenerateWeaponPool()
{
var weaponsAndMods = databaseService
@@ -267,7 +268,7 @@ public class BotEquipmentModPoolService(
/// </summary>
protected ConcurrentDictionary<
string,
ConcurrentDictionary<string, HashSet<string>>
ConcurrentDictionary<string, HashSet<MongoId>>
> GenerateGearPool()
{
var gearAndMods = databaseService
@@ -711,7 +711,7 @@ public class CircleOfCultistService(
.Select(templateItem => templateItem.Key);
// Create set of unique values to ignore
var itemRewardBlacklist = new HashSet<string>();
var itemRewardBlacklist = new HashSet<MongoId>();
itemRewardBlacklist.UnionWith(_seasonalEventService.GetInactiveSeasonalEventItems());
itemRewardBlacklist.UnionWith(_itemFilterService.GetItemRewardBlacklist());
itemRewardBlacklist.UnionWith(_itemFilterService.GetBlacklistedItems());
@@ -785,7 +785,7 @@ public class CircleOfCultistService(
/// <param name="rewardPool">Pool to add items to</param>
protected void AddTaskItemRequirementsToRewardPool(
PmcData pmcData,
HashSet<string> itemRewardBlacklist,
HashSet<MongoId> itemRewardBlacklist,
HashSet<string> rewardPool
)
{
@@ -826,7 +826,7 @@ public class CircleOfCultistService(
protected void AddHideoutUpgradeRequirementsToRewardPool(
Hideout hideoutDbData,
PmcData pmcData,
HashSet<string> itemRewardBlacklist,
HashSet<MongoId> itemRewardBlacklist,
HashSet<string> rewardPool
)
{
@@ -900,7 +900,7 @@ public class CircleOfCultistService(
/// <returns>Set of item tpls</returns>
protected HashSet<string> GenerateRandomisedItemsAndAddToRewardPool(
HashSet<string> rewardPool,
HashSet<string> itemRewardBlacklist,
HashSet<MongoId> itemRewardBlacklist,
bool itemsShouldBeHighValue
)
{
@@ -1,6 +1,7 @@
using System.Diagnostics;
using SPTarkov.Common.Extensions;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Spt.Bots;
@@ -263,7 +264,7 @@ public class DatabaseService(
}
/// <returns> assets/database/templates/items.json </returns>
public Dictionary<string, TemplateItem> GetItems()
public Dictionary<MongoId, TemplateItem> GetItems()
{
if (_databaseServer.GetTables().Templates?.Items == null)
{
@@ -423,6 +424,20 @@ public class DatabaseService(
return true;
}
private bool ValidateTable<T>(Dictionary<MongoId, T> table, string tableType)
{
foreach (var keyValuePair in table)
{
if (!_hashUtil.IsValidMongoId(keyValuePair.Key))
{
_logger.Error($"Invalid {tableType} ID: '{keyValuePair.Key}'");
return false;
}
}
return true;
}
/// <summary>
/// Check if the database is valid
/// </summary>
@@ -1552,10 +1552,11 @@ public class FenceService(
// Randomise armor durability
if (
itemDetails.Parent
is BaseClasses.ARMORED_EQUIPMENT
or BaseClasses.FACECOVER
or BaseClasses.ARMOR_PLATE
(
itemDetails.Parent == BaseClasses.ARMORED_EQUIPMENT
|| itemDetails.Parent == BaseClasses.FACECOVER
|| itemDetails.Parent == BaseClasses.ARMOR_PLATE
)
&& itemDetails.Properties.MaxDurability.GetValueOrDefault(0) > 0
)
{
@@ -1,4 +1,5 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
@@ -16,10 +17,10 @@ public class ItemFilterService(
ConfigServer _configServer
)
{
protected readonly HashSet<string>? _itemBlacklistCache = [];
protected readonly HashSet<MongoId>? _itemBlacklistCache = [];
protected readonly ItemConfig _itemConfig = _configServer.GetConfig<ItemConfig>();
protected readonly HashSet<string>? _lootableItemBlacklistCache = [];
protected readonly HashSet<MongoId>? _lootableItemBlacklistCache = [];
/// <summary>
/// Check if the provided template id is blacklisted in config/item.json/blacklist
@@ -50,7 +51,7 @@ public class ItemFilterService(
/// Get an HashSet of items that should never be given as a reward to player
/// </summary>
/// <returns> HashSet of item tpls </returns>
public HashSet<string> GetItemRewardBlacklist()
public HashSet<MongoId> GetItemRewardBlacklist()
{
return _cloner.Clone(_itemConfig.RewardItemBlacklist);
}
@@ -59,7 +60,7 @@ public class ItemFilterService(
/// Get an HashSet of item types that should never be given as a reward to player
/// </summary>
/// <returns> HashSet of item base ids </returns>
public HashSet<string> GetItemRewardBaseTypeBlacklist()
public HashSet<MongoId> GetItemRewardBaseTypeBlacklist()
{
return _cloner.Clone(_itemConfig.RewardItemTypeBlacklist);
}
@@ -68,7 +69,7 @@ public class ItemFilterService(
/// Return every template id blacklisted in config/item.json
/// </summary>
/// <returns> HashSet of blacklisted template ids </returns>
public HashSet<string> GetBlacklistedItems()
public HashSet<MongoId> GetBlacklistedItems()
{
return _cloner.Clone(_itemConfig.Blacklist);
}
@@ -77,7 +78,7 @@ public class ItemFilterService(
/// Return every template id blacklisted in config/item.json/lootableItemBlacklist
/// </summary>
/// <returns> HashSet of blacklisted template ids </returns>
public HashSet<string> GetBlacklistedLootableItems()
public HashSet<MongoId> GetBlacklistedLootableItems()
{
return _cloner.Clone(_itemConfig.LootableItemBlacklist);
}
@@ -96,7 +97,7 @@ public class ItemFilterService(
/// Return boss items in config/item.json
/// </summary>
/// <returns> HashSet of boss item template ids </returns>
public HashSet<string> GetBossItems()
public HashSet<MongoId> GetBossItems()
{
return _cloner.Clone(_itemConfig.BossItems).ToHashSet();
}
@@ -1,6 +1,7 @@
using System.Reflection;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Spt.Mod;
@@ -320,7 +321,7 @@ public class CustomItemService(
return;
}
var baseWeaponModObject = new Dictionary<string, HashSet<string>?>();
var baseWeaponModObject = new Dictionary<string, HashSet<MongoId>?>();
// Get all slots weapon has and create a dictionary of them with possible mods that slot into each
var weaponSlots = weapon.Value.Properties.Slots;
@@ -2,6 +2,7 @@ using System.Text.RegularExpressions;
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;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Hideout;
@@ -862,7 +863,7 @@ public class ProfileFixerService(
protected bool ShouldRemoveWeaponEquipmentBuild(
string buildType,
UserBuild build,
Dictionary<string, TemplateItem> itemsDb
Dictionary<MongoId, TemplateItem> itemsDb
)
{
if (buildType == "weapon")
@@ -931,7 +932,7 @@ public class ProfileFixerService(
/// <returns> True if the build should be removed from the build list, false otherwise </returns>
protected bool ShouldRemoveMagazineBuild(
MagazineBuild magazineBuild,
Dictionary<string, TemplateItem> itemsDb
Dictionary<MongoId, TemplateItem> itemsDb
)
{
foreach (var item in magazineBuild.Items)
@@ -1,5 +1,6 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Utils;
@@ -13,9 +14,9 @@ public class RagfairLinkedItemService(
ISptLogger<RagfairLinkedItemService> logger
)
{
protected readonly Dictionary<string, HashSet<string>> linkedItemsCache = new();
protected readonly Dictionary<string, HashSet<MongoId>> linkedItemsCache = new();
public HashSet<string> GetLinkedItems(string linkedSearchId)
public HashSet<MongoId> GetLinkedItems(string linkedSearchId)
{
if (!linkedItemsCache.TryGetValue(linkedSearchId, out var set))
{
@@ -60,7 +61,7 @@ public class RagfairLinkedItemService(
/// </summary>
protected void BuildLinkedItemTable()
{
var linkedItems = new Dictionary<string, HashSet<string>>();
var linkedItems = new Dictionary<string, HashSet<MongoId>>();
foreach (var item in databaseService.GetItems().Values)
{
@@ -117,7 +118,7 @@ public class RagfairLinkedItemService(
/// <param name="itemLinkedSet"> Set to add to </param>
protected void AddRevolverCylinderAmmoToLinkedItems(
TemplateItem cylinder,
HashSet<string> itemLinkedSet
HashSet<MongoId> itemLinkedSet
)
{
var cylinderMod = cylinder.Properties.Slots?.FirstOrDefault(x => x.Name == "mod_magazine");
@@ -144,9 +145,9 @@ public class RagfairLinkedItemService(
/// </summary>
/// <param name="item">Db item to get tpls from</param>
/// <returns>Set of tpls</returns>
protected HashSet<string> GetSlotFilters(TemplateItem item)
protected HashSet<MongoId> GetSlotFilters(TemplateItem item)
{
var result = new HashSet<string>();
var result = new HashSet<MongoId>();
var slots = item.Properties?.Slots;
if (slots is null || slots.Count == 0)
@@ -172,9 +173,9 @@ public class RagfairLinkedItemService(
return result;
}
protected HashSet<string> GetChamberFilters(TemplateItem item)
protected HashSet<MongoId> GetChamberFilters(TemplateItem item)
{
var result = new HashSet<string>();
var result = new HashSet<MongoId>();
var chambers = item.Properties?.Chambers;
if (chambers is null || chambers.Count == 0)
@@ -198,9 +199,9 @@ public class RagfairLinkedItemService(
return result;
}
protected HashSet<string> GetCartridgeFilters(TemplateItem item)
protected HashSet<MongoId> GetCartridgeFilters(TemplateItem item)
{
var result = new HashSet<string>();
var result = new HashSet<MongoId>();
var cartridges = item.Properties?.Cartridges;
if (cartridges is null || cartridges.Count == 0)
@@ -2,6 +2,7 @@ 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;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
@@ -151,17 +152,17 @@ public class SeasonalEventService(
/// or, if halloween and christmas are inactive, return both sets of items
/// </summary>
/// <returns>array of tpl strings</returns>
public HashSet<string> GetInactiveSeasonalEventItems()
public HashSet<MongoId> GetInactiveSeasonalEventItems()
{
var items = new HashSet<string>();
var items = new HashSet<MongoId>();
if (!ChristmasEventEnabled())
{
items.UnionWith(_christmasEventItems);
items.UnionWith(_christmasEventItems.ToMongoIds());
}
if (!HalloweenEventEnabled())
{
items.UnionWith(_halloweenEventItems);
items.UnionWith(_halloweenEventItems.ToMongoIds());
}
return items;
@@ -144,14 +144,14 @@ public class ProbabilityObjectArray<K, V> : List<ProbabilityObject<K, V>>
return this.Min(x => x.RelativeProbability.Value);
}
/**
* Draw random element of the ProbabilityObject N times to return an array of N keys.
* Drawing can be with or without replacement
* @param count The number of times we want to draw
* @param removeAfterDraw Draw with or without replacement from the input dict (true = dont remove after drawing)
* @param lockList list keys which shall be replaced even if drawing without replacement
* @returns Array consisting of N random keys for this ProbabilityObjectArray
*/
/// <summary>
/// Draw random element of the ProbabilityObject N times to return an array of N keys.
/// Drawing can be with or without replacement
/// </summary>
/// <param name="drawCount">The number of times we want to draw</param>
/// <param name="removeAfterDraw">Draw with or without replacement from the input dict (true = don't remove after drawing)</param>
/// <param name="neverRemoveWhitelist">List of keys which shall be replaced even if drawing without replacement</param>
/// <returns>Collection consisting of N random keys for this ProbabilityObjectArray</returns>
public List<K> Draw(
int drawCount = 1,
bool removeAfterDraw = true,
+6 -9
View File
@@ -3,6 +3,7 @@ using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Callbacks;
using SPTarkov.Server.Core.DI;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Utils;
@@ -26,7 +27,7 @@ public class ItemTplGenerator(
private readonly HashSet<string> collidedEnumKeys = [];
private string _enumDir;
private IDictionary<string, string> _itemOverrides;
private Dictionary<string, TemplateItem> _items;
private Dictionary<MongoId, TemplateItem> _items;
public async Task Run()
{
@@ -420,20 +421,16 @@ public class ItemTplGenerator(
private string GetAmmoBoxPrefix(TemplateItem item)
{
var ammoItem = item.Properties?.StackSlots?[0]?.Props?.Filters?[
0
]?.Filter?.FirstOrDefault();
var ammoTpl = item.Properties?.StackSlots?[0]?.Props?.Filters?[0]?.Filter?.FirstOrDefault();
return GetAmmoPrefix(_items[ammoItem]);
return GetAmmoPrefix(_items[ammoTpl.Value]);
}
private string GetMagazinePrefix(TemplateItem item)
{
var ammoItem = item.Properties?.Cartridges?[0]?.Props?.Filters?[
0
]?.Filter?.FirstOrDefault();
var ammoTpl = item.Properties?.Cartridges?[0]?.Props?.Filters?[0]?.Filter?.FirstOrDefault();
return GetAmmoPrefix(_items[ammoItem]);
return GetAmmoPrefix(_items[ammoTpl.Value]);
}
/// <summary>