From 8474f40aa878a15fb0c8efdef47302b4a22162a3 Mon Sep 17 00:00:00 2001 From: Chomp Date: Mon, 7 Jul 2025 12:31:13 +0100 Subject: [PATCH] More MongoId changes + updated nullability of EOH objects --- .../Controllers/DialogueController.cs | 2 +- .../Controllers/HideoutController.cs | 26 +++++----- .../Helpers/HideoutHelper.cs | 12 ++--- .../Models/Eft/Common/Tables/BotBase.cs | 51 +++++-------------- .../Eft/ItemEvent/ItemEventRouterBase.cs | 4 +- .../Models/Eft/Profile/UserDialogInfo.cs | 3 +- .../Routers/EventOutputHolder.cs | 51 +++++++++++-------- .../Services/PmcChatResponseService.cs | 4 +- 8 files changed, 64 insertions(+), 89 deletions(-) diff --git a/Libraries/SPTarkov.Server.Core/Controllers/DialogueController.cs b/Libraries/SPTarkov.Server.Core/Controllers/DialogueController.cs index 30b37e87..b6de0bd7 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/DialogueController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/DialogueController.cs @@ -355,7 +355,7 @@ public class DialogueController( result.Add( new UserDialogInfo { - Id = fullProfile.ProfileInfo?.ProfileId, + Id = fullProfile.ProfileInfo.ProfileId.Value, Aid = fullProfile.ProfileInfo?.Aid, Info = new UserDialogDetails { diff --git a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs index 959b4928..29f59712 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs @@ -1547,27 +1547,24 @@ public class HideoutController( return httpResponseUtil.AppendErrorToOutput(output); } - // Add all improvemets to output object + // Add all improvements to output object var improvements = hideoutDbData.Stages[profileHideoutArea.Level.ToString()].Improvements; var timestamp = timeUtil.GetTimeStamp(); - if (output.ProfileChanges[sessionId].Improvements is null) - { - output.ProfileChanges[sessionId].Improvements = - new Dictionary(); - } + // nullguard + output.ProfileChanges[sessionId].Improvements ??= []; - foreach (var improvement in improvements) + foreach (var stageImprovement in improvements) { var improvementDetails = new HideoutImprovement { Completed = false, - ImproveCompleteTimestamp = (long)(timestamp + improvement.ImprovementTime), + ImproveCompleteTimestamp = (long)(timestamp + stageImprovement.ImprovementTime), }; - output.ProfileChanges[sessionId].Improvements[improvement.Id] = improvementDetails; + output.ProfileChanges[sessionId].Improvements[stageImprovement.Id] = improvementDetails; - pmcData.Hideout.Improvements ??= new Dictionary(); - pmcData.Hideout.Improvements[improvement.Id] = improvementDetails; + pmcData.Hideout.Improvements ??= []; + pmcData.Hideout.Improvements[stageImprovement.Id] = improvementDetails; } return output; @@ -1662,8 +1659,9 @@ public class HideoutController( return output; } - pmcData.Hideout.Customization[GetHideoutCustomisationType(itemDetails.Type)] = - itemDetails.ItemId; + pmcData.Hideout.Customization[GetHideoutCustomisationType(itemDetails.Type)] = itemDetails + .ItemId + .Value; return output; } @@ -1774,7 +1772,7 @@ public class HideoutController( foreach (var poseKvP in request.Poses) { // Nullguard - pmcData.Hideout.MannequinPoses ??= new Dictionary(); + pmcData.Hideout.MannequinPoses ??= []; pmcData.Hideout.MannequinPoses[poseKvP.Key] = poseKvP.Value; } diff --git a/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs index 7097aa12..74b93909 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs @@ -67,10 +67,7 @@ public class HideoutHelper( // @Important: Here we need to be very exact: // - normal recipe: Production time value is stored in attribute "productionType" with small "p" // - scav case recipe: Production time value is stored in attribute "ProductionType" with capital "P" - if (pmcData.Hideout?.Production is null) - { - pmcData.Hideout.Production = new Dictionary(); - } + pmcData.Hideout.Production ??= []; var modifiedProductionTime = GetAdjustedCraftTimeWithSkills( pmcData, @@ -146,10 +143,7 @@ public class HideoutHelper( // @Important: Here we need to be very exact: // - normal recipe: Production time value is stored in attribute "productionType" with small "p" // - scav case recipe: Production time value is stored in attribute "ProductionType" with capital "P" - if (pmcData.Hideout?.Production is null) - { - pmcData.Hideout.Production = new Dictionary(); - } + pmcData.Hideout.Production ??= []; var modifiedProductionTime = GetAdjustedCraftTimeWithSkills( pmcData, @@ -162,7 +156,7 @@ public class HideoutHelper( recipe.NeedFuelForAllProductionTime ); - pmcData.Hideout.Production[productionRequest.RecipeId] = production; + pmcData.Hideout.Production[productionRequest.RecipeId.Value] = production; } /// diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/BotBase.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/BotBase.cs index 8c2e98df..69a8aa5b 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/BotBase.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/BotBase.cs @@ -108,7 +108,7 @@ public record BotBase public DictionaryOrList? WishList { get; set; } [JsonPropertyName("moneyTransferLimitData")] - public MoneyTransferLimits? MoneyTransferLimitData { get; set; } + public MoneyTransferLimits MoneyTransferLimitData { get; set; } /// /// SPT specific property used during bot generation in raid @@ -166,7 +166,7 @@ public record UnlockedInfo public Dictionary? ExtensionData { get; set; } [JsonPropertyName("unlockedProductionRecipe")] - public HashSet? UnlockedProductionRecipe { get; set; } + public HashSet? UnlockedProductionRecipe { get; set; } } public record Info @@ -458,7 +458,7 @@ public record BotBaseInventory [JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonPropertyName("hideoutAreaStashes")] // TODO: key should be EAreaType enum - public Dictionary? HideoutAreaStashes { get; set; } + public Dictionary? HideoutAreaStashes { get; set; } // Key = hideout area key as string [JsonPropertyName("fastPanel")] public Dictionary? FastPanel { get; set; } @@ -569,7 +569,7 @@ public record DroppedItem [JsonExtensionData] public Dictionary? ExtensionData { get; set; } - public string? QuestId { get; set; } + public MongoId QuestId { get; set; } public MongoId? ItemId { get; set; } @@ -581,7 +581,7 @@ public record FoundInRaidItem [JsonExtensionData] public Dictionary? ExtensionData { get; set; } - public string? QuestId { get; set; } + public MongoId QuestId { get; set; } public MongoId? ItemId { get; set; } } @@ -593,7 +593,7 @@ public record Victim public string? AccountId { get; set; } - public string? ProfileId { get; set; } + public MongoId? ProfileId { get; set; } public string? Name { get; set; } @@ -786,7 +786,7 @@ public record BackendCounter public string? Id { get; set; } [JsonPropertyName("qid")] - public string? QId { get; set; } + public MongoId? QId { get; set; } [JsonPropertyName("value")] public double? Value { get; set; } @@ -801,7 +801,7 @@ public record InsuredItem /// Trader ID item was insured by /// [JsonPropertyName("tid")] - public string? TId { get; set; } + public MongoId TId { get; set; } [JsonPropertyName("itemId")] public MongoId? ItemId { get; set; } @@ -812,11 +812,11 @@ public record Hideout [JsonExtensionData] public Dictionary? ExtensionData { get; set; } - public Dictionary? Production { get; set; } + public Dictionary? Production { get; set; } public List? Areas { get; set; } - public Dictionary? Improvements { get; set; } + public Dictionary? Improvements { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.Never)] public HideoutCounters? HideoutCounters { get; set; } @@ -826,12 +826,12 @@ public record Hideout /// public string? Seed { get; set; } - public Dictionary? MannequinPoses { get; set; } + public Dictionary? MannequinPoses { get; set; } [JsonPropertyName("sptUpdateLastRunTimestamp")] public long? SptUpdateLastRunTimestamp { get; set; } - public Dictionary? Customization { get; set; } + public Dictionary? Customization { get; set; } // Key = Area customisaion type as string, e.g. "Wall", "Light", "ShootingRangeMark" } public record HideoutCounters @@ -1016,33 +1016,6 @@ public enum SurvivorClass SURVIVOR = 4, } -public record Quests -{ - [JsonExtensionData] - public Dictionary? ExtensionData { get; set; } - - [JsonPropertyName("qid")] - public string? QId { get; set; } - - [JsonPropertyName("startTime")] - public long? StartTime { get; set; } - - [JsonPropertyName("status")] - public QuestStatusEnum? Status { get; set; } - - [JsonPropertyName("statusTimers")] - public Dictionary? StatusTimers { get; set; } - - /// - /// Property does not exist in live profile data, but is used by ProfileChanges.questsStatus when sent to client - /// - [JsonPropertyName("completedConditions")] - public List? CompletedConditions { get; set; } - - [JsonPropertyName("availableAfter")] - public long? AvailableAfter { get; set; } -} - public record TraderInfo { [JsonExtensionData] diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/ItemEvent/ItemEventRouterBase.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/ItemEvent/ItemEventRouterBase.cs index a4a45582..988b3531 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/ItemEvent/ItemEventRouterBase.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/ItemEvent/ItemEventRouterBase.cs @@ -65,13 +65,13 @@ public record ProfileChange [JsonIgnore(Condition = JsonIgnoreCondition.Never)] [JsonPropertyName("production")] - public Dictionary? Production { get; set; } + public Dictionary? Production { get; set; } /// /// Hideout area improvement id /// [JsonPropertyName("improvements")] - public Dictionary? Improvements { get; set; } + public Dictionary? Improvements { get; set; } [JsonPropertyName("skills")] public Skills? Skills { get; set; } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Profile/UserDialogInfo.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Profile/UserDialogInfo.cs index d2fa5bdf..d496b8e5 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Profile/UserDialogInfo.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Profile/UserDialogInfo.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Enums; namespace SPTarkov.Server.Core.Models.Eft.Profile; @@ -12,7 +13,7 @@ public record UserDialogInfo /// _id /// [JsonPropertyName("_id")] - public string? Id { get; set; } + public MongoId Id { get; set; } [JsonPropertyName("aid")] public int? Aid { get; set; } diff --git a/Libraries/SPTarkov.Server.Core/Routers/EventOutputHolder.cs b/Libraries/SPTarkov.Server.Core/Routers/EventOutputHolder.cs index 71653ff9..923b181a 100644 --- a/Libraries/SPTarkov.Server.Core/Routers/EventOutputHolder.cs +++ b/Libraries/SPTarkov.Server.Core/Routers/EventOutputHolder.cs @@ -70,8 +70,8 @@ public class EventOutputHolder( ChangedItems = [], DeletedItems = [], }, - Production = new Dictionary(), - Improvements = new Dictionary(), + Production = [], + Improvements = [], Skills = new Skills { Common = [], @@ -79,7 +79,7 @@ public class EventOutputHolder( Points = 0, }, Health = cloner.Clone(pmcProfile.Health), - TraderRelations = new Dictionary(), + TraderRelations = [], QuestsStatus = [], } }, @@ -104,27 +104,39 @@ public class EventOutputHolder( profileChanges.Skills.Mastering = cloner.Clone(pmcData.Skills.Mastering); // Clone productions to ensure we preserve the profile jsons data - profileChanges.Production = GetProductionsFromProfileAndFlagComplete( - cloner.Clone(pmcData.Hideout.Production), - sessionId - ); - profileChanges.Improvements = cloner.Clone( - GetImprovementsFromProfileAndFlagComplete(pmcData) - ); + var hideoutProductionNull = pmcData.Hideout.Production == null; + if (!hideoutProductionNull) + { + profileChanges.Production = GetProductionsFromProfileAndFlagComplete( + cloner.Clone(pmcData.Hideout.Production), + sessionId + ); + } + + if (pmcData.Hideout.Improvements != null) + { + profileChanges.Improvements = cloner.Clone( + GetImprovementsFromProfileAndFlagComplete(pmcData) + ); + } + profileChanges.TraderRelations = ConstructTraderRelations(pmcData.TradersInfo); ResetMoneyTransferLimit(pmcData.MoneyTransferLimitData); profileChanges.MoneyTransferLimitData = pmcData.MoneyTransferLimitData; // Fixes container craft from water collector not resetting after collection + removed completed normal crafts - CleanUpCompleteCraftsInProfile(pmcData.Hideout.Production); + if (!hideoutProductionNull && pmcData.Hideout.Production.Any()) + { + CleanUpCompleteCraftsInProfile(pmcData.Hideout.Production); + } } /// /// Required as continuous productions don't reset and stay at 100% completion but client thinks it hasn't started /// /// Productions in a profile - protected void CleanUpCompleteCraftsInProfile(Dictionary? productions) + protected void CleanUpCompleteCraftsInProfile(Dictionary? productions) { foreach (var production in productions) { @@ -157,14 +169,12 @@ public class EventOutputHolder( /// /// Player profile /// Dictionary of hideout improvements - protected Dictionary? GetImprovementsFromProfileAndFlagComplete( + protected Dictionary GetImprovementsFromProfileAndFlagComplete( PmcData pmcData ) { - foreach (var improvementKey in pmcData.Hideout.Improvements) + foreach (var (key, improvement) in pmcData.Hideout.Improvements) { - var improvement = pmcData.Hideout.Improvements[improvementKey.Key]; - // Skip completed if (improvement.Completed ?? false) { @@ -186,8 +196,8 @@ public class EventOutputHolder( /// Productions from player profile /// Player session ID /// Dictionary of hideout productions - protected Dictionary? GetProductionsFromProfileAndFlagComplete( - Dictionary? productions, + protected Dictionary GetProductionsFromProfileAndFlagComplete( + Dictionary? productions, MongoId sessionId ) { @@ -215,10 +225,9 @@ public class EventOutputHolder( } // Client informed of craft, remove from data returned - Dictionary? storageForSessionId = null; - if (!_clientActiveSessionStorage.TryGetValue(sessionId, out storageForSessionId)) + if (!_clientActiveSessionStorage.TryGetValue(sessionId, out var storageForSessionId)) { - _clientActiveSessionStorage.Add(sessionId, new Dictionary()); + _clientActiveSessionStorage.Add(sessionId, []); storageForSessionId = _clientActiveSessionStorage[sessionId]; } diff --git a/Libraries/SPTarkov.Server.Core/Services/PmcChatResponseService.cs b/Libraries/SPTarkov.Server.Core/Services/PmcChatResponseService.cs index 4f043630..58b39084 100644 --- a/Libraries/SPTarkov.Server.Core/Services/PmcChatResponseService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/PmcChatResponseService.cs @@ -48,7 +48,7 @@ public class PmcChatResponseService( if (string.IsNullOrEmpty(victim.Name)) { logger.Warning( - $"Victim: {victim.ProfileId} does not have a nickname, skipping pmc response message send" + $"Victim: {victim.ProfileId.ToString()} does not have a nickname, skipping pmc response message send" ); continue; @@ -320,7 +320,7 @@ public class PmcChatResponseService( return new UserDialogInfo { - Id = pmcVictim.ProfileId, + Id = pmcVictim.ProfileId.Value, Aid = int.Parse(pmcVictim.AccountId), Info = new UserDialogDetails {