From 529fe61f23426eca23dceac4c732fde6c304ca6e Mon Sep 17 00:00:00 2001 From: Cj <161484149+CJ-SPT@users.noreply.github.com> Date: Tue, 5 Aug 2025 11:24:59 -0400 Subject: [PATCH] Controller house keeping (#532) * Cleanup BotController.cs * More controller cleanup * More dialogue changes --- .../SPT_Data/database/locales/server/en.json | 1 + .../Callbacks/CustomizationCallbacks.cs | 2 +- .../Callbacks/DialogueCallbacks.cs | 32 ++++- .../Controllers/BotController.cs | 129 +++++++++--------- .../Controllers/CustomizationController.cs | 48 +++---- .../Controllers/DialogueController.cs | 91 +++++++----- .../Helpers/DialogueHelper.cs | 8 +- .../Eft/Common/Tables/ProfileTemplate.cs | 2 +- .../Eft/Dialog/ClearMailMessageRequest.cs | 3 +- .../Dialog/GetMailDialogInfoRequestData.cs | 3 +- .../Models/Eft/Dialog/PinDialogRequestData.cs | 3 +- .../Eft/Dialog/RemoveDialogRequestData.cs | 3 +- .../Eft/Dialog/SetDialogReadRequestData.cs | 3 +- .../Models/Eft/Profile/SptProfile.cs | 4 +- .../Models/Spt/Config/CoreConfig.cs | 3 +- 15 files changed, 189 insertions(+), 146 deletions(-) diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locales/server/en.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locales/server/en.json index 7e29d799..4b48f202 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locales/server/en.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/database/locales/server/en.json @@ -75,6 +75,7 @@ "dialog-chatbot_id_already_exists": "Chat bot: %s being registered already exists, unable to register bot", "dialog-missing_item_template": "Unable to find item tpl {{tpl}} in db, cannot send message of type {{type}}, skipping", "dialogue-unable_to_find_dialogs_in_profile": "No dialog object in profile: {{sessionId}}", + "dialogue-list_from_client_empty": "No dialog object sent from client: {{sessionId}}", "dialogue-unable_to_find_in_profile": "No dialog in profile: {{sessionId}} found with id: {{dialogueId}}", "event-unhandled_event": "[UNHANDLED EVENT] %s", "executing_startup_callbacks": "Server: executing startup callbacks...", diff --git a/Libraries/SPTarkov.Server.Core/Callbacks/CustomizationCallbacks.cs b/Libraries/SPTarkov.Server.Core/Callbacks/CustomizationCallbacks.cs index 1e62d0bb..a9cd64d6 100644 --- a/Libraries/SPTarkov.Server.Core/Callbacks/CustomizationCallbacks.cs +++ b/Libraries/SPTarkov.Server.Core/Callbacks/CustomizationCallbacks.cs @@ -52,7 +52,7 @@ public class CustomizationCallbacks( /// public ValueTask GetHideoutCustomisation(string url, EmptyRequestData _, MongoId sessionID) { - return new ValueTask(httpResponseUtil.GetBody(customizationController.GetHideoutCustomisation(sessionID))); + return new ValueTask(httpResponseUtil.GetBody(customizationController.GetHideoutCustomisation())); } /// diff --git a/Libraries/SPTarkov.Server.Core/Callbacks/DialogueCallbacks.cs b/Libraries/SPTarkov.Server.Core/Callbacks/DialogueCallbacks.cs index 0ed78a25..14ad5416 100644 --- a/Libraries/SPTarkov.Server.Core/Callbacks/DialogueCallbacks.cs +++ b/Libraries/SPTarkov.Server.Core/Callbacks/DialogueCallbacks.cs @@ -37,7 +37,7 @@ public class DialogueCallbacks(TimeUtil timeUtil, HttpResponseUtil httpResponseU { new() { - Id = new Models.Common.MongoId(), + Id = new MongoId(), RegistrationId = 20, DateTime = timeUtil.GetTimeStamp(), IsDeveloper = true, @@ -80,7 +80,9 @@ public class DialogueCallbacks(TimeUtil timeUtil, HttpResponseUtil httpResponseU /// public virtual ValueTask GetMailDialogInfo(string url, GetMailDialogInfoRequestData request, MongoId sessionID) { - return new ValueTask(httpResponseUtil.GetBody(dialogueController.GetDialogueInfo(request.DialogId, sessionID))); + return new ValueTask( + httpResponseUtil.GetBody(dialogueController.GetDialogueInfo(request.DialogId ?? MongoId.Empty(), sessionID)) + ); } /// @@ -89,7 +91,7 @@ public class DialogueCallbacks(TimeUtil timeUtil, HttpResponseUtil httpResponseU /// public virtual ValueTask RemoveDialog(string url, RemoveDialogRequestData request, MongoId sessionID) { - dialogueController.RemoveDialogue(request.DialogId, sessionID); + dialogueController.RemoveDialogue(request.DialogId ?? MongoId.Empty(), sessionID); return new ValueTask(httpResponseUtil.EmptyArrayResponse()); } @@ -99,7 +101,7 @@ public class DialogueCallbacks(TimeUtil timeUtil, HttpResponseUtil httpResponseU /// public virtual ValueTask PinDialog(string url, PinDialogRequestData request, MongoId sessionID) { - dialogueController.SetDialoguePin(request.DialogId, true, sessionID); + dialogueController.SetDialoguePin(request.DialogId ?? MongoId.Empty(), true, sessionID); return new ValueTask(httpResponseUtil.EmptyArrayResponse()); } @@ -109,7 +111,7 @@ public class DialogueCallbacks(TimeUtil timeUtil, HttpResponseUtil httpResponseU /// public virtual ValueTask UnpinDialog(string url, PinDialogRequestData request, MongoId sessionID) { - dialogueController.SetDialoguePin(request.DialogId, false, sessionID); + dialogueController.SetDialoguePin(request.DialogId ?? MongoId.Empty(), false, sessionID); return new ValueTask(httpResponseUtil.EmptyArrayResponse()); } @@ -232,6 +234,10 @@ public class DialogueCallbacks(TimeUtil timeUtil, HttpResponseUtil httpResponseU return new ValueTask(httpResponseUtil.NullResponse()); } + /// + /// Handle /client/mail/dialog/clear + /// + /// public virtual ValueTask ClearMail(string url, ClearMailMessageRequest request, MongoId sessionID) { dialogueController.ClearMessages(sessionID, request); @@ -239,21 +245,37 @@ public class DialogueCallbacks(TimeUtil timeUtil, HttpResponseUtil httpResponseU return new ValueTask(httpResponseUtil.EmptyArrayResponse()); } + /// + /// Handle /client/mail/dialog/group/create + /// + /// public virtual ValueTask CreateGroupMail(string url, CreateGroupMailRequest request, MongoId sessionID) { return new ValueTask(httpResponseUtil.EmptyArrayResponse()); } + /// + /// Handle /client/mail/dialog/group/owner/change + /// + /// public virtual ValueTask ChangeMailGroupOwner(string url, ChangeGroupMailOwnerRequest request, MongoId sessionID) { return new ValueTask("Not Implemented!"); // Not implemented in Node } + /// + /// Handle /client/mail/dialog/group/users/add + /// + /// public virtual ValueTask AddUserToMail(string url, AddUserGroupMailRequest request, MongoId sessionID) { return new ValueTask("Not Implemented!"); // Not implemented in Node } + /// + /// Handle /client/mail/dialog/group/users/remove + /// + /// public virtual ValueTask RemoveUserFromMail(string url, RemoveUserGroupMailRequest request, MongoId sessionID) { return new ValueTask("Not Implemented!"); // Not implemented in Node diff --git a/Libraries/SPTarkov.Server.Core/Controllers/BotController.cs b/Libraries/SPTarkov.Server.Core/Controllers/BotController.cs index 4885d2f0..bee0bdba 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/BotController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/BotController.cs @@ -23,24 +23,23 @@ namespace SPTarkov.Server.Core.Controllers; [Injectable] public class BotController( - ISptLogger _logger, - DatabaseService _databaseService, - BotGenerator _botGenerator, - BotHelper _botHelper, - BotDifficultyHelper _botDifficultyHelper, - ServerLocalisationService _serverLocalisationService, - SeasonalEventService _seasonalEventService, - MatchBotDetailsCacheService _matchBotDetailsCacheService, - ProfileHelper _profileHelper, - ConfigServer _configServer, - ProfileActivityService _profileActivityService, - RandomUtil _randomUtil, - ICloner _cloner + ISptLogger logger, + DatabaseService databaseService, + BotGenerator botGenerator, + BotHelper botHelper, + BotDifficultyHelper botDifficultyHelper, + ServerLocalisationService serverLocalisationService, + SeasonalEventService seasonalEventService, + MatchBotDetailsCacheService matchBotDetailsCacheService, + ProfileHelper profileHelper, + ConfigServer configServer, + ProfileActivityService profileActivityService, + RandomUtil randomUtil, + ICloner cloner ) { - private readonly BotConfig _botConfig = _configServer.GetConfig(); - private readonly PmcConfig _pmcConfig = _configServer.GetConfig(); - private static readonly Lock _botListLock = new(); + protected readonly BotConfig botConfig = configServer.GetConfig(); + protected readonly PmcConfig pmcConfig = configServer.GetConfig(); /// /// Return the number of bot load-out varieties to be generated @@ -49,9 +48,9 @@ public class BotController( /// number of bots to generate public int GetBotPresetGenerationLimit(string type) { - if (!_botConfig.PresetBatch.TryGetValue(type, out var limit)) + if (!botConfig.PresetBatch.TryGetValue(type, out var limit)) { - _logger.Warning(_serverLocalisationService.GetText("bot-bot_preset_count_value_missing", type)); + logger.Warning(serverLocalisationService.GetText("bot-bot_preset_count_value_missing", type)); return 10; } @@ -66,7 +65,7 @@ public class BotController( /// public Dictionary GetBotCoreDifficulty() { - return _databaseService.GetBots().Core!; + return databaseService.GetBots().Core; } /// @@ -82,11 +81,11 @@ public class BotController( { var difficulty = diffLevel.ToLowerInvariant(); - var raidConfig = _profileActivityService.GetProfileActivityRaidData(sessionId).RaidConfiguration; + var raidConfig = profileActivityService.GetProfileActivityRaidData(sessionId).RaidConfiguration; if (!(raidConfig != null || ignoreRaidSettings)) { - _logger.Error(_serverLocalisationService.GetText("bot-missing_application_context", "RAID_CONFIGURATION")); + logger.Error(serverLocalisationService.GetText("bot-missing_application_context", "RAID_CONFIGURATION")); } // Check value chosen in pre-raid difficulty dropdown @@ -94,11 +93,11 @@ public class BotController( var botDifficultyDropDownValue = raidConfig?.WavesSettings?.BotDifficulty?.ToString().ToLowerInvariant() ?? "asonline"; if (botDifficultyDropDownValue != "asonline") { - difficulty = _botDifficultyHelper.ConvertBotDifficultyDropdownToBotDifficulty(botDifficultyDropDownValue); + difficulty = botDifficultyHelper.ConvertBotDifficultyDropdownToBotDifficulty(botDifficultyDropDownValue); } - var botDb = _databaseService.GetBots(); - return _botDifficultyHelper.GetBotDifficultySettings(type, difficulty, botDb); + var botDb = databaseService.GetBots(); + return botDifficultyHelper.GetBotDifficultySettings(type, difficulty, botDb); } /// @@ -109,7 +108,7 @@ public class BotController( { var result = new Dictionary>(); - var botTypesDb = _databaseService.GetBots().Types; + var botTypesDb = databaseService.GetBots().Types; if (botTypesDb is null) { return result; @@ -128,9 +127,9 @@ public class BotController( { // No bot of this type found, copy details from assault result[botTypeLower] = result[Roles.Assault]; - if (_logger.IsLogEnabled(LogLevel.Debug)) + if (logger.IsLogEnabled(LogLevel.Debug)) { - _logger.Debug($"Unable to find bot: {botTypeLower} in db, copying: '{Roles.Assault}'"); + logger.Debug($"Unable to find bot: {botTypeLower} in db, copying: '{Roles.Assault}'"); } continue; @@ -139,7 +138,7 @@ public class BotController( if (botDetails?.BotDifficulty is null) { // Bot has no difficulty values, skip - _logger.Warning($"Unable to find bot: {botTypeLower} difficulty values in db, skipping"); + logger.Warning($"Unable to find bot: {botTypeLower} difficulty values in db, skipping"); continue; } @@ -166,9 +165,9 @@ public class BotController( /// Session/Player id /// /// List of bots - public async Task> Generate(MongoId sessionId, GenerateBotsRequestData request) + public async Task> Generate(MongoId sessionId, GenerateBotsRequestData request) { - var pmcProfile = _profileHelper.GetPmcProfile(sessionId); + var pmcProfile = profileHelper.GetPmcProfile(sessionId); return await GenerateBotWaves(sessionId, request, pmcProfile); } @@ -180,7 +179,7 @@ public class BotController( /// Client bot generation request /// Player profile generating bots /// List of generated bots - protected async Task> GenerateBotWaves(MongoId sessionId, GenerateBotsRequestData request, PmcData? pmcProfile) + protected async Task> GenerateBotWaves(MongoId sessionId, GenerateBotsRequestData request, PmcData? pmcProfile) { if (request.Conditions is null || !request.Conditions.Any()) { @@ -191,7 +190,7 @@ public class BotController( // Get chosen raid settings from app context var raidSettings = GetMostRecentRaidSettings(sessionId); - var allPmcsHaveSameNameAsPlayer = _randomUtil.GetChance100(_pmcConfig.AllPMCsHavePlayerNameWithRandomPrefixChance); + var allPmcsHaveSameNameAsPlayer = randomUtil.GetChance100(pmcConfig.AllPMCsHavePlayerNameWithRandomPrefixChance); // Split each bot wave into its own task var waveGenerationTasks = request.Conditions.Select(condition => @@ -213,9 +212,9 @@ public class BotController( var results = await Task.WhenAll(waveGenerationTasks); stopwatch.Stop(); - if (_logger.IsLogEnabled(LogLevel.Debug)) + if (logger.IsLogEnabled(LogLevel.Debug)) { - _logger.Debug($"Took {stopwatch.ElapsedMilliseconds}ms to GenerateMultipleBotsAndCache()"); + logger.Debug($"Took {stopwatch.ElapsedMilliseconds}ms to GenerateMultipleBotsAndCache()"); } // Merge + flatten results of all wave generations @@ -229,7 +228,7 @@ public class BotController( /// /// /// Result of generating bot wave - protected IEnumerable GenerateBotWave( + protected IEnumerable GenerateBotWave( MongoId sessionId, GenerateCondition generateRequest, BotGenerationDetails botGenerationDetails @@ -240,33 +239,33 @@ public class BotController( { // Add eventRole data + reassign role property to be base type botGenerationDetails.EventRole = generateRequest.Role; - botGenerationDetails.Role = _seasonalEventService.GetBaseRoleForEventBot(botGenerationDetails.EventRole); + botGenerationDetails.Role = seasonalEventService.GetBaseRoleForEventBot(botGenerationDetails.EventRole); } // Event role must take priority to generate correctly var role = botGenerationDetails.EventRole ?? botGenerationDetails.Role; - if (_logger.IsLogEnabled(LogLevel.Debug)) + if (logger.IsLogEnabled(LogLevel.Debug)) { - _logger.Debug( + logger.Debug( $"Generating wave of: {botGenerationDetails.BotCountToGenerate} bots of type: {role} {botGenerationDetails.BotDifficulty}" ); } var generatedBots = Enumerable .Range(0, botGenerationDetails.BotCountToGenerate) - .AsParallel() // Parallelise above range of values so they can each generate a bot + .AsParallel() // Parallelize above range of values so they can each generate a bot .Select(i => TryGenerateSingleBot(sessionId, botGenerationDetails, i)) .Where(bot => bot is not null ) // Skip failed bots ; // Materialise parallel query into data - if (_logger.IsLogEnabled(LogLevel.Debug)) + if (logger.IsLogEnabled(LogLevel.Debug)) { - _logger.Debug( + logger.Debug( $"Generated: {botGenerationDetails.BotCountToGenerate} {botGenerationDetails.Role}" - + $"({botGenerationDetails.EventRole ?? botGenerationDetails.Role ?? ""}) {botGenerationDetails.BotDifficulty} bots" + + $"({botGenerationDetails.EventRole ?? botGenerationDetails.Role}) {botGenerationDetails.BotDifficulty} bots" ); } @@ -282,22 +281,22 @@ public class BotController( try { // Clone for thread safety TODO: confirm if clone is necessary (likely not) - var bot = _botGenerator.PrepareAndGenerateBot(sessionId, _cloner.Clone(generationDetails)); + var bot = botGenerator.PrepareAndGenerateBot(sessionId, cloner.Clone(generationDetails)!); // Client expects Side for PMCs to be `Savage`, must be altered here before it's cached - if (bot.Info.Side is Sides.Bear or Sides.Usec) + if (bot.Info?.Side is Sides.Bear or Sides.Usec) { bot.Info.Side = Sides.Savage; } // Store bot details in cache before returning. - _matchBotDetailsCacheService.CacheBot(bot); + matchBotDetailsCacheService.CacheBot(bot); return bot; } catch (Exception e) { - _logger.Error($"Failed to generate bot #{botIndex + 1} ({generationDetails.Role}): {e.Message}"); + logger.Error($"Failed to generate bot #{botIndex + 1} ({generationDetails.Role}): {e.Message}"); return null; } } @@ -308,11 +307,11 @@ public class BotController( /// GetRaidConfigurationRequestData if it exists protected GetRaidConfigurationRequestData? GetMostRecentRaidSettings(MongoId sessionId) { - var raidConfiguration = _profileActivityService.GetProfileActivityRaidData(sessionId)?.RaidConfiguration; + var raidConfiguration = profileActivityService.GetProfileActivityRaidData(sessionId).RaidConfiguration; if (raidConfiguration is null) { - _logger.Warning(_serverLocalisationService.GetText("bot-unable_to_load_raid_settings_from_appcontext")); + logger.Warning(serverLocalisationService.GetText("bot-unable_to_load_raid_settings_from_appcontext")); } return raidConfiguration; @@ -323,9 +322,9 @@ public class BotController( /// /// Map name e.g. factory4_day /// MinMax values - protected MinMax GetPmcLevelRangeForMap(string? location) + protected MinMax? GetPmcLevelRangeForMap(string? location) { - return _pmcConfig.LocationSpecificPmcLevelOverride!.GetValueOrDefault(location?.ToLowerInvariant() ?? "", null); + return pmcConfig.LocationSpecificPmcLevelOverride!.GetValueOrDefault(location?.ToLowerInvariant() ?? "", null); } /// @@ -343,18 +342,18 @@ public class BotController( GetRaidConfigurationRequestData? raidSettings ) { - var generateAsPmc = _botHelper.IsBotPmc(condition.Role); + var generateAsPmc = botHelper.IsBotPmc(condition.Role); return new BotGenerationDetails { IsPmc = generateAsPmc, - Side = generateAsPmc ? _botHelper.GetPmcSideByRole(condition.Role ?? string.Empty) : "Savage", - Role = condition.Role, + Side = generateAsPmc ? botHelper.GetPmcSideByRole(condition.Role ?? string.Empty) : "Savage", + Role = condition.Role!, PlayerLevel = pmcProfile?.Info?.Level ?? 1, PlayerName = pmcProfile?.Info?.Nickname, - BotRelativeLevelDeltaMax = _pmcConfig.BotRelativeLevelDelta.Max, - BotRelativeLevelDeltaMin = _pmcConfig.BotRelativeLevelDelta.Min, - BotCountToGenerate = Math.Max(GetBotPresetGenerationLimit(condition.Role), condition.Limit), // Choose largest between value passed in from request vs what's in bot.config + BotRelativeLevelDeltaMax = pmcConfig.BotRelativeLevelDelta.Max, + BotRelativeLevelDeltaMin = pmcConfig.BotRelativeLevelDelta.Min, + BotCountToGenerate = Math.Max(GetBotPresetGenerationLimit(condition.Role!), condition.Limit), // Choose largest between value passed in from request vs what's in bot.config BotDifficulty = condition.Difficulty, LocationSpecificPmcLevelOverride = GetPmcLevelRangeForMap(raidSettings?.Location), // Min/max levels for PMCs to generate within IsPlayerScav = false, @@ -371,14 +370,14 @@ public class BotController( /// bot cap for map public int GetBotCap(string location) { - if (!_botConfig.MaxBotCap.TryGetValue(location.ToLowerInvariant(), out var maxCap)) + if (!botConfig.MaxBotCap.TryGetValue(location.ToLowerInvariant(), out var maxCap)) { - return _botConfig.MaxBotCap["default"]; + return botConfig.MaxBotCap["default"]; } if (location == "default") { - _logger.Warning(_serverLocalisationService.GetText("bot-no_bot_cap_found_for_location", location.ToLowerInvariant())); + logger.Warning(serverLocalisationService.GetText("bot-no_bot_cap_found_for_location", location.ToLowerInvariant())); } return maxCap; @@ -392,9 +391,9 @@ public class BotController( { return new AiBotBrainTypes { - PmcType = _pmcConfig.PmcType, - Assault = _botConfig.AssaultBrainType, - PlayerScav = _botConfig.PlayerScavBrainType, + PmcType = pmcConfig.PmcType, + Assault = botConfig.AssaultBrainType, + PlayerScav = botConfig.PlayerScavBrainType, }; } } @@ -402,11 +401,11 @@ public class BotController( public record AiBotBrainTypes { [JsonPropertyName("pmc")] - public Dictionary>> PmcType { get; set; } + public required Dictionary>> PmcType { get; set; } [JsonPropertyName("assault")] - public Dictionary> Assault { get; set; } + public required Dictionary> Assault { get; set; } [JsonPropertyName("playerScav")] - public Dictionary> PlayerScav { get; set; } + public required Dictionary> PlayerScav { get; set; } } diff --git a/Libraries/SPTarkov.Server.Core/Controllers/CustomizationController.cs b/Libraries/SPTarkov.Server.Core/Controllers/CustomizationController.cs index b1d30ec3..b993ae2a 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/CustomizationController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/CustomizationController.cs @@ -13,6 +13,7 @@ using SPTarkov.Server.Core.Routers; using SPTarkov.Server.Core.Servers; using SPTarkov.Server.Core.Services; using SPTarkov.Server.Core.Utils.Cloners; +using Customization = SPTarkov.Server.Core.Models.Eft.Common.Tables.Customization; namespace SPTarkov.Server.Core.Controllers; @@ -38,7 +39,7 @@ public class CustomizationController( { var pmcData = profileHelper.GetPmcProfile(sessionId); var clothing = databaseService.GetCustomization(); - var suits = databaseService.GetTrader(traderId).Suits; + var suits = databaseService.GetTrader(traderId)?.Suits; var matchingSuits = suits?.Where(s => clothing.ContainsKey(s.SuiteId)); matchingSuits = matchingSuits?.Where(s => @@ -99,7 +100,7 @@ public class CustomizationController( Type = CustomisationType.SUITE, }; - profile.CustomisationUnlocks.Add(rewardToStore); + profile.CustomisationUnlocks?.Add(rewardToStore); return output; } @@ -115,7 +116,7 @@ public class CustomizationController( var fullProfile = profileHelper.GetFullProfile(sessionId); // Check if clothing can be found by id - return fullProfile.CustomisationUnlocks.Exists(customisation => Equals(customisation.Id, suitId)); + return fullProfile.CustomisationUnlocks?.Exists(customisation => Equals(customisation.Id, suitId)) ?? false; } /// @@ -158,11 +159,11 @@ public class CustomizationController( { var options = new ProcessBuyTradeRequestData { - SchemeItems = [new IdWithCount { Count = inventoryItemToProcess.Count.Value, Id = inventoryItemToProcess.Id }], + SchemeItems = [new IdWithCount { Count = inventoryItemToProcess.Count!.Value, Id = inventoryItemToProcess.Id }], TransactionId = Traders.RAGMAN, Action = "BuyCustomization", Type = "", - ItemId = "", + ItemId = MongoId.Empty(), Count = 0, SchemeId = 0, }; @@ -183,7 +184,7 @@ public class CustomizationController( foreach (var (traderId, trader) in traders) { - if (trader.Base?.CustomizationSeller is not null && trader.Base.CustomizationSeller.Value) + if (trader.Base.CustomizationSeller is not null && trader.Base.CustomizationSeller.Value) { result.AddRange(GetTraderSuits(traderId, sessionId)); } @@ -195,11 +196,10 @@ public class CustomizationController( /// /// Handle client/hideout/customization/offer/list /// - /// Session/Player id - /// - public HideoutCustomisation GetHideoutCustomisation(MongoId sessionId) + /// Hideout customizations + public HideoutCustomisation GetHideoutCustomisation() { - return databaseService.GetHideout().Customisation!; + return databaseService.GetHideout().Customisation; } /// @@ -212,10 +212,6 @@ public class CustomizationController( var customisationResultsClone = cloner.Clone(databaseService.GetTemplates().CustomisationStorage); var profile = profileHelper.GetFullProfile(sessionId); - if (profile is null) - { - return customisationResultsClone!; - } customisationResultsClone!.AddRange(profile.CustomisationUnlocks ?? []); @@ -231,7 +227,7 @@ public class CustomizationController( /// ItemEventRouterResponse public ItemEventRouterResponse SetCustomisation(MongoId sessionId, CustomizationSetRequest request, PmcData pmcData) { - foreach (var customisation in request.Customizations) + foreach (var customisation in request.Customizations!) { switch (customisation.Type) { @@ -268,19 +264,19 @@ public class CustomizationController( return; } - // Body - if (dbSuit.Parent == CustomisationTypeId.UPPER) - { - pmcData.Customization.Body = dbSuit.Properties.Body; - pmcData.Customization.Hands = dbSuit.Properties.Hands; + pmcData.Customization ??= new Customization(); - return; - } - - // Feet - if (dbSuit.Parent == CustomisationTypeId.LOWER) + switch (dbSuit?.Parent) { - pmcData.Customization.Feet = dbSuit.Properties.Feet; + // Body + case CustomisationTypeId.UPPER: + pmcData.Customization.Body = dbSuit.Properties.Body; + pmcData.Customization.Hands = dbSuit.Properties.Hands; + return; + // Feet + case CustomisationTypeId.LOWER: + pmcData.Customization.Feet = dbSuit.Properties.Feet; + break; } } } diff --git a/Libraries/SPTarkov.Server.Core/Controllers/DialogueController.cs b/Libraries/SPTarkov.Server.Core/Controllers/DialogueController.cs index bd573baa..46d6f79f 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/DialogueController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/DialogueController.cs @@ -73,22 +73,30 @@ public class DialogueController( // Add any friends the user has after the chatbots var profile = profileHelper.GetFullProfile(sessionId); - if (profile?.FriendProfileIds is not null) + + if (profile.FriendProfileIds is null) { - foreach (var friendId in profile.FriendProfileIds) + return new GetFriendListDataResponse { - var friendProfile = profileHelper.GetChatRoomMemberFromSessionId(friendId); - if (friendProfile is not null) - { - friends.Add( - new UserDialogInfo - { - Id = friendProfile.Id, - Aid = friendProfile.Aid, - Info = friendProfile.Info, - } - ); - } + Friends = friends, + Ignore = [], + InIgnoreList = [], + }; + } + + foreach (var friendId in profile.FriendProfileIds) + { + var friendProfile = profileHelper.GetChatRoomMemberFromSessionId(friendId); + if (friendProfile is not null) + { + friends.Add( + new UserDialogInfo + { + Id = friendProfile.Id, + Aid = friendProfile.Aid, + Info = friendProfile.Info, + } + ); } } @@ -100,6 +108,10 @@ public class DialogueController( }; } + /// + /// Get all active chatbots + /// + /// Active chatbots public List GetActiveChatBots() { var activeBots = new List(); @@ -109,7 +121,7 @@ public class DialogueController( foreach (var bot in _dialogueChatBots) { var botData = bot.GetChatBot(); - if (chatBotConfig.EnabledBots.ContainsKey(botData.Id!)) + if (chatBotConfig.EnabledBots.ContainsKey(botData.Id)) { activeBots.Add(botData); } @@ -148,10 +160,10 @@ public class DialogueController( /// Dialog id /// Session Id /// DialogueInfo - public virtual DialogueInfo? GetDialogueInfo(string? dialogueId, MongoId sessionId) + public virtual DialogueInfo? GetDialogueInfo(MongoId dialogueId, MongoId sessionId) { var dialogs = dialogueHelper.GetDialogsForProfile(sessionId); - var dialogue = dialogs!.GetValueOrDefault(dialogueId); + var dialogue = dialogs.GetValueOrDefault(dialogueId); return GetDialogueInfo(dialogue, sessionId); } @@ -162,9 +174,9 @@ public class DialogueController( /// Dialog /// Session Id /// DialogueInfo - public virtual DialogueInfo? GetDialogueInfo(Dialogue dialogue, MongoId sessionId) + public virtual DialogueInfo? GetDialogueInfo(Dialogue? dialogue, MongoId sessionId) { - if (!dialogue.Messages.Any()) + if (dialogue is null || dialogue.Messages?.Count == 0) { return null; } @@ -236,7 +248,7 @@ public class DialogueController( var fullProfile = saveServer.GetProfile(sessionId); var dialogue = GetDialogByIdFromProfile(fullProfile, request); - if (!dialogue.Messages.Any()) + if (dialogue.Messages?.Count == 0) { return new GetMailDialogViewResponseData { @@ -250,7 +262,7 @@ public class DialogueController( dialogue.New = 0; // Set number of new attachments, but ignore those that have expired. - dialogue.AttachmentsNew = GetUnreadMessagesWithAttachmentsCount(sessionId, dialogueId!); + dialogue.AttachmentsNew = GetUnreadMessagesWithAttachmentsCount(sessionId, dialogueId); return new GetMailDialogViewResponseData { @@ -268,12 +280,12 @@ public class DialogueController( /// Dialogue protected Dialogue GetDialogByIdFromProfile(SptProfile profile, GetMailDialogViewRequestData request) { - if (profile.DialogueRecords is null || profile.DialogueRecords.ContainsKey(request.DialogId!)) + if (profile.DialogueRecords is null || profile.DialogueRecords.ContainsKey(request.DialogId)) { - return profile.DialogueRecords?[request.DialogId!] ?? throw new NullReferenceException(); + return profile.DialogueRecords?[request.DialogId] ?? throw new NullReferenceException(); } - profile.DialogueRecords[request.DialogId!] = new Dialogue + profile.DialogueRecords[request.DialogId] = new Dialogue { Id = request.DialogId, AttachmentsNew = 0, @@ -285,22 +297,22 @@ public class DialogueController( if (request.Type != MessageType.UserMessage) { - return profile.DialogueRecords[request.DialogId!]; + return profile.DialogueRecords[request.DialogId]; } - var dialogue = profile.DialogueRecords[request.DialogId!]; + var dialogue = profile.DialogueRecords[request.DialogId]; dialogue.Users = []; var chatBot = _dialogueChatBots.FirstOrDefault(cb => cb.GetChatBot().Id == request.DialogId); if (chatBot is null) { - return profile.DialogueRecords[request.DialogId!]; + return profile.DialogueRecords[request.DialogId]; } dialogue.Users ??= []; dialogue.Users.Add(chatBot.GetChatBot()); - return profile.DialogueRecords[request.DialogId!]; + return profile.DialogueRecords[request.DialogId]; } /// @@ -352,7 +364,7 @@ public class DialogueController( /// Session id /// Dialog id /// Count of messages with attachments - protected int GetUnreadMessagesWithAttachmentsCount(MongoId sessionId, string dialogueId) + protected int GetUnreadMessagesWithAttachmentsCount(MongoId sessionId, MongoId dialogueId) { var newAttachmentCount = 0; var activeMessages = GetActiveMessagesFromDialog(sessionId, dialogueId); @@ -373,7 +385,7 @@ public class DialogueController( /// Session/Player id /// Dialog to get mail attachments from /// Message array - protected List GetActiveMessagesFromDialog(MongoId sessionId, string dialogueId) + protected List GetActiveMessagesFromDialog(MongoId sessionId, MongoId dialogueId) { var timeNow = timeUtil.GetTimeStamp(); var dialogs = dialogueHelper.GetDialogsForProfile(sessionId); @@ -403,10 +415,10 @@ public class DialogueController( /// /// id of the dialog to remove /// Player id - public virtual void RemoveDialogue(string? dialogueId, MongoId sessionId) + public virtual void RemoveDialogue(MongoId dialogueId, MongoId sessionId) { var profile = saveServer.GetProfile(sessionId); - if (!profile.DialogueRecords.Remove(dialogueId)) + if (!profile.DialogueRecords?.Remove(dialogueId) ?? false) { logger.Error(serverLocalisationService.GetText("dialogue-unable_to_find_in_profile", new { sessionId, dialogueId })); } @@ -418,7 +430,7 @@ public class DialogueController( /// /// /// Session/Player id - public virtual void SetDialoguePin(string? dialogueId, bool shouldPin, MongoId sessionId) + public virtual void SetDialoguePin(MongoId dialogueId, bool shouldPin, MongoId sessionId) { var dialog = dialogueHelper.GetDialogsForProfile(sessionId).GetValueOrDefault(dialogueId); if (dialog is null) @@ -437,10 +449,17 @@ public class DialogueController( /// /// Dialog ids to set as read /// Player profile id - public virtual void SetRead(List? dialogueIds, MongoId sessionId) + public virtual void SetRead(List? dialogueIds, MongoId sessionId) { + if (dialogueIds is null) + { + logger.Error(serverLocalisationService.GetText("dialogue-list_from_client_empty", new { sessionId })); + + return; + } + var dialogs = dialogueHelper.GetDialogsForProfile(sessionId); - if (dialogs.Any() != true) + if (dialogs.Count == 0) { logger.Error(serverLocalisationService.GetText("dialogue-unable_to_find_dialogs_in_profile", new { sessionId })); @@ -629,7 +648,7 @@ public class DialogueController( public void ClearMessages(MongoId sessionId, ClearMailMessageRequest request) { var profile = saveServer.GetProfile(sessionId); - if (!profile.DialogueRecords.TryGetValue(request.DialogId, out var dialogToClear)) + if (profile.DialogueRecords is null || !profile.DialogueRecords.TryGetValue(request.DialogId, out var dialogToClear)) { logger.Warning($"unable to clear messages from dialog: {request.DialogId} as it cannot be found in profile: {sessionId}"); diff --git a/Libraries/SPTarkov.Server.Core/Helpers/DialogueHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/DialogueHelper.cs index 1c888fd3..dddb30c7 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/DialogueHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/DialogueHelper.cs @@ -17,7 +17,7 @@ public class DialogueHelper(ISptLogger logger, ProfileHelper pro public MessagePreview GetMessagePreview(Models.Eft.Profile.Dialogue? dialogue) { // The last message of the dialogue should be shown on the preview. - var message = dialogue.Messages.LastOrDefault(); + var message = dialogue?.Messages?.LastOrDefault(); MessagePreview result = new() { @@ -92,10 +92,10 @@ public class DialogueHelper(ISptLogger logger, ProfileHelper pro /// /// Session/player id /// Dialog dictionary - public Dictionary GetDialogsForProfile(MongoId sessionId) + public Dictionary GetDialogsForProfile(MongoId sessionId) { var profile = profileHelper.GetFullProfile(sessionId); - return profile.DialogueRecords ?? (profile.DialogueRecords = new Dictionary()); + return profile.DialogueRecords ?? (profile.DialogueRecords = new Dictionary()); } /// @@ -104,7 +104,7 @@ public class DialogueHelper(ISptLogger logger, ProfileHelper pro /// Profile to look in /// Dialog to return /// Dialogue - public Models.Eft.Profile.Dialogue? GetDialogueFromProfile(MongoId profileId, string dialogueId) + public Models.Eft.Profile.Dialogue? GetDialogueFromProfile(MongoId profileId, MongoId dialogueId) { var dialogues = GetDialogsForProfile(profileId); if (dialogues.TryGetValue(dialogueId, out var dialogue)) diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/ProfileTemplate.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/ProfileTemplate.cs index 87f79f30..edae8d98 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/ProfileTemplate.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/ProfileTemplate.cs @@ -31,7 +31,7 @@ public record TemplateSide public List? Suits { get; set; } [JsonPropertyName("dialogues")] - public Dictionary? Dialogues { get; set; } + public Dictionary? Dialogues { get; set; } [JsonPropertyName("userbuilds")] public UserBuilds? UserBuilds { get; set; } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/ClearMailMessageRequest.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/ClearMailMessageRequest.cs index 3c74c85e..2fb9f011 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/ClearMailMessageRequest.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/ClearMailMessageRequest.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Utils; namespace SPTarkov.Server.Core.Models.Eft.Dialog; @@ -9,5 +10,5 @@ public record ClearMailMessageRequest : IRequestData public Dictionary? ExtensionData { get; set; } [JsonPropertyName("dialogId")] - public string? DialogId { get; set; } + public required MongoId DialogId { get; set; } } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/GetMailDialogInfoRequestData.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/GetMailDialogInfoRequestData.cs index c40acdc7..b000d127 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/GetMailDialogInfoRequestData.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/GetMailDialogInfoRequestData.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Utils; namespace SPTarkov.Server.Core.Models.Eft.Dialog; @@ -9,5 +10,5 @@ public record GetMailDialogInfoRequestData : IRequestData public Dictionary? ExtensionData { get; set; } [JsonPropertyName("dialogId")] - public string? DialogId { get; set; } + public MongoId? DialogId { get; set; } } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/PinDialogRequestData.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/PinDialogRequestData.cs index a9a8907b..a91e7289 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/PinDialogRequestData.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/PinDialogRequestData.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Utils; namespace SPTarkov.Server.Core.Models.Eft.Dialog; @@ -9,5 +10,5 @@ public record PinDialogRequestData : IRequestData public Dictionary? ExtensionData { get; set; } [JsonPropertyName("dialogId")] - public string? DialogId { get; set; } + public MongoId? DialogId { get; set; } } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/RemoveDialogRequestData.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/RemoveDialogRequestData.cs index 5159baf1..6e60742a 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/RemoveDialogRequestData.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/RemoveDialogRequestData.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Utils; namespace SPTarkov.Server.Core.Models.Eft.Dialog; @@ -9,5 +10,5 @@ public record RemoveDialogRequestData : IRequestData public Dictionary? ExtensionData { get; set; } [JsonPropertyName("dialogId")] - public string? DialogId { get; set; } + public MongoId? DialogId { get; set; } } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/SetDialogReadRequestData.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/SetDialogReadRequestData.cs index cc5e64cc..97b067ac 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/SetDialogReadRequestData.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Dialog/SetDialogReadRequestData.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Utils; namespace SPTarkov.Server.Core.Models.Eft.Dialog; @@ -9,5 +10,5 @@ public record SetDialogReadRequestData : IRequestData public Dictionary? ExtensionData { get; set; } [JsonPropertyName("dialogs")] - public List? Dialogs { get; set; } + public List? Dialogs { get; set; } } diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Profile/SptProfile.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Profile/SptProfile.cs index 0b9f0648..a6951af2 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Profile/SptProfile.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Profile/SptProfile.cs @@ -30,7 +30,7 @@ public record SptProfile public UserBuilds? UserBuildData { get; set; } [JsonPropertyName("dialogues")] - public Dictionary? DialogueRecords { get; set; } + public Dictionary? DialogueRecords { get; set; } [JsonPropertyName("spt")] public Spt? SptData { get; set; } @@ -249,7 +249,7 @@ public record DialogueInfo public int? New { get; set; } [JsonPropertyName("_id")] - public string? Id { get; set; } + public MongoId Id { get; set; } [JsonPropertyName("type")] public MessageType? Type { get; set; } diff --git a/Libraries/SPTarkov.Server.Core/Models/Spt/Config/CoreConfig.cs b/Libraries/SPTarkov.Server.Core/Models/Spt/Config/CoreConfig.cs index 51274b0f..0c39e6eb 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Spt/Config/CoreConfig.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Spt/Config/CoreConfig.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Eft.Game; namespace SPTarkov.Server.Core.Models.Spt.Config; @@ -258,7 +259,7 @@ public record ChatbotFeatures /// Bot Ids player is allowed to interact with /// [JsonPropertyName("enabledBots")] - public required Dictionary EnabledBots { get; set; } + public required Dictionary EnabledBots { get; set; } } public record CommandoFeatures