Begin converting some id's to MongoId (#435)

* Begin converting some id's to MongoId

* Remove nullability on MongoId's

* Update trader MongoId's
This commit is contained in:
Jesse
2025-06-30 16:25:47 +02:00
committed by GitHub
parent 0ec544e6a3
commit 6ac747d18d
15 changed files with 142 additions and 68 deletions
@@ -244,7 +244,7 @@ public class InsuranceController(
protected Dictionary<string, List<Item>> PopulateParentAttachmentsMap(
string rootItemParentID,
Insurance insured,
Dictionary<string, Item> itemsMap
Dictionary<MongoId, Item> itemsMap
)
{
var mainParentToAttachmentsMap = new Dictionary<string, List<Item>>();
@@ -340,7 +340,7 @@ public class InsuranceController(
/// <returns></returns>
protected Dictionary<string, List<Item>> RemoveNonModdableAttachments(
Dictionary<string, List<Item>> parentAttachmentsMap,
Dictionary<string, Item> itemsMap
Dictionary<MongoId, Item> itemsMap
)
{
var updatedMap = new Dictionary<string, List<Item>>();
@@ -442,7 +442,7 @@ public class InsuranceController(
/// <param name="toDelete">Tracked attachment ids to be removed</param>
protected void ProcessAttachments(
Dictionary<string, List<Item>> mainParentToAttachmentsMap,
Dictionary<string, Item> itemsMap,
Dictionary<MongoId, Item> itemsMap,
string? insuredTraderId,
HashSet<string> toDelete
)
@@ -324,7 +324,7 @@ public class RagfairController
/// <param name="searchRequest">Client search request data</param>
/// <param name="offers">Ragfair offers to get categories for</param>
/// <returns>Record with templates + counts</returns>
protected Dictionary<string, int> GetSpecificCategories(
protected Dictionary<MongoId, int> GetSpecificCategories(
PmcData pmcProfile,
SearchRequestData searchRequest,
List<RagfairOffer> offers
@@ -352,7 +352,7 @@ public class RagfairController
_logger.Debug(_jsonUtil.Serialize(searchRequest));
}
return new Dictionary<string, int>();
return [];
}
return _ragfairServer.GetAllActiveCategories(
@@ -1,4 +1,5 @@
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
{
@@ -119,9 +120,7 @@ namespace SPTarkov.Server.Core.Extensions
)
{
// Get items parent
var parent = items.FirstOrDefault(item =>
item.Id.Equals(itemToCheck.ParentId, StringComparison.OrdinalIgnoreCase)
);
var parent = items.FirstOrDefault(item => item.Id.Equals(itemToCheck.ParentId));
if (parent is null)
// No parent, end of line, not inside container
{
@@ -156,7 +155,7 @@ namespace SPTarkov.Server.Core.Extensions
/// </summary>
/// <param name="items">Collection of items</param>
/// <returns>Dictionary of items</returns>
public static Dictionary<string, Item> GenerateItemsMap(this IEnumerable<Item> items)
public static Dictionary<MongoId, Item> GenerateItemsMap(this IEnumerable<Item> items)
{
// Convert list to dictionary, keyed by items Id
return items.ToDictionary(item => item.Id);
@@ -175,9 +174,7 @@ namespace SPTarkov.Server.Core.Extensions
foreach (var item in items)
{
// Check if the item's parent exists.
var parentExists = items.Any(parentItem =>
parentItem.Id.Equals(item.ParentId, StringComparison.OrdinalIgnoreCase)
);
var parentExists = items.Any(parentItem => parentItem.Id.Equals(item.ParentId));
// If the parent does not exist and the item is not already a 'hideout' item, adopt the orphaned item by
// setting the parent ID to the PMCs inventory equipment ID, the slot ID to 'hideout', and remove the location.
@@ -2,6 +2,7 @@ using System.Text.Json.Serialization;
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;
@@ -1084,8 +1085,9 @@ public class LocationLootGenerator(
)
{
var chosenItem = items.FirstOrDefault(item => item.Id == chosenComposedKey);
var chosenTpl = chosenItem?.Template;
if (chosenTpl is null)
MongoId chosenTpl = chosenItem?.Template ?? MongoId.Empty();
if (chosenTpl == null)
{
throw new Exception(
$"Item for tpl {chosenComposedKey} was not found in the spawn point"
@@ -1,6 +1,7 @@
using System.Collections.Frozen;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
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;
@@ -144,9 +145,7 @@ public class ItemHelper(
);
// Check if any item in the filtered pool matches the provided item
return filteredPool.FirstOrDefault(poolItem =>
poolItem.Template.Equals(tpl, StringComparison.OrdinalIgnoreCase)
);
return filteredPool.FirstOrDefault(poolItem => poolItem.Template.Equals(tpl));
}
/// <summary>
@@ -171,9 +170,7 @@ public class ItemHelper(
foreach (var itemOf1 in item1)
{
var itemOf2 = item2.FirstOrDefault(i2 =>
i2.Template.Equals(itemOf1.Template, StringComparison.OrdinalIgnoreCase)
);
var itemOf2 = item2.FirstOrDefault(i2 => i2.Template.Equals(itemOf1.Template));
if (itemOf2 is null)
{
return false;
@@ -327,6 +324,24 @@ public class ItemHelper(
return _itemBaseClassService.ItemHasBaseClass(tpl, baseClassTpls);
}
/// <summary>
/// Temporary until we have better MongoId handling
/// </summary>
/// <param name="tpl"></param>
/// <param name="baseClassTpls"></param>
/// <returns></returns>
public bool IsOfBaseclasses(string tpl, ICollection<MongoId> baseClassTpls)
{
List<string> MongoList = [];
foreach (var baseTpl in baseClassTpls)
{
MongoList.Add(baseTpl);
}
return _itemBaseClassService.ItemHasBaseClass(tpl, MongoList);
}
/// <summary>
/// Does the provided item have the chance to require soft armor inserts
/// Only applies to helmets/vest/armors
@@ -428,7 +443,7 @@ public class ItemHelper(
/// </summary>
/// <param name="tpls">item tpls to look up the price of</param>
/// <returns>Total price in roubles</returns>
public double GetItemAndChildrenPrice(IEnumerable<string> tpls)
public double GetItemAndChildrenPrice(IEnumerable<MongoId> tpls)
{
// Run getItemPrice for each tpl in tpls array, return sum
return tpls.Aggregate(
@@ -910,9 +925,7 @@ public class ItemHelper(
{
var filterResult = itemsToSearch.Where(item =>
{
return by == "tpl"
? item.Template.Equals(barterId, StringComparison.OrdinalIgnoreCase)
: item.Id.Equals(barterId, StringComparison.OrdinalIgnoreCase);
return by == "tpl" ? item.Template.Equals(barterId) : item.Id.Equals(barterId);
});
matchingItems.AddRange(filterResult);
@@ -1266,7 +1279,7 @@ public class ItemHelper(
/// <param name="itemId">The unique identifier of the item for which to find the main parent.</param>
/// <param name="itemsMap">A Dictionary containing item IDs mapped to their corresponding Item objects for quick lookup.</param>
/// <returns>The Item object representing the top-most parent of the given item, or null if no such parent exists.</returns>
public Item? GetAttachmentMainParent(string itemId, Dictionary<string, Item> itemsMap)
public Item? GetAttachmentMainParent(string itemId, Dictionary<MongoId, Item> itemsMap)
{
var currentItem = itemsMap.FirstOrDefault(x => x.Key == itemId).Value;
@@ -1337,10 +1350,7 @@ public class ItemHelper(
public ItemSize GetItemSize(ICollection<Item> items, string rootItemId)
{
var rootTemplate = GetItem(
items
.Where(x => x.Id.Equals(rootItemId, StringComparison.OrdinalIgnoreCase))
.ToList()[0]
.Template
items.Where(x => x.Id.Equals(rootItemId)).ToList()[0].Template
).Value;
var width = rootTemplate.Properties.Width;
var height = rootTemplate.Properties.Height;
@@ -1432,11 +1442,7 @@ public class ItemHelper(
var cartridgeMaxStackSize = cartridgeDetails.Value.Properties.StackMaxSize;
// Exit early if ammo already exists in box
if (
ammoBox.Any(item =>
item.Template.Equals(cartridgeTpl, StringComparison.OrdinalIgnoreCase)
)
)
if (ammoBox.Any(item => item.Template.Equals(cartridgeTpl)))
{
return;
}
@@ -1931,7 +1937,7 @@ public class ItemHelper(
// Has parentId + no remapping exists for its parent
if (
mod.ParentId is not null
mod.ParentId != null
&& (!idMappings.ContainsKey(mod.ParentId) || idMappings?[mod.ParentId] is null)
)
// Make remapping for items parentId
@@ -1940,7 +1946,7 @@ public class ItemHelper(
}
mod.Id = idMappings[mod.Id];
if (mod.ParentId is not null)
if (mod.ParentId != null)
{
mod.ParentId = idMappings[mod.ParentId];
}
@@ -1973,7 +1979,7 @@ public class ItemHelper(
foreach (var item in itemWithChildren)
{
// Root, update id
if (item.Id.Equals(rootItemExistingId, StringComparison.OrdinalIgnoreCase))
if (item.Id.Equals(rootItemExistingId))
{
item.Id = newId;
@@ -1,4 +1,5 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Spt.Presets;
@@ -39,7 +40,7 @@ public class PresetHelper(DatabaseService _databaseService, ItemHelper _itemHelp
/// Get weapon and armor default presets, keyed to root items tpl
/// </summary>
/// <returns>dictionary of presets keyed by the root items tpl</returns>
public Dictionary<string, Preset> GetDefaultPresetsByTplKey()
public Dictionary<MongoId, Preset> GetDefaultPresetsByTplKey()
{
// Weapons and equipment keyed by their preset id
var weapons = GetDefaultWeaponPresets().Values;
@@ -126,7 +126,17 @@ public readonly partial struct MongoId : IEquatable<MongoId>
return _stringId.GetHashCode();
}
public MongoId Empty()
public bool IsEmpty()
{
if (_stringId == "000000000000000000000000")
{
return true;
}
return false;
}
public static MongoId Empty()
{
return new MongoId("000000000000000000000000");
}
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Utils.Json.Converters;
@@ -9,29 +10,17 @@ public record Item
[JsonExtensionData]
public Dictionary<string, object>? ExtensionData { get; set; }
private string? _id;
private string? _parentId;
private string? _SlotId;
private string? _tpl;
// MongoId
[JsonPropertyName("_id")]
public string? Id
{
get { return _id; }
set { _id = string.Intern(value); }
}
public required MongoId Id { get; set; }
[JsonPropertyName("_tpl")]
// MongoId
public string? Template
{
get { return _tpl; }
set { _tpl = string.Intern(value); }
}
public MongoId Template { get; set; }
[JsonPropertyName("parentId")]
public string? ParentId
@@ -66,7 +55,7 @@ public record HideoutItem
/// Hideout inventory id that was used by improvement action
/// </summary>
[JsonPropertyName("_id")]
public string? _Id
public MongoId _Id
{
get { return Id; }
set
@@ -81,10 +70,10 @@ public record HideoutItem
}
[JsonPropertyName("id")]
public string? Id { get; set; }
public required MongoId Id { get; set; }
[JsonPropertyName("_tpl")]
public string? Template { get; set; }
public required MongoId Template { get; set; }
[JsonPropertyName("upd")]
public Upd? Upd { get; set; }
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Spt.Services;
using SPTarkov.Server.Core.Utils.Json.Converters;
@@ -38,7 +39,7 @@ public record TraderBase
public bool? RefreshTraderRagfairOffers { get; set; }
[JsonPropertyName("_id")]
public string? Id { get; set; }
public MongoId Id { get; set; }
[JsonPropertyName("availableInRaid")]
public bool? AvailableInRaid { get; set; }
@@ -137,11 +138,11 @@ public record ItemBuyData
// MongoId
[JsonPropertyName("category")]
public List<string>? Category { get; set; }
public required List<MongoId> Category { get; set; }
// MongoId
[JsonPropertyName("id_list")]
public List<string>? IdList { get; set; }
public required List<MongoId> IdList { get; set; }
}
public record ItemSellData
@@ -150,10 +151,10 @@ public record ItemSellData
public Dictionary<string, object>? ExtensionData { get; set; }
[JsonPropertyName("category")]
public required List<string> Category { get; set; }
public required List<MongoId> Category { get; set; }
[JsonPropertyName("id_list")]
public required List<string> IdList { get; set; }
public required List<MongoId> IdList { get; set; }
}
public record TraderInsurance
@@ -166,7 +167,7 @@ public record TraderInsurance
// MongoId
[JsonPropertyName("excluded_category")]
public List<string>? ExcludedCategory { get; set; }
public List<MongoId>? ExcludedCategory { get; set; }
// Confirmed in client
[JsonPropertyName("max_return_hour")]
@@ -225,7 +226,7 @@ public record TraderRepair
public bool? Availability { get; set; }
[JsonPropertyName("currency")]
public string? Currency { get; set; }
public MongoId Currency { get; set; }
[JsonPropertyName("currency_coefficient")]
public double? CurrencyCoefficient { get; set; }
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Models.Common;
namespace SPTarkov.Server.Core.Models.Eft.Ragfair;
@@ -8,7 +9,7 @@ public record GetOffersResult
public Dictionary<string, object>? ExtensionData { get; set; }
[JsonPropertyName("categories")]
public Dictionary<string, int>? Categories { get; set; }
public Dictionary<MongoId, int>? Categories { get; set; }
[JsonPropertyName("offers")]
public List<RagfairOffer>? Offers { get; set; }
@@ -1,5 +1,6 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Ragfair;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Spt.Config;
@@ -81,7 +82,7 @@ public class RagfairServer(
return _ragfairConfig.Traders.Keys.ToList();
}
public Dictionary<string, int> GetAllActiveCategories(
public Dictionary<MongoId, int> GetAllActiveCategories(
bool fleaUnlocked,
SearchRequestData searchRequestData,
List<RagfairOffer> offers
@@ -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.Eft.Hideout;
@@ -552,7 +553,7 @@ public class CircleOfCultistService(
)
{
// Get sacrificed tpls
IEnumerable<string> sacrificedItemTpls = sacrificedItems
IEnumerable<MongoId> sacrificedItemTpls = sacrificedItems
.Select(item => item.Template)
.Where(item => item != null);
// Create md5 key of the items player sacrificed so we can compare against the direct reward cache
@@ -964,12 +965,23 @@ public class CircleOfCultistService(
return requirements.Where(requirement => requirement.Type == "Item").ToList();
}
/// <summary>
/// Temporary until MongoId conversion is done, should be removed and the mongoid one kept in place
/// </summary>
/// <param name="requiredItems"></param>
/// <returns></returns>
protected string CreateSacrificeCacheKey(IEnumerable<string> requiredItems)
{
var concat = string.Join(",", requiredItems.OrderBy(item => item));
return _hashUtil.GenerateHashForData(HashingAlgorithm.MD5, concat);
}
protected string CreateSacrificeCacheKey(IEnumerable<MongoId> requiredItems)
{
var concat = string.Join(",", requiredItems.OrderBy(item => item));
return _hashUtil.GenerateHashForData(HashingAlgorithm.MD5, concat);
}
/// <summary>
/// Create a map of the possible direct rewards, keyed by the items needed to be sacrificed
/// </summary>
@@ -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.Ragfair;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Utils;
@@ -19,7 +20,7 @@ public class RagfairCategoriesService(
/// <param name="searchRequestData">Search criteria requested</param>
/// <param name="fleaUnlocked">Can player see full flea yet (level 15 by default)</param>
/// <returns>KVP of item tpls + count of offers</returns>
public Dictionary<string, int> GetCategoriesFromOffers(
public Dictionary<MongoId, int> GetCategoriesFromOffers(
List<RagfairOffer> offers,
SearchRequestData searchRequestData,
bool fleaUnlocked
@@ -16,6 +16,7 @@ public class SptJsonConverterRegistrator : IJsonConverterRegistrator
new DictionaryOrListConverter(),
new EftEnumConverter<LogLevel>(), // Special case, this belongs to a lib.
new BaseInteractionRequestDataConverter(),
new StringToMongoIdConverter(),
.. GetGenericJsonConverters(),
];
}
@@ -0,0 +1,52 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using SPTarkov.Server.Core.Models.Common;
namespace SPTarkov.Server.Core.Utils.Json.Converters
{
public class StringToMongoIdConverter : JsonConverter<MongoId>
{
public override MongoId Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options
)
{
if (reader.TokenType == JsonTokenType.String)
{
return new MongoId(reader.GetString());
}
throw new JsonException();
}
public override void Write(
Utf8JsonWriter writer,
MongoId mongoId,
JsonSerializerOptions options
)
{
JsonSerializer.Serialize(writer, mongoId.ToString(), options);
}
// Deserialize MongoId as a dictionary key
public override MongoId ReadAsPropertyName(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options
)
{
return new MongoId(reader.GetString());
}
// Serialize MongoId as a dictionary key
public override void WriteAsPropertyName(
Utf8JsonWriter writer,
MongoId value,
JsonSerializerOptions options
)
{
writer.WritePropertyName(value.ToString());
}
}
}