Updated class param formatting

This commit is contained in:
Chomp
2025-08-11 21:08:55 +01:00
parent f66a982f09
commit 4a081a7ac3
23 changed files with 355 additions and 358 deletions
@@ -8,8 +8,8 @@ using SPTarkov.Server.Core.Services;
namespace SPTarkov.Server.Core.Helpers.Dialogue; namespace SPTarkov.Server.Core.Helpers.Dialogue;
public abstract class AbstractDialogChatBot( public abstract class AbstractDialogChatBot(
ISptLogger<AbstractDialogChatBot> _logger, ISptLogger<AbstractDialogChatBot> logger,
MailSendService _mailSendService, MailSendService mailSendService,
ServerLocalisationService localisationService, ServerLocalisationService localisationService,
IEnumerable<IChatCommand> chatCommands IEnumerable<IChatCommand> chatCommands
) : IDialogueChatBot ) : IDialogueChatBot
@@ -22,7 +22,7 @@ public abstract class AbstractDialogChatBot(
{ {
if (request.Text.Length == 0) if (request.Text.Length == 0)
{ {
_logger.Error(localisationService.GetText("chatbot-command_was_empty")); logger.Error(localisationService.GetText("chatbot-command_was_empty"));
return request.DialogId; return request.DialogId;
} }
@@ -43,20 +43,20 @@ public abstract class AbstractDialogChatBot(
return await SendPlayerHelpMessage(sessionId, request); return await SendPlayerHelpMessage(sessionId, request);
} }
_mailSendService.SendUserMessageToPlayer(sessionId, GetChatBot(), GetUnrecognizedCommandMessage(), [], null); mailSendService.SendUserMessageToPlayer(sessionId, GetChatBot(), GetUnrecognizedCommandMessage(), [], null);
return string.Empty; return string.Empty;
} }
protected async ValueTask<string> SendPlayerHelpMessage(MongoId sessionId, SendMessageRequest request) protected async ValueTask<string> SendPlayerHelpMessage(MongoId sessionId, SendMessageRequest request)
{ {
_mailSendService.SendUserMessageToPlayer(sessionId, GetChatBot(), "The available commands will be listed below:", [], null); mailSendService.SendUserMessageToPlayer(sessionId, GetChatBot(), "The available commands will be listed below:", [], null);
foreach (var chatCommand in _chatCommands.Values) foreach (var chatCommand in _chatCommands.Values)
{ {
// due to BSG being dumb with messages we need a mandatory timeout between messages so they get out on the right order // due to BSG being dumb with messages we need a mandatory timeout between messages so they get out on the right order
await Task.Delay(TimeSpan.FromSeconds(1)); await Task.Delay(TimeSpan.FromSeconds(1));
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
GetChatBot(), GetChatBot(),
$"Commands available for \"{chatCommand.CommandPrefix}\" prefix:", $"Commands available for \"{chatCommand.CommandPrefix}\" prefix:",
@@ -68,7 +68,7 @@ public abstract class AbstractDialogChatBot(
foreach (var subCommand in chatCommand.Commands) foreach (var subCommand in chatCommand.Commands)
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
GetChatBot(), GetChatBot(),
$"Subcommand {subCommand}:\n{chatCommand.GetCommandHelp(subCommand)}", $"Subcommand {subCommand}:\n{chatCommand.GetCommandHelp(subCommand)}",
@@ -15,14 +15,14 @@ namespace SPTarkov.Server.Core.Helpers.Dialogue.Commando.SptCommands.GiveCommand
[Injectable] [Injectable]
public class GiveSptCommand( public class GiveSptCommand(
ISptLogger<GiveSptCommand> _logger, ISptLogger<GiveSptCommand> logger,
ItemHelper _itemHelper, ItemHelper itemHelper,
DatabaseService databaseService, DatabaseService databaseService,
PresetHelper _presetHelper, PresetHelper presetHelper,
ItemFilterService _itemFilterService, ItemFilterService itemFilterService,
MailSendService _mailSendService, MailSendService mailSendService,
LocaleService _localeService, LocaleService localeService,
ICloner _cloner ICloner cloner
) : ISptCommand ) : ISptCommand
{ {
private const double _acceptableConfidence = 0.9d; private const double _acceptableConfidence = 0.9d;
@@ -57,7 +57,7 @@ public class GiveSptCommand(
{ {
if (!_commandRegex.IsMatch(request.Text)) if (!_commandRegex.IsMatch(request.Text))
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of give command. Use 'help' for more information." "Invalid use of give command. Use 'help' for more information."
@@ -78,7 +78,7 @@ public class GiveSptCommand(
{ {
if (!_savedCommand.ContainsKey(sessionId)) if (!_savedCommand.ContainsKey(sessionId))
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of give command. Use 'help' for more information." "Invalid use of give command. Use 'help' for more information."
@@ -90,7 +90,7 @@ public class GiveSptCommand(
var locationSixValue = +int.Parse(result.Groups[6].Value); var locationSixValue = +int.Parse(result.Groups[6].Value);
if (locationSixValue > savedCommand.PotentialItemNames.Count) if (locationSixValue > savedCommand.PotentialItemNames.Count)
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid selection. Outside of bounds! Use 'help' for more information." "Invalid selection. Outside of bounds! Use 'help' for more information."
@@ -114,7 +114,7 @@ public class GiveSptCommand(
quantity = +int.Parse(result.Groups[6].Value); quantity = +int.Parse(result.Groups[6].Value);
if (quantity <= 0) if (quantity <= 0)
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid quantity! Must be 1 or higher. Use 'help' for more information." "Invalid quantity! Must be 1 or higher. Use 'help' for more information."
@@ -126,17 +126,17 @@ public class GiveSptCommand(
{ {
try try
{ {
locale = result.Groups[4].Value ?? _localeService.GetDesiredGameLocale() ?? "en"; locale = result.Groups[4].Value ?? localeService.GetDesiredGameLocale() ?? "en";
} }
catch (Exception ex) catch (Exception ex)
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
$"An error occurred while trying to use localized text. Locale will be defaulted to 'en'. {ex.Message}" $"An error occurred while trying to use localized text. Locale will be defaulted to 'en'. {ex.Message}"
); );
_logger.Warning(ex.Message); logger.Warning(ex.Message);
locale = "en"; locale = "en";
} }
@@ -164,7 +164,7 @@ public class GiveSptCommand(
// max 10 item names and map them // max 10 item names and map them
var itemList = slicedItems.Select(match => $"{i++}. {match.ItemName} (conf: {Math.Round(match.Match * 100d), 2})"); var itemList = slicedItems.Select(match => $"{i++}. {match.ItemName} (conf: {Math.Round(match.Match * 100d), 2})");
_savedCommand.Add(sessionId, new SavedCommand(quantity, slicedItems.Select(item => item.ItemName).ToList(), locale)); _savedCommand.Add(sessionId, new SavedCommand(quantity, slicedItems.Select(item => item.ItemName).ToList(), locale));
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
$"Could not find exact match. Closest are:\n{string.Join("\n", itemList)}\n\nUse 'spt give [above number]' to select one." $"Could not find exact match. Closest are:\n{string.Join("\n", itemList)}\n\nUse 'spt give [above number]' to select one."
@@ -186,10 +186,10 @@ public class GiveSptCommand(
.Id .Id
: item; : item;
var checkedItem = _itemHelper.GetItem(tplId); var checkedItem = itemHelper.GetItem(tplId);
if (!checkedItem.Key) if (!checkedItem.Key)
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"That item could not be found. Please refine your request and try again." "That item could not be found. Please refine your request and try again."
@@ -198,17 +198,17 @@ public class GiveSptCommand(
} }
List<Item> itemsToSend = []; List<Item> itemsToSend = [];
var preset = _presetHelper.GetDefaultPreset(checkedItem.Value.Id); var preset = presetHelper.GetDefaultPreset(checkedItem.Value.Id);
if (preset is not null && !_excludedPresetItems.Contains(checkedItem.Value.Id)) if (preset is not null && !_excludedPresetItems.Contains(checkedItem.Value.Id))
{ {
for (var i = 0; i < quantity; i++) for (var i = 0; i < quantity; i++)
{ {
var items = _cloner.Clone(preset.Items); var items = cloner.Clone(preset.Items);
items = items.ReplaceIDs().ToList(); items = items.ReplaceIDs().ToList();
itemsToSend.AddRange(items); itemsToSend.AddRange(items);
} }
} }
else if (_itemHelper.IsOfBaseclass(checkedItem.Value.Id, BaseClasses.AMMO_BOX)) else if (itemHelper.IsOfBaseclass(checkedItem.Value.Id, BaseClasses.AMMO_BOX))
{ {
for (var i = 0; i < quantity; i++) for (var i = 0; i < quantity; i++)
{ {
@@ -234,7 +234,7 @@ public class GiveSptCommand(
{ {
Id = new MongoId(), Id = new MongoId(),
Template = checkedItem.Value.Id, Template = checkedItem.Value.Id,
Upd = _itemHelper.GenerateUpdForItem(checkedItem.Value), Upd = itemHelper.GenerateUpdForItem(checkedItem.Value),
} }
); );
} }
@@ -245,16 +245,16 @@ public class GiveSptCommand(
{ {
Id = new MongoId(), Id = new MongoId(),
Template = checkedItem.Value.Id, Template = checkedItem.Value.Id,
Upd = _itemHelper.GenerateUpdForItem(checkedItem.Value), Upd = itemHelper.GenerateUpdForItem(checkedItem.Value),
}; };
itemToSend.Upd.StackObjectsCount = quantity; itemToSend.Upd.StackObjectsCount = quantity;
try try
{ {
itemsToSend.AddRange(_itemHelper.SplitStack(itemToSend)); itemsToSend.AddRange(itemHelper.SplitStack(itemToSend));
} }
catch catch
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Too many items requested. Please lower the amount and try again." "Too many items requested. Please lower the amount and try again."
@@ -266,9 +266,9 @@ public class GiveSptCommand(
} }
// Flag the items as FiR // Flag the items as FiR
_itemHelper.SetFoundInRaid(itemsToSend); itemHelper.SetFoundInRaid(itemsToSend);
_mailSendService.SendSystemMessageToPlayer(sessionId, $"SPT GIVE DELIVERY: {item}", itemsToSend); mailSendService.SendSystemMessageToPlayer(sessionId, $"SPT GIVE DELIVERY: {item}", itemsToSend);
return new ValueTask<string>(request.DialogId); return new ValueTask<string>(request.DialogId);
} }
@@ -280,7 +280,7 @@ public class GiveSptCommand(
/// <returns></returns> /// <returns></returns>
protected Dictionary<string, string> GetGlobalsLocale(string desiredLocale) protected Dictionary<string, string> GetGlobalsLocale(string desiredLocale)
{ {
return _localeService.GetLocaleDb(desiredLocale); return localeService.GetLocaleDb(desiredLocale);
} }
/// <summary> /// <summary>
@@ -292,9 +292,9 @@ public class GiveSptCommand(
{ {
return templateItem.Type != "Node" return templateItem.Type != "Node"
&& !templateItem.IsQuestItem() && !templateItem.IsQuestItem()
&& !_itemFilterService.IsItemBlacklisted(templateItem.Id) && !itemFilterService.IsItemBlacklisted(templateItem.Id)
&& (templateItem.Properties?.Prefab?.Path ?? "") != "" && (templateItem.Properties?.Prefab?.Path ?? "") != ""
&& !_itemHelper.IsOfBaseclasses( && !itemHelper.IsOfBaseclasses(
templateItem.Id, templateItem.Id,
[ [
BaseClasses.HIDEOUT_AREA_CONTAINER, BaseClasses.HIDEOUT_AREA_CONTAINER,
@@ -13,7 +13,7 @@ using SPTarkov.Server.Core.Services;
namespace SPTarkov.Server.Core.Helpers.Dialogue.Commando.SptCommands.ProfileCommand; namespace SPTarkov.Server.Core.Helpers.Dialogue.Commando.SptCommands.ProfileCommand;
[Injectable] [Injectable]
public class ProfileSptCommand(ISptLogger<ProfileSptCommand> _logger, MailSendService _mailSendService, ProfileHelper _profileHelper) public class ProfileSptCommand(ISptLogger<ProfileSptCommand> logger, MailSendService mailSendService, ProfileHelper profileHelper)
: ISptCommand : ISptCommand
{ {
/// <summary> /// <summary>
@@ -49,7 +49,7 @@ public class ProfileSptCommand(ISptLogger<ProfileSptCommand> _logger, MailSendSe
if (!isCommand && !isExamine) if (!isCommand && !isExamine)
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of trader command. Use 'help' for more information." "Invalid use of trader command. Use 'help' for more information."
@@ -67,9 +67,9 @@ public class ProfileSptCommand(ISptLogger<ProfileSptCommand> _logger, MailSendSe
switch (command) switch (command)
{ {
case "level": case "level":
if (quantity < 1 || quantity > _profileHelper.GetMaxLevel()) if (quantity < 1 || quantity > profileHelper.GetMaxLevel())
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of profile command, the level was outside bounds: 1 to 70. Use 'help' for more information." "Invalid use of profile command, the level was outside bounds: 1 to 70. Use 'help' for more information."
@@ -87,7 +87,7 @@ public class ProfileSptCommand(ISptLogger<ProfileSptCommand> _logger, MailSendSe
if (enumSkill == null) if (enumSkill == null)
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of profile command, the skill was not found. Use 'help' for more information." "Invalid use of profile command, the skill was not found. Use 'help' for more information."
@@ -97,7 +97,7 @@ public class ProfileSptCommand(ISptLogger<ProfileSptCommand> _logger, MailSendSe
if (quantity is < 0 or > 51) if (quantity is < 0 or > 51)
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of profile command, the skill level was outside bounds: 1 to 51. Use 'help' for more information." "Invalid use of profile command, the skill level was outside bounds: 1 to 51. Use 'help' for more information."
@@ -114,7 +114,7 @@ public class ProfileSptCommand(ISptLogger<ProfileSptCommand> _logger, MailSendSe
break; break;
} }
default: default:
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
$"If you are reading this, this is bad. Please report this to SPT staff with a screenshot. Command: {command}." $"If you are reading this, this is bad. Please report this to SPT staff with a screenshot. Command: {command}."
@@ -122,7 +122,7 @@ public class ProfileSptCommand(ISptLogger<ProfileSptCommand> _logger, MailSendSe
return new ValueTask<string>(request.DialogId); return new ValueTask<string>(request.DialogId);
} }
_mailSendService.SendSystemMessageToPlayer( mailSendService.SendSystemMessageToPlayer(
sessionId, sessionId,
"A single ruble is being attached, required by BSG logic.", "A single ruble is being attached, required by BSG logic.",
[ [
@@ -156,7 +156,7 @@ public class ProfileSptCommand(ISptLogger<ProfileSptCommand> _logger, MailSendSe
protected ProfileChangeEvent HandleLevelCommand(int level) protected ProfileChangeEvent HandleLevelCommand(int level)
{ {
var exp = _profileHelper.GetExperience(level); var exp = profileHelper.GetExperience(level);
var profileChangeEvent = new ProfileChangeEvent var profileChangeEvent = new ProfileChangeEvent
{ {
Id = new MongoId(), Id = new MongoId(),
@@ -14,8 +14,7 @@ using SPTarkov.Server.Core.Services;
namespace SPTarkov.Server.Core.Helpers.Dialogue.Commando.SptCommands.TraderCommand; namespace SPTarkov.Server.Core.Helpers.Dialogue.Commando.SptCommands.TraderCommand;
[Injectable] [Injectable]
public class TraderSptCommand(ISptLogger<TraderSptCommand> _logger, TraderHelper _traderHelper, MailSendService _mailSendService) public class TraderSptCommand(ISptLogger<TraderSptCommand> logger, TraderHelper traderHelper, MailSendService mailSendService) : ISptCommand
: ISptCommand
{ {
protected readonly Regex _commandRegex = new(@"^spt trader (?<trader>[\w]+) (?<command>rep|spend) (?<quantity>(?!0+)[0-9]+)$"); protected readonly Regex _commandRegex = new(@"^spt trader (?<trader>[\w]+) (?<command>rep|spend) (?<quantity>(?!0+)[0-9]+)$");
@@ -36,7 +35,7 @@ public class TraderSptCommand(ISptLogger<TraderSptCommand> _logger, TraderHelper
{ {
if (!_commandRegex.IsMatch(request.Text)) if (!_commandRegex.IsMatch(request.Text))
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of trader command. Use 'help' for more information." "Invalid use of trader command. Use 'help' for more information."
@@ -50,10 +49,10 @@ public class TraderSptCommand(ISptLogger<TraderSptCommand> _logger, TraderHelper
var command = result.Groups["command"].Captures.Count > 0 ? result.Groups["command"].Captures[0].Value : null; var command = result.Groups["command"].Captures.Count > 0 ? result.Groups["command"].Captures[0].Value : null;
var quantity = double.Parse(result.Groups["command"].Captures.Count > 0 ? result.Groups["quantity"].Captures[0].Value : "0"); var quantity = double.Parse(result.Groups["command"].Captures.Count > 0 ? result.Groups["quantity"].Captures[0].Value : "0");
var dbTrader = _traderHelper.GetTraderByNickName(trader); var dbTrader = traderHelper.GetTraderByNickName(trader);
if (dbTrader == null) if (dbTrader == null)
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of trader command, the trader was not found. Use 'help' for more information." "Invalid use of trader command, the trader was not found. Use 'help' for more information."
@@ -74,7 +73,7 @@ public class TraderSptCommand(ISptLogger<TraderSptCommand> _logger, TraderHelper
break; break;
default: default:
{ {
_mailSendService.SendUserMessageToPlayer( mailSendService.SendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of trader command, ProfileChangeEventType was not found. Use 'help' for more information." "Invalid use of trader command, ProfileChangeEventType was not found. Use 'help' for more information."
@@ -84,7 +83,7 @@ public class TraderSptCommand(ISptLogger<TraderSptCommand> _logger, TraderHelper
} }
} }
_mailSendService.SendSystemMessageToPlayer( mailSendService.SendSystemMessageToPlayer(
sessionId, sessionId,
"A single ruble is being attached, required by BSG logic.", "A single ruble is being attached, required by BSG logic.",
[ [
@@ -6,19 +6,19 @@ using SPTarkov.Server.Core.Utils;
namespace SPTarkov.Server.Core.Loaders; namespace SPTarkov.Server.Core.Loaders;
[Injectable(InjectionType.Singleton)] [Injectable(InjectionType.Singleton)]
public class OnWebAppBuildModLoader(ISptLogger<OnWebAppBuildModLoader> _logger, IEnumerable<IOnWebAppBuildModAsync> _onWebAppBuildMods) public class OnWebAppBuildModLoader(ISptLogger<OnWebAppBuildModLoader> logger, IEnumerable<IOnWebAppBuildModAsync> onWebAppBuildMods)
{ {
public async Task OnLoad() public async Task OnLoad()
{ {
if (ProgramStatics.MODS()) if (ProgramStatics.MODS())
{ {
_logger.Info("Loading OnWebAppBuildMods..."); logger.Info("Loading OnWebAppBuildMods...");
foreach (var onWebAppBuildMod in _onWebAppBuildMods) foreach (var onWebAppBuildMod in onWebAppBuildMods)
{ {
await onWebAppBuildMod.OnWebAppBuildAsync(); await onWebAppBuildMod.OnWebAppBuildAsync();
} }
_logger.Info("Finished loading OnWebAppBuildMods..."); logger.Info("Finished loading OnWebAppBuildMods...");
} }
} }
} }
@@ -8,19 +8,19 @@ namespace SPTarkov.Server.Core.Loaders;
[Obsolete("This mod loader is obsolete and will be removed in 4.1.0. See documentation in IPostDBLoadModAsync for more information.")] [Obsolete("This mod loader is obsolete and will be removed in 4.1.0. See documentation in IPostDBLoadModAsync for more information.")]
[Injectable(TypePriority = OnLoadOrder.PostDBModLoader)] [Injectable(TypePriority = OnLoadOrder.PostDBModLoader)]
public class PostDBModLoader(ISptLogger<PostDBModLoader> _logger, IEnumerable<IPostDBLoadModAsync> _postDbLoadMods) : IOnLoad public class PostDBModLoader(ISptLogger<PostDBModLoader> logger, IEnumerable<IPostDBLoadModAsync> postDbLoadMods) : IOnLoad
{ {
public async Task OnLoad() public async Task OnLoad()
{ {
if (ProgramStatics.MODS()) if (ProgramStatics.MODS())
{ {
_logger.Info("Loading PostDBMods..."); logger.Info("Loading PostDBMods...");
foreach (var postDbLoadMod in _postDbLoadMods) foreach (var postDbLoadMod in postDbLoadMods)
{ {
await postDbLoadMod.PostDBLoadAsync(); await postDbLoadMod.PostDBLoadAsync();
} }
_logger.Info("Finished loading PostDBMods..."); logger.Info("Finished loading PostDBMods...");
} }
} }
} }
@@ -8,19 +8,19 @@ namespace SPTarkov.Server.Core.Loaders;
[Obsolete("This mod loader is obsolete and will be removed in 4.1.0. See documentation in IPostSptLoadModAsync for more information.")] [Obsolete("This mod loader is obsolete and will be removed in 4.1.0. See documentation in IPostSptLoadModAsync for more information.")]
[Injectable(TypePriority = OnLoadOrder.PostSptModLoader)] [Injectable(TypePriority = OnLoadOrder.PostSptModLoader)]
public class PostSptModLoader(ISptLogger<PostSptModLoader> _logger, IEnumerable<IPostSptLoadModAsync> _postSptLoadMods) : IOnLoad public class PostSptModLoader(ISptLogger<PostSptModLoader> logger, IEnumerable<IPostSptLoadModAsync> postSptLoadMods) : IOnLoad
{ {
public async Task OnLoad() public async Task OnLoad()
{ {
if (ProgramStatics.MODS()) if (ProgramStatics.MODS())
{ {
_logger.Info("Loading PostSptMods..."); logger.Info("Loading PostSptMods...");
foreach (var postSptLoadMod in _postSptLoadMods) foreach (var postSptLoadMod in postSptLoadMods)
{ {
await postSptLoadMod.PostSptLoadAsync(); await postSptLoadMod.PostSptLoadAsync();
} }
_logger.Info("Finished loading PostSptMods..."); logger.Info("Finished loading PostSptMods...");
} }
} }
} }
@@ -7,19 +7,19 @@ using SPTarkov.Server.Core.Utils;
namespace SPTarkov.Server.Core.Loaders; namespace SPTarkov.Server.Core.Loaders;
[Injectable(InjectionType.Singleton, TypePriority = OnLoadOrder.PreSptModLoader)] [Injectable(InjectionType.Singleton, TypePriority = OnLoadOrder.PreSptModLoader)]
public class PreSptModLoader(ISptLogger<PreSptModLoader> _logger, IEnumerable<IPreSptLoadModAsync> _preSptLoadMods) : IOnLoad public class PreSptModLoader(ISptLogger<PreSptModLoader> logger, IEnumerable<IPreSptLoadModAsync> preSptLoadMods) : IOnLoad
{ {
public async Task OnLoad() public async Task OnLoad()
{ {
if (ProgramStatics.MODS()) if (ProgramStatics.MODS())
{ {
_logger.Info("Loading PreSptMods..."); logger.Info("Loading PreSptMods...");
foreach (var postSptLoadMod in _preSptLoadMods) foreach (var postSptLoadMod in preSptLoadMods)
{ {
await postSptLoadMod.PreSptLoadAsync(); await postSptLoadMod.PreSptLoadAsync();
} }
_logger.Info("Finished loading PreSptMods..."); logger.Info("Finished loading PreSptMods...");
} }
} }
} }
@@ -12,16 +12,16 @@ namespace SPTarkov.Server.Core.Servers;
public class ConfigServer public class ConfigServer
{ {
protected readonly FrozenSet<string> acceptableFileExtensions = ["json", "jsonc"]; protected readonly FrozenSet<string> acceptableFileExtensions = ["json", "jsonc"];
protected readonly FileUtil _fileUtil; protected readonly FileUtil FileUtil;
protected readonly JsonUtil _jsonUtil; protected readonly JsonUtil JsonUtil;
protected readonly ISptLogger<ConfigServer> _logger; protected readonly ISptLogger<ConfigServer> Logger;
private static readonly Dictionary<string, object> _configs = new(); private static readonly Dictionary<string, object> _configs = new();
public ConfigServer(ISptLogger<ConfigServer> logger, JsonUtil jsonUtil, FileUtil fileUtil) public ConfigServer(ISptLogger<ConfigServer> logger, JsonUtil jsonUtil, FileUtil fileUtil)
{ {
_logger = logger; Logger = logger;
_jsonUtil = jsonUtil; JsonUtil = jsonUtil;
_fileUtil = fileUtil; FileUtil = fileUtil;
if (_configs.Count == 0) if (_configs.Count == 0)
{ {
@@ -60,37 +60,37 @@ public class ConfigServer
public void Initialize() public void Initialize()
{ {
if (_logger.IsLogEnabled(LogLevel.Debug)) if (Logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug("Importing configs..."); Logger.Debug("Importing configs...");
} }
// Get all filepaths // Get all filepaths
const string filepath = "./SPT_Data/configs/"; const string filepath = "./SPT_Data/configs/";
var files = _fileUtil.GetFiles(filepath); var files = FileUtil.GetFiles(filepath);
// Add file content to result // Add file content to result
foreach (var file in files) foreach (var file in files)
{ {
if (acceptableFileExtensions.Contains(_fileUtil.GetFileExtension(file))) if (acceptableFileExtensions.Contains(FileUtil.GetFileExtension(file)))
{ {
var type = GetConfigTypeByFilename(file); var type = GetConfigTypeByFilename(file);
var deserializedContent = _jsonUtil.DeserializeFromFile(file, type); var deserializedContent = JsonUtil.DeserializeFromFile(file, type);
if (deserializedContent == null) if (deserializedContent == null)
{ {
_logger.Error($"Config file: {file} is corrupt. Use a site like: https://jsonlint.com to find the issue."); Logger.Error($"Config file: {file} is corrupt. Use a site like: https://jsonlint.com to find the issue.");
throw new Exception($"Server will not run until the: {file} config error mentioned above is fixed"); throw new Exception($"Server will not run until the: {file} config error mentioned above is fixed");
} }
_configs[$"spt-{_fileUtil.StripExtension(file)}"] = deserializedContent; _configs[$"spt-{FileUtil.StripExtension(file)}"] = deserializedContent;
} }
} }
} }
private Type GetConfigTypeByFilename(string filename) private Type GetConfigTypeByFilename(string filename)
{ {
var type = Enum.GetValues<ConfigTypes>().First(en => en.GetValue().Contains(_fileUtil.StripExtension(filename))); var type = Enum.GetValues<ConfigTypes>().First(en => en.GetValue().Contains(FileUtil.StripExtension(filename)));
return type.GetConfigType(); return type.GetConfigType();
} }
} }
@@ -16,13 +16,13 @@ namespace SPTarkov.Server.Core.Servers.Http;
[Injectable] [Injectable]
public class SptHttpListener( public class SptHttpListener(
HttpRouter _httpRouter, HttpRouter httpRouter,
IEnumerable<ISerializer> _serializers, IEnumerable<ISerializer> serializers,
ISptLogger<SptHttpListener> _logger, ISptLogger<SptHttpListener> logger,
ISptLogger<RequestLogger> _requestsLogger, ISptLogger<RequestLogger> requestsLogger,
JsonUtil _jsonUtil, JsonUtil jsonUtil,
HttpResponseUtil _httpResponseUtil, HttpResponseUtil httpResponseUtil,
ServerLocalisationService _serverLocalisationService ServerLocalisationService serverLocalisationService
) : IHttpListener ) : IHttpListener
{ {
// We want to read 1KB at a time, for most request this is already big enough // We want to read 1KB at a time, for most request this is already big enough
@@ -30,8 +30,8 @@ public class SptHttpListener(
private static readonly ImmutableHashSet<string> SupportedMethods = ["GET", "PUT", "POST"]; private static readonly ImmutableHashSet<string> SupportedMethods = ["GET", "PUT", "POST"];
protected readonly HttpRouter _router = _httpRouter; protected readonly HttpRouter _router = httpRouter;
protected readonly IEnumerable<ISerializer> _serializers = _serializers; protected readonly IEnumerable<ISerializer> _serializers = serializers;
public bool CanHandle(MongoId _, HttpRequest req) public bool CanHandle(MongoId _, HttpRequest req)
{ {
@@ -92,9 +92,9 @@ public class SptHttpListener(
if (!requestIsCompressed) if (!requestIsCompressed)
{ {
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug(body); logger.Debug(body);
} }
} }
@@ -105,7 +105,7 @@ public class SptHttpListener(
default: default:
{ {
_logger.Warning($"{_serverLocalisationService.GetText("unknown_request")}: {req.Method}"); logger.Warning($"{serverLocalisationService.GetText("unknown_request")}: {req.Method}");
break; break;
} }
} }
@@ -123,15 +123,15 @@ public class SptHttpListener(
{ {
body ??= new object(); body ??= new object();
var bodyInfo = _jsonUtil.Serialize(body); var bodyInfo = jsonUtil.Serialize(body);
if (IsDebugRequest(req)) if (IsDebugRequest(req))
{ {
// Send only raw response without transformation // Send only raw response without transformation
await SendJson(resp, output, sessionID); await SendJson(resp, output, sessionID);
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"Response: {output}"); logger.Debug($"Response: {output}");
} }
LogRequest(req, output); LogRequest(req, output);
@@ -173,7 +173,7 @@ public class SptHttpListener(
if (ProgramStatics.ENTRY_TYPE() != EntryType.RELEASE) if (ProgramStatics.ENTRY_TYPE() != EntryType.RELEASE)
{ {
var log = new Response(req.Method, output); var log = new Response(req.Method, output);
_requestsLogger.Info($"RESPONSE={_jsonUtil.Serialize(log)}"); requestsLogger.Info($"RESPONSE={jsonUtil.Serialize(log)}");
} }
} }
@@ -184,15 +184,15 @@ public class SptHttpListener(
// Route doesn't exist or response is not properly set up // Route doesn't exist or response is not properly set up
if (string.IsNullOrEmpty(output)) if (string.IsNullOrEmpty(output))
{ {
_logger.Error(_serverLocalisationService.GetText("unhandled_response", req.Path.ToString())); logger.Error(serverLocalisationService.GetText("unhandled_response", req.Path.ToString()));
output = _httpResponseUtil.GetBody<object?>(null, BackendErrorCodes.HTTPNotFound, $"UNHANDLED RESPONSE: {req.Path.ToString()}"); output = httpResponseUtil.GetBody<object?>(null, BackendErrorCodes.HTTPNotFound, $"UNHANDLED RESPONSE: {req.Path.ToString()}");
} }
if (ProgramStatics.ENTRY_TYPE() != EntryType.RELEASE) if (ProgramStatics.ENTRY_TYPE() != EntryType.RELEASE)
{ {
// Parse quest info into object // Parse quest info into object
var log = new Request(req.Method, new RequestData(req.Path.ToString(), req.Headers)); var log = new Request(req.Method, new RequestData(req.Path.ToString(), req.Headers));
_requestsLogger.Info($"REQUEST={_jsonUtil.Serialize(log)}"); requestsLogger.Info($"REQUEST={jsonUtil.Serialize(log)}");
} }
return output; return output;
@@ -12,21 +12,21 @@ namespace SPTarkov.Server.Core.Servers;
[Injectable(InjectionType.Singleton)] [Injectable(InjectionType.Singleton)]
public class HttpServer( public class HttpServer(
ISptLogger<HttpServer> _logger, ISptLogger<HttpServer> logger,
ServerLocalisationService _serverLocalisationService, ServerLocalisationService serverLocalisationService,
ConfigServer _configServer, ConfigServer configServer,
WebSocketServer _webSocketServer, WebSocketServer webSocketServer,
ProfileActivityService _profileActivityService, ProfileActivityService profileActivityService,
IEnumerable<IHttpListener> _httpListeners IEnumerable<IHttpListener> httpListeners
) )
{ {
private readonly HttpConfig _httpConfig = _configServer.GetConfig<HttpConfig>(); private readonly HttpConfig _httpConfig = configServer.GetConfig<HttpConfig>();
public async Task HandleRequest(HttpContext context) public async Task HandleRequest(HttpContext context)
{ {
if (context.WebSockets.IsWebSocketRequest) if (context.WebSockets.IsWebSocketRequest)
{ {
await _webSocketServer.OnConnection(context); await webSocketServer.OnConnection(context);
return; return;
} }
@@ -36,7 +36,7 @@ public class HttpServer(
: MongoId.Empty(); : MongoId.Empty();
if (!string.IsNullOrEmpty(sessionIdString)) if (!string.IsNullOrEmpty(sessionIdString))
{ {
_profileActivityService.SetActivityTimestamp(sessionId); profileActivityService.SetActivityTimestamp(sessionId);
} }
// Extract header for original IP detection // Extract header for original IP detection
@@ -50,7 +50,7 @@ public class HttpServer(
try try
{ {
var listener = _httpListeners.FirstOrDefault(l => l.CanHandle(sessionId, context.Request)); var listener = httpListeners.FirstOrDefault(l => l.CanHandle(sessionId, context.Request));
if (listener != null) if (listener != null)
{ {
@@ -59,9 +59,9 @@ public class HttpServer(
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Critical("Error handling request: " + context.Request.Path); logger.Critical("Error handling request: " + context.Request.Path);
_logger.Critical(ex.Message); logger.Critical(ex.Message);
_logger.Critical(ex.StackTrace); logger.Critical(ex.StackTrace);
#if DEBUG #if DEBUG
throw; // added this so we can debug something. throw; // added this so we can debug something.
#endif #endif
@@ -80,11 +80,11 @@ public class HttpServer(
{ {
if (isLocalRequest) if (isLocalRequest)
{ {
_logger.Info(_serverLocalisationService.GetText("client_request", context.Request.Path.Value)); logger.Info(serverLocalisationService.GetText("client_request", context.Request.Path.Value));
} }
else else
{ {
_logger.Info(_serverLocalisationService.GetText("client_request_ip", new { ip = clientIp, url = context.Request.Path.Value })); logger.Info(serverLocalisationService.GetText("client_request_ip", new { ip = clientIp, url = context.Request.Path.Value }));
} }
} }
@@ -13,24 +13,24 @@ namespace SPTarkov.Server.Core.Servers;
[Injectable] [Injectable]
public class RagfairServer( public class RagfairServer(
ISptLogger<RagfairServer> _logger, ISptLogger<RagfairServer> logger,
TimeUtil timeUtil, TimeUtil timeUtil,
RagfairOfferService _ragfairOfferService, RagfairOfferService ragfairOfferService,
RagfairCategoriesService _ragfairCategoriesService, RagfairCategoriesService ragfairCategoriesService,
RagfairRequiredItemsService _ragfairRequiredItemsService, RagfairRequiredItemsService ragfairRequiredItemsService,
ServerLocalisationService _serverLocalisationService, ServerLocalisationService serverLocalisationService,
RagfairOfferGenerator _ragfairOfferGenerator, RagfairOfferGenerator ragfairOfferGenerator,
RagfairOfferHolder _ragfairOfferHolder, RagfairOfferHolder ragfairOfferHolder,
ConfigServer _configServer, ConfigServer configServer,
ICloner cloner ICloner cloner
) )
{ {
protected readonly RagfairConfig _ragfairConfig = _configServer.GetConfig<RagfairConfig>(); protected readonly RagfairConfig _ragfairConfig = configServer.GetConfig<RagfairConfig>();
public void Load() public void Load()
{ {
_logger.Info(_serverLocalisationService.GetText("ragfair-generating_offers")); logger.Info(serverLocalisationService.GetText("ragfair-generating_offers"));
_ragfairOfferGenerator.GenerateDynamicOffers(); ragfairOfferGenerator.GenerateDynamicOffers();
Update(); Update();
} }
@@ -40,7 +40,7 @@ public class RagfairServer(
ProcessExpiredFleaOffers(); ProcessExpiredFleaOffers();
// Update requirements now the offers have been expired/regenerated to ensure they're accurate // Update requirements now the offers have been expired/regenerated to ensure they're accurate
_ragfairRequiredItemsService.BuildRequiredItemTable(); ragfairRequiredItemsService.BuildRequiredItemTable();
} }
protected void RefreshTraderOffers() protected void RefreshTraderOffers()
@@ -50,10 +50,10 @@ public class RagfairServer(
foreach (var traderId in tradersToProcess) foreach (var traderId in tradersToProcess)
{ {
// Each trader has its own expiry time // Each trader has its own expiry time
if (_ragfairOfferService.TraderOffersNeedRefreshing(traderId)) if (ragfairOfferService.TraderOffersNeedRefreshing(traderId))
{ {
// Trader has passed its offer expiry time, update stock and reset offer times // Trader has passed its offer expiry time, update stock and reset offer times
_ragfairOfferGenerator.GenerateFleaOffersForTrader(traderId); ragfairOfferGenerator.GenerateFleaOffersForTrader(traderId);
} }
} }
} }
@@ -61,18 +61,18 @@ public class RagfairServer(
private void ProcessExpiredFleaOffers() private void ProcessExpiredFleaOffers()
{ {
// Regenerate expired offers when over timestamp threshold // Regenerate expired offers when over timestamp threshold
_ragfairOfferHolder.FlagExpiredOffersAfterDate(timeUtil.GetTimeStamp()); ragfairOfferHolder.FlagExpiredOffersAfterDate(timeUtil.GetTimeStamp());
if (!_ragfairOfferService.EnoughExpiredOffersExistToProcess()) if (!ragfairOfferService.EnoughExpiredOffersExistToProcess())
{ {
// Not enough expired offers to process, exit // Not enough expired offers to process, exit
return; return;
} }
// Must occur BEFORE "RemoveExpiredOffers" + clone items as they'll be purged by `RemoveExpiredOffers()` // Must occur BEFORE "RemoveExpiredOffers" + clone items as they'll be purged by `RemoveExpiredOffers()`
var expiredOfferItemsClone = cloner.Clone(_ragfairOfferHolder.GetExpiredOfferItems()); var expiredOfferItemsClone = cloner.Clone(ragfairOfferHolder.GetExpiredOfferItems());
_ragfairOfferService.RemoveExpiredOffers(); ragfairOfferService.RemoveExpiredOffers();
// Force a cleanup+compact now all the expired offers are gone // Force a cleanup+compact now all the expired offers are gone
GC.Collect(GC.MaxGeneration, GCCollectionMode.Optimized, true, true); GC.Collect(GC.MaxGeneration, GCCollectionMode.Optimized, true, true);
@@ -80,7 +80,7 @@ public class RagfairServer(
if (expiredOfferItemsClone is not null) if (expiredOfferItemsClone is not null)
{ {
// Replace the expired offers with new ones // Replace the expired offers with new ones
_ragfairOfferGenerator.GenerateDynamicOffers(expiredOfferItemsClone); ragfairOfferGenerator.GenerateDynamicOffers(expiredOfferItemsClone);
} }
} }
@@ -99,7 +99,7 @@ public class RagfairServer(
IEnumerable<RagfairOffer> offers IEnumerable<RagfairOffer> offers
) )
{ {
return _ragfairCategoriesService.GetCategoriesFromOffers(offers, searchRequestData, fleaUnlocked); return ragfairCategoriesService.GetCategoriesFromOffers(offers, searchRequestData, fleaUnlocked);
} }
/// <summary> /// <summary>
@@ -108,12 +108,12 @@ public class RagfairServer(
/// <param name="offerId"> OfferID to hide </param> /// <param name="offerId"> OfferID to hide </param>
public void HideOffer(MongoId offerId) public void HideOffer(MongoId offerId)
{ {
var offers = _ragfairOfferService.GetOffers(); var offers = ragfairOfferService.GetOffers();
var offer = offers.FirstOrDefault(x => x.Id == offerId); var offer = offers.FirstOrDefault(x => x.Id == offerId);
if (offer is null) if (offer is null)
{ {
_logger.Error(_serverLocalisationService.GetText("ragfair-offer_not_found_unable_to_hide", offerId)); logger.Error(serverLocalisationService.GetText("ragfair-offer_not_found_unable_to_hide", offerId));
return; return;
} }
@@ -123,26 +123,26 @@ public class RagfairServer(
public RagfairOffer? GetOffer(MongoId offerId) public RagfairOffer? GetOffer(MongoId offerId)
{ {
return _ragfairOfferService.GetOfferByOfferId(offerId); return ragfairOfferService.GetOfferByOfferId(offerId);
} }
public List<RagfairOffer> GetOffers() public List<RagfairOffer> GetOffers()
{ {
return _ragfairOfferService.GetOffers(); return ragfairOfferService.GetOffers();
} }
public void ReduceOfferQuantity(MongoId offerId, int amount) public void ReduceOfferQuantity(MongoId offerId, int amount)
{ {
_ragfairOfferService.ReduceOfferQuantity(offerId, amount); ragfairOfferService.ReduceOfferQuantity(offerId, amount);
} }
public bool DoesOfferExist(MongoId offerId) public bool DoesOfferExist(MongoId offerId)
{ {
return _ragfairOfferService.DoesOfferExist(offerId); return ragfairOfferService.DoesOfferExist(offerId);
} }
public void AddPlayerOffers() public void AddPlayerOffers()
{ {
_ragfairOfferService.AddPlayerOffers(); ragfairOfferService.AddPlayerOffers();
} }
} }
@@ -8,7 +8,7 @@ using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Servers; namespace SPTarkov.Server.Core.Servers;
[Injectable(InjectionType.Singleton)] [Injectable(InjectionType.Singleton)]
public class WebSocketServer(IEnumerable<IWebSocketConnectionHandler> _webSocketConnectionHandler, ISptLogger<WebSocketServer> _logger) public class WebSocketServer(IEnumerable<IWebSocketConnectionHandler> webSocketConnectionHandler, ISptLogger<WebSocketServer> logger)
{ {
public async Task OnConnection(HttpContext httpContext) public async Task OnConnection(HttpContext httpContext)
{ {
@@ -18,7 +18,7 @@ public class WebSocketServer(IEnumerable<IWebSocketConnectionHandler> _webSocket
private async Task HandleWebSocket(HttpContext context, WebSocket webSocket) private async Task HandleWebSocket(HttpContext context, WebSocket webSocket)
{ {
var socketHandlers = _webSocketConnectionHandler.Where(wsh => context.Request.Path.Value.Contains(wsh.GetHookUrl())); var socketHandlers = webSocketConnectionHandler.Where(wsh => context.Request.Path.Value.Contains(wsh.GetHookUrl()));
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
var wsToken = cts.Token; var wsToken = cts.Token;
@@ -27,34 +27,34 @@ public class WebSocketServer(IEnumerable<IWebSocketConnectionHandler> _webSocket
{ {
var message = var message =
$"Socket connection received for url {context.Request.Path.Value}, but there is no websocket handler configured for it!"; $"Socket connection received for url {context.Request.Path.Value}, but there is no websocket handler configured for it!";
_logger.Debug(message); logger.Debug(message);
await webSocket.CloseAsync(WebSocketCloseStatus.ProtocolError, message, CancellationToken.None); await webSocket.CloseAsync(WebSocketCloseStatus.ProtocolError, message, CancellationToken.None);
return; return;
} }
var webSocketIdContext = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff"); var webSocketIdContext = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"[WS] Notifying handlers of new websocket connection opening with reference {webSocketIdContext}"); logger.Debug($"[WS] Notifying handlers of new websocket connection opening with reference {webSocketIdContext}");
} }
foreach (var wsh in socketHandlers) foreach (var wsh in socketHandlers)
{ {
if (webSocket.State == WebSocketState.Open) if (webSocket.State == WebSocketState.Open)
{ {
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"WebSocketHandler \"{wsh.GetSocketId()}\" connected"); logger.Debug($"WebSocketHandler \"{wsh.GetSocketId()}\" connected");
} }
} }
await wsh.OnConnection(webSocket, context, webSocketIdContext); await wsh.OnConnection(webSocket, context, webSocketIdContext);
} }
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"[WS] Starting read loop for websocket reference {webSocketIdContext}"); logger.Debug($"[WS] Starting read loop for websocket reference {webSocketIdContext}");
} }
var thread = Task.Factory.StartNew( var thread = Task.Factory.StartNew(
@@ -98,7 +98,7 @@ public class WebSocketServer(IEnumerable<IWebSocketConnectionHandler> _webSocket
// If this is not handled an exception is thrown on the client // If this is not handled an exception is thrown on the client
if (result.MessageType == WebSocketMessageType.Close) if (result.MessageType == WebSocketMessageType.Close)
{ {
_logger.Debug($"[WS] WebSocket reference {webSocketIdContext} sent close frame, stopping."); logger.Debug($"[WS] WebSocket reference {webSocketIdContext} sent close frame, stopping.");
await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Closing..", wsToken); await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Closing..", wsToken);
socketClosing = true; socketClosing = true;
break; break;
@@ -108,9 +108,9 @@ public class WebSocketServer(IEnumerable<IWebSocketConnectionHandler> _webSocket
if (result.EndOfMessage) if (result.EndOfMessage)
{ {
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug( logger.Debug(
$"[WS] Read loop for websocket reference {webSocketIdContext} received new message. Notifying socket handlers." $"[WS] Read loop for websocket reference {webSocketIdContext} received new message. Notifying socket handlers."
); );
} }
@@ -134,9 +134,9 @@ public class WebSocketServer(IEnumerable<IWebSocketConnectionHandler> _webSocket
var counter = 0; var counter = 0;
while (webSocket.State == WebSocketState.Open) while (webSocket.State == WebSocketState.Open)
{ {
if (counter == 30 && _logger.IsLogEnabled(LogLevel.Debug)) if (counter == 30 && logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug( logger.Debug(
$"[WS] Websocket keep alive for reference {webSocketIdContext}. Thread state {thread.Status}. Websocket state {webSocket.State}" $"[WS] Websocket keep alive for reference {webSocketIdContext}. Thread state {thread.Status}. Websocket state {webSocket.State}"
); );
counter = 0; counter = 0;
@@ -150,9 +150,9 @@ public class WebSocketServer(IEnumerable<IWebSocketConnectionHandler> _webSocket
Thread.Sleep(1000); Thread.Sleep(1000);
} }
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"[WS] State for websocket reference {webSocketIdContext} is now {webSocket.State}, closing"); logger.Debug($"[WS] State for websocket reference {webSocketIdContext} is now {webSocket.State}, closing");
} }
// Disconnect has been received, cancel the token and send OnClose to the relevant WebSockets. // Disconnect has been received, cancel the token and send OnClose to the relevant WebSockets.
@@ -160,17 +160,17 @@ public class WebSocketServer(IEnumerable<IWebSocketConnectionHandler> _webSocket
{ {
await cts.CancelAsync(); await cts.CancelAsync();
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"[WS] OnClose for websocket reference {webSocketIdContext} requested"); logger.Debug($"[WS] OnClose for websocket reference {webSocketIdContext} requested");
} }
await wsh.OnClose(webSocket, context, webSocketIdContext); await wsh.OnClose(webSocket, context, webSocketIdContext);
} }
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"[WS] Websocket reference {webSocketIdContext} fully closed."); logger.Debug($"[WS] Websocket reference {webSocketIdContext} fully closed.");
} }
} }
} }
@@ -6,10 +6,10 @@ using SPTarkov.Server.Core.Models.Utils;
namespace SPTarkov.Server.Core.Servers.Ws.Message; namespace SPTarkov.Server.Core.Servers.Ws.Message;
[Injectable] [Injectable]
public class DefaultSptWebSocketMessageHandler(ISptLogger<DefaultSptWebSocketMessageHandler> _logger) : ISptWebSocketMessageHandler public class DefaultSptWebSocketMessageHandler(ISptLogger<DefaultSptWebSocketMessageHandler> logger) : ISptWebSocketMessageHandler
{ {
public async Task OnSptMessage(string sessionID, WebSocket client, byte[] rawData) public async Task OnSptMessage(string sessionID, WebSocket client, byte[] rawData)
{ {
_logger.Debug($"[{sessionID}] SPT message received: {Encoding.UTF8.GetString(rawData)}"); logger.Debug($"[{sessionID}] SPT message received: {Encoding.UTF8.GetString(rawData)}");
} }
} }
@@ -14,11 +14,11 @@ namespace SPTarkov.Server.Core.Servers.Ws;
[Injectable(InjectionType.Singleton)] [Injectable(InjectionType.Singleton)]
public class SptWebSocketConnectionHandler( public class SptWebSocketConnectionHandler(
ISptLogger<SptWebSocketConnectionHandler> _logger, ISptLogger<SptWebSocketConnectionHandler> logger,
ServerLocalisationService _serverLocalisationService, ServerLocalisationService serverLocalisationService,
JsonUtil _jsonUtil, JsonUtil jsonUtil,
ProfileHelper _profileHelper, ProfileHelper profileHelper,
IEnumerable<ISptWebSocketMessageHandler> _messageHandlers IEnumerable<ISptWebSocketMessageHandler> messageHandlers
) : IWebSocketConnectionHandler ) : IWebSocketConnectionHandler
{ {
protected readonly Dictionary<string, Dictionary<string, WebSocket>> _sockets = new(); protected readonly Dictionary<string, Dictionary<string, WebSocket>> _sockets = new();
@@ -38,11 +38,11 @@ public class SptWebSocketConnectionHandler(
{ {
var splitUrl = context.Request.Path.Value.Split("/"); var splitUrl = context.Request.Path.Value.Split("/");
var sessionID = splitUrl.Last(); var sessionID = splitUrl.Last();
var playerProfile = _profileHelper.GetFullProfile(sessionID); var playerProfile = profileHelper.GetFullProfile(sessionID);
var playerInfoText = $"{playerProfile.ProfileInfo.Username} ({sessionID})"; var playerInfoText = $"{playerProfile.ProfileInfo.Username} ({sessionID})";
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"[WS] Websocket connect for player {playerInfoText} started with context {sessionIdContext}"); logger.Debug($"[WS] Websocket connect for player {playerInfoText} started with context {sessionIdContext}");
} }
lock (_socketsLock) lock (_socketsLock)
@@ -51,10 +51,10 @@ public class SptWebSocketConnectionHandler(
{ {
if (sessionSockets.Any()) if (sessionSockets.Any())
{ {
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug( logger.Debug(
_serverLocalisationService.GetText( serverLocalisationService.GetText(
"websocket-player_reconnect", "websocket-player_reconnect",
new { sessionId = playerInfoText, contextId = sessionIdContext } new { sessionId = playerInfoText, contextId = sessionIdContext }
) )
@@ -69,10 +69,10 @@ public class SptWebSocketConnectionHandler(
} }
sessionSockets.Add(sessionIdContext, ws); sessionSockets.Add(sessionIdContext, ws);
if (_logger.IsLogEnabled(LogLevel.Info)) if (logger.IsLogEnabled(LogLevel.Info))
{ {
_logger.Info( logger.Info(
_serverLocalisationService.GetText( serverLocalisationService.GetText(
"websocket-player_connected", "websocket-player_connected",
new { sessionId = playerInfoText, contextId = sessionIdContext } new { sessionId = playerInfoText, contextId = sessionIdContext }
) )
@@ -87,12 +87,12 @@ public class SptWebSocketConnectionHandler(
{ {
var splitUrl = context.Request.Path.Value.Split("/"); var splitUrl = context.Request.Path.Value.Split("/");
var sessionID = splitUrl.Last(); var sessionID = splitUrl.Last();
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"[WS] Message for session {sessionID} received. Notifying message handlers."); logger.Debug($"[WS] Message for session {sessionID} received. Notifying message handlers.");
} }
foreach (var sptWebSocketMessageHandler in _messageHandlers) foreach (var sptWebSocketMessageHandler in messageHandlers)
{ {
await sptWebSocketMessageHandler.OnSptMessage(sessionID, ws, receivedMessage); await sptWebSocketMessageHandler.OnSptMessage(sessionID, ws, receivedMessage);
} }
@@ -105,40 +105,40 @@ public class SptWebSocketConnectionHandler(
lock (_socketsLock) lock (_socketsLock)
{ {
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"Attempting to close websocket session {sessionID} with context {sessionIdContext}"); logger.Debug($"Attempting to close websocket session {sessionID} with context {sessionIdContext}");
} }
if (_sockets.TryGetValue(sessionID, out var sessionSockets) && sessionSockets.Any()) if (_sockets.TryGetValue(sessionID, out var sessionSockets) && sessionSockets.Any())
{ {
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"Websockets for session {sessionID} entry matched, attempting to find context {sessionIdContext}"); logger.Debug($"Websockets for session {sessionID} entry matched, attempting to find context {sessionIdContext}");
} }
if (!sessionSockets.TryGetValue(sessionIdContext, out _) && _logger.IsLogEnabled(LogLevel.Info)) if (!sessionSockets.TryGetValue(sessionIdContext, out _) && logger.IsLogEnabled(LogLevel.Info))
{ {
_logger.Info( logger.Info(
$"[ws] The websocket session {sessionID} with reference: {sessionIdContext} has already been removed or reconnected" $"[ws] The websocket session {sessionID} with reference: {sessionIdContext} has already been removed or reconnected"
); );
} }
else else
{ {
sessionSockets.Remove(sessionIdContext); sessionSockets.Remove(sessionIdContext);
if (_logger.IsLogEnabled(LogLevel.Info)) if (logger.IsLogEnabled(LogLevel.Info))
{ {
var playerProfile = _profileHelper.GetFullProfile(sessionID); var playerProfile = profileHelper.GetFullProfile(sessionID);
var playerInfoText = $"{playerProfile.ProfileInfo.Username} ({sessionID})"; var playerInfoText = $"{playerProfile.ProfileInfo.Username} ({sessionID})";
_logger.Info($"[ws] player: {playerInfoText} {sessionIdContext} has disconnected"); logger.Info($"[ws] player: {playerInfoText} {sessionIdContext} has disconnected");
} }
} }
} }
else else
{ {
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug( logger.Debug(
$"Websocket for session {sessionID} with context {sessionIdContext} does not exist on the socket map, nothing was removed" $"Websocket for session {sessionID} with context {sessionIdContext} does not exist on the socket map, nothing was removed"
); );
} }
@@ -165,47 +165,47 @@ public class SptWebSocketConnectionHandler(
{ {
var webSockets = GetSessionWebSocket(sessionID); var webSockets = GetSessionWebSocket(sessionID);
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"Send message for {sessionID} matched {webSockets.Count()} websockets. Messages being sent"); logger.Debug($"Send message for {sessionID} matched {webSockets.Count()} websockets. Messages being sent");
} }
foreach (var webSocket in webSockets) foreach (var webSocket in webSockets)
{ {
var sendTask = webSocket.SendAsync( var sendTask = webSocket.SendAsync(
Encoding.UTF8.GetBytes(_jsonUtil.Serialize(output, output.GetType())), Encoding.UTF8.GetBytes(jsonUtil.Serialize(output, output.GetType())),
WebSocketMessageType.Text, WebSocketMessageType.Text,
true, true,
CancellationToken.None CancellationToken.None
); );
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"Send message for {sessionID} on websocket async started"); logger.Debug($"Send message for {sessionID} on websocket async started");
} }
sendTask.Wait(); sendTask.Wait();
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"Send message for {sessionID} on websocket async finished"); logger.Debug($"Send message for {sessionID} on websocket async finished");
} }
} }
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug(_serverLocalisationService.GetText("websocket-message_sent")); logger.Debug(serverLocalisationService.GetText("websocket-message_sent"));
} }
} }
else else
{ {
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug(_serverLocalisationService.GetText("websocket-not_ready_message_not_sent", sessionID)); logger.Debug(serverLocalisationService.GetText("websocket-not_ready_message_not_sent", sessionID));
} }
} }
} }
catch (Exception err) catch (Exception err)
{ {
_logger.Error(_serverLocalisationService.GetText("websocket-message_send_failed_with_error"), err); logger.Error(serverLocalisationService.GetText("websocket-message_send_failed_with_error"), err);
} }
} }
@@ -16,14 +16,14 @@ namespace SPTarkov.Server.Core.Services;
[Injectable] [Injectable]
public class AirdropService( public class AirdropService(
ISptLogger<AirdropService> _logger, ISptLogger<AirdropService> logger,
ConfigServer configServer, ConfigServer configServer,
LootGenerator _lootGenerator, LootGenerator lootGenerator,
DatabaseService databaseService, DatabaseService databaseService,
WeightedRandomHelper _weightedRandomHelper, WeightedRandomHelper weightedRandomHelper,
ServerLocalisationService _serverLocalisationService, ServerLocalisationService serverLocalisationService,
ItemFilterService _itemFilterService, ItemFilterService itemFilterService,
ItemHelper _itemHelper ItemHelper itemHelper
) )
{ {
protected readonly AirdropConfig _airdropConfig = configServer.GetConfig<AirdropConfig>(); protected readonly AirdropConfig _airdropConfig = configServer.GetConfig<AirdropConfig>();
@@ -36,7 +36,7 @@ public class AirdropService(
return GenerateAirdropLoot(customAirdropInformation); return GenerateAirdropLoot(customAirdropInformation);
} }
_logger.Warning(_serverLocalisationService.GetText("airdrop-unable_to_find_container_id_generating_random", request.ContainerId)); logger.Warning(serverLocalisationService.GetText("airdrop-unable_to_find_container_id_generating_random", request.ContainerId));
return GenerateAirdropLoot(); return GenerateAirdropLoot();
} }
@@ -51,9 +51,9 @@ public class AirdropService(
public GetAirdropLootResponse GenerateAirdropLoot(SptAirdropTypeEnum? forcedAirdropType = null) public GetAirdropLootResponse GenerateAirdropLoot(SptAirdropTypeEnum? forcedAirdropType = null)
{ {
var airdropType = forcedAirdropType ?? ChooseAirdropType(); var airdropType = forcedAirdropType ?? ChooseAirdropType();
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"Chose: {airdropType} for airdrop loot"); logger.Debug($"Chose: {airdropType} for airdrop loot");
} }
// Common/weapon/etc // Common/weapon/etc
@@ -61,8 +61,8 @@ public class AirdropService(
// generate loot to put into airdrop crate // generate loot to put into airdrop crate
var crateLootPool = airdropConfig.UseForcedLoot.GetValueOrDefault(false) var crateLootPool = airdropConfig.UseForcedLoot.GetValueOrDefault(false)
? _lootGenerator.CreateForcedLoot(airdropConfig.ForcedLoot) ? lootGenerator.CreateForcedLoot(airdropConfig.ForcedLoot)
: _lootGenerator.CreateRandomLoot(airdropConfig); : lootGenerator.CreateRandomLoot(airdropConfig);
// Create airdrop crate and add to result in first spot // Create airdrop crate and add to result in first spot
var airdropCrateItem = GetAirdropCrateItem(airdropType); var airdropCrateItem = GetAirdropCrateItem(airdropType);
@@ -106,13 +106,13 @@ public class AirdropService(
var lootResult = new List<List<Item>>(); var lootResult = new List<List<Item>>();
// Get 2d mapping of container // Get 2d mapping of container
var containerMap = _itemHelper.GetContainerMapping(container.Template); var containerMap = itemHelper.GetContainerMapping(container.Template);
var failedToFitAttemptCount = 0; var failedToFitAttemptCount = 0;
foreach (var itemAndChildren in crateLootPool) foreach (var itemAndChildren in crateLootPool)
{ {
// Get x/y size of item (weapons get larger with children attached) // Get x/y size of item (weapons get larger with children attached)
var itemSize = _itemHelper.GetItemSize(itemAndChildren, itemAndChildren[0].Id); var itemSize = itemHelper.GetItemSize(itemAndChildren, itemAndChildren[0].Id);
// Look for open slot to put chosen item into // Look for open slot to put chosen item into
var result = containerMap.FindSlotForItem(itemSize.Width, itemSize.Height); var result = containerMap.FindSlotForItem(itemSize.Width, itemSize.Height);
@@ -136,7 +136,7 @@ public class AirdropService(
if (failedToFitAttemptCount > 3) if (failedToFitAttemptCount > 3)
// 3 attempts to fit an item, container is probably full, stop trying to add more // 3 attempts to fit an item, container is probably full, stop trying to add more
{ {
_logger.Debug( logger.Debug(
$"Airdrop is too full of loot to add: {itemAndChildren[0].Template} after {failedToFitAttemptCount} attempts, stopped adding more" $"Airdrop is too full of loot to add: {itemAndChildren[0].Template} after {failedToFitAttemptCount} attempts, stopped adding more"
); );
break; break;
@@ -196,7 +196,7 @@ public class AirdropService(
{ {
var possibleAirdropTypes = _airdropConfig.AirdropTypeWeightings; var possibleAirdropTypes = _airdropConfig.AirdropTypeWeightings;
return _weightedRandomHelper.GetWeightedValue(possibleAirdropTypes); return weightedRandomHelper.GetWeightedValue(possibleAirdropTypes);
} }
/// <summary> /// <summary>
@@ -208,7 +208,7 @@ public class AirdropService(
{ {
if (!_airdropConfig.Loot.TryGetValue(airdropType.ToString(), out var lootSettingsByType)) if (!_airdropConfig.Loot.TryGetValue(airdropType.ToString(), out var lootSettingsByType))
{ {
_logger.Error(_serverLocalisationService.GetText("location-unable_to_find_airdrop_drop_config_of_type", airdropType)); logger.Error(serverLocalisationService.GetText("location-unable_to_find_airdrop_drop_config_of_type", airdropType));
// TODO: Get Radar airdrop to work. Atm Radar will default to common supply drop (mixed) // TODO: Get Radar airdrop to work. Atm Radar will default to common supply drop (mixed)
// Default to common // Default to common
@@ -216,17 +216,17 @@ public class AirdropService(
} }
// Get all items that match the blacklisted types and fold into item blacklist // Get all items that match the blacklisted types and fold into item blacklist
var itemTypeBlacklist = _itemFilterService.GetItemRewardBaseTypeBlacklist(); var itemTypeBlacklist = itemFilterService.GetItemRewardBaseTypeBlacklist();
var itemsMatchingTypeBlacklist = databaseService var itemsMatchingTypeBlacklist = databaseService
.GetItems() .GetItems()
.Where(kvp => !kvp.Value.Parent.IsEmpty) .Where(kvp => !kvp.Value.Parent.IsEmpty)
.Where(kvp => _itemHelper.IsOfBaseclasses(kvp.Value.Parent, itemTypeBlacklist)) .Where(kvp => itemHelper.IsOfBaseclasses(kvp.Value.Parent, itemTypeBlacklist))
.Select(kvp => kvp.Key) .Select(kvp => kvp.Key)
.ToHashSet(); .ToHashSet();
var itemBlacklist = new HashSet<MongoId>(); var itemBlacklist = new HashSet<MongoId>();
itemBlacklist.UnionWith(lootSettingsByType.ItemBlacklist); itemBlacklist.UnionWith(lootSettingsByType.ItemBlacklist);
itemBlacklist.UnionWith(_itemFilterService.GetItemRewardBlacklist()); itemBlacklist.UnionWith(itemFilterService.GetItemRewardBlacklist());
itemBlacklist.UnionWith(_itemFilterService.GetBossItems()); itemBlacklist.UnionWith(itemFilterService.GetBossItems());
itemBlacklist.UnionWith(itemsMatchingTypeBlacklist); itemBlacklist.UnionWith(itemsMatchingTypeBlacklist);
return new AirdropLootRequest return new AirdropLootRequest
@@ -19,11 +19,12 @@ public class BackupService
// Runs Init() every x minutes // Runs Init() every x minutes
protected Timer _backupIntervalTimer; protected Timer _backupIntervalTimer;
protected readonly FileUtil _fileUtil;
protected readonly JsonUtil _jsonUtil; protected readonly FileUtil FileUtil;
protected readonly ISptLogger<BackupService> _logger; protected readonly JsonUtil JsonUtil;
protected readonly TimeUtil _timeUtil; protected readonly ISptLogger<BackupService> Logger;
protected readonly IReadOnlyList<SptMod> _loadedMods; protected readonly TimeUtil TimeUtil;
protected readonly IReadOnlyList<SptMod> LoadedMods;
public BackupService( public BackupService(
ISptLogger<BackupService> logger, ISptLogger<BackupService> logger,
@@ -34,11 +35,11 @@ public class BackupService
FileUtil fileUtil FileUtil fileUtil
) )
{ {
_logger = logger; Logger = logger;
_jsonUtil = jsonUtil; JsonUtil = jsonUtil;
_timeUtil = timeUtil; TimeUtil = timeUtil;
_fileUtil = fileUtil; FileUtil = fileUtil;
_loadedMods = loadedMods; LoadedMods = loadedMods;
_activeServerMods = GetActiveServerMods(); _activeServerMods = GetActiveServerMods();
_backupConfig = configServer.GetConfig<BackupConfig>(); _backupConfig = configServer.GetConfig<BackupConfig>();
@@ -66,7 +67,7 @@ public class BackupService
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error($"Profile backup failed: {ex.Message}, {ex.StackTrace}"); Logger.Error($"Profile backup failed: {ex.Message}, {ex.StackTrace}");
} }
}, },
null, null,
@@ -93,19 +94,19 @@ public class BackupService
List<string> currentProfilePaths; List<string> currentProfilePaths;
try try
{ {
currentProfilePaths = _fileUtil.GetFiles(_profileDir); currentProfilePaths = FileUtil.GetFiles(_profileDir);
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Debug($"Skipping profile backup: Unable to read profiles directory, {ex.Message}"); Logger.Debug($"Skipping profile backup: Unable to read profiles directory, {ex.Message}");
return; return;
} }
if (currentProfilePaths.Count == 0) if (currentProfilePaths.Count == 0)
{ {
if (_logger.IsLogEnabled(LogLevel.Debug)) if (Logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug("No profiles to backup"); Logger.Debug("No profiles to backup");
} }
return; return;
@@ -113,33 +114,33 @@ public class BackupService
try try
{ {
_fileUtil.CreateDirectory(targetDir); FileUtil.CreateDirectory(targetDir);
foreach (var profilePath in currentProfilePaths) foreach (var profilePath in currentProfilePaths)
{ {
// Get filename + extension, removing the path // Get filename + extension, removing the path
var profileFileName = _fileUtil.GetFileNameAndExtension(profilePath); var profileFileName = FileUtil.GetFileNameAndExtension(profilePath);
// Create absolute path to file // Create absolute path to file
var relativeSourceFilePath = Path.Combine(_profileDir, profileFileName); var relativeSourceFilePath = Path.Combine(_profileDir, profileFileName);
var absoluteDestinationFilePath = Path.Combine(targetDir, profileFileName); var absoluteDestinationFilePath = Path.Combine(targetDir, profileFileName);
if (!_fileUtil.CopyFile(relativeSourceFilePath, absoluteDestinationFilePath)) if (!FileUtil.CopyFile(relativeSourceFilePath, absoluteDestinationFilePath))
{ {
_logger.Error($"Source file not found: {relativeSourceFilePath}. Cannot copy to: {absoluteDestinationFilePath}"); Logger.Error($"Source file not found: {relativeSourceFilePath}. Cannot copy to: {absoluteDestinationFilePath}");
} }
} }
// Write a copy of active mods. // Write a copy of active mods.
await _fileUtil.WriteFileAsync(Path.Combine(targetDir, "activeMods.json"), _jsonUtil.Serialize(_activeServerMods)); await FileUtil.WriteFileAsync(Path.Combine(targetDir, "activeMods.json"), JsonUtil.Serialize(_activeServerMods));
if (_logger.IsLogEnabled(LogLevel.Debug)) if (Logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"Profile backup created in: {targetDir}"); Logger.Debug($"Profile backup created in: {targetDir}");
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error($"Unable to write to backup profile directory: {ex.Message}"); Logger.Error($"Unable to write to backup profile directory: {ex.Message}");
return; return;
} }
@@ -157,9 +158,9 @@ public class BackupService
return true; return true;
} }
if (_logger.IsLogEnabled(LogLevel.Debug)) if (Logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug("Profile backups disabled"); Logger.Debug("Profile backups disabled");
} }
return false; return false;
@@ -182,7 +183,7 @@ public class BackupService
/// <returns> The formatted backup date string. </returns> /// <returns> The formatted backup date string. </returns>
protected string GenerateBackupDate() protected string GenerateBackupDate()
{ {
return _timeUtil.GetDateTimeNow().ToString("yyyy-MM-dd_HH-mm-ss"); return TimeUtil.GetDateTimeNow().ToString("yyyy-MM-dd_HH-mm-ss");
} }
/// <summary> /// <summary>
@@ -229,7 +230,7 @@ public class BackupService
/// <returns> List of sorted backup file paths. </returns> /// <returns> List of sorted backup file paths. </returns>
protected List<string> GetBackupPaths(string dir) protected List<string> GetBackupPaths(string dir)
{ {
var backups = _fileUtil.GetDirectories(dir).ToList(); var backups = FileUtil.GetDirectories(dir).ToList();
backups.Sort(CompareBackupDates); backups.Sort(CompareBackupDates);
return backups; return backups;
@@ -269,7 +270,7 @@ public class BackupService
return dateTime; return dateTime;
} }
_logger.Warning($"Invalid backup folder name format: {folderPath}, [{folderName}]"); Logger.Warning($"Invalid backup folder name format: {folderPath}, [{folderName}]");
return null; return null;
} }
@@ -283,11 +284,11 @@ public class BackupService
var filePathsToDelete = backupFilenames.Select(x => x); var filePathsToDelete = backupFilenames.Select(x => x);
foreach (var pathToDelete in filePathsToDelete) foreach (var pathToDelete in filePathsToDelete)
{ {
_fileUtil.DeleteDirectory(Path.Combine(pathToDelete), true); FileUtil.DeleteDirectory(Path.Combine(pathToDelete), true);
if (_logger.IsLogEnabled(LogLevel.Debug)) if (Logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"Deleted old backup: {pathToDelete}"); Logger.Debug($"Deleted old backup: {pathToDelete}");
} }
} }
} }
@@ -300,7 +301,7 @@ public class BackupService
{ {
List<string> result = []; List<string> result = [];
foreach (var mod in _loadedMods) foreach (var mod in LoadedMods)
{ {
result.Add($"{mod.ModMetadata.Author} - {mod.ModMetadata.Version}"); result.Add($"{mod.ModMetadata.Author} - {mod.ModMetadata.Version}");
} }
+36 -39
View File
@@ -2,7 +2,6 @@ using Microsoft.Extensions.Hosting;
using SPTarkov.DI.Annotations; using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.DI; using SPTarkov.Server.Core.DI;
using SPTarkov.Server.Core.Extensions; using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Models.Utils; using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers; using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services; using SPTarkov.Server.Core.Services;
@@ -13,47 +12,45 @@ namespace SPTarkov.Server.Core.Utils;
[Injectable(InjectionType.Singleton)] [Injectable(InjectionType.Singleton)]
public class App( public class App(
IServiceProvider _serviceProvider, IServiceProvider serviceProvider,
ISptLogger<App> _logger, ISptLogger<App> logger,
TimeUtil _timeUtil, TimeUtil timeUtil,
RandomUtil _randomUtil, RandomUtil randomUtil,
ServerLocalisationService _serverLocalisationService, ServerLocalisationService serverLocalisationService,
ConfigServer _configServer, HttpServer httpServer,
HttpServer _httpServer, DatabaseService databaseService,
DatabaseService _databaseService, IHostApplicationLifetime appLifeTime,
IHostApplicationLifetime _appLifeTime, IEnumerable<IOnLoad> onLoadComponents,
IEnumerable<IOnLoad> _onLoadComponents, IEnumerable<IOnUpdate> onUpdateComponents
IEnumerable<IOnUpdate> _onUpdateComponents
) )
{ {
protected readonly CoreConfig _coreConfig = _configServer.GetConfig<CoreConfig>();
protected readonly Dictionary<string, long> _onUpdateLastRun = new(); protected readonly Dictionary<string, long> _onUpdateLastRun = new();
public async Task InitializeAsync() public async Task InitializeAsync()
{ {
ServiceLocator.SetServiceProvider(_serviceProvider); ServiceLocator.SetServiceProvider(serviceProvider);
if (_logger.IsLogEnabled(LogLevel.Debug)) if (logger.IsLogEnabled(LogLevel.Debug))
{ {
_logger.Debug($"OS: {Environment.OSVersion.Version} | {Environment.OSVersion.Platform}"); logger.Debug($"OS: {Environment.OSVersion.Version} | {Environment.OSVersion.Platform}");
_logger.Debug($"Ran as admin: {Environment.IsPrivilegedProcess}"); logger.Debug($"Ran as admin: {Environment.IsPrivilegedProcess}");
_logger.Debug($"CPU cores: {Environment.ProcessorCount}"); logger.Debug($"CPU cores: {Environment.ProcessorCount}");
_logger.Debug($"PATH: {(Environment.ProcessPath ?? "null returned").Encode(EncodeType.BASE64)}"); logger.Debug($"PATH: {(Environment.ProcessPath ?? "null returned").Encode(EncodeType.BASE64)}");
_logger.Debug($"Server: {ProgramStatics.SPT_VERSION()}"); logger.Debug($"Server: {ProgramStatics.SPT_VERSION()}");
// _logger.Debug($"RAM: {(os.totalmem() / 1024 / 1024 / 1024).toFixed(2)}GB"); // _logger.Debug($"RAM: {(os.totalmem() / 1024 / 1024 / 1024).toFixed(2)}GB");
if (ProgramStatics.BUILD_TIME() != 0) if (ProgramStatics.BUILD_TIME() != 0)
{ {
_logger.Debug($"Date: {ProgramStatics.BUILD_TIME()}"); logger.Debug($"Date: {ProgramStatics.BUILD_TIME()}");
} }
_logger.Debug($"Commit: {ProgramStatics.COMMIT()}"); logger.Debug($"Commit: {ProgramStatics.COMMIT()}");
} }
// execute onLoad callbacks // execute onLoad callbacks
_logger.Info(_serverLocalisationService.GetText("executing_startup_callbacks")); logger.Info(serverLocalisationService.GetText("executing_startup_callbacks"));
foreach (var onLoad in _onLoadComponents) foreach (var onLoad in onLoadComponents)
{ {
await onLoad.OnLoad(); await onLoad.OnLoad();
} }
@@ -61,36 +58,36 @@ public class App(
// Discard here, as this task will run indefinitely // Discard here, as this task will run indefinitely
_ = Task.Run(Update); _ = Task.Run(Update);
_logger.Success(_serverLocalisationService.GetText("started_webserver_success", _httpServer.ListeningUrl())); logger.Success(serverLocalisationService.GetText("started_webserver_success", httpServer.ListeningUrl()));
_logger.Success(_serverLocalisationService.GetText("websocket-started", _httpServer.ListeningUrl().Replace("https://", "wss://"))); logger.Success(serverLocalisationService.GetText("websocket-started", httpServer.ListeningUrl().Replace("https://", "wss://")));
_logger.Success(GetRandomisedStartMessage()); logger.Success(GetRandomisedStartMessage());
} }
protected string GetRandomisedStartMessage() protected string GetRandomisedStartMessage()
{ {
if (_randomUtil.GetInt(1, 1000) > 999) if (randomUtil.GetInt(1, 1000) > 999)
{ {
return _serverLocalisationService.GetRandomTextThatMatchesPartialKey("server_start_meme_"); return serverLocalisationService.GetRandomTextThatMatchesPartialKey("server_start_meme_");
} }
return _serverLocalisationService.GetText("server_start_success"); return serverLocalisationService.GetText("server_start_success");
} }
protected async Task Update() protected async Task Update()
{ {
while (!_appLifeTime.ApplicationStopping.IsCancellationRequested) while (!appLifeTime.ApplicationStopping.IsCancellationRequested)
{ {
// If the server has failed to start, skip any update calls // If the server has failed to start, skip any update calls
if (!_databaseService.IsDatabaseValid()) if (!databaseService.IsDatabaseValid())
{ {
await Task.Delay(5000, _appLifeTime.ApplicationStopping); await Task.Delay(5000, appLifeTime.ApplicationStopping);
// Skip forward to the next loop // Skip forward to the next loop
continue; continue;
} }
foreach (var updateable in _onUpdateComponents) foreach (var updateable in onUpdateComponents)
{ {
var updateableName = updateable.GetType().FullName; var updateableName = updateable.GetType().FullName;
if (string.IsNullOrEmpty(updateableName)) if (string.IsNullOrEmpty(updateableName))
@@ -99,13 +96,13 @@ public class App(
} }
var lastRunTimeTimestamp = _onUpdateLastRun.GetValueOrDefault(updateableName, 0); var lastRunTimeTimestamp = _onUpdateLastRun.GetValueOrDefault(updateableName, 0);
var secondsSinceLastRun = _timeUtil.GetTimeStamp() - lastRunTimeTimestamp; var secondsSinceLastRun = timeUtil.GetTimeStamp() - lastRunTimeTimestamp;
try try
{ {
if (await updateable.OnUpdate(secondsSinceLastRun)) if (await updateable.OnUpdate(secondsSinceLastRun))
{ {
_onUpdateLastRun[updateableName] = _timeUtil.GetTimeStamp(); _onUpdateLastRun[updateableName] = timeUtil.GetTimeStamp();
} }
} }
catch (Exception err) catch (Exception err)
@@ -114,13 +111,13 @@ public class App(
} }
} }
await Task.Delay(5000, _appLifeTime.ApplicationStopping); await Task.Delay(5000, appLifeTime.ApplicationStopping);
} }
} }
protected void LogUpdateException(Exception err, IOnUpdate updateable) protected void LogUpdateException(Exception err, IOnUpdate updateable)
{ {
_logger.Error(_serverLocalisationService.GetText("scheduled_event_failed_to_run", updateable.GetType().FullName)); logger.Error(serverLocalisationService.GetText("scheduled_event_failed_to_run", updateable.GetType().FullName));
_logger.Error(err.ToString()); logger.Error(err.ToString());
} }
} }
@@ -10,7 +10,7 @@ using SPTarkov.Server.Core.Utils.Json;
namespace SPTarkov.Server.Core.Utils; namespace SPTarkov.Server.Core.Utils;
[Injectable(InjectionType.Singleton)] [Injectable(InjectionType.Singleton)]
public class ImporterUtil(ISptLogger<ImporterUtil> _logger, FileUtil _fileUtil, JsonUtil _jsonUtil) public class ImporterUtil(ISptLogger<ImporterUtil> logger, FileUtil fileUtil, JsonUtil jsonUtil)
{ {
private readonly FrozenSet<string> _directoriesToIgnore = ["./SPT_Data/database/locales/server"]; private readonly FrozenSet<string> _directoriesToIgnore = ["./SPT_Data/database/locales/server"];
private readonly FrozenSet<string> _filesToIgnore = ["bearsuits.json", "usecsuits.json", "archivedquests.json"]; private readonly FrozenSet<string> _filesToIgnore = ["bearsuits.json", "usecsuits.json", "archivedquests.json"];
@@ -46,15 +46,15 @@ public class ImporterUtil(ISptLogger<ImporterUtil> _logger, FileUtil _fileUtil,
var result = Activator.CreateInstance(loadedType); var result = Activator.CreateInstance(loadedType);
// get all filepaths // get all filepaths
var files = _fileUtil.GetFiles(filePath); var files = fileUtil.GetFiles(filePath);
var directories = _fileUtil.GetDirectories(filePath); var directories = fileUtil.GetDirectories(filePath);
// Process files // Process files
foreach (var file in files) foreach (var file in files)
{ {
if ( if (
_fileUtil.GetFileExtension(file) != "json" fileUtil.GetFileExtension(file) != "json"
|| _filesToIgnore.Contains(_fileUtil.GetFileNameAndExtension(file).ToLowerInvariant()) || _filesToIgnore.Contains(fileUtil.GetFileNameAndExtension(file).ToLowerInvariant())
) )
{ {
continue; continue;
@@ -98,7 +98,7 @@ public class ImporterUtil(ISptLogger<ImporterUtil> _logger, FileUtil _fileUtil,
// Get the set method to update the object // Get the set method to update the object
var setMethod = GetSetMethod( var setMethod = GetSetMethod(
_fileUtil.StripExtension(file).ToLowerInvariant(), fileUtil.StripExtension(file).ToLowerInvariant(),
loadedType, loadedType,
out var propertyType, out var propertyType,
out var isDictionary out var isDictionary
@@ -113,7 +113,7 @@ public class ImporterUtil(ISptLogger<ImporterUtil> _logger, FileUtil _fileUtil,
lock (dictionaryLock) lock (dictionaryLock)
{ {
setMethod.Invoke(result, isDictionary ? [_fileUtil.StripExtension(file), fileDeserialized] : [fileDeserialized]); setMethod.Invoke(result, isDictionary ? [fileUtil.StripExtension(file), fileDeserialized] : [fileDeserialized]);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -179,7 +179,7 @@ public class ImporterUtil(ISptLogger<ImporterUtil> _logger, FileUtil _fileUtil,
return CreateLazyLoadDeserialization(file, propertyType); return CreateLazyLoadDeserialization(file, propertyType);
} }
return await _jsonUtil.DeserializeFromFileAsync(file, propertyType); return await jsonUtil.DeserializeFromFileAsync(file, propertyType);
} }
private object CreateLazyLoadDeserialization(string file, Type propertyType) private object CreateLazyLoadDeserialization(string file, Type propertyType)
@@ -187,7 +187,7 @@ public class ImporterUtil(ISptLogger<ImporterUtil> _logger, FileUtil _fileUtil,
var genericArgument = propertyType.GetGenericArguments()[0]; var genericArgument = propertyType.GetGenericArguments()[0];
var deserializeCall = Expression.Call( var deserializeCall = Expression.Call(
Expression.Constant(_jsonUtil), Expression.Constant(jsonUtil),
"DeserializeFromFile", "DeserializeFromFile",
Type.EmptyTypes, Type.EmptyTypes,
Expression.Constant(file), Expression.Constant(file),
@@ -220,14 +220,14 @@ public class ImporterUtil(ISptLogger<ImporterUtil> _logger, FileUtil _fileUtil,
.FirstOrDefault(prop => .FirstOrDefault(prop =>
string.Equals( string.Equals(
prop.Name.ToLowerInvariant(), prop.Name.ToLowerInvariant(),
_fileUtil.StripExtension(propertyName).ToLowerInvariant(), fileUtil.StripExtension(propertyName).ToLowerInvariant(),
StringComparison.Ordinal StringComparison.Ordinal
) )
); );
if (matchedProperty == null) if (matchedProperty == null)
{ {
throw new Exception($"Unable to find property '{_fileUtil.StripExtension(propertyName)}' for type '{type.Name}'"); throw new Exception($"Unable to find property '{fileUtil.StripExtension(propertyName)}' for type '{type.Name}'");
} }
propertyType = matchedProperty.PropertyType; propertyType = matchedProperty.PropertyType;
@@ -12,10 +12,10 @@ namespace SPTarkov.Server.Core.Utils;
[Injectable(InjectionType.Singleton)] [Injectable(InjectionType.Singleton)]
public class RagfairOfferHolder( public class RagfairOfferHolder(
ISptLogger<RagfairOfferHolder> _logger, ISptLogger<RagfairOfferHolder> logger,
RagfairServerHelper _ragfairServerHelper, RagfairServerHelper ragfairServerHelper,
ServerLocalisationService _serverLocalisationService, ServerLocalisationService serverLocalisationService,
ItemHelper _itemHelper ItemHelper itemHelper
) )
{ {
/// <summary> /// <summary>
@@ -146,7 +146,7 @@ public class RagfairOfferHolder(
!itemTpl.IsEmpty // Has tpl !itemTpl.IsEmpty // Has tpl
&& offer.IsFakePlayerOffer() && offer.IsFakePlayerOffer()
&& _fakePlayerOffers.TryGetValue(itemTpl, out var offers) && _fakePlayerOffers.TryGetValue(itemTpl, out var offers)
&& offers?.Count >= _ragfairServerHelper.GetOfferCountByBaseType(_itemHelper.GetItem(itemTpl).Value.Parent) && offers?.Count >= ragfairServerHelper.GetOfferCountByBaseType(itemHelper.GetItem(itemTpl).Value.Parent)
) )
{ {
// If it is an NPC PMC offer AND we have already reached the maximum amount of possible offers // If it is an NPC PMC offer AND we have already reached the maximum amount of possible offers
@@ -156,7 +156,7 @@ public class RagfairOfferHolder(
if (!_offersById.TryAdd(offer.Id, offer)) if (!_offersById.TryAdd(offer.Id, offer))
{ {
_logger.Warning($"Offer: {offer.Id} already exists"); logger.Warning($"Offer: {offer.Id} already exists");
} }
if (offer.IsTraderOffer()) if (offer.IsTraderOffer())
@@ -182,14 +182,14 @@ public class RagfairOfferHolder(
{ {
if (!_offersById.TryGetValue(offerId, out var offer)) if (!_offersById.TryGetValue(offerId, out var offer))
{ {
_logger.Warning(_serverLocalisationService.GetText("ragfair-unable_to_remove_offer_doesnt_exist", offerId)); logger.Warning(serverLocalisationService.GetText("ragfair-unable_to_remove_offer_doesnt_exist", offerId));
return; return;
} }
if (!_offersById.TryRemove(offer.Id, out _)) if (!_offersById.TryRemove(offer.Id, out _))
{ {
_logger.Warning($"Unable to remove offer by id: {offer.Id} not found"); logger.Warning($"Unable to remove offer by id: {offer.Id} not found");
} }
if (checkTraderOffers && _offersByTrader.TryGetValue(offer.User.Id, out var traderOfferIds)) if (checkTraderOffers && _offersByTrader.TryGetValue(offer.User.Id, out var traderOfferIds))
@@ -202,7 +202,7 @@ public class RagfairOfferHolder(
// Users with no offers were never cleaned up // Users with no offers were never cleaned up
if (!_offersByTrader.TryRemove(offer.User.Id, out _)) if (!_offersByTrader.TryRemove(offer.User.Id, out _))
{ {
_logger.Warning($"Unable to remove Trader offer: {offer.Id} not found"); logger.Warning($"Unable to remove Trader offer: {offer.Id} not found");
} }
} }
} }
@@ -235,7 +235,7 @@ public class RagfairOfferHolder(
{ {
if (!_offersById.TryRemove(offerId, out _)) if (!_offersById.TryRemove(offerId, out _))
{ {
_logger.Warning($"Unable to remove offer: {offerId}"); logger.Warning($"Unable to remove offer: {offerId}");
} }
} }
@@ -265,7 +265,7 @@ public class RagfairOfferHolder(
return true; return true;
} }
_logger.Warning($"Unable to add offer: {offerId} to _offersByTemplate"); logger.Warning($"Unable to add offer: {offerId} to _offersByTemplate");
return false; return false;
} }
@@ -292,7 +292,7 @@ public class RagfairOfferHolder(
return true; return true;
} }
_logger.Error($"Unable to add offer: {offerId} to _offersByTrader"); logger.Error($"Unable to add offer: {offerId} to _offersByTrader");
return false; return false;
} }
@@ -313,7 +313,7 @@ public class RagfairOfferHolder(
return true; return true;
} }
_logger.Error($"Unable to add offer: {offerId} to _fakePlayerOffers"); logger.Error($"Unable to add offer: {offerId} to _fakePlayerOffers");
return false; return false;
} }
@@ -328,7 +328,7 @@ public class RagfairOfferHolder(
{ {
if (!_expiredOfferIds.Add(staleOfferId)) if (!_expiredOfferIds.Add(staleOfferId))
{ {
_logger.Warning($"Unable to add offer: {staleOfferId} to expired offers"); logger.Warning($"Unable to add offer: {staleOfferId} to expired offers");
} }
} }
} }
@@ -364,13 +364,13 @@ public class RagfairOfferHolder(
var offer = GetOfferById(expiredOfferId); var offer = GetOfferById(expiredOfferId);
if (offer is null) if (offer is null)
{ {
_logger.Warning($"Expired offerId: {expiredOfferId} not found, skipping"); logger.Warning($"Expired offerId: {expiredOfferId} not found, skipping");
continue; continue;
} }
if (offer.Items?.Count == 0) if (offer.Items?.Count == 0)
{ {
_logger.Error($"Expired offerId: {expiredOfferId} has no items, skipping"); logger.Error($"Expired offerId: {expiredOfferId} has no items, skipping");
continue; continue;
} }
@@ -401,7 +401,7 @@ public class RagfairOfferHolder(
{ {
foreach (var offer in GetOffers()) foreach (var offer in GetOffers())
{ {
if (_expiredOfferIds.Contains(offer.Id) || _ragfairServerHelper.IsTrader(offer.User.Id)) if (_expiredOfferIds.Contains(offer.Id) || ragfairServerHelper.IsTrader(offer.User.Id))
{ {
// Already flagged or trader offer (handled separately), skip // Already flagged or trader offer (handled separately), skip
continue; continue;
@@ -411,7 +411,7 @@ public class RagfairOfferHolder(
{ {
if (!_expiredOfferIds.Add(offer.Id)) if (!_expiredOfferIds.Add(offer.Id))
{ {
_logger.Warning($"Unable to add offer: {offer.Id} to expired offers as it already exists"); logger.Warning($"Unable to add offer: {offer.Id} to expired offers as it already exists");
} }
} }
} }
@@ -7,7 +7,7 @@ namespace SPTarkov.Server.Core.Utils;
// TODO: Finish porting this class // TODO: Finish porting this class
[Injectable(InjectionType.Singleton)] [Injectable(InjectionType.Singleton)]
public class RandomUtil(ISptLogger<RandomUtil> _logger, ICloner _cloner) public class RandomUtil(ISptLogger<RandomUtil> logger, ICloner cloner)
{ {
private const int DecimalPointRandomPrecision = 6; private const int DecimalPointRandomPrecision = 6;
@@ -257,7 +257,7 @@ public class RandomUtil(ISptLogger<RandomUtil> _logger, ICloner _cloner)
if (!replacement) if (!replacement)
{ {
list = _cloner.Clone(originalList); list = cloner.Clone(originalList);
// Adjust drawCount to avoid drawing more elements than available // Adjust drawCount to avoid drawing more elements than available
if (drawCount > list.Count) if (drawCount > list.Count)
{ {
@@ -324,13 +324,13 @@ public class RandomUtil(ISptLogger<RandomUtil> _logger, ICloner _cloner)
if (max < min) if (max < min)
{ {
_logger.Error($"Invalid argument, Bounded random number generation max is smaller than min({max} < {min}"); logger.Error($"Invalid argument, Bounded random number generation max is smaller than min({max} < {min}");
return -1; return -1;
} }
if (n < 1) if (n < 1)
{ {
_logger.Error($"Invalid argument, 'n' must be 1 or greater(received {n})"); logger.Error($"Invalid argument, 'n' must be 1 or greater(received {n})");
return -1; return -1;
} }
@@ -346,10 +346,10 @@ public class RandomUtil(ISptLogger<RandomUtil> _logger, ICloner _cloner)
// A shift that is equal to the available range only has a 50% chance of rolling correctly, theoretically halving performance. // A shift that is equal to the available range only has a 50% chance of rolling correctly, theoretically halving performance.
// Shifting even further drops the success chance very rapidly - so we want to warn against that // Shifting even further drops the success chance very rapidly - so we want to warn against that
_logger.Warning( logger.Warning(
"Bias shift for random number generation is greater than the range of available numbers. This will have a severe performance impact" "Bias shift for random number generation is greater than the range of available numbers. This will have a severe performance impact"
); );
_logger.Warning($"min-> {min}; max-> {max}; shift-> {shift}"); logger.Warning($"min-> {min}; max-> {max}; shift-> {shift}");
} }
var biasedMin = shift >= 0 ? min - shift : min; var biasedMin = shift >= 0 ? min - shift : min;
+2 -2
View File
@@ -6,9 +6,9 @@ using SPTarkov.Server.Core.Utils.Cloners;
namespace UnitTests.Mock; namespace UnitTests.Mock;
[Injectable(TypeOverride = typeof(RandomUtil))] [Injectable(TypeOverride = typeof(RandomUtil))]
public class MockRandomUtil(ISptLogger<RandomUtil> _logger, ICloner _cloner) : RandomUtil(_logger, _cloner) public class MockRandomUtil(ISptLogger<RandomUtil> logger, ICloner cloner) : RandomUtil(logger, cloner)
{ {
public override int GetInt(int min, int max = Int32.MaxValue, bool exclusive = false) public override int GetInt(int min, int max = int.MaxValue, bool exclusive = false)
{ {
return min; return min;
} }
@@ -13,12 +13,12 @@ namespace HideoutCraftQuestIdGenerator;
[Injectable] [Injectable]
public class HideoutCraftQuestIdGenerator( public class HideoutCraftQuestIdGenerator(
ISptLogger<HideoutCraftQuestIdGenerator> _logger, ISptLogger<HideoutCraftQuestIdGenerator> logger,
FileUtil _fileUtil, FileUtil fileUtil,
JsonUtil _jsonUtil, JsonUtil jsonUtil,
DatabaseServer _databaseServer, DatabaseServer databaseServer,
ItemHelper _itemHelper, ItemHelper itemHelper,
DatabaseImporter _databaseImporter DatabaseImporter databaseImporter
) )
{ {
private static readonly HashSet<MongoId> _blacklistedProductions = private static readonly HashSet<MongoId> _blacklistedProductions =
@@ -41,7 +41,7 @@ public class HideoutCraftQuestIdGenerator(
public async Task Run() public async Task Run()
{ {
await _databaseImporter.OnLoad(); await databaseImporter.OnLoad();
// Build up our dataset // Build up our dataset
BuildQuestProductionList(); BuildQuestProductionList();
@@ -52,14 +52,14 @@ public class HideoutCraftQuestIdGenerator(
const string productionPath = "Libraries\\SPTarkov.Server.Assets\\SPT_Data\\database\\hideout\\production.json"; const string productionPath = "Libraries\\SPTarkov.Server.Assets\\SPT_Data\\database\\hideout\\production.json";
var productionFilePath = Path.Combine(projectDir.FullName, productionPath); var productionFilePath = Path.Combine(projectDir.FullName, productionPath);
var updatedProductionJson = _jsonUtil.Serialize(_databaseServer.GetTables().Hideout.Production, true); var updatedProductionJson = jsonUtil.Serialize(databaseServer.GetTables().Hideout.Production, true);
await _fileUtil.WriteFileAsync(productionFilePath, updatedProductionJson); await fileUtil.WriteFileAsync(productionFilePath, updatedProductionJson);
} }
// Build a list of all quests and what production they unlock // Build a list of all quests and what production they unlock
private void BuildQuestProductionList() private void BuildQuestProductionList()
{ {
foreach (var (questId, quest) in _databaseServer.GetTables().Templates.Quests) foreach (var (questId, quest) in databaseServer.GetTables().Templates.Quests)
{ {
var combinedRewards = CombineRewards(quest.Rewards).Where(x => x.Type == RewardType.ProductionScheme).ToList(); var combinedRewards = CombineRewards(quest.Rewards).Where(x => x.Type == RewardType.ProductionScheme).ToList();
foreach (var reward in combinedRewards) foreach (var reward in combinedRewards)
@@ -78,7 +78,7 @@ public class HideoutCraftQuestIdGenerator(
{ {
if (item.Template != output.ItemTemplate) if (item.Template != output.ItemTemplate)
{ {
_logger.Error($"Production scheme has multiple output items. " + $"{output.ItemTemplate} != {item.Template}"); logger.Error($"Production scheme has multiple output items. " + $"{output.ItemTemplate} != {item.Template}");
continue; continue;
} }
@@ -94,12 +94,12 @@ public class HideoutCraftQuestIdGenerator(
private void UpdateProductionQuests() private void UpdateProductionQuests()
{ {
// Loop through all productions, and try to associate any with a `QuestComplete` type with its quest // Loop through all productions, and try to associate any with a `QuestComplete` type with its quest
foreach (var production in _databaseServer.GetTables().Hideout.Production.Recipes) foreach (var production in databaseServer.GetTables().Hideout.Production.Recipes)
{ {
// Skip blacklisted productions // Skip blacklisted productions
if (_blacklistedProductions.Contains(production.Id)) if (_blacklistedProductions.Contains(production.Id))
{ {
_logger.Debug($"Skipped blacklisted production: {production.Id}"); logger.Debug($"Skipped blacklisted production: {production.Id}");
continue; continue;
} }
@@ -113,7 +113,7 @@ public class HideoutCraftQuestIdGenerator(
if (questCompleteRequirements.Count > 1) if (questCompleteRequirements.Count > 1)
{ {
_logger.Error($"Error, prodId: {production.Id} contains multiple QuestComplete requirements"); logger.Error($"Error, prodId: {production.Id} contains multiple QuestComplete requirements");
// Production has no multiple quest requirements // Production has no multiple quest requirements
continue; continue;
@@ -122,11 +122,11 @@ public class HideoutCraftQuestIdGenerator(
// Check for forced ids // Check for forced ids
if (_forcedQuestToProductionAssociations.TryGetValue(production.Id, out var associatedQuestIdToComplete)) if (_forcedQuestToProductionAssociations.TryGetValue(production.Id, out var associatedQuestIdToComplete))
{ {
var enLocale = _databaseServer.GetTables().Locales.Global["en"].Value; var enLocale = databaseServer.GetTables().Locales.Global["en"].Value;
var questName = enLocale[$"{associatedQuestIdToComplete} name"]; var questName = enLocale[$"{associatedQuestIdToComplete} name"];
// Found one, move to next production // Found one, move to next production
_logger.Success( logger.Success(
$"FORCED - Updated: prodId: {production.Id} endProd: {production.EndProduct} ({_itemHelper.GetItemName(production.EndProduct)}) with quantity: {production.Count} to quest: {associatedQuestIdToComplete} {questName}" $"FORCED - Updated: prodId: {production.Id} endProd: {production.EndProduct} ({itemHelper.GetItemName(production.EndProduct)}) with quantity: {production.Count} to quest: {associatedQuestIdToComplete} {questName}"
); );
questCompleteRequirements[0].QuestId = associatedQuestIdToComplete; questCompleteRequirements[0].QuestId = associatedQuestIdToComplete;
@@ -147,7 +147,7 @@ public class HideoutCraftQuestIdGenerator(
// Update the production quest ID // Update the production quest ID
_questProductionMap[questProductionOutputs[0].QuestId] = production.Id; _questProductionMap[questProductionOutputs[0].QuestId] = production.Id;
questCompleteRequirements[0].QuestId = questProductionOutputs[0].QuestId; questCompleteRequirements[0].QuestId = questProductionOutputs[0].QuestId;
_logger.Success( logger.Success(
$"Updated prodId: {production.Id}, endProd: {production.EndProduct} quantity: {production.Count} to quest: {questProductionOutputs[0].QuestId} {questProductionOutputs[0].QuestName}" $"Updated prodId: {production.Id}, endProd: {production.EndProduct} quantity: {production.Count} to quest: {questProductionOutputs[0].QuestId} {questProductionOutputs[0].QuestName}"
); );
} }
@@ -162,8 +162,8 @@ public class HideoutCraftQuestIdGenerator(
// A lot of error handling for edge cases // A lot of error handling for edge cases
if (!questProductionOutputs.Any()) if (!questProductionOutputs.Any())
{ {
_logger.Error( logger.Error(
$"Error: Unable to find matching quest for prodId: {production.Id}, endProduct: {production.EndProduct} ({_itemHelper.GetItemName(production.EndProduct)}) quantity: {production.Count}. Potential new or removed quest?" $"Error: Unable to find matching quest for prodId: {production.Id}, endProduct: {production.EndProduct} ({itemHelper.GetItemName(production.EndProduct)}) quantity: {production.Count}. Potential new or removed quest?"
); );
return false; return false;
} }
@@ -171,7 +171,7 @@ public class HideoutCraftQuestIdGenerator(
if (questProductionOutputs.Count > 1) if (questProductionOutputs.Count > 1)
{ {
var questNamesCSV = string.Join(",", questProductionOutputs.Select(x => x.QuestName)); var questNamesCSV = string.Join(",", questProductionOutputs.Select(x => x.QuestName));
_logger.Error( logger.Error(
$"Error: Multiple quests match prodId: {production.Id}, endProduct: {production.EndProduct} with quantity: {production.Count}, quests: {questNamesCSV}" $"Error: Multiple quests match prodId: {production.Id}, endProduct: {production.EndProduct} with quantity: {production.Count}, quests: {questNamesCSV}"
); );
return false; return false;
@@ -179,7 +179,7 @@ public class HideoutCraftQuestIdGenerator(
if (questComplete.QuestId is not null && questComplete.QuestId != questProductionOutputs[0].QuestId) if (questComplete.QuestId is not null && questComplete.QuestId != questProductionOutputs[0].QuestId)
{ {
_logger.Error( logger.Error(
$"Error: Multiple productions match quest. EndProduct: {production.EndProduct} with quantity {production.Count}, existing quest: {questComplete.QuestId} {questProductionOutputs[0].QuestName}" $"Error: Multiple productions match quest. EndProduct: {production.EndProduct} with quantity {production.Count}, existing quest: {questComplete.QuestId} {questProductionOutputs[0].QuestName}"
); );
@@ -188,11 +188,11 @@ public class HideoutCraftQuestIdGenerator(
if (_questProductionMap.ContainsKey(questProductionOutputs[0].QuestId)) if (_questProductionMap.ContainsKey(questProductionOutputs[0].QuestId))
{ {
var recipies = _databaseServer.GetTables().Hideout.Production.Recipes; var recipies = databaseServer.GetTables().Hideout.Production.Recipes;
var prodId = _questProductionMap[questProductionOutputs[0].QuestId]; var prodId = _questProductionMap[questProductionOutputs[0].QuestId];
var prod = recipies.FirstOrDefault(x => x.Id == prodId); var prod = recipies.FirstOrDefault(x => x.Id == prodId);
var prodItemName = _itemHelper.GetItemName(prod.EndProduct); var prodItemName = itemHelper.GetItemName(prod.EndProduct);
_logger.Warning( logger.Warning(
$"Error: Quest {questProductionOutputs[0].QuestId} {questProductionOutputs[0].QuestName} already associated with production: {prodId} {prodItemName}. Potential conflict" $"Error: Quest {questProductionOutputs[0].QuestId} {questProductionOutputs[0].QuestName} already associated with production: {prodId} {prodItemName}. Potential conflict"
); );
} }