diff --git a/Libraries/SPTarkov.Common/Extensions/ListExtensions.cs b/Libraries/SPTarkov.Common/Extensions/ListExtensions.cs index de63cf8a..e8b1f0b2 100644 --- a/Libraries/SPTarkov.Common/Extensions/ListExtensions.cs +++ b/Libraries/SPTarkov.Common/Extensions/ListExtensions.cs @@ -11,15 +11,15 @@ public static class ListExtensions public static T PopFirst(this IList source) { - var r = source.First(); - source.Remove(source.First()); + var r = source[0]; + source.Remove(source[0]); return r; } public static T PopLast(this IList source) { - var r = source.Last(); - source.Remove(source.Last()); + var r = source[^1]; + source.Remove(source[^1]); return r; } } diff --git a/Libraries/SPTarkov.Common/Extensions/ObjectExtensions.cs b/Libraries/SPTarkov.Common/Extensions/ObjectExtensions.cs index c485155f..8688d1ee 100644 --- a/Libraries/SPTarkov.Common/Extensions/ObjectExtensions.cs +++ b/Libraries/SPTarkov.Common/Extensions/ObjectExtensions.cs @@ -6,7 +6,7 @@ namespace SPTarkov.Common.Extensions; public static class ObjectExtensions { private static readonly Dictionary> _indexedProperties = new(); - private static readonly object _indexedPropertiesLockObject = new(); + private static readonly Lock _indexedPropertiesLockObject = new(); private static bool TryGetCachedProperty(Type type, string key, out PropertyInfo cachedProperty) { @@ -32,10 +32,8 @@ public static class ObjectExtensions /// public static bool ContainsJsonProp(this object? obj, T key) { - if (obj == null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(obj); + ArgumentNullException.ThrowIfNull(key); return TryGetCachedProperty(obj.GetType(), key.ToString(), out _); } diff --git a/Libraries/SPTarkov.Common/Extensions/StringExtensions.cs b/Libraries/SPTarkov.Common/Extensions/StringExtensions.cs index 0c13f39b..4910e4a5 100644 --- a/Libraries/SPTarkov.Common/Extensions/StringExtensions.cs +++ b/Libraries/SPTarkov.Common/Extensions/StringExtensions.cs @@ -6,7 +6,7 @@ namespace SPTarkov.Common.Extensions; public static class StringExtensions { private static readonly Dictionary RegexCache = new(); - private static readonly object RegexCacheLock = new(); + private static readonly Lock RegexCacheLock = new(); public static string RegexReplace(this string source, [StringSyntax(StringSyntaxAttribute.Regex)] string regexString, string newValue) { diff --git a/Libraries/SPTarkov.DI/DependencyInjectionRegistrator.cs b/Libraries/SPTarkov.DI/DependencyInjectionRegistrator.cs index a07b0457..8014709f 100644 --- a/Libraries/SPTarkov.DI/DependencyInjectionRegistrator.cs +++ b/Libraries/SPTarkov.DI/DependencyInjectionRegistrator.cs @@ -25,7 +25,7 @@ public static class DependencyInjectionRegistrator { var attributes = (Injectable[]) Attribute.GetCustomAttributes(t, typeof(Injectable)); var registerableType = t; - var registerableComponents = new List(); + var registerableComponents = new List(); foreach (var attribute in attributes) { // if we have a type override this takes priority @@ -39,34 +39,36 @@ public static class DependencyInjectionRegistrator registerableType = registerableType.GetInterfaces()[0]; } - registerableComponents.Add(new RegisterableType(registerableType, t, attribute)); + registerableComponents.Add(new RegistrableType(registerableType, t, attribute)); } return registerableComponents; } ) - .GroupBy(t => t.RegisterableInterface.FullName); + .GroupBy(t => t.RegistrableInterface.FullName); // We get all injectable services to register them on our services foreach (var groupedInjectables in groupedTypes) - foreach (var valueTuple in groupedInjectables.OrderBy(t => t.InjectableAttribute.TypePriority)) { - if (valueTuple.TypeToRegister.IsGenericType) + foreach (var valueTuple in groupedInjectables.OrderBy(t => t.InjectableAttribute.TypePriority)) { - RegisterGenericComponents(builderServices, valueTuple); - } - else - { - RegisterComponent( - builderServices, - valueTuple.InjectableAttribute.InjectionType, - valueTuple.RegisterableInterface, - valueTuple.TypeToRegister - ); + if (valueTuple.TypeToRegister.IsGenericType) + { + RegisterGenericComponents(builderServices, valueTuple); + } + else + { + RegisterComponent( + builderServices, + valueTuple.InjectableAttribute.InjectionType, + valueTuple.RegistrableInterface, + valueTuple.TypeToRegister + ); + } } } } - private static void RegisterGenericComponents(IServiceCollection builderServices, RegisterableType valueTuple) + private static void RegisterGenericComponents(IServiceCollection builderServices, RegistrableType valueTuple) { try { @@ -78,7 +80,7 @@ public static class DependencyInjectionRegistrator } _allConstructors ??= _allLoadedTypes.SelectMany(t => t.GetConstructors()).ToList(); - var typeName = $"{valueTuple.RegisterableInterface.Namespace}.{valueTuple.RegisterableInterface.Name}"; + var typeName = $"{valueTuple.RegistrableInterface.Namespace}.{valueTuple.RegistrableInterface.Name}"; try { var matchedConstructors = _allConstructors.Where( @@ -96,20 +98,19 @@ public static class DependencyInjectionRegistrator } foreach (var matchedConstructor in constructorInfos) - foreach (var parameterInfo in matchedConstructor.GetParameters() - .Where( - p => p.ParameterType.IsGenericType && - p.ParameterType.GetGenericTypeDefinition().FullName == typeName - )) { - var parameters = parameterInfo.ParameterType.GetGenericArguments(); - var typedGeneric = valueTuple.TypeToRegister.MakeGenericType(parameters); - RegisterComponent( - builderServices, - valueTuple.InjectableAttribute.InjectionType, - parameterInfo.ParameterType, - typedGeneric - ); + var constructorParams = matchedConstructor.GetParameters(); + foreach (var parameterInfo in constructorParams.Where(x => IsMatchingGenericType(x,typeName))) + { + var parameters = parameterInfo.ParameterType.GetGenericArguments(); + var typedGeneric = valueTuple.TypeToRegister.MakeGenericType(parameters); + RegisterComponent( + builderServices, + valueTuple.InjectableAttribute.InjectionType, + parameterInfo.ParameterType, + typedGeneric + ); + } } } catch (Exception e) @@ -119,26 +120,32 @@ public static class DependencyInjectionRegistrator } } + private static bool IsMatchingGenericType(ParameterInfo paramInfo, string typeName) + { + return paramInfo.ParameterType.IsGenericType && + paramInfo.ParameterType.GetGenericTypeDefinition().FullName == typeName; + } + private static void RegisterComponent( IServiceCollection builderServices, InjectionType injectionType, - Type registerableInterface, - Type imlementationType + Type registrableInterface, + Type implementationType ) { switch (injectionType) { case InjectionType.Singleton: - builderServices.AddSingleton(registerableInterface, imlementationType); + builderServices.AddSingleton(registrableInterface, implementationType); break; case InjectionType.Transient: - builderServices.AddTransient(registerableInterface, imlementationType); + builderServices.AddTransient(registrableInterface, implementationType); break; case InjectionType.Scoped: - builderServices.AddScoped(registerableInterface, imlementationType); + builderServices.AddScoped(registrableInterface, implementationType); break; default: - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(injectionType), "unknown injection type"); } } @@ -159,12 +166,12 @@ public static class DependencyInjectionRegistrator ); } - private class RegisterableType(Type registerableInterface, Type typeToRegister, Injectable injectableAttribute) + private sealed class RegistrableType(Type registrableInterface, Type typeToRegister, Injectable injectableAttribute) { - public Type RegisterableInterface + public Type RegistrableInterface { get; - } = registerableInterface; + } = registrableInterface; public Type TypeToRegister { diff --git a/Libraries/SPTarkov.Server.Core/Callbacks/ItemEventCallbacks.cs b/Libraries/SPTarkov.Server.Core/Callbacks/ItemEventCallbacks.cs index e5747540..128faf68 100644 --- a/Libraries/SPTarkov.Server.Core/Callbacks/ItemEventCallbacks.cs +++ b/Libraries/SPTarkov.Server.Core/Callbacks/ItemEventCallbacks.cs @@ -24,7 +24,7 @@ public class ItemEventCallbacks(HttpResponseUtil _httpResponseUtil, ItemEventRou /// /// The list of warnings to check for critical errors /// - public bool IsCriticalError(List? warnings) + public static bool IsCriticalError(List? warnings) { if (warnings is null) { @@ -48,7 +48,7 @@ public class ItemEventCallbacks(HttpResponseUtil _httpResponseUtil, ItemEventRou return false; } - public BackendErrorCodes GetErrorCode(List warnings) + public static BackendErrorCodes GetErrorCode(List warnings) { // Cast int to string to get the error code of 220 for Unknown Error. return warnings.FirstOrDefault()?.Code is null ? BackendErrorCodes.UnknownError : warnings.FirstOrDefault()?.Code ?? BackendErrorCodes.UnknownError; diff --git a/Libraries/SPTarkov.Server.Core/Callbacks/SaveCallbacks.cs b/Libraries/SPTarkov.Server.Core/Callbacks/SaveCallbacks.cs index abfcd228..fd0f951f 100644 --- a/Libraries/SPTarkov.Server.Core/Callbacks/SaveCallbacks.cs +++ b/Libraries/SPTarkov.Server.Core/Callbacks/SaveCallbacks.cs @@ -28,9 +28,9 @@ public class SaveCallbacks( return "spt-save"; } - public bool OnUpdate(long secondsSinceLastRun) + public bool OnUpdate(long timeSinceLastRun) { - if (secondsSinceLastRun > _coreConfig.ProfileSaveIntervalInSeconds) + if (timeSinceLastRun > _coreConfig.ProfileSaveIntervalInSeconds) { _saveServer.Save(); return true; diff --git a/Libraries/SPTarkov.Server.Core/Context/ApplicationContext.cs b/Libraries/SPTarkov.Server.Core/Context/ApplicationContext.cs index 626e7d75..00d524a0 100644 --- a/Libraries/SPTarkov.Server.Core/Context/ApplicationContext.cs +++ b/Libraries/SPTarkov.Server.Core/Context/ApplicationContext.cs @@ -7,11 +7,27 @@ public class ApplicationContext { protected const short MaxSavedValues = 10; protected readonly Dictionary> variables = new(); - private readonly Lock variablesLock = new(); + private readonly Lock _lockObject = new(); + + private static ApplicationContext? _applicationContext; + + /// + /// When ApplicationContext gets created by the DI container we store the singleton reference so we can provide it + /// statically for harmony patches! + /// + public ApplicationContext() + { + _applicationContext = this; + } + + public static ApplicationContext? GetInstance() + { + return _applicationContext; + } public ContextVariable? GetLatestValue(ContextVariableType type) { - lock (variablesLock) + lock (_lockObject) { if (variables.TryGetValue(type, out var savedValues)) { @@ -24,7 +40,7 @@ public class ApplicationContext public ICollection GetValues(ContextVariableType type) { - lock (variablesLock) + lock (_lockObject) { var values = new List(); if (variables.TryGetValue(type, out var savedValues)) @@ -38,7 +54,7 @@ public class ApplicationContext public void AddValue(ContextVariableType type, object value) { - lock (variablesLock) + lock (_lockObject) { if (!variables.TryGetValue(type, out var savedValues)) { @@ -57,7 +73,7 @@ public class ApplicationContext public void ClearValues(ContextVariableType type) { - lock (variablesLock) + lock (_lockObject) { variables.Remove(type); } diff --git a/Libraries/SPTarkov.Server.Core/Context/ContextVariableType.cs b/Libraries/SPTarkov.Server.Core/Context/ContextVariableType.cs index 85b3d35b..69dcda07 100644 --- a/Libraries/SPTarkov.Server.Core/Context/ContextVariableType.cs +++ b/Libraries/SPTarkov.Server.Core/Context/ContextVariableType.cs @@ -19,5 +19,6 @@ public enum ContextVariableType TRANSIT_INFO = 5, APP_BUILDER = 6, LOADED_MOD_ASSEMBLIES = 7, - WEB_APPLICATION = 8 + WEB_APPLICATION = 8, + SERVICE_PROVIDER = 9 } diff --git a/Libraries/SPTarkov.Server.Core/Controllers/AchievementController.cs b/Libraries/SPTarkov.Server.Core/Controllers/AchievementController.cs index d924c04b..5b4fae73 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/AchievementController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/AchievementController.cs @@ -40,7 +40,7 @@ public class AchievementController( var profiles = profileHelper.GetProfiles(); var achievements = databaseService.GetAchievements(); - foreach (var achievement in achievements) { + foreach (var achievementId in achievements.Select(achievement => achievement.Id).Where(achievementId => !string.IsNullOrEmpty(achievementId))) { var percentage = 0; foreach (var (profileId, profile) in profiles) { if (coreConfig.Features.AchievementProfileIdBlacklist.Contains(profileId)) @@ -53,7 +53,7 @@ public class AchievementController( continue; } - if (!profile.CharacterData.PmcData.Achievements.ContainsKey(achievement.Id)) + if (!profile.CharacterData.PmcData.Achievements.ContainsKey(achievementId)) { continue; } @@ -62,7 +62,7 @@ public class AchievementController( } percentage = (percentage / profiles.Count) * 100; - stats.Add(achievement.Id, percentage); + stats.Add(achievementId, percentage); } return new CompletedAchievementsResponse{ Elements = stats }; diff --git a/Libraries/SPTarkov.Server.Core/Controllers/BotController.cs b/Libraries/SPTarkov.Server.Core/Controllers/BotController.cs index 0ddb9dd2..69bff177 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/BotController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/BotController.cs @@ -223,7 +223,7 @@ public class BotController( /// protected List GenerateBotWave(GenerateCondition generateRequest, BotGenerationDetails botGenerationDetails, string sessionId) { - var isEventBot = generateRequest.Role?.ToLower().Contains("event"); + var isEventBot = generateRequest.Role?.Contains("event", StringComparison.OrdinalIgnoreCase); if (isEventBot.GetValueOrDefault(false)) { // Add eventRole data + reassign role property to be base type diff --git a/Libraries/SPTarkov.Server.Core/Controllers/BuildController.cs b/Libraries/SPTarkov.Server.Core/Controllers/BuildController.cs index 35caf2a9..8fdf6b19 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/BuildController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/BuildController.cs @@ -130,11 +130,10 @@ public class BuildController( /// public void SaveEquipmentBuild(string sessionID, PresetBuildActionRequestData request) { - var buildType = "equipmentBuilds"; var profile = _profileHelper.GetFullProfile(sessionID); var pmcData = profile.CharacterData.PmcData; - List existingSavedEquipmentBuilds = + var existingSavedEquipmentBuilds = _saveServer.GetProfile(sessionID).UserBuildData.EquipmentBuilds; // Replace duplicate ID's. The first item is the base item. @@ -150,7 +149,7 @@ public class BuildController( Items = request.Items }; - var existingBuild = existingSavedEquipmentBuilds.FirstOrDefault( + var existingBuild = existingSavedEquipmentBuilds?.FirstOrDefault( build => build.Name == request.Name || build.Id == request.Id ); if (existingBuild is not null) @@ -200,16 +199,15 @@ public class BuildController( profile.UserBuildData.MagazineBuilds ??= []; - var existingArrayId = profile.UserBuildData.MagazineBuilds.FirstOrDefault(item => item.Name == request.Name); - if (existingArrayId is not null) + // Check if template with desired name already exists and remove it + var magazineBuildToRemove = profile.UserBuildData.MagazineBuilds.FirstOrDefault(item => item.Name == request.Name); + if (magazineBuildToRemove is not null) { - { - profile.UserBuildData.MagazineBuilds.Remove(existingArrayId); - } - - - profile.UserBuildData.MagazineBuilds.Add(result); + profile.UserBuildData.MagazineBuilds.Remove(magazineBuildToRemove); } + + // Add new template to profile + profile.UserBuildData.MagazineBuilds.Add(result); } /// diff --git a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs index 3365ab05..491b768e 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs @@ -141,7 +141,7 @@ public class HideoutController( var timestamp = _timeUtil.GetTimeStamp(); - profileHideoutArea.CompleteTime = Math.Round((double) (timestamp - ctime)); + profileHideoutArea.CompleteTime = (int)Math.Round(timestamp - ctime.Value); profileHideoutArea.Constructing = true; } } diff --git a/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs b/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs index d7e72aeb..99a92129 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/InsuranceController.cs @@ -542,7 +542,7 @@ public class InsuranceController( /// Attachment count to remove protected double GetAttachmentCountToRemove(Dictionary weightedAttachmentByPrice, string? traderId) { - var removeCount = 0; + const int removeCount = 0; if (_randomUtil.GetChance100(_insuranceConfig.ChanceNoAttachmentsTakenPercent)) { diff --git a/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs b/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs index de2f13fc..8460e9d9 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs @@ -236,7 +236,7 @@ public class InventoryController( var desiredArea = pmcData.Hideout.Areas.FirstOrDefault(area => area.Type == hideoutAreaType); if (desiredArea is not null) { - desiredArea.Level = newValue; + desiredArea.Level = (int?)newValue; } break; @@ -610,11 +610,10 @@ public class InventoryController( public void BindItem(PmcData pmcData, InventoryBindRequestData bindRequest, string sessionId, ItemEventRouterResponse output) { - foreach (var kvp in pmcData.Inventory.FastPanel.Where(kvp => kvp.Value == bindRequest.Index)) + // Remove link + if (pmcData.Inventory.FastPanel.ContainsKey(bindRequest.Index)) { - pmcData.Inventory.FastPanel.Remove(kvp.Key); - - break; + pmcData.Inventory.FastPanel.Remove(bindRequest.Index); } // Create link between fast panel slot and requested item diff --git a/Libraries/SPTarkov.Server.Core/Controllers/QuestController.cs b/Libraries/SPTarkov.Server.Core/Controllers/QuestController.cs index 246ae6e8..26bec296 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/QuestController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/QuestController.cs @@ -343,8 +343,8 @@ public class QuestController( output ); - // Complete - if (totalItemCountToRemove == handedInCount) + // Complete - handedInCount == totalItemCountToRemove + if (Math.Abs(totalItemCountToRemove - handedInCount) < 0.01) { break; } diff --git a/Libraries/SPTarkov.Server.Core/Controllers/RagfairController.cs b/Libraries/SPTarkov.Server.Core/Controllers/RagfairController.cs index 484ed57e..9fb003e5 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/RagfairController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/RagfairController.cs @@ -456,10 +456,9 @@ public class RagfairController var output = _eventOutputHolder.GetOutput(sessionID); var fullProfile = _profileHelper.GetFullProfile(sessionID); - var validationMessage = ""; - if (!IsValidPlayerOfferRequest(offerRequest, validationMessage)) + if (!IsValidPlayerOfferRequest(offerRequest)) { - return _httpResponseUtil.AppendErrorToOutput(output, validationMessage); + return _httpResponseUtil.AppendErrorToOutput(output, "Unable to add offer, check server for error"); } var typeOfOffer = GetOfferType(offerRequest); @@ -492,9 +491,8 @@ public class RagfairController /// Is the item to be listed on the flea valid /// /// Client offer request - /// message to show to player when offer is invalid /// Is offer valid - protected bool IsValidPlayerOfferRequest(AddOfferRequestData offerRequest, string validationMessage) + protected bool IsValidPlayerOfferRequest(AddOfferRequestData offerRequest) { if (offerRequest?.Items is null || offerRequest.Items.Count == 0) { diff --git a/Libraries/SPTarkov.Server.Core/DI/ISerializer.cs b/Libraries/SPTarkov.Server.Core/DI/ISerializer.cs index a65d3543..b566c16e 100644 --- a/Libraries/SPTarkov.Server.Core/DI/ISerializer.cs +++ b/Libraries/SPTarkov.Server.Core/DI/ISerializer.cs @@ -3,5 +3,5 @@ namespace SPTarkov.Server.Core.DI; public interface ISerializer { public void Serialize(string sessionID, HttpRequest req, HttpResponse resp, object? body); - public bool CanHandle(string something); + public bool CanHandle(string route); } diff --git a/Libraries/SPTarkov.Server.Core/Generators/BotEquipmentModGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/BotEquipmentModGenerator.cs index 9641d013..84deeb9c 100644 --- a/Libraries/SPTarkov.Server.Core/Generators/BotEquipmentModGenerator.cs +++ b/Libraries/SPTarkov.Server.Core/Generators/BotEquipmentModGenerator.cs @@ -1,3 +1,4 @@ +using System.Collections.Frozen; using SPTarkov.Server.Core.Helpers; using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Eft.Common; @@ -40,10 +41,10 @@ public class BotEquipmentModGenerator( ) { protected BotConfig _botConfig = _configServer.GetConfig(); - protected static HashSet _modSightIds = ["mod_sight_front", "mod_sight_rear"]; + protected static readonly FrozenSet _modSightIds = ["mod_sight_front", "mod_sight_rear"]; // Slots that hold scopes - protected static HashSet _scopeIds = + protected static readonly FrozenSet _scopeIds = [ "mod_scope", "mod_mount", @@ -55,14 +56,19 @@ public class BotEquipmentModGenerator( ]; // Slots that hold muzzles - protected static HashSet _muzzleIds = ["mod_muzzle", "mod_muzzle_000", "mod_muzzle_001"]; + protected static readonly FrozenSet _muzzleIds = ["mod_muzzle", "mod_muzzle_000", "mod_muzzle_001"]; // Slots a weapon can store its stock in - protected static HashSet _stockSlots = ["mod_stock", "mod_stock_000", "mod_stock_001", "mod_stock_akms"]; + protected static readonly FrozenSet _stockSlots = ["mod_stock", "mod_stock_000", "mod_stock_001", "mod_stock_akms"]; // Slots that hold cartridges - protected static HashSet _cartridgeHolderSlots = - ["mod_magazine", "patron_in_weapon", "patron_in_weapon_000", "patron_in_weapon_001", "cartridges"]; + protected static readonly FrozenSet _cartridgeHolderSlots = + [ + "mod_magazine", + "patron_in_weapon", + "patron_in_weapon_000", + "patron_in_weapon_001", + "cartridges"]; /// /// Check mods are compatible and add to array @@ -313,9 +319,9 @@ public class BotEquipmentModGenerator( // Get lowest and highest plate classes available for this armor var minMaxArmorPlateClass = GetMinMaxArmorPlateClass(platesFromDb.ToList()); - // Increment plate class level in attempt to get useable plate + // Increment plate class level in attempt to get usable plate var findCompatiblePlateAttempts = 0; - var maxAttempts = 3; + const int maxAttempts = 3; for (var i = 0; i < maxAttempts; i++) { var chosenArmorPlateLevelDouble = int.Parse(chosenArmorPlateLevelString) + 1; @@ -832,16 +838,16 @@ public class BotEquipmentModGenerator( var isMount = _itemHelper.IsOfBaseclass(itemTplWithKeysToSort, BaseClasses.MOUNT); HashSet sortedKeys = []; - var modRecieverKey = "mod_reciever"; - var modMount001Key = "mod_mount_001"; - var modGasBlockKey = "mod_gas_block"; - var modPistolGrip = "mod_pistol_grip"; - var modStockKey = "mod_stock"; - var modBarrelKey = "mod_barrel"; - var modHandguardKey = "mod_handguard"; - var modMountKey = "mod_mount"; - var modScopeKey = "mod_scope"; - var modScope000Key = "mod_scope_000"; + const string modRecieverKey = "mod_reciever"; + const string modMount001Key = "mod_mount_001"; + const string modGasBlockKey = "mod_gas_block"; + const string modPistolGrip = "mod_pistol_grip"; + const string modStockKey = "mod_stock"; + const string modBarrelKey = "mod_barrel"; + const string modHandguardKey = "mod_handguard"; + const string modMountKey = "mod_mount"; + const string modScopeKey = "mod_scope"; + const string modScope000Key = "mod_scope_000"; // Mounts are a special case, they need scopes first before more mounts if (isMount) @@ -1482,7 +1488,7 @@ public class BotEquipmentModGenerator( /// e.g. mod_magazine / patron_in_weapon_000 /// /// string array - public HashSet GetAmmoContainers() + public FrozenSet GetAmmoContainers() { return _cartridgeHolderSlots; } diff --git a/Libraries/SPTarkov.Server.Core/Generators/BotInventoryGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/BotInventoryGenerator.cs index 1df78c38..a1f1d1c4 100644 --- a/Libraries/SPTarkov.Server.Core/Generators/BotInventoryGenerator.cs +++ b/Libraries/SPTarkov.Server.Core/Generators/BotInventoryGenerator.cs @@ -1,3 +1,4 @@ +using System.Collections.Frozen; using SPTarkov.Server.Core.Context; using SPTarkov.Server.Core.Helpers; using SPTarkov.Server.Core.Models.Eft.Common.Tables; @@ -39,7 +40,7 @@ public class BotInventoryGenerator( private readonly BotConfig _botConfig = _configServer.GetConfig(); // Slots handled individually inside `GenerateAndAddEquipmentToBot` - private static readonly HashSet _excludedEquipmentSlots = + private static readonly FrozenSet _excludedEquipmentSlots = [ EquipmentSlots.Pockets, EquipmentSlots.FirstPrimaryWeapon, diff --git a/Libraries/SPTarkov.Server.Core/Generators/LocationLootGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/LocationLootGenerator.cs index 1a813559..7a8be294 100644 --- a/Libraries/SPTarkov.Server.Core/Generators/LocationLootGenerator.cs +++ b/Libraries/SPTarkov.Server.Core/Generators/LocationLootGenerator.cs @@ -1056,7 +1056,7 @@ public class LocationLootGenerator( itemTemplate, // Magazine template staticAmmoDist, null, - _locationConfig.MinFillLooseMagazinePercent / 100 + _locationConfig.MinFillLooseMagazinePercent / 100d ); } @@ -1324,7 +1324,7 @@ public class LocationLootGenerator( itemTemplate, staticAmmoDist, null, - _locationConfig.MinFillStaticMagazinePercent / 100 + _locationConfig.MinFillStaticMagazinePercent / 100d ); // Replace existing magazine with above array diff --git a/Libraries/SPTarkov.Server.Core/Generators/PlayerScavGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/PlayerScavGenerator.cs index 666694e6..4e1daac5 100644 --- a/Libraries/SPTarkov.Server.Core/Generators/PlayerScavGenerator.cs +++ b/Libraries/SPTarkov.Server.Core/Generators/PlayerScavGenerator.cs @@ -216,7 +216,7 @@ public class PlayerScavGenerator( /// IBotType object protected BotType ConstructBotBaseTemplate(string botTypeForLoot) { - var baseScavType = "assault"; + const string baseScavType = "assault"; var asssaultBase = _cloner.Clone(_botHelper.GetBotTemplate(baseScavType)); // Loot bot is same as base bot, return base with no modification diff --git a/Libraries/SPTarkov.Server.Core/Generators/RepeatableQuestGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/RepeatableQuestGenerator.cs index 10f2f6d5..b1d93338 100644 --- a/Libraries/SPTarkov.Server.Core/Generators/RepeatableQuestGenerator.cs +++ b/Libraries/SPTarkov.Server.Core/Generators/RepeatableQuestGenerator.cs @@ -133,7 +133,7 @@ public class RepeatableQuestGenerator( var maxBodyPartsDifficulty = eliminationConfig.MinKills / bodyPartsConfig.MinProbability(); // maxDistDifficulty is defined by 2, this could be a tuning parameter if we don't like the reward generation - var maxDistDifficulty = 2; + const int maxDistDifficulty = 2; var maxKillDifficulty = eliminationConfig.MaxKills; diff --git a/Libraries/SPTarkov.Server.Core/Helpers/BotGeneratorHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/BotGeneratorHelper.cs index e48d28f6..65eda049 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/BotGeneratorHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/BotGeneratorHelper.cs @@ -10,6 +10,7 @@ using SPTarkov.Server.Core.Services; using SPTarkov.Server.Core.Utils; using SPTarkov.Common.Annotations; using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel; +using System.Collections.Frozen; namespace SPTarkov.Server.Core.Helpers; @@ -30,7 +31,7 @@ public class BotGeneratorHelper( protected PmcConfig _pmcConfig = _configServer.GetConfig(); // Equipment slot ids that do not conflict with other slots - protected static readonly HashSet _slotsWithNoCompatIssues = ["Scabbard", "Backpack", "SecureContainer", "Holster", "ArmBand"]; + protected static readonly FrozenSet _slotsWithNoCompatIssues = ["Scabbard", "Backpack", "SecureContainer", "Holster", "ArmBand"]; /// /// Adds properties to an item diff --git a/Libraries/SPTarkov.Server.Core/Helpers/BotHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/BotHelper.cs index 95ee7cdc..e9e1036e 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/BotHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/BotHelper.cs @@ -5,6 +5,7 @@ using SPTarkov.Server.Core.Servers; using SPTarkov.Server.Core.Services; using SPTarkov.Server.Core.Utils; using SPTarkov.Common.Annotations; +using System.Collections.Frozen; namespace SPTarkov.Server.Core.Helpers; @@ -18,7 +19,7 @@ public class BotHelper( { protected BotConfig _botConfig = _configServer.GetConfig(); protected PmcConfig _pmcConfig = _configServer.GetConfig(); - protected static readonly HashSet _pmcTypeIds = ["usec", "bear", "pmc", "pmcbear", "pmcusec"]; + protected static readonly FrozenSet _pmcTypeIds = ["usec", "bear", "pmc", "pmcbear", "pmcusec"]; protected Dictionary> _pmcNameCache = new(); /// @@ -70,7 +71,7 @@ public class BotHelper( /// bot type to add to friendly list public void AddBotToFriendlyList(DifficultyCategories difficultySettings, string typeToAdd) { - var friendlyBotTypesKey = "FRIENDLY_BOT_TYPES"; + const string friendlyBotTypesKey = "FRIENDLY_BOT_TYPES"; // Null guard if (difficultySettings.Mind[friendlyBotTypesKey] is null) @@ -88,7 +89,7 @@ public class BotHelper( /// bot type to add to revenge list public void AddBotToRevengeList(DifficultyCategories difficultySettings, string[] typesToAdd) { - var revengePropKey = "REVENGE_BOT_TYPES"; + const string revengePropKey = "REVENGE_BOT_TYPES"; // Nothing to add if (typesToAdd is null) diff --git a/Libraries/SPTarkov.Server.Core/Helpers/BotWeaponGeneratorHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/BotWeaponGeneratorHelper.cs index 732ff30c..832c4f88 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/BotWeaponGeneratorHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/BotWeaponGeneratorHelper.cs @@ -5,6 +5,7 @@ using SPTarkov.Server.Core.Servers; using SPTarkov.Server.Core.Services; using SPTarkov.Server.Core.Utils; using SPTarkov.Common.Annotations; +using System.Collections.Frozen; namespace SPTarkov.Server.Core.Helpers; @@ -20,7 +21,7 @@ public class BotWeaponGeneratorHelper( LocalisationService _localisationService ) { - private static readonly HashSet _magCheck = ["CylinderMagazine", "SpringDrivenCylinder"]; + private static readonly FrozenSet _magCheck = ["CylinderMagazine", "SpringDrivenCylinder"]; /// /// Get a randomized number of bullets for a specific magazine diff --git a/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/Commando/SptCommands/GiveCommand/GiveSptCommand.cs b/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/Commando/SptCommands/GiveCommand/GiveSptCommand.cs index 1deeba6b..2810c938 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/Commando/SptCommands/GiveCommand/GiveSptCommand.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/Commando/SptCommands/GiveCommand/GiveSptCommand.cs @@ -9,6 +9,7 @@ using SPTarkov.Server.Core.Services; using SPTarkov.Server.Core.Utils; using SPTarkov.Server.Core.Utils.Cloners; using SPTarkov.Common.Annotations; +using System.Collections.Frozen; namespace SPTarkov.Server.Core.Helpers.Dialogue.Commando.SptCommands.GiveCommand; @@ -29,7 +30,7 @@ public class GiveSptCommand( private static readonly Regex _commandRegex = new(@"^spt give (((([a-z]{2,5}) )?""(.+)""|\w+) )?([0-9]+)$"); // Exception for flares - protected static readonly HashSet _excludedPresetItems = + protected static readonly FrozenSet _excludedPresetItems = [ ItemTpl.FLARE_RSP30_REACTIVE_SIGNAL_CARTRIDGE_RED, ItemTpl.FLARE_RSP30_REACTIVE_SIGNAL_CARTRIDGE_GREEN, diff --git a/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/SPTFriend/Commands/HelloMessageHandler.cs b/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/SPTFriend/Commands/HelloMessageHandler.cs index 1bfe8c47..dffb5338 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/SPTFriend/Commands/HelloMessageHandler.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/Dialogue/SPTFriend/Commands/HelloMessageHandler.cs @@ -4,6 +4,7 @@ using SPTarkov.Server.Core.Models.Eft.Profile; using SPTarkov.Server.Core.Services; using SPTarkov.Server.Core.Utils; using SPTarkov.Common.Annotations; +using System.Collections.Frozen; namespace SPTarkov.Server.Core.Helpers.Dialogue.SPTFriend.Commands; @@ -12,7 +13,7 @@ public class HelloMessageHandler( MailSendService _mailSendService, RandomUtil _randomUtil) : IChatMessageHandler { - protected static readonly HashSet _listOfGreetings = ["hello", "hi", "sup", "yo", "hey", "bonjour"]; + protected static readonly FrozenSet _listOfGreetings = ["hello", "hi", "sup", "yo", "hey", "bonjour"]; public int GetPriority() diff --git a/Libraries/SPTarkov.Server.Core/Helpers/DialogueHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/DialogueHelper.cs index fe201c08..cdcc18d3 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/DialogueHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/DialogueHelper.cs @@ -109,21 +109,21 @@ public class DialogueHelper( return profile.DialogueRecords ?? (profile.DialogueRecords = new Dictionary()); } + /// + /// Find and return a profiles dialogue by id + /// + /// Profile to look in + /// Dialog to return + /// Dialogue public Models.Eft.Profile.Dialogue? GetDialogueFromProfile(string profileId, string dialogueId) { - Models.Eft.Profile.Dialogue? returnDialogue = null; var dialogues = GetDialogsForProfile(profileId); - - foreach (var dialogue in dialogues.Values) + if (dialogues.TryGetValue(dialogueId, out var dialogue)) { - if (dialogue.Id == dialogueId) - { - returnDialogue = dialogue; - } - - break; + return dialogue; } - return returnDialogue; + _logger.Error($"Unable to find a dialogue with id: {dialogueId} in profile: {profileId}"); + return null; } } diff --git a/Libraries/SPTarkov.Server.Core/Helpers/HandbookHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/HandbookHelper.cs index 328629dc..a8e7de84 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/HandbookHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/HandbookHelper.cs @@ -98,7 +98,7 @@ public class HandbookHelper( var handbookItem = _databaseService.GetHandbook().Items?.FirstOrDefault(item => item.Id == tpl); if (handbookItem is null) { - var newValue = 0; + const int newValue = 0; if (!_handbookPriceCache.Items.ById.TryAdd(tpl, newValue)) { diff --git a/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs index 1cb93fd7..2bcef28c 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs @@ -256,6 +256,11 @@ public class HideoutHelper( return hideoutProperties; } + /// + /// Does a water collection hideout area have a water filter installed + /// + /// Hideout area to check + /// protected bool DoesWaterCollectorHaveFilter(BotHideoutArea waterCollector) { // Can put filters in from L3 @@ -272,7 +277,7 @@ public class HideoutHelper( /// /// Iterate over productions and update their progress timers /// - /// Profile to check for productions and update + /// Profile to check for productions and update /// Hideout properties protected void UpdateProductionTimers( PmcData pmcData, @@ -913,7 +918,7 @@ public class HideoutHelper( var globalSkillsDb = _databaseService.GetGlobals().Configuration.SkillsSettings; // 100 resources last 8 hrs 20 min, 100/8.33/60/60 = 0.00333 - var filterDrainRate = 0.00333; + const double filterDrainRate = 0.00333d; var hideoutManagementConsumptionBonus = GetSkillBonusMultipliedBySkillLevel( pmcData, diff --git a/Libraries/SPTarkov.Server.Core/Helpers/InventoryHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/InventoryHelper.cs index ed3141a2..84cf3c25 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/InventoryHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/InventoryHelper.cs @@ -16,6 +16,7 @@ using SPTarkov.Server.Core.Utils.Cloners; using SPTarkov.Common.Annotations; using SPTarkov.Common.Extensions; using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel; +using System.Collections.Frozen; namespace SPTarkov.Server.Core.Helpers; @@ -36,7 +37,7 @@ public class InventoryHelper( ) { protected InventoryConfig _inventoryConfig = _configServer.GetConfig(); - private static readonly HashSet _variableSizeItemTypes = [BaseClasses.WEAPON, BaseClasses.FUNCTIONAL_MOD]; + private static readonly FrozenSet _variableSizeItemTypes = [BaseClasses.WEAPON, BaseClasses.FUNCTIONAL_MOD]; /// /// Add multiple items to player stash (assuming they all fit) diff --git a/Libraries/SPTarkov.Server.Core/Helpers/ItemHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/ItemHelper.cs index e63f0156..13cbd94d 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/ItemHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/ItemHelper.cs @@ -9,6 +9,7 @@ using SPTarkov.Server.Core.Utils.Cloners; using SPTarkov.Server.Core.Utils.Collections; using SPTarkov.Common.Annotations; using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel; +using System.Collections.Frozen; namespace SPTarkov.Server.Core.Helpers; @@ -27,7 +28,7 @@ public class ItemHelper( ICloner _cloner ) { - protected static readonly HashSet _defaultInvalidBaseTypes = + protected static readonly FrozenSet _defaultInvalidBaseTypes = [ BaseClasses.LOOT_CONTAINER, BaseClasses.MOB_CONTAINER, @@ -38,7 +39,7 @@ public class ItemHelper( BaseClasses.POCKETS ]; - protected static readonly HashSet _slotsAsStrings = + protected static readonly FrozenSet _slotsAsStrings = [ EquipmentSlots.Headwear.ToString(), EquipmentSlots.Earpiece.ToString(), @@ -56,7 +57,7 @@ public class ItemHelper( EquipmentSlots.Scabbard.ToString() ]; - protected static readonly HashSet _dogTagTpls = + protected static readonly FrozenSet _dogTagTpls = [ ItemTpl.BARTER_DOGTAG_BEAR, ItemTpl.BARTER_DOGTAG_BEAR_EOD, @@ -70,7 +71,7 @@ public class ItemHelper( ItemTpl.BARTER_DOGTAG_USEC_PRESTIGE_2 ]; - protected static readonly HashSet _softInsertIds = + protected static readonly FrozenSet _softInsertIds = [ "groin", "groin_back", @@ -88,7 +89,7 @@ public class ItemHelper( "helmet_ears" ]; - protected static readonly HashSet _removablePlateSlotIds = + protected static readonly FrozenSet _removablePlateSlotIds = [ "front_plate", "back_plate", @@ -451,7 +452,7 @@ public class ItemHelper( // Get all soft insert slot ids // @returns A List of soft insert ids (e.g. soft_armor_back, helmet_top) - public HashSet GetSoftInsertSlotIds() + public FrozenSet GetSoftInsertSlotIds() { return _softInsertIds; } @@ -1080,6 +1081,11 @@ public class ItemHelper( } } + /// + /// Regenerate all GUIDs with new IDs, except special item types (e.g. quest, sorting table, etc.) + /// + /// + /// public List ReplaceIDs(List items) { foreach (var item in items) @@ -1112,10 +1118,10 @@ public class ItemHelper( /// Player profile /// Insured items that should not have their IDs replaced /// Quick slot panel - /// List + /// Items public List ReplaceIDs( List originalItems, - PmcData? pmcData = null, + PmcData? pmcData, List? insuredItems = null, Dictionary? fastPanel = null) { @@ -1975,7 +1981,7 @@ public class ItemHelper( // Get a list of slot names that hold removable plates // Returns Array of slot ids (e.g. front_plate) - public HashSet GetRemovablePlateSlotIds() + public FrozenSet GetRemovablePlateSlotIds() { return _removablePlateSlotIds; } diff --git a/Libraries/SPTarkov.Server.Core/Helpers/PresetHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/PresetHelper.cs index fd28fa3d..5391d8f8 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/PresetHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/PresetHelper.cs @@ -148,6 +148,11 @@ public class PresetHelper( return null; } + if (presetDetails.DefaultId is null) + { + return null; + } + // Use default preset id from above cache to find the weapon/equipment preset if (!_defaultWeaponPresets.TryGetValue(presetDetails.DefaultId, out var defaultPreset)) { diff --git a/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs index b6f36bd2..8d71d0b2 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs @@ -10,6 +10,7 @@ using SPTarkov.Server.Core.Utils; using SPTarkov.Server.Core.Utils.Cloners; using SPTarkov.Common.Annotations; using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel; +using System.Collections.Frozen; namespace SPTarkov.Server.Core.Helpers; @@ -27,7 +28,7 @@ public class ProfileHelper( ConfigServer _configServer ) { - protected static readonly HashSet gameEditionsWithFreeRefresh = ["edge_of_darkness", "unheard_edition"]; + protected static readonly FrozenSet gameEditionsWithFreeRefresh = ["edge_of_darkness", "unheard_edition"]; protected InventoryConfig _inventoryConfig = _configServer.GetConfig(); /// diff --git a/Libraries/SPTarkov.Server.Core/Helpers/QuestHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/QuestHelper.cs index eb7ae2f5..d6782866 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/QuestHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/QuestHelper.cs @@ -1028,7 +1028,7 @@ public class QuestHelper( var clientQuestsClone = _cloner.Clone(GetClientQuests(sessionID)); // Must be gathered prior to applyQuestReward() & failQuests() - var newQuestState = QuestStatusEnum.Success; + const QuestStatusEnum newQuestState = QuestStatusEnum.Success; UpdateQuestState(pmcData, newQuestState, completedQuestId); var questRewards = _questRewardHelper.ApplyQuestReward( pmcData, diff --git a/Libraries/SPTarkov.Server.Core/Helpers/RagfairOfferHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/RagfairOfferHelper.cs index ba999e96..c89bcf61 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/RagfairOfferHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/RagfairOfferHelper.cs @@ -12,6 +12,7 @@ using SPTarkov.Server.Core.Services; using SPTarkov.Server.Core.Utils; using SPTarkov.Common.Annotations; using SPTarkov.Common.Extensions; +using System.Collections.Frozen; namespace SPTarkov.Server.Core.Helpers; @@ -43,7 +44,7 @@ public class RagfairOfferHelper( protected BotConfig _botConfig = _configServer.GetConfig(); protected RagfairConfig _ragfairConfig = _configServer.GetConfig(); - protected static readonly HashSet _currencies = ["all", "RUB", "USD", "EUR"]; + protected static readonly FrozenSet _currencies = ["all", "RUB", "USD", "EUR"]; /// /// Passthrough to ragfairOfferService.getOffers(), get flea offers a player should see diff --git a/Libraries/SPTarkov.Server.Core/Helpers/TradeHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/TradeHelper.cs index 6b55fe3d..16f09b1d 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/TradeHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/TradeHelper.cs @@ -275,7 +275,7 @@ public class TradeHelper( IncrementCirculateSoldToTraderCounter(profileWithItemsToSell, profileToReceiveMoney, sellRequest); } - var pattern = @"\s+"; + const string pattern = @"\s+"; // Find item in inventory and remove it foreach (var itemToBeRemoved in sellRequest.Items) @@ -320,7 +320,7 @@ public class TradeHelper( ProcessSellTradeRequestData sellRequest ) { - var circulateQuestId = "6663149f1d3ec95634095e75"; + const string circulateQuestId = "6663149f1d3ec95634095e75"; var activeCirculateQuest = profileToReceiveMoney.Quests.FirstOrDefault( quest => quest.QId == circulateQuestId && quest.Status == QuestStatusEnum.Started ); diff --git a/Libraries/SPTarkov.Server.Core/Loaders/BundleLoader.cs b/Libraries/SPTarkov.Server.Core/Loaders/BundleLoader.cs index 23734028..74b46715 100644 --- a/Libraries/SPTarkov.Server.Core/Loaders/BundleLoader.cs +++ b/Libraries/SPTarkov.Server.Core/Loaders/BundleLoader.cs @@ -149,28 +149,33 @@ namespace SPTarkov.Server.Core.Loaders } } } -} -public record BundleManifest -{ - [JsonPropertyName("manifest")] - public List Manifest { get; set; } -} - -public record BundleManifestEntry -{ - [JsonPropertyName("key")] - public string Key + public record BundleManifest { - get; - set; + [JsonPropertyName("manifest")] + public List Manifest + { + get; set; + } } - [JsonPropertyName("dependencyKeys")] - public List? DependencyKeys + public record BundleManifestEntry { - get; - set; + [JsonPropertyName("key")] + public string Key + { + get; + set; + } + + [JsonPropertyName("dependencyKeys")] + public List? DependencyKeys + { + get; + set; + } } } + + 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 f25a510a..f63036c3 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/BotBase.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/BotBase.cs @@ -1841,7 +1841,7 @@ public record BotHideoutArea } [JsonPropertyName("level")] - public double? Level + public int? Level { get; set; @@ -1865,7 +1865,7 @@ public record BotHideoutArea /// Must be integer /// [JsonPropertyName("completeTime")] - public double? CompleteTime + public int? CompleteTime { get; set; @@ -1899,7 +1899,7 @@ public record HideoutSlot /// SPT specific value to keep track of what index this slot is (0,1,2,3 etc.) /// [JsonPropertyName("locationIndex")] - public double? LocationIndex + public int? LocationIndex { get; set; diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Match/RaidSettings.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Match/RaidSettings.cs index 181b8a91..30809e33 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Eft/Match/RaidSettings.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Match/RaidSettings.cs @@ -14,6 +14,13 @@ public record RaidSettings set; } + [JsonPropertyName("onlinePveRaidStates")] + public Dictionary OnlinePveRaidStates + { + get; + set; + } = []; + [JsonPropertyName("location")] public string? Location { diff --git a/Libraries/SPTarkov.Server.Core/Models/Spt/Presets/PresetCacheDetails.cs b/Libraries/SPTarkov.Server.Core/Models/Spt/Presets/PresetCacheDetails.cs index 13edcedc..4745c1e7 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Spt/Presets/PresetCacheDetails.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Spt/Presets/PresetCacheDetails.cs @@ -10,7 +10,7 @@ } // Id of the default preset for this tpl - public string DefaultId + public string? DefaultId { get; set; diff --git a/Libraries/SPTarkov.Server.Core/Models/Spt/Server/Locations.cs b/Libraries/SPTarkov.Server.Core/Models/Spt/Server/Locations.cs index 6054cb0a..a01dfade 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Spt/Server/Locations.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Spt/Server/Locations.cs @@ -1,3 +1,4 @@ +using System.Collections.Frozen; using System.Text.Json.Serialization; using SPTarkov.Server.Core.Models.Eft.Common.Tables; @@ -7,7 +8,7 @@ public record Locations { // sometimes we get the key or value given so save changing logic in each place // have it key both - private static readonly Dictionary _locationMappings = new() + private readonly FrozenDictionary _locationMappings = new Dictionary { // EFT { "factory4_day", "Factory4Day" }, @@ -48,7 +49,7 @@ public record Locations { "Woods", "Woods" }, { "Sandbox", "Sandbox" }, { "SandboxHigh", "SandboxHigh" } - }; + }.ToFrozenDictionary(); private Dictionary? _locationDictionaryCache; @@ -209,7 +210,7 @@ public record Locations /// public string GetMappedKey(string key) { - return _locationMappings.TryGetValue(key, out var value) ? value : key; + return _locationMappings.GetValueOrDefault(key, key); } private void HydrateDictionary() diff --git a/Libraries/SPTarkov.Server.Core/Servers/ConfigServer.cs b/Libraries/SPTarkov.Server.Core/Servers/ConfigServer.cs index 16004c7a..29d88a04 100644 --- a/Libraries/SPTarkov.Server.Core/Servers/ConfigServer.cs +++ b/Libraries/SPTarkov.Server.Core/Servers/ConfigServer.cs @@ -63,7 +63,7 @@ public class ConfigServer } // Get all filepaths - var filepath = "./Assets/configs/"; + const string filepath = "./Assets/configs/"; var files = _fileUtil.GetFiles(filepath); // Add file content to result diff --git a/Libraries/SPTarkov.Server.Core/Servers/HttpServer.cs b/Libraries/SPTarkov.Server.Core/Servers/HttpServer.cs index 62045914..d86aa215 100644 --- a/Libraries/SPTarkov.Server.Core/Servers/HttpServer.cs +++ b/Libraries/SPTarkov.Server.Core/Servers/HttpServer.cs @@ -133,7 +133,16 @@ public class HttpServer( } - _httpListeners.SingleOrDefault(l => l.CanHandle(sessionId, context.Request))?.Handle(sessionId, context.Request, context.Response); + try + { + _httpListeners.SingleOrDefault(l => l.CanHandle(sessionId, context.Request))?.Handle(sessionId, context.Request, context.Response); + } + catch (Exception ex) + { + _logger.Critical(ex.Message); + _logger.Critical(ex.StackTrace); + } + // This http request would be passed through the SPT Router and handled by an ICallback } diff --git a/Libraries/SPTarkov.Server.Core/Servers/Ws/SptWebSocketConnectionHandler.cs b/Libraries/SPTarkov.Server.Core/Servers/Ws/SptWebSocketConnectionHandler.cs index 08a7244e..6c5bfd78 100644 --- a/Libraries/SPTarkov.Server.Core/Servers/Ws/SptWebSocketConnectionHandler.cs +++ b/Libraries/SPTarkov.Server.Core/Servers/Ws/SptWebSocketConnectionHandler.cs @@ -22,7 +22,7 @@ public class SptWebSocketConnectionHandler( ) : IWebSocketConnectionHandler { protected WsPing _defaultNotification = new(); - protected Lock _lockObject = new(); + protected readonly Lock _lockObject = new(); protected Dictionary _sockets = new(); public string GetHookUrl() diff --git a/Libraries/SPTarkov.Server.Core/Services/BackupService.cs b/Libraries/SPTarkov.Server.Core/Services/BackupService.cs index 47ebf65f..f0f88c21 100644 --- a/Libraries/SPTarkov.Server.Core/Services/BackupService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/BackupService.cs @@ -44,9 +44,9 @@ public class BackupService _backupConfig = configServer.GetConfig(); } - /** - * Start the backup interval if enabled in config. - */ + /// + /// Start the backup interval if enabled in config. + /// public void StartBackupSystem() { if (!_backupConfig.BackupInterval.Enabled) @@ -75,14 +75,11 @@ public class BackupService ); } - /** - * Initializes the backup process. - * - * This method orchestrates the profile backup service. Handles copying profiles to a backup directory and cleaning - * up old backups if the number exceeds the configured maximum. - * - * @returns A promise that resolves when the backup process is complete. - */ + /// + /// Initializes the backup process.
+ /// This method orchestrates the profile backup service. Handles copying profiles to a backup directory and cleaning + /// up old backups if the number exceeds the configured maximum. + ///
public void Init() { if (!IsEnabled()) @@ -146,11 +143,10 @@ public class BackupService CleanBackups(); } - /** - * Check to see if the backup service is enabled via the config. - * - * @returns True if enabled, false otherwise. - */ + /// + /// Check to see if the backup service is enabled via the config. + /// + /// True if enabled, false otherwise. protected bool IsEnabled() { if (_backupConfig.Enabled) @@ -166,23 +162,21 @@ public class BackupService return false; } - /** - * Generates the target directory path for the backup. The directory path is constructed using the `directory` from - * the configuration and the current backup date. - * - * @returns The target directory path for the backup. - */ + /// + /// Generates the target directory path for the backup. The directory path is constructed using the `directory` from + /// the configuration and the current backup date. + /// + /// The target directory path for the backup. protected string GenerateBackupTargetDir() { var backupDate = GenerateBackupDate(); return Path.GetFullPath($"{_backupConfig.Directory}/{backupDate}"); } - /** - * Generates a formatted backup date string in the format `YYYY-MM-DD_hh-mm-ss`. - * - * @returns The formatted backup date string. - */ + /// + /// Generates a formatted backup date string in the format `YYYY-MM-DD_hh-mm-ss`. + /// + /// The formatted backup date string. protected string GenerateBackupDate() { var date = _timeUtil.GetDateTimeNow(); @@ -190,14 +184,11 @@ public class BackupService return $"{date.Year}-{date.Month}-{date.Day}_{date.Hour}-{date.Minute}-{date.Second}"; } - /** - * Cleans up old backups in the backup directory. - * - * This method reads the backup directory, and sorts backups by modification time. If the number of backups exceeds - * the configured maximum, it deletes the oldest backups. - * - * @returns A promise that resolves when the cleanup is complete. - */ + /// + /// Cleans up old backups in the backup directory.
+ /// This method reads the backup directory, and sorts backups by modification time. If the number of backups exceeds + /// the configured maximum, it deletes the oldest backups. + ///
protected void CleanBackups() { var backupDir = _backupConfig.Directory; @@ -230,12 +221,11 @@ public class BackupService return result; } - /** - * Retrieves and sorts the backup file paths from the specified directory. - * - * @param dir - The directory to search for backup files. - * @returns A promise that resolves to a List of sorted backup file paths. - */ + /// + /// Retrieves and sorts the backup file paths from the specified directory. + /// + /// The directory to search for backup files. + /// List of sorted backup file paths. private List GetBackupPaths(string dir) { var backups = _fileUtil.GetDirectories(dir).ToList(); @@ -244,13 +234,12 @@ public class BackupService return backups; } - /** - * Compares two backup folder names based on their extracted dates. - * - * @param a - The name of the first backup folder. - * @param b - The name of the second backup folder. - * @returns The difference in time between the two dates in milliseconds, or `null` if either date is invalid. - */ + /// + /// Compares two backup folder names based on their extracted dates. + /// + /// The name of the first backup folder. + /// The name of the second backup folder. + /// The difference in time between the two dates in milliseconds, or `null` if either date is invalid. private int CompareBackupDates(string a, string b) { var dateA = ExtractDateFromFolderName(a); @@ -264,12 +253,11 @@ public class BackupService return (int) (dateA.Value.ToFileTimeUtc() - dateB.Value.ToFileTimeUtc()); } - /** - * Extracts a date from a folder name string formatted as `YYYY-MM-DD_hh-mm-ss`. - * - * @param folderName - The name of the folder from which to extract the date. - * @returns A DateTime object if the folder name is in the correct format, otherwise null. - */ + /// + /// Extracts a date from a folder name string formatted as `YYYY-MM-DD_hh-mm-ss`. + /// + /// The name of the folder from which to extract the date. + /// A DateTime object if the folder name is in the correct format, otherwise null. private DateTime? ExtractDateFromFolderName(string folderName) { // backup @@ -290,12 +278,11 @@ public class BackupService return new DateTime(year, month, day, hour, minute, second); } - /** - * Removes excess backups from the backup directory. - * - * @param backups - A List of backup file names to be removed. - * @returns A promise that resolves when all specified backups have been removed. - */ + /// + /// Removes excess backups from the backup directory. + /// + /// List of backup file names to be removed. + /// A promise that resolves when all specified backups have been removed. private void RemoveExcessBackups(List backupFilenames) { var filePathsToDelete = backupFilenames.Select(x => x); @@ -310,14 +297,17 @@ public class BackupService } } - /** - * Get a List of active server mod details. - * - * @returns A List of mod names. - */ + /// + /// Get a List of active server mod details. + /// + /// A List of mod names. protected List GetActiveServerMods() { - var mods = _applicationContext?.GetLatestValue(ContextVariableType.LOADED_MOD_ASSEMBLIES).GetValue>(); + var mods = _applicationContext?.GetLatestValue(ContextVariableType.LOADED_MOD_ASSEMBLIES)?.GetValue>(); + if (mods == null) + { + return []; + } List result = []; foreach (var mod in mods) diff --git a/Libraries/SPTarkov.Server.Core/Services/BotEquipmentModPoolService.cs b/Libraries/SPTarkov.Server.Core/Services/BotEquipmentModPoolService.cs index c65b429d..fd910b0f 100644 --- a/Libraries/SPTarkov.Server.Core/Services/BotEquipmentModPoolService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/BotEquipmentModPoolService.cs @@ -12,7 +12,7 @@ namespace SPTarkov.Server.Core.Services; [Injectable(InjectionType.Singleton)] public class BotEquipmentModPoolService { - private readonly Lock _lock = new(); + private readonly Lock _lockObject = new(); protected bool _armorPoolGenerated; protected BotConfig _botConfig; protected ConfigServer _configServer; @@ -44,10 +44,11 @@ public class BotEquipmentModPoolService _gearModPool = new ConcurrentDictionary>>(); } - /** - * Store dictionary of mods for each item passed in - * @param items items to find related mods and store in modPool - */ + /// + /// Store dictionary of mods for each item passed in + /// + /// Items to find related mods and store in modPool + /// Mod pool to choose from e.g. "weapon" for weaponModPool protected void GeneratePool(IEnumerable? items, string poolType) { if (items is null) @@ -121,7 +122,7 @@ public class BotEquipmentModPoolService private bool SetContainsTpl(HashSet itemSet, string tpl) { - lock (_lock) + lock (_lockObject) { return itemSet.Contains(tpl); } @@ -129,7 +130,7 @@ public class BotEquipmentModPoolService private bool AddTplToSet(HashSet itemSet, string itemToAddTpl) { - lock (_lock) + lock (_lockObject) { return itemSet.Add(itemToAddTpl); } @@ -137,26 +138,26 @@ public class BotEquipmentModPoolService private bool InitSetInDict(ConcurrentDictionary> dictionary, string slotName) { - lock (_lock) + lock (_lockObject) { return dictionary.TryAdd(slotName, []); } } - /** - * Empty the mod pool - */ + /// + /// Empty the mod pool + /// public void ResetPool() { _weaponModPool.Clear(); } - /** - * Get array of compatible mods for an items mod slot (generate pool if it doesn't exist already) - * @param itemTpl item to look up - * @param slotName slot to get compatible mods for - * @returns tpls that fit the slot - */ + /// + /// Get array of compatible mods for an items mod slot (generate pool if it doesn't exist already) + /// + /// Item to look up + /// Slot to get compatible mods for + /// Hashset of tpls that fit the slot public HashSet GetCompatibleModsForWeaponSlot(string itemTpl, string slotName) { if (!_weaponPoolGenerated) @@ -168,11 +169,11 @@ public class BotEquipmentModPoolService return _weaponModPool[itemTpl][slotName]; } - /** - * Get mods for a piece of gear by its tpl - * @param itemTpl items tpl to look up mods for - * @returns Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value - */ + /// + /// Get mods for a piece of gear by its tpl + /// + /// Items tpl to look up mods for + /// Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value public ConcurrentDictionary> GetModsForGearSlot(string itemTpl) { if (!_armorPoolGenerated) @@ -185,11 +186,11 @@ public class BotEquipmentModPoolService : []; } - /** - * Get mods for a weapon by its tpl - * @param itemTpl Weapons tpl to look up mods for - * @returns Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value - */ + /// + /// Get mods for a weapon by its tpl + /// + /// Weapons tpl to look up mods for + /// Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value public ConcurrentDictionary> GetModsForWeaponSlot(string itemTpl) { if (!_weaponPoolGenerated) @@ -200,6 +201,11 @@ public class BotEquipmentModPoolService return _weaponModPool[itemTpl]; } + /// + /// Get required mods for a weapon by its tpl + /// + /// Weapons tpl to look up mods for + /// Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value public Dictionary>? GetRequiredModsForWeaponSlot(string itemTpl) { var result = new Dictionary>(); @@ -225,9 +231,9 @@ public class BotEquipmentModPoolService return result; } - /** - * Create weapon mod pool and set generated flag to true - */ + /// + /// Create weapon mod pool and set generated flag to true + /// protected void GenerateWeaponPool() { var weapons = _databaseService.GetItems() @@ -240,9 +246,9 @@ public class BotEquipmentModPoolService _weaponPoolGenerated = true; } - /** - * Create gear mod pool and set generated flag to true - */ + /// + /// Create gear mod pool and set generated flag to true + /// protected void GenerateGearPool() { var gear = _databaseService.GetItems() diff --git a/Libraries/SPTarkov.Server.Core/Services/BotGenerationCacheService.cs b/Libraries/SPTarkov.Server.Core/Services/BotGenerationCacheService.cs index 08fc3a50..14eb95be 100644 --- a/Libraries/SPTarkov.Server.Core/Services/BotGenerationCacheService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/BotGenerationCacheService.cs @@ -16,10 +16,11 @@ public class BotGenerationCacheService( protected ConcurrentDictionary> _storedBots = new(); - /** - * Store list of bots in cache, shuffle results before storage - * @param botsToStore Bots we want to store in the cache - */ + /// + /// Store list of bots in cache, shuffle results before storage + /// + /// Role bot is stored as (assault/bossTagilla etc.) + /// Bots we want to store in the cache public void StoreBots(string key, List botsToStore) { foreach (var bot in botsToStore) @@ -31,12 +32,12 @@ public class BotGenerationCacheService( } } - /** - * Find and return a bot based on its role - * Remove bot from internal list so it can't be retrieved again - * @param key role to retrieve (assault/bossTagilla etc) - * @returns BotBase object - */ + /// + /// Find and return a bot based on its role.
+ /// Remove bot from internal list so it can't be retrieved again. + ///
+ /// role to retrieve (assault/bossTagilla etc) + /// BotBase object public BotBase? GetBot(string key) { if (_storedBots.TryGetValue(key, out var bots)) @@ -62,39 +63,39 @@ public class BotGenerationCacheService( return null; } - /** - * Cache a bot that has been sent to the client in memory for later use post-raid to determine if player killed a traitor scav - * @param botToStore Bot object to store - */ + /// + /// Cache a bot that has been sent to the client in memory for later use post-raid to determine if player killed a traitor scav + /// + /// Bot object to store public void StoreUsedBot(BotBase botToStore) { _activeBotsInRaid.Enqueue(botToStore); } - /** - * Get a bot by its profileId that has been generated and sent to client for current raid - * Cache is wiped post-raid in client/match/offline/end endOfflineRaid() - * @param profileId Id of bot to get - * @returns BotBase - */ + /// + /// Get a bot by its profileId that has been generated and sent to client for current raid.
+ /// Cache is wiped post-raid in client/match/offline/end endOfflineRaid() + ///
+ /// ID of bot to get + /// BotBase object public BotBase? GetUsedBot(string profileId) { return _activeBotsInRaid.FirstOrDefault(x => x.Id == profileId); } - /** - * Remove all cached bot profiles from memory - */ + /// + /// Remove all cached bot profiles from memory + /// public void ClearStoredBots() { _storedBots.Clear(); _activeBotsInRaid = []; } - /** - * Does cache have a bot with requested key - * @returns false if empty - */ + /// + /// Does cache have a bot with requested key + /// + /// False if empty public bool CacheHasBotWithKey(string key, int size = 0) { return _storedBots.ContainsKey(key) && _storedBots[key].Count > size; diff --git a/Libraries/SPTarkov.Server.Core/Services/BotLootCacheService.cs b/Libraries/SPTarkov.Server.Core/Services/BotLootCacheService.cs index ad8ef662..1d983733 100644 --- a/Libraries/SPTarkov.Server.Core/Services/BotLootCacheService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/BotLootCacheService.cs @@ -20,7 +20,7 @@ public class BotLootCacheService( ICloner _cloner ) { - protected object _lock = new(); + protected readonly Lock _lockObject = new(); protected Dictionary _lootCache = new(); /// @@ -28,7 +28,7 @@ public class BotLootCacheService( /// public void ClearCache() { - lock (_lock) + lock (_lockObject) { _lootCache.Clear(); } @@ -49,7 +49,7 @@ public class BotLootCacheService( BotType botJsonTemplate, MinMax? itemPriceMinMax = null) { - lock (_lock) + lock (_lockObject) { if (!BotRoleExistsInCache(botRole)) { @@ -60,7 +60,7 @@ public class BotLootCacheService( Dictionary result = null; BotLootCache botRoleCache; - lock (_lock) + lock (_lockObject) { botRoleCache = _lootCache[botRole]; } @@ -448,7 +448,7 @@ public class BotLootCacheService( } BotLootCache cacheForRole; - lock (_lock) + lock (_lockObject) { cacheForRole = _lootCache[botRole]; @@ -544,7 +544,7 @@ public class BotLootCacheService( /// true if they exist protected bool BotRoleExistsInCache(string botRole) { - lock (_lock) + lock (_lockObject) { return _lootCache.ContainsKey(botRole); } @@ -556,7 +556,7 @@ public class BotLootCacheService( /// Bot role to hydrate protected void InitCacheForBotRole(string botRole) { - lock (_lock) + lock (_lockObject) { _lootCache.Add( botRole, diff --git a/Libraries/SPTarkov.Server.Core/Services/BotNameService.cs b/Libraries/SPTarkov.Server.Core/Services/BotNameService.cs index 43e580e2..ab5f6dc5 100644 --- a/Libraries/SPTarkov.Server.Core/Services/BotNameService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/BotNameService.cs @@ -21,7 +21,7 @@ public class BotNameService( ) { protected BotConfig _botConfig = _configServer.GetConfig(); - protected object _lock = new(); + protected readonly Lock _lockObject = new(); protected HashSet _usedNameCache = new(); /// @@ -113,7 +113,7 @@ public class BotNameService( private bool AddNameToCache(string name) { - lock (_lock) + lock (_lockObject) { return _usedNameCache.Add(name); } @@ -121,7 +121,7 @@ public class BotNameService( protected bool CacheContainsName(string name) { - lock (_lock) + lock (_lockObject) { return _usedNameCache.Contains(name); } diff --git a/Libraries/SPTarkov.Server.Core/Services/BotWeaponModLimitService.cs b/Libraries/SPTarkov.Server.Core/Services/BotWeaponModLimitService.cs index 3f28ae59..97679c02 100644 --- a/Libraries/SPTarkov.Server.Core/Services/BotWeaponModLimitService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/BotWeaponModLimitService.cs @@ -56,10 +56,10 @@ public class BotWeaponModLimitService( } /// - /// Check if weapon mod item is on limited list + has surpassed the limit set for it - /// Exception: Always allow ncstar backup mount - /// Exception: Always allow scopes with a scope for a parent - /// Exception: Always disallow mounts that hold only scopes once scope limit reached + /// Check if weapon mod item is on limited list + has surpassed the limit set for it
+ /// Exception: Always allow ncstar backup mount
+ /// Exception: Always allow scopes with a scope for a parent
+ /// Exception: Always disallow mounts that hold only scopes once scope limit reached
/// Exception: Always disallow mounts that hold only flashlights once flashlight limit reached ///
/// role the bot has e.g. assault diff --git a/Libraries/SPTarkov.Server.Core/Services/CircleOfCultistService.cs b/Libraries/SPTarkov.Server.Core/Services/CircleOfCultistService.cs index 6bb61015..2ab9e620 100644 --- a/Libraries/SPTarkov.Server.Core/Services/CircleOfCultistService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/CircleOfCultistService.cs @@ -123,7 +123,12 @@ public class CircleOfCultistService( return output; } - + /// + /// Get the reward amount multiple value based on players hideout management skill + configs rewardPriceMultiplerMinMax values + /// + /// Player profile + /// Circle config settings + /// Reward Amount Multiplier private double GetRewardAmountMultiplier(PmcData pmcData, CultistCircleSettings cultistCircleSettings) { // Get a randomised value to multiply the sacrificed rouble cost by diff --git a/Libraries/SPTarkov.Server.Core/Services/CreateProfileService.cs b/Libraries/SPTarkov.Server.Core/Services/CreateProfileService.cs index 5596d1ea..0ac248e4 100644 --- a/Libraries/SPTarkov.Server.Core/Services/CreateProfileService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/CreateProfileService.cs @@ -215,10 +215,10 @@ public class CreateProfileService( return pmcData.Id; } - /** - * Delete a profile - * @param sessionID Id of profile to delete - */ + /// + /// Delete a profile + /// + /// ID of profile to delete protected void DeleteProfileBySessionId(string sessionID) { if (_saveServer.GetProfiles().ContainsKey(sessionID)) @@ -233,10 +233,10 @@ public class CreateProfileService( } } - /** - * make profiles pmcData.Inventory.equipment unique - * @param pmcData Profile to update - */ + /// + /// Make profiles pmcData.Inventory.equipment unique + /// + /// Profile to update protected void UpdateInventoryEquipmentId(PmcData pmcData) { var oldEquipmentId = pmcData.Inventory.Equipment; @@ -257,10 +257,10 @@ public class CreateProfileService( } } - /** - * For each trader reset their state to what a level 1 player would see - * @param sessionId Session id of profile to reset - */ + /// + /// For each trader reset their state to what a level 1 player would see + /// + /// Session ID of profile to reset protected void ResetAllTradersInProfile(string sessionId) { foreach (var traderId in _databaseService.GetTraders().Keys) @@ -269,11 +269,11 @@ public class CreateProfileService( } } - /** - * Ensure a profile has the necessary internal containers e.g. questRaidItems / sortingTable - * DOES NOT check that stash exists - * @param pmcData Profile to check - */ + /// + /// Ensure a profile has the necessary internal containers e.g. questRaidItems / sortingTable
+ /// DOES NOT check that stash exists + ///
+ /// Profile to check protected void AddMissingInternalContainersToProfile(PmcData pmcData) { if (!pmcData.Inventory.Items.Any(item => item.Id == pmcData.Inventory.HideoutCustomizationStashId)) @@ -462,9 +462,9 @@ public class CreateProfileService( } } - /** - * Get the game edition of a profile chosen on creation in Launcher - */ + /// + /// Get the game edition of a profile chosen on creation in Launcher + /// private string? GetGameEdition(SptProfile profile) { var edition = profile.CharacterData?.PmcData?.Info?.GameVersion; @@ -486,13 +486,13 @@ public class CreateProfileService( } } - /** - * Iterate over all quests in player profile, inspect rewards for the quests current state (accepted/completed) - * and send rewards to them in mail - * @param profileDetails Player profile - * @param sessionID Session id - * @param response Event router response - */ + /// + /// Iterate over all quests in player profile, inspect rewards for the quests current state (accepted/completed) + /// and send rewards to them in mail + /// + /// Player profile + /// Session ID + /// Event router response protected void GivePlayerStartingQuestRewards( SptProfile profileDetails, string sessionID, diff --git a/Libraries/SPTarkov.Server.Core/Services/CustomLocaleService.cs b/Libraries/SPTarkov.Server.Core/Services/CustomLocaleService.cs index 38ea1fdc..e6142c7f 100644 --- a/Libraries/SPTarkov.Server.Core/Services/CustomLocaleService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/CustomLocaleService.cs @@ -14,7 +14,7 @@ public class CustomLocaleService( /// /// Path should link to a folder containing every locale that should be added to the server locales - /// e.g. en.json for english, fr.json for french + /// e.g. en.json for english, fr.json for french.
/// Inside each JSON should be a Dictionary of the locale key and localised text ///
/// en/fr/de @@ -27,7 +27,7 @@ public class CustomLocaleService( /// /// Path should link to a folder containing every locale that should be added to the game locales - /// e.g. en.json for english, fr.json for french + /// e.g. en.json for english, fr.json for french.
/// Inside each JSON should be a Dictionary of the locale key and localised text ///
/// en/fr/de diff --git a/Libraries/SPTarkov.Server.Core/Services/DatabaseService.cs b/Libraries/SPTarkov.Server.Core/Services/DatabaseService.cs index 7c361239..fa63314a 100644 --- a/Libraries/SPTarkov.Server.Core/Services/DatabaseService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/DatabaseService.cs @@ -25,17 +25,13 @@ public class DatabaseService( { protected bool isDataValid = true; - /** - * @returns assets/database/ - */ + /// assets/database/ public DatabaseTables GetTables() { return _databaseServer.GetTables(); } - /** - * @returns assets/database/bots/ - */ + /// assets/database/bots/ public Bots GetBots() { if (_databaseServer.GetTables().Bots == null) @@ -46,9 +42,7 @@ public class DatabaseService( return _databaseServer.GetTables().Bots!; } - /** - * @returns assets/database/globals.json - */ + /// assets/database/globals.json public Globals GetGlobals() { if (_databaseServer.GetTables().Globals == null) @@ -64,9 +58,7 @@ public class DatabaseService( return _databaseServer.GetTables().Globals!; } - /** - * @returns assets/database/hideout/ - */ + /// assets/database/hideout/ public Hideout GetHideout() { if (_databaseServer.GetTables().Hideout == null) @@ -79,9 +71,7 @@ public class DatabaseService( return _databaseServer.GetTables().Hideout!; } - /** - * @returns assets/database/locales/ - */ + /// assets/database/locales/ public LocaleBase GetLocales() { if (_databaseServer.GetTables().Locales == null) @@ -94,9 +84,7 @@ public class DatabaseService( return _databaseServer.GetTables().Locales!; } - /** - * @returns assets/database/locations - */ + /// assets/database/locations public Locations GetLocations() { if (_databaseServer.GetTables().Locations == null) @@ -109,11 +97,11 @@ public class DatabaseService( return _databaseServer.GetTables().Locations!; } - /** - * Get specific location by its Id - * @param locationId Desired location id - * @returns assets/database/locations/ - */ + /// + /// Get specific location by its ID + /// + /// Desired location ID + /// assets/database/locations/ public Location GetLocation(string locationId) { var locations = GetLocations(); @@ -126,9 +114,7 @@ public class DatabaseService( return desiredLocation; } - /** - * @returns assets/database/match/ - */ + /// assets/database/match/ public Match GetMatch() { if (_databaseServer.GetTables().Match == null) @@ -141,9 +127,7 @@ public class DatabaseService( return _databaseServer.GetTables().Match!; } - /** - * @returns assets/database/server.json - */ + /// assets/database/server.json public ServerBase GetServer() { if (_databaseServer.GetTables().Server == null) @@ -159,9 +143,7 @@ public class DatabaseService( return _databaseServer.GetTables().Server!; } - /** - * @returns assets/database/settings.json - */ + /// assets/database/settings.json public SettingsBase GetSettings() { if (_databaseServer.GetTables().Settings == null) @@ -177,9 +159,7 @@ public class DatabaseService( return _databaseServer.GetTables().Settings!; } - /** - * @returns assets/database/templates/ - */ + /// assets/database/templates/ public Templates GetTemplates() { if (_databaseServer.GetTables().Templates == null) @@ -195,9 +175,7 @@ public class DatabaseService( return _databaseServer.GetTables().Templates!; } - /** - * @returns assets/database/templates/achievements.json - */ + /// assets/database/templates/achievements.json public List GetAchievements() { if (_databaseServer.GetTables().Templates?.Achievements == null) @@ -213,9 +191,7 @@ public class DatabaseService( return _databaseServer.GetTables().Templates?.Achievements!; } - /** - * @returns assets/database/templates/customisation.json - */ + /// assets/database/templates/customisation.json public Dictionary GetCustomization() { if (_databaseServer.GetTables().Templates?.Customization == null) @@ -231,9 +207,7 @@ public class DatabaseService( return _databaseServer.GetTables().Templates?.Customization!; } - /** - * @returns assets/database/templates/handbook.json - */ + /// assets/database/templates/handbook.json public HandbookBase GetHandbook() { if (_databaseServer.GetTables().Templates?.Handbook == null) @@ -244,9 +218,7 @@ public class DatabaseService( return _databaseServer.GetTables().Templates?.Handbook!; } - /** - * @returns assets/database/templates/items.json - */ + /// assets/database/templates/items.json public Dictionary GetItems() { if (_databaseServer.GetTables().Templates?.Items == null) @@ -257,9 +229,7 @@ public class DatabaseService( return _databaseServer.GetTables().Templates?.Items!; } - /** - * @returns assets/database/templates/prices.json - */ + /// assets/database/templates/prices.json public Dictionary GetPrices() { if (_databaseServer.GetTables().Templates?.Prices == null) @@ -270,9 +240,7 @@ public class DatabaseService( return _databaseServer.GetTables().Templates?.Prices!; } - /** - * @returns assets/database/templates/profiles.json - */ + /// assets/database/templates/profiles.json public ProfileTemplates GetProfiles() { if (_databaseServer.GetTables().Templates?.Profiles == null) @@ -283,9 +251,7 @@ public class DatabaseService( return _databaseServer.GetTables().Templates?.Profiles!; } - /** - * @returns assets/database/templates/quests.json - */ + /// assets/database/templates/quests.json public Dictionary GetQuests() { if (_databaseServer.GetTables().Templates?.Quests == null) @@ -296,9 +262,7 @@ public class DatabaseService( return _databaseServer.GetTables().Templates?.Quests!; } - /** - * @returns assets/database/traders/ - */ + /// assets/database/traders/ public Dictionary GetTraders() { if (_databaseServer.GetTables().Traders == null) @@ -309,11 +273,11 @@ public class DatabaseService( return _databaseServer.GetTables().Traders!; } - /** - * Get specific trader by their Id - * @param traderId Desired trader id - * @returns assets/database/traders/ - */ + /// + /// Get specific trader by their ID + /// + /// Desired trader ID + /// assets/database/traders/ public Trader GetTrader(string traderId) { var traders = GetTraders(); @@ -325,9 +289,7 @@ public class DatabaseService( return desiredTrader; } - /** - * @returns assets/database/locationServices/ - */ + /// assets/database/locationServices/ public LocationServices GetLocationServices() { if (_databaseServer.GetTables().Templates?.LocationServices == null) @@ -338,9 +300,9 @@ public class DatabaseService( return _databaseServer.GetTables().Templates?.LocationServices!; } - /** - * Validates that the database doesn't contain invalid ID data - */ + /// + /// Validates that the database doesn't contain invalid ID data + /// public void ValidateDatabase() { var start = Stopwatch.StartNew(); @@ -363,12 +325,12 @@ public class DatabaseService( } } - /** - * Validate that the given table only contains valid MongoIDs - * @param table Table to validate for MongoIDs - * @param tableType The type of table, used in output message - * @returns True if the table only contains valid data - */ + /// + /// Validate that the given table only contains valid MongoIDs + /// + /// Table to validate for MongoIDs + /// The type of table, used in output message + /// True if the table only contains valid data private bool ValidateTable(Dictionary table, string tableType) { foreach (var keyValuePair in table) @@ -383,10 +345,10 @@ public class DatabaseService( return true; } - /** - * Check if the database is valid - * @returns True if the database contains valid data, false otherwise - */ + /// + /// Check if the database is valid + /// + /// True if the database contains valid data, false otherwise public bool IsDatabaseValid() { return isDataValid; diff --git a/Libraries/SPTarkov.Server.Core/Services/FenceService.cs b/Libraries/SPTarkov.Server.Core/Services/FenceService.cs index d1865d0c..3b9d0d39 100644 --- a/Libraries/SPTarkov.Server.Core/Services/FenceService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/FenceService.cs @@ -28,19 +28,19 @@ public class FenceService( ICloner _cloner ) { - /** - * Desired baseline counts - Hydrated on initial assort generation as part of generateFenceAssorts() - */ + /// + /// Desired baseline counts - Hydrated on initial assort generation as part of generateFenceAssorts() + /// protected FenceAssortGenerationValues desiredAssortCounts; - /** - * Main assorts you see at all rep levels - */ + /// + /// Main assorts you see at all rep levels + /// protected TraderAssort? fenceAssort; - /** - * Assorts shown on a separate tab when you max out fence rep - */ + /// + /// Assorts shown on a separate tab when you max out fence rep + /// protected TraderAssort? fenceDiscountAssort; protected HashSet fenceItemUpdCompareProperties = @@ -56,65 +56,57 @@ public class FenceService( "RepairKit" ]; - /** - * Time when some items in assort will be replaced - */ + /// + /// Time when some items in assort will be replaced + /// protected long nextPartialRefreshTimestamp; protected TraderConfig traderConfig = configServer.GetConfig(); - /** - * Replace main fence assort with new assort - * @param assort New assorts to replace old with - */ + /// + /// Replace main fence assort with new assort + /// + /// New assorts to replace old with public void SetFenceAssort(TraderAssort assort) { fenceAssort = assort; } - /** - * Replace discount fence assort with new assort - * @param assort New assorts to replace old with - */ - public void SetDiscountFenceAssort(TraderAssort assort) - { - fenceDiscountAssort = assort; - } - - /** - * Get main fence assort - * @return ITraderAssort - */ - public TraderAssort? GetMainFenceAssort() - { - return fenceAssort; - } - - /** - * Get discount fence assort - * @return ITraderAssort - */ - public TraderAssort? GetDiscountFenceAssort() - { - return fenceDiscountAssort; - } - - /** - * Replace high rep level fence assort with new assort - * @param discountAssort New assorts to replace old with - */ + /// + /// Replace discount fence assort with new assort + /// + /// New assorts to replace old with public void SetFenceDiscountAssort(TraderAssort discountAssort) { fenceDiscountAssort = discountAssort; } - /** - * Get assorts player can purchase - * Adjust prices based on fence level of player - * @param pmcProfile Player profile - * @returns ITraderAssort - */ + /// + /// Get main fence assort + /// + /// TraderAssort + public TraderAssort? GetMainFenceAssort() + { + return fenceAssort; + } + + /// + /// Get discount fence assort + /// + /// TraderAssort + /// @return ITraderAssort + public TraderAssort? GetDiscountFenceAssort() + { + return fenceDiscountAssort; + } + + /// + /// Get assorts player can purchase
+ /// Adjust prices based on fence level of player + ///
+ /// Player profile + /// TraderAssort public TraderAssort GetFenceAssorts(PmcData pmcProfile) { if (traderConfig.Fence.RegenerateAssortsOnRefresh) @@ -144,11 +136,11 @@ public class FenceService( return assort; } - /** - * Adds to fence assort a single item (with its children) - * @param items the items to add with all its childrens - * @param mainItem the most parent item of the array - */ + /// + /// Adds to fence assort a single item (with its children) + /// + /// The items to add with all its children + /// The most parent item of the array public void AddItemsToFenceAssort(List items, Item mainItem) { // HUGE THANKS TO LACYWAY AND LEAVES FOR PROVIDING THIS SOLUTION FOR SPT TO IMPLEMENT!! @@ -192,12 +184,12 @@ public class FenceService( UpdateFenceAssorts(createAssort, fenceAssort); } - /** - * Calculates the overall price for an item (with all its children) - * @param itemTpl the item tpl to calculate the fence price for - * @param items the items (with its children) to calculate fence price for - * @returns the fence price of the item - */ + /// + /// Calculates the overall price for an item (with all its children) + /// + /// The item tpl to calculate the fence price for + /// The items (with its children) to calculate fence price for + /// Price of the item for Fence public double? GetItemPrice(string itemTpl, List items) { return itemHelper.IsOfBaseclass(itemTpl, BaseClasses.AMMO_BOX) @@ -205,12 +197,12 @@ public class FenceService( : handbookHelper.GetTemplatePrice(itemTpl) * traderConfig.Fence.ItemPriceMult; } - /** - * Calculate the overall price for an ammo box, where only one item is - * the ammo box itself and every other items are the bullets in that box - * @param items the ammo box (and all its children ammo items) - * @returns the price of the ammo box - */ + /// + /// Calculate the overall price for an ammo box, where only one item is + /// the ammo box itself and every other items are the bullets in that box + /// + /// The ammo box (and all its children ammo items) + /// The price of the ammo box protected double? GetAmmoBoxPrice(List items) { double? total = 0D; @@ -225,12 +217,12 @@ public class FenceService( return total; } - /** - * Adjust all items contained inside an assort by a multiplier - * @param assort (clone)Assort that contains items with prices to adjust - * @param itemMultiplier multiplier to use on items - * @param presetMultiplier preset multiplier to use on presets - */ + /// + /// Adjust all items contained inside an assort by a multiplier + /// + /// (clone) Assort that contains items with prices to adjust + /// Multiplier to use on items + /// Multiplier to use on presets protected void AdjustAssortItemPricesByConfigMultiplier( TraderAssort assort, double itemMultiplier, @@ -244,12 +236,13 @@ public class FenceService( } } - /** - * Merge two trader assort files together - * @param firstAssort assort 1# - * @param secondAssort assort #2 - * @returns merged assort - */ + /// + /// Merge two trader assort files together + /// + /// Assort #1 + /// Assort #2 + /// Merged assort + // TODO: can be moved to a helper? protected TraderAssort MergeAssorts(TraderAssort firstAssort, TraderAssort secondAssort) { foreach (var itemId in secondAssort.BarterScheme.Keys) @@ -270,13 +263,13 @@ public class FenceService( return firstAssort; } - /** - * Adjust assorts price by a modifier - * @param item assort item details - * @param assort assort to be modified - * @param modifier value to multiply item price by - * @param presetModifier value to multiply preset price by - */ + /// + /// Adjust assorts price by a modifier + /// + /// Assort item details + /// Assort to be modified + /// Value to multiply item price by + /// Value to multiply preset price by protected void AdjustItemPriceByModifier( Item item, TraderAssort assort, @@ -313,27 +306,27 @@ public class FenceService( } } - /** - * Get fence assorts with no price adjustments based on fence rep - * @returns ITraderAssort - */ + /// + /// Get fence assorts with no price adjustments based on fence rep + /// + /// TraderAssort public TraderAssort GetRawFenceAssorts() { return MergeAssorts(_cloner.Clone(fenceAssort), _cloner.Clone(fenceDiscountAssort)); } - /** - * Does fence need to perform a partial refresh because its passed the refresh timer defined in trader.json - * @returns true if it needs a partial refresh - */ + /// + /// Does fence need to perform a partial refresh because its passed the refresh timer defined in trader.json + /// + /// True if it needs a partial refresh public bool NeedsPartialRefresh() { return timeUtil.GetTimeStamp() > nextPartialRefreshTimestamp; } - /** - * Replace a percentage of fence assorts with freshly generated items - */ + /// + /// Replace a percentage of fence assorts with freshly generated items + /// public void PerformPartialRefresh() { var itemCountToReplace = GetCountOfItemsToReplace(traderConfig.Fence.AssortSize); @@ -391,11 +384,11 @@ public class FenceService( IncrementPartialRefreshTime(); } - /** - * Handle the process of folding new assorts into existing assorts, when a new assort exists already, increment its StackObjectsCount instead - * @param newFenceAssorts Assorts to fold into existing fence assorts - * @param existingFenceAssorts Current fence assorts new assorts will be added to - */ + /// + /// Handle the process of folding new assorts into existing assorts, when a new assort exists already, increment its StackObjectsCount instead + /// + /// Assorts to fold into existing fence assorts + /// Current fence assorts, new assorts will be added to protected void UpdateFenceAssorts( CreateFenceAssortsResult newFenceAssorts, TraderAssort existingFenceAssorts @@ -454,20 +447,20 @@ public class FenceService( } } - /** - * Increment fence next refresh timestamp by current timestamp + partialRefreshTimeSeconds from config - */ + /// + /// Increment fence next refresh timestamp by current timestamp + partialRefreshTimeSeconds from config + /// protected void IncrementPartialRefreshTime() { nextPartialRefreshTimestamp = timeUtil.GetTimeStamp() + traderConfig.Fence.PartialRefreshTimeSeconds; } - /** - * Get values that will hydrate the passed in assorts back to the desired counts - * @param assortItems Current assorts after items have been removed - * @param generationValues Base counts assorts should be adjusted to - * @returns IGenerationAssortValues object with adjustments needed to reach desired state - */ + /// + /// Get values that will hydrate the passed in assorts back to the desired counts + /// + /// Current assorts after items have been removed + /// Base counts assorts should be adjusted to + /// GenerationAssortValues object with adjustments needed to reach desired state protected GenerationAssortValues GetItemCountsToGenerate( List assortItems, GenerationAssortValues generationValues @@ -507,11 +500,11 @@ public class FenceService( }; } - /** - * Delete desired number of items from assort (including children) - * @param itemCountToReplace - * @param discountItemCountToReplace - */ + /// + /// Delete desired number of items from assort (including children) + /// + /// Number of items to replace + /// Assort to adjust protected void DeleteRandomAssorts(int itemCountToReplace, TraderAssort assort) { if (assort?.Items?.Count > 0) @@ -524,11 +517,11 @@ public class FenceService( } } - /** - * Choose an item at random and remove it + mods from assorts - * @param assort Trader assort to remove item from - * @param rootItems Pool of root items to pick from to remove - */ + /// + /// Choose an item at random and remove it + mods from assorts + /// + /// Trader assort to remove item from + /// Pool of root items to pick from to remove protected void RemoveRandomItemFromAssorts(TraderAssort assort, List rootItems) { // Pick a random root item to remove from Fence @@ -573,20 +566,20 @@ public class FenceService( assort.LoyalLevelItems.Remove(rootItemToAdjust.Id); } - /** - * Get an integer rounded count of items to replace based on percentrage from traderConfig value - * @param totalItemCount total item count - * @returns rounded int of items to replace - */ + /// + /// Get an integer rounded count of items to replace based on percentage from traderConfig value + /// + /// Total item count + /// Rounded int of items to replace protected int GetCountOfItemsToReplace(int totalItemCount) { return (int) Math.Round(totalItemCount * (traderConfig.Fence.PartialRefreshChangePercent / 100)); } - /** - * Get the count of items fence offers - * @returns number - */ + /// + /// Get the count of items fence offers + /// + /// Number public int GetOfferCount() { if ((fenceAssort?.Items?.Count ?? 0) == 0) @@ -597,10 +590,10 @@ public class FenceService( return fenceAssort.Items.Count; } - /** - * Create trader assorts for fence and store in fenceService cache - * Uses fence base cache generatedon server start as a base - */ + /// + /// Create trader assorts for fence and store in fenceService cache + /// Uses fence base cache generation server start as a base + /// public void GenerateFenceAssorts() { // Reset refresh time now assorts are being generated @@ -622,11 +615,11 @@ public class FenceService( SetFenceDiscountAssort(ConvertIntoFenceAssort(discountAssorts)); } - /** - * Convert the intermediary assort data generated into format client can process - * @param intermediaryAssorts Generated assorts that will be converted - * @returns ITraderAssort - */ + /// + /// Convert the intermediary assort data generated into format client can process + /// + /// Generated assorts that will be converted + /// TraderAssort in the correct data format for Fence protected TraderAssort ConvertIntoFenceAssort(CreateFenceAssortsResult intermediaryAssorts) { var result = CreateFenceAssortSkeleton(); @@ -641,10 +634,10 @@ public class FenceService( return result; } - /** - * Create object that contains calculated fence assort item values to make based on config - * Stored in desiredAssortCounts - */ + /// + /// Create object that contains calculated fence assort item values to make based on config. + /// Stored in desiredAssortCounts + /// protected void CreateInitialFenceAssortGenerationValues() { var result = new FenceAssortGenerationValues @@ -690,10 +683,10 @@ public class FenceService( desiredAssortCounts = result; } - /** - * Create skeleton to hold assort items - * @returns ITraderAssort object - */ + /// + /// Create skeleton to hold assort items + /// + /// TraderAssort object protected TraderAssort CreateFenceAssortSkeleton() { return new TraderAssort @@ -705,11 +698,12 @@ public class FenceService( }; } - /** - * Hydrate assorts parameter object with generated assorts - * @param assortCount Number of assorts to generate - * @param assorts object to add created assorts to - */ + /// + /// Hydrate assorts parameter object with generated assorts + /// + /// Number of items to generate per type (Item, WeaponPreset, EquipmentPreset) + /// Loyalty level to set new item to + /// CreateFenceAssortResult object protected CreateFenceAssortsResult CreateAssorts(GenerationAssortValues itemCounts, int loyaltyLevel) { var result = new CreateFenceAssortsResult @@ -742,14 +736,14 @@ public class FenceService( return result; } - /** - * Add item assorts to existing assort data - * @param assortCount Number to add - * @param assorts Assorts data to add to - * @param baseFenceAssortClone Base data to draw from - * @param itemTypeLimits - * @param loyaltyLevel Loyalty level to set new item to - */ + /// + /// Add item assorts to existing assort data + /// + /// Number to add + /// Data to add to + /// Base data to draw from + /// Item limits per base class + /// Loyalty level to set new item to protected void AddItemAssorts( int? assortCount, CreateFenceAssortsResult assorts, @@ -868,14 +862,14 @@ public class FenceService( } } - /** - * Find an assort item that matches the first parameter, also matches based on Upd properties - * e.g. salewa hp resource units left - * @param rootItemBeingAdded item to look for a match against - * @param itemDbDetails Db details of matching item - * @param itemsWithChildren Items to search through - * @returns Matching assort item - */ + /// + /// Find an assort item that matches the first parameter, also matches based on Upd properties + /// e.g. salewa hp resource units left + /// + /// item to look for a match against + /// DB details of matching item + /// Items to search through + /// Matching assort item protected Item? GetMatchingItem( Item rootItemBeingAdded, TemplateItem itemDbDetails, @@ -946,12 +940,12 @@ public class FenceService( return null; } - /** - * Should this item be forced into only 1 stack on fence - * @param existingItem Existing item from fence assort - * @param itemDbDetails Item we want to add db details - * @returns True item should be force stacked - */ + /// + /// Should this item be forced into only 1 stack on fence + /// + /// Existing item from fence assort + /// Item we want to add DB details + /// True item should be force stacked protected bool ItemShouldBeForceStacked(Item? existingItem, TemplateItem itemDbDetails) { // No existing item in assort @@ -975,12 +969,12 @@ public class FenceService( return itemHelper.IsOfBaseclasses(tpl, traderConfig.Fence.PreventDuplicateOffersOfCategory); } - /** - * Adjust price of item based on what is left to buy (resource/uses left) - * @param barterSchemes All barter scheme for item having price adjusted - * @param itemRoot Root item having price adjusted - * @param itemTemplate Db template of item - */ + /// + /// Adjust price of item based on what is left to buy (resource/uses left) + /// + /// All barter scheme for item having price adjusted + /// Root item having price adjusted + /// DB template of item protected void AdjustItemPriceByQuality( Dictionary>> barterSchemes, Item itemRoot, @@ -1033,13 +1027,14 @@ public class FenceService( return null; } - /** - * Find presets in base fence assort and add desired number to 'assorts' parameter - * @param desiredWeaponPresetsCount - * @param assorts Assorts to add preset to - * @param baseFenceAssort Base data to draw from - * @param loyaltyLevel Which loyalty level is required to see/buy item - */ + /// + /// Find presets in base fence assort and add desired number to 'assorts' parameter + /// + /// How many WeaponPresets to add + /// How many WeaponPresets to add + /// Assorts to add preset to + /// Base data to draw from + /// Loyalty level to set new presets to protected void AddPresetsToAssort( int? desiredWeaponPresetsCount, int? desiredEquipmentPresetsCount, @@ -1178,11 +1173,11 @@ public class FenceService( } } - /** - * Adjust plate / soft insert durability values - * @param armor Armor item array to add mods into - * @param itemDbDetails Armor items db template - */ + /// + /// Adjust plate / soft insert durability values + /// + /// Armor item array to add mods into + /// Armor items db template protected void RandomiseArmorModDurability(List armor, TemplateItem itemDbDetails) { // Armor has no mods, nothing to randomise @@ -1207,11 +1202,11 @@ public class FenceService( } } - /** - * Randomise the durability values of items on armor with a passed in slot - * @param softInsertSlots Slots of items to randomise - * @param armorItemAndMods Array of armor + inserts to get items from - */ + /// + /// Randomise the durability values of items on armor with a passed in slot + /// + /// Slots of items to randomise + /// Array of armor + inserts to get items from protected void RandomiseArmorSoftInsertDurabilities(List softInsertSlots, List armorItemAndMods) { foreach (var requiredSlot in softInsertSlots) @@ -1264,12 +1259,12 @@ public class FenceService( } } - /** - * Randomise the durability values of plate items in armor - * Has chance to remove plate - * @param plateSlots Slots of items to randomise - * @param armorItemAndMods Array of armor + inserts to get items from - */ + /// + /// Randomise the durability values of plate items in armor
+ /// Has chance to remove plate + ///
+ /// Slots of items to randomise + /// Array of armor + inserts to get items from protected void RandomiseArmorInsertsDurabilities(List plateSlots, List armorItemAndMods) { foreach (var plateSlot in plateSlots) @@ -1334,11 +1329,11 @@ public class FenceService( } } - /** - * Get stack size of a singular item (no mods) - * @param itemDbDetails item being added to fence - * @returns Stack size - */ + /// + /// Get stack size of a singular item (no mods) + /// + /// Item being added to fence + /// Stack size protected int GetSingleItemStackCount(TemplateItem itemDbDetails) { MinMax? overrideValues; @@ -1374,10 +1369,10 @@ public class FenceService( return 1; } - /** - * Remove parts of a weapon prior to being listed on flea - * @param itemAndMods Weapon to remove parts from - */ + /// + /// Remove parts of a weapon prior to being listed on flea + /// + /// Weapon to remove parts from protected void RemoveRandomModsOfItem(List itemAndMods) { // Items to be removed from inventory @@ -1410,12 +1405,12 @@ public class FenceService( } } - /** - * Roll % chance check to see if item should be removed - * @param weaponMod Weapon mod being checked - * @param itemsBeingDeleted Current list of items on weapon being deleted - * @returns True if item will be removed - */ + /// + /// Roll % chance check to see if item should be removed + /// + /// Weapon mod being checked + /// Current list of items on weapon being deleted + /// True if item will be removed protected bool PresetModItemWillBeRemoved(Item weaponMod, HashSet itemsBeingDeleted) { var slotIdsThatCanFail = traderConfig.Fence.PresetSlotsToRemoveChancePercent; @@ -1430,11 +1425,11 @@ public class FenceService( return removalChance > randomChance && !itemsBeingDeleted.Contains(weaponMod.Id); } - /** - * Randomise items' Upd properties e.g. med packs/weapons/armor - * @param itemDetails Item being randomised - * @param itemToAdjust Item being edited - */ + /// + /// Randomise items' Upd properties e.g. med packs/weapons/armor + /// + /// Item being randomised + /// Item being edited protected void RandomiseItemUpdProperties(TemplateItem itemDetails, Item itemToAdjust) { if (itemDetails.Properties == null) @@ -1535,12 +1530,12 @@ public class FenceService( } } - /** - * Generate a randomised current and max durability value for an armor item - * @param itemDetails Item to create values for - * @param equipmentDurabilityLimits Max durability percent min/max values - * @returns Durability + MaxDurability values - */ + /// + /// Generate a randomised current and max durability value for an armor item + /// + /// Item to create values for + /// Max durability percent min/max values + /// Durability + MaxDurability values protected UpdRepairable GetRandomisedArmorDurabilityValues( TemplateItem itemDetails, ItemDurabilityCurrentMax equipmentDurabilityLimits @@ -1564,11 +1559,11 @@ public class FenceService( }; } - /** - * Construct item limit record to hold max and current item count - * @param limits limits as defined in config - * @returns record, key: item tplId, value: current/max item count allowed - */ + /// + /// Construct item limit record to hold max and current item count + /// + /// Limits as defined in config + /// Record, key: item tplId, value: current/max item count allowed protected Dictionary InitItemLimitCounter(Dictionary limits) { var itemTypeCounts = new Dictionary(); @@ -1581,10 +1576,10 @@ public class FenceService( return itemTypeCounts; } - /** - * Get the next Update timestamp for fence - * @returns future timestamp - */ + /// + /// Get the next Update timestamp for fence + /// + /// Future timestamp public long GetNextFenceUpdateTimestamp() { var time = timeUtil.GetTimeStamp(); @@ -1592,10 +1587,10 @@ public class FenceService( return time + updateSeconds; } - /** - * Get fence refresh time in seconds - * @returns Refresh time in seconds - */ + /// + /// Get fence refresh time in seconds + /// + /// Refresh time in seconds protected int GetFenceRefreshTime() { var fence = traderConfig.UpdateTime.FirstOrDefault(x => x.TraderId == Traders.FENCE).Seconds; @@ -1603,11 +1598,11 @@ public class FenceService( return randomUtil.GetInt((int) fence.Min, (int) fence.Max); } - /** - * Get fence level the passed in profile has - * @param pmcData Player profile - * @returns FenceLevel object - */ + /// + /// Get fence level the passed in profile has + /// + /// Player profile + /// FenceLevel object public FenceLevel GetFenceInfo(PmcData pmcData) { var fenceSettings = databaseService.GetGlobals().Configuration.FenceSettings; @@ -1636,11 +1631,11 @@ public class FenceService( return fenceSettings.Levels[pmcFenceLevel]; } - /** - * Remove or lower stack size of an assort from fence by id - * @param assortId assort id to adjust - * @param buyCount Count of items bought - */ + /// + /// Remove or lower stack size of an assort from fence by id + /// + /// Assort ID to adjust + /// `Count of items bought public void AmendOrRemoveFenceOffer(string assortId, int buyCount) { var isNormalAssort = true; diff --git a/Libraries/SPTarkov.Server.Core/Services/GiftService.cs b/Libraries/SPTarkov.Server.Core/Services/GiftService.cs index 4ac9a521..00898200 100644 --- a/Libraries/SPTarkov.Server.Core/Services/GiftService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/GiftService.cs @@ -23,11 +23,11 @@ public class GiftService( { protected GiftsConfig _giftConfig = _configServer.GetConfig(); - /** - * Does a gift with a specific ID exist in db - * @param giftId Gift id to check for - * @returns True if it exists in db - */ + /// + /// Does a gift with a specific ID exist in db + /// + /// Gift id to check for + /// True if it exists in db public bool GiftExists(string giftId) { return _giftConfig.Gifts.ContainsKey(giftId); @@ -40,30 +40,30 @@ public class GiftService( return gift; } - /** - * Get dictionary of all gifts - * @returns Dict keyed by gift id - */ + /// + /// Get dictionary of all gifts + /// + /// Dict keyed by gift id public Dictionary GetGifts() { return _giftConfig.Gifts; } - /** - * Get an array of all gift ids - * @returns string array of gift ids - */ + /// + /// Get an array of all gift ids + /// + /// String list of gift ids public List GetGiftIds() { return _giftConfig.Gifts.Keys.ToList(); } - /** - * Send player a gift from a range of sources - * @param playerId Player to send gift to / sessionId - * @param giftId Id of gift in configs/gifts.json to send player - * @returns outcome of sending gift to player - */ + /// + /// Send player a gift from a range of sources + /// + /// Player to send gift to / sessionID + /// ID of gift in configs/gifts.json to send player + /// Outcome of sending gift to player public GiftSentResult SendGiftToPlayer(string playerId, string giftId) { var giftData = GetGiftById(giftId); @@ -182,11 +182,11 @@ public class GiftService( return GiftSentResult.SUCCESS; } - /** - * Get sender id based on gifts sender type enum - * @param giftData Gift to send player - * @returns trader/user/system id - */ + /// + /// Get sender id based on gifts sender type enum + /// + /// Gift to send player + /// trader/user/system id private string? GetSenderId(Gift giftData) { if (giftData.Sender == GiftSenderType.Trader) @@ -202,11 +202,11 @@ public class GiftService( return null; } - /** - * Convert GiftSenderType into a dialog MessageType - * @param giftData Gift to send player - * @returns MessageType enum value - */ + /// + /// Convert GiftSenderType into a dialog MessageType + /// + /// Gift to send player + /// MessageType enum value protected MessageType? GetMessageType(Gift giftData) { switch (giftData.Sender) @@ -223,11 +223,11 @@ public class GiftService( } } - /** - * Prapor sends gifts to player for first week after profile creation - * @param sessionId Player id - * @param day What day to give gift for - */ + /// + /// Prapor sends gifts to player for first week after profile creation + /// + /// Player ID + /// What day to give gift for public void SendPraporStartingGift(string sessionId, int day) { var giftId = day switch @@ -246,12 +246,12 @@ public class GiftService( } } - /** - * Send player a gift with silent received check - * @param giftId Id of gift to send - * @param sessionId Session id of player to send to - * @param giftCount OPTIONAL How many to send - */ + /// + /// Send player a gift with silent received check + /// + /// ID of gift to send + /// Session ID of player to send to + /// Optional, how many to send public void SendGiftWithSilentReceivedCheck(string giftId, string? sessionId, int giftCount) { if (!_profileHelper.PlayerHasRecievedMaxNumberOfGift(sessionId, giftId, giftCount)) diff --git a/Libraries/SPTarkov.Server.Core/Services/InMemoryCacheService.cs b/Libraries/SPTarkov.Server.Core/Services/InMemoryCacheService.cs index 221ee262..429cf3eb 100644 --- a/Libraries/SPTarkov.Server.Core/Services/InMemoryCacheService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/InMemoryCacheService.cs @@ -10,17 +10,21 @@ public class InMemoryCacheService( { protected Dictionary _cacheData = new(); - // Store data into an in-memory object - // key to store data against - // Data to store in cache + /// + /// Store data into an in-memory object + /// + /// Key to store data against + /// Data to store in cache public void StoreByKey(string key, T dataToCache) { _cacheData[key] = _cloner.Clone(dataToCache); } - // Retrieve data stored by a key - // key - // Stored data + /// + /// Retrieve data stored by a key + /// + /// key + /// Stored data public T? GetDataByKey(string key) { if (_cacheData.ContainsKey(key)) @@ -31,22 +35,28 @@ public class InMemoryCacheService( return default; } - // Does data exist against the provided key - // Key to check for data against - // true if exists + /// + /// Does data exist against the provided key + /// + /// Key to check for data against + /// True if exists public bool HasStoredDataByKey(string key) { return _cacheData.ContainsKey(key); } - // Remove data stored against key - // Key to remove data against + /// + /// Remove data stored against key + /// + /// Key to remove data against public void ClearDataStoredByKey(string key) { _cacheData.Remove(key); } - // Remove all data stored + /// + /// Remove all data stored + /// public void ClearCache() { _cacheData.Clear(); diff --git a/Libraries/SPTarkov.Server.Core/Services/ItemBaseClassService.cs b/Libraries/SPTarkov.Server.Core/Services/ItemBaseClassService.cs index f28f6c6b..0b256e09 100644 --- a/Libraries/SPTarkov.Server.Core/Services/ItemBaseClassService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/ItemBaseClassService.cs @@ -5,6 +5,9 @@ using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel; namespace SPTarkov.Server.Core.Services; +/// +/// Cache the baseids for each item in the items db inside a dictionary +/// [Injectable(InjectionType.Singleton)] public class ItemBaseClassService( ISptLogger _logger, @@ -15,10 +18,10 @@ public class ItemBaseClassService( private bool _cacheGenerated; private Dictionary> _itemBaseClassesCache; - /** - * Create cache and store inside ItemBaseClassService - * Store a dict of an items tpl to the base classes it and its parents have - */ + /// + /// Create cache and store inside ItemBaseClassService
+ /// Store a dict of an items tpl to the base classes it and its parents have + ///
public void HydrateItemBaseClassCache() { // Clear existing cache @@ -40,11 +43,11 @@ public class ItemBaseClassService( _cacheGenerated = true; } - /** - * Helper method, recursively iterate through items parent items, finding and adding ids to dictionary - * @param itemIdToUpdate item tpl to store base ids against in dictionary - * @param item item being checked - */ + /// + /// Helper method, recursively iterate through items parent items, finding and adding ids to dictionary + /// + /// Item tpl to store base ids against in dictionary + /// Item being checked protected void AddBaseItems(string itemIdToUpdate, TemplateItem item) { _itemBaseClassesCache[itemIdToUpdate].Add(item.Parent); @@ -56,12 +59,12 @@ public class ItemBaseClassService( } } - /** - * Does item tpl inherit from the requested base class - * @param itemTpl item to check base classes of - * @param baseClass base class to check for - * @returns true if item inherits from base class passed in - */ + /// + /// Does item tpl inherit from the requested base class + /// + /// ItemTpl item to check base classes of + /// BaseClass base class to check for + /// true if item inherits from base class passed in public bool ItemHasBaseClass(string itemTpl, ICollection baseClasses) { if (!_cacheGenerated) @@ -107,21 +110,21 @@ public class ItemBaseClassService( return false; } - /** - * Check if cached item template is of type Item - * @param itemTemplateId item to check - * @returns true if item is of type Item - */ + /// + /// Check if cached item template is of type Item + /// + /// ItemTemplateId item to check + /// True if item is of type Item private bool CachedItemIsOfItemType(string itemTemplateId) { return string.Equals(_databaseService.GetItems()[itemTemplateId]?.Type,"Item", StringComparison.OrdinalIgnoreCase); } - /** - * Get base classes item inherits from - * @param itemTpl item to get base classes for - * @returns array of base classes - */ + /// + /// Get base classes item inherits from + /// + /// ItemTpl item to get base classes for + /// array of base classes public List GetItemBaseClasses(string itemTpl) { if (!_cacheGenerated) diff --git a/Libraries/SPTarkov.Server.Core/Services/ItemFilterService.cs b/Libraries/SPTarkov.Server.Core/Services/ItemFilterService.cs index c28a316c..e3c9024c 100644 --- a/Libraries/SPTarkov.Server.Core/Services/ItemFilterService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/ItemFilterService.cs @@ -5,7 +5,9 @@ using SPTarkov.Server.Core.Utils.Cloners; using SPTarkov.Common.Annotations; namespace SPTarkov.Server.Core.Services; - +/// +/// Centralise the handling of blacklisting items, uses blacklist found in config/item.json, stores items that should not be used by players / broken items +/// [Injectable(InjectionType.Singleton)] public class ItemFilterService( ISptLogger _logger, @@ -18,11 +20,11 @@ public class ItemFilterService( protected HashSet? _lootableItemBlacklistCache = []; - /** - * Check if the provided template id is blacklisted in config/item.json/blacklist - * @param tpl template id - * @returns true if blacklisted - */ + /// + /// Check if the provided template id is blacklisted in config/item.json/blacklist + /// + /// Template id + /// True if blacklisted public bool ItemBlacklisted(string tpl) { if (_itemBlacklistCache.Count == 0) @@ -33,76 +35,76 @@ public class ItemFilterService( return _itemBlacklistCache.Contains(tpl); } - /** - * Check if item is blacklisted from being a reward for player - * @param tpl item tpl to check is on blacklist - * @returns True when blacklisted - */ + /// + /// Check if item is blacklisted from being a reward for player + /// + /// Item tpl to check is on blacklist + /// True when blacklisted public bool ItemRewardBlacklisted(string tpl) { return _itemConfig.RewardItemBlacklist.Contains(tpl); } - /** - * Get an array of items that should never be given as a reward to player - * @returns string array of item tpls - */ + /// + /// Get an HashSet of items that should never be given as a reward to player + /// + /// HashSet of item tpls public HashSet GetItemRewardBlacklist() { return _cloner.Clone(_itemConfig.RewardItemBlacklist); } - /** - * Get an array of item types that should never be given as a reward to player - * @returns string array of item base ids - */ + /// + /// Get an HashSet of item types that should never be given as a reward to player + /// + /// HashSet of item base ids public HashSet GetItemRewardBaseTypeBlacklist() { return _cloner.Clone(_itemConfig.RewardItemTypeBlacklist); } - /** - * Return every template id blacklisted in config/item.json - * @returns string array of blacklisted template ids - */ + /// + /// Return every template id blacklisted in config/item.json + /// + /// HashSet of blacklisted template ids public HashSet GetBlacklistedItems() { return _cloner.Clone(_itemConfig.Blacklist); } - /** - * Return every template id blacklisted in config/item.json/lootableItemBlacklist - * @returns string array of blacklisted template ids - */ + /// + /// Return every template id blacklisted in config/item.json/lootableItemBlacklist + /// + /// HashSet of blacklisted template ids public HashSet GetBlacklistedLootableItems() { return _cloner.Clone(_itemConfig.LootableItemBlacklist); } - /** - * Check if the provided template id is boss item in config/item.json - * @param tpl template id - * @returns true if boss item - */ + /// + /// Check if the provided template id is boss item in config/item.json + /// + /// template id + /// True if boss item public bool BossItem(string tpl) { return _itemConfig.BossItems.Contains(tpl); } - /** - * Return boss items in config/item.json - * @returns string array of boss item template ids - */ + /// + /// Return boss items in config/item.json + /// + /// HashSet of boss item template ids public HashSet GetBossItems() { return _cloner.Clone(_itemConfig.BossItems).ToHashSet(); } - /** - * Check if the provided template id is blacklisted in config/item.json/lootableItemBlacklist - * @param tpl template id - * @returns true if blacklisted - */ + /// + /// Check if the provided template id is blacklisted in config/item.json/lootableItemBlacklist + /// + /// Template id + /// True if blacklisted public bool IsLootableItemBlacklisted(string itemKey) { if (!_lootableItemBlacklistCache.Any()) @@ -139,21 +141,21 @@ public class ItemFilterService( } } - /** - * Check if the provided template id is boss item in config/item.json - * @param tpl template id - * @returns true if boss item - */ + /// + /// Check if the provided template id is boss item in config/item.json + /// + /// Template id + /// True if boss item public bool IsBossItem(string tpl) { return _itemConfig.BossItems.Contains(tpl); } - /** - * Check if item is blacklisted from being a reward for player - * @param tpl item tpl to check is on blacklist - * @returns True when blacklisted - */ + /// + /// Check if item is blacklisted from being a reward for player + /// + /// Item tpl to check is on blacklist + /// true when blacklisted public bool IsItemRewardBlacklisted(string tpl) { return _itemConfig.RewardItemBlacklist.Contains(tpl); diff --git a/Libraries/SPTarkov.Server.Core/Services/LocaleService.cs b/Libraries/SPTarkov.Server.Core/Services/LocaleService.cs index f2eae3c9..7fbdb73d 100644 --- a/Libraries/SPTarkov.Server.Core/Services/LocaleService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/LocaleService.cs @@ -15,10 +15,10 @@ public class LocaleService( { protected LocaleConfig _localeConfig = _configServer.GetConfig(); - /** - * Get the eft globals db file based on the configured locale in config/locale.json, if not found, fall back to 'en' - * @returns dictionary - */ + /// + /// Get the eft globals db file based on the configured locale in config/locale.json, if not found, fall back to 'en' + /// + /// Dictionary public Dictionary GetLocaleDb() { if (_databaseServer.GetTables().Locales.Global.TryGetValue(GetDesiredGameLocale(), out var desiredLocale)) @@ -33,11 +33,11 @@ public class LocaleService( return _databaseServer.GetTables().Locales.Global["en"].Value; } - /** - * Gets the game locale key from the locale.json file, - * if value is 'system' get system locale - * @returns locale e.g en/ge/cz/cn - */ + /// + /// Gets the game locale key from the locale.json file, + /// if value is 'system' get system locale + /// + /// Locale e.g en/ge/cz/cn public string GetDesiredGameLocale() { if (_localeConfig.GameLocale.ToLower() == "system") @@ -48,11 +48,11 @@ public class LocaleService( return _localeConfig.GameLocale.ToLower(); } - /** - * Gets the game locale key from the locale.json file, - * if value is 'system' get system locale - * @returns locale e.g en/ge/cz/cn - */ + /// + /// Gets the game locale key from the locale.json file, + /// if value is 'system' get system locale + /// + /// Locale e.g en/ge/cz/cn public string GetDesiredServerLocale() { if (_localeConfig.ServerLocale.ToLower() == "system") @@ -63,28 +63,28 @@ public class LocaleService( return _localeConfig.ServerLocale.ToLower(); } - /** - * Get array of languages supported for localisation - * @returns array of locales e.g. en/fr/cn - */ + /// + /// Get array of languages supported for localisation + /// + /// List of locales e.g. en/fr/cn public List GetServerSupportedLocales() { return _localeConfig.ServerSupportedLocales; } - /** - * Get array of languages supported for localisation - * @returns array of locales e.g. en/fr/cn - */ + /// + /// Get array of languages supported for localisation + /// + /// Dictionary of locales e.g. en/fr/cn public Dictionary GetLocaleFallbacks() { return _localeConfig.Fallbacks; } - /** - * Get the full locale of the computer running the server lowercased e.g. en-gb / pt-pt - * @returns string - */ + /// + /// Get the full locale of the computer running the server lowercased e.g. en-gb / pt-pt + /// + /// System locale as String public string GetPlatformForServerLocale() { var platformLocale = GetPlatformLocale(); @@ -124,10 +124,10 @@ public class LocaleService( return baseNameCode; } - /** - * Get the locale of the computer running the server - * @returns langage part of locale e.g. 'en' part of 'en-US' - */ + /// + /// Get the locale of the computer running the server + /// + /// Language part of locale e.g. 'en' part of 'en-US' protected string GetPlatformForClientLocale() { var platformLocale = GetPlatformLocale(); @@ -150,12 +150,11 @@ public class LocaleService( return languageCode; } - /* - const regionCode = platformLocale.region?.toLocaleLowerCase(); - if (regionCode && locales.global[regionCode]) { - return regionCode; - } - */ + // + // const regionCode = platformLocale.region?.toLocaleLowerCase(); + // if (regionCode && locales.global[regionCode]) { + // return regionCode; + // } // BSG map DE to GE some reason if (baseNameCode == "de") @@ -167,10 +166,10 @@ public class LocaleService( return "en"; } - /** - * This is in a function so we can overwrite it during testing - * @returns The current platform locale - */ + /// + /// This is in a function so we can overwrite it during testing + /// + /// The current platform locale protected CultureInfo GetPlatformLocale() { return CultureInfo.InstalledUICulture; diff --git a/Libraries/SPTarkov.Server.Core/Services/LocalisationService.cs b/Libraries/SPTarkov.Server.Core/Services/LocalisationService.cs index 8c991f4f..e4a5eb21 100644 --- a/Libraries/SPTarkov.Server.Core/Services/LocalisationService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/LocalisationService.cs @@ -5,6 +5,9 @@ using SPTarkov.Common.Annotations; namespace SPTarkov.Server.Core.Services; +/// +/// Handles translating server text into different langauges +/// [Injectable(InjectionType.Singleton)] public class LocalisationService { @@ -41,7 +44,12 @@ public class LocalisationService ); _i18nService.SetLocaleByKey(localeService.GetDesiredServerLocale()); } - + /// + /// Get a localised value using the passed in key + /// + /// Key to look up locale for + /// optional arguments + /// Localised string public string GetText(string key, object? args = null) { return args is null @@ -49,16 +57,31 @@ public class LocalisationService : _i18nService.GetLocalised(key, args); } + /// + /// Get a localised value using the passed in key + /// + /// Key to look up locale for + /// Value to localize + /// Localised string public string GetText(string key, T value) where T : IConvertible? { return _i18nService.GetLocalised(key, value); } + /// + /// Get all locale keys + /// + /// Generic collection of keys public ICollection GetKeys() { return _i18nService.GetLocalisedKeys(); } + /// + /// From the provided partial key, find all keys that start with text and choose a random match + /// + /// Key to match locale keys on + /// Locale text public string GetRandomTextThatMatchesPartialKey(string partialKey) { var values = _localeService.GetLocaleKeysThatStartsWithValue(partialKey); diff --git a/Libraries/SPTarkov.Server.Core/Services/LocationLifecycleService.cs b/Libraries/SPTarkov.Server.Core/Services/LocationLifecycleService.cs index cbc0bf0d..f87ee979 100644 --- a/Libraries/SPTarkov.Server.Core/Services/LocationLifecycleService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/LocationLifecycleService.cs @@ -124,9 +124,9 @@ public class LocationLifecycleService _pmcConfig = _configServer.GetConfig(); } - /** - * Handle client/match/local/start - */ + /// + /// Handle client/match/local/start + /// public virtual StartLocalRaidResponseData StartLocalRaid(string sessionId, StartLocalRaidRequestData request) { _logger.Debug($"Starting: {request.Location}"); @@ -196,12 +196,12 @@ public class LocationLifecycleService return result; } - /** - * Replace map exits with scav exits when player is scavving - * @param playerSide Players side (savage/usec/bear) - * @param location id of map being loaded - * @param locationData Maps location base data - */ + /// + /// Replace map exits with scav exits when player is scavving + /// + /// Players side (savage/usec/bear) + /// ID of map being loaded + /// Maps location base data protected void AdjustExtracts(string playerSide, string location, LocationBase locationData) { var playerIsScav = playerSide.ToLower() == "savage"; @@ -228,10 +228,10 @@ public class LocationLifecycleService } } - /** - * Adjust the bot hostility values prior to entering a raid - * @param location map to adjust values of - */ + /// + /// Adjust the bot hostility values prior to entering a raid + /// + /// Map to adjust values of protected void AdjustBotHostilitySettings(LocationBase location) { foreach (var botId in _pmcConfig.HostilitySettings) @@ -322,13 +322,19 @@ public class LocationLifecycleService } } - /** - * Generate a maps base location (cloned) and loot - * @param name Map name - * @param generateLoot OPTIONAL - Should loot be generated for the map before being returned - * @returns LocationBase - */ - protected LocationBase GenerateLocationAndLoot(string name, bool generateLoot = true) + /// + /// Generate a maps base location (cloned) and loot + /// + /// Map name + /// OPTIONAL - Should loot be generated for the map before being returned + /// LocationBase + /// LocationBase + /// OPTIONAL - Should loot be generated for the map before being returned + /// Map name + ///
+ /// Generate a maps base location (cloned) and loot + /// + public virtual LocationBase GenerateLocationAndLoot(string name, bool generateLoot = true) { var location = _databaseService.GetLocation(name); var locationBaseClone = _cloner.Clone(location.Base); @@ -401,9 +407,9 @@ public class LocationLifecycleService return locationBaseClone; } - /** - * Handle client/match/local/end - */ + /// + /// Handle client/match/local/end + /// public virtual void EndLocalRaid(string sessionId, EndLocalRaidRequestData request) { // Clear bot loot cache @@ -510,11 +516,11 @@ public class LocationLifecycleService ); } - /** - * Was extract by car - * @param extractName name of extract - * @returns True if extract was by car - */ + /// + /// Was extract by car + /// + /// Name of extract + /// True if extract was by car protected bool ExtractWasViaCar(string extractName) { // exit name is undefined on death @@ -531,12 +537,12 @@ public class LocationLifecycleService return _inRaidConfig.CarExtracts.Contains(extractName.Trim()); } - /** - * Handle when a player extracts using a car - Add rep to fence - * @param extractName name of the extract used - * @param pmcData Player profile - * @param sessionId Session id - */ + /// + /// Handle when a player extracts using a car - Add rep to fence + /// + /// Name of the extract used + /// Player profile + /// Session ID protected void HandleCarExtract(string extractName, PmcData pmcData, string sessionId) { pmcData.CarExtractCounts?.TryAdd(extractName, 0); @@ -550,7 +556,7 @@ public class LocationLifecycleService pmcData.CarExtractCounts[extractName] ); - var fenceId = Traders.FENCE; + const string fenceId = Traders.FENCE; pmcData.TradersInfo[fenceId].Standing = newFenceStanding; // Check if new standing has leveled up trader @@ -565,12 +571,12 @@ public class LocationLifecycleService scavData.TradersInfo[fenceId].LoyaltyLevel = pmcData.TradersInfo[fenceId].LoyaltyLevel; } - /** - * Handle when a player extracts using a coop extract - add rep to fence - * @param sessionId Session/player id - * @param pmcData Profile - * @param extractName Name of extract taken - */ + /// + /// Handle when a player extracts using a coop extract - add rep to fence + /// + /// Session/player id + /// Player profile + /// Name of extract taken protected void HandleCoopExtract(string sessionId, PmcData pmcData, string extractName) { pmcData.CoopExtractCounts?.TryAdd(extractName, 0); @@ -583,7 +589,7 @@ public class LocationLifecycleService pmcData.CoopExtractCounts[extractName] ); - var fenceId = Traders.FENCE; + const string fenceId = Traders.FENCE; pmcData.TradersInfo[fenceId].Standing = newFenceStanding; // Check if new standing has leveled up trader @@ -598,16 +604,16 @@ public class LocationLifecycleService scavData.TradersInfo[fenceId].LoyaltyLevel = pmcData.TradersInfo[fenceId].LoyaltyLevel; } - /** - * Get the fence rep gain from using a car or coop extract - * @param pmcData Profile - * @param baseGain amount gained for the first extract - * @param extractCount Number of times extract was taken - * @returns Fence standing after taking extract - */ + /// + /// Get the fence rep gain from using a car or coop extract + /// + /// Profile + /// Amount gained for the first extract + /// Number of times extract was taken + /// Fence standing after taking extract protected double GetFenceStandingAfterExtract(PmcData pmcData, double baseGain, double extractCount) { - var fenceId = Traders.FENCE; + const string fenceId = Traders.FENCE; var fenceStanding = pmcData.TradersInfo[fenceId].Standing; // get standing after taking extract x times, x.xx format, gain from extract can be no smaller than 0.01 @@ -620,11 +626,11 @@ public class LocationLifecycleService return Math.Round(newFenceStanding, 2); } - /** - * Did player take a COOP extract - * @param extractName Name of extract player took - * @returns True if coop extract - */ + /// + /// Did player take a COOP extract + /// + /// Name of extract player took + /// True if coop extract protected bool ExtractTakenWasCoop(string extractName) { // No extract name, not a coop extract @@ -709,11 +715,11 @@ public class LocationLifecycleService _saveServer.SaveProfile(sessionId); } - /** - * Scav quest progress isnt transferred automatically from scav to pmc, we do this manually - * @param scavProfile Scav profile with quest progress post-raid - * @param pmcProfile Server pmc profile to copy scav quest progress into - */ + /// + /// Scav quest progress isn't transferred automatically from scav to pmc, we do this manually + /// + /// Scav profile with quest progress post-raid + /// Server pmc profile to copy scav quest progress into private void MigrateScavQuestProgressToPmcProfile(PmcData scavProfile, PmcData pmcProfile) { foreach (var scavQuest in scavProfile.Quests) @@ -753,11 +759,11 @@ public class LocationLifecycleService } } - /** - * Does provided profile contain any condition counters - * @param profile Profile to check for condition counters - * @returns Profile has condition counters - */ + /// + /// Does the provided profile contain any condition counters + /// + /// Profile to check for condition counters + /// Profile has condition counters protected bool ProfileHasConditionCounters(PmcData profile) { if (profile.TaskConditionCounters is null) @@ -768,15 +774,17 @@ public class LocationLifecycleService return profile.TaskConditionCounters.Count > 0; } - /** - * @param sessionId Player id - * @param pmcProfile Pmc profile - * @param scavProfile Scav profile - * @param isDead Player died/got left behind in raid - * @param isSurvived Not same as opposite of `isDead`, specific status - * @param request - * @param locationName - */ + /// + /// Handles PMC Profile after the raid + /// + /// Player id + /// Pmc profile + /// Scav profile + /// Player died/got left behind in raid + /// Not same as opposite of `isDead`, specific status + /// Player transferred to another map + /// Client request data + /// Current finished Raid location protected void HandlePostRaidPmc( string sessionId, SptProfile fullProfile, @@ -823,7 +831,7 @@ public class LocationLifecycleService // Must occur AFTER experience is set and stats copied over pmcProfile.Stats.Eft.TotalSessionExperience = 0; - var fenceId = Traders.FENCE; + const string fenceId = Traders.FENCE; // Clamp fence standing var currentFenceStanding = postRaidProfile.TradersInfo[fenceId].Standing; @@ -884,6 +892,13 @@ public class LocationLifecycleService } } + /// + /// On death Quest items are lost, the client does not clean up completed conditions for picking up those quest items, + /// If the completed conditions remain in the profile the player is unable to pick the item up again + /// + /// Session ID + /// Quest items lost on player death + /// Quest status data from player profile protected void CheckForAndFixPickupQuestsAfterDeath( string sessionId, List lostQuestItems, @@ -953,11 +968,16 @@ public class LocationLifecycleService } } -/* - * In 0.15 Lightkeeper quests do not give rewards in PvE, this issue also occurs in spt - * We check for newly completed Lk quests and run them through the servers `CompleteQuest` process - * This rewards players with items + craft unlocks + new trader assorts - */ + + /// + /// In 0.15 Lightkeeper quests do not give rewards in PvE, this issue also occurs in spt. + /// We check for newly completed Lk quests and run them through the servers `CompleteQuest` process. + /// This rewards players with items + craft unlocks + new trader assorts. + /// + /// Session ID + /// Quest statuses post-raid + /// Quest statuses pre-raid + /// Players profile protected void LightkeeperQuestWorkaround( string sessionId, List postRaidQuests, @@ -997,10 +1017,12 @@ public class LocationLifecycleService } } -/* - * Convert post-raid quests into correct format - * Quest status comes back as a string version of the enum `Success`, not the expected value of 1 - */ + /// + /// Convert post-raid quests into correct format. + /// Quest status comes back as a string version of the enum `Success`, not the expected value of 1. + /// + /// Quests data from client + /// List of adjusted QuestStatus post-raid protected List ProcessPostRaidQuests(List questsToProcess) { var failedQuests = questsToProcess.Where(quest => quest.Status == QuestStatusEnum.MarkedAsFailed); @@ -1021,9 +1043,11 @@ public class LocationLifecycleService return questsToProcess; } -/* - * Adjust server trader settings if they differ from data sent by client - */ + /// + /// Adjust server trader settings if they differ from data sent by client + /// + /// Server + /// Client protected void ApplyTraderStandingAdjustments( Dictionary? tradersServerProfile, Dictionary? tradersClientProfile @@ -1046,9 +1070,11 @@ public class LocationLifecycleService } } -/* - * Check if player used BTR or transit item sending service and send items to player via mail if found - */ + /// + /// Check if player used BTR or transit item sending service and send items to player via mail if found + /// + /// Session ID + /// End raid request from client protected void HandleItemTransferEvent(string sessionId, EndLocalRaidRequestData request) { var transferTypes = new List @@ -1147,71 +1173,21 @@ public class LocationLifecycleService } } -/* - * Return the equipped items from a players inventory - */ - protected List GetEquippedGear(List items) - { - var inventorySlots = new HashSet - { - "FirstPrimaryWeapon", - "SecondPrimaryWeapon", - "Holster", - "Scabbard", - "Compass", - "Headwear", - "Earpiece", - "Eyewear", - "FaceCover", - "ArmBand", - "ArmorVest", - "TacticalVest", - "Backpack", - "pocket1", - "pocket2", - "pocket3", - "pocket4", - "SpecialSlot1", - "SpecialSlot2", - "SpecialSlot3" - }; - - // Get an array of root player items - var inventoryItems = items.Where(item => inventorySlots.Contains(item.SlotId)).ToList(); - - // Loop through these items and get all of their children - var newItems = inventoryItems; - while (newItems.Count > 0) - { - var foundItems = new List(); - foreach (var item in newItems) - { - // Find children of this item - foundItems.AddRange(items.Where(newItem => string.Equals(newItem.ParentId, item.Id, StringComparison.Ordinal))); - } - - // Add these newly found items to our list of inventory items - inventoryItems.AddRange(inventoryItems); - inventoryItems.AddRange(foundItems); - - // Now find the children of these items - newItems = foundItems; - } - - return inventoryItems; - } - -/* - * Checks to see if player survives. run through will return false - */ + /// + /// Checks to see if player survives. run through will return false + /// + /// Post raid request + /// True if survived protected bool IsPlayerSurvived(EndRaidResult results) { return results.Result == ExitStatus.SURVIVED; } -/* - * Is the player dead after a raid - dead = anything other than "survived" / "runner" - */ + /// + /// Is the player dead after a raid - dead = anything other than "survived" / "runner" + /// + /// Post raid request + /// True if dead protected bool IsPlayerDead(EndRaidResult results) { var deathEnums = new List @@ -1223,17 +1199,20 @@ public class LocationLifecycleService return deathEnums.Contains(results.Result.Value); } -/* - * Has the player moved from one map to another - */ + /// + /// Has the player moved from one map to another + /// + /// Post raid request + /// True if players transferred protected bool IsMapToMapTransfer(EndRaidResult results) { return results.Result == ExitStatus.TRANSIT; } -/* - * Reset the skill points earned in a raid to 0, ready for next raid - */ + /// + /// Reset the skill points earned in a raid to 0, ready for next raid + /// + /// Profile common skills to update protected void ResetSkillPointsEarnedDuringRaid(List commonSkills) { foreach (var skill in commonSkills) @@ -1242,10 +1221,12 @@ public class LocationLifecycleService } } -/* - * merge two dictionaries together - * Prioritise pair that has true as a value - */ + /// + /// Merge two dictionaries together. + /// Prioritise pair that has true as a value + /// + /// Main dictionary + /// Secondary dictionary protected void MergePmcAndScavEncyclopedias(PmcData primary, PmcData secondary) { var mergedDicts = primary.Encyclopedia?.Union(secondary.Encyclopedia) @@ -1259,6 +1240,11 @@ public class LocationLifecycleService secondary.Encyclopedia = mergedDicts; } + /// + /// Check for and add any rewards found via the gained achievements this raid + /// + /// Profile to add customisations to + /// All profile achievements at the end of a raid protected void ProcessAchievementRewards(SptProfile fullProfile, Dictionary? postRaidAchievements) { var sessionId = fullProfile.ProfileInfo.ProfileId; diff --git a/Libraries/SPTarkov.Server.Core/Services/MailSendService.cs b/Libraries/SPTarkov.Server.Core/Services/MailSendService.cs index e4bcf3fc..89b84f63 100644 --- a/Libraries/SPTarkov.Server.Core/Services/MailSendService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/MailSendService.cs @@ -31,15 +31,17 @@ public class MailSendService( protected HashSet _messageTypes = [MessageType.NPC_TRADER, MessageType.FLEAMARKET_MESSAGE]; protected HashSet _slotNames = ["hideout", "main"]; - /** - * Send a message from an NPC (e.g. prapor) to the player with or without items using direct message text, do not look up any locale - * @param sessionId The session ID to send the message to - * @param trader The trader sending the message - * @param messageType What type the message will assume (e.g. QUEST_SUCCESS) - * @param message Text to send to the player - * @param items Optional items to send to player - * @param maxStorageTimeSeconds Optional time to collect items before they expire - */ + /// + /// Send a message from an NPC (e.g. prapor) to the player with or without items using direct message text, do not look up any locale + /// + /// The session ID to send the message to + /// The trader sending the message + /// What type the message will assume (e.g. QUEST_SUCCESS) + /// Text to send to the player + /// Optional items to send to player + /// Optional time to collect items before they expire + /// + /// public void SendDirectNpcMessageToPlayer( string sessionId, string? trader, @@ -97,15 +99,17 @@ public class MailSendService( SendMessageToPlayer(details); } - /** - * Send a message from an NPC (e.g. prapor) to the player with or without items - * @param sessionId The session ID to send the message to - * @param trader The trader sending the message - * @param messageType What type the message will assume (e.g. QUEST_SUCCESS) - * @param messageLocaleId The localised text to send to player - * @param items Optional items to send to player - * @param maxStorageTimeSeconds Optional time to collect items before they expire - */ + /// + /// Send a message from an NPC (e.g. prapor) to the player with or without items + /// + /// The session ID to send the message to + /// The trader sending the message + /// What type the message will assume (e.g. QUEST_SUCCESS) + /// The localised text to send to player + /// Optional items to send to player + /// Optional time to collect items before they expire + /// + /// public void SendLocalisedNpcMessageToPlayer( string sessionId, string? trader, @@ -171,13 +175,14 @@ public class MailSendService( SendMessageToPlayer(details); } - /** - * Send a message from SYSTEM to the player with or without items - * @param sessionId The session ID to send the message to - * @param message The text to send to player - * @param items Optional items to send to player - * @param maxStorageTimeSeconds Optional time to collect items before they expire - */ + /// + /// Send a message from SYSTEM to the player with or without items + /// + /// The session ID to send the message to + /// The text to send to player + /// Optional items to send to player + /// Optional time to collect items before they expire + /// public void SendSystemMessageToPlayer( string sessionId, string message, @@ -209,7 +214,14 @@ public class MailSendService( SendMessageToPlayer(details); } - + /// + /// Send a message from SYSTEM to the player with or without items with localised text + /// + /// The session ID to send the message to + /// Id of key from locale file to send to player + /// Optional items to send to player + /// + /// Optional time to collect items before they expire public void SendLocalisedSystemMessageToPlayer( string sessionId, string messageLocaleId, @@ -241,14 +253,14 @@ public class MailSendService( SendMessageToPlayer(details); } - /** - * Send a USER message to a player with or without items - * @param sessionId The session ID to send the message to - * @param senderId Who is sending the message - * @param message The text to send to player - * @param items Optional items to send to player - * @param maxStorageTimeSeconds Optional time to collect items before they expire - */ + /// + /// Send a USER message to a player with or without items + /// + /// The session ID to send the message to + /// Who is sending the message + /// The text to send to player + /// Optional items to send to player + /// Optional time to collect items before they expire public void SendUserMessageToPlayer( string sessionId, UserDialogInfo senderDetails, @@ -276,11 +288,11 @@ public class MailSendService( SendMessageToPlayer(details); } - /** - * Large function to send messages to players from a variety of sources (SYSTEM/NPC/USER) - * Helper functions in this class are available to simplify common actions - * @param messageDetails Details needed to send a message to the player - */ + /// + /// Large function to send messages to players from a variety of sources (SYSTEM/NPC/USER). + /// Helper functions in this class are available to simplify common actions + /// + /// Details needed to send a message to the player public void SendMessageToPlayer(SendMessageDetails messageDetails) { // Get dialog, create if doesn't exist @@ -332,6 +344,12 @@ public class MailSendService( _notificationSendHelper.SendMessage(messageDetails.RecipientId, notificationMessage); } + /// + /// Send a message from the player to an NPC + /// + /// Session ID + /// NPC message is sent to + /// Text to send to NPC public void SendPlayerMessageToNpc(string sessionId, string targetNpcId, string message) { var playerProfile = _saveServer.GetProfile(sessionId); @@ -356,6 +374,12 @@ public class MailSendService( ); } + /// + /// Create a message for storage inside a dialog in the player profile + /// + /// ID of dialog that will hold the message + /// Various details on what the message must contain/do + /// Message private Message CreateDialogMessage(string dialogId, SendMessageDetails messageDetails) { Message message = new() @@ -385,12 +409,13 @@ public class MailSendService( return message; } - /** - * @param recipientId The id of the recipient - * @param replyToId The id of the message to reply to - * @param dialogueId The id of the dialogue (traderId or profileId) - * @returns A new instance with data from the found message, otherwise undefined - */ + /// + /// Finds the Message to reply to using the ID of the recipient, message and the dialogue. + /// + /// The ID of the recipient + /// The ID of the message to reply to + /// The ID of the dialogue (traderId or profileId) + /// A new instance with data from the found message, otherwise undefined protected ReplyTo? GetMessageToReplyTo(string recipientId, string replyToId, string dialogueId) { var currentDialogue = _dialogueHelper.GetDialogueFromProfile(recipientId, dialogueId); @@ -417,12 +442,12 @@ public class MailSendService( }; } - /** - * Add items to message and adjust various properties to reflect the items being added - * @param message Message to add items to - * @param itemsToSendToPlayer Items to add to message - * @param maxStorageTimeSeconds total time items are stored in mail before being deleted - */ + /// + /// Add items to message and adjust various properties to reflect the items being added + /// + /// Message to add items to + /// Items to add to message + /// Total time the items are stored in mail before being deleted private void AddRewardItemsToMessage(Message message, MessageItems? itemsToSendToPlayer, long? maxStorageTimeSeconds) { if ((itemsToSendToPlayer?.Data?.Count ?? 0) > 0) @@ -434,6 +459,12 @@ public class MailSendService( } } + /// + /// Perform various sanitising actions on the items before they're considered ready for insertion into message + /// + /// The type of the dialog that will hold the reward items being processed + /// Details fo the message e.g. Text, items it has etc. + /// Sanitised items private MessageItems ProcessItemsBeforeAddingToMail(MessageType? dialogType, SendMessageDetails messageDetails) { var items = _databaseService.GetItems(); @@ -544,11 +575,11 @@ public class MailSendService( return itemsToSendToPlayer; } - /** - * Try to find the most correct item to be the 'primary' item in a reward mail - * @param items Possible items to choose from - * @returns Chosen 'primary' item - */ + /// + /// Try to find the most correct item to be the 'primary' item in a reward mail + /// + /// Possible items to choose from + /// Chosen 'primary' item private Item GetBaseItemFromRewards(List? items) { // Only one item in reward, return it @@ -576,12 +607,13 @@ public class MailSendService( return items[0]; } - /** - * Get a dialog with a specified entity (user/trader) - * Create and store empty dialog if none exists in profile - * @param messageDetails Data on what message should do - * @returns Relevant Dialogue - */ + /// + /// Get a dialog with a specified entity (user/trader). + /// Create and store empty dialog if none exists in profile. + /// + /// Data on what message should do + /// Relevant Dialogue object + /// Thrown when message not found private Dialogue GetDialog(SendMessageDetails messageDetails) { var senderId = GetMessageSenderIdByType(messageDetails); @@ -610,11 +642,11 @@ public class MailSendService( return dialogsInProfile[senderId]; } - /** - * Get the appropriate sender id by the sender enum type - * @param messageDetails - * @returns gets an id of the individual sending it - */ + /// + /// Get the appropriate sender id by the sender enum type + /// + /// Data of the message + /// Gets an id of the individual sending it private string? GetMessageSenderIdByType(SendMessageDetails messageDetails) { if (messageDetails.Sender == MessageType.SYSTEM_MESSAGE) diff --git a/Libraries/SPTarkov.Server.Core/Services/MatchBotDetailsCacheService.cs b/Libraries/SPTarkov.Server.Core/Services/MatchBotDetailsCacheService.cs index 7fbf6e4f..b6255164 100644 --- a/Libraries/SPTarkov.Server.Core/Services/MatchBotDetailsCacheService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/MatchBotDetailsCacheService.cs @@ -5,6 +5,9 @@ using SPTarkov.Common.Annotations; namespace SPTarkov.Server.Core.Services; +/// +/// Cache bots in a dictionary, keyed by the bots name, keying by name isnt ideal as its not unique but this is used by the post-raid system which doesnt have any bot ids, only name +/// [Injectable(InjectionType.Singleton)] public class MatchBotDetailsCacheService( ISptLogger _logger, @@ -13,6 +16,10 @@ public class MatchBotDetailsCacheService( { protected ConcurrentDictionary _botDetailsCache = new(); + /// + /// Store a bot in the cache, keyed by its name. + /// + /// Bot details to cache public void CacheBot(BotBase botToCache) { if (botToCache.Info.Nickname is null) @@ -29,11 +36,20 @@ public class MatchBotDetailsCacheService( _botDetailsCache.TryAdd(key, botToCache); } + /// + /// Clean the cache of all bot details. + /// public void ClearCache() { _botDetailsCache.Clear(); } + /// + /// Find a bot in the cache by its name and side. + /// + /// Name of bot to find + /// Side of the bot + /// public BotBase? GetBotByNameAndSide(string botName, string botSide) { var botInCache = _botDetailsCache.GetValueOrDefault($"{botName}{botSide}`", null); diff --git a/Libraries/SPTarkov.Server.Core/Services/Mod/CustomItemService.cs b/Libraries/SPTarkov.Server.Core/Services/Mod/CustomItemService.cs index d6e74c39..0339a16c 100644 --- a/Libraries/SPTarkov.Server.Core/Services/Mod/CustomItemService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/Mod/CustomItemService.cs @@ -20,16 +20,16 @@ public class CustomItemService( ICloner cloner ) { - /** - * Create a new item from a cloned item base - * WARNING - If no item id is supplied, an id will be generated, this id will be random every time you add an item and will not be the same on each subsequent server start - * Add to the items db - * Add to the flea market - * Add to the handbook - * Add to the locales - * @param newItemDetails Item details for the new item to be created - * @returns tplId of the new item created - */ + /// + /// Create a new item from a cloned item base
+ /// WARNING - If no item id is supplied, an id will be generated, this id will be random every time you add an item and will not be the same on each subsequent server start
+ /// Add to the items db
+ /// Add to the flea market
+ /// Add to the handbook
+ /// Add to the locales + ///
+ /// Item details for the new item to be created + /// tplId of the new item created public CreateItemResult CreateItemFromClone(NewItemFromCloneDetails newItemDetails) { var result = new CreateItemResult(); @@ -78,15 +78,15 @@ public class CustomItemService( return result; } - /** - * Create a new item without using an existing item as a template - * Add to the items db - * Add to the flea market - * Add to the handbook - * Add to the locales - * @param newItemDetails Details on what the item to be created - * @returns CreateItemResult containing the completed items Id - */ + /// + /// Create a new item without using an existing item as a template
+ /// Add to the items db
+ /// Add to the flea market
+ /// Add to the handbook
+ /// Add to the locales
+ ///
+ /// Details on what the item to be created + /// CreateItemResult containing the completed items ID public CreateItemResult CreateItem(NewItemDetails newItemDetails) { var result = new CreateItemResult(); @@ -122,22 +122,22 @@ public class CustomItemService( return result; } - /** - * If the id provided is an empty string, return a randomly generated guid, otherwise return the newId parameter - * @param newId id supplied to code - * @returns item id - */ + /// + /// If the ID provided is an empty string, return a randomly generated guid, otherwise return the newId parameter + /// + /// ID supplied to code + /// ItemID protected string GetOrGenerateIdForItem(string newId) { return newId == "" ? hashUtil.Generate() : newId; } - /** - * Iterates through supplied properties and updates the cloned items properties with them - * Complex objects cannot have overrides, they must be fully hydrated with values if they are to be used - * @param overrideProperties new properties to apply - * @param itemClone item to update - */ + /// + /// Iterates through supplied properties and updates the cloned items properties with them + /// Complex objects cannot have overrides, they must be fully hydrated with values if they are to be used + /// + /// New properties to apply + /// Item to update protected void UpdateBaseItemPropertiesWithOverrides(Props? overrideProperties, TemplateItem itemClone) { if (overrideProperties is null) @@ -151,11 +151,11 @@ public class CustomItemService( } } - /** - * Add a new item object to the in-memory representation of items.json - * @param newItemId id of the item to add to items.json - * @param itemToAdd Item to add against the new id - */ + /// + /// Add a new item object to the in-memory representation of items.json + /// + /// ID of the item to add to items.json + /// Item to add against the new id protected void AddToItemsDb(string newItemId, TemplateItem itemToAdd) { if (!databaseService.GetItems().TryAdd(newItemId, itemToAdd)) @@ -164,12 +164,12 @@ public class CustomItemService( } } - /** - * Add a handbook price for an item - * @param newItemId id of the item being added - * @param parentId parent id of the item being added - * @param priceRoubles price of the item being added - */ + /// + /// Add a handbook price for an item + /// + /// ID of the item being added + /// Parent ID of the item being added + /// Price of the item being added protected void AddToHandbookDb(string newItemId, string parentId, double? priceRoubles) { databaseService @@ -185,17 +185,17 @@ public class CustomItemService( // TODO: would we want to keep this the same or get them to send a HandbookItem } - /** - * Iterate through the passed in locale data and add to each locale in turn - * If data is not provided for each language EFT uses, the first object will be used in its place - * e.g. - * en[0] - * fr[1] - * - * No jp provided, so english will be used as a substitute - * @param localeDetails key is language, value are the new locale details - * @param newItemId id of the item being created - */ + /// + /// Iterate through the passed in locale data and add to each locale in turn
+ /// If data is not provided for each language EFT uses, the first object will be used in its place
+ /// e.g.
+ /// en[0]
+ /// fr[1]
+ ///
+ /// No jp provided, so english will be used as a substitute + ///
+ /// key is language, value are the new locale details + /// ID of the item being created protected void AddToLocaleDbs(Dictionary localeDetails, string newItemId) { var languages = databaseService.GetLocales().Languages; @@ -220,20 +220,20 @@ public class CustomItemService( } } - /** - * Add a price to the in-memory representation of prices.json, used to inform the flea of an items price on the market - * @param newItemId id of the new item - * @param fleaPriceRoubles Price of the new item - */ + /// + /// Add a price to the in-memory representation of prices.json, used to inform the flea of an items price on the market + /// + /// ID of the new item + /// Price of the new item protected void AddToFleaPriceDb(string newItemId, double? fleaPriceRoubles) { databaseService.GetTemplates().Prices[newItemId] = fleaPriceRoubles ?? 0; } - /** - * Add a weapon to the hideout weapon shelf whitelist - * @param newItemId Weapon id to add - */ + /// + /// Add a weapon to the hideout weapon shelf whitelist + /// + /// Weapon ID to add protected void AddToWeaponShelf(string newItemId) { // Ids for wall stashes in db @@ -253,12 +253,12 @@ public class CustomItemService( } } - /** - * Add a custom weapon to PMCs loadout - * @param weaponTpl Custom weapon tpl to add to PMCs - * @param weaponWeight The weighting for the weapon to be picked vs other weapons - * @param weaponSlot The slot the weapon should be added to (e.g. FirstPrimaryWeapon/SecondPrimaryWeapon/Holster) - */ + /// + /// Add a custom weapon to PMCs loadout + /// + /// Custom weapon tpl to add to PMCs + /// The weighting for the weapon to be picked vs other weapons + /// The slot the weapon should be added to (e.g. FirstPrimaryWeapon/SecondPrimaryWeapon/Holster) public void AddCustomWeaponToPMCs(string weaponTpl, double weaponWeight, string weaponSlot) { var weapon = itemHelper.GetItem(weaponTpl); diff --git a/Libraries/SPTarkov.Server.Core/Services/OpenZoneService.cs b/Libraries/SPTarkov.Server.Core/Services/OpenZoneService.cs index a18d75e3..884d6d2b 100644 --- a/Libraries/SPTarkov.Server.Core/Services/OpenZoneService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/OpenZoneService.cs @@ -5,6 +5,9 @@ using SPTarkov.Common.Annotations; namespace SPTarkov.Server.Core.Services; +/// +/// Service for adding new zones to a maps OpenZones property. +/// [Injectable(InjectionType.Singleton)] public class OpenZoneService( ISptLogger _logger, diff --git a/Libraries/SPTarkov.Server.Core/Services/PaymentService.cs b/Libraries/SPTarkov.Server.Core/Services/PaymentService.cs index 377a80b3..c413f9ff 100644 --- a/Libraries/SPTarkov.Server.Core/Services/PaymentService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/PaymentService.cs @@ -31,13 +31,13 @@ public class PaymentService( { protected InventoryConfig _inventoryConfig = _configServer.GetConfig(); - /** - * Take money and insert items into return to server request - * @param pmcData Pmc profile - * @param request Buy item request - * @param sessionID Session id - * @param output Client response - */ + /// + /// Take money and insert items into return to server request + /// + /// PMC Profile + /// Buy item request + /// Session ID + /// Client response public void PayMoney(PmcData pmcData, ProcessBuyTradeRequestData request, string sessionID, ItemEventRouterResponse output) { // May need to convert to trader currency @@ -142,6 +142,12 @@ public class PaymentService( } } + /// + /// Get the item price of a specific traders assort + /// + /// ID of the assort to look up + /// ID of trader with assort + /// Handbook rouble price of the item private double? GetTraderItemHandbookPriceRouble(string? traderAssortId, string traderId) { var purchasedAssortItem = _traderHelper.GetTraderAssortItemByAssortId(traderId, traderAssortId); @@ -161,6 +167,14 @@ public class PaymentService( return assortItemPriceRouble; } + /// + /// Receive money back after selling + /// + /// PMC Profile + /// Money to send back + /// Sell Trade request data + /// Client response + /// Session ID public void GiveProfileMoney(PmcData pmcData, double? amountToSend, ProcessSellTradeRequestData request, ItemEventRouterResponse output, string sessionID) { @@ -256,14 +270,14 @@ public class PaymentService( _traderHelper.LevelUp(request.TransactionId, pmcData); } - /** - * Remove currency from player stash/inventory and update client object with changes - * @param pmcData Player profile to find and remove currency from - * @param currencyTpl Type of currency to pay - * @param amountToPay money value to pay - * @param sessionID Session id - * @param output output object to send to client - */ + /// + /// Remove currency from player stash/inventory and update client object with changes + /// + /// Player profile to find and remove currency from + /// Type of currency to pay + /// Money value to pay + /// Session ID + /// Client response public void AddPaymentToOutput( PmcData pmcData, string currencyTpl, @@ -337,14 +351,14 @@ public class PaymentService( } } - /** - * TODO - ensure money in containers inside secure container are LAST - * Get all money stacks in inventory and prioritise items in stash - * @param pmcData Player profile - * @param currencyTpl - * @param playerStashId Players stash id - * @returns Sorting money items - */ + /// + /// Get all money stacks in inventory and prioritise items in stash + /// + /// Player profile + /// Currency to find + /// Players stash ID + /// List of sorted money items + // TODO - ensure money in containers inside secure container are LAST protected List GetSortedMoneyItemsInInventory(PmcData pmcData, string currencyTpl, string playerStashId) { var moneyItemsInInventory = _itemHelper.FindBarterItems("tpl", pmcData.Inventory.Items, currencyTpl); @@ -359,15 +373,15 @@ public class PaymentService( return moneyItemsInInventory; } - /** - * Prioritise player stash first over player inventory - * Post-raid healing would often take money out of the players pockets/secure container - * @param a First money stack item - * @param b Second money stack item - * @param inventoryItems players inventory items - * @param playerStashId Players stash id - * @returns sort order - */ + /// + /// Prioritise player stash first over player inventory. + /// Post-raid healing would often take money out of the players pockets/secure container. + /// + /// First money stack item + /// Second money stack item + /// Players inventory items + /// Players stash ID + /// Sort order, -1 if in a, 1 if in b, 0 if they match protected int PrioritiseStashSort(Item a, Item b, List inventoryItems, string playerStashId) { // a in root of stash, prioritise @@ -433,13 +447,13 @@ public class PaymentService( return 0; } - /** - * Recursively check items parents to see if it is inside the players inventory, not stash - * @param itemId item id to check - * @param inventoryItems player inventory - * @param playerStashId Players stash id - * @returns true if its in inventory - */ + /// + /// Recursively check items parents to see if it is inside the players inventory, not stash + /// + /// Item ID to check + /// Player inventory + /// Players stash ID + /// True if it's in inventory protected bool IsInStash(string itemId, List inventoryItems, string playerStashId) { var itemParent = inventoryItems.FirstOrDefault(item => item.Id == itemId); diff --git a/Libraries/SPTarkov.Server.Core/Services/PlayerService.cs b/Libraries/SPTarkov.Server.Core/Services/PlayerService.cs index 1a5a1123..80348d8e 100644 --- a/Libraries/SPTarkov.Server.Core/Services/PlayerService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/PlayerService.cs @@ -8,11 +8,14 @@ public class PlayerService( DatabaseService _databaseService ) { - /** - * Get level of player - * @param pmcData Player profile - * @returns Level of player - */ + /// + /// Calculates the current level of a player based on their accumulated experience points. + /// This method iterates through an experience table to determine the highest level achieved + /// by comparing the player's experience against cumulative thresholds. + /// + /// Player profile + /// The calculated level of the player as an integer, or null if the level cannot be determined. + /// This value is also assigned to within the provided profile. public int? CalculateLevel(PmcData pmcData) { var accExp = 0; diff --git a/Libraries/SPTarkov.Server.Core/Services/PmcChatResponseService.cs b/Libraries/SPTarkov.Server.Core/Services/PmcChatResponseService.cs index db31f750..5bffe677 100644 --- a/Libraries/SPTarkov.Server.Core/Services/PmcChatResponseService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/PmcChatResponseService.cs @@ -29,12 +29,12 @@ public class PmcChatResponseService( protected GiftsConfig _giftConfig = _configServer.GetConfig(); protected PmcChatResponse _pmcResponsesConfig = _configServer.GetConfig(); - /** - * For each PMC victim of the player, have a chance to send a message to the player, can be positive or negative - * @param sessionId Session id - * @param pmcVictims List of bots killed by player - * @param pmcData Player profile - */ + /// + /// For each PMC victim of the player, have a chance to send a message to the player, can be positive or negative + /// + /// Session ID + /// List of bots killed by player + /// Player profile public void SendVictimResponse(string sessionId, List pmcVictims, PmcData pmcData) { foreach (var victim in pmcVictims) @@ -65,12 +65,12 @@ public class PmcChatResponseService( } } - /** - * Not fully implemented yet, needs method of acquiring killers details after raid - * @param sessionId Session id - * @param pmcData Players profile - * @param killer The bot who killed the player - */ + /// + /// Not fully implemented yet, needs method of acquiring killers details after raid + /// + /// Session id + /// Players profile + /// The bot who killed the player public void SendKillerResponse(string sessionId, PmcData pmcData, Aggressor killer) { if (killer is null) @@ -128,13 +128,13 @@ public class PmcChatResponseService( _notificationSendHelper.SendMessageToPlayer(sessionId, killerDetails, message, MessageType.USER_MESSAGE); } - /** - * Choose a localised message to send the player (different if sender was killed or killed player) - * @param isVictim Is the message coming from a bot killed by the player - * @param pmcData Player profile - * @param victimData OPTIMAL - details of the pmc killed - * @returns Message from PMC to player - */ + /// + /// Choose a localised message to send the player (different if sender was killed or killed player) + /// + /// Is the message coming from a bot killed by the player + /// Player profile + /// OPTIONAL - details of the pmc killed + /// Message from PMC to player protected string? ChooseMessage(bool isVictim, PmcData pmcData, Victim? victimData = null) { // Positive/negative etc @@ -189,22 +189,22 @@ public class PmcChatResponseService( return responseText; } - /** - * use map key to get a localised location name - * e.g. factory4_day becomes "Factory" - * @param locationKey location key to localise - * @returns Localised location name - */ + /// + /// use map key to get a localised location name + /// e.g. factory4_day becomes "Factory" + /// + /// Location key to localise + /// Localised location name protected string GetLocationName(string locationKey) { return _localeService.GetLocaleDb()[locationKey] ?? locationKey; } - /** - * Should capitalisation be stripped from the message response before sending - * @param isVictim Was responder a victim of player - * @returns true = should be stripped - */ + /// + /// Should capitalisation be stripped from the message response before sending + /// + /// Was responder a victim of player + /// True = should be stripped protected bool StripCapitalisation(bool isVictim) { var chance = isVictim @@ -214,11 +214,11 @@ public class PmcChatResponseService( return _randomUtil.GetChance100(chance); } - /** - * Should capitalisation be stripped from the message response before sending - * @param isVictim Was responder a victim of player - * @returns true = should be stripped - */ + /// + /// Should capitalisation be stripped from the message response before sending + /// + /// Was responder a victim of player + /// True = should be stripped protected bool AllCaps(bool isVictim) { var chance = isVictim @@ -228,11 +228,11 @@ public class PmcChatResponseService( return _randomUtil.GetChance100(chance); } - /** - * Should a suffix be appended to the end of the message being sent to player - * @param isVictim Was responder a victim of player - * @returns true = should be stripped - */ + /// + /// Should a suffix be appended to the end of the message being sent to player + /// + /// Was responder a victim of player + /// True = should be appended protected bool AppendSuffixToMessageEnd(bool isVictim) { var chance = isVictim @@ -242,11 +242,11 @@ public class PmcChatResponseService( return _randomUtil.GetChance100(chance); } - /** - * Choose a type of response based on the weightings in pmc response config - * @param isVictim Was responder killed by player - * @returns Response type (positive/negative) - */ + /// + /// Choose a type of response based on the weightings in pmc response config + /// + /// Was responder killed by player + /// Response type (positive/negative) protected string ChooseResponseType(bool isVictim = true) { var responseWeights = isVictim @@ -256,12 +256,12 @@ public class PmcChatResponseService( return _weightedRandomHelper.GetWeightedValue(responseWeights); } - /** - * Get locale keys related to the type of response to send (victim/killer) - * @param keyType Positive/negative - * @param isVictim Was responder killed by player - * @returns - */ + /// + /// Get locale keys related to the type of response to send (victim/killer) + /// + /// Positive/negative + /// Was responder killed by player + /// List of response locale keys protected List GetResponseLocaleKeys(string keyType, bool isVictim = true) { var keyBase = isVictim ? "pmcresponse-victim_" : "pmcresponse-killer_"; @@ -270,10 +270,10 @@ public class PmcChatResponseService( return keys.Where(x => x.StartsWith($"{keyBase}{keyType}")).ToList(); } - /** - * Get all locale keys that start with `pmcresponse-suffix` - * @returns list of keys - */ + /// + /// Get all locale keys that start with `pmcresponse-suffix` + /// + /// List of keys protected List GetResponseSuffixLocaleKeys() { var keys = _localisationService.GetKeys(); @@ -281,12 +281,12 @@ public class PmcChatResponseService( return keys.Where(x => x.StartsWith("pmcresponse-suffix")).ToList(); } - /** - * TODO: is this used? - * Randomly draw a victim of the list and return their details - * @param pmcVictims Possible victims to choose from - * @returns IUserDialogInfo - */ + /// + /// Randomly draw a victim of the list and return their details + /// + /// Possible victims to choose from + /// UserDialogInfo object + // TODO: is this used? protected UserDialogInfo ChooseRandomVictim(List pmcVictims) { var randomVictim = _randomUtil.GetArrayValue(pmcVictims); @@ -294,11 +294,11 @@ public class PmcChatResponseService( return GetVictimDetails(randomVictim); } - /** - * Convert a victim object into a IUserDialogInfo object - * @param pmcVictim victim to convert - * @returns IUserDialogInfo - */ + /// + /// Convert a victim object into a IUserDialogInfo object + /// + /// Victim to convert + /// UserDialogInfo object protected UserDialogInfo GetVictimDetails(Victim pmcVictim) { var categories = new List diff --git a/Libraries/SPTarkov.Server.Core/Services/PostDbLoadService.cs b/Libraries/SPTarkov.Server.Core/Services/PostDbLoadService.cs index 554be59c..6ae67b6d 100644 --- a/Libraries/SPTarkov.Server.Core/Services/PostDbLoadService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/PostDbLoadService.cs @@ -275,7 +275,9 @@ public class PostDbLoadService( } } - // Apply custom limits on bot types as defined in configs/location.json/botTypeLimits + /// + /// Apply custom limits on bot types as defined in configs/location.json/botTypeLimits + /// protected void AdjustMapBotLimits() { var mapsDb = _databaseService.GetLocations().GetDictionary(); @@ -386,7 +388,9 @@ public class PostDbLoadService( } } -// Make Rogues spawn later to allow for scavs to spawn first instead of rogues filling up all spawn positions + /// + /// Make Rogues spawn later to allow for scavs to spawn first instead of rogues filling up all spawn positions + /// protected void FixRoguesSpawningInstantlyOnLighthouse() { var rogueSpawnDelaySeconds = _locationConfig.RogueLighthouseSpawnTimeSettings.WaitTimeSeconds; @@ -406,7 +410,9 @@ public class PostDbLoadService( } } -// Make non-trigger-spawned raiders spawn earlier + always + /// + /// Make non-trigger-spawned raiders spawn earlier + always + /// protected void AdjustLabsRaiderSpawnRate() { var labsBase = _databaseService.GetLocations().Laboratory.Base; @@ -437,7 +443,10 @@ public class PostDbLoadService( } } -// Adjust all hideout craft times to be no higher than the override + /// + /// Adjust all hideout craft times to be no higher than the override + /// + /// Time in seconds protected void AdjustHideoutBuildTimes(int overrideSeconds) { if (overrideSeconds == -1) @@ -472,7 +481,9 @@ public class PostDbLoadService( } } -// Blank out the "test" mail message from prapor + /// + /// Blank out the "test" mail message from prapor + /// protected void RemovePraporTestMessage() { // Iterate over all languages (e.g. "en", "fr") @@ -483,7 +494,9 @@ public class PostDbLoadService( } } -// Check for any missing assorts inside each traders assort.json data, checking against traders questassort.json + /// + /// Check for any missing assorts inside each traders assort.json data, checking against traders questassort.json + /// protected void ValidateQuestAssortUnlocksExist() { var db = _databaseService.GetTables(); @@ -499,7 +512,7 @@ public class PostDbLoadService( // Merge started/success/fail quest assorts into one dictionary var mergedQuestAssorts = new Dictionary(); - mergedQuestAssorts.Concat(traderData.QuestAssort["started"]) + mergedQuestAssorts = mergedQuestAssorts.Concat(traderData.QuestAssort["started"]) .Concat(traderData.QuestAssort["success"]) .Concat(traderData.QuestAssort["fail"]) .ToDictionary(); diff --git a/Libraries/SPTarkov.Server.Core/Services/ProfileActivityService.cs b/Libraries/SPTarkov.Server.Core/Services/ProfileActivityService.cs index 557ea943..0073e4d3 100644 --- a/Libraries/SPTarkov.Server.Core/Services/ProfileActivityService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/ProfileActivityService.cs @@ -10,12 +10,12 @@ public class ProfileActivityService( { private readonly Dictionary profileActivityTimestamps = new(); - /** - * Was the requested profile active in the last requested minutes - * @param sessionId Profile to check - * @param minutes Minutes to check for activity in - * @returns True when profile was active within past x minutes - */ + /// + /// Was the requested profile active in the last requested minutes + /// + /// Profile to check + /// Minutes to check for activity in + /// True when profile was active within past x minutes public bool ActiveWithinLastMinutes(string sessionId, int minutes) { var currentTimestamp = _timeUtil.GetTimeStamp(); @@ -27,11 +27,11 @@ public class ProfileActivityService( return currentTimestamp - storedActivityTimestamp < minutes * 60; } - /** - * Get a list of profile ids that were active in the last x minutes - * @param minutes How many minutes from now to search for profiles - * @returns List of profile ids - */ + /// + /// Get a list of profile ids that were active in the last x minutes + /// + /// How many minutes from now to search for profiles + /// List of profile ids public List GetActiveProfileIdsWithinMinutes(int minutes) { var currentTimestamp = _timeUtil.GetTimeStamp(); @@ -55,10 +55,10 @@ public class ProfileActivityService( return result; } - /** - * Update the timestamp a profile was last observed active - * @param sessionId Profile to update - */ + /// + /// Update the timestamp a profile was last observed active + /// + /// Profile to update public void SetActivityTimestamp(string sessionId) { profileActivityTimestamps[sessionId] = _timeUtil.GetTimeStamp(); diff --git a/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs b/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs index f3923282..3a055a84 100644 --- a/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs @@ -401,11 +401,11 @@ public class ProfileFixerService( } } - /** - * Remove any entries from `pmcProfile.InsuredItems` that do not have a corresponding - * `pmcProfile.Inventory.items` entry - * @param pmcProfile - */ + /// + /// Remove any entries from `pmcProfile.InsuredItems` that do not have a corresponding + /// `pmcProfile.Inventory.items` entry + /// + /// PMC Profile to fix protected void FixOrphanedInsurance(PmcData pmcProfile) { // Check if the player inventory contains this item @@ -526,10 +526,10 @@ public class ProfileFixerService( return slots; } - /** - * Check for and cap profile skills at 5100. - * @param pmcProfile profile to check and fix - */ + /// + /// Check for and cap profile skills at 5100. + /// + /// Profile to check and fix protected void CheckForSkillsOverMaxLevel(PmcData pmcProfile) { var skills = pmcProfile.Skills.Common; @@ -540,11 +540,11 @@ public class ProfileFixerService( } } - /** - * Checks profile inventory for items that do not exist inside the items db - * @param sessionId Session id - * @param pmcProfile Profile to check inventory of - */ + /// + /// Checks profile inventory for items that do not exist inside the items DB + /// + /// Session ID + /// Profile to check inventory of public void CheckForOrphanedModdedItems(string sessionId, SptProfile fullProfile) { var itemsDb = _databaseService.GetItems(); @@ -720,12 +720,13 @@ public class ProfileFixerService( } } - /** - * @param buildType The type of build, used for logging only - * @param build The build to check for invalid items - * @param itemsDb The items database to use for item lookup - * @returns True if the build should be removed from the build list, false otherwise - */ + /// + /// Check whether a weapon build should be removed from the equipment list. + /// + /// The type of build, used for logging only + /// The build to check for invalid items + /// The items database to use for item lookup + /// True if the build should be removed from the build list, false otherwise protected bool ShouldRemoveWeaponEquipmentBuild( string buildType, UserBuild build, @@ -773,11 +774,12 @@ public class ProfileFixerService( return false; } - /** - * @param magazineBuild The magazine build to check for validity - * @param itemsDb The items database to use for item lookup - * @returns True if the build should be removed from the build list, false otherwise - */ + /// + /// Checks whether magazine build shou8ld be removed form the build list. + /// + /// The magazine build to check for validity + /// The items database to use for item lookup + /// True if the build should be removed from the build list, false otherwise protected bool ShouldRemoveMagazineBuild( MagazineBuild magazineBuild, Dictionary itemsDb) @@ -809,11 +811,11 @@ public class ProfileFixerService( return false; } - /** - * REQUIRED for dev profiles - * Iterate over players hideout areas and find what's built, look for missing bonuses those areas give and add them if missing - * @param pmcProfile Profile to update - */ + /// + /// REQUIRED for dev profiles
+ /// Iterate over players hideout areas and find what's built, look for missing bonuses those areas give and add them if missing + ///
+ /// Profile to update public void AddMissingHideoutBonusesToProfile(PmcData pmcProfile) { var dbHideoutAreas = _databaseService.GetHideout().Areas; @@ -869,11 +871,12 @@ public class ProfileFixerService( } } - /** - * @param profileBonuses bonuses from profile - * @param bonus bonus to find - * @returns matching bonus - */ + /// + /// Finds a bonus in a profile + /// + /// Bonuses from profile + /// Bonus to find + /// Matching bonus protected Bonus? GetBonusFromProfile(List? profileBonuses, Bonus bonus) { // match by id first, used by "TextBonus" bonuses diff --git a/Libraries/SPTarkov.Server.Core/Services/RagfairLinkedItemService.cs b/Libraries/SPTarkov.Server.Core/Services/RagfairLinkedItemService.cs index aaedf6ac..2eba3de8 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RagfairLinkedItemService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RagfairLinkedItemService.cs @@ -27,11 +27,11 @@ public class RagfairLinkedItemService( return set; } - /** - * Use ragfair linked item service to get an array of items that can fit on or in designated itemtpl - * @param itemTpl Item to get sub-items for - * @returns ITemplateItem array - */ + /// + /// Use ragfair linked item service to get an list of items that can fit on or in designated itemtpl + /// + /// Item to get sub-items for + /// TemplateItem list public List GetLinkedDbItems(string itemTpl) { var linkedItemsToWeaponTpls = GetLinkedItems(itemTpl); @@ -54,9 +54,9 @@ public class RagfairLinkedItemService( ); } - /** - * Create Dictionary of every item and the items associated with it - */ + /// + /// Create Dictionary of every item and the items associated with it + /// protected void BuildLinkedItemTable() { var linkedItems = new Dictionary>(); @@ -92,11 +92,11 @@ public class RagfairLinkedItemService( return linkedItems[id]; } - /** - * Add ammo to revolvers linked item dictionary - * @param cylinder Revolvers cylinder - * @param applyLinkedItems - */ + /// + /// Add ammo to revolvers linked item dictionary + /// + /// Revolvers cylinder + /// Set to add to protected void AddRevolverCylinderAmmoToLinkedItems(TemplateItem cylinder, HashSet itemLinkedSet) { var cylinderMod = cylinder.Properties.Slots?.FirstOrDefault(x => x.Name == "mod_magazine"); diff --git a/Libraries/SPTarkov.Server.Core/Services/RagfairOfferService.cs b/Libraries/SPTarkov.Server.Core/Services/RagfairOfferService.cs index a88a294d..56aade59 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RagfairOfferService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RagfairOfferService.cs @@ -30,10 +30,10 @@ public class RagfairOfferService( protected bool _playerOffersLoaded; protected RagfairConfig _ragfairConfig = configServer.GetConfig(); - /** - * Get all offers - * @returns RagfairOffer array - */ + /// + /// Get all offers + /// + /// List of RagfairOffers public List GetOffers() { return ragfairOfferHolder.GetOffers(); @@ -54,30 +54,30 @@ public class RagfairOfferService( ragfairOfferHolder.AddOffer(offer); } - /** - * Does the offer exist on the ragfair - * @param offerId offer id to check for - * @returns offer exists - true - */ + /// + /// Does the offer exist on the ragfair + /// + /// Offer id to check for + /// True when offer exists public bool DoesOfferExist(string offerId) { return ragfairOfferHolder.GetOfferById(offerId) != null; } - /** - * Remove an offer from ragfair by offer id - * @param offerId Offer id to remove - */ + /// + /// Remove an offer from ragfair by offer id + /// + /// Offer id to remove public void RemoveOfferById(string offerId) { ragfairOfferHolder.RemoveOffer(offerId); } - /** - * Reduce size of an offer stack by specified amount - * @param offerId Offer to adjust stack size of - * @param amount How much to deduct from offers stack size - */ + /// + /// Reduce size of an offer stack by specified amount + /// + /// Offer to adjust stack size of + /// How much to deduct from offers stack size public void ReduceOfferQuantity(string offerId, int amount) { var offer = ragfairOfferHolder.GetOfferById(offerId); @@ -99,11 +99,11 @@ public class RagfairOfferService( ragfairOfferHolder.RemoveAllOffersByTrader(traderId); } - /** - * Do the trader offers on flea need to be refreshed - * @param traderID Trader to check - * @returns true if they do - */ + /// + /// Do the trader offers on flea need to be refreshed + /// + /// Trader to check + /// True if they do public bool TraderOffersNeedRefreshing(string traderID) { var trader = databaseService.GetTrader(traderID); @@ -153,11 +153,10 @@ public class RagfairOfferService( ragfairOfferHolder.ResetExpiredOfferIds(); } - - /** - * Remove stale offer from flea - * @param staleOffer Stale offer to process - */ + /// + /// Remove stale offer from flea + /// + /// Stale offer to process protected void ProcessStaleOffer(RagfairOffer staleOffer) { var staleOfferId = staleOffer.Id; @@ -243,13 +242,13 @@ public class RagfairOfferService( profile.RagfairInfo.Offers.Splice(offerinProfileIndex, 1); } - /** - * Flea offer items are stacked up often beyond the StackMaxSize limit - * Un stack the items into an array of root items and their children - * Will create new items equal to the - * @param items Offer items to unstack - * @returns Unstacked array of items - */ + /// + /// Flea offer items are stacked up often beyond the StackMaxSize limit. + /// Unstack the items into an array of root items and their children. + /// Will create new items equal to the stack. + /// + /// Offer items to unstack + /// Unstacked array of items protected List UnstackOfferItems(List items) { var result = new List(); diff --git a/Libraries/SPTarkov.Server.Core/Services/RagfairPriceService.cs b/Libraries/SPTarkov.Server.Core/Services/RagfairPriceService.cs index 1e7b6887..d6bf5026 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RagfairPriceService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RagfairPriceService.cs @@ -12,6 +12,9 @@ using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel; namespace SPTarkov.Server.Core.Services; +/// +/// Stores flea prices for items as well as methods to interact with them. +/// [Injectable(InjectionType.Singleton)] public class RagfairPriceService( ISptLogger _logger, @@ -112,11 +115,11 @@ public class RagfairPriceService( return offerItems.Sum(item => GetFleaPriceForItem(item.Template)); } - /** - * get the dynamic (flea) price for an item - * @param itemTpl item template id to look up - * @returns price in roubles - */ + /// + /// Get the dynamic (flea) price for an item + /// + /// Item template id to look up + /// Price in roubles public double? GetDynamicPriceForItem(string itemTpl) { _databaseService.GetPrices().TryGetValue(itemTpl, out var value); diff --git a/Libraries/SPTarkov.Server.Core/Services/RagfairTaxService.cs b/Libraries/SPTarkov.Server.Core/Services/RagfairTaxService.cs index 17e7fc1a..f75fa5af 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RagfairTaxService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RagfairTaxService.cs @@ -37,16 +37,16 @@ public class RagfairTaxService( return _playerOfferTaxCache[offerIdToGet]; } - /** - * // This method, along with CalculateItemWorth, is trying to mirror the client-side code found in the method "CalculateTaxPrice". - * // It's structured to resemble the client-side code as closely as possible - avoid making any big structure changes if it's not necessary. - * * @param item Item being sold on flea - * * @param pmcData player profile - * * @param requirementsValue - * * @param offerItemCount Number of offers being created - * * @param sellInOnePiece - * * @returns Tax in roubles - */ + /// + /// This method, along with CalculateItemWorth, is trying to mirror the client-side code found in the method "CalculateTaxPrice". + /// It's structured to resemble the client-side code as closely as possible - avoid making any big structure changes if it's not necessary. + /// + /// Item being sold on flea + /// Player profile + /// + /// Number of offers being created + /// + /// Tax in roubles public double CalculateTax( Item item, PmcData pmcData, @@ -127,8 +127,16 @@ public class RagfairTaxService( return taxValue; } - // This method is trying to replicate the item worth calculation method found in the client code. - // Any inefficiencies or style issues are intentional and should not be fixed, to preserve the client-side code mirroring. + /// + /// This method is trying to replicate the item worth calculation method found in the client code. + /// Any inefficiencies or style issues are intentional and should not be fixed, to preserve the client-side code mirroring. + /// + /// + /// + /// + /// + /// + /// protected double CalculateItemWorth( Item item, TemplateItem itemTemplate, diff --git a/Libraries/SPTarkov.Server.Core/Services/TraderPurchasePersisterService.cs b/Libraries/SPTarkov.Server.Core/Services/TraderPurchasePersisterService.cs index 21bfb2e6..cf97cf3e 100644 --- a/Libraries/SPTarkov.Server.Core/Services/TraderPurchasePersisterService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/TraderPurchasePersisterService.cs @@ -20,12 +20,12 @@ public class TraderPurchasePersisterService( { protected TraderConfig _traderConfig = _configServer.GetConfig(); - /** - * Get the purchases made from a trader for this profile before the last trader reset - * @param sessionId Session id - * @param traderId Trader to loop up purchases for - * @returns Dictionary of assort id and count purchased - */ + /// + /// Get the purchases made from a trader for this profile before the last trader reset + /// + /// Session id + /// Trader to loop up purchases for + /// Dictionary of assort id and count purchased public Dictionary? GetProfileTraderPurchases(string sessionId, string traderId) { var profile = _profileHelper.GetFullProfile(sessionId); @@ -43,13 +43,13 @@ public class TraderPurchasePersisterService( return null; } - /** - * Get a purchase made from a trader for requested profile before the last trader reset - * @param sessionId Session id - * @param traderId Trader to loop up purchases for - * @param assortId Id of assort to get data for - * @returns TraderPurchaseData - */ + /// + /// Get a purchase made from a trader for requested profile before the last trader reset + /// + /// Session ID + /// Trader to loop up purchases for + /// ID of assort to get data for + /// TraderPurchaseData public TraderPurchaseData? GetProfileTraderPurchase( string sessionId, string traderId, @@ -77,10 +77,10 @@ public class TraderPurchasePersisterService( return traderPurchases[assortId]; } - /** - * Remove all trader purchase records from all profiles that exist - * @param traderId Traders id - */ + /// + /// Remove all trader purchase records from all profiles that exist + /// + /// Traders ID public void ResetTraderPurchasesStoredInProfile(string traderId) { // Reset all profiles purchase dictionaries now a trader update has occured; @@ -105,10 +105,10 @@ public class TraderPurchasePersisterService( _logger.Debug($"Reset trader: {traderId} assort buy limits"); } - /** - * Iterate over all server profiles and remove specific trader purchase data that has passed the trader refresh time - * @param traderId Trader id - */ + /// + /// Iterate over all server profiles and remove specific trader purchase data that has passed the trader refresh time + /// + /// Trader ID public void RemoveStalePurchasesFromProfiles(string traderId) { var profiles = _profileHelper.GetProfiles(); diff --git a/Libraries/SPTarkov.Server.Core/Utils/ImporterUtil.cs b/Libraries/SPTarkov.Server.Core/Utils/ImporterUtil.cs index cbcea964..a8faeb11 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/ImporterUtil.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/ImporterUtil.cs @@ -52,7 +52,7 @@ public class ImporterUtil ) { var tasks = new List(); - var dictionaryLock = new object(); + var dictionaryLock = new Lock(); var result = Activator.CreateInstance(loadedType); // get all filepaths @@ -93,7 +93,7 @@ public class ImporterUtil Action? onReadCallback, Action? onObjectDeserialized, object result, - object dictionaryLock + Lock dictionaryLock ) { try @@ -135,7 +135,7 @@ public class ImporterUtil string directory, Type loadedType, object result, - object dictionaryLock + Lock dictionaryLock ) { try diff --git a/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/ArrayToObjectFactoryConverter.cs b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/ArrayToObjectFactoryConverter.cs index 70bea49d..e34369ee 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/ArrayToObjectFactoryConverter.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/ArrayToObjectFactoryConverter.cs @@ -42,7 +42,7 @@ public class ArrayToObjectFactoryConverter : JsonConverterFactory public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options) { - if (value == null) + if (EqualityComparer.Default.Equals(value, default)) { writer.WriteStartArray(); writer.WriteEndArray(); diff --git a/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/StringToNumberFactoryConverter.cs b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/StringToNumberFactoryConverter.cs index 4335d891..47a09d5e 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/StringToNumberFactoryConverter.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/StringToNumberFactoryConverter.cs @@ -72,7 +72,7 @@ public class StringToNumberFactoryConverter : JsonConverterFactory public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options) { - if (value == null) + if (EqualityComparer.Default.Equals(value, default)) { value = default; } diff --git a/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/StringToObjectFactoryConverter.cs b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/StringToObjectFactoryConverter.cs index 75d68cd0..996444d0 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/StringToObjectFactoryConverter.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/Json/Converters/StringToObjectFactoryConverter.cs @@ -38,7 +38,7 @@ public class StringToObjectFactoryConverter : JsonConverterFactory public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options) { - if (value == null) + if (EqualityComparer.Default.Equals(value, default)) { value = default; } diff --git a/Libraries/SPTarkov.Server.Core/Utils/JsonUtil.cs b/Libraries/SPTarkov.Server.Core/Utils/JsonUtil.cs index a310bddb..409d9ea8 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/JsonUtil.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/JsonUtil.cs @@ -14,7 +14,7 @@ namespace SPTarkov.Server.Core.Utils; [Injectable(InjectionType.Singleton)] public class JsonUtil { - private static readonly JsonSerializerOptions jsonSerializerOptionsNoIndent = new() + private static JsonSerializerOptions jsonSerializerOptionsNoIndent = new() { WriteIndented = false, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, @@ -55,7 +55,7 @@ public class JsonUtil } }; - private static readonly JsonSerializerOptions jsonSerializerOptionsIndented = new(jsonSerializerOptionsNoIndent) + private static JsonSerializerOptions jsonSerializerOptionsIndented = new(jsonSerializerOptionsNoIndent) { WriteIndented = true }; @@ -154,4 +154,43 @@ public class JsonUtil { return obj == null ? null : JsonSerializer.Serialize(obj, type, indented ? jsonSerializerOptionsIndented : jsonSerializerOptionsNoIndent); } + + private void AddConverter(JsonSerializerOptions options, JsonConverter newConverter) + { + if (!options.Converters.Any(c => c.GetType() == newConverter.GetType())) + { + options.Converters.Add(newConverter); + } + } + + /// + /// Register a Json converter to serializer options + /// + /// The converter to add + public void RegisterJsonConverter(JsonConverter converter) + { + // This might actually be a terrible thing to do, but it is what it is for now + + if (!jsonSerializerOptionsNoIndent.IsReadOnly) + { + AddConverter(jsonSerializerOptionsNoIndent, converter); + } + else + { + var noIndentConverter = new JsonSerializerOptions(jsonSerializerOptionsNoIndent); + AddConverter(noIndentConverter, converter); + jsonSerializerOptionsNoIndent = noIndentConverter; + } + + if (!jsonSerializerOptionsIndented.IsReadOnly) + { + AddConverter(jsonSerializerOptionsIndented, converter); + } + else + { + var indentedConverter = new JsonSerializerOptions(jsonSerializerOptionsIndented); + AddConverter(indentedConverter, converter); + jsonSerializerOptionsIndented = indentedConverter; + } + } } diff --git a/Libraries/SPTarkov.Server.Core/Utils/RagfairOfferHolder.cs b/Libraries/SPTarkov.Server.Core/Utils/RagfairOfferHolder.cs index adfebe43..5ae5b2a9 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/RagfairOfferHolder.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/RagfairOfferHolder.cs @@ -20,14 +20,14 @@ public class RagfairOfferHolder( { protected int _maxOffersPerTemplate = configServer.GetConfig().Dynamic.OfferItemCount.Max; protected Dictionary _offersById = new(); - protected object _offersByIdLock = new(); + protected readonly Lock _offersByIdLock = new(); protected Dictionary> _offersByTemplate = new(); // key = tplId, value = list of offerIds - protected object _offersByTemplateLock = new(); + protected readonly Lock _offersByTemplateLock = new(); protected Dictionary> _offersByTrader = new(); // key = traderId, value = list of offerIds - protected object _offersByTraderLock = new(); + protected readonly Lock _offersByTraderLock = new(); protected HashSet _expiredOfferIds = []; - protected object _expiredOfferIdsLock = new(); + protected readonly Lock _expiredOfferIdsLock = new(); /// /// Get a ragfair offer by its id diff --git a/SPTarkov.Server/Program.cs b/SPTarkov.Server/Program.cs index 85f678e5..cca906fb 100644 --- a/SPTarkov.Server/Program.cs +++ b/SPTarkov.Server/Program.cs @@ -45,6 +45,9 @@ public static class Program // Initialize Watermak watermark?.Initialize(); + var appContext = serviceProvider.GetService(); + appContext?.AddValue(ContextVariableType.SERVICE_PROVIDER, serviceProvider); + // Initialize PreSptMods var preSptLoadMods = serviceProvider.GetServices(); foreach (var preSptLoadMod in preSptLoadMods) @@ -52,7 +55,6 @@ public static class Program preSptLoadMod.PreSptLoad(); } - var appContext = serviceProvider.GetService(); // Add the Loaded Mod Assemblies for later appContext?.AddValue(ContextVariableType.LOADED_MOD_ASSEMBLIES, mods); // This is the builder that will get use by the HttpServer to start up the web application diff --git a/Tools/HideoutCraftQuestIdGenerator/HideoutCraftQuestIdGenerator.cs b/Tools/HideoutCraftQuestIdGenerator/HideoutCraftQuestIdGenerator.cs index bf7fedd5..711f19cd 100644 --- a/Tools/HideoutCraftQuestIdGenerator/HideoutCraftQuestIdGenerator.cs +++ b/Tools/HideoutCraftQuestIdGenerator/HideoutCraftQuestIdGenerator.cs @@ -53,7 +53,7 @@ public class HideoutCraftQuestIdGenerator( // Figure out our source and target directories var projectDir = Directory.GetParent("./").Parent.Parent.Parent.Parent.Parent; - var productionPath = "Libraries\\SPTarkov.Server.Assets\\Assets\\database\\hideout\\production.json"; + const string productionPath = "Libraries\\SPTarkov.Server.Assets\\Assets\\database\\hideout\\production.json"; var productionFilePath = Path.Combine(projectDir.FullName, productionPath); var updatedProductionJson = _jsonUtil.Serialize(_databaseServer.GetTables().Hideout.Production, true); diff --git a/Tools/ItemTplGenerator/ItemTplGenerator.cs b/Tools/ItemTplGenerator/ItemTplGenerator.cs index 9b778b60..0842064c 100644 --- a/Tools/ItemTplGenerator/ItemTplGenerator.cs +++ b/Tools/ItemTplGenerator/ItemTplGenerator.cs @@ -304,7 +304,7 @@ public class ItemTplGenerator( private bool IsValidItem(TemplateItem item) { - var shrapnelId = "5943d9c186f7745a13413ac9"; + const string shrapnelId = "5943d9c186f7745a13413ac9"; if (item.Type != "Item") { diff --git a/server-csharp.sln.DotSettings b/server-csharp.sln.DotSettings index 2599328f..a05aa8f3 100644 --- a/server-csharp.sln.DotSettings +++ b/server-csharp.sln.DotSettings @@ -1,4 +1,5 @@  True True + True True \ No newline at end of file