Code cleanup and format

This commit is contained in:
CWX
2025-04-22 14:49:05 +01:00
parent 8ba498a4bc
commit 7c7297f63c
368 changed files with 2880 additions and 2994 deletions
+2 -2
View File
@@ -10,11 +10,11 @@ namespace Benchmarks;
[MemoryDiagnoser]
public class ClonerBenchmarks
{
private Templates? _templates;
private ICloner _fastCloner;
private ICloner _jsonCloner;
private ICloner _reflectionsCloner;
private ICloner _fastCloner;
private Templates? _templates;
[GlobalSetup]
public void Setup()
@@ -1,18 +1,17 @@
using Microsoft.Extensions.Primitives;
namespace SPTarkov.Common.Extensions
{
public static class HttpContextExtensions
{
public static StringValues? GetHeaderIfExists(this HttpContext context, string key)
{
context.Request.Headers.TryGetValue(key, out var value);
if (string.IsNullOrEmpty(value))
{
return null;
}
namespace SPTarkov.Common.Extensions;
return value;
public static class HttpContextExtensions
{
public static StringValues? GetHeaderIfExists(this HttpContext context, string key)
{
context.Request.Headers.TryGetValue(key, out var value);
if (string.IsNullOrEmpty(value))
{
return null;
}
return value;
}
}
@@ -20,8 +20,7 @@ public static class DependencyInjectionRegistrator
public static void RegisterComponents(IServiceCollection builderServices, IEnumerable<Type> types)
{
var groupedTypes = types.SelectMany(
t =>
var groupedTypes = types.SelectMany(t =>
{
var attributes = (Injectable[]) Attribute.GetCustomAttributes(t, typeof(Injectable));
var registerableType = t;
@@ -74,21 +73,20 @@ public static class DependencyInjectionRegistrator
{
_allLoadedTypes ??= AppDomain.CurrentDomain.GetAssemblies().SelectMany(t => t.GetTypes()).ToList();
}
catch(ReflectionTypeLoadException ex)
catch (ReflectionTypeLoadException ex)
{
Console.WriteLine($"COULD NOT LOAD TYPE: {ex}");
}
_allConstructors ??= _allLoadedTypes.SelectMany(t => t.GetConstructors()).ToList();
var typeName = $"{valueTuple.RegistrableInterface.Namespace}.{valueTuple.RegistrableInterface.Name}";
try
{
var matchedConstructors = _allConstructors.Where(
c => c.GetParameters()
.Any(
p => p.ParameterType.IsGenericType &&
p.ParameterType.GetGenericTypeDefinition().FullName == typeName
)
var matchedConstructors = _allConstructors.Where(c => c.GetParameters()
.Any(p => p.ParameterType.IsGenericType &&
p.ParameterType.GetGenericTypeDefinition().FullName == typeName
)
);
var constructorInfos = matchedConstructors.ToList();
@@ -100,7 +98,7 @@ public static class DependencyInjectionRegistrator
foreach (var matchedConstructor in constructorInfos)
{
var constructorParams = matchedConstructor.GetParameters();
foreach (var parameterInfo in constructorParams.Where(x => IsMatchingGenericType(x,typeName)))
foreach (var parameterInfo in constructorParams.Where(x => IsMatchingGenericType(x, typeName)))
{
var parameters = parameterInfo.ParameterType.GetGenericArguments();
var typedGeneric = valueTuple.TypeToRegister.MakeGenericType(parameters);
@@ -1,7 +1,7 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,10 +1,10 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Context;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Bot;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Match;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,9 +1,9 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Builds;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.PresetBuild;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,7 +1,7 @@
using SPTarkov.Server.Core.Loaders;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Loaders;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -20,7 +20,7 @@ public class BundleCallbacks(
}
/// <summary>
/// TODO: what does it do
/// TODO: what does it do
/// </summary>
/// <returns></returns>
public string GetBundle(string url, object info, string sessionID)
@@ -1,12 +1,11 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Models.Spt.Logging;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Enums;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,10 +1,10 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Customization;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,8 +1,8 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,11 +1,10 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.DI;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Request;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Dialog;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -73,7 +72,7 @@ public class DialogueCallbacks(
/// <summary>
/// Handle client/mail/dialog/list
/// TODO: request properties are not handled
/// TODO: request properties are not handled
/// </summary>
/// <returns></returns>
public virtual string GetMailDialogList(string url, GetMailDialogListRequestData request, string sessionID)
@@ -1,11 +1,11 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.DI;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Request;
using SPTarkov.Server.Core.Models.Eft.Game;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,6 +1,6 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.DI;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,10 +1,10 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Health;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.DI;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -5,7 +6,6 @@ using SPTarkov.Server.Core.Models.Eft.Hideout;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -172,7 +172,7 @@ public class HideoutCallbacks(
}
/// <summary>
/// Handle client/game/profile/items/moving - hideoutCustomizationSetMannequinPose
/// Handle client/game/profile/items/moving - hideoutCustomizationSetMannequinPose
/// </summary>
/// <returns></returns>
public ItemEventRouterResponse HideoutCustomizationSetMannequinPose(PmcData pmcData, HideoutCustomizationSetMannequinPoseRequest request, string sessionId)
@@ -1,7 +1,7 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Context;
using SPTarkov.Server.Core.DI;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,8 +1,8 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.InRaid;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,4 +1,5 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.DI;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Insurance;
@@ -7,7 +8,6 @@ using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,9 +1,9 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Inventory;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Models.Eft.Quests;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -274,7 +274,7 @@ public class InventoryCallbacks(
}
/// <summary>
/// Handle game/profile/items/moving SetFavoriteItems
/// Handle game/profile/items/moving SetFavoriteItems
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="info"></param>
@@ -1,8 +1,8 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Routers;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,9 +1,9 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Launcher;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,8 +1,8 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Launcher;
using SPTarkov.Server.Core.Models.Spt.Launcher;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,8 +1,8 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Location;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,9 +1,9 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Match;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
using static SPTarkov.Server.Core.Services.MatchLocationService;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,8 +1,8 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Models.Eft.Notes;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -5,7 +6,6 @@ using SPTarkov.Server.Core.Models.Eft.Common.Request;
using SPTarkov.Server.Core.Models.Eft.Notifier;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -17,12 +17,11 @@ public class NotifierCallbacks(
HttpServerHelper httpServerHelper
)
{
/// <summary>
/// If we don't have anything to send, it's ok to not send anything back
/// because notification requests can be long-polling. In fact, we SHOULD wait
/// until we actually have something to send because otherwise we'd spam the client
/// and the client would abort the connection due to spam.
/// If we don't have anything to send, it's ok to not send anything back
/// because notification requests can be long-polling. In fact, we SHOULD wait
/// until we actually have something to send because otherwise we'd spam the client
/// and the client would abort the connection due to spam.
/// </summary>
public void SendNotification(string sessionID, HttpRequest req, HttpResponse resp, object data)
{
@@ -40,12 +39,11 @@ public class NotifierCallbacks(
/// <summary>
/// TODO: removed from client?
/// Handle push/notifier/get
/// Handle push/notifier/getwebsocket
/// TODO: removed from client?
/// Handle push/notifier/get
/// Handle push/notifier/getwebsocket
/// </summary>
/// <returns></returns>
public string GetNotifier(string url, IRequestData info, string sessionID)
{
return _httpResponseUtil.EmptyArrayResponse();
@@ -1,6 +1,6 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.DI;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,8 +1,8 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Prestige;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -5,7 +6,6 @@ using SPTarkov.Server.Core.Models.Eft.Launcher;
using SPTarkov.Server.Core.Models.Eft.Profile;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -18,7 +18,7 @@ public class ProfileCallbacks(
)
{
/// <summary>
/// Handle client/game/profile/create
/// Handle client/game/profile/create
/// </summary>
/// <returns></returns>
public string CreateProfile(string url, ProfileCreateRequestData info, string sessionID)
@@ -33,8 +33,8 @@ public class ProfileCallbacks(
}
/// <summary>
/// Handle client/game/profile/list
/// Get the complete player profile (scav + pmc character)
/// Handle client/game/profile/list
/// Get the complete player profile (scav + pmc character)
/// </summary>
/// <returns></returns>
public string GetProfileData(string url, EmptyRequestData _, string sessionID)
@@ -43,9 +43,9 @@ public class ProfileCallbacks(
}
/// <summary>
/// Handle client/game/profile/savage/regenerate
/// Handle the creation of a scav profile for player
/// Occurs post-raid and when profile first created immediately after character details are confirmed by player
/// Handle client/game/profile/savage/regenerate
/// Handle the creation of a scav profile for player
/// Occurs post-raid and when profile first created immediately after character details are confirmed by player
/// </summary>
/// <returns></returns>
public string RegenerateScav(string url, EmptyRequestData _, string sessionID)
@@ -59,7 +59,7 @@ public class ProfileCallbacks(
}
/// <summary>
/// Handle client/game/profile/voice/change event
/// Handle client/game/profile/voice/change event
/// </summary>
/// <returns></returns>
public string ChangeVoice(string url, ProfileChangeVoiceRequestData info, string sessionID)
@@ -69,8 +69,8 @@ public class ProfileCallbacks(
}
/// <summary>
/// Handle client/game/profile/nickname/change event
/// Client allows player to adjust their profile name
/// Handle client/game/profile/nickname/change event
/// Client allows player to adjust their profile name
/// </summary>
/// <returns></returns>
public string ChangeNickname(string url, ProfileChangeNicknameRequestData info, string sessionID)
@@ -92,7 +92,7 @@ public class ProfileCallbacks(
}
/// <summary>
/// Handle client/game/profile/nickname/validate
/// Handle client/game/profile/nickname/validate
/// </summary>
/// <returns></returns>
public string ValidateNickname(string url, ValidateNicknameRequestData info, string sessionID)
@@ -113,7 +113,7 @@ public class ProfileCallbacks(
}
/// <summary>
/// Handle client/game/profile/nickname/reserved
/// Handle client/game/profile/nickname/reserved
/// </summary>
/// <returns></returns>
public string GetReservedNickname(string url, EmptyRequestData _, string sessionID)
@@ -128,8 +128,8 @@ public class ProfileCallbacks(
}
/// <summary>
/// Handle client/profile/status
/// Called when creating a character when choosing a character face/voice
/// Handle client/profile/status
/// Called when creating a character when choosing a character face/voice
/// </summary>
/// <returns></returns>
public string GetProfileStatus(string url, EmptyRequestData _, string sessionID)
@@ -138,8 +138,8 @@ public class ProfileCallbacks(
}
/// <summary>
/// Handle client/profile/view
/// Called when viewing another players profile
/// Handle client/profile/view
/// Called when viewing another players profile
/// </summary>
/// <returns></returns>
public string GetOtherProfile(string url, GetOtherProfileRequest request, string sessionID)
@@ -148,7 +148,7 @@ public class ProfileCallbacks(
}
/// <summary>
/// Handle client/profile/settings
/// Handle client/profile/settings
/// </summary>
/// <returns></returns>
public string GetProfileSettings(string url, GetProfileSettingsRequest info, string sessionID)
@@ -157,7 +157,7 @@ public class ProfileCallbacks(
}
/// <summary>
/// Handle client/game/profile/search
/// Handle client/game/profile/search
/// </summary>
/// <returns></returns>
public string SearchProfiles(string url, SearchProfilesRequestData info, string sessionID)
@@ -166,7 +166,7 @@ public class ProfileCallbacks(
}
/// <summary>
/// Handle launcher/profile/info
/// Handle launcher/profile/info
/// </summary>
/// <returns></returns>
public string GetMiniProfile(string url, GetMiniProfileRequestData info, string sessionID)
@@ -175,7 +175,7 @@ public class ProfileCallbacks(
}
/// <summary>
/// Handle /launcher/profiles
/// Handle /launcher/profiles
/// </summary>
/// <returns></returns>
public string GetAllMiniProfiles(string url, EmptyRequestData _, string sessionID)
@@ -1,9 +1,9 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Models.Eft.Quests;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.DI;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -7,7 +8,6 @@ using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,8 +1,8 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Models.Eft.Repair;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,8 +1,8 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.DI;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,8 +1,8 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Models.Eft.Trade;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,10 +1,10 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.DI;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,7 +1,7 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -1,8 +1,8 @@
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Controllers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Models.Eft.Wishlist;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Callbacks;
@@ -8,14 +8,14 @@ namespace SPTarkov.Server.Core.Context;
public class ApplicationContext
{
protected const short MaxSavedValues = 10;
protected readonly ConcurrentDictionary<ContextVariableType, LinkedList<ContextVariable>> variables = new();
private static ApplicationContext? _applicationContext;
private readonly ISptLogger<ApplicationContext> _logger;
protected readonly ConcurrentDictionary<ContextVariableType, LinkedList<ContextVariable>> variables = new();
/// <summary>
/// When ApplicationContext gets created by the DI container we store the singleton reference so we can provide it
/// statically for harmony patches!
/// When ApplicationContext gets created by the DI container we store the singleton reference so we can provide it
/// statically for harmony patches!
/// </summary>
public ApplicationContext
(
@@ -1,9 +1,9 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Profile;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -17,7 +17,7 @@ public class AchievementController(
protected CoreConfig coreConfig = configServer.GetConfig<CoreConfig>();
/// <summary>
/// Get base achievements
/// Get base achievements
/// </summary>
/// <param name="sessionID">Session/player id</param>
/// <returns></returns>
@@ -30,7 +30,7 @@ public class AchievementController(
}
/// <summary>
/// Shows % of 'other' players who've completed each achievement
/// Shows % of 'other' players who've completed each achievement
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <returns>CompletedAchievementsResponse</returns>
@@ -40,9 +40,11 @@ public class AchievementController(
var profiles = profileHelper.GetProfiles();
var achievements = databaseService.GetAchievements();
foreach (var achievementId in achievements.Select(achievement => achievement.Id).Where(achievementId => !string.IsNullOrEmpty(achievementId))) {
foreach (var achievementId in achievements.Select(achievement => achievement.Id).Where(achievementId => !string.IsNullOrEmpty(achievementId)))
{
var percentage = 0;
foreach (var (profileId, profile) in profiles) {
foreach (var (profileId, profile) in profiles)
{
if (coreConfig.Features.AchievementProfileIdBlacklist.Contains(profileId))
{
continue;
@@ -61,10 +63,13 @@ public class AchievementController(
percentage++;
}
percentage = (percentage / profiles.Count) * 100;
percentage = percentage / profiles.Count * 100;
stats.Add(achievementId, percentage);
}
return new CompletedAchievementsResponse{ Elements = stats };
return new CompletedAchievementsResponse
{
Elements = stats
};
}
}
@@ -1,5 +1,6 @@
using System.Diagnostics;
using System.Text.Json.Serialization;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Context;
using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Helpers;
@@ -15,7 +16,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Controllers;
@@ -41,13 +41,12 @@ public class BotController(
private readonly PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
/// <summary>
/// Return the number of bot load-out varieties to be generated
/// Return the number of bot load-out varieties to be generated
/// </summary>
/// <param name="type">bot Type we want the load-out gen count for</param>
/// <returns>number of bots to generate</returns>
public int GetBotPresetGenerationLimit(string type)
{
if (!_botConfig.PresetBatch.TryGetValue(type, out var limit))
{
_logger.Warning(_localisationService.GetText("bot-bot_preset_count_value_missing", type));
@@ -56,12 +55,11 @@ public class BotController(
}
return limit;
}
/// <summary>
/// Handle singleplayer/settings/bot/difficulty
/// Get the core.json difficulty settings from database/bots
/// Handle singleplayer/settings/bot/difficulty
/// Get the core.json difficulty settings from database/bots
/// </summary>
/// <returns></returns>
public Dictionary<string, object> GetBotCoreDifficulty()
@@ -70,8 +68,8 @@ public class BotController(
}
/// <summary>
/// Get bot difficulty settings
/// Adjust PMC settings to ensure they engage the correct bot types
/// Get bot difficulty settings
/// Adjust PMC settings to ensure they engage the correct bot types
/// </summary>
/// <param name="type">what bot the server is requesting settings for</param>
/// <param name="diffLevel">difficulty level server requested settings for</param>
@@ -100,7 +98,7 @@ public class BotController(
}
/// <summary>
/// Handle singleplayer/settings/bot/difficulties
/// Handle singleplayer/settings/bot/difficulties
/// </summary>
/// <returns></returns>
public Dictionary<string, Dictionary<string, DifficultyCategories>> GetAllBotDifficulties()
@@ -160,7 +158,7 @@ public class BotController(
}
/// <summary>
/// Generate bots for a wave
/// Generate bots for a wave
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="request"></param>
@@ -173,7 +171,7 @@ public class BotController(
}
/// <summary>
/// Generate bots for passed in wave data
/// Generate bots for passed in wave data
/// </summary>
/// <param name="request"></param>
/// <param name="pmcProfile">Player generating bots</param>
@@ -193,17 +191,18 @@ public class BotController(
Task.WaitAll((request.Conditions ?? [])
.Select(condition => Task.Factory.StartNew(() =>
{
var botWaveGenerationDetails = GetBotGenerationDetailsForWave(
condition,
pmcProfile,
allPmcsHaveSameNameAsPlayer,
raidSettings,
Math.Max(GetBotPresetGenerationLimit(condition.Role), condition.Limit), // Choose largest between value passed in from request vs what's in bot.config
_botHelper.IsBotPmc(condition.Role));
{
var botWaveGenerationDetails = GetBotGenerationDetailsForWave(
condition,
pmcProfile,
allPmcsHaveSameNameAsPlayer,
raidSettings,
Math.Max(GetBotPresetGenerationLimit(condition.Role),
condition.Limit), // Choose largest between value passed in from request vs what's in bot.config
_botHelper.IsBotPmc(condition.Role));
result.AddRange(GenerateBotWave(condition, botWaveGenerationDetails, sessionId));
})).ToArray());
result.AddRange(GenerateBotWave(condition, botWaveGenerationDetails, sessionId));
})).ToArray());
stopwatch.Stop();
if (_logger.IsLogEnabled(LogLevel.Debug))
@@ -215,7 +214,7 @@ public class BotController(
}
/// <summary>
/// Generate bots for a single wave request
/// Generate bots for a single wave request
/// </summary>
/// <param name="generateRequest"></param>
/// <param name="botGenerationDetails"></param>
@@ -276,7 +275,7 @@ public class BotController(
}
/// <summary>
/// Pull raid settings from Application context
/// Pull raid settings from Application context
/// </summary>
/// <returns>GetRaidConfigurationRequestData if it exists</returns>
protected GetRaidConfigurationRequestData? GetMostRecentRaidSettings()
@@ -294,7 +293,7 @@ public class BotController(
}
/// <summary>
/// Get min/max level range values for a specific map
/// Get min/max level range values for a specific map
/// </summary>
/// <param name="location">Map name e.g. factory4_day</param>
/// <returns>MinMax values</returns>
@@ -304,7 +303,7 @@ public class BotController(
}
/// <summary>
/// Create a BotGenerationDetails for the bot generator to use
/// Create a BotGenerationDetails for the bot generator to use
/// </summary>
/// <param name="condition">Data from client defining bot type and difficulty</param>
/// <param name="pmcProfile">Player who is generating bots</param>
@@ -339,8 +338,8 @@ public class BotController(
}
/// <summary>
/// Get the max number of bots allowed on a map
/// Looks up location player is entering when getting cap value
/// Get the max number of bots allowed on a map
/// Looks up location player is entering when getting cap value
/// </summary>
/// <param name="location">The map location cap was requested for</param>
/// <returns>bot cap for map</returns>
@@ -350,6 +349,7 @@ public class BotController(
{
return _botConfig.MaxBotCap["default"];
}
if (location == "default")
{
_logger.Warning(
@@ -361,7 +361,7 @@ public class BotController(
}
/// <summary>
/// Get weights for what each bot type should use as a brain - used by client
/// Get weights for what each bot type should use as a brain - used by client
/// </summary>
/// <returns></returns>
public AiBotBrainTypes GetAiBotBrainTypes()
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Builds;
using SPTarkov.Server.Core.Models.Eft.PresetBuild;
@@ -9,7 +10,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -51,8 +51,7 @@ public class BuildController(
.ToList();
// Get players secure container
var playerSecureContainer = profile?.CharacterData?.PmcData?.Inventory?.Items?.FirstOrDefault(
x => x.SlotId == secureContainerSlotId
var playerSecureContainer = profile?.CharacterData?.PmcData?.Inventory?.Items?.FirstOrDefault(x => x.SlotId == secureContainerSlotId
);
var firstDefaultItemsSecureContainer = defaultEquipmentPresetsClone?
@@ -149,8 +148,7 @@ public class BuildController(
Items = request.Items
};
var existingBuild = existingSavedEquipmentBuilds?.FirstOrDefault(
build => build.Name == request.Name || build.Id == request.Id
var existingBuild = existingSavedEquipmentBuilds?.FirstOrDefault(build => build.Name == request.Name || build.Id == request.Id
);
if (existingBuild is not null)
{
@@ -211,8 +209,8 @@ public class BuildController(
}
/// <summary>
/// Handle client/builds/delete
/// Remove build from players profile
/// Handle client/builds/delete
/// Remove build from players profile
/// </summary>
/// <param name="idToRemove"></param>
/// <param name="sessionId">Session/Player id</param>
@@ -1,7 +1,7 @@
using SPTarkov.Server.Core.Models.Spt.Logging;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Logging;
using SPTarkov.Server.Core.Models.Spt.Logging;
using SPTarkov.Server.Core.Models.Utils;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Controllers;
@@ -35,7 +35,7 @@ public class ClientLogController(
_logger.Info(message);
break;
case LogLevel.Custom:
_logger.LogWithColor(message, color, backgroundColor, null);
_logger.LogWithColor(message, color, backgroundColor);
break;
case LogLevel.Debug:
_logger.Debug(message);
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -12,7 +13,6 @@ using SPTarkov.Server.Core.Routers;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -44,11 +44,10 @@ public class CustomizationController(
var suits = _databaseService.GetTrader(traderId).Suits;
var matchingSuits = suits?.Where(s => clothing.ContainsKey(s.SuiteId!)).ToList();
matchingSuits = matchingSuits?.Where(
s => clothing[s.SuiteId ?? string.Empty]
?.Properties?.Side?
.Contains(pmcData?.Info?.Side ?? string.Empty) ??
false
matchingSuits = matchingSuits?.Where(s => clothing[s.SuiteId ?? string.Empty]
?.Properties?.Side?
.Contains(pmcData?.Info?.Side ?? string.Empty) ??
false
)
.ToList();
@@ -121,7 +120,7 @@ public class CustomizationController(
}
/// <summary>
/// Has an outfit been purchased by a player
/// Has an outfit been purchased by a player
/// </summary>
/// <param name="suitId">clothing id</param>
/// <param name="sessionId">Session id of profile to check for clothing in</param>
@@ -135,7 +134,7 @@ public class CustomizationController(
}
/// <summary>
/// Get clothing offer from trader by suit id
/// Get clothing offer from trader by suit id
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="offerId"></param>
@@ -192,7 +191,7 @@ public class CustomizationController(
}
/// <summary>
/// Get all suits from Traders
/// Get all suits from Traders
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <returns></returns>
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Helpers.Dialogue;
using SPTarkov.Server.Core.Models.Eft.Dialog;
@@ -9,7 +10,6 @@ using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -340,7 +340,7 @@ public class DialogueController(
}
/// <summary>
/// Get messages from a specific dialog that have items not expired
/// Get messages from a specific dialog that have items not expired
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <param name="dialogueId">Dialog to get mail attachments from</param>
@@ -503,9 +503,8 @@ public class DialogueController(
{
_mailSendService.SendPlayerMessageToNpc(sessionId, request.DialogId!, request.Text!);
return (_dialogueChatBots.FirstOrDefault(
cb =>
cb.GetChatBot().Id == request.DialogId
return (_dialogueChatBots.FirstOrDefault(cb =>
cb.GetChatBot().Id == request.DialogId
)
?.HandleMessage(sessionId, request) ??
request.DialogId) ??
@@ -557,7 +556,7 @@ public class DialogueController(
}
/// <summary>
/// Has a dialog message expired
/// Has a dialog message expired
/// </summary>
/// <param name="message">Message to check expiry of</param>
/// <returns>True = expired</returns>
@@ -567,7 +566,7 @@ public class DialogueController(
}
/// <summary>
/// Handle client/friend/request/send
/// Handle client/friend/request/send
/// </summary>
/// <param name="sessionID">Session/player id</param>
/// <param name="request">Sent friend request</param>
@@ -618,7 +617,7 @@ public class DialogueController(
}
/// <summary>
/// Handle client/friend/delete
/// Handle client/friend/delete
/// </summary>
/// <param name="sessionID">Session/player id</param>
/// <param name="request">Sent delete friend request</param>
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Context;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -5,6 +6,7 @@ using SPTarkov.Server.Core.Models.Eft.Game;
using SPTarkov.Server.Core.Models.Eft.Profile;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Models.Spt.Location;
using SPTarkov.Server.Core.Models.Spt.Mod;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
@@ -12,10 +14,7 @@ using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Server.Core.Utils.Json;
using SPTarkov.Server;
using SPTarkov.Common.Annotations;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
using SPTarkov.Server.Core.Models.Spt.Location;
namespace SPTarkov.Server.Core.Controllers;
@@ -458,7 +457,7 @@ public class GameController(
}
/// <summary>
/// Mechanic sends players a measuring tape on profile start for some reason
/// Mechanic sends players a measuring tape on profile start for some reason
/// </summary>
/// <param name="pmcProfile"></param>
protected void SendMechanicGiftsToNewProfile(PmcData pmcProfile)
@@ -478,9 +477,8 @@ public class GameController(
foreach (var mod in mods)
{
if (
fullProfile.SptData.Mods.Any(
m =>
m.Author == mod.PackageJson.Author && m.Version == mod.PackageJson.Version && m.Name == mod.PackageJson.Name
fullProfile.SptData.Mods.Any(m =>
m.Author == mod.PackageJson.Author && m.Version == mod.PackageJson.Version && m.Name == mod.PackageJson.Name
)
)
{
@@ -1,3 +1,5 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Common.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -10,8 +12,6 @@ using SPTarkov.Server.Core.Routers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
using SPTarkov.Common.Extensions;
namespace SPTarkov.Server.Core.Controllers;
@@ -208,7 +208,7 @@ public class HealthController(
}
/// <summary>
/// Apply effects to profile from consumable used
/// Apply effects to profile from consumable used
/// </summary>
/// <param name="bodyValue">Hydration/Energy</param>
/// <param name="consumptionDetails">Properties of consumed item</param>
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
@@ -15,7 +16,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -58,8 +58,8 @@ public class HideoutController(
protected HideoutConfig _hideoutConfig = _configServer.GetConfig<HideoutConfig>();
/// <summary>
/// Handle HideoutUpgrade event
/// Start a hideout area upgrade
/// Handle HideoutUpgrade event
/// Start a hideout area upgrade
/// </summary>
/// <param name="pmcData">Player profile</param>
/// <param name="request">Start upgrade request</param>
@@ -67,8 +67,7 @@ public class HideoutController(
/// <param name="output">Client response</param>
public void StartUpgrade(PmcData pmcData, HideoutUpgradeRequestData request, string sessionID, ItemEventRouterResponse output)
{
var items = request.Items.Select(
reqItem =>
var items = request.Items.Select(reqItem =>
{
var item = pmcData.Inventory.Items.FirstOrDefault(invItem => invItem.Id == reqItem.Id);
return new
@@ -141,14 +140,14 @@ public class HideoutController(
var timestamp = _timeUtil.GetTimeStamp();
profileHideoutArea.CompleteTime = (int)Math.Round(timestamp - ctime.Value);
profileHideoutArea.CompleteTime = (int) Math.Round(timestamp - ctime.Value);
profileHideoutArea.Constructing = true;
}
}
/// <summary>
/// Handle HideoutUpgradeComplete event
/// Complete a hideout area upgrade
/// Handle HideoutUpgradeComplete event
/// Complete a hideout area upgrade
/// </summary>
/// <param name="pmcData">Player profile</param>
/// <param name="request">Completed upgrade request</param>
@@ -232,7 +231,7 @@ public class HideoutController(
}
/// <summary>
/// Upgrade wall status to visible in profile if medstation/water collector are both level 1
/// Upgrade wall status to visible in profile if medstation/water collector are both level 1
/// </summary>
/// <param name="pmcData">Player profile</param>
protected void SetWallVisibleIfPrereqsMet(PmcData pmcData)
@@ -250,7 +249,7 @@ public class HideoutController(
}
/// <summary>
/// Add a stash upgrade to profile
/// Add a stash upgrade to profile
/// </summary>
/// <param name="output">Client response</param>
/// <param name="sessionId">Session/Player id</param>
@@ -317,7 +316,7 @@ public class HideoutController(
}
/// <summary>
/// Add an inventory item to profile from a hideout area stage data
/// Add an inventory item to profile from a hideout area stage data
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -344,7 +343,7 @@ public class HideoutController(
}
/// <summary>
/// Include container upgrade in client response
/// Include container upgrade in client response
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="changedHideoutStashesKey">Key of hideout area that's been upgraded</param>
@@ -366,8 +365,8 @@ public class HideoutController(
}
/// <summary>
/// Handle HideoutPutItemsInAreaSlots
/// Create item in hideout slot item array, remove item from player inventory
/// Handle HideoutPutItemsInAreaSlots
/// Create item in hideout slot item array, remove item from player inventory
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="addItemToHideoutRequest">request from client to place item in area slot</param>
@@ -377,8 +376,7 @@ public class HideoutController(
{
var output = _eventOutputHolder.GetOutput(sessionID);
var itemsToAdd = addItemToHideoutRequest.Items.Select(
kvp =>
var itemsToAdd = addItemToHideoutRequest.Items.Select(kvp =>
{
var item = pmcData.Inventory.Items.FirstOrDefault(invItem => invItem.Id == kvp.Value.Id);
return new
@@ -421,8 +419,7 @@ public class HideoutController(
// Add item to area.slots
var destinationLocationIndex = int.Parse(item.slot);
var hideoutSlotIndex = hideoutArea.Slots.FindIndex(
slot => slot.LocationIndex == destinationLocationIndex
var hideoutSlotIndex = hideoutArea.Slots.FindIndex(slot => slot.LocationIndex == destinationLocationIndex
);
if (hideoutSlotIndex == -1)
{
@@ -452,8 +449,8 @@ public class HideoutController(
}
/// <summary>
/// Handle HideoutTakeItemsFromAreaSlots event
/// Remove item from hideout area and place into player inventory
/// Handle HideoutTakeItemsFromAreaSlots event
/// Remove item from hideout area and place into player inventory
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Take item out of area request</param>
@@ -496,7 +493,7 @@ public class HideoutController(
}
/// <summary>
/// Find resource item in hideout area, add copy to player inventory, remove Item from hideout slot
/// Find resource item in hideout area, add copy to player inventory, remove Item from hideout slot
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -549,8 +546,8 @@ public class HideoutController(
}
/// <summary>
/// Handle HideoutToggleArea event
/// Toggle area on/off
/// Handle HideoutToggleArea event
/// Toggle area on/off
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Toggle area request</param>
@@ -576,7 +573,7 @@ public class HideoutController(
}
/// <summary>
/// Handle HideoutSingleProductionStart event
/// Handle HideoutSingleProductionStart event
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request"></param>
@@ -605,8 +602,7 @@ public class HideoutController(
foreach (var itemToDelete in itemsToDelete)
{
var itemToCheck = pmcData.Inventory.Items.FirstOrDefault(i => i.Id == itemToDelete.Id);
var requirement = recipeRequirementsClone.FirstOrDefault(
requirement => requirement.TemplateId == itemToCheck.Template
var requirement = recipeRequirementsClone.FirstOrDefault(requirement => requirement.TemplateId == itemToCheck.Template
);
// Handle tools not having a `count`, but always only requiring 1
@@ -629,8 +625,8 @@ public class HideoutController(
}
/// <summary>
/// Handle HideoutScavCaseProductionStart event
/// Handles event after clicking 'start' on the scav case hideout page
/// Handle HideoutScavCaseProductionStart event
/// Handles event after clicking 'start' on the scav case hideout page
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request"></param>
@@ -699,7 +695,7 @@ public class HideoutController(
}
/// <summary>
/// Adjust scav case time based on fence standing
/// Adjust scav case time based on fence standing
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="productionTime">Time to complete scav case in seconds</param>
@@ -716,7 +712,7 @@ public class HideoutController(
}
/// <summary>
/// Add generated scav case rewards to player profile
/// Add generated scav case rewards to player profile
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="rewards">reward items to add to profile</param>
@@ -731,7 +727,7 @@ public class HideoutController(
}
/// <summary>
/// Start production of continuously created item
/// Start production of continuously created item
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Continuous production request</param>
@@ -745,8 +741,8 @@ public class HideoutController(
}
/// <summary>
/// Handle HideoutTakeProduction event
/// Take completed item out of hideout area and place into player inventory
/// Handle HideoutTakeProduction event
/// Take completed item out of hideout area and place into player inventory
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Remove production from area request</param>
@@ -793,7 +789,7 @@ public class HideoutController(
}
/// <summary>
/// Take recipe-type production out of hideout area and place into player inventory
/// Take recipe-type production out of hideout area and place into player inventory
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <param name="recipe">Completed recipe of item</param>
@@ -1005,7 +1001,7 @@ public class HideoutController(
}
/// <summary>
/// Ensure non-stackable items are 'unstacked'
/// Ensure non-stackable items are 'unstacked'
/// </summary>
/// <param name="recipe"></param>
/// <param name="itemAndChildrenToSendToPlayer"></param>
@@ -1060,7 +1056,6 @@ public class HideoutController(
}
/// <summary>
///
/// </summary>
/// <param name="recipe"></param>
/// <returns></returns>
@@ -1069,7 +1064,7 @@ public class HideoutController(
var defaultPreset = _presetHelper.GetDefaultPreset(recipe.EndProduct);
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
List<Item> presetAndMods = _itemHelper.ReplaceIDs(_cloner.Clone(defaultPreset.Items));
var presetAndMods = _itemHelper.ReplaceIDs(_cloner.Clone(defaultPreset.Items));
_itemHelper.RemapRootItemId(presetAndMods);
@@ -1078,7 +1073,7 @@ public class HideoutController(
}
/// <summary>
/// Get the "CounterHoursCrafting" TaskConditionCounter from a profile
/// Get the "CounterHoursCrafting" TaskConditionCounter from a profile
/// </summary>
/// <param name="pmcData">Profile to get counter from</param>
/// <param name="recipe">Recipe being crafted</param>
@@ -1101,7 +1096,7 @@ public class HideoutController(
}
/// <summary>
/// Handles generating scav case rewards and sending to player inventory
/// Handles generating scav case rewards and sending to player inventory
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -1163,8 +1158,8 @@ public class HideoutController(
}
/// <summary>
/// Handle HideoutQuickTimeEvent on client/game/profile/items/moving
/// Called after completing workout at gym
/// Handle HideoutQuickTimeEvent on client/game/profile/items/moving
/// Called after completing workout at gym
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -1214,7 +1209,7 @@ public class HideoutController(
}
/// <summary>
/// Apply mild/severe muscle pain after gym use
/// Apply mild/severe muscle pain after gym use
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="finishEffect">Effect data to apply after completing QTE gym event</param>
@@ -1249,7 +1244,7 @@ public class HideoutController(
}
/// <summary>
/// Record a high score from the shooting range into a player profiles `overallcounters`
/// Record a high score from the shooting range into a player profiles `overallcounters`
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -1278,7 +1273,7 @@ public class HideoutController(
}
/// <summary>
/// Handle client/game/profile/items/moving - HideoutImproveArea
/// Handle client/game/profile/items/moving - HideoutImproveArea
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -1289,8 +1284,7 @@ public class HideoutController(
var output = _eventOutputHolder.GetOutput(sessionId);
// Create mapping of required item with corresponding item from player inventory
var items = request.Items.Select(
reqItem =>
var items = request.Items.Select(reqItem =>
{
var item = pmcData.Inventory.Items.FirstOrDefault(invItem => invItem.Id == reqItem.Id);
return new
@@ -1369,7 +1363,7 @@ public class HideoutController(
}
/// <summary>
/// Handle client/game/profile/items/moving HideoutCancelProductionCommand
/// Handle client/game/profile/items/moving HideoutCancelProductionCommand
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -1402,7 +1396,7 @@ public class HideoutController(
}
/// <summary>
/// Handle HideoutDeleteProductionCommand event
/// Handle HideoutDeleteProductionCommand event
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -1419,7 +1413,7 @@ public class HideoutController(
}
/// <summary>
/// Handle HideoutCustomizationApply event
/// Handle HideoutCustomizationApply event
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -1445,7 +1439,7 @@ public class HideoutController(
}
/// <summary>
/// Map an internal customisation type to a client hideout customisation type
/// Map an internal customisation type to a client hideout customisation type
/// </summary>
/// <param name="type"></param>
/// <returns>hideout customisation type</returns>
@@ -1470,7 +1464,7 @@ public class HideoutController(
}
/// <summary>
/// Add stand1/stand2/stand3 inventory items to profile, depending on passed in hideout stage
/// Add stand1/stand2/stand3 inventory items to profile, depending on passed in hideout stage
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="equipmentPresetStage">Current EQUIPMENT_PRESETS_STAND stage data</param>
@@ -1485,8 +1479,8 @@ public class HideoutController(
foreach (var mannequinSlot in slots)
{
// Check if we've already added this mannequin
var existingMannequin = pmcData.Inventory.Items.FirstOrDefault(
item => item.ParentId == equipmentPresetHideoutArea.Id && item.SlotId == mannequinSlot.Name
var existingMannequin = pmcData.Inventory.Items.FirstOrDefault(item =>
item.ParentId == equipmentPresetHideoutArea.Id && item.SlotId == mannequinSlot.Name
);
// No child, add it
@@ -1506,8 +1500,7 @@ public class HideoutController(
var mannequinPocketItemToAdd = new Item
{
Id = _hashUtil.Generate(),
Template = pmcData.Inventory.Items.FirstOrDefault(
item => item.SlotId == "Pockets" && item.ParentId == pmcData.Inventory.Equipment
Template = pmcData.Inventory.Items.FirstOrDefault(item => item.SlotId == "Pockets" && item.ParentId == pmcData.Inventory.Equipment
)
.Template, // Same pocket tpl as players profile (unheard get bigger, matching pockets etc)
ParentId = standId,
@@ -1546,8 +1539,8 @@ public class HideoutController(
}
/// <summary>
/// Handle client/hideout/qte/list
/// Get quick time event list for hideout
/// Handle client/hideout/qte/list
/// Get quick time event list for hideout
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <returns></returns>
@@ -1557,7 +1550,7 @@ public class HideoutController(
}
/// <summary>
/// Function called every `hideoutConfig.runIntervalSeconds` seconds as part of onUpdate event
/// Function called every `hideoutConfig.runIntervalSeconds` seconds as part of onUpdate event
/// </summary>
public void Update()
{
@@ -1,10 +1,10 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Context;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.InRaid;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -57,8 +57,8 @@ public class InRaidController(
}
/// <summary>
/// Handle singleplayer/scav/traitorscavhostile
/// Get a % chance a scav will be hostile to the player when they're also a scav
/// Handle singleplayer/scav/traitorscavhostile
/// Get a % chance a scav will be hostile to the player when they're also a scav
/// </summary>
/// <param name="url"></param>
/// <param name="sessionId">Session/Player id</param>
@@ -69,7 +69,7 @@ public class InRaidController(
}
/// <summary>
/// Get all boss role types e.g. bossTagilla
/// Get all boss role types e.g. bossTagilla
/// </summary>
/// <param name="url"></param>
/// <param name="sessionId">Session/Player id</param>
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -14,7 +15,6 @@ using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Server.Core.Utils.Collections;
using SPTarkov.Common.Annotations;
using Insurance = SPTarkov.Server.Core.Models.Eft.Profile.Insurance;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
@@ -46,7 +46,7 @@ public class InsuranceController(
protected InsuranceConfig _insuranceConfig = _configServer.GetConfig<InsuranceConfig>();
/// <summary>
/// Process insurance items of all profiles prior to being given back to the player through the mail service
/// Process insurance items of all profiles prior to being given back to the player through the mail service
/// </summary>
public void ProcessReturn()
{
@@ -58,7 +58,7 @@ public class InsuranceController(
}
/// <summary>
/// Process insurance items of a single profile prior to being given back to the player through the mail service
/// Process insurance items of a single profile prior to being given back to the player through the mail service
/// </summary>
/// <param name="sessionId">Player id</param>
public void ProcessReturnByProfile(string sessionId)
@@ -76,7 +76,7 @@ public class InsuranceController(
}
/// <summary>
/// Get all insured items that are ready to be processed in a specific profile
/// Get all insured items that are ready to be processed in a specific profile
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="time">The time to check ready status against. Current time by default</param>
@@ -99,7 +99,7 @@ public class InsuranceController(
}
/// <summary>
/// This method orchestrates the processing of insured items in a profile
/// This method orchestrates the processing of insured items in a profile
/// </summary>
/// <param name="insuranceDetails">The insured items to process</param>
/// <param name="sessionId">session ID that should receive the processed items</param>
@@ -142,7 +142,7 @@ public class InsuranceController(
}
/// <summary>
/// Count all items in all insurance packages
/// Count all items in all insurance packages
/// </summary>
/// <param name="insuranceDetails"></param>
/// <returns>Count of insured items</returns>
@@ -152,19 +152,18 @@ public class InsuranceController(
}
/// <summary>
/// Remove an insurance package from a profile using the package's system data information.
/// Remove an insurance package from a profile using the package's system data information.
/// </summary>
/// <param name="sessionId">The session ID of the profile to remove the package from.</param>
/// <param name="insPackage">The array index of the insurance package to remove.</param>
protected void RemoveInsurancePackageFromProfile(string sessionId, Insurance insPackage)
{
var profile = _saveServer.GetProfile(sessionId);
profile.InsuranceList = profile.InsuranceList.Where(
insurance =>
insurance.TraderId != insPackage.TraderId ||
insurance.SystemData?.Date != insPackage.SystemData?.Date ||
insurance.SystemData?.Time != insPackage.SystemData?.Time ||
insurance.SystemData?.Location != insPackage.SystemData?.Location
profile.InsuranceList = profile.InsuranceList.Where(insurance =>
insurance.TraderId != insPackage.TraderId ||
insurance.SystemData?.Date != insPackage.SystemData?.Date ||
insurance.SystemData?.Time != insPackage.SystemData?.Time ||
insurance.SystemData?.Location != insPackage.SystemData?.Location
)
.ToList();
@@ -175,7 +174,7 @@ public class InsuranceController(
}
/// <summary>
/// Finds the items that should be deleted based on the given Insurance object
/// Finds the items that should be deleted based on the given Insurance object
/// </summary>
/// <param name="rootItemParentId">The ID that should be assigned to all "hideout"/root items</param>
/// <param name="insured">The insurance object containing the items to evaluate for deletion</param>
@@ -190,8 +189,7 @@ public class InsuranceController(
var parentAttachmentsMap = PopulateParentAttachmentsMap(rootItemParentId, insured, itemsMap);
// Check to see if any regular items are present.
var hasRegularItems = itemsMap.Values.Any(
item => !_itemHelper.IsAttachmentAttached(item)
var hasRegularItems = itemsMap.Values.Any(item => !_itemHelper.IsAttachmentAttached(item)
);
// Process all items that are not attached, attachments; those are handled separately, by value.
@@ -223,9 +221,9 @@ public class InsuranceController(
}
/// <summary>
/// Initialize a dictionary that holds main-parents to all of their attachments. Note that "main-parent" in this
/// context refers to the parent item that an attachment is attached to. For example, a suppressor attached to a gun,
/// not the backpack that the gun is located in (the gun's parent).
/// Initialize a dictionary that holds main-parents to all of their attachments. Note that "main-parent" in this
/// context refers to the parent item that an attachment is attached to. For example, a suppressor attached to a gun,
/// not the backpack that the gun is located in (the gun's parent).
/// </summary>
/// <param name="rootItemParentID">The ID that should be assigned to all "hideout"/root items</param>
/// <param name="insured">The insurance object containing the items to evaluate</param>
@@ -318,13 +316,14 @@ public class InsuranceController(
}
/// <summary>
/// Remove attachments that can not be moddable in-raid from the parentAttachmentsMap. If no moddable attachments
/// remain, the parent is removed from the map as well
/// Remove attachments that can not be moddable in-raid from the parentAttachmentsMap. If no moddable attachments
/// remain, the parent is removed from the map as well
/// </summary>
/// <param name="parentAttachmentsMap">Dictionary containing parent item IDs to arrays of their attachment items</param>
/// <param name="itemsMap">Hashset containing parent item IDs to arrays of their attachment items which are not moddable in-raid</param>
/// <returns></returns>
protected Dictionary<string, List<Item>> RemoveNonModdableAttachments(Dictionary<string, List<Item>> parentAttachmentsMap, Dictionary<string, Item> itemsMap)
protected Dictionary<string, List<Item>> RemoveNonModdableAttachments(Dictionary<string, List<Item>> parentAttachmentsMap,
Dictionary<string, Item> itemsMap)
{
var updatedMap = new Dictionary<string, List<Item>>();
@@ -365,9 +364,9 @@ public class InsuranceController(
}
/// <summary>
/// Process "regular" insurance items. Any insured item that is not an attached, attachment is considered a "regular"
/// item. This method iterates over them, preforming item deletion rolls to see if they should be deleted. If so,
/// they (and their attached, attachments, if any) are marked for deletion in the toDelete Dictionary
/// Process "regular" insurance items. Any insured item that is not an attached, attachment is considered a "regular"
/// item. This method iterates over them, preforming item deletion rolls to see if they should be deleted. If so,
/// they (and their attached, attachments, if any) are marked for deletion in the toDelete Dictionary
/// </summary>
/// <param name="insured">Insurance object containing the items to evaluate</param>
/// <param name="toDelete">Hashset to keep track of items marked for deletion</param>
@@ -414,7 +413,7 @@ public class InsuranceController(
}
/// <summary>
/// Process parent items and their attachments, updating the toDelete Set accordingly
/// Process parent items and their attachments, updating the toDelete Set accordingly
/// </summary>
/// <param name="mainParentToAttachmentsMap">Dictionary containing parent item IDs to arrays of their attachment items</param>
/// <param name="itemsMap">Dictionary for quick item look-up by item ID</param>
@@ -447,10 +446,10 @@ public class InsuranceController(
/// <summary>
/// Takes an array of attachment items that belong to the same main-parent item, sorts them in descending order by
/// their maximum price. For each attachment, a roll is made to determine if a deletion should be made. Once the
/// number of deletions has been counted, the attachments are added to the toDelete Set, starting with the most
/// valuable attachments first
/// Takes an array of attachment items that belong to the same main-parent item, sorts them in descending order by
/// their maximum price. For each attachment, a roll is made to determine if a deletion should be made. Once the
/// number of deletions has been counted, the attachments are added to the toDelete Set, starting with the most
/// valuable attachments first
/// </summary>
/// <param name="attachments">Array of attachment items to sort, filter, and roll</param>
/// <param name="traderId">ID of the trader to that has ensured these items</param>
@@ -488,7 +487,7 @@ public class InsuranceController(
}
/// <summary>
/// Write out attachments being removed
/// Write out attachments being removed
/// </summary>
/// <param name="attachmentIdsToRemove"></param>
/// <param name="attachments"></param>
@@ -511,7 +510,7 @@ public class InsuranceController(
}
/// <summary>
/// Get dictionary of items with their corresponding price
/// Get dictionary of items with their corresponding price
/// </summary>
/// <param name="attachments">Item attachments</param>
/// <returns></returns>
@@ -535,7 +534,7 @@ public class InsuranceController(
}
/// <summary>
/// Get count of items to remove from weapon (take into account trader + price of attachment)
/// Get count of items to remove from weapon (take into account trader + price of attachment)
/// </summary>
/// <param name="weightedAttachmentByPrice">Dict of item Tpls and their rouble price</param>
/// <param name="traderId">Trader the attachment is insured against</param>
@@ -556,7 +555,7 @@ public class InsuranceController(
}
/// <summary>
/// Remove items from the insured items that should not be returned to the player
/// Remove items from the insured items that should not be returned to the player
/// </summary>
/// <param name="insured">The insured items to process</param>
/// <param name="toDelete">The items that should be deleted</param>
@@ -566,7 +565,7 @@ public class InsuranceController(
}
/// <summary>
/// Handle sending the insurance message to the user that potentially contains the valid insurance items
/// Handle sending the insurance message to the user that potentially contains the valid insurance items
/// </summary>
/// <param name="sessionId">Profile that should receive the insurance message</param>
/// <param name="insurance">context of insurance to use</param>
@@ -605,7 +604,7 @@ public class InsuranceController(
}
/// <summary>
/// Edge case - labs doesn't allow for insurance returns unless location config is edited
/// Edge case - labs doesn't allow for insurance returns unless location config is edited
/// </summary>
/// <param name="insurance">The insured items to process</param>
/// <param name="labsId">OPTIONAL - id of labs location</param>
@@ -617,7 +616,7 @@ public class InsuranceController(
}
/// <summary>
/// Update IInsurance object with new messageTemplateId and wipe out items array data
/// Update IInsurance object with new messageTemplateId and wipe out items array data
/// </summary>
/// <param name="traderDialogMessages"></param>
/// <param name="insurance"></param>
@@ -637,7 +636,7 @@ public class InsuranceController(
/// <summary>
/// Roll for chance of item being 'lost'
/// Roll for chance of item being 'lost'
/// </summary>
/// <param name="traderId">Trader item was insured with</param>
/// <param name="insuredItem">Item being rolled on</param>
@@ -669,7 +668,7 @@ public class InsuranceController(
}
/// <summary>
/// Handle Insure event, Add insurance to an item
/// Handle Insure event, Add insurance to an item
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Insurance request</param>
@@ -742,15 +741,14 @@ public class InsuranceController(
}
/// <summary>
/// Ensure soft inserts of Armor that has soft insert slots, Allows armors to come back after being lost correctly
/// Ensure soft inserts of Armor that has soft insert slots, Allows armors to come back after being lost correctly
/// </summary>
/// <param name="itemWithSoftInserts">Armor item to be insured</param>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Insurance request data</param>
public void InsureSoftInserts(Item itemWithSoftInserts, PmcData pmcData, InsureRequestData request)
{
var softInsertSlots = pmcData.Inventory.Items.Where(
item => item.ParentId == itemWithSoftInserts.Id && _itemHelper.IsSoftInsertId(item.SlotId.ToLower())
var softInsertSlots = pmcData.Inventory.Items.Where(item => item.ParentId == itemWithSoftInserts.Id && _itemHelper.IsSoftInsertId(item.SlotId.ToLower())
);
foreach (var softInsertSlot in softInsertSlots)
@@ -771,8 +769,8 @@ public class InsuranceController(
}
/// <summary>
/// Handle client/insurance/items/list/cost
/// Calculate insurance cost
/// Handle client/insurance/items/list/cost
/// Calculate insurance cost
/// </summary>
/// <param name="request">request object</param>
/// <param name="sessionId">Session/Player id</param>
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -12,7 +13,6 @@ using SPTarkov.Server.Core.Routers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -42,8 +42,8 @@ public class InventoryController(
)
{
/// <summary>
/// Move Item - change location of item with parentId and slotId, transfers items from one profile to another if fromOwner/toOwner is set in the body.
/// Otherwise, move is contained within the same profile_f
/// Move Item - change location of item with parentId and slotId, transfers items from one profile to another if fromOwner/toOwner is set in the body.
/// Otherwise, move is contained within the same profile_f
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="moveRequest">Move request data</param>
@@ -93,7 +93,8 @@ public class InventoryController(
// Item is moving into or out of place of fame dog tag slot
if (moveRequest.To?.Container != null &&
(moveRequest.To.Container.StartsWith("dogtag", StringComparison.OrdinalIgnoreCase) || originalLocationSlotId.StartsWith("dogtag", StringComparison.OrdinalIgnoreCase)))
(moveRequest.To.Container.StartsWith("dogtag", StringComparison.OrdinalIgnoreCase) ||
originalLocationSlotId.StartsWith("dogtag", StringComparison.OrdinalIgnoreCase)))
{
_hideoutHelper.ApplyPlaceOfFameDogtagBonus(pmcData);
}
@@ -109,7 +110,7 @@ public class InventoryController(
}
/// <summary>
/// Get an event router response with inventory trader message
/// Get an event router response with inventory trader message
/// </summary>
/// <param name="output">Item event router response</param>
protected void AppendTraderExploitErrorResponse(ItemEventRouterResponse output)
@@ -122,8 +123,8 @@ public class InventoryController(
}
/// <summary>
/// Handle /client/game/profile/items/moving - PinLock
/// Requires no response to client, only server change
/// Handle /client/game/profile/items/moving - PinLock
/// Requires no response to client, only server change
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Pin/Lock request data</param>
@@ -147,7 +148,7 @@ public class InventoryController(
}
/// <summary>
/// Handle /client/game/profile/items/moving SetFavoriteItems
/// Handle /client/game/profile/items/moving SetFavoriteItems
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request"></param>
@@ -160,7 +161,7 @@ public class InventoryController(
}
/// <summary>
/// Handle /client/game/profile/items/moving RedeemProfileReward
/// Handle /client/game/profile/items/moving RedeemProfileReward
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request"></param>
@@ -236,7 +237,7 @@ public class InventoryController(
var desiredArea = pmcData.Hideout.Areas.FirstOrDefault(area => area.Type == hideoutAreaType);
if (desiredArea is not null)
{
desiredArea.Level = (int?)newValue;
desiredArea.Level = (int?) newValue;
}
break;
@@ -250,7 +251,7 @@ public class InventoryController(
}
/// <summary>
/// Flag an item as seen in profiles encyclopedia + add inspect xp to profile
/// Flag an item as seen in profiles encyclopedia + add inspect xp to profile
/// </summary>
/// <param name="itemTpls">Inspected item tpls</param>
/// <param name="fullProfile">Profile to add xp to</param>
@@ -284,8 +285,8 @@ public class InventoryController(
}
/// <summary>
/// Handle OpenRandomLootContainer event
/// Handle event fired when a container is unpacked (e.g. halloween pumpkin)
/// Handle OpenRandomLootContainer event
/// Handle event fired when a container is unpacked (e.g. halloween pumpkin)
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request"></param>
@@ -358,7 +359,7 @@ public class InventoryController(
}
/// <summary>
/// Edit an existing map marker
/// Edit an existing map marker
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Edit marker request</param>
@@ -374,7 +375,7 @@ public class InventoryController(
}
/// <summary>
/// Delete a map marker
/// Delete a map marker
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Delete marker request</param>
@@ -399,7 +400,7 @@ public class InventoryController(
}
/// <summary>
/// Add note to a map
/// Add note to a map
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Add marker request</param>
@@ -434,7 +435,7 @@ public class InventoryController(
}
/// <summary>
/// Flag item as 'seen' by player in profile
/// Flag item as 'seen' by player in profile
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request"></param>
@@ -452,7 +453,7 @@ public class InventoryController(
}
/// <summary>
/// Handle examining an item
/// Handle examining an item
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Examine item request</param>
@@ -501,7 +502,7 @@ public class InventoryController(
}
/// <summary>
/// Get the tplid of an item from the examine request object
/// Get the tplid of an item from the examine request object
/// </summary>
/// <param name="request"></param>
/// <param name="sessionId">Session/Player id</param>
@@ -583,8 +584,8 @@ public class InventoryController(
}
/// <summary>
/// Unbind an inventory item from quick access menu at bottom of player screen
/// Handle unbind event
/// Unbind an inventory item from quick access menu at bottom of player screen
/// Handle unbind event
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request"></param>
@@ -600,8 +601,8 @@ public class InventoryController(
}
/// <summary>
/// Handle bind event
/// Bind an inventory item to the quick access menu at bottom of player screen
/// Handle bind event
/// Bind an inventory item to the quick access menu at bottom of player screen
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="bindRequest"></param>
@@ -621,7 +622,7 @@ public class InventoryController(
}
/// <summary>
/// Add a tag to an inventory item
/// Add a tag to an inventory item
/// </summary>
/// <param name="pmcData">Profile with item to add tag to</param>
/// <param name="request"></param>
@@ -655,7 +656,7 @@ public class InventoryController(
}
/// <summary>
/// Toggles "Toggleable" items like night vision goggles and face shields.
/// Toggles "Toggleable" items like night vision goggles and face shields.
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Toggle request</param>
@@ -697,7 +698,7 @@ public class InventoryController(
}
/// <summary>
/// Handles folding of Weapons
/// Handles folding of Weapons
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Fold item request</param>
@@ -740,9 +741,9 @@ public class InventoryController(
}
/// <summary>
/// Swap Item
/// used for "reload" if you have weapon in hands and magazine is somewhere else in rig or backpack in equipment
/// Also used to swap items using quick selection on character screen
/// Swap Item
/// used for "reload" if you have weapon in hands and magazine is somewhere else in rig or backpack in equipment
/// Also used to swap items using quick selection on character screen
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Swap item request</param>
@@ -819,9 +820,9 @@ public class InventoryController(
}
/// <summary>
/// TODO: Adds no data to output to send to client, is this by design?
/// Transfer items from one stack into another while keeping original stack
/// Used to take items from scav inventory into stash or to insert ammo into mags (shotgun ones) and reloading weapon by clicking "Reload"
/// TODO: Adds no data to output to send to client, is this by design?
/// Transfer items from one stack into another while keeping original stack
/// Used to take items from scav inventory into stash or to insert ammo into mags (shotgun ones) and reloading weapon by clicking "Reload"
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Transfer item request</param>
@@ -882,8 +883,8 @@ public class InventoryController(
}
/// <summary>
/// Fully merge 2 inventory stacks together into one stack (merging where both stacks remain is called 'transfer')
/// Deletes item from `body.item` and adding number of stacks into `body.with`
/// Fully merge 2 inventory stacks together into one stack (merging where both stacks remain is called 'transfer')
/// Deletes item from `body.item` and adding number of stacks into `body.with`
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Merge stacks request</param>
@@ -973,7 +974,7 @@ public class InventoryController(
}
/// <summary>
/// Split Item stack - 1 stack into 2
/// Split Item stack - 1 stack into 2
/// </summary>
/// <param name="pmcData">(unused, getOwnerInventoryItems() gets profile)</param>
/// <param name="request">Split stack request</param>
@@ -1037,8 +1038,8 @@ public class InventoryController(
}
/// <summary>
/// Implements "Discard" functionality from Main menu (Stash etc.)
/// Removes item from PMC Profile
/// Implements "Discard" functionality from Main menu (Stash etc.)
/// Removes item from PMC Profile
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Discard item request</param>
@@ -1,3 +1,5 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Common.Extensions;
using SPTarkov.Server.Core.Context;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -9,8 +11,6 @@ using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
using SPTarkov.Common.Extensions;
using Info = SPTarkov.Server.Core.Models.Eft.Profile.Info;
namespace SPTarkov.Server.Core.Controllers;
@@ -33,7 +33,7 @@ public class LauncherController(
protected CoreConfig _coreConfig = _configServer.GetConfig<CoreConfig>();
/// <summary>
/// Handle launcher connecting to server
/// Handle launcher connecting to server
/// </summary>
/// <returns>ConnectResponse</returns>
public ConnectResponse Connect()
@@ -56,7 +56,7 @@ public class LauncherController(
}
/// <summary>
/// Get descriptive text for each of the profile editions a player can choose, keyed by profile.json profile type e.g. "Edge Of Darkness"
/// Get descriptive text for each of the profile editions a player can choose, keyed by profile.json profile type e.g. "Edge Of Darkness"
/// </summary>
/// <returns>Dictionary of profile types with related descriptive text</returns>
protected Dictionary<string, string> GetProfileDescriptions()
@@ -80,7 +80,6 @@ public class LauncherController(
}
/// <summary>
///
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <returns></returns>
@@ -90,7 +89,6 @@ public class LauncherController(
}
/// <summary>
///
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
@@ -109,7 +107,6 @@ public class LauncherController(
}
/// <summary>
///
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
@@ -127,7 +124,6 @@ public class LauncherController(
}
/// <summary>
///
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
@@ -154,7 +150,6 @@ public class LauncherController(
}
/// <summary>
///
/// </summary>
/// <returns></returns>
protected string GenerateProfileId()
@@ -165,7 +160,6 @@ public class LauncherController(
}
/// <summary>
///
/// </summary>
/// <param name="timeStamp"></param>
/// <param name="counter"></param>
@@ -179,7 +173,6 @@ public class LauncherController(
}
/// <summary>
///
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
@@ -196,7 +189,6 @@ public class LauncherController(
}
/// <summary>
///
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
@@ -213,7 +205,7 @@ public class LauncherController(
}
/// <summary>
/// Handle launcher requesting profile be wiped
/// Handle launcher requesting profile be wiped
/// </summary>
/// <param name="info">Registration data</param>
/// <returns>Session id</returns>
@@ -237,7 +229,6 @@ public class LauncherController(
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public string GetCompatibleTarkovVersion()
@@ -246,7 +237,7 @@ public class LauncherController(
}
/// <summary>
/// Get the mods the server has currently loaded
/// Get the mods the server has currently loaded
/// </summary>
/// <returns>Dictionary of mod name and mod details</returns>
public Dictionary<string, PackageJsonData> GetLoadedServerMods()
@@ -263,7 +254,7 @@ public class LauncherController(
}
/// <summary>
/// Get the mods a profile has ever loaded into game with
/// Get the mods a profile has ever loaded into game with
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <returns>Array of mod details</returns>
@@ -280,7 +271,6 @@ public class LauncherController(
}
/// <summary>
///
/// </summary>
/// <param name="profileMods"></param>
/// <returns></returns>
@@ -1,3 +1,6 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Common.Extensions;
using SPTarkov.Server.Core.Context;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Launcher;
using SPTarkov.Server.Core.Models.Eft.Profile;
@@ -7,9 +10,6 @@ using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
using SPTarkov.Common.Extensions;
using SPTarkov.Server.Core.Context;
using Info = SPTarkov.Server.Core.Models.Eft.Profile.Info;
namespace SPTarkov.Server.Core.Controllers;
@@ -1,10 +1,10 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Location;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Context;
using SPTarkov.Server.Core.Models.Eft.Match;
using SPTarkov.Server.Core.Models.Spt.Config;
@@ -5,7 +6,6 @@ using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
using static SPTarkov.Server.Core.Services.MatchLocationService;
namespace SPTarkov.Server.Core.Controllers;
@@ -25,7 +25,7 @@ public class MatchController(
protected PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
/// <summary>
/// Handle client/match/available
/// Handle client/match/available
/// </summary>
/// <returns>True if server should be available</returns>
public bool GetEnabled()
@@ -1,8 +1,8 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Models.Eft.Notes;
using SPTarkov.Server.Core.Routers;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -1,8 +1,8 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Notifier;
using SPTarkov.Server.Core.Models.Eft.Ws;
using SPTarkov.Server.Core.Services;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -25,7 +25,8 @@ public class NotifierController(
/// <param name="sessionId">Session/Player id</param>
public Task<List<WsNotificationEvent>> NotifyAsync(string sessionId)
{
return Task.Factory.StartNew(() => {
return Task.Factory.StartNew(() =>
{
// keep track of our timeout
var counter = 0;
@@ -67,7 +68,7 @@ public class NotifierController(
}
/// <summary>
/// Get the notifier server url
/// Get the notifier server url
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <returns>Notification server url</returns>
@@ -1,8 +1,8 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Spt.Presets;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Services;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -33,7 +33,10 @@ public class PresetController(
// Get root items tpl
var tpl = preset.Items.FirstOrDefault()?.Template;
result.TryAdd(tpl, new PresetCacheDetails{PresetIds = [] });
result.TryAdd(tpl, new PresetCacheDetails
{
PresetIds = []
});
result.TryGetValue(tpl, out var details);
details.PresetIds.Add(presetId);
@@ -1,12 +1,11 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Prestige;
using SPTarkov.Server.Core.Models.Eft.Profile;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -20,7 +19,7 @@ public class PrestigeController(
{
/// <summary>
/// Handle /client/prestige/list
/// Get a collection of all possible prestiges
/// Get a collection of all possible prestiges
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <returns>Prestige</returns>
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -11,7 +12,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -38,7 +38,7 @@ public class ProfileController(
)
{
/// <summary>
/// Handle /launcher/profiles
/// Handle /launcher/profiles
/// </summary>
/// <returns></returns>
public virtual List<MiniProfile> GetMiniProfiles()
@@ -47,7 +47,7 @@ public class ProfileController(
}
/// <summary>
/// Handle launcher/profile/info
/// Handle launcher/profile/info
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <returns></returns>
@@ -102,7 +102,7 @@ public class ProfileController(
}
/// <summary>
/// Handle client/game/profile/list
/// Handle client/game/profile/list
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <returns>Return a full profile, scav and pmc profiles + meta data</returns>
@@ -112,7 +112,7 @@ public class ProfileController(
}
/// <summary>
/// Handle client/game/profile/create
/// Handle client/game/profile/create
/// </summary>
/// <param name="request">Create profile request</param>
/// <param name="sessionID">Player id</param>
@@ -123,8 +123,8 @@ public class ProfileController(
}
/// <summary>
/// Generate a player scav object
/// PMC profile MUST exist first before player-scav can be generated
/// Generate a player scav object
/// PMC profile MUST exist first before player-scav can be generated
/// </summary>
/// <param name="sessionID">Player id</param>
/// <returns>PmcData</returns>
@@ -134,7 +134,7 @@ public class ProfileController(
}
/// <summary>
/// Handle client/game/profile/nickname/validate
/// Handle client/game/profile/nickname/validate
/// </summary>
/// <param name="request">Validate nickname request</param>
/// <param name="sessionID">Session/Player id</param>
@@ -155,8 +155,8 @@ public class ProfileController(
}
/// <summary>
/// Handle client/game/profile/nickname/change event
/// Client allows player to adjust their profile name
/// Handle client/game/profile/nickname/change event
/// Client allows player to adjust their profile name
/// </summary>
/// <param name="request">Change nickname request</param>
/// <param name="sessionID">Player id</param>
@@ -183,7 +183,7 @@ public class ProfileController(
}
/// <summary>
/// Handle client/game/profile/voice/change event
/// Handle client/game/profile/voice/change event
/// </summary>
/// <param name="request">Change voice request</param>
/// <param name="sessionID">Player id</param>
@@ -194,7 +194,7 @@ public class ProfileController(
}
/// <summary>
/// Handle client/game/profile/search
/// Handle client/game/profile/search
/// </summary>
/// <param name="request">Search profiles request</param>
/// <param name="sessionID">Player id</param>
@@ -221,7 +221,7 @@ public class ProfileController(
}
/// <summary>
/// Handle client/profile/status
/// Handle client/profile/status
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <returns></returns>
@@ -258,7 +258,7 @@ public class ProfileController(
}
/// <summary>
/// Handle client/profile/view
/// Handle client/profile/view
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="request">Get other profile request</param>
@@ -345,7 +345,7 @@ public class ProfileController(
}
/// <summary>
/// Handle client/profile/settings
/// Handle client/profile/settings
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="request">Get profile settings request</param>
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -11,7 +12,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
@@ -39,13 +39,13 @@ public class QuestController(
ICloner _cloner
)
{
protected QuestConfig _questConfig = _configServer.GetConfig<QuestConfig>();
protected static readonly List<string> _questTypes = ["PickUp", "Exploration", "Elimination"];
protected QuestConfig _questConfig = _configServer.GetConfig<QuestConfig>();
/// <summary>
/// Handle client/quest/list
/// Get all quests visible to player
/// Exclude quests with incomplete preconditions (level/loyalty)
/// Handle client/quest/list
/// Get all quests visible to player
/// Exclude quests with incomplete preconditions (level/loyalty)
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <returns>Collection of Quest</returns>
@@ -55,10 +55,10 @@ public class QuestController(
}
/// <summary>
/// Handle QuestAccept event
/// Handle the client accepting a quest and starting it
/// Send starting rewards if any to player and
/// Send start notification if any to player
/// Handle QuestAccept event
/// Handle the client accepting a quest and starting it
/// Send starting rewards if any to player and
/// Send start notification if any to player
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="acceptedQuest">Quest accepted</param>
@@ -131,7 +131,7 @@ public class QuestController(
}
/// <summary>
/// Add a quests condition counters to chosen profile
/// Add a quests condition counters to chosen profile
/// </summary>
/// <param name="questConditions">Conditions to iterate over and possibly add to profile</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -163,10 +163,10 @@ public class QuestController(
}
/// <summary>
/// TODO: Move this code into RepeatableQuestController
/// Handle the client accepting a repeatable quest and starting it
/// Send starting rewards if any to player and
/// Send start notification if any to player
/// TODO: Move this code into RepeatableQuestController
/// Handle the client accepting a repeatable quest and starting it
/// Send starting rewards if any to player and
/// Send start notification if any to player
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="acceptedQuest">Repeatable quest accepted</param>
@@ -211,7 +211,7 @@ public class QuestController(
}
/// <summary>
/// Look for an accepted quest inside player profile, return quest that matches
/// Look for an accepted quest inside player profile, return quest that matches
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="questId">Quest id to return</param>
@@ -238,10 +238,10 @@ public class QuestController(
}
/// <summary>
/// Handle QuestComplete event
/// Update completed quest in profile
/// Add newly unlocked quests to profile
/// Also recalculate their level due to exp rewards
/// Handle QuestComplete event
/// Update completed quest in profile
/// Add newly unlocked quests to profile
/// Also recalculate their level due to exp rewards
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Complete quest request</param>
@@ -253,8 +253,8 @@ public class QuestController(
}
/// <summary>
/// Handle QuestHandover event
/// Player hands over an item to trader to complete/partially complete quest
/// Handle QuestHandover event
/// Player hands over an item to trader to complete/partially complete quest
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Handover request</param>
@@ -407,7 +407,7 @@ public class QuestController(
}
/// <summary>
/// Show warning to user and write to log that repeatable quest failed a condition check
/// Show warning to user and write to log that repeatable quest failed a condition check
/// </summary>
/// <param name="questId">Quest id that failed</param>
/// <param name="conditionId">Relevant condition id that failed</param>
@@ -419,8 +419,8 @@ public class QuestController(
"repeatable-quest_handover_failed_condition_invalid",
new
{
questId = questId,
conditionId = conditionId
questId,
conditionId
}
);
_logger.Error(errorMessage);
@@ -429,7 +429,7 @@ public class QuestController(
}
/// <summary>
/// Show warning to user and write to log quest item handed over did not match what is required
/// Show warning to user and write to log quest item handed over did not match what is required
/// </summary>
/// <param name="handoverQuestRequest">Handover request</param>
/// <param name="itemHandedOver">Non-matching item found</param>
@@ -454,8 +454,8 @@ public class QuestController(
}
/// <summary>
/// Increment a backend counter stored value by an amount
/// Create counter if it does not exist
/// Increment a backend counter stored value by an amount
/// Create counter if it does not exist
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="conditionId">Backend counter id to update</param>
@@ -480,7 +480,7 @@ public class QuestController(
}
/// <summary>
/// Handle /client/game/profile/items/moving - QuestFail
/// Handle /client/game/profile/items/moving - QuestFail
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="request">Fail quest request</param>
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
@@ -14,7 +15,6 @@ using SPTarkov.Server.Core.Routers;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Controllers;
@@ -105,7 +105,7 @@ public class RagfairController
}
/// <summary>
/// Check all profiles and sell player offers / send player money for listing if it sold
/// Check all profiles and sell player offers / send player money for listing if it sold
/// </summary>
public void Update()
{
@@ -124,7 +124,7 @@ public class RagfairController
}
/// <summary>
/// Handles client/ragfair/find
/// Handles client/ragfair/find
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <param name="searchRequest">Search request data</param>
@@ -188,7 +188,7 @@ public class RagfairController
}
/// <summary>
/// Adjust ragfair offer stack count to match same value as traders assort stack count
/// Adjust ragfair offer stack count to match same value as traders assort stack count
/// </summary>
/// <param name="offer">Flea offer to adjust stack size of</param>
private void SetTraderOfferStackSize(RagfairOffer offer)
@@ -217,7 +217,7 @@ public class RagfairController
}
/// <summary>
/// Update a trader flea offer with buy restrictions stored in the traders assort
/// Update a trader flea offer with buy restrictions stored in the traders assort
/// </summary>
/// <param name="offer">Flea offer to update</param>
/// <param name="fullProfile">Players full profile</param>
@@ -256,7 +256,7 @@ public class RagfairController
}
/// <summary>
/// Add index to all offers passed in (0-indexed)
/// Add index to all offers passed in (0-indexed)
/// </summary>
/// <param name="offers">Offers to add index value to</param>
protected void AddIndexValueToOffers(List<RagfairOffer> offers)
@@ -270,7 +270,7 @@ public class RagfairController
}
/// <summary>
/// Get categories for the type of search being performed, linked/required/all
/// Get categories for the type of search being performed, linked/required/all
/// </summary>
/// <param name="pmcProfile"></param>
/// <param name="searchRequest">Client search request data</param>
@@ -307,7 +307,7 @@ public class RagfairController
}
/// <summary>
/// Is the flea search being performed a 'linked' search type
/// Is the flea search being performed a 'linked' search type
/// </summary>
/// <param name="searchRequest">Search request</param>
/// <returns>True = a 'linked' search type</returns>
@@ -317,7 +317,7 @@ public class RagfairController
}
/// <summary>
/// Is the flea search being performed a 'required' search type
/// Is the flea search being performed a 'required' search type
/// </summary>
/// <param name="searchRequest">Search request</param>
/// <returns>True if it is a 'required' search type</returns>
@@ -327,7 +327,7 @@ public class RagfairController
}
/// <summary>
/// Get offers for the client based on type of search being performed
/// Get offers for the client based on type of search being performed
/// </summary>
/// <param name="searchRequest">Client search request data</param>
/// <param name="itemsToAdd">Comes from ragfairHelper.filterCategories()</param>
@@ -354,7 +354,7 @@ public class RagfairController
}
/// <summary>
/// Called when creating an offer on flea, fills values in top right corner
/// Called when creating an offer on flea, fills values in top right corner
/// </summary>
/// <param name="getPriceRequest">Client request object</param>
/// <param name="ignoreTraderOffers">OPTIONAL - Should trader offers be ignored in the calculation</param>
@@ -445,7 +445,7 @@ public class RagfairController
}
/// <summary>
/// List item(s) on flea for sale
/// List item(s) on flea for sale
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="offerRequest">Flea list creation offer</param>
@@ -488,7 +488,7 @@ public class RagfairController
}
/// <summary>
/// Is the item to be listed on the flea valid
/// Is the item to be listed on the flea valid
/// </summary>
/// <param name="offerRequest">Client offer request</param>
/// <returns>Is offer valid</returns>
@@ -512,7 +512,7 @@ public class RagfairController
}
/// <summary>
/// Given a client request, determine what type of offer is being created single/multi/pack
/// Given a client request, determine what type of offer is being created single/multi/pack
/// </summary>
/// <param name="offerRequest">Client request</param>
/// <returns>FleaOfferType</returns>
@@ -542,9 +542,9 @@ public class RagfairController
}
/// <summary>
/// Create a flea offer for multiples of the same item, can be single items or items with multiple in the stack
/// e.g. 2 ammo stacks of 30 cartridges each
/// Each item can be purchased individually
/// Create a flea offer for multiples of the same item, can be single items or items with multiple in the stack
/// e.g. 2 ammo stacks of 30 cartridges each
/// Each item can be purchased individually
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <param name="offerRequest">Offer request from client</param>
@@ -652,9 +652,9 @@ public class RagfairController
}
/// <summary>
/// Create a flea offer for multiple items, can be single items or items with multiple in the stack
/// e.g. 2 ammo stacks of 30 cartridges each
/// The entire package must be purchased in one go
/// Create a flea offer for multiple items, can be single items or items with multiple in the stack
/// e.g. 2 ammo stacks of 30 cartridges each
/// The entire package must be purchased in one go
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <param name="offerRequest">Offer request from client</param>
@@ -762,8 +762,8 @@ public class RagfairController
}
/// <summary>
/// Create a flea offer for a single item - includes an item with > 1 sized stack
/// e.g. 1 ammo stack of 30 cartridges
/// Create a flea offer for a single item - includes an item with > 1 sized stack
/// e.g. 1 ammo stack of 30 cartridges
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <param name="offerRequest">Offer request from client</param>
@@ -859,7 +859,7 @@ public class RagfairController
}
/// <summary>
/// Charge player a listing fee for using flea, pulls charge from data previously sent by client
/// Charge player a listing fee for using flea, pulls charge from data previously sent by client
/// </summary>
/// <param name="sessionId"></param>
/// <param name="rootItem">Base item being listed (used when client tax cost not found and must be done on server)</param>
@@ -913,7 +913,7 @@ public class RagfairController
}
/// <summary>
/// Create a flea offer for a player
/// Create a flea offer for a player
/// </summary>
/// <param name="sessionId">Session/Player id</param>
/// <param name="requirements"></param>
@@ -924,8 +924,7 @@ public class RagfairController
bool sellInOnePiece)
{
const int loyalLevel = 1;
var formattedItems = items.Select(
item =>
var formattedItems = items.Select(item =>
{
var isChild = items.Any(subItem => subItem.Id == item.ParentId);
@@ -940,8 +939,7 @@ public class RagfairController
}
);
var formattedRequirements = requirements.Select(
item => new BarterScheme
var formattedRequirements = requirements.Select(item => new BarterScheme
{
Template = item.Template,
Count = item.Count,
@@ -955,13 +953,13 @@ public class RagfairController
formattedItems.ToList(),
formattedRequirements.ToList(),
loyalLevel,
(int?)items.FirstOrDefault()?.Upd?.StackObjectsCount ?? 1,
(int?) items.FirstOrDefault()?.Upd?.StackObjectsCount ?? 1,
sellInOnePiece
);
}
/// <summary>
/// Get the handbook price in roubles for the items being listed
/// Get the handbook price in roubles for the items being listed
/// </summary>
/// <param name="requirements"></param>
/// <returns>Rouble price</returns>
@@ -982,7 +980,7 @@ public class RagfairController
}
/// <summary>
/// Find items with their children from players inventory
/// Find items with their children from players inventory
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="itemIdsFromFleaOfferRequest">Request</param>
@@ -1038,8 +1036,8 @@ public class RagfairController
}
/// <summary>
/// Flag an offer as being ready for removal - sets expiry for very near future
/// Will be picked up by update() once expiry time has passed
/// Flag an offer as being ready for removal - sets expiry for very near future
/// Will be picked up by update() once expiry time has passed
/// </summary>
/// <param name="offerId">Id of offer to remove</param>
/// <param name="sessionId">Session id of requesting player</param>
@@ -1058,7 +1056,7 @@ public class RagfairController
new
{
profileId = sessionId,
offerId = offerId
offerId
}
)
);
@@ -1074,7 +1072,7 @@ public class RagfairController
"ragfair-offer_not_found_in_profile",
new
{
offerId = offerId
offerId
}
)
);
@@ -1098,7 +1096,7 @@ public class RagfairController
}
/// <summary>
/// Extend a flea offers active time
/// Extend a flea offers active time
/// </summary>
/// <param name="extendRequest">Extend time request</param>
/// <param name="sessionId">Session/Player id</param>
@@ -1167,7 +1165,7 @@ public class RagfairController
}
/// <summary>
/// Create a basic trader request object with price and currency type
/// Create a basic trader request object with price and currency type
/// </summary>
/// <param name="currency">What currency: RUB, EURO, USD</param>
/// <param name="value">Amount of currency</param>
@@ -1194,7 +1192,7 @@ public class RagfairController
}
/// <summary>
/// Get prices for all items on flea
/// Get prices for all items on flea
/// </summary>
/// <returns>Dictionary of tpl and item price</returns>
public Dictionary<string, double> GetAllFleaPrices()
@@ -1,9 +1,9 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Models.Eft.Repair;
using SPTarkov.Server.Core.Routers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -16,7 +17,6 @@ using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
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;
namespace SPTarkov.Server.Core.Controllers;
@@ -44,7 +44,7 @@ public class RepeatableQuestController(
protected QuestConfig _questConfig = _configServer.GetConfig<QuestConfig>();
/// <summary>
/// Handle RepeatableQuestChange event
/// Handle RepeatableQuestChange event
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="changeRequest">Change quest request</param>
@@ -77,8 +77,7 @@ public class RepeatableQuestController(
var replacedQuestTraderId = questToReplace.TraderId;
// Update active quests to exclude the quest we're replacing
repeatablesOfTypeInProfile.ActiveQuests = repeatablesOfTypeInProfile.ActiveQuests.Where(
quest => quest.Id != changeRequest.QuestId
repeatablesOfTypeInProfile.ActiveQuests = repeatablesOfTypeInProfile.ActiveQuests.Where(quest => quest.Id != changeRequest.QuestId
)
.ToList();
@@ -91,8 +90,7 @@ public class RepeatableQuestController(
repeatablesOfTypeInProfile.ChangeRequirement.Remove(changeRequest.QuestId);
// Get config for this repeatable sub-type (daily/weekly/scav)
var repeatableConfig = _questConfig.RepeatableQuests.FirstOrDefault(
config => config.Name == repeatablesOfTypeInProfile.Name
var repeatableConfig = _questConfig.RepeatableQuests.FirstOrDefault(config => config.Name == repeatablesOfTypeInProfile.Name
);
// If the configuration dictates to replace with the same quest type, adjust the available quest types
@@ -183,9 +181,8 @@ public class RepeatableQuestController(
}
/// <summary>
/// Some accounts have access to free repeatable quest refreshes
/// Track the usage of them inside players profile
///
/// Some accounts have access to free repeatable quest refreshes
/// Track the usage of them inside players profile
/// </summary>
/// <param name="fullProfile">Full player profile</param>
/// <param name="repeatableSubType">Can be daily / weekly / scav repeatable</param>
@@ -227,7 +224,7 @@ public class RepeatableQuestController(
}
/// <summary>
/// Clean up the repeatables `changeRequirement` dictionary of expired data
/// Clean up the repeatables `changeRequirement` dictionary of expired data
/// </summary>
/// <param name="repeatablesOfTypeInProfile">repeatables that have the replaced and new quest</param>
/// <param name="replacedQuestId">Id of the replaced quest</param>
@@ -248,7 +245,7 @@ public class RepeatableQuestController(
}
/// <summary>
/// Generate a repeatable quest
/// Generate a repeatable quest
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -289,7 +286,7 @@ public class RepeatableQuestController(
}
/// <summary>
/// Remove the provided quest from pmc and scav character profiles
/// Remove the provided quest from pmc and scav character profiles
/// </summary>
/// <param name="fullProfile">Profile to remove quest from</param>
/// <param name="questToReplaceId">Quest id to remove from profile</param>
@@ -309,8 +306,7 @@ public class RepeatableQuestController(
}
/// <summary>
/// Find a repeatable (daily/weekly/scav) from a players profile by its id
///
/// Find a repeatable (daily/weekly/scav) from a players profile by its id
/// </summary>
/// <param name="questId">Id of quest to find</param>
/// <param name="pmcData">Profile that contains quests to look through</param>
@@ -339,25 +335,23 @@ public class RepeatableQuestController(
}
/// <summary>
/// Handle client/repeatalbeQuests/activityPeriods
/// Returns an array of objects in the format of repeatable quests to the client.
/// repeatableQuestObject = {
/// *id: Unique Id,
///name: "Daily",
///endTime: the time when the quests expire
///activeQuests: currently available quests in an array. Each element of quest type format(see assets/ database / templates / repeatableQuests.json).
///inactiveQuests: the quests which were previously active(required by client to fail them if they are not completed)
/// }
///
/// The method checks if the player level requirement for repeatable quests(e.g.daily lvl5, weekly lvl15) is met and if the previously active quests
/// are still valid.This ischecked by endTime persisted in profile accordning to the resetTime configured for each repeatable kind(daily, weekly)
/// in QuestCondig.js
///
/// If the condition is met, new repeatableQuests are created, old quests(which are persisted in the profile.RepeatableQuests[i].activeQuests) are
/// moved to profile.RepeatableQuests[i].inactiveQuests.This memory is required to get rid of old repeatable quest data in the profile, otherwise
/// they'll litter the profile's Quests field.
/// (if the are on "Succeed" but not "Completed" we keep them, to allow the player to complete them and get the rewards)
/// The new quests generated are again persisted in profile.RepeatableQuests
/// Handle client/repeatalbeQuests/activityPeriods
/// Returns an array of objects in the format of repeatable quests to the client.
/// repeatableQuestObject = {
/// *id: Unique Id,
/// name: "Daily",
/// endTime: the time when the quests expire
/// activeQuests: currently available quests in an array. Each element of quest type format(see assets/ database / templates / repeatableQuests.json).
/// inactiveQuests: the quests which were previously active(required by client to fail them if they are not completed)
/// }
/// The method checks if the player level requirement for repeatable quests(e.g.daily lvl5, weekly lvl15) is met and if the previously active quests
/// are still valid.This ischecked by endTime persisted in profile accordning to the resetTime configured for each repeatable kind(daily, weekly)
/// in QuestCondig.js
/// If the condition is met, new repeatableQuests are created, old quests(which are persisted in the profile.RepeatableQuests[i].activeQuests) are
/// moved to profile.RepeatableQuests[i].inactiveQuests.This memory is required to get rid of old repeatable quest data in the profile, otherwise
/// they'll litter the profile's Quests field.
/// (if the are on "Succeed" but not "Completed" we keep them, to allow the player to complete them and get the rewards)
/// The new quests generated are again persisted in profile.RepeatableQuests
/// </summary>
/// <param name="sessionID">Session/Player id</param>
/// <returns>Array of repeatable quests</returns>
@@ -491,7 +485,7 @@ public class RepeatableQuestController(
}
/// <summary>
/// Get repeatable quest data from profile from name (daily/weekly), creates base repeatable quest object if none exists
/// Get repeatable quest data from profile from name (daily/weekly), creates base repeatable quest object if none exists
/// </summary>
/// <param name="repeatableConfig">daily/weekly config</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -500,8 +494,7 @@ public class RepeatableQuestController(
PmcData pmcData)
{
// Get from profile, add if missing
var repeatableQuestDetails = pmcData.RepeatableQuests.FirstOrDefault(
repeatable => repeatable.Name == repeatableConfig.Name
var repeatableQuestDetails = pmcData.RepeatableQuests.FirstOrDefault(repeatable => repeatable.Name == repeatableConfig.Name
);
var hasAccess = _profileHelper.HasAccessToRepeatableFreeRefreshSystem(pmcData);
@@ -535,7 +528,7 @@ public class RepeatableQuestController(
}
/// <summary>
/// Check if a repeatable quest type (daily/weekly) is active for the given profile
/// Check if a repeatable quest type (daily/weekly) is active for the given profile
/// </summary>
/// <param name="repeatableConfig">Repeatable quest config</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -563,7 +556,7 @@ public class RepeatableQuestController(
}
/// <summary>
/// Does player have daily pmc quests unlocked
/// Does player have daily pmc quests unlocked
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <param name="repeatableConfig">Config of daily type to check</param>
@@ -574,7 +567,7 @@ public class RepeatableQuestController(
}
/// <summary>
/// Does player have daily scav quests unlocked
/// Does player have daily scav quests unlocked
/// </summary>
/// <param name="pmcData">Players PMC profile</param>
/// <returns>True if unlocked</returns>
@@ -586,7 +579,7 @@ public class RepeatableQuestController(
}
/// <summary>
/// Expire quests and replace expired quests with ready-to-hand-in quests inside generatedRepeatables.activeQuests
/// Expire quests and replace expired quests with ready-to-hand-in quests inside generatedRepeatables.activeQuests
/// </summary>
/// <param name="generatedRepeatables">Repeatables to process (daily/weekly)</param>
/// <param name="pmcData">Players PMC profile</param>
@@ -629,9 +622,9 @@ public class RepeatableQuestController(
}
/// <summary>
/// Used to create a quest pool during each cycle of repeatable quest generation. The pool will be subsequently
/// narrowed down during quest generation to avoid duplicate quests. Like duplicate extractions or elimination quests
/// where you have to e.g. kill scavs in same locations
/// Used to create a quest pool during each cycle of repeatable quest generation. The pool will be subsequently
/// narrowed down during quest generation to avoid duplicate quests. Like duplicate extractions or elimination quests
/// where you have to e.g. kill scavs in same locations
/// </summary>
/// <param name="repeatableConfig">main repeatable quest config</param>
/// <param name="pmcLevel">Players level</param>
@@ -680,8 +673,7 @@ public class RepeatableQuestController(
var allowedLocations =
targetKvP.Key == "Savage"
? possibleLocations.Where(
location => location != ELocationName.laboratory
? possibleLocations.Where(location => location != ELocationName.laboratory
) // Exclude labs for Savage targets.
: possibleLocations;
@@ -696,7 +688,7 @@ public class RepeatableQuestController(
}
/// <summary>
/// Create a pool of quests to generate quests from
/// Create a pool of quests to generate quests from
/// </summary>
/// <param name="repeatableConfig">Main repeatable config</param>
/// <returns>QuestTypePool</returns>
@@ -724,7 +716,7 @@ public class RepeatableQuestController(
}
/// <summary>
/// Get a dictionary of map locations the player can access based on their current level
/// Get a dictionary of map locations the player can access based on their current level
/// </summary>
/// <param name="locations"></param>
/// <param name="pmcLevel"></param>
@@ -754,7 +746,7 @@ public class RepeatableQuestController(
}
/// <summary>
/// Return true if the given pmcLevel is allowed on the given location
/// Return true if the given pmcLevel is allowed on the given location
/// </summary>
/// <param name="location">location name to check</param>
/// <param name="pmcLevel">level of the pmc</param>
@@ -792,7 +784,8 @@ public class RepeatableQuestController(
}
// Add elite bonus to daily quests
if (string.Equals(repeatableConfig.Name, "daily", StringComparison.OrdinalIgnoreCase) && _profileHelper.HasEliteSkillLevel(SkillTypes.Charisma, fullProfile.CharacterData.PmcData))
if (string.Equals(repeatableConfig.Name, "daily", StringComparison.OrdinalIgnoreCase) &&
_profileHelper.HasEliteSkillLevel(SkillTypes.Charisma, fullProfile.CharacterData.PmcData))
// Elite charisma skill gives extra daily quest(s)
{
questCount += _databaseService
@@ -807,7 +800,7 @@ public class RepeatableQuestController(
}
// Add any extra repeatable quests the profile has unlocked
questCount += (int)fullProfile.SptData.ExtraRepeatableQuests.GetValueOrDefault(repeatableConfig.Id, 0);
questCount += (int) fullProfile.SptData.ExtraRepeatableQuests.GetValueOrDefault(repeatableConfig.Id, 0);
return questCount;
}
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -11,7 +12,6 @@ using SPTarkov.Server.Core.Routers;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Controllers;
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -9,7 +10,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -73,8 +73,8 @@ public class TraderController(
}
/// <summary>
/// Adjust trader item prices based on config value multiplier
/// only applies to items sold for currency
/// Adjust trader item prices based on config value multiplier
/// only applies to items sold for currency
/// </summary>
/// <param name="trader">Trader to adjust prices of</param>
/// <param name="multiplier">Coef to apply to traders' items' prices</param>
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Weather;
@@ -7,7 +8,6 @@ using SPTarkov.Server.Core.Models.Spt.Weather;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -1,8 +1,8 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
using SPTarkov.Server.Core.Models.Eft.Wishlist;
using SPTarkov.Server.Core.Routers;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Controllers;
@@ -1,4 +1,5 @@
using System.Collections.Frozen;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -12,7 +13,6 @@ using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
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;
namespace SPTarkov.Server.Core.Generators;
@@ -40,7 +40,6 @@ public class BotEquipmentModGenerator(
ICloner _cloner
)
{
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected static readonly FrozenSet<string> _modSightIds = ["mod_sight_front", "mod_sight_rear"];
// Slots that hold scopes
@@ -63,12 +62,15 @@ public class BotEquipmentModGenerator(
// Slots that hold cartridges
protected static readonly FrozenSet<string> _cartridgeHolderSlots =
[
"mod_magazine",
"patron_in_weapon",
"patron_in_weapon_000",
"patron_in_weapon_001",
"cartridges"];
[
"mod_magazine",
"patron_in_weapon",
"patron_in_weapon_000",
"patron_in_weapon_001",
"cartridges"
];
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
/// <summary>
/// Check mods are compatible and add to array
@@ -272,10 +274,9 @@ public class BotEquipmentModGenerator(
}
// Get the front/back/side weights based on bots level
var plateSlotWeights = settings.BotEquipmentConfig?.ArmorPlateWeighting.FirstOrDefault(
armorWeight =>
settings.BotData.Level >= armorWeight.LevelRange.Min &&
settings.BotData.Level <= armorWeight.LevelRange.Max
var plateSlotWeights = settings.BotEquipmentConfig?.ArmorPlateWeighting.FirstOrDefault(armorWeight =>
settings.BotData.Level >= armorWeight.LevelRange.Min &&
settings.BotData.Level <= armorWeight.LevelRange.Max
);
if (plateSlotWeights is null)
@@ -390,14 +391,13 @@ public class BotEquipmentModGenerator(
}
/// <summary>
/// Gets the minimum and maximum plate class levels from an array of plates
/// Gets the minimum and maximum plate class levels from an array of plates
/// </summary>
/// <param name="platePool">Pool of plates to sort by armorClass to get min and max</param>
/// <returns>MinMax of armorClass from plate pool</returns>
protected static MinMax<int> GetMinMaxArmorPlateClass(List<TemplateItem> platePool)
{
platePool.Sort(
(x, y) =>
platePool.Sort((x, y) =>
{
if (x.Properties.ArmorClass < y.Properties.ArmorClass)
{
@@ -421,7 +421,7 @@ public class BotEquipmentModGenerator(
}
/// <summary>
/// Get the default plate an armor has in its db item
/// Get the default plate an armor has in its db item
/// </summary>
/// <param name="armorItem">Item to look up default plate</param>
/// <param name="modSlot">front/back</param>
@@ -434,7 +434,7 @@ public class BotEquipmentModGenerator(
}
/// <summary>
/// Get the matching armor slot from the default preset matching passed in armor tpl
/// Get the matching armor slot from the default preset matching passed in armor tpl
/// </summary>
/// <param name="armorItemTpl"></param>
/// <param name="modSlot"></param>
@@ -733,7 +733,7 @@ public class BotEquipmentModGenerator(
}
/// <summary>
/// Does the passed in db item lack slot cartridges or chambers
/// Does the passed in db item lack slot cartridges or chambers
/// </summary>
/// <param name="item">Item to check</param>
/// <returns>True it lacks cartridges/chamber slots</returns>
@@ -1032,9 +1032,8 @@ public class BotEquipmentModGenerator(
if ((request.WeaponStats.HasOptic ?? false) && modPool.Count > 1)
{
// Attempt to limit modpool to low profile gas blocks when weapon has an optic
var onlyLowProfileGasBlocks = modPool.Where(
tpl =>
_botConfig.LowProfileGasBlockTpls.Contains(tpl)
var onlyLowProfileGasBlocks = modPool.Where(tpl =>
_botConfig.LowProfileGasBlockTpls.Contains(tpl)
);
if (onlyLowProfileGasBlocks.Any())
{
@@ -1044,8 +1043,7 @@ public class BotEquipmentModGenerator(
else if ((request.WeaponStats.HasRearIronSight ?? false) && modPool.Count > 1)
{
// Attempt to limit modpool to high profile gas blocks when weapon has rear iron sight + no front iron sight
var onlyHighProfileGasBlocks = modPool.Where(
tpl => !_botConfig.LowProfileGasBlockTpls.Contains(tpl)
var onlyHighProfileGasBlocks = modPool.Where(tpl => !_botConfig.LowProfileGasBlockTpls.Contains(tpl)
);
if (onlyHighProfileGasBlocks.Any())
{
@@ -1127,8 +1125,7 @@ public class BotEquipmentModGenerator(
var weaponTpl = modSpawnRequest.Weapon[0].Template;
modSpawnRequest.RandomisationSettings.MinimumMagazineSize.TryGetValue(weaponTpl, out var minMagSizeFromSettings);
var minMagazineSize = minMagSizeFromSettings;
var desiredMagazineTpls = modPool.Where(
magTpl =>
var desiredMagazineTpls = modPool.Where(magTpl =>
{
var magazineDb = _itemHelper.GetItem(magTpl).Value;
return magazineDb.Properties is not null && magazineDb.Properties.Cartridges.FirstOrDefault().MaxCount >= minMagazineSize;
@@ -1236,9 +1233,8 @@ public class BotEquipmentModGenerator(
}
// Check if existing weapon mods are incompatible with chosen item
var existingItemBlockingChoice = weapon.FirstOrDefault(
item =>
pickedItemDetails.Value.Properties.ConflictingItems?.Contains(item.Template) ?? false
var existingItemBlockingChoice = weapon.FirstOrDefault(item =>
pickedItemDetails.Value.Properties.ConflictingItems?.Contains(item.Template) ?? false
);
if (existingItemBlockingChoice is not null)
{
@@ -1326,7 +1322,7 @@ public class BotEquipmentModGenerator(
}
/// <summary>
/// Get a pool of mods from the default weapon preset for passed in weapon
/// Get a pool of mods from the default weapon preset for passed in weapon
/// </summary>
/// <param name="request"></param>
/// <param name="weaponTemplate"></param>
@@ -1360,8 +1356,8 @@ public class BotEquipmentModGenerator(
// Get an array of items that are allowed in slot from parent item
// Check the filter of the slot to ensure a chosen mod fits
var parentSlotCompatibleItems = request.ParentTemplate.Properties.Slots?.FirstOrDefault(
slot => string.Equals(slot.Name.ToLower(), request.ModSlot.ToLower(), StringComparison.Ordinal)
var parentSlotCompatibleItems = request.ParentTemplate.Properties.Slots?.FirstOrDefault(slot =>
string.Equals(slot.Name.ToLower(), request.ModSlot.ToLower(), StringComparison.Ordinal)
)
?.Props.Filters?[0].Filter;
@@ -1413,7 +1409,7 @@ public class BotEquipmentModGenerator(
}
/// <summary>
/// Get Desired item from preset
/// Get Desired item from preset
/// </summary>
/// <param name="request"></param>
/// <param name="weaponTemplate"></param>
@@ -1834,20 +1830,17 @@ public class BotEquipmentModGenerator(
// Check to see if mount has a scope slot (only include primary slot, ignore the rest like the backup sight slots)
// Should only find 1 as there's currently no items with a mod_scope AND a mod_scope_000
HashSet<string> filter = ["mod_scope", "mod_scope_000"];
var scopeSlot = itemDetails.Properties.Slots.Where(
slot =>
filter.Contains(slot.Name)
var scopeSlot = itemDetails.Properties.Slots.Where(slot =>
filter.Contains(slot.Name)
);
// Mods scope slot found must allow ALL whitelisted scope types OR be a mount
if (scopeSlot?.All(
slot =>
slot.Props.Filters[0]
.Filter.All(
tpl =>
_itemHelper.IsOfBaseclasses(tpl, whitelistedSightTypes) ||
_itemHelper.IsOfBaseclass(tpl, BaseClasses.MOUNT)
)
if (scopeSlot?.All(slot =>
slot.Props.Filters[0]
.Filter.All(tpl =>
_itemHelper.IsOfBaseclasses(tpl, whitelistedSightTypes) ||
_itemHelper.IsOfBaseclass(tpl, BaseClasses.MOUNT)
)
) ??
false)
// Add mod to allowed list
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -10,7 +11,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
using BodyPart = SPTarkov.Server.Core.Models.Eft.Common.Tables.BodyPart;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
@@ -509,7 +509,7 @@ public class BotGenerator(
Health = new CurrentMinMax
{
Current = _randomUtil.GetDouble(bodyParts.Head.Min, bodyParts.Head.Max),
Maximum = (double) Math.Round(bodyParts.Head.Max)
Maximum = Math.Round(bodyParts.Head.Max)
}
}
},
@@ -519,7 +519,7 @@ public class BotGenerator(
Health = new CurrentMinMax
{
Current = _randomUtil.GetDouble(bodyParts.Chest.Min, bodyParts.Chest.Max),
Maximum = (double) Math.Round(bodyParts.Chest.Max)
Maximum = Math.Round(bodyParts.Chest.Max)
}
}
},
@@ -1,4 +1,5 @@
using System.Collections.Frozen;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Context;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -10,7 +11,6 @@ using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Generators;
@@ -37,8 +37,6 @@ public class BotInventoryGenerator(
ConfigServer _configServer
)
{
private readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
// Slots handled individually inside `GenerateAndAddEquipmentToBot`
private static readonly FrozenSet<EquipmentSlots> _excludedEquipmentSlots =
[
@@ -53,6 +51,8 @@ public class BotInventoryGenerator(
EquipmentSlots.Earpiece
];
private readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
private readonly HashSet<string> _slotsToCheck = [EquipmentSlots.Pockets.ToString(), EquipmentSlots.SecuredContainer.ToString()];
/// <summary>
@@ -386,7 +386,7 @@ public class BotInventoryGenerator(
}
/// <summary>
/// Get RootEquipmentPool id based on game version
/// Get RootEquipmentPool id based on game version
/// </summary>
/// <param name="chosenGameVersion"></param>
/// <param name="templateInventory"></param>
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Bot;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -5,7 +6,6 @@ using SPTarkov.Server.Core.Models.Spt.Bots;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Generators;
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
@@ -8,7 +9,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Generators;
@@ -337,8 +337,7 @@ public class BotLootGenerator(
return null;
}
var matchingValue = _pmcConfig?.LootItemLimitsRub?.FirstOrDefault(
minMaxValue => botLevel >= minMaxValue.Min && botLevel <= minMaxValue.Max
var matchingValue = _pmcConfig?.LootItemLimitsRub?.FirstOrDefault(minMaxValue => botLevel >= minMaxValue.Min && botLevel <= minMaxValue.Max
);
return matchingValue;
@@ -358,14 +357,13 @@ public class BotLootGenerator(
return 0;
}
var matchingValue = _pmcConfig.MaxBackpackLootTotalRub.FirstOrDefault(
minMaxValue => botLevel >= minMaxValue.Min && botLevel <= minMaxValue.Max
var matchingValue = _pmcConfig.MaxBackpackLootTotalRub.FirstOrDefault(minMaxValue => botLevel >= minMaxValue.Min && botLevel <= minMaxValue.Max
);
return matchingValue?.Value;
}
/// <summary>
/// Get an array of the containers a bot has on them (pockets/backpack/vest)
/// Get an array of the containers a bot has on them (pockets/backpack/vest)
/// </summary>
/// <param name="botInventory">Bot to check</param>
/// <returns>Array of available slots</returns>
@@ -595,7 +593,7 @@ public class BotLootGenerator(
}
/// <summary>
/// Adds loot to the specified Wallet
/// Adds loot to the specified Wallet
/// </summary>
/// <param name="walletId"> Wallet to add loot to</param>
/// <returns>Generated list of currency stacks with the wallet as their parent</returns>
@@ -605,19 +603,19 @@ public class BotLootGenerator(
// Choose how many stacks of currency will be added to wallet
var itemCount = _randomUtil.GetInt(
(int) _botConfig.WalletLoot.ItemCount.Min,
(int) _botConfig.WalletLoot.ItemCount.Max
_botConfig.WalletLoot.ItemCount.Min,
_botConfig.WalletLoot.ItemCount.Max
);
for (var index = 0; index < itemCount; index++)
{
// Choose the size of the currency stack - default is 5k, 10k, 15k, 20k, 25k
var chosenStackCount = _weightedRandomHelper.GetWeightedValue<string>(_botConfig.WalletLoot.StackSizeWeight);
var chosenStackCount = _weightedRandomHelper.GetWeightedValue(_botConfig.WalletLoot.StackSizeWeight);
List<Item> items =
[
new()
{
Id = _hashUtil.Generate(),
Template = _weightedRandomHelper.GetWeightedValue<string>(_botConfig.WalletLoot.CurrencyWeight),
Template = _weightedRandomHelper.GetWeightedValue(_botConfig.WalletLoot.CurrencyWeight),
ParentId = walletId,
Upd = new Upd
{
@@ -693,8 +691,8 @@ public class BotLootGenerator(
]
);
var randomisedWeaponCount = _randomUtil.GetInt(
(int) _pmcConfig.LooseWeaponInBackpackLootMinMax.Min,
(int) _pmcConfig.LooseWeaponInBackpackLootMinMax.Max
_pmcConfig.LooseWeaponInBackpackLootMinMax.Min,
_pmcConfig.LooseWeaponInBackpackLootMinMax.Max
);
if (randomisedWeaponCount <= 0)
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Generators.WeaponGen;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -10,7 +11,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Generators;
@@ -200,7 +200,7 @@ public class BotWeaponGenerator(
// Add cartridge(s) to gun chamber(s)
if (weaponItemTemplate.Properties?.Chambers?.Count > 0 &&
weaponItemTemplate.Properties.Chambers[0].Props.Filters[0].Filter.Contains(ammoTpl))
weaponItemTemplate.Properties.Chambers[0].Props.Filters[0].Filter.Contains(ammoTpl))
{
// Guns have variety of possible Chamber ids, patron_in_weapon/patron_in_weapon_000/patron_in_weapon_001
var chamberSlotNames = weaponItemTemplate.Properties.Chambers.Select(chamberSlot => chamberSlot.Name);
@@ -363,8 +363,7 @@ public class BotWeaponGenerator(
foreach (var modSlotTemplate in modTemplate.Properties.Slots?.Where(slot => slot.Required.GetValueOrDefault(false)) ?? [])
{
var slotName = modSlotTemplate.Name;
var hasWeaponSlotItem = weaponItemList.Any(
weaponItem => weaponItem.ParentId == mod.Id && weaponItem.SlotId == slotName
var hasWeaponSlotItem = weaponItemList.Any(weaponItem => weaponItem.ParentId == mod.Id && weaponItem.SlotId == slotName
);
if (!hasWeaponSlotItem)
{
@@ -639,7 +638,8 @@ public class BotWeaponGenerator(
var magazineCaliberData = _itemHelper.GetItem(compatibleCartridgesInMagazine.FirstOrDefault()).Value.Properties.Caliber;
cartridgePoolForWeapon = cartridgePool[magazineCaliberData];
foreach (var cartridgeKvP in cartridgePoolForWeapon) {
foreach (var cartridgeKvP in cartridgePoolForWeapon)
{
if (compatibleCartridgesInMagazine.Contains(cartridgeKvP.Key))
{
compatibleCartridges[cartridgeKvP.Key] = cartridgeKvP.Value;
@@ -676,12 +676,13 @@ public class BotWeaponGenerator(
}
/// <summary>
/// Get the cartridge ids from a weapon's magazine template that work with the weapon
/// Get the cartridge ids from a weapon's magazine template that work with the weapon
/// </summary>
/// <param name="weaponTemplate">Weapon db template to get magazine cartridges for</param>
/// <returns>Hashset of cartridge tpls</returns>
/// <exception cref="ArgumentNullException">Thrown when weaponTemplate is null.</exception>
protected HashSet<string> GetCompatibleCartridgesFromMagazineTemplate(TemplateItem weaponTemplate) {
protected HashSet<string> GetCompatibleCartridgesFromMagazineTemplate(TemplateItem weaponTemplate)
{
ArgumentNullException.ThrowIfNull(weaponTemplate);
// Get the first magazine's template from the weapon
@@ -801,8 +802,7 @@ public class BotWeaponGenerator(
/// <param name="magazineTemplate">Magazines db template</param>
protected void AddOrUpdateMagazinesChildWithAmmo(List<Item> weaponWithMods, Item magazine, string chosenAmmoTpl, TemplateItem magazineTemplate)
{
var magazineCartridgeChildItem = weaponWithMods.FirstOrDefault(
m => m.ParentId == magazine.Id && m.SlotId == "cartridges"
var magazineCartridgeChildItem = weaponWithMods.FirstOrDefault(m => m.ParentId == magazine.Id && m.SlotId == "cartridges"
);
if (magazineCartridgeChildItem is not null)
{
@@ -824,6 +824,7 @@ public class BotWeaponGenerator(
return;
}
weaponWithMods.RemoveAt(magazineIndex);
// Insert new mag at same index position original was
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
@@ -7,7 +8,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Generators;
@@ -30,7 +30,7 @@ public class FenceBaseAssortGenerator(
protected TraderConfig traderConfig = configServer.GetConfig<TraderConfig>();
/// <summary>
/// Create base fence assorts dynamically and store in memory
/// Create base fence assorts dynamically and store in memory
/// </summary>
public void GenerateFenceBaseAssorts()
{
@@ -201,7 +201,7 @@ public class FenceBaseAssortGenerator(
}
/// <summary>
/// Check ammo in boxes + loose ammos has a penetration value above the configured value in trader.json / ammoMaxPenLimit
/// Check ammo in boxes + loose ammos has a penetration value above the configured value in trader.json / ammoMaxPenLimit
/// </summary>
/// <param name="rootItemDb"> Ammo box or ammo item from items.db </param>
/// <returns>True if penetration value is above limit set in config</returns>
@@ -218,7 +218,7 @@ public class FenceBaseAssortGenerator(
}
/// <summary>
/// Get the penetration power value of an ammo, works with ammo boxes and raw ammos
/// Get the penetration power value of an ammo, works with ammo boxes and raw ammos
/// </summary>
/// <param name="rootItemDb"> Ammo box or ammo item from items.db </param>
/// <returns> Penetration power of passed in item, undefined if it doesnt have a power </returns>
@@ -251,7 +251,7 @@ public class FenceBaseAssortGenerator(
}
/// <summary>
/// Add soft inserts + armor plates to an armor
/// Add soft inserts + armor plates to an armor
/// </summary>
/// <param name="armor"> Armor item array to add mods into </param>
/// <param name="itemDbDetails">Armor items db template</param>
@@ -337,7 +337,7 @@ public class FenceBaseAssortGenerator(
}
/// <summary>
/// Check if item is valid for being added to fence assorts
/// Check if item is valid for being added to fence assorts
/// </summary>
/// <param name="item"> Item to check </param>
/// <returns> True if valid fence item </returns>
@@ -1,5 +1,5 @@
using System.Reflection.Metadata.Ecma335;
using System.Text.Json.Serialization;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -11,7 +11,6 @@ using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
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;
namespace SPTarkov.Server.Core.Generators;
@@ -84,8 +83,7 @@ public class LocationLootGenerator(
// Remove christmas items from loot data
if (!_seasonalEventService.ChristmasEventEnabled())
{
allStaticContainersOnMapClone = allStaticContainersOnMapClone.Where(
item => !_seasonalEventConfig.ChristmasContainerIds.Contains(item.Template.Id)
allStaticContainersOnMapClone = allStaticContainersOnMapClone.Where(item => !_seasonalEventConfig.ChristmasContainerIds.Contains(item.Template.Id)
)
.ToList();
}
@@ -121,7 +119,7 @@ public class LocationLootGenerator(
// Randomisation is turned off globally or just turned off for this map
if (!_locationConfig.ContainerRandomisationSettings.Enabled || !_locationConfig.ContainerRandomisationSettings.Maps.ContainsKey(locationId)
)
)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
{
@@ -207,8 +205,7 @@ public class LocationLootGenerator(
foreach (var chosenContainerId in chosenContainerIds)
{
// Look up container object from full list of containers on map
var containerObject = staticRandomisableContainersOnMap.FirstOrDefault(
staticContainer => staticContainer.Template.Id == chosenContainerId
var containerObject = staticRandomisableContainersOnMap.FirstOrDefault(staticContainer => staticContainer.Template.Id == chosenContainerId
);
if (containerObject is null)
{
@@ -253,13 +250,12 @@ public class LocationLootGenerator(
/// <returns>StaticContainerData array</returns>
protected List<StaticContainerData> GetRandomisableContainersOnMap(List<StaticContainerData> staticContainers)
{
return staticContainers.Where(
staticContainer =>
staticContainer.Probability != 1 &&
!staticContainer.Template.IsAlwaysSpawn.GetValueOrDefault(false) &&
!_locationConfig.ContainerRandomisationSettings.ContainerTypesToNotRandomise.Contains(
staticContainer.Template.Items[0].Template
)
return staticContainers.Where(staticContainer =>
staticContainer.Probability != 1 &&
!staticContainer.Template.IsAlwaysSpawn.GetValueOrDefault(false) &&
!_locationConfig.ContainerRandomisationSettings.ContainerTypesToNotRandomise.Contains(
staticContainer.Template.Items[0].Template
)
)
.ToList();
}
@@ -271,13 +267,12 @@ public class LocationLootGenerator(
/// <returns>IStaticContainerData array</returns>
protected List<StaticContainerData> GetGuaranteedContainers(List<StaticContainerData> staticContainersOnMap)
{
return staticContainersOnMap.Where(
staticContainer =>
staticContainer.Probability == 1 ||
staticContainer.Template.IsAlwaysSpawn.GetValueOrDefault(false) ||
_locationConfig.ContainerRandomisationSettings.ContainerTypesToNotRandomise.Contains(
staticContainer.Template.Items[0].Template
)
return staticContainersOnMap.Where(staticContainer =>
staticContainer.Probability == 1 ||
staticContainer.Template.IsAlwaysSpawn.GetValueOrDefault(false) ||
_locationConfig.ContainerRandomisationSettings.ContainerTypesToNotRandomise.Contains(
staticContainer.Template.Items[0].Template
)
)
.ToList();
}
@@ -519,7 +514,7 @@ public class LocationLootGenerator(
}
/// <summary>
/// Get the height/width of an item including its children
/// Get the height/width of an item including its children
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
@@ -691,12 +686,12 @@ public class LocationLootGenerator(
// Remove christmas items from loot data
if (!_seasonalEventService.ChristmasEventEnabled())
{
dynamicLootDist.Spawnpoints = dynamicLootDist.Spawnpoints.Where(
point => !point.Template.Id.StartsWith("christmas", StringComparison.OrdinalIgnoreCase)
dynamicLootDist.Spawnpoints = dynamicLootDist.Spawnpoints.Where(point =>
!point.Template.Id.StartsWith("christmas", StringComparison.OrdinalIgnoreCase)
)
.ToList();
dynamicLootDist.SpawnpointsForced = dynamicLootDist.SpawnpointsForced.Where(
point => !point.Template.Id.StartsWith("christmas", StringComparison.OrdinalIgnoreCase)
dynamicLootDist.SpawnpointsForced = dynamicLootDist.SpawnpointsForced.Where(point =>
!point.Template.Id.StartsWith("christmas", StringComparison.OrdinalIgnoreCase)
)
.ToList();
}
@@ -809,16 +804,14 @@ public class LocationLootGenerator(
}
// Ensure no blacklisted lootable items are in pool
spawnPoint.Template.Items = spawnPoint.Template.Items.Where(
item => !_itemFilterService.IsLootableItemBlacklisted(item.Template)
spawnPoint.Template.Items = spawnPoint.Template.Items.Where(item => !_itemFilterService.IsLootableItemBlacklisted(item.Template)
)
.ToList();
// Ensure no seasonal items are in pool if not in-season
if (!seasonalEventActive)
{
spawnPoint.Template.Items = spawnPoint.Template.Items.Where(
item => !seasonalItemTplBlacklist.Contains(item.Template)
spawnPoint.Template.Items = spawnPoint.Template.Items.Where(item => !seasonalItemTplBlacklist.Contains(item.Template)
)
.ToList();
}
@@ -897,8 +890,7 @@ public class LocationLootGenerator(
foreach (var itemTpl in lootToForceSingleAmountOnMap)
{
// Get all spawn positions for item tpl in forced loot array
var items = forcedSpawnPoints.Where(
forcedSpawnPoint => forcedSpawnPoint.Template.Items[0].Template == itemTpl
var items = forcedSpawnPoints.Where(forcedSpawnPoint => forcedSpawnPoint.Template.Items[0].Template == itemTpl
);
if (items is null || !items.Any())
{
@@ -975,8 +967,7 @@ public class LocationLootGenerator(
forcedLootLocation.Template.Items = createItemResult.Items;
// Push forced location into array as long as it doesnt exist already
var existingLocation = lootLocationTemplates.Any(
spawnPoint => spawnPoint.Id == locationTemplateToAdd.Id
var existingLocation = lootLocationTemplates.Any(spawnPoint => spawnPoint.Id == locationTemplateToAdd.Id
);
if (!existingLocation)
{
@@ -993,8 +984,9 @@ public class LocationLootGenerator(
}
}
}
/// <summary>
/// Create array of item (with child items) and return
/// Create array of item (with child items) and return
/// </summary>
/// <param name="chosenComposedKey"> Key we want to look up items for </param>
/// <param name="items"> Location loot Template </param>
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
@@ -10,7 +11,6 @@ using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Generators;
@@ -50,9 +50,8 @@ public class LootGenerator(
{
// Get list of all sealed containers from db - they're all the same, just for flavor
var itemsDb = _itemHelper.GetItems();
var sealedWeaponContainerPool = itemsDb.Where(
item =>
item.Name.Contains("event_container_airdrop")
var sealedWeaponContainerPool = itemsDb.Where(item =>
item.Name.Contains("event_container_airdrop")
);
for (var index = 0; index < sealedWeaponCrateCount; index++)
@@ -106,9 +105,8 @@ public class LootGenerator(
);
if (randomisedWeaponPresetCount > 0)
{
var weaponDefaultPresets = globalDefaultPresets.Where(
preset =>
_itemHelper.IsOfBaseclass(preset.Encyclopedia, BaseClasses.WEAPON)
var weaponDefaultPresets = globalDefaultPresets.Where(preset =>
_itemHelper.IsOfBaseclass(preset.Encyclopedia, BaseClasses.WEAPON)
)
.ToList();
@@ -139,13 +137,11 @@ public class LootGenerator(
);
if (randomisedArmorPresetCount > 0)
{
var armorDefaultPresets = globalDefaultPresets.Where(
preset =>
_itemHelper.ArmorItemCanHoldMods(preset.Encyclopedia)
var armorDefaultPresets = globalDefaultPresets.Where(preset =>
_itemHelper.ArmorItemCanHoldMods(preset.Encyclopedia)
);
var levelFilteredArmorPresets = armorDefaultPresets.Where(
armor =>
IsArmorOfDesiredProtectionLevel(armor, options)
var levelFilteredArmorPresets = armorDefaultPresets.Where(armor =>
IsArmorOfDesiredProtectionLevel(armor, options)
)
.ToList();
@@ -252,12 +248,11 @@ public class LootGenerator(
itemBlacklist.UnionWith(_seasonalEventService.GetInactiveSeasonalEventItems());
}
var items = itemsDb.Where(
item =>
!itemBlacklist.Contains(item.Id) &&
string.Equals(item.Type, "item", StringComparison.OrdinalIgnoreCase) &&
!item.Properties.QuestItem.GetValueOrDefault(false) &&
itemTypeWhitelist.Contains(item.Parent)
var items = itemsDb.Where(item =>
!itemBlacklist.Contains(item.Id) &&
string.Equals(item.Type, "item", StringComparison.OrdinalIgnoreCase) &&
!item.Properties.QuestItem.GetValueOrDefault(false) &&
itemTypeWhitelist.Contains(item.Parent)
)
.ToList();
@@ -487,7 +482,7 @@ public class LootGenerator(
List<List<Item>> itemsToReturn = [];
// Choose a weapon to give to the player (weighted)
var chosenWeaponTpl = _weightedRandomHelper.GetWeightedValue<string>(
var chosenWeaponTpl = _weightedRandomHelper.GetWeightedValue(
containerSettings.WeaponRewardWeight
);
@@ -558,8 +553,7 @@ public class LootGenerator(
if (rewardKey == BaseClasses.AMMO_BOX)
{
// Get ammo boxes from db
var ammoBoxesDetails = containerSettings.AmmoBoxWhitelist.Select(
tpl =>
var ammoBoxesDetails = containerSettings.AmmoBoxWhitelist.Select(tpl =>
{
var itemDetails = _itemHelper.GetItem(tpl);
return itemDetails.Value;
@@ -568,9 +562,8 @@ public class LootGenerator(
// Need to find boxes that matches weapons caliber
var weaponCaliber = weaponDetailsDb.Properties.AmmoCaliber;
var ammoBoxesMatchingCaliber = ammoBoxesDetails.Where(
x =>
x.Properties.AmmoCaliber == weaponCaliber
var ammoBoxesMatchingCaliber = ammoBoxesDetails.Where(x =>
x.Properties.AmmoCaliber == weaponCaliber
);
if (!ammoBoxesMatchingCaliber.Any())
{
@@ -602,13 +595,12 @@ public class LootGenerator(
// Get all items of the desired type + not quest items + not globally blacklisted
var rewardItemPool = _databaseService.GetItems()
.Values.Where(
item =>
item.Parent == rewardKey &&
string.Equals(item.Type, "item", StringComparison.OrdinalIgnoreCase) &&
_itemFilterService.IsItemBlacklisted(item.Id) &&
!(containerSettings.AllowBossItems || _itemFilterService.IsBossItem(item.Id)) &&
item.Properties.QuestItem is null
.Values.Where(item =>
item.Parent == rewardKey &&
string.Equals(item.Type, "item", StringComparison.OrdinalIgnoreCase) &&
_itemFilterService.IsItemBlacklisted(item.Id) &&
!(containerSettings.AllowBossItems || _itemFilterService.IsBossItem(item.Id)) &&
item.Properties.QuestItem is null
);
if (!rewardItemPool.Any())
@@ -664,8 +656,7 @@ public class LootGenerator(
}
// Get items that fulfil reward type criteria from items that fit on gun
var relatedItems = linkedItemsToWeapon?.Where(
item => item?.Parent == rewardKey && !_itemFilterService.IsItemBlacklisted(item.Id)
var relatedItems = linkedItemsToWeapon?.Where(item => item?.Parent == rewardKey && !_itemFilterService.IsItemBlacklisted(item.Id)
);
if (relatedItems is null || !relatedItems.Any())
{
@@ -719,7 +710,7 @@ public class LootGenerator(
var preset = _presetHelper.GetDefaultPreset(chosenRewardItemTpl);
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
List<Item> presetAndMods = _itemHelper.ReplaceIDs(preset.Items);
var presetAndMods = _itemHelper.ReplaceIDs(preset.Items);
_itemHelper.RemapRootItemId(presetAndMods);
itemsToReturn.Add(presetAndMods);
@@ -755,8 +746,7 @@ public class LootGenerator(
return _randomUtil.GetArrayValue(
GetItemRewardPool([], rewardContainerDetails.RewardTypePool, true, true, false)
.ItemPool.Select(
item => item.Id
.ItemPool.Select(item => item.Id
)
);
}
@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
@@ -6,7 +7,6 @@ using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Generators;
@@ -63,19 +63,19 @@ public class PMCLootGenerator
_pocketLootPool = new ConcurrentDictionary<string, double>();
var items = _databaseService.GetItems();
var pmcPriceOverrides =
_databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items.Pockets;
_databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items
.Pockets;
var allowedItemTypeWhitelist = _pmcConfig.PocketLoot.Whitelist;
var blacklist = GetLootBlacklist();
var itemsToAdd = items.Where(
item =>
allowedItemTypeWhitelist.Contains(item.Value.Parent) &&
_itemHelper.IsValidItem(item.Value.Id) &&
!blacklist.Contains(item.Value.Id) &&
!blacklist.Contains(item.Value.Parent) &&
ItemFitsInto1By2Slot(item.Value)
var itemsToAdd = items.Where(item =>
allowedItemTypeWhitelist.Contains(item.Value.Parent) &&
_itemHelper.IsValidItem(item.Value.Id) &&
!blacklist.Contains(item.Value.Id) &&
!blacklist.Contains(item.Value.Parent) &&
ItemFitsInto1By2Slot(item.Value)
).Select(x => x.Key);
foreach (var tpl in itemsToAdd)
@@ -132,19 +132,19 @@ public class PMCLootGenerator
_vestLootPool = new ConcurrentDictionary<string, double>();
var items = _databaseService.GetItems();
var pmcPriceOverrides =
_databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items.TacticalVest;
_databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items
.TacticalVest;
var allowedItemTypeWhitelist = _pmcConfig.VestLoot.Whitelist;
var blacklist = GetLootBlacklist();
var itemsToAdd = items.Where(
item =>
allowedItemTypeWhitelist.Contains(item.Value.Parent) &&
_itemHelper.IsValidItem(item.Value.Id) &&
!blacklist.Contains(item.Value.Id) &&
!blacklist.Contains(item.Value.Parent) &&
ItemFitsInto2By2Slot(item.Value)
var itemsToAdd = items.Where(item =>
allowedItemTypeWhitelist.Contains(item.Value.Parent) &&
_itemHelper.IsValidItem(item.Value.Id) &&
!blacklist.Contains(item.Value.Id) &&
!blacklist.Contains(item.Value.Parent) &&
ItemFitsInto2By2Slot(item.Value)
).Select(x => x.Key);
foreach (var tpl in itemsToAdd)
@@ -215,18 +215,18 @@ public class PMCLootGenerator
_backpackLootPool = new ConcurrentDictionary<string, double>();
var items = _databaseService.GetItems();
var pmcPriceOverrides =
_databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items.Backpack;
_databaseService.GetBots().Types[string.Equals(botRole, "pmcbear", StringComparison.OrdinalIgnoreCase) ? "bear" : "usec"].BotInventory.Items
.Backpack;
var allowedItemTypeWhitelist = _pmcConfig.BackpackLoot.Whitelist;
var blacklist = GetLootBlacklist();
var itemsToAdd = items.Where(
item =>
allowedItemTypeWhitelist.Contains(item.Value.Parent) &&
_itemHelper.IsValidItem(item.Value.Id) &&
!blacklist.Contains(item.Value.Id) &&
!blacklist.Contains(item.Value.Parent)
var itemsToAdd = items.Where(item =>
allowedItemTypeWhitelist.Contains(item.Value.Parent) &&
_itemHelper.IsValidItem(item.Value.Id) &&
!blacklist.Contains(item.Value.Id) &&
!blacklist.Contains(item.Value.Parent)
).Select(x => x.Key);
foreach (var tpl in itemsToAdd)
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -10,7 +11,6 @@ using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Server.Core.Utils.Json;
using SPTarkov.Common.Annotations;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
@@ -1,81 +1,88 @@
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Generators
namespace SPTarkov.Server.Core.Generators;
[Injectable]
public class PmcWaveGenerator
{
[Injectable]
public class PmcWaveGenerator
protected ConfigServer _configServer;
protected DatabaseService _databaseService;
protected ISptLogger<PmcWaveGenerator> _logger;
protected PmcConfig _pmcConfig;
protected RandomUtil _randomUtil;
public PmcWaveGenerator(
ISptLogger<PmcWaveGenerator> _logger,
RandomUtil _randomUtil,
DatabaseService _databaseService,
ConfigServer _configServer
)
{
protected ISptLogger<PmcWaveGenerator> _logger;
protected RandomUtil _randomUtil;
protected DatabaseService _databaseService;
protected ConfigServer _configServer;
protected PmcConfig _pmcConfig;
this._logger = _logger;
this._randomUtil = _randomUtil;
this._databaseService = _databaseService;
this._configServer = _configServer;
_pmcConfig = _configServer.GetConfig<PmcConfig>();
}
public PmcWaveGenerator(
ISptLogger<PmcWaveGenerator> _logger,
RandomUtil _randomUtil,
DatabaseService _databaseService,
ConfigServer _configServer
)
/// <summary>
/// Add a pmc wave to a map
/// </summary>
/// <param name="locationId"> e.g. factory4_day, bigmap </param>
/// <param name="waveToAdd"> Boss wave to add to map </param>
public void AddPmcWaveToLocation(string locationId, BossLocationSpawn waveToAdd)
{
_pmcConfig.CustomPmcWaves[locationId].Add(waveToAdd);
}
/// <summary>
/// Add custom boss and normal waves to all maps found in config/location.json to db
/// </summary>
public void ApplyWaveChangesToAllMaps()
{
foreach (var location in _pmcConfig.CustomPmcWaves)
{
this._logger = _logger;
this._randomUtil = _randomUtil;
this._databaseService = _databaseService;
this._configServer = _configServer;
_pmcConfig = _configServer.GetConfig<PmcConfig>();
}
/// <summary>
/// Add a pmc wave to a map
/// </summary>
/// <param name="locationId"> e.g. factory4_day, bigmap </param>
/// <param name="waveToAdd"> Boss wave to add to map </param>
public void AddPmcWaveToLocation(string locationId, BossLocationSpawn waveToAdd)
{
_pmcConfig.CustomPmcWaves[locationId].Add(waveToAdd);
}
/// <summary>
/// Add custom boss and normal waves to all maps found in config/location.json to db
/// </summary>
public void ApplyWaveChangesToAllMaps() {
foreach (var location in _pmcConfig.CustomPmcWaves) {
ApplyWaveChangesToMapByName(location.Key);
}
}
/// <summary>
/// Add custom boss and normal waves to a map found in config/location.json to db by name
/// </summary>
/// <param name="name"> e.g. factory4_day, bigmap </param>
public void ApplyWaveChangesToMapByName(string name) {
if (!_pmcConfig.CustomPmcWaves.TryGetValue(name, out var pmcWavesToAdd)) {
return;
}
var location = _databaseService.GetLocation(name);
if (location is null) {
return;
}
location.Base.BossLocationSpawn.AddRange(pmcWavesToAdd);
}
/// <summary>
/// Add custom boss and normal waves to a map found in config/location.json to db by LocationBase
/// </summary>
/// <param name="location"> Location Object </param>
public void ApplyWaveChangesToMap(LocationBase location) {
if (!_pmcConfig.CustomPmcWaves.TryGetValue(location.Id.ToLower(), out var pmcWavesToAdd))
{
return;
}
location.BossLocationSpawn.AddRange(pmcWavesToAdd);
ApplyWaveChangesToMapByName(location.Key);
}
}
/// <summary>
/// Add custom boss and normal waves to a map found in config/location.json to db by name
/// </summary>
/// <param name="name"> e.g. factory4_day, bigmap </param>
public void ApplyWaveChangesToMapByName(string name)
{
if (!_pmcConfig.CustomPmcWaves.TryGetValue(name, out var pmcWavesToAdd))
{
return;
}
var location = _databaseService.GetLocation(name);
if (location is null)
{
return;
}
location.Base.BossLocationSpawn.AddRange(pmcWavesToAdd);
}
/// <summary>
/// Add custom boss and normal waves to a map found in config/location.json to db by LocationBase
/// </summary>
/// <param name="location"> Location Object </param>
public void ApplyWaveChangesToMap(LocationBase location)
{
if (!_pmcConfig.CustomPmcWaves.TryGetValue(location.Id.ToLower(), out var pmcWavesToAdd))
{
return;
}
location.BossLocationSpawn.AddRange(pmcWavesToAdd);
}
}
@@ -1,4 +1,5 @@
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
@@ -7,7 +8,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Generators;
@@ -36,8 +36,8 @@ public class RagfairAssortGenerator(
];
/// <summary>
/// Get a list of lists that can be sold on the flea. <br/>
/// Each sub list contains item + children (if any)
/// Get a list of lists that can be sold on the flea. <br />
/// Each sub list contains item + children (if any)
/// </summary>
/// <returns> List with children lists of items </returns>
public List<List<Item>> GetAssortItems()
@@ -51,7 +51,7 @@ public class RagfairAssortGenerator(
}
/// <summary>
/// Check if internal generatedAssortItems list has objects
/// Check if internal generatedAssortItems list has objects
/// </summary>
/// <returns> True if array has objects </returns>
protected bool AssortsAreGenerated()
@@ -60,7 +60,7 @@ public class RagfairAssortGenerator(
}
/// <summary>
/// Generate a list of lists (item + children) the flea can sell
/// Generate a list of lists (item + children) the flea can sell
/// </summary>
/// <returns> List of lists (item + children)</returns>
protected List<List<Item>> GenerateRagfairAssortItems()
@@ -132,8 +132,8 @@ public class RagfairAssortGenerator(
}
/// <summary>
/// Get presets from globals to add to flea. <br/>
/// ragfairConfig.dynamic.showDefaultPresetsOnly decides if it's all presets or just defaults
/// Get presets from globals to add to flea. <br />
/// ragfairConfig.dynamic.showDefaultPresetsOnly decides if it's all presets or just defaults
/// </summary>
/// <returns> List of Preset </returns>
protected List<Preset> GetPresetsToAdd()
@@ -144,7 +144,7 @@ public class RagfairAssortGenerator(
}
/// <summary>
/// Create a base assort item and return it with populated values + 999999 stack count + unlimited count = true
/// Create a base assort item and return it with populated values + 999999 stack count + unlimited count = true
/// </summary>
/// <param name="tplId"> tplid to add to item </param>
/// <param name="id"> id to add to item </param>
@@ -1,4 +1,6 @@
using System.Diagnostics;
using SPTarkov.Common.Annotations;
using SPTarkov.Common.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Ragfair;
@@ -10,8 +12,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
using SPTarkov.Common.Extensions;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Generators;
@@ -44,10 +44,11 @@ public class RagfairOfferGenerator(
/// Internal counter to ensure each offer created has a unique value for its intId property
protected int offerCounter;
protected RagfairConfig ragfairConfig = configServer.GetConfig<RagfairConfig>();
/// <summary>
/// Create a flea offer and store it in the Ragfair server offers array
/// Create a flea offer and store it in the Ragfair server offers array
/// </summary>
/// <param name="userId">Owner of the offer</param>
/// <param name="time">Time offer is listed at</param>
@@ -74,7 +75,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Create an offer object ready to send to ragfairOfferService.addOffer()
/// Create an offer object ready to send to ragfairOfferService.addOffer()
/// </summary>
/// <param name="userId">Owner of the offer</param>
/// <param name="time">Timestamp offer is listed at</param>
@@ -94,8 +95,7 @@ public class RagfairOfferGenerator(
bool isPackOffer = false
)
{
var offerRequirements = barterScheme.Select(
barter =>
var offerRequirements = barterScheme.Select(barter =>
{
var offerRequirement = new OfferRequirement
{
@@ -155,7 +155,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Create the user object stored inside each flea offer object
/// Create the user object stored inside each flea offer object
/// </summary>
/// <param name="userId">User creating the offer</param>
/// <param name="isTrader">Is the user creating the offer a trader</param>
@@ -206,7 +206,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Calculate the offer price that's listed on the flea listing
/// Calculate the offer price that's listed on the flea listing
/// </summary>
/// <param name="offerRequirements"> barter requirements for offer </param>
/// <returns> rouble cost of offer </returns>
@@ -215,16 +215,16 @@ public class RagfairOfferGenerator(
var roublePrice = 0d;
foreach (var requirement in offerRequirements)
{
roublePrice += (paymentHelper.IsMoneyTpl(requirement.Template)
roublePrice += paymentHelper.IsMoneyTpl(requirement.Template)
? Math.Round(CalculateRoublePrice(requirement.Count.Value, requirement.Template))
: ragfairPriceService.GetFleaPriceForItem(requirement.Template) * requirement.Count.Value); // Get flea price for barter offer items
: ragfairPriceService.GetFleaPriceForItem(requirement.Template) * requirement.Count.Value; // Get flea price for barter offer items
}
return roublePrice;
}
/// <summary>
/// Get avatar url from trader table in db
/// Get avatar url from trader table in db
/// </summary>
/// <param name="isTrader"> Is user we're getting avatar for a trader </param>
/// <param name="userId"> Persons id to get avatar of </param>
@@ -240,7 +240,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Convert a count of currency into roubles
/// Convert a count of currency into roubles
/// </summary>
/// <param name="currencyCount"> Amount of currency to convert into roubles </param>
/// <param name="currencyType"> Type of currency (euro/dollar/rouble) </param>
@@ -256,7 +256,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Check userId, if it's a player, return their pmc _id, otherwise return userId parameter
/// Check userId, if it's a player, return their pmc _id, otherwise return userId parameter
/// </summary>
/// <param name="userId"> Users ID to check </param>
/// <returns> Users ID </returns>
@@ -271,7 +271,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Get a flea trading rating for the passed in user
/// Get a flea trading rating for the passed in user
/// </summary>
/// <param name="userId"> User to get flea rating of </param>
/// <returns> Flea rating value </returns>
@@ -290,11 +290,11 @@ public class RagfairOfferGenerator(
}
// Generated pmc offer
return randomUtil.GetDouble((double) ragfairConfig.Dynamic.Rating.Min, (double) ragfairConfig.Dynamic.Rating.Max);
return randomUtil.GetDouble(ragfairConfig.Dynamic.Rating.Min, ragfairConfig.Dynamic.Rating.Max);
}
/// <summary>
/// Is the offers user rating growing
/// Is the offers user rating growing
/// </summary>
/// <param name="userID"> User to check rating of</param>
/// <returns> True if growing </returns>
@@ -318,7 +318,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Get number of section until offer should expire
/// Get number of section until offer should expire
/// </summary>
/// <param name="userID"> ID of the offer owner </param>
/// <param name="time"> Time the offer is posted in seconds </param>
@@ -345,7 +345,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Create multiple offers for items by using a unique list of items we've generated previously
/// Create multiple offers for items by using a unique list of items we've generated previously
/// </summary>
/// <param name="expiredOffers"> Optional, expired offers to regenerate </param>
public void GenerateDynamicOffers(List<List<Item>>? expiredOffers = null)
@@ -368,8 +368,7 @@ public class RagfairOfferGenerator(
foreach (var assortItem in assortItemsToProcess)
{
tasks.Add(
Task.Factory.StartNew(
() =>
Task.Factory.StartNew(() =>
{
CreateOffersFromAssort(assortItem, replacingExpiredOffers, ragfairConfig.Dynamic);
}
@@ -386,7 +385,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Generates offers from an item and it's children on the flea market
/// Generates offers from an item and it's children on the flea market
/// </summary>
/// <param name="assortItemWithChildren"> Item with its children to process into offers </param>
/// <param name="isExpiredOffer"> Is an expired offer </param>
@@ -439,7 +438,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Iterate over an items children and look for plates above desired level and remove them
/// Iterate over an items children and look for plates above desired level and remove them
/// </summary>
/// <param name="presetWithChildren"> Preset to check for plates </param>
/// <param name="plateSettings"> Settings </param>
@@ -483,7 +482,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Create one flea offer for a specific item
/// Create one flea offer for a specific item
/// </summary>
/// <param name="sellerId"> ID of seller</param>
/// <param name="itemWithChildren"> Item to create offer for </param>
@@ -523,9 +522,8 @@ public class RagfairOfferGenerator(
var shouldRemovePlates = randomUtil.GetChance100(armorConfig.RemoveRemovablePlateChance);
if (shouldRemovePlates && itemHelper.ArmorItemHasRemovablePlateSlots(itemWithChildren[0].Template))
{
var offerItemPlatesToRemove = itemWithChildren.Where(
item =>
armorConfig.PlateSlotIdToRemovePool.Contains(item.SlotId?.ToLower())
var offerItemPlatesToRemove = itemWithChildren.Where(item =>
armorConfig.PlateSlotIdToRemovePool.Contains(item.SlotId?.ToLower())
);
// Latest first, to ensure we don't move later items off by 1 each time we remove an item below it
@@ -579,7 +577,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Generate trader offers on flea using the traders assort data
/// Generate trader offers on flea using the traders assort data
/// </summary>
/// <param name="traderID"> Trader to generate offers for </param>
public void GenerateFleaOffersForTrader(string traderID)
@@ -656,7 +654,7 @@ public class RagfairOfferGenerator(
var barterSchemeItems = barterScheme[0];
var loyalLevel = assortsClone.LoyalLevelItems[item.Id];
var offer = CreateAndAddFleaOffer(traderID, time, items, barterSchemeItems, loyalLevel, (int?)item.Upd.StackObjectsCount ?? 1);
var offer = CreateAndAddFleaOffer(traderID, time, items, barterSchemeItems, loyalLevel, (int?) item.Upd.StackObjectsCount ?? 1);
// Refresh complete, reset flag to false
trader.Base.RefreshTraderRagfairOffers = false;
@@ -664,8 +662,8 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Get array of an item with its mods + condition properties (e.g. durability) <br/>
/// Apply randomisation adjustments to condition if item base is found in ragfair.json/dynamic/condition
/// Get array of an item with its mods + condition properties (e.g. durability) <br />
/// Apply randomisation adjustments to condition if item base is found in ragfair.json/dynamic/condition
/// </summary>
/// <param name="userID"> ID of owner of item </param>
/// <param name="itemWithMods"> Item and mods, get condition of first item (only first array item is modified) </param>
@@ -693,7 +691,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Get the relevant condition id if item tpl matches in ragfair.json/condition
/// Get the relevant condition id if item tpl matches in ragfair.json/condition
/// </summary>
/// <param name="tpl"> Item to look for matching condition object</param>
/// <returns> Condition ID </returns>
@@ -713,7 +711,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Alter an items condition based on its item base type
/// Alter an items condition based on its item base type
/// </summary>
/// <param name="conditionSettingsId"> Also the parentID of item being altered </param>
/// <param name="itemWithMods"> Item to adjust condition details of </param>
@@ -727,10 +725,10 @@ public class RagfairOfferGenerator(
var rootItem = itemWithMods[0];
var itemConditionValues = ragfairConfig.Dynamic.Condition[conditionSettingsId];
var maxMultiplier = randomUtil.GetDouble((double) itemConditionValues.Max.Min, (double) itemConditionValues.Max.Min);
var maxMultiplier = randomUtil.GetDouble(itemConditionValues.Max.Min, itemConditionValues.Max.Min);
var currentMultiplier = randomUtil.GetDouble(
(double) itemConditionValues.Current.Min,
(double) itemConditionValues.Current.Max
itemConditionValues.Current.Min,
itemConditionValues.Current.Max
);
// Randomise armor + plates + armor related things
@@ -808,8 +806,8 @@ public class RagfairOfferGenerator(
}
}
///<summary>
/// Adjust an items durability/maxDurability value
/// <summary>
/// Adjust an items durability/maxDurability value
/// </summary>
/// <param name="item"> Item (weapon/armor) to adjust </param>
/// <param name="itemDbDetails"> Item details from DB </param>
@@ -836,7 +834,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Randomise the durability values for an armors plates and soft inserts
/// Randomise the durability values for an armors plates and soft inserts
/// </summary>
/// <param name="armorWithMods"> Armor item with its child mods </param>
/// <param name="currentMultiplier"> Chosen multiplier to use for current durability value </param>
@@ -871,9 +869,9 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Add missing conditions to an item if needed. <br/>
/// Durabiltiy for repairable items. <br/>
/// HpResource for medical items.
/// Add missing conditions to an item if needed. <br />
/// Durabiltiy for repairable items. <br />
/// HpResource for medical items.
/// </summary>
/// <param name="item"> Item to add conditions to </param>
protected void AddMissingConditions(Item item)
@@ -937,7 +935,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Create a barter-based barter scheme, if not possible, fall back to making barter scheme currency based
/// Create a barter-based barter scheme, if not possible, fall back to making barter scheme currency based
/// </summary>
/// <param name="offerItems"> Items for sale in offer </param>
/// <param name="barterConfig"> Barter config from ragfairConfig.Dynamic.barter </param>
@@ -967,13 +965,12 @@ public class RagfairOfferGenerator(
var offerCostVarianceRoubles = desiredItemCostRouble * barterConfig.PriceRangeVariancePercent / 100;
// Dict of items and their flea price (cached on first use)
List<TplWithFleaPrice> itemFleaPrices = GetFleaPricesAsArray();
var itemFleaPrices = GetFleaPricesAsArray();
// Filter possible barters to items that match the price range + not itself
var min = desiredItemCostRouble - offerCostVarianceRoubles;
var max = desiredItemCostRouble + offerCostVarianceRoubles;
var itemsInsidePriceBounds = itemFleaPrices.Where(
itemAndPrice =>
var itemsInsidePriceBounds = itemFleaPrices.Where(itemAndPrice =>
itemAndPrice.Price >= min &&
itemAndPrice.Price <= max &&
!string.Equals(itemAndPrice.Tpl, offerItems[0].Template,
@@ -1001,7 +998,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Get an array of flea prices + item tpl, cached in generator class inside `allowedFleaPriceItemsForBarter`
/// Get an array of flea prices + item tpl, cached in generator class inside `allowedFleaPriceItemsForBarter`
/// </summary>
/// <returns> List with tpl/price values </returns>
protected List<TplWithFleaPrice> GetFleaPricesAsArray()
@@ -1013,8 +1010,7 @@ public class RagfairOfferGenerator(
// Only get prices for items that also exist in items.json
var filteredFleaItems = fleaPrices
.Select(
kvTpl => new TplWithFleaPrice
.Select(kvTpl => new TplWithFleaPrice
{
Tpl = kvTpl.Key,
Price = kvTpl.Value
@@ -1030,7 +1026,7 @@ public class RagfairOfferGenerator(
}
/// <summary>
/// Create a random currency-based barter scheme for an array of items
/// Create a random currency-based barter scheme for an array of items
/// </summary>
/// <param name="offerWithChildren"> Items on offer </param>
/// <param name="isPackOffer"> Is the barter scheme being created for a pack offer </param>
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -11,7 +12,6 @@ using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Server.Core.Utils.Collections;
using SPTarkov.Server.Core.Utils.Json;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Generators;
@@ -236,8 +236,7 @@ public class RepeatableQuestGenerator(
.GetDictionary()
.Select(x => x.Value)
.Where(x => x.Base?.Id != null)
.Select(
x => new
.Select(x => new
{
x.Base.Id,
BossSpawn = x.Base.BossLocationSpawn
@@ -245,8 +244,7 @@ public class RepeatableQuestGenerator(
);
// filter for the current boss to spawn on map
var thisBossSpawns = bossSpawns
.Select(
x => new
.Select(x => new
{
x.Id,
BossSpawn = x.BossSpawn
@@ -283,9 +281,8 @@ public class RepeatableQuestGenerator(
List<string> weaponTypeBlacklist = ["Shotgun", "Pistol"];
weaponCategoryRequirementConfig =
(ProbabilityObjectArray<string, List<string>>) weaponCategoryRequirementConfig
.Where(
category => weaponTypeBlacklist
.Contains(category.Key)
.Where(category => weaponTypeBlacklist
.Contains(category.Key)
);
}
else if (distance < 20)
@@ -294,9 +291,8 @@ public class RepeatableQuestGenerator(
// Filter out far range weapons from close distance requirement
weaponCategoryRequirementConfig =
(ProbabilityObjectArray<string, List<string>>) weaponCategoryRequirementConfig
.Where(
category => weaponTypeBlacklist
.Contains(category.Key)
.Where(category => weaponTypeBlacklist
.Contains(category.Key)
);
}
@@ -383,7 +379,7 @@ public class RepeatableQuestGenerator(
}
/// <summary>
/// Get a number of kills needed to complete elimination quest
/// Get a number of kills needed to complete elimination quest
/// </summary>
/// <param name="targetKey"> Target type desired e.g. anyPmc/bossBully/Savage </param>
/// <param name="targetsConfig"> Config of the target </param>
@@ -541,8 +537,7 @@ public class RepeatableQuestGenerator(
(double) (_mathUtil.Interp1(pmcLevel, levelsConfig, roublesConfig) * multi)
);
roublesBudget = Math.Max(roublesBudget, 5000d);
var itemSelection = possibleItemsToRetrievePool.Where(
x => _itemHelper.GetItemPrice(x.Id) < roublesBudget
var itemSelection = possibleItemsToRetrievePool.Where(x => _itemHelper.GetItemPrice(x.Id) < roublesBudget
)
.ToList();
@@ -557,8 +552,7 @@ public class RepeatableQuestGenerator(
.Where(p => p.MinPlayerLevel <= pmcLevel)
.SelectMany(x => x.ItemIds)
.ToHashSet(); //.Aggregate((a, p) => a.Concat(p.ItemIds), []);
itemSelection = itemSelection.Where(
x =>
itemSelection = itemSelection.Where(x =>
{
// Whitelist can contain item tpls and item base type ids
return itemIdsWhitelisted.Any(v => _itemHelper.IsOfBaseclass(x.Id, v)) ||
@@ -581,8 +575,7 @@ public class RepeatableQuestGenerator(
.SelectMany(x => x.ItemIds)
.ToHashSet(); //.Aggregate(List<ItemsBlacklist> , (a, p) => a.Concat(p.ItemIds) );
itemSelection = itemSelection.Where(
x =>
itemSelection = itemSelection.Where(x =>
{
return itemIdsBlacklisted.All(v => !_itemHelper.IsOfBaseclass(x.Id, v)) ||
!itemIdsBlacklisted.Contains(x.Id);
@@ -831,12 +824,11 @@ public class RepeatableQuestGenerator(
var exitPool = mapExits.Where(exit => exit.Chance > 0).ToList();
// Exclude exits with a requirement to leave (e.g. car extracts)
var possibleExits = exitPool.Where(
exit =>
exit.PassageRequirement is not null ||
repeatableConfig.QuestConfig.Exploration.SpecificExits.PassageRequirementWhitelist.Contains(
"PassageRequirement"
)
var possibleExits = exitPool.Where(exit =>
exit.PassageRequirement is not null ||
repeatableConfig.QuestConfig.Exploration.SpecificExits.PassageRequirementWhitelist.Contains(
"PassageRequirement"
)
)
.ToList();
@@ -906,14 +898,12 @@ public class RepeatableQuestGenerator(
findCondition.Target = new ListOrT<string>([itemTypeToFetchWithCount.ItemType], null);
findCondition.Value = itemCountToFetch;
var counterCreatorCondition = quest.Conditions.AvailableForFinish.FirstOrDefault(
x => x.ConditionType == "CounterCreator"
var counterCreatorCondition = quest.Conditions.AvailableForFinish.FirstOrDefault(x => x.ConditionType == "CounterCreator"
);
// var locationCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Location");
// (locationCondition._props as ILocationConditionProps).target = [...locationTarget];
var equipmentCondition = counterCreatorCondition.Counter.Conditions.FirstOrDefault(
x => x.ConditionType == "Equipment"
var equipmentCondition = counterCreatorCondition.Counter.Conditions.FirstOrDefault(x => x.ConditionType == "Equipment"
);
equipmentCondition.EquipmentInclusive = [[itemTypeToFetchWithCount.ItemType]];
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -10,7 +11,6 @@ using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
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;
namespace SPTarkov.Server.Core.Generators;
@@ -35,21 +35,21 @@ public class RepeatableQuestRewardGenerator(
protected QuestConfig _questConfig = _configServer.GetConfig<QuestConfig>();
/// <summary>
/// Generate the reward for a mission. A reward can consist of: <br/>
/// - Experience <br/>
/// - Money <br/>
/// - GP coins <br/>
/// - Weapon preset <br/>
/// - Items <br/>
/// - Trader Reputation <br/>
/// - Skill level experience <br/>
/// <br/>
/// The reward is dependent on the player level as given by the wiki. The exact mapping of pmcLevel to <br/>
/// experience / money / items / trader reputation can be defined in QuestConfig.js <br/>
/// <br/>
/// There's also a random variation of the reward the spread of which can be also defined in the config <br/>
/// <br/>
/// Additionally, a scaling factor w.r.t. quest difficulty going from 0.2...1 can be used
/// Generate the reward for a mission. A reward can consist of: <br />
/// - Experience <br />
/// - Money <br />
/// - GP coins <br />
/// - Weapon preset <br />
/// - Items <br />
/// - Trader Reputation <br />
/// - Skill level experience <br />
/// <br />
/// The reward is dependent on the player level as given by the wiki. The exact mapping of pmcLevel to <br />
/// experience / money / items / trader reputation can be defined in QuestConfig.js <br />
/// <br />
/// There's also a random variation of the reward the spread of which can be also defined in the config <br />
/// <br />
/// Additionally, a scaling factor w.r.t. quest difficulty going from 0.2...1 can be used
/// </summary>
/// <param name="pmcLevel"> Level of player reward is being generated for </param>
/// <param name="difficulty"> Reward scaling factor from 0.2 to 1 </param>
@@ -110,8 +110,7 @@ public class RepeatableQuestRewardGenerator(
rewardIndex++;
// Add preset weapon to reward if checks pass
var traderWhitelistDetails = repeatableConfig.TraderWhitelist.FirstOrDefault(
traderWhitelist => traderWhitelist.TraderId == traderId
var traderWhitelistDetails = repeatableConfig.TraderWhitelist.FirstOrDefault(traderWhitelist => traderWhitelist.TraderId == traderId
);
if (traderWhitelistDetails?.RewardCanBeWeapon ??
(false && _randomUtil.GetChance100(traderWhitelistDetails.WeaponRewardChancePercent ?? 0))
@@ -132,8 +131,7 @@ public class RepeatableQuestRewardGenerator(
if (rewardTplBlacklist is not null)
{
// Filter reward pool of items from blacklist, only use if there's at least 1 item remaining
var filteredRewardItemPool = inBudgetRewardItemPool.Where(
item => !rewardTplBlacklist.Contains(item.Id)
var filteredRewardItemPool = inBudgetRewardItemPool.Where(item => !rewardTplBlacklist.Contains(item.Id)
);
if (filteredRewardItemPool.Count() > 0)
{
@@ -319,7 +317,7 @@ public class RepeatableQuestRewardGenerator(
}
/// <summary>
/// Get an array of items + stack size to give to player as reward that fit inside a rouble budget.
/// Get an array of items + stack size to give to player as reward that fit inside a rouble budget.
/// </summary>
/// <param name="itemPool"> All possible items to choose rewards from </param>
/// <param name="maxItemCount"> Total number of items to reward </param>
@@ -405,8 +403,8 @@ public class RepeatableQuestRewardGenerator(
}
/// <summary>
/// Get a count of cartridges that fits the rouble budget amount provided.<br/>
/// e.g. how many M80s for 50,000 roubles.
/// Get a count of cartridges that fits the rouble budget amount provided.<br />
/// e.g. how many M80s for 50,000 roubles.
/// </summary>
/// <param name="itemSelected"> Cartridge template </param>
/// <param name="roublesBudget"> Rouble budget </param>
@@ -449,7 +447,7 @@ public class RepeatableQuestRewardGenerator(
}
/// <summary>
/// Get a randomised number a reward items stack size should be based on its handbook price
/// Get a randomised number a reward items stack size should be based on its handbook price
/// </summary>
/// <param name="item"> Reward item to get stack size for </param>
/// <returns> Matching stack size for the passed in items price </returns>
@@ -476,7 +474,7 @@ public class RepeatableQuestRewardGenerator(
}
/// <summary>
/// Select a number of items that have a collective value of the passed in parameter
/// Select a number of items that have a collective value of the passed in parameter
/// </summary>
/// <param name="repeatableConfig"> Config </param>
/// <param name="roublesBudget"> Total value of items to return </param>
@@ -518,7 +516,7 @@ public class RepeatableQuestRewardGenerator(
}
/// <summary>
/// Filters a list of reward Items within a budget.
/// Filters a list of reward Items within a budget.
/// </summary>
/// <param name="rewardItems"> List of reward items to filter </param>
/// <param name="roublesBudget"> The budget remaining for rewards </param>
@@ -527,8 +525,7 @@ public class RepeatableQuestRewardGenerator(
protected List<TemplateItem> FilterRewardPoolWithinBudget(List<TemplateItem> rewardItems, double roublesBudget,
double minPrice)
{
return rewardItems.Where(
item =>
return rewardItems.Where(item =>
{
var itemPrice = _presetHelper.GetDefaultPresetOrItemPrice(item.Id);
return itemPrice < roublesBudget && itemPrice > minPrice;
@@ -538,7 +535,7 @@ public class RepeatableQuestRewardGenerator(
}
/// <summary>
/// Choose a random Weapon preset that fits inside a rouble amount limit
/// Choose a random Weapon preset that fits inside a rouble amount limit
/// </summary>
/// <param name="roublesBudget"> Budget in roubles </param>
/// <param name="rewardIndex"> Index of the reward </param>
@@ -581,7 +578,7 @@ public class RepeatableQuestRewardGenerator(
}
/// <summary>
/// Helper to create a reward item structured as required by the client
/// Helper to create a reward item structured as required by the client
/// </summary>
/// <param name="tpl"> ItemId of the rewarded item </param>
/// <param name="count"> Amount of items to give </param>
@@ -626,7 +623,7 @@ public class RepeatableQuestRewardGenerator(
}
/// <summary>
/// Helper to create a reward item structured as required by the client
/// Helper to create a reward item structured as required by the client
/// </summary>
/// <param name="tpl"> ItemId of the rewarded item </param>
/// <param name="count"> Amount of items to give</param>
@@ -682,11 +679,11 @@ public class RepeatableQuestRewardGenerator(
/// <summary>
/// Picks rewardable items from items.json <br/>
/// This means they must: <br/>
/// - Fit into the inventory <br/>
/// - Shouldn't be keys <br/>
/// - Have a price greater than 0
/// Picks rewardable items from items.json <br />
/// This means they must: <br />
/// - Fit into the inventory <br />
/// - Shouldn't be keys <br />
/// - Have a price greater than 0
/// </summary>
/// <param name="repeatableQuestConfig"> Config </param>
/// <param name="tradderId"> ID of trader who will give reward to player </param>
@@ -700,8 +697,7 @@ public class RepeatableQuestRewardGenerator(
// also check if the price is greater than 0; there are some items whose price can not be found
// those are not in the game yet (e.g. AGS grenade launcher)
return _databaseService.GetItems()
.Values.Where(
itemTemplate =>
.Values.Where(itemTemplate =>
{
// Base "Item" item has no parent, ignore it
if (itemTemplate.Parent == "")
@@ -714,8 +710,7 @@ public class RepeatableQuestRewardGenerator(
return false;
}
var traderWhitelist = repeatableQuestConfig.TraderWhitelist.FirstOrDefault(
trader => trader.TraderId == traderId
var traderWhitelist = repeatableQuestConfig.TraderWhitelist.FirstOrDefault(trader => trader.TraderId == traderId
);
return IsValidRewardItem(
@@ -729,8 +724,8 @@ public class RepeatableQuestRewardGenerator(
}
/// <summary>
/// Checks if an id is a valid item. Valid meaning that it's an item that may be a reward
/// or content of bot loot. Items that are tested as valid may be in a player backpack or stash.
/// Checks if an id is a valid item. Valid meaning that it's an item that may be a reward
/// or content of bot loot. Items that are tested as valid may be in a player backpack or stash.
/// </summary>
/// <param name="tpl"> Template id of item to check</param>
/// <param name="repeatableQuestConfig"> Config </param>
@@ -1,3 +1,5 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Common.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
@@ -10,8 +12,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
using SPTarkov.Common.Extensions;
namespace SPTarkov.Server.Core.Generators;
@@ -97,8 +97,7 @@ public class ScavCaseRewardGenerator(
if (!_dbItemsCache.Any())
{
_dbItemsCache = _databaseService.GetItems()
.Values.Where(
item =>
.Values.Where(item =>
{
// Base "Item" item has no parent, ignore it
if (item.Parent == "")
@@ -157,8 +156,7 @@ public class ScavCaseRewardGenerator(
if (!_dbAmmoItemsCache.Any())
{
_dbAmmoItemsCache = _databaseService.GetItems()
.Values.Where(
item =>
.Values.Where(item =>
{
// Base "Item" item has no parent, ignore it
if (item.Parent == "")
@@ -301,8 +299,7 @@ public class ScavCaseRewardGenerator(
/// <returns>random ammo item from items.json</returns>
protected TemplateItem GetRandomAmmo(string rarity)
{
var possibleAmmoPool = _dbAmmoItemsCache.Where(
ammo =>
var possibleAmmoPool = _dbAmmoItemsCache.Where(ammo =>
{
// Is ammo handbook price between desired range
var handbookPrice = _ragfairPriceService.GetStaticPriceForItem(ammo.Id);
@@ -397,8 +394,7 @@ public class ScavCaseRewardGenerator(
List<TemplateItem> dbItems,
RewardCountAndPriceDetails itemFilters)
{
return dbItems.Where(
item =>
return dbItems.Where(item =>
{
var handbookPrice = _ragfairPriceService.GetStaticPriceForItem(item.Id);
if (handbookPrice >= itemFilters.MinPriceRub && handbookPrice <= itemFilters.MaxPriceRub)
@@ -461,6 +457,7 @@ public class ScavCaseRewardGenerator(
_ => 1
};
}
/// <summary>
/// Randomises the size of ammo stacks
/// </summary>
@@ -473,6 +470,7 @@ public class ScavCaseRewardGenerator(
itemToCalculate.Properties.StackMaxSize ?? 0
);
}
/// <summary>
/// Randomises the size of money stacks
/// </summary>
@@ -1,7 +1,7 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Generators.WeaponGen.Implementations;
@@ -1,10 +1,10 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Generators.WeaponGen.Implementations;
@@ -158,8 +158,9 @@ public class ExternalInventoryMagGen(
}
}
}
/// <summary>
/// Get a random compatible external magazine for a weapon, exclude internal magazines from possible pool
/// Get a random compatible external magazine for a weapon, exclude internal magazines from possible pool
/// </summary>
/// <param name="weaponTpl"> Weapon to get mag for </param>
/// <param name="magazineBlacklist"> Blacklisted magazines </param>
@@ -176,8 +177,7 @@ public class ExternalInventoryMagGen(
// All possible mags that fit into the weapon excluding blacklisted
var magazinePool = magSlot.Props.Filters[0]
.Filter.Where(x => !magazineBlacklist.Contains(x))
.Select(
x => _itemHelper.GetItem(x).Value
.Select(x => _itemHelper.GetItem(x).Value
);
if (magazinePool is null)
{
@@ -1,6 +1,6 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Generators.WeaponGen.Implementations;
@@ -1,6 +1,6 @@
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Generators.WeaponGen.Implementations;
@@ -1,5 +1,5 @@
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Common.Annotations;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
namespace SPTarkov.Server.Core.Generators.WeaponGen;
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Eft.Weather;
using SPTarkov.Server.Core.Models.Enums;
@@ -5,7 +6,6 @@ using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Generators;
@@ -22,7 +22,7 @@ public class WeatherGenerator(
protected WeatherConfig _weatherConfig = _configServer.GetConfig<WeatherConfig>();
/// <summary>
/// Get current + raid datetime and format into correct BSG format.
/// Get current + raid datetime and format into correct BSG format.
/// </summary>
/// <param name="data"> Weather data </param>
/// <returns> WeatherData </returns>
@@ -39,8 +39,8 @@ public class WeatherGenerator(
}
/// <summary>
/// Get server uptime seconds multiplied by a multiplier and add to current time as seconds.
/// Formatted to BSGs requirements
/// Get server uptime seconds multiplied by a multiplier and add to current time as seconds.
/// Formatted to BSGs requirements
/// </summary>
/// <returns>Formatted time as String </returns>
protected string GetBsgFormattedInRaidTime()
@@ -51,7 +51,7 @@ public class WeatherGenerator(
}
/// <summary>
/// Get current time formatted to fit BSGs requirement
/// Get current time formatted to fit BSGs requirement
/// </summary>
/// <param name="date"> Date to format into bsg style </param>
/// <returns> Time formatted in BSG format </returns>
@@ -61,7 +61,7 @@ public class WeatherGenerator(
}
/// <summary>
/// Return randomised Weather data with help of config/weather.json
/// Return randomised Weather data with help of config/weather.json
/// </summary>
/// <param name="currentSeason"> The currently active season </param>
/// <param name="timestamp"> Optional, what timestamp to generate the weather data at, defaults to now when not supplied </param>
@@ -112,7 +112,7 @@ public class WeatherGenerator(
}
/// <summary>
/// Choose a temperature for the raid based on time of day
/// Choose a temperature for the raid based on time of day
/// </summary>
/// <param name="weather"> What season Tarkov is currently in </param>
/// <param name="inRaidTimestamp"> What time is the raid running at </param>
@@ -129,7 +129,7 @@ public class WeatherGenerator(
}
/// <summary>
/// Set Weather date/time/timestamp values to now
/// Set Weather date/time/timestamp values to now
/// </summary>
/// <param name="weather"> Object to update </param>
/// <param name="timestamp"> Optional, timestamp used </param>
@@ -1,10 +1,10 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Helpers;
@@ -18,7 +18,7 @@ public class AssortHelper(
)
{
/// <summary>
/// Remove assorts from a trader that have not been unlocked yet (via player completing corresponding quest)
/// Remove assorts from a trader that have not been unlocked yet (via player completing corresponding quest)
/// </summary>
/// <param name="pmcProfile"></param>
/// <param name="traderId">Traders id the assort belongs to</param>
@@ -65,7 +65,7 @@ public class AssortHelper(
}
/// <summary>
/// Get a quest id + the statuses quest can be in to unlock assort
/// Get a quest id + the statuses quest can be in to unlock assort
/// </summary>
/// <param name="mergedQuestAssorts">quest assorts to search for assort id</param>
/// <param name="assortId">Assort to look for linked quest id</param>
@@ -1,3 +1,4 @@
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Spt.Bots;
using SPTarkov.Server.Core.Models.Spt.Config;
@@ -6,7 +7,6 @@ using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Helpers;
@@ -1,3 +1,5 @@
using System.Collections.Frozen;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Context;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Match;
@@ -8,9 +10,7 @@ using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
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;
@@ -27,11 +27,10 @@ public class BotGeneratorHelper(
ConfigServer _configServer
)
{
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
// Equipment slot ids that do not conflict with other slots
protected static readonly FrozenSet<string> _slotsWithNoCompatIssues = ["Scabbard", "Backpack", "SecureContainer", "Holster", "ArmBand"];
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
/// <summary>
/// Adds properties to an item
@@ -509,9 +508,9 @@ public class BotGeneratorHelper(
protected bool HasBlockingProperty(TemplateItem? item, string blockingPropertyName)
{
return item?.Properties?.GetType().GetProperties()
.FirstOrDefault(x =>x.PropertyType == typeof(bool)
.FirstOrDefault(x => x.PropertyType == typeof(bool)
&& x.Name.ToLower() == blockingPropertyName
&& (bool)x.GetValue(item.Properties)) is not null;
&& (bool) x.GetValue(item.Properties)) is not null;
}
/// <summary>
@@ -618,9 +617,8 @@ public class BotGeneratorHelper(
}
// Get all root items in found container
var existingContainerItems = (inventory.Items ?? []).Where(
item => item.ParentId == container.Id && item.SlotId == slotGrid.Name
);
var existingContainerItems = (inventory.Items ?? []).Where(item => item.ParentId == container.Id && item.SlotId == slotGrid.Name
);
// Get root items in container we can iterate over to find out what space is free
var containerItemsToCheck = existingContainerItems.Where(x => x.SlotId == slotGrid.Name);
@@ -1,12 +1,12 @@
using System.Collections.Concurrent;
using System.Collections.Frozen;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Models.Utils;
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,9 +18,9 @@ public class BotHelper(
ConfigServer _configServer
)
{
protected static readonly FrozenSet<string> _pmcTypeIds = ["usec", "bear", "pmc", "pmcbear", "pmcusec"];
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
protected static readonly FrozenSet<string> _pmcTypeIds = ["usec", "bear", "pmc", "pmcbear", "pmcusec"];
protected ConcurrentDictionary<string, List<string>> _pmcNameCache = new();
/// <summary>
@@ -141,8 +141,7 @@ public class BotHelper(
return null;
}
return botEquipConfig.Randomisation.FirstOrDefault(
randDetails => botLevel >= randDetails.LevelRange.Min && botLevel <= randDetails.LevelRange.Max
return botEquipConfig.Randomisation.FirstOrDefault(randDetails => botLevel >= randDetails.LevelRange.Min && botLevel <= randDetails.LevelRange.Max
);
}
@@ -1,11 +1,11 @@
using System.Collections.Frozen;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Utils;
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;
@@ -1,218 +1,215 @@
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Utils;
namespace SPTarkov.Server.Core.Helpers
namespace SPTarkov.Server.Core.Helpers;
[Injectable]
public class CertificateHelper(ISptLogger<CertificateHelper> _logger, FileUtil _fileUtil)
{
[Injectable]
public class CertificateHelper(ISptLogger<CertificateHelper> _logger, FileUtil _fileUtil)
private const string certificatePath = "./user/certs/server.crt";
private const string certificateKeyPath = "./user/certs/server.key";
private const string certificatePfxPath = "./user/certs/certificate.pfx";
//Todo: Finish off to match TS server
/// <summary>
/// Currently not in use
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public X509Certificate2 LoadOrGenerateCertificate()
{
private const string certificatePath = "./user/certs/server.crt";
private const string certificateKeyPath = "./user/certs/server.key";
private const string certificatePfxPath = "./user/certs/certificate.pfx";
//Todo: Finish off to match TS server
/// <summary>
/// Currently not in use
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public X509Certificate2 LoadOrGenerateCertificate()
if (!Directory.Exists("./user/certs"))
{
if (!Directory.Exists("./user/certs"))
{
Directory.CreateDirectory("./user/certs");
}
Directory.CreateDirectory("./user/certs");
}
var certificate = LoadCertificate();
var certificate = LoadCertificate();
if (certificate == null)
{
// Generate self-signed certificate
certificate = GenerateSelfSignedCertificate("localhost");
SaveCertificate(certificate); // Save cert and new key
certificate = LoadCertificate();
if (certificate == null)
{
// Generate self-signed certificate
certificate = GenerateSelfSignedCertificate("localhost");
SaveCertificate(certificate); // Save cert and new key
certificate = LoadCertificate();
if (certificate == null)
{
// if we are still null here there is a serious problem creating cert
throw new Exception("Certificate could not be loaded for the second time.");
}
_logger.Success($"Generated and stored self-signed certificate ({certificatePath})");
// if we are still null here there is a serious problem creating cert
throw new Exception("Certificate could not be loaded for the second time.");
}
return certificate;
_logger.Success($"Generated and stored self-signed certificate ({certificatePath})");
}
//Todo: When the above is finished off, remove any method with Pfx in the name
public X509Certificate2 LoadOrGenerateCertificatePfx()
{
if (!Directory.Exists("./user/certs"))
{
Directory.CreateDirectory("./user/certs");
}
return certificate;
}
if (TryLoadCertificatePfx(out var cert))
{
_logger.Success($"Loaded self-signed certificate ({certificatePath})");
return cert;
}
else
{
// shit went wrong, throw a wobbly and close app
_logger.Critical("Certificate pfx could not be loaded. Stopping server...");
Environment.Exit(1);
return null;
}
//Todo: When the above is finished off, remove any method with Pfx in the name
public X509Certificate2 LoadOrGenerateCertificatePfx()
{
if (!Directory.Exists("./user/certs"))
{
Directory.CreateDirectory("./user/certs");
}
private X509Certificate2? LoadCertificate()
if (TryLoadCertificatePfx(out var cert))
{
try
{
return X509Certificate2.CreateFromPemFile(certificatePath, certificateKeyPath);
}
catch (Exception)
{
return null;
}
_logger.Success($"Loaded self-signed certificate ({certificatePath})");
return cert;
}
/// <summary>
/// if the cert exist, try load it, else create one and try load again
/// </summary>
/// <returns></returns>
private bool TryLoadCertificatePfx(out X509Certificate2? certificate)
// shit went wrong, throw a wobbly and close app
_logger.Critical("Certificate pfx could not be loaded. Stopping server...");
Environment.Exit(1);
return null;
}
private X509Certificate2? LoadCertificate()
{
try
{
X509Certificate2 cert = null;
if (!File.Exists(certificatePfxPath))
{
// file doesnt exist so create straight away
cert = GenerateSelfSignedCertificate("localhost");
SaveCertificatePfx(cert);
_logger.Success($"Generated and stored self-signed certificate ({certificatePath})");
}
return X509Certificate2.CreateFromPemFile(certificatePath, certificateKeyPath);
}
catch (Exception)
{
return null;
}
}
try
{
//Archangel: For some reason despite this being deprecated this is the only way to load a certificate file
//No idea why, I want to eventually switch over to the other format so it lines up with the TS server
//But for now this works fine
certificate = new X509Certificate2(certificatePfxPath);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
if (certificate is not null)
{
return true;
}
return false;
/// <summary>
/// if the cert exist, try load it, else create one and try load again
/// </summary>
/// <returns></returns>
private bool TryLoadCertificatePfx(out X509Certificate2? certificate)
{
X509Certificate2 cert = null;
if (!File.Exists(certificatePfxPath))
{
// file doesnt exist so create straight away
cert = GenerateSelfSignedCertificate("localhost");
SaveCertificatePfx(cert);
_logger.Success($"Generated and stored self-signed certificate ({certificatePath})");
}
/// <summary>
/// Get a certificate from provided path and return
/// </summary>
/// <returns>X509Certificate2</returns>
private X509Certificate2? LoadCertificatePfx()
try
{
try
{
//Archangel: For some reason despite this being deprecated this is the only way to load a certificate file
//No idea why, I want to eventually switch over to the other format so it lines up with the TS server
//But for now this works fine
return new(certificatePfxPath);
}
catch (Exception)
{
return null;
}
//Archangel: For some reason despite this being deprecated this is the only way to load a certificate file
//No idea why, I want to eventually switch over to the other format so it lines up with the TS server
//But for now this works fine
certificate = new X509Certificate2(certificatePfxPath);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
/// <summary>
/// Generate and return a self-signed certificate
/// </summary>
/// <param name="subjectName">e.g. localhost</param>
/// <returns>X509Certificate2</returns>
private X509Certificate2 GenerateSelfSignedCertificate(string subjectName)
if (certificate is not null)
{
var sanBuilder = new SubjectAlternativeNameBuilder();
sanBuilder.AddIpAddress(IPAddress.Loopback);
sanBuilder.AddDnsName("localhost");
sanBuilder.AddDnsName(Environment.MachineName);
var distinguishedName = new X500DistinguishedName($"CN={subjectName}");
using var rsa = RSA.Create(2048);
var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
request.CertificateExtensions.Add(sanBuilder.Build());
//Todo: Enable when Pfx methods can be removed
//SavePrivateKey(rsa);
return request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), new DateTimeOffset(DateTime.UtcNow.AddDays(3650)));
return true;
}
/// <summary>
/// Save a certificate as a file to disk
/// </summary>
/// <param name="certificate">Certificate to save</param>
private void SaveCertificate(X509Certificate2 certificate)
return false;
}
/// <summary>
/// Get a certificate from provided path and return
/// </summary>
/// <returns>X509Certificate2</returns>
private X509Certificate2? LoadCertificatePfx()
{
try
{
try
{
// Save as PEM (ensure the certificate is in PEM format)
var certPem = "-----BEGIN CERTIFICATE-----\n" +
Convert.ToBase64String(certificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks) +
"\n-----END CERTIFICATE-----";
_fileUtil.WriteFile(certificatePath, certPem);
}
catch (Exception ex)
{
_logger.Error($"Error saving certificate: {ex.Message}");
}
//Archangel: For some reason despite this being deprecated this is the only way to load a certificate file
//No idea why, I want to eventually switch over to the other format so it lines up with the TS server
//But for now this works fine
return new X509Certificate2(certificatePfxPath);
}
/// <summary>
/// Save a certificate as a file to disk
/// </summary>
/// <param name="certificate">Certificate to save</param>
private void SaveCertificatePfx(X509Certificate2 certificate)
catch (Exception)
{
try
{
_fileUtil.WriteFile(certificatePfxPath, certificate.Export(X509ContentType.Pfx));
}
catch (Exception ex)
{
_logger.Error($"Error saving certificate: {ex.Message}");
}
return null;
}
}
private void SavePrivateKey(RSA privateKey)
/// <summary>
/// Generate and return a self-signed certificate
/// </summary>
/// <param name="subjectName">e.g. localhost</param>
/// <returns>X509Certificate2</returns>
private X509Certificate2 GenerateSelfSignedCertificate(string subjectName)
{
var sanBuilder = new SubjectAlternativeNameBuilder();
sanBuilder.AddIpAddress(IPAddress.Loopback);
sanBuilder.AddDnsName("localhost");
sanBuilder.AddDnsName(Environment.MachineName);
var distinguishedName = new X500DistinguishedName($"CN={subjectName}");
using var rsa = RSA.Create(2048);
var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
request.CertificateExtensions.Add(sanBuilder.Build());
//Todo: Enable when Pfx methods can be removed
//SavePrivateKey(rsa);
return request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), new DateTimeOffset(DateTime.UtcNow.AddDays(3650)));
}
/// <summary>
/// Save a certificate as a file to disk
/// </summary>
/// <param name="certificate">Certificate to save</param>
private void SaveCertificate(X509Certificate2 certificate)
{
try
{
try
{
var privateKeyBytes = privateKey.ExportPkcs8PrivateKey();
// Save as PEM (ensure the certificate is in PEM format)
var certPem = "-----BEGIN CERTIFICATE-----\n" +
Convert.ToBase64String(certificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks) +
"\n-----END CERTIFICATE-----";
_fileUtil.WriteFile(certificatePath, certPem);
}
catch (Exception ex)
{
_logger.Error($"Error saving certificate: {ex.Message}");
}
}
// Convert the private key to PEM format (Base64 encoded)
var privateKeyString = "-----BEGIN PRIVATE KEY-----\n" +
Convert.ToBase64String(privateKeyBytes, Base64FormattingOptions.InsertLineBreaks) +
"\n-----END PRIVATE KEY-----";
/// <summary>
/// Save a certificate as a file to disk
/// </summary>
/// <param name="certificate">Certificate to save</param>
private void SaveCertificatePfx(X509Certificate2 certificate)
{
try
{
_fileUtil.WriteFile(certificatePfxPath, certificate.Export(X509ContentType.Pfx));
}
catch (Exception ex)
{
_logger.Error($"Error saving certificate: {ex.Message}");
}
}
_fileUtil.WriteFile(certificateKeyPath, privateKeyString);
}
catch (Exception ex)
{
_logger.Error($"Error saving certificate key: {ex.Message}");
}
private void SavePrivateKey(RSA privateKey)
{
try
{
var privateKeyBytes = privateKey.ExportPkcs8PrivateKey();
// Convert the private key to PEM format (Base64 encoded)
var privateKeyString = "-----BEGIN PRIVATE KEY-----\n" +
Convert.ToBase64String(privateKeyBytes, Base64FormattingOptions.InsertLineBreaks) +
"\n-----END PRIVATE KEY-----";
_fileUtil.WriteFile(certificateKeyPath, privateKeyString);
}
catch (Exception ex)
{
_logger.Error($"Error saving certificate key: {ex.Message}");
}
}
}
@@ -1,10 +1,10 @@
using SPTarkov.Server.Core.Helpers.Dialog.Commando.SptCommands;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers.Dialog.Commando.SptCommands;
using SPTarkov.Server.Core.Models.Eft.Dialog;
using SPTarkov.Server.Core.Models.Eft.Profile;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Helpers.Dialog.Commando;
@@ -1,4 +1,6 @@
using System.Collections.Frozen;
using System.Text.RegularExpressions;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers.Dialog.Commando.SptCommands;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Dialog;
@@ -8,8 +10,6 @@ using SPTarkov.Server.Core.Models.Utils;
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;
@@ -146,16 +146,14 @@ public class GiveSptCommand(
var allAllowedItemNames = _itemHelper
.GetItems()
.Where(IsItemAllowed)
.Select(
i => localizedGlobal
.GetValueOrDefault($"{i.Id} Name", i.Properties.Name)
?.ToLower()
.Select(i => localizedGlobal
.GetValueOrDefault($"{i.Id} Name", i.Properties.Name)
?.ToLower()
)
.Where(i => !string.IsNullOrEmpty(i));
var closestItemsMatchedByName = allAllowedItemNames
.Select(
i => new
.Select(i => new
{
Match = StringSimilarity.Match(item, i, 2, true),
ItemName = i
@@ -296,7 +294,7 @@ public class GiveSptCommand(
}
/// <summary>
/// Return the desired locale, falls back to english if it cannot be found
/// Return the desired locale, falls back to english if it cannot be found
/// </summary>
/// <param name="desiredLocale">Locale code, e.g. "fr" for french</param>
/// <returns></returns>
@@ -1,4 +1,5 @@
using System.Text.RegularExpressions;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers.Dialog.Commando.SptCommands;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Dialog;
@@ -8,7 +9,6 @@ using SPTarkov.Server.Core.Models.Spt.Dialog;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Helpers.Dialogue.Commando.SptCommands.ProfileCommand;
@@ -85,8 +85,7 @@ public class ProfileSptCommand(
{
var enumSkill = Enum.GetValues<SkillTypes>()
.Cast<SkillTypes?>()
.FirstOrDefault(
t => t?.ToString().ToLower() == skill
.FirstOrDefault(t => t?.ToString().ToLower() == skill
);
if (enumSkill == null)
@@ -1,4 +1,5 @@
using System.Text.RegularExpressions;
using SPTarkov.Common.Annotations;
using SPTarkov.Server.Core.Helpers.Dialog.Commando.SptCommands;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Dialog;
@@ -8,7 +9,6 @@ using SPTarkov.Server.Core.Models.Spt.Dialog;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils;
using SPTarkov.Common.Annotations;
namespace SPTarkov.Server.Core.Helpers.Dialogue.Commando.SptCommands.TraderCommand;

Some files were not shown because too many files have changed in this diff Show More