diff --git a/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs b/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs index b8b144f8..204e7247 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs @@ -244,7 +244,7 @@ public class InsuranceController( protected Dictionary> PopulateParentAttachmentsMap( string rootItemParentID, Insurance insured, - Dictionary itemsMap + Dictionary itemsMap ) { var mainParentToAttachmentsMap = new Dictionary>(); @@ -340,7 +340,7 @@ public class InsuranceController( /// protected Dictionary> RemoveNonModdableAttachments( Dictionary> parentAttachmentsMap, - Dictionary itemsMap + Dictionary itemsMap ) { var updatedMap = new Dictionary>(); @@ -442,7 +442,7 @@ public class InsuranceController( /// Tracked attachment ids to be removed protected void ProcessAttachments( Dictionary> mainParentToAttachmentsMap, - Dictionary itemsMap, + Dictionary itemsMap, string? insuredTraderId, HashSet toDelete ) diff --git a/Libraries/SPTarkov.Server.Core/Controllers/RagfairController.cs b/Libraries/SPTarkov.Server.Core/Controllers/RagfairController.cs index f52d0dc7..01132526 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/RagfairController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/RagfairController.cs @@ -324,7 +324,7 @@ public class RagfairController /// Client search request data /// Ragfair offers to get categories for /// Record with templates + counts - protected Dictionary GetSpecificCategories( + protected Dictionary GetSpecificCategories( PmcData pmcProfile, SearchRequestData searchRequest, List offers @@ -352,7 +352,7 @@ public class RagfairController _logger.Debug(_jsonUtil.Serialize(searchRequest)); } - return new Dictionary(); + return []; } return _ragfairServer.GetAllActiveCategories( diff --git a/Libraries/SPTarkov.Server.Core/Extensions/ItemExtensions.cs b/Libraries/SPTarkov.Server.Core/Extensions/ItemExtensions.cs index 18c42444..be57b0c0 100644 --- a/Libraries/SPTarkov.Server.Core/Extensions/ItemExtensions.cs +++ b/Libraries/SPTarkov.Server.Core/Extensions/ItemExtensions.cs @@ -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 /// /// Collection of items /// Dictionary of items - public static Dictionary GenerateItemsMap(this IEnumerable items) + public static Dictionary GenerateItemsMap(this IEnumerable 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. diff --git a/Libraries/SPTarkov.Server.Core/Generators/LocationLootGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/LocationLootGenerator.cs index 1752fe67..aa60da68 100644 --- a/Libraries/SPTarkov.Server.Core/Generators/LocationLootGenerator.cs +++ b/Libraries/SPTarkov.Server.Core/Generators/LocationLootGenerator.cs @@ -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" diff --git a/Libraries/SPTarkov.Server.Core/Helpers/ItemHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/ItemHelper.cs index acc60e67..b1e0ab51 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/ItemHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/ItemHelper.cs @@ -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)); } /// @@ -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); } + /// + /// Temporary until we have better MongoId handling + /// + /// + /// + /// + public bool IsOfBaseclasses(string tpl, ICollection baseClassTpls) + { + List MongoList = []; + + foreach (var baseTpl in baseClassTpls) + { + MongoList.Add(baseTpl); + } + + return _itemBaseClassService.ItemHasBaseClass(tpl, MongoList); + } + /// /// 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( /// /// item tpls to look up the price of /// Total price in roubles - public double GetItemAndChildrenPrice(IEnumerable tpls) + public double GetItemAndChildrenPrice(IEnumerable 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( /// The unique identifier of the item for which to find the main parent. /// A Dictionary containing item IDs mapped to their corresponding Item objects for quick lookup. /// The Item object representing the top-most parent of the given item, or null if no such parent exists. - public Item? GetAttachmentMainParent(string itemId, Dictionary itemsMap) + public Item? GetAttachmentMainParent(string itemId, Dictionary itemsMap) { var currentItem = itemsMap.FirstOrDefault(x => x.Key == itemId).Value; @@ -1337,10 +1350,7 @@ public class ItemHelper( public ItemSize GetItemSize(ICollection 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; diff --git a/Libraries/SPTarkov.Server.Core/Helpers/PresetHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/PresetHelper.cs index b3fd6287..3603799f 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/PresetHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/PresetHelper.cs @@ -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 /// /// dictionary of presets keyed by the root items tpl - public Dictionary GetDefaultPresetsByTplKey() + public Dictionary GetDefaultPresetsByTplKey() { // Weapons and equipment keyed by their preset id var weapons = GetDefaultWeaponPresets().Values; diff --git a/Libraries/SPTarkov.Server.Core/Models/Common/MongoId.cs b/Libraries/SPTarkov.Server.Core/Models/Common/MongoId.cs index f8cbdb3a..313e2514 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Common/MongoId.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Common/MongoId.cs @@ -126,7 +126,17 @@ public readonly partial struct MongoId : IEquatable return _stringId.GetHashCode(); } - public MongoId Empty() + public bool IsEmpty() + { + if (_stringId == "000000000000000000000000") + { + return true; + } + + return false; + } + + public static MongoId Empty() { return new MongoId("000000000000000000000000"); } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/Item.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/Item.cs index a57ad2b3..86e3837a 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/Item.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/Item.cs @@ -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? 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 /// [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; } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/Trader.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/Trader.cs index 565008ee..f1eeebb0 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/Trader.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/Trader.cs @@ -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? Category { get; set; } + public required List Category { get; set; } // MongoId [JsonPropertyName("id_list")] - public List? IdList { get; set; } + public required List IdList { get; set; } } public record ItemSellData @@ -150,10 +151,10 @@ public record ItemSellData public Dictionary? ExtensionData { get; set; } [JsonPropertyName("category")] - public required List Category { get; set; } + public required List Category { get; set; } [JsonPropertyName("id_list")] - public required List IdList { get; set; } + public required List IdList { get; set; } } public record TraderInsurance @@ -166,7 +167,7 @@ public record TraderInsurance // MongoId [JsonPropertyName("excluded_category")] - public List? ExcludedCategory { get; set; } + public List? 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; } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Ragfair/GetOffersResult.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Ragfair/GetOffersResult.cs index 8c4f57f7..3683bd12 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Ragfair/GetOffersResult.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Ragfair/GetOffersResult.cs @@ -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? ExtensionData { get; set; } [JsonPropertyName("categories")] - public Dictionary? Categories { get; set; } + public Dictionary? Categories { get; set; } [JsonPropertyName("offers")] public List? Offers { get; set; } diff --git a/Libraries/SPTarkov.Server.Core/Servers/RagfairServer.cs b/Libraries/SPTarkov.Server.Core/Servers/RagfairServer.cs index 09f44ce2..fb9f9349 100644 --- a/Libraries/SPTarkov.Server.Core/Servers/RagfairServer.cs +++ b/Libraries/SPTarkov.Server.Core/Servers/RagfairServer.cs @@ -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 GetAllActiveCategories( + public Dictionary GetAllActiveCategories( bool fleaUnlocked, SearchRequestData searchRequestData, List offers diff --git a/Libraries/SPTarkov.Server.Core/Services/CircleOfCultistService.cs b/Libraries/SPTarkov.Server.Core/Services/CircleOfCultistService.cs index cc3a0450..1f6bea9a 100644 --- a/Libraries/SPTarkov.Server.Core/Services/CircleOfCultistService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/CircleOfCultistService.cs @@ -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 sacrificedItemTpls = sacrificedItems + IEnumerable 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(); } + /// + /// Temporary until MongoId conversion is done, should be removed and the mongoid one kept in place + /// + /// + /// protected string CreateSacrificeCacheKey(IEnumerable requiredItems) { var concat = string.Join(",", requiredItems.OrderBy(item => item)); return _hashUtil.GenerateHashForData(HashingAlgorithm.MD5, concat); } + protected string CreateSacrificeCacheKey(IEnumerable requiredItems) + { + var concat = string.Join(",", requiredItems.OrderBy(item => item)); + return _hashUtil.GenerateHashForData(HashingAlgorithm.MD5, concat); + } + /// /// Create a map of the possible direct rewards, keyed by the items needed to be sacrificed /// diff --git a/Libraries/SPTarkov.Server.Core/Services/RagfairCategoriesService.cs b/Libraries/SPTarkov.Server.Core/Services/RagfairCategoriesService.cs index b42fd63a..72081d93 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RagfairCategoriesService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RagfairCategoriesService.cs @@ -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( /// Search criteria requested /// Can player see full flea yet (level 15 by default) /// KVP of item tpls + count of offers - public Dictionary GetCategoriesFromOffers( + public Dictionary GetCategoriesFromOffers( List offers, SearchRequestData searchRequestData, bool fleaUnlocked diff --git a/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/SptJsonConverterRegistrator.cs b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/SptJsonConverterRegistrator.cs index a16f736e..1491f9c5 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/SptJsonConverterRegistrator.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/SptJsonConverterRegistrator.cs @@ -16,6 +16,7 @@ public class SptJsonConverterRegistrator : IJsonConverterRegistrator new DictionaryOrListConverter(), new EftEnumConverter(), // Special case, this belongs to a lib. new BaseInteractionRequestDataConverter(), + new StringToMongoIdConverter(), .. GetGenericJsonConverters(), ]; } diff --git a/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/StringToMongoIdConverter.cs b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/StringToMongoIdConverter.cs new file mode 100644 index 00000000..aa4684aa --- /dev/null +++ b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/StringToMongoIdConverter.cs @@ -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 + { + 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()); + } + } +}