Merge branch 'develop' into bugfix/upd-lockable-2

This commit is contained in:
Chris Adamson
2025-04-28 08:47:49 -05:00
committed by GitHub
415 changed files with 140778 additions and 139956 deletions
+4 -1
View File
@@ -13,7 +13,10 @@ indent_size = 4
trim_trailing_whitespace = true
[*.json]
ij_formatter_enabled = false
ij_formatter_enabled = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
# C# files
[*.cs]
+5 -5
View File
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\Build.props" />
<Import Project="..\Build.props"/>
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -9,10 +9,10 @@
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.14.0"/>
<ProjectReference Include="..\Libraries\SPTarkov.Server.Core\SPTarkov.Server.Core.csproj" />
<ProjectReference Include="..\Libraries\SPTarkov.Server.Assets\SPTarkov.Server.Assets.csproj" />
<ProjectReference Include="..\Libraries\SPTarkov.Common\SPTarkov.Common.csproj" />
<ProjectReference Include="..\Libraries\SPTarkov.DI\SPTarkov.DI.csproj" />
<ProjectReference Include="..\Libraries\SPTarkov.Server.Core\SPTarkov.Server.Core.csproj"/>
<ProjectReference Include="..\Libraries\SPTarkov.Server.Assets\SPTarkov.Server.Assets.csproj"/>
<ProjectReference Include="..\Libraries\SPTarkov.Common\SPTarkov.Common.csproj"/>
<ProjectReference Include="..\Libraries\SPTarkov.DI\SPTarkov.DI.csproj"/>
</ItemGroup>
<ItemGroup>
+3 -3
View File
@@ -10,17 +10,17 @@ 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()
{
var jsonUtil = new JsonUtil();
var importer = new ImporterUtil(new MockLogger<ImporterUtil>(), new FileUtil(new MockLogger<FileUtil>()),
var importer = new ImporterUtil(new MockLogger<ImporterUtil>(), new FileUtil(),
jsonUtil);
var loadTask = importer.LoadRecursiveAsync<Templates>("./Assets/database/templates/");
loadTask.Wait();
+16
View File
@@ -41,6 +41,17 @@ public class MockLogger<T> : ISptLogger<T>
Console.WriteLine(data);
}
public void Log(
LogLevel level,
string data,
LogTextColor? textColor = null,
LogBackgroundColor? backgroundColor = null,
Exception? ex = null
)
{
throw new NotImplementedException();
}
public void WriteToLogFile(string body, LogLevel level = LogLevel.Info)
{
throw new NotImplementedException();
@@ -51,6 +62,11 @@ public class MockLogger<T> : ISptLogger<T>
return false;
}
public void DumpAndStop()
{
throw new NotImplementedException();
}
public void LogWithColor(
string data,
Exception? ex = null,
@@ -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;
}
}
@@ -5,18 +5,18 @@ namespace SPTarkov.Common.Extensions;
public static class StringExtensions
{
private static readonly Dictionary<string, Regex> RegexCache = new();
private static readonly Lock RegexCacheLock = new();
private static readonly Dictionary<string, Regex> _regexCache = new();
private static readonly Lock _regexCacheLock = new();
public static string RegexReplace(this string source, [StringSyntax(StringSyntaxAttribute.Regex)] string regexString, string newValue)
{
Regex regex;
lock (RegexCacheLock)
lock (_regexCacheLock)
{
if (!RegexCache.TryGetValue(regexString, out regex))
if (!_regexCache.TryGetValue(regexString, out regex))
{
regex = new Regex(regexString);
RegexCache[regexString] = regex;
_regexCache[regexString] = regex;
}
}
@@ -26,12 +26,12 @@ public static class StringExtensions
public static bool RegexMatch(this string source, [StringSyntax(StringSyntaxAttribute.Regex)] string regexString, out Match? matchedString)
{
Regex regex;
lock (RegexCacheLock)
lock (_regexCacheLock)
{
if (!RegexCache.TryGetValue(regexString, out regex))
if (!_regexCache.TryGetValue(regexString, out regex))
{
regex = new Regex(regexString);
RegexCache[regexString] = regex;
_regexCache[regexString] = regex;
}
}
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Import Project="..\..\Build.props" />
<Import Project="..\..\Build.props"/>
<PropertyGroup>
<PackageId>SPTarkov.Common</PackageId>
<Authors>Single Player Tarkov</Authors>
@@ -16,11 +16,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SemanticVersioning" Version="3.0.0" />
<PackageReference Include="SemanticVersioning" Version="3.0.0"/>
</ItemGroup>
<ItemGroup>
<None Include="..\..\LICENSE" Pack="true" Visible="false" PackagePath="" />
<None Include="..\..\LICENSE" Pack="true" Visible="false" PackagePath=""/>
</ItemGroup>
</Project>
@@ -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);
+3 -3
View File
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Import Project="..\..\Build.props" />
<Import Project="..\..\Build.props"/>
<PropertyGroup>
<PackageId>SPTarkov.DI</PackageId>
@@ -16,11 +16,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.1"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SPTarkov.Common\SPTarkov.Common.csproj" />
<ProjectReference Include="..\SPTarkov.Common\SPTarkov.Common.csproj"/>
</ItemGroup>
<ItemGroup>
@@ -263,7 +263,7 @@
"min": 7
},
"pack": {
"chancePercent": 6,
"chancePercent": 0.5,
"itemCountMax": 17,
"itemCountMin": 4,
"itemTypeWhitelist": [
@@ -2452,7 +2452,6 @@
"Borkel",
"Helldiver",
"Sanote",
"ViolentAmbush",
"Jeo",
"Dirtbikercj",
"svbtext",
@@ -2638,7 +2637,6 @@
"SilverParsnip",
"nader",
"IsaacSin",
"Kaeno",
"TheSparta",
"Akiw",
"Capital_Grin",
@@ -2740,7 +2738,6 @@
"devilwalker",
"Fatheals",
"HereticJ",
"InternalError_",
"jayy",
"JP21",
"Juniper",
@@ -2753,7 +2750,152 @@
"The_Antman",
"worshipme",
"Myksa",
"weeny"
"weeny",
"3xtremehamster",
"AcidMC",
"AcksBerg",
"adishee",
"Affengeneral",
"ALameLlama",
"alta1r",
"AmsPhysics",
"APerson",
"AT233",
"BababooeyRatatouille",
"BigTastyNugz",
"Blackleaf420",
"Blahaj Enjoyer",
"BubbaGMobile",
"cabanyakeglya",
"CausingAphid01",
"ChooChoo",
"Colobos9mm",
"Cougarinou",
"CptMoreGun",
"cybensis",
"CZPZ",
"DarkEsteves",
"DeadW0Lf",
"Delod",
"DrunkGeko",
"ehaugw",
"EpicRangeTime",
"FlatCult",
"flir",
"Flowless",
"FriedEngineer",
"Fums",
"garlicbreadtcg",
"GeneralGoon",
"GhostFenixx",
"Gipphe",
"Golani",
"GromAV",
"h3ticnade",
"Hauzman",
"Hjal",
"Hood",
"Hooshu",
"HOT DOG",
"ImBenCole",
"ItsReaperGirl",
"J0nathan550",
"JankyTheClown",
"JonBons",
"jordanbr",
"Josh Mate",
"K.V'7K'PVRIS",
"KaikiNoodles",
"KappaCam",
"knon",
"konstantin90s",
"Kopat1ch",
"kyoukopan",
"LeftHandedCat",
"LightoftheWorld",
"Lily Potter",
"Local Crew",
"madmanbeavis",
"MAGICERASER",
"Magyeong",
"MakerMacher",
"Marine",
"matsix",
"MDZZWOC",
"melonyninja",
"MiseryMachinery",
"mpstark",
"MrUlfen",
"MT_Militia",
"Murasame_chan",
"mynamealien",
"NanamiTV",
"NateDog",
"Navi",
"netVnum",
"Nicholas",
"NoNeedName",
"November75",
"OperatorD9",
"OptimusChad",
"Peepo",
"pein",
"penguingreentea",
"Pizza_rat",
"Praxideke",
"prezidento23",
"privateryan",
"Provocator",
"PulledP0rk",
"PureRussianVodka",
"Qwertyalex",
"Radzig",
"RagingBeardo",
"ragnaroks",
"Randomizzatore",
"Rising_Star",
"RivviN",
"rodentmessiah",
"rzambol",
"S3NN0M0",
"saintdeer",
"SashaSwan",
"Schrader",
"ScottieKnowz",
"Sever12",
"sgt_dogwater",
"sgtlaggy",
"Shibdib",
"Sianyde",
"Skulltag",
"Sneaky_Weasel",
"Solethia",
"stckytwl",
"sugonyak",
"Szonszczyk",
"szszss",
"Tadikas",
"TakiiiNotFound",
"techy",
"TeejayMerks",
"TexaHans",
"TheDevilsrevenge",
"Therkelsen",
"trap",
"Troike",
"turbodestroyer",
"Turok",
"UnderdomeRiot",
"Vesuvius1300",
"viniHNS",
"VioletAmbush",
"ViP3R_76",
"Vortania",
"watsy",
"WispsFlame",
"WUVGAWORE",
"YukoVR",
"ZenosBleed"
],
"generation": {
"items": {
@@ -2442,7 +2442,6 @@
"Borkel",
"Helldiver",
"Sanote",
"ViolentAmbush",
"Jeo",
"Dirtbikercj",
"svbtext",
@@ -2628,7 +2627,6 @@
"SilverParsnip",
"nader",
"IsaacSin",
"Kaeno",
"TheSparta",
"Akiw",
"Capital_Grin",
@@ -2667,83 +2665,227 @@
"mr_puudlik_",
"TarkovBasement",
"Damirka_EA",
"John Halo",
"AGX",
"Mugnum",
"Spring",
"rpmwpm",
"IdiotTurtle",
"MrVibesRSA",
"FiveF",
"desze",
"Boogle",
"sch_kuromi",
"Lillian",
"Tarkin",
"Netnikogo",
"ZGFueDkx",
"TakiiNotFound",
"bushtail",
"wizard83",
"Super",
"harmony",
"SKINNY BEPIS GAMING",
"toothpaste OJ combo",
"Cooler daniel",
"Markosz",
"RootsNine",
"Dsnyder",
"inory",
"HANAVI",
"Dildz",
"fryciarz7",
"PenOkOh",
"Randek",
"ThinkSlow",
"House16",
"egbog",
"bakahashi",
"Harmer",
"Slickboi",
"blkdnm",
"numberdjester",
"vargrasen",
"doom",
"cardsmen",
"Saryn",
"sirdadbearingtonthe69",
"sarynkia",
"estamnar",
"dvize",
"floofyyq",
"jpdarkone",
"gley",
"loafedbread",
"bkreporn",
"malachitekell",
"chonkiee",
"schuetze_klaus",
"yojenkz",
"[666]Silent",
"Berryok",
"Bloom",
"devilwalker",
"Fatheals",
"HereticJ",
"InternalError_",
"jayy",
"JP21",
"Juniper",
"Mauzy-Mir",
"ngage",
"Plaguey",
"roman biznes",
"Slayer-of-Reshala",
"Straxus",
"The_Antman",
"worshipme",
"Myksa",
"weeny"
"John Halo",
"AGX",
"Mugnum",
"Spring",
"rpmwpm",
"IdiotTurtle",
"MrVibesRSA",
"FiveF",
"desze",
"Boogle",
"sch_kuromi",
"Lillian",
"Tarkin",
"Netnikogo",
"ZGFueDkx",
"TakiiNotFound",
"bushtail",
"wizard83",
"Super",
"harmony",
"SKINNY BEPIS GAMING",
"toothpaste OJ combo",
"Cooler daniel",
"Markosz",
"RootsNine",
"Dsnyder",
"inory",
"HANAVI",
"Dildz",
"fryciarz7",
"PenOkOh",
"Randek",
"ThinkSlow",
"House16",
"egbog",
"bakahashi",
"Harmer",
"Slickboi",
"blkdnm",
"numberdjester",
"vargrasen",
"doom",
"cardsmen",
"Saryn",
"sirdadbearingtonthe69",
"sarynkia",
"estamnar",
"dvize",
"floofyyq",
"jpdarkone",
"gley",
"loafedbread",
"bkreporn",
"malachitekell",
"chonkiee",
"schuetze_klaus",
"yojenkz",
"[666]Silent",
"Berryok",
"Bloom",
"devilwalker",
"Fatheals",
"HereticJ",
"jayy",
"JP21",
"Juniper",
"Mauzy-Mir",
"ngage",
"Plaguey",
"roman biznes",
"Slayer-of-Reshala",
"Straxus",
"The_Antman",
"worshipme",
"Myksa",
"weeny",
"3xtremehamster",
"AcidMC",
"AcksBerg",
"adishee",
"Affengeneral",
"ALameLlama",
"alta1r",
"AmsPhysics",
"APerson",
"AT233",
"BababooeyRatatouille",
"BigTastyNugz",
"Blackleaf420",
"Blahaj Enjoyer",
"BubbaGMobile",
"cabanyakeglya",
"CausingAphid01",
"ChooChoo",
"Colobos9mm",
"Cougarinou",
"CptMoreGun",
"cybensis",
"CZPZ",
"DarkEsteves",
"DeadW0Lf",
"Delod",
"DrunkGeko",
"ehaugw",
"EpicRangeTime",
"FlatCult",
"flir",
"Flowless",
"FriedEngineer",
"Fums",
"garlicbreadtcg",
"GeneralGoon",
"GhostFenixx",
"Gipphe",
"Golani",
"GromAV",
"h3ticnade",
"Hauzman",
"Hjal",
"Hood",
"Hooshu",
"HOT DOG",
"ImBenCole",
"ItsReaperGirl",
"J0nathan550",
"JankyTheClown",
"JonBons",
"jordanbr",
"Josh Mate",
"K.V'7K'PVRIS",
"KaikiNoodles",
"KappaCam",
"knon",
"konstantin90s",
"Kopat1ch",
"kyoukopan",
"LeftHandedCat",
"LightoftheWorld",
"Lily Potter",
"Local Crew",
"madmanbeavis",
"MAGICERASER",
"Magyeong",
"MakerMacher",
"Marine",
"matsix",
"MDZZWOC",
"melonyninja",
"MiseryMachinery",
"mpstark",
"MrUlfen",
"MT_Militia",
"Murasame_chan",
"mynamealien",
"NanamiTV",
"NateDog",
"Navi",
"netVnum",
"Nicholas",
"NoNeedName",
"November75",
"OperatorD9",
"OptimusChad",
"Peepo",
"pein",
"penguingreentea",
"Pizza_rat",
"Praxideke",
"prezidento23",
"privateryan",
"Provocator",
"PulledP0rk",
"PureRussianVodka",
"Qwertyalex",
"Radzig",
"RagingBeardo",
"ragnaroks",
"Randomizzatore",
"Rising_Star",
"RivviN",
"rodentmessiah",
"rzambol",
"S3NN0M0",
"saintdeer",
"SashaSwan",
"Schrader",
"ScottieKnowz",
"Sever12",
"sgt_dogwater",
"sgtlaggy",
"Shibdib",
"Sianyde",
"Skulltag",
"Sneaky_Weasel",
"Solethia",
"stckytwl",
"sugonyak",
"Szonszczyk",
"szszss",
"Tadikas",
"TakiiiNotFound",
"techy",
"TeejayMerks",
"TexaHans",
"TheDevilsrevenge",
"Therkelsen",
"trap",
"Troike",
"turbodestroyer",
"Turok",
"UnderdomeRiot",
"Vesuvius1300",
"viniHNS",
"VioletAmbush",
"ViP3R_76",
"Vortania",
"watsy",
"WispsFlame",
"WUVGAWORE",
"YukoVR",
"ZenosBleed"
],
"generation": {
"items": {
File diff suppressed because it is too large Load Diff
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\Build.props" />
<Import Project="..\..\Build.props"/>
<PropertyGroup>
<PackageId>SPTarkov.Server.Assets</PackageId>
@@ -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;
@@ -39,15 +39,15 @@ public class BotController(
{
private readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
private readonly PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
private static readonly Lock _botListLock = new();
/// <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 +56,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 +69,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 +99,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 +159,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 +172,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 +192,21 @@ 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());
lock (_botListLock)
{
result.AddRange(GenerateBotWave(condition, botWaveGenerationDetails, sessionId));
}
})).ToArray());
stopwatch.Stop();
if (_logger.IsLogEnabled(LogLevel.Debug))
@@ -215,7 +218,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 +279,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 +297,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 +307,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 +342,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 +353,7 @@ public class BotController(
{
return _botConfig.MaxBotCap["default"];
}
if (location == "default")
{
_logger.Warning(
@@ -361,7 +365,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;
@@ -22,27 +22,6 @@ public class ClientLogController(
var color = logRequest.Color ?? LogTextColor.White;
var backgroundColor = logRequest.BackgroundColor ?? LogBackgroundColor.Default;
switch (logRequest.Level)
{
case LogLevel.Error:
_logger.Error(message);
break;
case LogLevel.Warn:
_logger.Warning(message);
break;
case LogLevel.Success:
case LogLevel.Info:
_logger.Info(message);
break;
case LogLevel.Custom:
_logger.LogWithColor(message, color, backgroundColor, null);
break;
case LogLevel.Debug:
_logger.Debug(message);
break;
default:
_logger.Info(message);
break;
}
_logger.Log(logRequest.Level ?? LogLevel.Info, message, color, backgroundColor);
}
}
@@ -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>
@@ -350,7 +350,11 @@ public class DialogueController(
var timeNow = _timeUtil.GetTimeStamp();
var dialogs = _dialogueHelper.GetDialogsForProfile(sessionId);
return dialogs[dialogueId].Messages?.Where(message => timeNow < message.DateTime + (message.MaxStorageTime ?? 0)).ToList() ?? [];
return dialogs[dialogueId].Messages?.Where(message =>
{
var checkTime = message.DateTime + (message.MaxStorageTime ?? 0);
return timeNow < checkTime;
}).ToList() ?? [];
}
/// <summary>
@@ -499,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) ??
@@ -553,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>
@@ -563,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>
@@ -614,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;
@@ -19,7 +19,6 @@ public class TraderController(
TimeUtil _timeUtil,
DatabaseService _databaseService,
TraderAssortHelper _traderAssortHelper,
TraderAssortService _traderAssortService,
ProfileHelper _profileHelper,
TraderHelper _traderHelper,
PaymentHelper _paymentHelper,
@@ -65,13 +64,6 @@ public class TraderController(
AdjustTraderItemPrices(trader, _traderConfig.TraderPriceMultiplier);
}
// Create dict of pristine trader assorts on server start
if (_traderAssortService.GetPristineTraderAssort(traderId) == null)
{
var assortsClone = _cloner.Clone(trader.Assort);
_traderAssortService.SetPristineTraderAssort(traderId, assortsClone);
}
_traderPurchasePersisterService.RemoveStalePurchasesFromProfiles(traderId);
// Set to next hour on clock or current time + 60 minutes
@@ -81,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;
@@ -431,30 +431,21 @@ public class BotGenerator(
// Remove blacklisted loot from loot containers
foreach (var lootContainerKey in lootContainersToFilter)
{
var prop = props.FirstOrDefault(x => string.Equals(x.Name, lootContainerKey, StringComparison.CurrentCultureIgnoreCase));
var propValue = (Dictionary<string, double>) prop.GetValue(botInventory.Items);
var propInfo = props
.FirstOrDefault(x => string.Equals(x.Name, lootContainerKey, StringComparison.CurrentCultureIgnoreCase));
var prop = (Dictionary<string, double>?) propInfo.GetValue(botInventory.Items);
// No container, skip
if (propValue?.Count == 0)
if (prop is null)
{
continue;
}
List<string> tplsToRemove = [];
foreach (var (key, _) in propValue)
var newProp = prop.Where(tpl =>
{
if (_itemFilterService.IsLootableItemBlacklisted(key))
{
tplsToRemove.Add(key);
}
}
foreach (var blacklistedTplToRemove in tplsToRemove)
{
propValue.Remove(blacklistedTplToRemove);
}
prop.SetValue(botInventory.Items, propValue);
return !_itemFilterService.IsLootableItemBlacklisted(tpl.Key);
}).ToDictionary();
propInfo.SetValue(botInventory.Items, newProp);
}
}
@@ -518,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)
}
}
},
@@ -528,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)
}
}
},
@@ -656,8 +647,8 @@ public class BotGenerator(
return [];
}
return skills.Select(
kvp =>
return skills
.Select(kvp =>
{
// Get skill from dict, skip if not found
var skill = kvp.Value;
@@ -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,4 +1,5 @@
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;
@@ -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;
@@ -83,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();
}
@@ -100,15 +99,14 @@ public class LocationLootGenerator(
staticContainerCount += guaranteedContainers.Count;
// Add loot to guaranteed containers and add to result
foreach (var container in guaranteedContainers)
foreach (var containerWithLoot in guaranteedContainers.Select(container => AddLootToContainer(
container,
staticForcedOnMapClone,
staticLootDist.Value,
staticAmmoDist,
locationId
)))
{
var containerWithLoot = AddLootToContainer(
container,
staticForcedOnMapClone,
staticLootDist.Value,
staticAmmoDist,
locationId
);
result.Add(containerWithLoot.Template);
staticLootItemCount += containerWithLoot.Template.Items.Count;
@@ -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();
}
@@ -413,7 +408,8 @@ public class LocationLootGenerator(
protected StaticContainerData AddLootToContainer(StaticContainerData staticContainer,
List<StaticForced>? staticForced,
Dictionary<string, StaticLootDetails> staticLootDist,
Dictionary<string, List<StaticAmmoDetails>> staticAmmoDist, string locationName
Dictionary<string, List<StaticAmmoDetails>> staticAmmoDist,
string locationName
)
{
var containerClone = _cloner.Clone(staticContainer);
@@ -428,6 +424,10 @@ public class LocationLootGenerator(
// Choose count of items to add to container
var itemCountToAdd = GetWeightedCountOfContainerItems(containerTpl, staticLootDist, locationName);
if (itemCountToAdd == 0)
{
return containerClone;
}
// Get all possible loot items for container
var containerLootPool = GetPossibleLootItemsForContainer(containerTpl, staticLootDist);
@@ -439,17 +439,22 @@ public class LocationLootGenerator(
// Draw random loot
// Allow money to spawn more than once in container
var failedToFitCount = 0;
var locklist = _itemHelper.GetMoneyTpls();
var failedToFitAttemptCount = 0;
var lockList = _itemHelper.GetMoneyTpls();
// Choose items to add to container, factor in weighting + lock money down
// Filter out items picked that're already in the above `tplsForced` array
// Filter out items picked that are already in the above `tplsForced` array
var chosenTpls = containerLootPool
.Draw(itemCountToAdd, _locationConfig.AllowDuplicateItemsInStaticContainers, locklist)
.Draw(itemCountToAdd, _locationConfig.AllowDuplicateItemsInStaticContainers, lockList)
.Where(tpl => !tplsForced.Contains(tpl));
// Add forced loot to chosen item pool
var tplsToAddToContainer = tplsForced.Concat(chosenTpls);
if (!tplsToAddToContainer.Any())
{
_logger.Warning($"Added no items to container: {containerTpl}");
}
foreach (var tplToAdd in tplsToAddToContainer)
{
var chosenItemWithChildren = CreateStaticLootItem(tplToAdd, staticAmmoDist, parentId);
@@ -458,46 +463,47 @@ public class LocationLootGenerator(
continue;
}
// Check if item should have children removed
var items = _locationConfig.TplsToStripChildItemsFrom.Contains(tplToAdd)
? [chosenItemWithChildren.Items[0]] // Strip children from parent
: chosenItemWithChildren.Items;
var itemSize = GetItemSize(items);
var width = itemSize.Width;
var height = itemSize.Height;
var itemWidth = itemSize.Width;
var itemHeight = itemSize.Height;
// look for open slot to put chosen item into
var result = _containerHelper.FindSlotForItem(containerMap, width, height);
var result = _containerHelper.FindSlotForItem(containerMap, itemWidth, itemHeight);
if (!result.Success.GetValueOrDefault(false))
{
if (failedToFitCount > _locationConfig.FitLootIntoContainerAttempts)
if (failedToFitAttemptCount > _locationConfig.FitLootIntoContainerAttempts)
// x attempts to fit an item, container is probably full, stop trying to add more
{
break;
}
// Can't fit item, skip
failedToFitCount++;
failedToFitAttemptCount++;
continue;
}
// Find somewhere for item inside container
_containerHelper.FillContainerMapWithItem(
containerMap,
result.X.Value,
result.Y.Value,
width,
height,
itemWidth,
itemHeight,
result.Rotation.GetValueOrDefault(false)
);
var rotation = result.Rotation.GetValueOrDefault(false) ? 1 : 0;
// Update root item properties with result of position finder
items[0].SlotId = "main";
items[0].Location = new ItemLocation
{
X = result.X,
Y = result.Y,
R = rotation
R = result.Rotation.GetValueOrDefault(false) ? 1 : 0
};
// Add loot to container before returning
@@ -507,6 +513,11 @@ public class LocationLootGenerator(
return containerClone;
}
/// <summary>
/// Get the height/width of an item including its children
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
protected ItemSize? GetItemSize(List<Item>? items)
{
var rootItem = items[0];
@@ -564,7 +575,7 @@ public class LocationLootGenerator(
protected int GetWeightedCountOfContainerItems(string containerTypeId,
Dictionary<string, StaticLootDetails> staticLootDist, string locationName)
{
// Create probability array to calcualte the total count of lootable items inside container
// Create probability array to calculate the total count of lootable items inside container
var itemCountArray =
new ProbabilityObjectArray<int, float?>(_mathUtil, _cloner);
var countDistribution = staticLootDist[containerTypeId]?.ItemCountDistribution;
@@ -675,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();
}
@@ -793,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();
}
@@ -881,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())
{
@@ -959,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)
{
@@ -977,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)
@@ -113,6 +113,7 @@ public class PMCLootGenerator
blacklist.UnionWith(_pmcConfig.PocketLoot.Blacklist);
blacklist.UnionWith(_pmcConfig.GlobalLootBlacklist);
blacklist.UnionWith(_itemFilterService.GetBlacklistedItems());
blacklist.UnionWith(_itemFilterService.GetBlacklistedLootableItems());
blacklist.UnionWith(_seasonalEventService.GetInactiveSeasonalEventItems());
return blacklist;
@@ -131,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)
@@ -214,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;
@@ -376,7 +376,7 @@ public class PlayerScavGenerator(
if (scavData?.Info != null)
{
scavData.Info.SavageLockTime = Math.Round(_timeUtil.GetTimeStampFromEpoch() / 1000 + (scavLockDuration ?? 0));
scavData.Info.SavageLockTime = Math.Round(_timeUtil.GetTimeStamp() + (scavLockDuration ?? 0));
}
return scavData;
@@ -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,30 +271,30 @@ 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>
protected double? GetRating(string userId)
{
// Player offer
if (profileHelper.IsPlayer(userId))
// Player offer
{
return saveServer.GetProfile(userId).CharacterData?.PmcData?.RagfairInfo?.Rating;
}
// Trader offer
if (ragfairServerHelper.IsTrader(userId))
// Trader offer
{
return 1;
}
// 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;

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