Service sessionIDs to mongoIDs (#454)

* Start updating service sessionIDs to mongoIDs

* Finish service conversion + fix other small issues
This commit is contained in:
Cj
2025-07-06 08:08:07 -04:00
committed by GitHub
parent 03ec62d17d
commit d1af6bf6e3
43 changed files with 1159 additions and 1371 deletions
@@ -899,10 +899,9 @@ public class ItemHelper(
)
{
// Find required items to take after buying (handles multiple items)
var desiredBarterIds =
desiredBarterItemIds.GetType() == typeof(string)
? [(string)desiredBarterItemIds]
: (List<string>)desiredBarterItemIds;
var desiredBarterIds = desiredBarterItemIds is MongoId id
? [id]
: (List<MongoId>)desiredBarterItemIds;
List<Item> matchingItems = [];
foreach (var barterId in desiredBarterIds)
@@ -129,7 +129,7 @@ public class PrestigeHelper
itemsToTransfer.Add(item);
}
_mailSendService.SendSystemMessageToPlayer(sessionId, "", itemsToTransfer, 31536000);
_mailSendService.SendSystemMessageToPlayer(sessionId.Value, "", itemsToTransfer, 31536000);
newProfile.CharacterData.PmcData.Info.PrestigeLevel = prestige.PrestigeLevel;
}
@@ -97,7 +97,7 @@ public class TraderHelper(
/// </summary>
/// <param name="traderId">Trader to get assorts for</param>
/// <returns>TraderAssort</returns>
public TraderAssort GetTraderAssortsByTraderId(string traderId)
public TraderAssort GetTraderAssortsByTraderId(MongoId traderId)
{
return traderId == Traders.FENCE
? _fenceService.GetRawFenceAssorts()
@@ -110,7 +110,7 @@ public class TraderHelper(
/// <param name="traderId">Trader to get assorts for</param>
/// <param name="assortId">Id of assort to find</param>
/// <returns>Item object</returns>
public Item? GetTraderAssortItemByAssortId(string traderId, string assortId)
public Item? GetTraderAssortItemByAssortId(MongoId traderId, MongoId assortId)
{
var traderAssorts = GetTraderAssortsByTraderId(traderId);
if (traderAssorts is null)
@@ -33,7 +33,7 @@ public class BotEquipmentFilterService(
/// <param name="botLevel">Level of the bot</param>
/// <param name="botGenerationDetails">details on how to generate a bot</param>
public void FilterBotEquipment(
string sessionId,
MongoId sessionId,
BotType baseBotNode,
int botLevel,
BotGenerationDetails botGenerationDetails
@@ -215,7 +215,7 @@ public class BotEquipmentModPoolService(
/// </summary>
/// <param name="itemTpl"> Weapons tpl to look up mods for </param>
/// <returns> Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value </returns>
public Dictionary<string, HashSet<MongoId>>? GetRequiredModsForWeaponSlot(MongoId itemTpl)
public Dictionary<string, HashSet<MongoId>> GetRequiredModsForWeaponSlot(MongoId itemTpl)
{
var result = new Dictionary<string, HashSet<MongoId>>();
@@ -1,120 +0,0 @@
using System.Collections.Concurrent;
using SPTarkov.Common.Extensions;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Utils;
namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class BotGenerationCacheService(
ISptLogger<BotGenerationCacheService> _logger,
ServerLocalisationService _serverLocalisationService
)
{
protected readonly Queue<BotBase> _activeBotsInRaid = [];
protected readonly ConcurrentDictionary<string, List<BotBase>> _storedBots = new();
/// <summary>
/// Store list of bots in cache, shuffle results before storage
/// </summary>
/// <param name="key"> Role bot is stored as (assault/bossTagilla etc.) </param>
/// <param name="botsToStore"> Bots we want to store in the cache </param>
public void StoreBots(string key, List<BotBase> botsToStore)
{
foreach (var bot in botsToStore)
{
if (!_storedBots.TryAdd(key, [bot]))
{
_storedBots[key].Add(bot);
}
}
}
/// <summary>
/// Find and return a bot based on its role. <br />
/// Remove bot from internal list so it can't be retrieved again.
/// </summary>
/// <param name="key"> role to retrieve (assault/bossTagilla etc) </param>
/// <returns> BotBase object </returns>
public BotBase? GetBot(string key)
{
if (_storedBots.TryGetValue(key, out var bots))
{
if (bots.Count > 0)
{
try
{
return bots.PopLast();
}
catch (Exception e)
{
_logger.Error(
_serverLocalisationService.GetText(
"bot-cache_has_zero_bots_of_requested_type",
key
)
);
_logger.Error(e.StackTrace);
}
}
_logger.Error(
_serverLocalisationService.GetText("bot-cache_has_zero_bots_of_requested_type", key)
);
return null;
}
_logger.Warning(_serverLocalisationService.GetText("bot-no_bot_type_in_cache", key));
return null;
}
/// <summary>
/// Cache a bot that has been sent to the client in memory for later use post-raid to determine if player killed a traitor scav
/// </summary>
/// <param name="botToStore"> Bot object to store </param>
public void StoreUsedBot(BotBase botToStore)
{
_activeBotsInRaid.Enqueue(botToStore);
}
/// <summary>
/// Get a bot by its profileId that has been generated and sent to client for current raid. <br />
/// Cache is wiped post-raid in client/match/offline/end endOfflineRaid()
/// </summary>
/// <param name="profileId"> ID of bot to get </param>
/// <returns> BotBase object </returns>
public BotBase? GetUsedBot(string profileId)
{
return _activeBotsInRaid.FirstOrDefault(x => x.Id == profileId);
}
/// <summary>
/// Remove all cached bot profiles from memory
/// </summary>
public void ClearStoredBots()
{
_storedBots.Clear();
_activeBotsInRaid.Clear();
}
/// <summary>
/// Does cache have a bot with requested key
/// </summary>
/// <returns> False if empty </returns>
public bool CacheHasBotWithKey(string key, int size = 0)
{
return _storedBots.ContainsKey(key) && _storedBots[key].Count > size;
}
public int GetCachedBotCount(string key)
{
return _storedBots.TryGetValue(key, out var bot) ? bot.Count : 0;
}
public string CreateCacheKey(string? role, string? difficulty)
{
return $"{role?.ToLowerInvariant()}{difficulty?.ToLowerInvariant()}";
}
}
@@ -13,11 +13,11 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class BotLootCacheService(
ISptLogger<BotLootCacheService> _logger,
ItemHelper _itemHelper,
PMCLootGenerator _pmcLootGenerator,
ServerLocalisationService _serverLocalisationService,
ICloner _cloner
ISptLogger<BotLootCacheService> logger,
ItemHelper itemHelper,
PMCLootGenerator pmcLootGenerator,
ServerLocalisationService serverLocalisationService,
ICloner cloner
)
{
protected readonly ConcurrentDictionary<string, BotLootCache> _lootCache = new();
@@ -64,7 +64,7 @@ public class BotLootCacheService(
if (!_lootCache.TryGetValue(botRole, out var botRoleCache))
{
_logger.Error($"Unable to find: {botRole} in loot cache");
logger.Error($"Unable to find: {botRole} in loot cache");
return [];
}
@@ -111,8 +111,8 @@ public class BotLootCacheService(
result = botRoleCache.StimItems;
break;
default:
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"bot-loot_type_not_found",
new
{
@@ -135,13 +135,13 @@ public class BotLootCacheService(
if (itemPriceMinMax is null)
{
// No filtering requested, exit
return _cloner.Clone(result);
return cloner.Clone(result);
}
// Filter the loot pool prior to returning
var filteredResult = result.Where(i =>
{
var itemPrice = _itemHelper.GetItemPrice(i.Key);
var itemPrice = itemHelper.GetItemPrice(i.Key);
if (itemPriceMinMax?.Min is not null && itemPriceMinMax?.Max is not null)
{
return itemPrice >= itemPriceMinMax?.Min && itemPrice <= itemPriceMinMax?.Max;
@@ -160,7 +160,7 @@ public class BotLootCacheService(
return false;
});
return _cloner.Clone(filteredResult.ToDictionary(pair => pair.Key, pair => pair.Value));
return cloner.Clone(filteredResult.ToDictionary(pair => pair.Key, pair => pair.Value));
}
/// <summary>
@@ -185,13 +185,9 @@ public class BotLootCacheService(
if (isPmc)
{
// Replace lootPool from bot json with our own generated list for PMCs
lootPool.Backpack = _cloner.Clone(
_pmcLootGenerator.GeneratePMCBackpackLootPool(botRole)
);
lootPool.Pockets = _cloner.Clone(_pmcLootGenerator.GeneratePMCPocketLootPool(botRole));
lootPool.TacticalVest = _cloner.Clone(
_pmcLootGenerator.GeneratePMCVestLootPool(botRole)
);
lootPool.Backpack = cloner.Clone(pmcLootGenerator.GeneratePMCBackpackLootPool(botRole));
lootPool.Pockets = cloner.Clone(pmcLootGenerator.GeneratePMCPocketLootPool(botRole));
lootPool.TacticalVest = cloner.Clone(pmcLootGenerator.GeneratePMCVestLootPool(botRole));
}
// Backpack/Pockets etc
@@ -231,7 +227,7 @@ public class BotLootCacheService(
AddItemsToPool(backpackLootPool, itemPool);
break;
default:
_logger.Warning($"How did you get here {containerType}");
logger.Warning($"How did you get here {containerType}");
break;
}
@@ -255,7 +251,7 @@ public class BotLootCacheService(
// No whitelist, find and assign from combined item pool
foreach (var itemKvP in specialLootPool)
{
var itemTemplate = _itemHelper.GetItem(itemKvP.Key).Value;
var itemTemplate = itemHelper.GetItem(itemKvP.Key).Value;
if (
!(
IsBulletOrGrenade(itemTemplate.Properties)
@@ -295,7 +291,7 @@ public class BotLootCacheService(
foreach (var itemKvP in combinedLootPool)
{
var itemTemplate = _itemHelper.GetItem(itemKvP.Key).Value;
var itemTemplate = itemHelper.GetItem(itemKvP.Key).Value;
if (itemTemplate is null)
{
continue;
@@ -333,7 +329,7 @@ public class BotLootCacheService(
if (addFoodItems)
{
if (_itemHelper.IsOfBaseclass(itemTemplate.Id, BaseClasses.FOOD))
if (itemHelper.IsOfBaseclass(itemTemplate.Id, BaseClasses.FOOD))
{
lock (_foodLock)
{
@@ -344,7 +340,7 @@ public class BotLootCacheService(
if (addDrinkItems)
{
if (_itemHelper.IsOfBaseclass(itemTemplate.Id, BaseClasses.DRINK))
if (itemHelper.IsOfBaseclass(itemTemplate.Id, BaseClasses.DRINK))
{
lock (_drinkLock)
{
@@ -355,7 +351,7 @@ public class BotLootCacheService(
if (addCurrencyItems)
{
if (_itemHelper.IsOfBaseclass(itemTemplate.Id, BaseClasses.MONEY))
if (itemHelper.IsOfBaseclass(itemTemplate.Id, BaseClasses.MONEY))
{
lock (_currencyLock)
{
@@ -423,7 +419,7 @@ public class BotLootCacheService(
var filteredVestItems = new Dictionary<MongoId, double>();
foreach (var itemKvP in vestLootPool)
{
var itemResult = _itemHelper.GetItem(itemKvP.Key);
var itemResult = itemHelper.GetItem(itemKvP.Key);
if (itemResult.Value is null)
{
continue;
@@ -455,7 +451,7 @@ public class BotLootCacheService(
if (!_lootCache.TryGetValue(botRole, out var cacheForRole))
{
_logger.Error($"Unable to get loot cache value using key: {botRole}");
logger.Error($"Unable to get loot cache value using key: {botRole}");
return;
}
@@ -488,7 +484,7 @@ public class BotLootCacheService(
var filteredItems = new Dictionary<MongoId, double>();
foreach (var (itemTpl, itemWeight) in lootPool)
{
var (isValidItem, itemTemplate) = _itemHelper.GetItem(itemTpl);
var (isValidItem, itemTemplate) = itemHelper.GetItem(itemTpl);
if (!isValidItem)
{
continue;
@@ -579,17 +575,17 @@ public class BotLootCacheService(
protected bool IsFood(MongoId tpl)
{
return _itemHelper.IsOfBaseclass(tpl, BaseClasses.FOOD);
return itemHelper.IsOfBaseclass(tpl, BaseClasses.FOOD);
}
protected bool IsDrink(MongoId tpl)
{
return _itemHelper.IsOfBaseclass(tpl, BaseClasses.DRINK);
return itemHelper.IsOfBaseclass(tpl, BaseClasses.DRINK);
}
protected bool IsCurrency(MongoId tpl)
{
return _itemHelper.IsOfBaseclass(tpl, BaseClasses.MONEY);
return itemHelper.IsOfBaseclass(tpl, BaseClasses.MONEY);
}
/// <summary>
@@ -12,16 +12,16 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class BotNameService(
ISptLogger<BotNameService> _logger,
BotHelper _botHelper,
RandomUtil _randomUtil,
ServerLocalisationService _serverLocalisationService,
DatabaseService _databaseService,
ConfigServer _configServer
ISptLogger<BotNameService> logger,
BotHelper botHelper,
RandomUtil randomUtil,
ServerLocalisationService serverLocalisationService,
DatabaseService databaseService,
ConfigServer configServer
)
{
protected readonly Lock _lockObject = new();
protected readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected readonly BotConfig _botConfig = configServer.GetConfig<BotConfig>();
protected readonly HashSet<string> _usedNameCache = new();
/// <summary>
@@ -60,11 +60,11 @@ public class BotNameService(
{
// Get bot name with leading/trailing whitespace removed
var name = isPmc.GetValueOrDefault(false) // Explicit handling of PMCs, all other bots will get "first_name last_name"
? _botHelper.GetPmcNicknameOfMaxLength(
? botHelper.GetPmcNicknameOfMaxLength(
_botConfig.BotNameLengthLimit,
botGenerationDetails.Side
)
: $"{_randomUtil.GetArrayValue(botJsonTemplate.FirstNames)} {(botJsonTemplate.LastNames.Count > 0 ? _randomUtil.GetArrayValue(botJsonTemplate.LastNames) : "")}";
: $"{randomUtil.GetArrayValue(botJsonTemplate.FirstNames)} {(botJsonTemplate.LastNames.Count > 0 ? randomUtil.GetArrayValue(botJsonTemplate.LastNames) : "")}";
name = name.Trim();
@@ -80,7 +80,7 @@ public class BotNameService(
&& botGenerationDetails.AllPmcsHaveSameNameAsPlayer.GetValueOrDefault(false)
)
{
var prefix = _serverLocalisationService.GetRandomTextThatMatchesPartialKey(
var prefix = serverLocalisationService.GetRandomTextThatMatchesPartialKey(
"pmc-name_prefix_"
);
name = $"{prefix} {name}";
@@ -97,10 +97,10 @@ public class BotNameService(
{
// 5 attempts to generate a name, pool probably isn't big enough
var genericName =
$"{botGenerationDetails.Side} {_randomUtil.GetInt(100000, 999999)}";
if (_logger.IsLogEnabled(LogLevel.Debug))
$"{botGenerationDetails.Side} {randomUtil.GetInt(100000, 999999)}";
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Failed to find unique name for: {botRole} {botGenerationDetails.Side} after 5 attempts, using: {genericName}"
);
}
@@ -158,12 +158,12 @@ public class BotNameService(
/// <returns>PMC name as string</returns>
protected string GetRandomPmcName()
{
var bots = _databaseService.GetBots().Types;
var bots = databaseService.GetBots().Types;
var pmcNames = new List<string>();
pmcNames.AddRange(bots["usec"].FirstNames);
pmcNames.AddRange(bots["bear"].FirstNames);
return _randomUtil.GetArrayValue(pmcNames);
return randomUtil.GetArrayValue(pmcNames);
}
}
@@ -1,5 +1,6 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Spt.Bots;
@@ -12,12 +13,12 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class BotWeaponModLimitService(
ISptLogger<BotWeaponModLimitService> _logger,
ConfigServer _configServer,
ItemHelper _itemHelper
ISptLogger<BotWeaponModLimitService> logger,
ConfigServer configServer,
ItemHelper itemHelper
)
{
protected readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected readonly BotConfig _botConfig = configServer.GetConfig<BotConfig>();
/// <summary>
/// Initalise mod limits to be used when generating a weapon
@@ -79,7 +80,7 @@ public class BotWeaponModLimitService(
// If weapon already has a longer ranged scope on it, allow ncstar to be spawned
if (
weapon.Any(item =>
_itemHelper.IsOfBaseclasses(
itemHelper.IsOfBaseclasses(
item.Template,
[
BaseClasses.ASSAULT_SCOPE,
@@ -97,8 +98,8 @@ public class BotWeaponModLimitService(
}
// Mods parent is scope and mod is scope, allow it (adds those mini-sights to the tops of sights)
var modIsScope = _itemHelper.IsOfBaseclasses(modTemplate.Id, modLimits.ScopeBaseTypes);
if (_itemHelper.IsOfBaseclasses(modsParent.Id, modLimits.ScopeBaseTypes) && modIsScope)
var modIsScope = itemHelper.IsOfBaseclasses(modTemplate.Id, modLimits.ScopeBaseTypes);
if (itemHelper.IsOfBaseclasses(modsParent.Id, modLimits.ScopeBaseTypes) && modIsScope)
{
return false;
}
@@ -122,8 +123,8 @@ public class BotWeaponModLimitService(
if (
modLimits.Scope.Count >= modLimits.ScopeMax
&& modTemplate.Properties.Slots?.Count == 1
&& _itemHelper.IsOfBaseclass(modTemplate.Id, BaseClasses.MOUNT)
&& !_itemHelper.IsOfBaseclass(modsParent.Id, BaseClasses.MOUNT)
&& itemHelper.IsOfBaseclass(modTemplate.Id, BaseClasses.MOUNT)
&& !itemHelper.IsOfBaseclass(modsParent.Id, BaseClasses.MOUNT)
&& modTemplate.Properties.Slots.Any(slot => slot.Name == "mod_scope")
)
{
@@ -131,7 +132,7 @@ public class BotWeaponModLimitService(
}
// If mod is a light/laser, return if limit reached
var modIsLightOrLaser = _itemHelper.IsOfBaseclasses(
var modIsLightOrLaser = itemHelper.IsOfBaseclasses(
modTemplate.Id,
modLimits.FlashlightLaserBaseTypes
);
@@ -149,7 +150,7 @@ public class BotWeaponModLimitService(
if (
modLimits.Scope.Count >= modLimits.ScopeMax
&& modTemplate.Properties.Slots?.Count == 1
&& _itemHelper.IsOfBaseclass(modTemplate.Id, BaseClasses.MOUNT)
&& itemHelper.IsOfBaseclass(modTemplate.Id, BaseClasses.MOUNT)
&& modTemplate.Properties.Slots.Any(slot => slot.Name == "mod_flashlight")
)
{
@@ -168,7 +169,7 @@ public class BotWeaponModLimitService(
/// <param name="botRole">role of bot we're checking weapon of</param>
/// <returns>true if limit reached</returns>
protected bool WeaponModLimitReached(
string modTpl,
MongoId modTpl,
ItemCount currentCount,
int? maxLimit,
string botRole
@@ -183,9 +184,9 @@ public class BotWeaponModLimitService(
// Has mod limit for bot type been reached
if (currentCount.Count >= maxLimit)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"[{botRole}] scope limit reached! tried to add {modTpl} but scope count is {currentCount.Count}"
);
}
@@ -14,19 +14,19 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class BtrDeliveryService(
ISptLogger<BtrDeliveryService> _logger,
DatabaseService _databaseService,
RandomUtil _randomUtil,
TimeUtil _timeUtil,
SaveServer _saveServer,
MailSendService _mailSendService,
ConfigServer _configServer,
ServerLocalisationService _serverLocalisationService
ISptLogger<BtrDeliveryService> logger,
DatabaseService databaseService,
RandomUtil randomUtil,
TimeUtil timeUtil,
SaveServer saveServer,
MailSendService mailSendService,
ConfigServer configServer,
ServerLocalisationService serverLocalisationService
)
{
protected readonly BtrDeliveryConfig _btrDeliveryConfig =
_configServer.GetConfig<BtrDeliveryConfig>();
protected readonly TraderConfig _traderConfig = _configServer.GetConfig<TraderConfig>();
configServer.GetConfig<BtrDeliveryConfig>();
protected readonly TraderConfig _traderConfig = configServer.GetConfig<TraderConfig>();
protected static readonly List<string> _transferTypes = new() { "btr", "transit" };
@@ -35,7 +35,7 @@ public class BtrDeliveryService(
/// </summary>
/// <param name="sessionId"> Session ID </param>
/// <param name="request"> End raid request from client </param>
public void HandleItemTransferEvent(string sessionId, EndLocalRaidRequestData request)
public void HandleItemTransferEvent(MongoId sessionId, EndLocalRaidRequestData request)
{
foreach (var transferType in _transferTypes)
{
@@ -59,9 +59,9 @@ public class BtrDeliveryService(
}
}
protected void HandleTransferItemDelivery(string sessionId, List<Item> items)
protected void HandleTransferItemDelivery(MongoId sessionId, List<Item> items)
{
var serverProfile = _saveServer.GetProfile(sessionId);
var serverProfile = saveServer.GetProfile(sessionId);
var pmcData = serverProfile.CharacterData.PmcData;
// Remove any items that were returned by the item delivery, but also insured, from the player's insurance list
@@ -71,13 +71,13 @@ public class BtrDeliveryService(
.InsuredItems.Where(insuredItem => !deliveredItemIds.Contains(insuredItem.ItemId.Value))
.ToList();
if (_saveServer.GetProfile(sessionId).BtrDeliveryList == null)
if (saveServer.GetProfile(sessionId).BtrDeliveryList == null)
{
_saveServer.GetProfile(sessionId).BtrDeliveryList = new List<BtrDelivery>();
saveServer.GetProfile(sessionId).BtrDeliveryList = new List<BtrDelivery>();
}
// Store delivery to send to player later in profile
_saveServer
saveServer
.GetProfile(sessionId)
.BtrDeliveryList.Add(
new BtrDelivery
@@ -89,13 +89,13 @@ public class BtrDeliveryService(
);
}
public void SendBTRDelivery(string sessionId, List<Item> items)
public void SendBTRDelivery(MongoId sessionId, List<Item> items)
{
var dialogueTemplates = _databaseService.GetTrader(Traders.BTR).Dialogue;
var dialogueTemplates = databaseService.GetTrader(Traders.BTR).Dialogue;
if (dialogueTemplates is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"inraid-unable_to_deliver_item_no_trader_found",
Traders.BTR
)
@@ -105,8 +105,8 @@ public class BtrDeliveryService(
if (!dialogueTemplates.TryGetValue("itemsDelivered", out var itemsDelivered))
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"btr-unable_to_find_items_in_dialog_template",
sessionId
)
@@ -115,13 +115,13 @@ public class BtrDeliveryService(
return;
}
var messageId = _randomUtil.GetArrayValue(itemsDelivered);
var messageStoreTime = _timeUtil.GetHoursAsSeconds(
var messageId = randomUtil.GetArrayValue(itemsDelivered);
var messageStoreTime = timeUtil.GetHoursAsSeconds(
_traderConfig.Fence.BtrDeliveryExpireHours
);
// Send the items to the player
_mailSendService.SendLocalisedNpcMessageToPlayer(
mailSendService.SendLocalisedNpcMessageToPlayer(
sessionId,
Traders.BTR,
MessageType.BtrItemsDelivery,
@@ -136,16 +136,16 @@ public class BtrDeliveryService(
/// </summary>
/// <param name="sessionId">The session ID of the profile to remove the package from.</param>
/// <param name="delivery">The BTR delivery package to remove.</param>
public void RemoveBTRDeliveryPackageFromProfile(string sessionId, BtrDelivery delivery)
public void RemoveBTRDeliveryPackageFromProfile(MongoId sessionId, BtrDelivery delivery)
{
var profile = _saveServer.GetProfile(sessionId);
var profile = saveServer.GetProfile(sessionId);
profile.BtrDeliveryList = profile
.BtrDeliveryList.Where(package => package.Id != delivery.Id)
.ToList();
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Removed processed BTR delivery package. Remaining packages: {profile.BtrDeliveryList.Count}"
);
}
@@ -160,16 +160,16 @@ public class BtrDeliveryService(
// If override in config is non-zero, use that
if (_btrDeliveryConfig.ReturnTimeOverrideSeconds > 0)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"BTR delivery override used: returning in {_btrDeliveryConfig.ReturnTimeOverrideSeconds} seconds"
);
}
return _timeUtil.GetTimeStamp() + _btrDeliveryConfig.ReturnTimeOverrideSeconds;
return timeUtil.GetTimeStamp() + _btrDeliveryConfig.ReturnTimeOverrideSeconds;
}
return _timeUtil.GetTimeStamp();
return timeUtil.GetTimeStamp();
}
}
@@ -5,28 +5,16 @@ using SPTarkov.Server.Core.Utils;
namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class BundleHashCacheService
public class BundleHashCacheService(
ISptLogger<BundleHashCacheService> logger,
JsonUtil jsonUtil,
HashUtil hashUtil,
FileUtil fileUtil
)
{
protected const string _bundleHashCachePath = "./user/cache/";
protected const string _cacheName = "bundleHashCache.json";
protected readonly Dictionary<string, uint> _bundleHashes = new();
private readonly FileUtil _fileUtil;
private readonly HashUtil _hashUtil;
private readonly JsonUtil _jsonUtil;
private readonly ISptLogger<BundleHashCacheService> _logger;
public BundleHashCacheService(
ISptLogger<BundleHashCacheService> logger,
JsonUtil jsonUtil,
HashUtil hashUtil,
FileUtil fileUtil
)
{
_logger = logger;
_jsonUtil = jsonUtil;
_hashUtil = hashUtil;
_fileUtil = fileUtil;
}
public uint GetStoredValue(string key)
{
@@ -47,12 +35,12 @@ public class BundleHashCacheService
Directory.CreateDirectory(_bundleHashCachePath);
}
_fileUtil.WriteFile(
fileUtil.WriteFile(
Path.Join(_bundleHashCachePath, _cacheName),
_jsonUtil.Serialize(_bundleHashes)
jsonUtil.Serialize(_bundleHashes)
);
_logger.Debug($"Bundle: {bundlePath} hash stored in: ${_bundleHashCachePath}");
logger.Debug($"Bundle: {bundlePath} hash stored in: ${_bundleHashCachePath}");
}
public bool CalculateAndMatchHash(string BundlePath)
@@ -67,8 +55,8 @@ public class BundleHashCacheService
public uint CalculateHash(string BundlePath)
{
var fileData = _fileUtil.ReadFile(BundlePath);
return _hashUtil.GenerateCrc32ForData(fileData);
var fileData = fileUtil.ReadFile(BundlePath);
return hashUtil.GenerateCrc32ForData(fileData);
}
public bool MatchWithStoredHash(string BundlePath, uint hash)
@@ -24,27 +24,27 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class CircleOfCultistService(
ISptLogger<CircleOfCultistService> _logger,
TimeUtil _timeUtil,
ICloner _cloner,
EventOutputHolder _eventOutputHolder,
RandomUtil _randomUtil,
HashUtil _hashUtil,
ItemHelper _itemHelper,
PresetHelper _presetHelper,
ProfileHelper _profileHelper,
InventoryHelper _inventoryHelper,
HideoutHelper _hideoutHelper,
QuestHelper _questHelper,
DatabaseService _databaseService,
ItemFilterService _itemFilterService,
SeasonalEventService _seasonalEventService,
ISptLogger<CircleOfCultistService> logger,
TimeUtil timeUtil,
ICloner cloner,
EventOutputHolder eventOutputHolder,
RandomUtil randomUtil,
HashUtil hashUtil,
ItemHelper itemHelper,
PresetHelper presetHelper,
ProfileHelper profileHelper,
InventoryHelper inventoryHelper,
HideoutHelper hideoutHelper,
QuestHelper questHelper,
DatabaseService databaseService,
ItemFilterService itemFilterService,
SeasonalEventService seasonalEventService,
ServerLocalisationService localisationService,
ConfigServer _configServer
ConfigServer configServer
)
{
protected const string CircleOfCultistSlotId = "CircleOfCultistsGrid1";
protected readonly HideoutConfig _hideoutConfig = _configServer.GetConfig<HideoutConfig>();
protected readonly HideoutConfig _hideoutConfig = configServer.GetConfig<HideoutConfig>();
/// <summary>
/// Start a sacrifice event
@@ -56,31 +56,31 @@ public class CircleOfCultistService(
/// <param name="request">Client request</param>
/// <returns>ItemEventRouterResponse</returns>
public ItemEventRouterResponse StartSacrifice(
string sessionId,
MongoId sessionId,
PmcData pmcData,
HideoutCircleOfCultistProductionStartRequestData request
)
{
var output = _eventOutputHolder.GetOutput(sessionId);
var output = eventOutputHolder.GetOutput(sessionId);
var cultistCircleStashId = pmcData.Inventory?.HideoutAreaStashes?.GetValueOrDefault(
((int)HideoutAreas.CircleOfCultists).ToString()
);
if (cultistCircleStashId is null)
{
_logger.Error(localisationService.GetText("cultistcircle-unable_to_find_stash_id"));
logger.Error(localisationService.GetText("cultistcircle-unable_to_find_stash_id"));
return output;
}
// `cultistRecipes` just has single recipeId
var cultistCraftData = _databaseService
var cultistCraftData = databaseService
.GetHideout()
.Production.CultistRecipes.FirstOrDefault();
var sacrificedItems = GetSacrificedItems(pmcData);
var sacrificedItemCostRoubles = sacrificedItems.Aggregate(
0D,
(sum, curr) => sum + (_itemHelper.GetItemPrice(curr.Template) ?? 0)
(sum, curr) => sum + (itemHelper.GetItemPrice(curr.Template) ?? 0)
);
var rewardAmountMultiplier = GetRewardAmountMultiplier(
@@ -123,7 +123,7 @@ public class CircleOfCultistService(
{
if (item.SlotId == CircleOfCultistSlotId)
{
_inventoryHelper.RemoveItem(pmcData, item.Id, sessionId, output);
inventoryHelper.RemoveItem(pmcData, item.Id, sessionId, output);
}
}
@@ -142,12 +142,12 @@ public class CircleOfCultistService(
);
// Get the container grid for cultist stash area
var cultistStashDbItem = _itemHelper.GetItem(
var cultistStashDbItem = itemHelper.GetItem(
ItemTpl.HIDEOUTAREACONTAINER_CIRCLEOFCULTISTS_STASH_1
);
// Ensure rewards fit into container
var containerGrid = _inventoryHelper.GetContainerSlotMap(cultistStashDbItem.Value.Id);
var containerGrid = inventoryHelper.GetContainerSlotMap(cultistStashDbItem.Value.Id);
AddRewardsToCircleContainer(
sessionId,
pmcData,
@@ -172,7 +172,7 @@ public class CircleOfCultistService(
)
{
// Get a randomised value to multiply the sacrificed rouble cost by
var rewardAmountMultiplier = _randomUtil.GetDouble(
var rewardAmountMultiplier = randomUtil.GetDouble(
cultistCircleSettings.RewardPriceMultiplierMinMax.Min,
cultistCircleSettings.RewardPriceMultiplierMinMax.Max
);
@@ -196,7 +196,7 @@ public class CircleOfCultistService(
/// <param name="sacrificedItems">Items player sacrificed</param>
/// <param name="craftingTime">How long the ritual should take</param>
protected void RegisterCircleOfCultistProduction(
string sessionId,
MongoId sessionId,
PmcData pmcData,
string recipeId,
List<Item> sacrificedItems,
@@ -204,7 +204,7 @@ public class CircleOfCultistService(
)
{
// Create circle production/craft object to add to player profile
var cultistProduction = _hideoutHelper.InitProduction(recipeId, craftingTime, false);
var cultistProduction = hideoutHelper.InitProduction(recipeId, craftingTime, false);
// Flag as cultist circle for code to pick up later
cultistProduction.SptIsCultistCircle = true;
@@ -292,7 +292,7 @@ public class CircleOfCultistService(
if (matchingThreshold is null)
{
// None found, use a default
_logger.Warning(
logger.Warning(
localisationService.GetText(
"cultistcircle-no_matching_threshhold_found",
new { rewardAmountRoubles = rewardAmountRoubles }
@@ -304,7 +304,7 @@ public class CircleOfCultistService(
var craftTime =
firstThreshold?.CraftTimeSeconds > 0
? firstThreshold.CraftTimeSeconds
: _timeUtil.GetHoursAsSeconds(12);
: timeUtil.GetHoursAsSeconds(12);
return new CraftTimeThreshold
{
@@ -371,26 +371,24 @@ public class CircleOfCultistService(
{
if (failedAttempts > circleConfig.MaxAttemptsToPickRewardsWithinBudget)
{
_logger.Warning(
$"Exiting reward generation after {failedAttempts} failed attempts"
);
logger.Warning($"Exiting reward generation after {failedAttempts} failed attempts");
break;
}
// Choose a random tpl from pool
var randomItemTplFromPool = _randomUtil.GetArrayValue(rewardItemTplPool);
var randomItemTplFromPool = randomUtil.GetArrayValue(rewardItemTplPool);
// Is weapon/armor, handle differently
if (
_itemHelper.ArmorItemHasRemovableOrSoftInsertSlots(randomItemTplFromPool)
|| _itemHelper.IsOfBaseclass(randomItemTplFromPool, BaseClasses.WEAPON)
itemHelper.ArmorItemHasRemovableOrSoftInsertSlots(randomItemTplFromPool)
|| itemHelper.IsOfBaseclass(randomItemTplFromPool, BaseClasses.WEAPON)
)
{
var defaultPreset = _presetHelper.GetDefaultPreset(randomItemTplFromPool);
var defaultPreset = presetHelper.GetDefaultPreset(randomItemTplFromPool);
if (defaultPreset is null)
{
_logger.Warning(
logger.Warning(
$"Reward tpl: {randomItemTplFromPool} lacks a default preset, skipping reward"
);
failedAttempts++;
@@ -403,10 +401,10 @@ public class CircleOfCultistService(
presetAndMods.RemapRootItemId();
// Set item as FiR
_itemHelper.SetFoundInRaid(presetAndMods);
itemHelper.SetFoundInRaid(presetAndMods);
rewardItemCount++;
totalRewardCost += (int)_itemHelper.GetItemPrice(randomItemTplFromPool);
totalRewardCost += (int)itemHelper.GetItemPrice(randomItemTplFromPool);
rewards.Add(presetAndMods);
continue;
@@ -431,18 +429,18 @@ public class CircleOfCultistService(
},
];
_itemHelper.SetFoundInRaid(rewardItem);
itemHelper.SetFoundInRaid(rewardItem);
// Edge case - item is ammo container and needs cartridges added
if (_itemHelper.IsOfBaseclass(randomItemTplFromPool, BaseClasses.AMMO_BOX))
if (itemHelper.IsOfBaseclass(randomItemTplFromPool, BaseClasses.AMMO_BOX))
{
var itemDetails = _itemHelper.GetItem(randomItemTplFromPool).Value;
_itemHelper.AddCartridgesToAmmoBox(rewardItem, itemDetails);
var itemDetails = itemHelper.GetItem(randomItemTplFromPool).Value;
itemHelper.AddCartridgesToAmmoBox(rewardItem, itemDetails);
}
// Increment price of rewards to give to player + add to reward array
rewardItemCount++;
var singleItemPrice = _itemHelper.GetItemPrice(randomItemTplFromPool);
var singleItemPrice = itemHelper.GetItemPrice(randomItemTplFromPool);
var itemPrice = singleItemPrice * stackSize;
totalRewardCost += (int)itemPrice;
@@ -460,7 +458,7 @@ public class CircleOfCultistService(
/// <param name="cultistCircleStashId">Id of stash item</param>
/// <returns>The reward object</returns>
protected List<List<Item>> GetDirectRewards(
string sessionId,
MongoId sessionId,
DirectRewardSettings directReward,
string cultistCircleStashId
)
@@ -471,7 +469,7 @@ public class CircleOfCultistService(
// Handle special case of tagilla helmets - only one reward is allowed
if (directReward.Reward.Contains(ItemTpl.FACECOVER_TAGILLAS_WELDING_MASK_GORILLA))
{
directReward.Reward = [_randomUtil.GetArrayValue(directReward.Reward)];
directReward.Reward = [randomUtil.GetArrayValue(directReward.Reward)];
}
// Loop because these can include multiple rewards
@@ -479,14 +477,14 @@ public class CircleOfCultistService(
{
// Is weapon/armor, handle differently
if (
_itemHelper.ArmorItemHasRemovableOrSoftInsertSlots(rewardTpl)
|| _itemHelper.IsOfBaseclass(rewardTpl, BaseClasses.WEAPON)
itemHelper.ArmorItemHasRemovableOrSoftInsertSlots(rewardTpl)
|| itemHelper.IsOfBaseclass(rewardTpl, BaseClasses.WEAPON)
)
{
var defaultPreset = _presetHelper.GetDefaultPreset(rewardTpl);
var defaultPreset = presetHelper.GetDefaultPreset(rewardTpl);
if (defaultPreset is null)
{
_logger.Warning(
logger.Warning(
$"Reward tpl: {rewardTpl} lacks a default preset, skipping reward"
);
@@ -498,7 +496,7 @@ public class CircleOfCultistService(
presetAndMods.RemapRootItemId();
// Set item as FiR
_itemHelper.SetFoundInRaid(presetAndMods);
itemHelper.SetFoundInRaid(presetAndMods);
rewards.Add(presetAndMods);
@@ -519,13 +517,13 @@ public class CircleOfCultistService(
},
];
_itemHelper.SetFoundInRaid(rewardItem);
itemHelper.SetFoundInRaid(rewardItem);
// Edge case - item is ammo container and needs cartridges added
if (_itemHelper.IsOfBaseclass(rewardTpl, BaseClasses.AMMO_BOX))
if (itemHelper.IsOfBaseclass(rewardTpl, BaseClasses.AMMO_BOX))
{
var itemDetails = _itemHelper.GetItem(rewardTpl).Value;
_itemHelper.AddCartridgesToAmmoBox(rewardItem, itemDetails);
var itemDetails = itemHelper.GetItem(rewardTpl).Value;
itemHelper.AddCartridgesToAmmoBox(rewardItem, itemDetails);
}
rewards.Add(rewardItem);
@@ -547,7 +545,7 @@ public class CircleOfCultistService(
/// <param name="sacrificedItems">Items sacrificed</param>
/// <returns>Direct reward items to send to player</returns>
protected DirectRewardSettings? CheckForDirectReward(
string sessionId,
MongoId sessionId,
List<Item> sacrificedItems,
Dictionary<string, DirectRewardSettings> directRewardsCache
)
@@ -566,7 +564,7 @@ public class CircleOfCultistService(
return null;
}
var fullProfile = _profileHelper.GetFullProfile(sessionId);
var fullProfile = profileHelper.GetFullProfile(sessionId);
var directRewardHash = GetDirectRewardHashKey(matchingDirectReward);
if (fullProfile.SptData.CultistRewards?.ContainsKey(directRewardHash) ?? false)
// Player has already received this direct reward
@@ -592,7 +590,7 @@ public class CircleOfCultistService(
// Key is sacrificed items separated by commas, a dash, then the rewards separated by commas
var key = $"{{{required}-{reward}}}";
return _hashUtil.GenerateHashForData(HashingAlgorithm.MD5, key);
return hashUtil.GenerateHashForData(HashingAlgorithm.MD5, key);
}
/// <summary>
@@ -602,10 +600,10 @@ public class CircleOfCultistService(
/// <returns>stack size of item</returns>
protected int GetDirectRewardBaseTypeStackSize(string rewardTpl)
{
var itemDetails = _itemHelper.GetItem(rewardTpl);
var itemDetails = itemHelper.GetItem(rewardTpl);
if (!itemDetails.Key)
{
_logger.Warning($"{rewardTpl} is not an item, setting stack size to 1");
logger.Warning($"{rewardTpl} is not an item, setting stack size to 1");
return 1;
}
@@ -619,7 +617,7 @@ public class CircleOfCultistService(
return 1;
}
return _randomUtil.GetInt(settings.Min, settings.Max);
return randomUtil.GetInt(settings.Min, settings.Max);
}
/// <summary>
@@ -628,14 +626,14 @@ public class CircleOfCultistService(
/// <param name="sessionId">Session id</param>
/// <param name="directReward">Reward sent to player</param>
protected void FlagDirectRewardAsAcceptedInProfile(
string sessionId,
MongoId sessionId,
DirectRewardSettings directReward
)
{
var fullProfile = _profileHelper.GetFullProfile(sessionId);
var fullProfile = profileHelper.GetFullProfile(sessionId);
var dataToStoreInProfile = new AcceptedCultistReward
{
Timestamp = _timeUtil.GetTimeStamp(),
Timestamp = timeUtil.GetTimeStamp(),
SacrificeItems = directReward.RequiredItems,
RewardItems = directReward.Reward,
};
@@ -653,28 +651,28 @@ public class CircleOfCultistService(
/// <returns>Size of stack</returns>
protected int GetRewardStackSize(MongoId itemTpl, int rewardPoolRemaining)
{
if (_itemHelper.IsOfBaseclass(itemTpl, BaseClasses.AMMO))
if (itemHelper.IsOfBaseclass(itemTpl, BaseClasses.AMMO))
{
var ammoTemplate = _itemHelper.GetItem(itemTpl).Value;
return _itemHelper.GetRandomisedAmmoStackSize(ammoTemplate);
var ammoTemplate = itemHelper.GetItem(itemTpl).Value;
return itemHelper.GetRandomisedAmmoStackSize(ammoTemplate);
}
if (_itemHelper.IsOfBaseclass(itemTpl, BaseClasses.MONEY))
if (itemHelper.IsOfBaseclass(itemTpl, BaseClasses.MONEY))
{
// Get currency-specific values from config
var settings = _hideoutConfig.CultistCircle.CurrencyRewards[itemTpl];
// What % of the pool remaining should be rewarded as chosen currency
var percentOfPoolToUse = _randomUtil.GetDouble(settings.Min, settings.Max);
var percentOfPoolToUse = randomUtil.GetDouble(settings.Min, settings.Max);
// Rouble amount of pool we want to reward as currency
var roubleAmountToFill = _randomUtil.GetPercentOfValue(
var roubleAmountToFill = randomUtil.GetPercentOfValue(
percentOfPoolToUse,
rewardPoolRemaining
);
// Convert currency to roubles
var currencyPriceAsRouble = _itemHelper.GetItemPrice(itemTpl);
var currencyPriceAsRouble = itemHelper.GetItemPrice(itemTpl);
// How many items can we fit into chosen pool
var itemCountToReward = Math.Round(roubleAmountToFill / currencyPriceAsRouble ?? 0);
@@ -694,27 +692,27 @@ public class CircleOfCultistService(
/// <param name="cultistCircleConfig">Circle config</param>
/// <returns>Array of tpls</returns>
protected List<string> GetCultistCircleRewardPool(
string sessionId,
MongoId sessionId,
PmcData pmcData,
CircleCraftDetails craftingInfo,
CultistCircleSettings cultistCircleConfig
)
{
var rewardPool = new HashSet<string>();
var hideoutDbData = _databaseService.GetHideout();
var itemsDb = _databaseService.GetItems();
var hideoutDbData = databaseService.GetHideout();
var itemsDb = databaseService.GetItems();
// Get all items that match the blacklisted types and fold into item blacklist below
var itemTypeBlacklist = _itemFilterService.GetItemRewardBaseTypeBlacklist();
var itemTypeBlacklist = itemFilterService.GetItemRewardBaseTypeBlacklist();
var itemsMatchingTypeBlacklist = itemsDb
.Where(templateItem => _itemHelper.IsOfBaseclasses(templateItem.Key, itemTypeBlacklist))
.Where(templateItem => itemHelper.IsOfBaseclasses(templateItem.Key, itemTypeBlacklist))
.Select(templateItem => templateItem.Key);
// Create set of unique values to ignore
var itemRewardBlacklist = new HashSet<MongoId>();
itemRewardBlacklist.UnionWith(_seasonalEventService.GetInactiveSeasonalEventItems());
itemRewardBlacklist.UnionWith(_itemFilterService.GetItemRewardBlacklist());
itemRewardBlacklist.UnionWith(_itemFilterService.GetBlacklistedItems());
itemRewardBlacklist.UnionWith(seasonalEventService.GetInactiveSeasonalEventItems());
itemRewardBlacklist.UnionWith(itemFilterService.GetItemRewardBlacklist());
itemRewardBlacklist.UnionWith(itemFilterService.GetBlacklistedItems());
itemRewardBlacklist.UnionWith(cultistCircleConfig.RewardItemBlacklist);
itemRewardBlacklist.UnionWith(itemsMatchingTypeBlacklist);
@@ -792,23 +790,21 @@ public class CircleOfCultistService(
var activeTasks = pmcData.Quests.Where(quest => quest.Status == QuestStatusEnum.Started);
foreach (var task in activeTasks)
{
var questData = _questHelper.GetQuestFromDb(task.QId, pmcData);
var questData = questHelper.GetQuestFromDb(task.QId, pmcData);
var handoverConditions = questData.Conditions.AvailableForFinish.Where(condition =>
condition.ConditionType == "HandoverItem"
);
foreach (var condition in handoverConditions)
foreach (var neededItem in condition.Target.List)
{
if (
itemRewardBlacklist.Contains(neededItem) || !_itemHelper.IsValidItem(neededItem)
)
if (itemRewardBlacklist.Contains(neededItem) || !itemHelper.IsValidItem(neededItem))
{
continue;
}
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Added Task Loot: {_itemHelper.GetItemName(neededItem)}");
logger.Debug($"Added Task Loot: {itemHelper.GetItemName(neededItem)}");
}
rewardPool.Add(neededItem);
@@ -847,17 +843,17 @@ public class CircleOfCultistService(
{
if (
itemRewardBlacklist.Contains(rewardToAdd.TemplateId)
|| !_itemHelper.IsValidItem(rewardToAdd.TemplateId)
|| !itemHelper.IsValidItem(rewardToAdd.TemplateId)
)
// Dont reward items sacrificed
{
continue;
}
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
$"Added Hideout Loot: {_itemHelper.GetItemName(rewardToAdd.TemplateId)}"
logger.Debug(
$"Added Hideout Loot: {itemHelper.GetItemName(rewardToAdd.TemplateId)}"
);
}
@@ -879,7 +875,7 @@ public class CircleOfCultistService(
{
if (
area.Type == HideoutAreas.ChristmasIllumination
&& !_seasonalEventService.ChristmasEventEnabled()
&& !seasonalEventService.ChristmasEventEnabled()
)
// Christmas tree area and not Christmas, skip
{
@@ -904,7 +900,7 @@ public class CircleOfCultistService(
bool itemsShouldBeHighValue
)
{
var allItems = _itemHelper.GetItems();
var allItems = itemHelper.GetItems();
var currentItemCount = 0;
var attempts = 0;
// `currentItemCount` var will look for the correct number of items, `attempts` var will keep this from never stopping if the highValueThreshold is too high
@@ -914,10 +910,10 @@ public class CircleOfCultistService(
)
{
attempts++;
var randomItem = _randomUtil.GetArrayValue(allItems);
var randomItem = randomUtil.GetArrayValue(allItems);
if (
itemRewardBlacklist.Contains(randomItem.Id)
|| !_itemHelper.IsValidItem(randomItem.Id)
|| !itemHelper.IsValidItem(randomItem.Id)
)
{
continue;
@@ -926,16 +922,16 @@ public class CircleOfCultistService(
// Valuable check
if (itemsShouldBeHighValue)
{
var itemValue = _itemHelper.GetItemMaxPrice(randomItem.Id);
var itemValue = itemHelper.GetItemMaxPrice(randomItem.Id);
if (itemValue < _hideoutConfig.CultistCircle.HighValueThresholdRub)
{
continue;
}
}
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Added: {_itemHelper.GetItemName(randomItem.Id)}");
logger.Debug($"Added: {itemHelper.GetItemName(randomItem.Id)}");
}
rewardPool.Add(randomItem.Id);
@@ -973,13 +969,13 @@ public class CircleOfCultistService(
protected string CreateSacrificeCacheKey(IEnumerable<string> requiredItems)
{
var concat = string.Join(",", requiredItems.OrderBy(item => item));
return _hashUtil.GenerateHashForData(HashingAlgorithm.MD5, concat);
return hashUtil.GenerateHashForData(HashingAlgorithm.MD5, concat);
}
protected string CreateSacrificeCacheKey(IEnumerable<MongoId> requiredItems)
{
var concat = string.Join(",", requiredItems.OrderBy(item => item));
return _hashUtil.GenerateHashForData(HashingAlgorithm.MD5, concat);
return hashUtil.GenerateHashForData(HashingAlgorithm.MD5, concat);
}
/// <summary>
@@ -1011,7 +1007,7 @@ public class CircleOfCultistService(
/// <param name="cultistCircleStashId">Stash id</param>
/// <param name="output">Client output</param>
protected void AddRewardsToCircleContainer(
string sessionId,
MongoId sessionId,
PmcData pmcData,
List<List<Item>> rewards,
int[,] containerGrid,
@@ -1022,8 +1018,8 @@ public class CircleOfCultistService(
var canAddToContainer = false;
while (!canAddToContainer && rewards.Count > 0)
{
canAddToContainer = _inventoryHelper.CanPlaceItemsInContainer(
_cloner.Clone(containerGrid), // MUST clone grid before passing in as function modifies grid
canAddToContainer = inventoryHelper.CanPlaceItemsInContainer(
cloner.Clone(containerGrid), // MUST clone grid before passing in as function modifies grid
rewards
);
@@ -1036,7 +1032,7 @@ public class CircleOfCultistService(
foreach (var itemToAdd in rewards)
{
_inventoryHelper.PlaceItemInContainer(
inventoryHelper.PlaceItemInContainer(
containerGrid,
itemToAdd,
cultistCircleStashId,
@@ -19,30 +19,33 @@ namespace SPTarkov.Server.Core.Services;
[Injectable]
public class CreateProfileService(
ISptLogger<CreateProfileService> _logger,
TimeUtil _timeUtil,
DatabaseService _databaseService,
ServerLocalisationService _serverLocalisationService,
ProfileHelper _profileHelper,
ItemHelper _itemHelper,
TraderHelper _traderHelper,
QuestHelper _questHelper,
QuestRewardHelper _questRewardHelper,
PrestigeHelper _prestigeHelper,
RewardHelper _rewardHelper,
ProfileFixerService _profileFixerService,
SaveServer _saveServer,
EventOutputHolder _eventOutputHolder,
PlayerScavGenerator _playerScavGenerator,
ICloner _cloner,
MailSendService _mailSendService
ISptLogger<CreateProfileService> logger,
TimeUtil timeUtil,
DatabaseService databaseService,
ServerLocalisationService serverLocalisationService,
ProfileHelper profileHelper,
ItemHelper itemHelper,
TraderHelper traderHelper,
QuestHelper questHelper,
QuestRewardHelper questRewardHelper,
PrestigeHelper prestigeHelper,
RewardHelper rewardHelper,
ProfileFixerService profileFixerService,
SaveServer saveServer,
EventOutputHolder eventOutputHolder,
PlayerScavGenerator playerScavGenerator,
ICloner cloner,
MailSendService mailSendService
)
{
public async ValueTask<string> CreateProfile(string sessionId, ProfileCreateRequestData request)
public async ValueTask<string> CreateProfile(
MongoId sessionId,
ProfileCreateRequestData request
)
{
var account = _cloner.Clone(_saveServer.GetProfile(sessionId));
var profileTemplateClone = _cloner.Clone(
_profileHelper.GetProfileTemplateForSide(account.ProfileInfo.Edition, request.Side)
var account = cloner.Clone(saveServer.GetProfile(sessionId));
var profileTemplateClone = cloner.Clone(
profileHelper.GetProfileTemplateForSide(account.ProfileInfo.Edition, request.Side)
);
var pmcData = profileTemplateClone.Character;
@@ -56,12 +59,12 @@ public class CreateProfileService(
pmcData.SessionId = sessionId;
pmcData.Info.Nickname = request.Nickname;
pmcData.Info.LowerNickname = request.Nickname.ToLowerInvariant();
pmcData.Info.RegistrationDate = (int)_timeUtil.GetTimeStamp();
pmcData.Info.Voice = _databaseService.GetCustomization()[request.VoiceId].Name;
pmcData.Stats = _profileHelper.GetDefaultCounters();
pmcData.Info.RegistrationDate = (int)timeUtil.GetTimeStamp();
pmcData.Info.Voice = databaseService.GetCustomization()[request.VoiceId].Name;
pmcData.Stats = profileHelper.GetDefaultCounters();
pmcData.Info.NeedWipeOptions = [];
pmcData.Customization.Head = request.HeadId;
pmcData.Health.UpdateTime = _timeUtil.GetTimeStamp();
pmcData.Health.UpdateTime = timeUtil.GetTimeStamp();
pmcData.Quests = [];
pmcData.Hideout.Seed = Convert.ToHexStringLower(RandomNumberGenerator.GetBytes(16));
pmcData.RepeatableQuests = [];
@@ -103,7 +106,7 @@ public class CreateProfileService(
AddMissingInternalContainersToProfile(pmcData);
// Change item IDs to be unique
_itemHelper.ReplaceProfileInventoryIds(pmcData.Inventory);
itemHelper.ReplaceProfileInventoryIds(pmcData.Inventory);
// Create profile
var profileDetails = new SptProfile
@@ -112,7 +115,7 @@ public class CreateProfileService(
CharacterData = new Characters { PmcData = pmcData, ScavData = new PmcData() },
UserBuildData = profileTemplateClone.UserBuilds,
DialogueRecords = profileTemplateClone.Dialogues,
SptData = _profileHelper.GetDefaultSptDataObject(),
SptData = profileHelper.GetDefaultSptDataObject(),
InraidData = new Inraid(),
InsuranceList = [],
BtrDeliveryList = [],
@@ -125,11 +128,11 @@ public class CreateProfileService(
profileDetails.AddSuitsToProfile(profileTemplateClone.Suits);
_profileFixerService.CheckForAndFixPmcProfileIssues(profileDetails.CharacterData.PmcData);
profileFixerService.CheckForAndFixPmcProfileIssues(profileDetails.CharacterData.PmcData);
if (profileDetails.CharacterData.PmcData.Achievements.Count > 0)
{
var achievementsDb = _databaseService.GetTemplates().Achievements;
var achievementsDb = databaseService.GetTemplates().Achievements;
var achievementRewardItemsToSend = new List<Item>();
foreach (var (achievementId, _) in profileDetails.CharacterData.PmcData.Achievements)
@@ -144,7 +147,7 @@ public class CreateProfileService(
}
achievementRewardItemsToSend.AddRange(
_rewardHelper.ApplyRewards(
rewardHelper.ApplyRewards(
rewards,
CustomisationSource.ACHIEVEMENT,
profileDetails,
@@ -156,8 +159,8 @@ public class CreateProfileService(
if (achievementRewardItemsToSend.Count > 0)
{
_mailSendService.SendLocalisedSystemMessageToPlayer(
profileDetails.ProfileInfo.ProfileId,
mailSendService.SendLocalisedSystemMessageToPlayer(
profileDetails.ProfileInfo.ProfileId.Value,
"670547bb5fa0b1a7c30d5836 0",
achievementRewardItemsToSend,
[],
@@ -176,14 +179,14 @@ public class CreateProfileService(
? account.SptData.PendingPrestige
: new PendingPrestige { PrestigeLevel = request.SptForcePrestigeLevel };
_prestigeHelper.ProcessPendingPrestige(account, profileDetails, pendingPrestige);
prestigeHelper.ProcessPendingPrestige(account, profileDetails, pendingPrestige);
}
_saveServer.AddProfile(profileDetails);
saveServer.AddProfile(profileDetails);
if (profileTemplateClone.Trader.SetQuestsAvailableForStart ?? false)
{
_questHelper.AddAllQuestsToProfile(
questHelper.AddAllQuestsToProfile(
profileDetails.CharacterData.PmcData,
[QuestStatusEnum.AvailableForStart]
);
@@ -192,7 +195,7 @@ public class CreateProfileService(
// Profile is flagged as wanting quests set to ready to hand in and collect rewards
if (profileTemplateClone.Trader.SetQuestsAvailableForFinish ?? false)
{
_questHelper.AddAllQuestsToProfile(
questHelper.AddAllQuestsToProfile(
profileDetails.CharacterData.PmcData,
[
QuestStatusEnum.AvailableForStart,
@@ -202,7 +205,7 @@ public class CreateProfileService(
);
// Make unused response so applyQuestReward works
var response = _eventOutputHolder.GetOutput(sessionId);
var response = eventOutputHolder.GetOutput(sessionId);
// Add rewards for starting quests to profile
GivePlayerStartingQuestRewards(profileDetails, sessionId, response);
@@ -210,17 +213,17 @@ public class CreateProfileService(
ResetAllTradersInProfile(sessionId);
_saveServer.GetProfile(sessionId).CharacterData.ScavData = _playerScavGenerator.Generate(
saveServer.GetProfile(sessionId).CharacterData.ScavData = playerScavGenerator.Generate(
sessionId
);
// Store minimal profile and reload it
await _saveServer.SaveProfileAsync(sessionId);
await _saveServer.LoadProfileAsync(sessionId);
await saveServer.SaveProfileAsync(sessionId);
await saveServer.LoadProfileAsync(sessionId);
// Completed account creation
_saveServer.GetProfile(sessionId).ProfileInfo.IsWiped = false;
await _saveServer.SaveProfileAsync(sessionId);
saveServer.GetProfile(sessionId).ProfileInfo.IsWiped = false;
await saveServer.SaveProfileAsync(sessionId);
return pmcData.Id;
}
@@ -229,16 +232,16 @@ public class CreateProfileService(
/// Delete a profile
/// </summary>
/// <param name="sessionID"> ID of profile to delete </param>
protected void DeleteProfileBySessionId(string sessionID)
protected void DeleteProfileBySessionId(MongoId sessionID)
{
if (_saveServer.GetProfiles().ContainsKey(sessionID))
if (saveServer.GetProfiles().ContainsKey(sessionID))
{
_saveServer.DeleteProfileById(sessionID);
saveServer.DeleteProfileById(sessionID);
}
else
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"profile-unable_to_find_profile_by_id_cannot_delete",
sessionID
)
@@ -274,11 +277,11 @@ public class CreateProfileService(
/// For each trader reset their state to what a level 1 player would see
/// </summary>
/// <param name="sessionId"> Session ID of profile to reset </param>
protected void ResetAllTradersInProfile(string sessionId)
protected void ResetAllTradersInProfile(MongoId sessionId)
{
foreach (var traderId in _databaseService.GetTraders().Keys)
foreach (var traderId in databaseService.GetTraders().Keys)
{
_traderHelper.ResetTrader(sessionId, traderId);
traderHelper.ResetTrader(sessionId, traderId);
}
}
@@ -347,24 +350,24 @@ public class CreateProfileService(
/// <param name="response"> Event router response </param>
protected void GivePlayerStartingQuestRewards(
SptProfile profileDetails,
string sessionID,
MongoId sessionID,
ItemEventRouterResponse response
)
{
foreach (var quest in profileDetails.CharacterData.PmcData.Quests)
{
var questFromDb = _questHelper.GetQuestFromDb(
var questFromDb = questHelper.GetQuestFromDb(
quest.QId,
profileDetails.CharacterData.PmcData
);
// Get messageId of text to send to player as text message in game
// Copy of code from QuestController.acceptQuest()
var messageId = _questHelper.GetMessageIdForQuestStart(
var messageId = questHelper.GetMessageIdForQuestStart(
questFromDb.StartedMessageText,
questFromDb.Description
);
var itemRewards = _questRewardHelper
var itemRewards = questRewardHelper
.ApplyQuestReward(
profileDetails.CharacterData.PmcData,
quest.QId,
@@ -374,13 +377,13 @@ public class CreateProfileService(
)
.ToList();
_mailSendService.SendLocalisedNpcMessageToPlayer(
mailSendService.SendLocalisedNpcMessageToPlayer(
sessionID,
questFromDb.TraderId,
MessageType.QuestStart,
messageId,
itemRewards,
_timeUtil.GetHoursAsSeconds(100)
timeUtil.GetHoursAsSeconds(100)
);
}
}
@@ -9,12 +9,12 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class CustomLocationWaveService(
ISptLogger<CustomLocationWaveService> _logger,
DatabaseService _databaseService,
ConfigServer _configServer
ISptLogger<CustomLocationWaveService> logger,
DatabaseService databaseService,
ConfigServer configServer
)
{
protected readonly LocationConfig _locationConfig = _configServer.GetConfig<LocationConfig>();
protected readonly LocationConfig _locationConfig = configServer.GetConfig<LocationConfig>();
/// <summary>
/// Add a boss wave to a map
@@ -64,10 +64,10 @@ public class CustomLocationWaveService(
foreach (var mapKvP in bossWavesToApply)
{
var locationBase = _databaseService.GetLocation(mapKvP.Key).Base;
var locationBase = databaseService.GetLocation(mapKvP.Key).Base;
if (locationBase is null)
{
_logger.Warning(
logger.Warning(
$"Unable to add custom boss wave to location: {mapKvP}, location not found"
);
@@ -83,9 +83,9 @@ public class CustomLocationWaveService(
}
locationBase.BossLocationSpawn.Add(bossWave);
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Added custom boss wave to {mapKvP.Key} of type {bossWave.BossName}, time: {bossWave.Time}, chance: {bossWave.BossChance}, zone: {(string.IsNullOrEmpty(bossWave.BossZone) ? "Global" : bossWave.BossZone)}"
);
}
@@ -94,10 +94,10 @@ public class CustomLocationWaveService(
foreach (var mapKvP in normalWavesToApply)
{
var locationBase = _databaseService.GetLocation(mapKvP.Key).Base;
var locationBase = databaseService.GetLocation(mapKvP.Key).Base;
if (locationBase is null)
{
_logger.Warning(
logger.Warning(
$"Unable to add custom wave to location: {mapKvP}, location not found"
);
@@ -21,9 +21,9 @@ namespace SPTarkov.Server.Core.Services;
/// </summary>
[Injectable(InjectionType.Singleton)]
public class DatabaseService(
ISptLogger<DatabaseService> _logger,
DatabaseServer _databaseServer,
ServerLocalisationService _serverLocalisationService
ISptLogger<DatabaseService> logger,
DatabaseServer databaseServer,
ServerLocalisationService serverLocalisationService
)
{
private bool _isDataValid = true;
@@ -31,87 +31,87 @@ public class DatabaseService(
/// <returns> assets/database/ </returns>
public DatabaseTables GetTables()
{
return _databaseServer.GetTables();
return databaseServer.GetTables();
}
/// <returns> assets/database/bots/ </returns>
public Bots GetBots()
{
if (_databaseServer.GetTables().Bots == null)
if (databaseServer.GetTables().Bots == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/bots"
)
);
}
return _databaseServer.GetTables().Bots!;
return databaseServer.GetTables().Bots!;
}
/// <returns> assets/database/globals.json </returns>
public Globals GetGlobals()
{
if (_databaseServer.GetTables().Globals == null)
if (databaseServer.GetTables().Globals == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/globals.json"
)
);
}
return _databaseServer.GetTables().Globals!;
return databaseServer.GetTables().Globals!;
}
/// <returns> assets/database/hideout/ </returns>
public Hideout GetHideout()
{
if (_databaseServer.GetTables().Hideout == null)
if (databaseServer.GetTables().Hideout == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/hideout"
)
);
}
return _databaseServer.GetTables().Hideout!;
return databaseServer.GetTables().Hideout!;
}
/// <returns> assets/database/locales/ </returns>
public LocaleBase GetLocales()
{
if (_databaseServer.GetTables().Locales == null)
if (databaseServer.GetTables().Locales == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/locales"
)
);
}
return _databaseServer.GetTables().Locales!;
return databaseServer.GetTables().Locales!;
}
/// <returns> assets/database/locations </returns>
public Locations GetLocations()
{
if (_databaseServer.GetTables().Locations == null)
if (databaseServer.GetTables().Locations == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/locations"
)
);
}
return _databaseServer.GetTables().Locations!;
return databaseServer.GetTables().Locations!;
}
/// <summary>
@@ -125,8 +125,8 @@ public class DatabaseService(
?.GetByJsonProp<Location>(locationId.ToLowerInvariant());
if (desiredLocation == null)
{
_logger.Error(
_serverLocalisationService.GetText("database-no_location_found_with_id", locationId)
logger.Error(
serverLocalisationService.GetText("database-no_location_found_with_id", locationId)
);
return null;
@@ -138,209 +138,209 @@ public class DatabaseService(
/// <returns> assets/database/match/ </returns>
public Match GetMatch()
{
if (_databaseServer.GetTables().Match == null)
if (databaseServer.GetTables().Match == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/locales"
)
);
}
return _databaseServer.GetTables().Match!;
return databaseServer.GetTables().Match!;
}
/// <returns> assets/database/server.json </returns>
public ServerBase GetServer()
{
if (_databaseServer.GetTables().Server == null)
if (databaseServer.GetTables().Server == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/server.json"
)
);
}
return _databaseServer.GetTables().Server!;
return databaseServer.GetTables().Server!;
}
/// <returns> assets/database/settings.json </returns>
public SettingsBase GetSettings()
{
if (_databaseServer.GetTables().Settings == null)
if (databaseServer.GetTables().Settings == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/settings.json"
)
);
}
return _databaseServer.GetTables().Settings!;
return databaseServer.GetTables().Settings!;
}
/// <returns> assets/database/templates/ </returns>
public Templates GetTemplates()
{
if (_databaseServer.GetTables().Templates == null)
if (databaseServer.GetTables().Templates == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/templates"
)
);
}
return _databaseServer.GetTables().Templates!;
return databaseServer.GetTables().Templates!;
}
/// <returns> assets/database/templates/achievements.json </returns>
public List<Achievement> GetAchievements()
{
if (_databaseServer.GetTables().Templates?.Achievements == null)
if (databaseServer.GetTables().Templates?.Achievements == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/templates/achievements.json"
)
);
}
return _databaseServer.GetTables().Templates?.Achievements!;
return databaseServer.GetTables().Templates?.Achievements!;
}
/// <returns> assets/database/templates/customAchievements.json </returns>
public List<Achievement> GetCustomAchievements()
{
if (_databaseServer.GetTables().Templates?.Achievements == null)
if (databaseServer.GetTables().Templates?.Achievements == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/templates/customAchievements.json"
)
);
}
return _databaseServer.GetTables().Templates?.CustomAchievements!;
return databaseServer.GetTables().Templates?.CustomAchievements!;
}
/// <returns> assets/database/templates/customisation.json </returns>
public Dictionary<string, CustomizationItem?> GetCustomization()
{
if (_databaseServer.GetTables().Templates?.Customization == null)
if (databaseServer.GetTables().Templates?.Customization == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/templates/customization.json"
)
);
}
return _databaseServer.GetTables().Templates?.Customization!;
return databaseServer.GetTables().Templates?.Customization!;
}
/// <returns> assets/database/templates/handbook.json </returns>
public HandbookBase GetHandbook()
{
if (_databaseServer.GetTables().Templates?.Handbook == null)
if (databaseServer.GetTables().Templates?.Handbook == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/templates/handbook.json"
)
);
}
return _databaseServer.GetTables().Templates?.Handbook!;
return databaseServer.GetTables().Templates?.Handbook!;
}
/// <returns> assets/database/templates/items.json </returns>
public Dictionary<MongoId, TemplateItem> GetItems()
{
if (_databaseServer.GetTables().Templates?.Items == null)
if (databaseServer.GetTables().Templates?.Items == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/templates/items.json"
)
);
}
return _databaseServer.GetTables().Templates?.Items!;
return databaseServer.GetTables().Templates?.Items!;
}
/// <returns> assets/database/templates/prices.json </returns>
public Dictionary<MongoId, double> GetPrices()
{
if (_databaseServer.GetTables().Templates?.Prices == null)
if (databaseServer.GetTables().Templates?.Prices == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/templates/prices.json"
)
);
}
return _databaseServer.GetTables().Templates?.Prices!;
return databaseServer.GetTables().Templates?.Prices!;
}
/// <returns> assets/database/templates/profiles.json </returns>
public Dictionary<string, ProfileSides> GetProfileTemplates()
{
if (_databaseServer.GetTables().Templates?.Profiles == null)
if (databaseServer.GetTables().Templates?.Profiles == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/templates/profiles.json"
)
);
}
return _databaseServer.GetTables().Templates?.Profiles!;
return databaseServer.GetTables().Templates?.Profiles!;
}
/// <returns> assets/database/templates/quests.json </returns>
public Dictionary<string, Quest> GetQuests()
{
if (_databaseServer.GetTables().Templates?.Quests == null)
if (databaseServer.GetTables().Templates?.Quests == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/templates/quests.json"
)
);
}
return _databaseServer.GetTables().Templates?.Quests!;
return databaseServer.GetTables().Templates?.Quests!;
}
/// <returns> assets/database/traders/ </returns>
public Dictionary<MongoId, Trader> GetTraders()
{
if (_databaseServer.GetTables().Traders == null)
if (databaseServer.GetTables().Traders == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/traders"
)
);
}
return _databaseServer.GetTables().Traders!;
return databaseServer.GetTables().Traders!;
}
/// <summary>
@@ -348,13 +348,13 @@ public class DatabaseService(
/// </summary>
/// <param name="traderId"> Desired trader ID </param>
/// <returns> assets/database/traders/ </returns>
public Trader? GetTrader(string traderId)
public Trader? GetTrader(MongoId traderId)
{
var traders = GetTraders();
if (!traders.TryGetValue(traderId, out var desiredTrader))
{
_logger.Error(
_serverLocalisationService.GetText("database-no_trader_found_with_id", traderId)
logger.Error(
serverLocalisationService.GetText("database-no_trader_found_with_id", traderId)
);
return null;
@@ -366,17 +366,17 @@ public class DatabaseService(
/// <returns> assets/database/locationServices/ </returns>
public LocationServices GetLocationServices()
{
if (_databaseServer.GetTables().Templates?.LocationServices == null)
if (databaseServer.GetTables().Templates?.LocationServices == null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"database-data_at_path_missing",
"assets/database/locationServices.json"
)
);
}
return _databaseServer.GetTables().Templates?.LocationServices!;
return databaseServer.GetTables().Templates?.LocationServices!;
}
/// <summary>
@@ -394,13 +394,13 @@ public class DatabaseService(
if (!_isDataValid)
{
_logger.Error(_serverLocalisationService.GetText("database-invalid_data"));
logger.Error(serverLocalisationService.GetText("database-invalid_data"));
}
start.Stop();
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"ID validation took: {start.ElapsedMilliseconds}ms");
logger.Debug($"ID validation took: {start.ElapsedMilliseconds}ms");
}
}
@@ -416,7 +416,7 @@ public class DatabaseService(
{
if (!keyValuePair.Key.IsValidMongoId())
{
_logger.Error($"Invalid {tableType} ID: '{keyValuePair.Key}'");
logger.Error($"Invalid {tableType} ID: '{keyValuePair.Key}'");
return false;
}
}
@@ -430,7 +430,7 @@ public class DatabaseService(
{
if (!keyValuePair.Key.IsValidMongoId())
{
_logger.Error($"Invalid {tableType} ID: '{keyValuePair.Key}'");
logger.Error($"Invalid {tableType} ID: '{keyValuePair.Key}'");
return false;
}
}
@@ -1,5 +1,6 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Profile;
using SPTarkov.Server.Core.Models.Enums;
using SPTarkov.Server.Core.Models.Spt.Config;
@@ -13,15 +14,15 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class GiftService(
ISptLogger<GiftService> _logger,
MailSendService _mailSendService,
ServerLocalisationService _serverLocalisationService,
TimeUtil _timeUtil,
ProfileHelper _profileHelper,
ConfigServer _configServer
ISptLogger<GiftService> logger,
MailSendService mailSendService,
ServerLocalisationService serverLocalisationService,
TimeUtil timeUtil,
ProfileHelper profileHelper,
ConfigServer configServer
)
{
protected readonly GiftsConfig _giftConfig = _configServer.GetConfig<GiftsConfig>();
protected readonly GiftsConfig _giftConfig = configServer.GetConfig<GiftsConfig>();
/// <summary>
/// Does a gift with a specific ID exist in db
@@ -74,11 +75,11 @@ public class GiftService(
var maxGiftsToSendCount = giftData.MaxToSendPlayer ?? 1;
if (_profileHelper.PlayerHasReceivedMaxNumberOfGift(playerId, giftId, maxGiftsToSendCount))
if (profileHelper.PlayerHasReceivedMaxNumberOfGift(playerId, giftId, maxGiftsToSendCount))
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Player already received gift: {giftId}");
logger.Debug($"Player already received gift: {giftId}");
}
return GiftSentResult.FAILED_GIFT_ALREADY_RECEIVED;
@@ -86,7 +87,7 @@ public class GiftService(
if (giftData.Items?.Count > 0 && giftData.CollectionTimeHours is null)
{
_logger.Warning(
logger.Warning(
$"Gift {giftId} has items but no collection time limit, defaulting to 48 hours"
);
}
@@ -97,21 +98,21 @@ public class GiftService(
// Has a localisable text id to send to player
if (giftData.LocaleTextId is not null)
{
_mailSendService.SendLocalisedSystemMessageToPlayer(
mailSendService.SendLocalisedSystemMessageToPlayer(
playerId,
giftData.LocaleTextId,
giftData.Items,
giftData.ProfileChangeEvents,
_timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1)
timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1)
);
}
else
{
_mailSendService.SendSystemMessageToPlayer(
mailSendService.SendSystemMessageToPlayer(
playerId,
giftData.MessageText,
giftData.Items,
_timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1),
timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1),
giftData.ProfileChangeEvents
);
}
@@ -119,36 +120,36 @@ public class GiftService(
// Handle user messages
else if (giftData.Sender == GiftSenderType.User)
{
_mailSendService.SendUserMessageToPlayer(
mailSendService.SendUserMessageToPlayer(
playerId,
giftData.SenderDetails,
giftData.MessageText,
giftData.Items,
_timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1)
timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1)
);
}
else if (giftData.Sender == GiftSenderType.Trader)
{
if (giftData.LocaleTextId is not null)
{
_mailSendService.SendLocalisedNpcMessageToPlayer(
mailSendService.SendLocalisedNpcMessageToPlayer(
playerId,
giftData.Trader,
MessageType.MessageWithItems,
giftData.LocaleTextId,
giftData.Items,
_timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1)
timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1)
);
}
else
{
_mailSendService.SendLocalisedNpcMessageToPlayer(
mailSendService.SendLocalisedNpcMessageToPlayer(
playerId,
giftData.Trader,
MessageType.MessageWithItems,
giftData.MessageText,
giftData.Items,
_timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1)
timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1)
);
}
}
@@ -168,7 +169,7 @@ public class GiftService(
},
MessageText = giftData.MessageText,
Items = giftData.Items,
ItemsMaxStorageLifetimeSeconds = _timeUtil.GetHoursAsSeconds(
ItemsMaxStorageLifetimeSeconds = timeUtil.GetHoursAsSeconds(
giftData.CollectionTimeHours ?? 0
),
};
@@ -178,10 +179,10 @@ public class GiftService(
details.Trader = giftData.Trader;
}
_mailSendService.SendMessageToPlayer(details);
mailSendService.SendMessageToPlayer(details);
}
_profileHelper.FlagGiftReceivedInProfile(playerId, giftId, maxGiftsToSendCount);
profileHelper.FlagGiftReceivedInProfile(playerId, giftId, maxGiftsToSendCount);
return GiftSentResult.SUCCESS;
}
@@ -222,8 +223,8 @@ public class GiftService(
case GiftSenderType.User:
return MessageType.UserMessage;
default:
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"gift-unable_to_handle_message_type_command",
giftData.Sender
)
@@ -237,7 +238,7 @@ public class GiftService(
/// </summary>
/// <param name="sessionId"> Player ID </param>
/// <param name="day"> What day to give gift for </param>
public void SendPraporStartingGift(string sessionId, int day)
public void SendPraporStartingGift(MongoId sessionId, int day)
{
var giftId = day switch
{
@@ -248,7 +249,7 @@ public class GiftService(
if (giftId is not null)
{
if (!_profileHelper.PlayerHasReceivedMaxNumberOfGift(sessionId, giftId, 1))
if (!profileHelper.PlayerHasReceivedMaxNumberOfGift(sessionId, giftId, 1))
{
SendGiftToPlayer(sessionId, giftId);
}
@@ -261,9 +262,9 @@ public class GiftService(
/// <param name="giftId"> ID of gift to send </param>
/// <param name="sessionId"> Session ID of player to send to </param>
/// <param name="giftCount"> Optional, how many to send </param>
public void SendGiftWithSilentReceivedCheck(string giftId, string? sessionId, int giftCount)
public void SendGiftWithSilentReceivedCheck(string giftId, MongoId? sessionId, int giftCount)
{
if (!_profileHelper.PlayerHasReceivedMaxNumberOfGift(sessionId, giftId, giftCount))
if (!profileHelper.PlayerHasReceivedMaxNumberOfGift(sessionId.Value, giftId, giftCount))
{
SendGiftToPlayer(sessionId, giftId);
}
@@ -4,7 +4,7 @@ using SPTarkov.Server.Core.Utils.Cloners;
namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class InMemoryCacheService(ICloner _cloner)
public class InMemoryCacheService(ICloner cloner)
{
protected readonly Dictionary<string, object?> _cacheData = new();
@@ -15,7 +15,7 @@ public class InMemoryCacheService(ICloner _cloner)
/// <param name="dataToCache"> Data to store in cache </param>
public void StoreByKey<T>(string key, T dataToCache)
{
_cacheData[key] = _cloner.Clone(dataToCache);
_cacheData[key] = cloner.Clone(dataToCache);
}
/// <summary>
@@ -1,6 +1,7 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Profile;
@@ -17,28 +18,27 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class InsuranceService(
ISptLogger<InsuranceService> _logger,
DatabaseService _databaseService,
RandomUtil _randomUtil,
ItemHelper _itemHelper,
TimeUtil _timeUtil,
SaveServer _saveServer,
TraderHelper _traderHelper,
ServerLocalisationService _serverLocalisationService,
MailSendService _mailSendService,
ConfigServer _configServer
ISptLogger<InsuranceService> logger,
DatabaseService databaseService,
RandomUtil randomUtil,
ItemHelper itemHelper,
TimeUtil timeUtil,
SaveServer saveServer,
TraderHelper traderHelper,
ServerLocalisationService serverLocalisationService,
MailSendService mailSendService,
ConfigServer configServer
)
{
protected readonly InsuranceConfig _insuranceConfig =
_configServer.GetConfig<InsuranceConfig>();
protected readonly Dictionary<string, Dictionary<string, List<Item>>?> _insured = new();
protected readonly InsuranceConfig _insuranceConfig = configServer.GetConfig<InsuranceConfig>();
protected readonly Dictionary<MongoId, Dictionary<MongoId, List<Item>>?> _insured = new();
/// <summary>
/// Does player have insurance dictionary exists
/// </summary>
/// <param name="sessionId">Player id</param>
/// <returns>True if exists</returns>
public bool InsuranceDictionaryExists(string sessionId)
public bool InsuranceDictionaryExists(MongoId sessionId)
{
return _insured.TryGetValue(sessionId, out _);
}
@@ -48,16 +48,16 @@ public class InsuranceService(
/// </summary>
/// <param name="sessionId">Profile id (session id)</param>
/// <returns>Item list</returns>
public Dictionary<string, List<Item>>? GetInsurance(string sessionId)
public Dictionary<MongoId, List<Item>>? GetInsurance(MongoId sessionId)
{
return _insured[sessionId];
}
public void ResetInsurance(string sessionId)
public void ResetInsurance(MongoId sessionId)
{
if (!_insured.TryAdd(sessionId, new Dictionary<string, List<Item>>()))
if (!_insured.TryAdd(sessionId, new Dictionary<MongoId, List<Item>>()))
{
_insured[sessionId] = new Dictionary<string, List<Item>>();
_insured[sessionId] = new Dictionary<MongoId, List<Item>>();
}
}
@@ -68,17 +68,17 @@ public class InsuranceService(
/// <param name="pmcData">Profile to send insured items to</param>
/// <param name="sessionID">SessionId of current player</param>
/// <param name="mapId">Id of the location player died/exited that caused the insurance to be issued on</param>
public void StartPostRaidInsuranceLostProcess(PmcData pmcData, string sessionID, string mapId)
public void StartPostRaidInsuranceLostProcess(PmcData pmcData, MongoId sessionID, string mapId)
{
// Get insurance items for each trader
var globals = _databaseService.GetGlobals();
var globals = databaseService.GetGlobals();
foreach (var traderKvP in GetInsurance(sessionID))
{
var traderBase = _traderHelper.GetTrader(traderKvP.Key, sessionID);
var traderBase = traderHelper.GetTrader(traderKvP.Key, sessionID);
if (traderBase is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"insurance-unable_to_find_trader_by_id",
traderKvP.Key
)
@@ -87,11 +87,11 @@ public class InsuranceService(
continue;
}
var dialogueTemplates = _databaseService.GetTrader(traderKvP.Key).Dialogue;
var dialogueTemplates = databaseService.GetTrader(traderKvP.Key).Dialogue;
if (dialogueTemplates is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"insurance-trader_lacks_dialogue_property",
traderKvP.Key
)
@@ -102,21 +102,21 @@ public class InsuranceService(
var systemData = new SystemData
{
Date = _timeUtil.GetBsgDateMailFormat(),
Time = _timeUtil.GetBsgTimeMailFormat(),
Date = timeUtil.GetBsgDateMailFormat(),
Time = timeUtil.GetBsgTimeMailFormat(),
Location = mapId,
};
// Send "i will go look for your stuff" message from trader to player
_mailSendService.SendLocalisedNpcMessageToPlayer(
mailSendService.SendLocalisedNpcMessageToPlayer(
sessionID,
traderKvP.Key,
MessageType.NpcTraderMessage,
_randomUtil.GetArrayValue(
randomUtil.GetArrayValue(
dialogueTemplates["insuranceStart"] ?? ["INSURANCE START MESSAGE MISSING"]
),
null,
_timeUtil.GetHoursAsSeconds(
timeUtil.GetHoursAsSeconds(
(int)globals.Configuration?.Insurance?.MaxStorageTimeInHour
),
systemData
@@ -124,7 +124,7 @@ public class InsuranceService(
// Store insurance to send to player later in profile
// Store insurance return details in profile + "hey i found your stuff, here you go!" message details to send to player at a later date
_saveServer
saveServer
.GetProfile(sessionID)
.InsuranceList.Add(
new Insurance
@@ -134,7 +134,7 @@ public class InsuranceService(
MaxStorageTime = (int)GetMaxInsuranceStorageTime(traderBase),
SystemData = systemData,
MessageType = MessageType.InsuranceReturn,
MessageTemplateId = _randomUtil.GetArrayValue(
MessageTemplateId = randomUtil.GetArrayValue(
dialogueTemplates["insuranceFound"]
),
Items = GetInsurance(sessionID)[traderKvP.Key],
@@ -157,14 +157,14 @@ public class InsuranceService(
// If override in config is non-zero, use that instead of trader values
if (_insuranceConfig.ReturnTimeOverrideSeconds > 0)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Insurance override used: returning in {_insuranceConfig.ReturnTimeOverrideSeconds} seconds"
);
}
return _timeUtil.GetTimeStamp() + _insuranceConfig.ReturnTimeOverrideSeconds;
return timeUtil.GetTimeStamp() + _insuranceConfig.ReturnTimeOverrideSeconds;
}
var insuranceReturnTimeBonusSum = pmcData.GetBonusValueFromProfile(
@@ -176,14 +176,14 @@ public class InsuranceService(
var traderMinReturnAsSeconds = trader.Insurance.MinReturnHour * TimeUtil.OneHourAsSeconds;
var traderMaxReturnAsSeconds = trader.Insurance.MaxReturnHour * TimeUtil.OneHourAsSeconds;
var randomisedReturnTimeSeconds = _randomUtil.GetDouble(
var randomisedReturnTimeSeconds = randomUtil.GetDouble(
traderMinReturnAsSeconds.Value,
traderMaxReturnAsSeconds.Value
);
// Check for Mark of The Unheard in players special slots (only slot item can fit)
var globals = _databaseService.GetGlobals();
var hasMarkOfUnheard = _itemHelper.HasItemWithTpl(
var globals = databaseService.GetGlobals();
var hasMarkOfUnheard = itemHelper.HasItemWithTpl(
pmcData.Inventory.Items,
ItemTpl.MARKOFUNKNOWN_MARK_OF_THE_UNHEARD,
"SpecialSlot"
@@ -212,7 +212,7 @@ public class InsuranceService(
// Calculate the final return time based on our bonus percent
var finalReturnTimeSeconds =
randomisedReturnTimeSeconds * (1d - insuranceReturnTimeBonusPercent);
return _timeUtil.GetTimeStamp() + finalReturnTimeSeconds;
return timeUtil.GetTimeStamp() + finalReturnTimeSeconds;
}
protected double GetMaxInsuranceStorageTime(TraderBase traderBase)
@@ -223,7 +223,7 @@ public class InsuranceService(
return _insuranceConfig.StorageTimeOverrideSeconds;
}
return _timeUtil.GetHoursAsSeconds((int)traderBase.Insurance.MaxStorageTime);
return timeUtil.GetHoursAsSeconds((int)traderBase.Insurance.MaxStorageTime);
}
/// <summary>
@@ -231,7 +231,7 @@ public class InsuranceService(
/// </summary>
/// <param name="equipmentPkg">Gear to store - generated by GetGearLostInRaid()</param>
public void StoreGearLostInRaidToSendLater(
string sessionID,
MongoId sessionID,
List<InsuranceEquipmentPkg> equipmentPkg
)
{
@@ -250,7 +250,7 @@ public class InsuranceService(
/// <param name="pmcProfile">Player profile</param>
/// <returns>InsuranceEquipmentPkg list</returns>
public List<InsuranceEquipmentPkg> MapInsuredItemsToTrader(
string sessionId,
MongoId sessionId,
List<Item> lostInsuredItems,
PmcData pmcProfile
)
@@ -264,7 +264,7 @@ public class InsuranceService(
);
if (insuranceDetails is null)
{
_logger.Error(
logger.Error(
$"unable to find insurance details for item id: {lostItem.Id} with tpl: {lostItem.Template}"
);
@@ -353,7 +353,7 @@ public class InsuranceService(
/// <param name="sessionId">Player id (session id)</param>
/// <param name="traderId">Trader items insured with</param>
/// <returns>True if exists</returns>
protected bool InsuranceTraderArrayExists(string sessionId, string traderId)
protected bool InsuranceTraderArrayExists(MongoId sessionId, MongoId traderId)
{
return _insured[sessionId].GetValueOrDefault(traderId) is not null;
}
@@ -363,7 +363,7 @@ public class InsuranceService(
/// </summary>
/// <param name="sessionId">Player id (session id)</param>
/// <param name="traderId">Trader items insured with</param>
public void ResetInsuranceTraderArray(string sessionId, string traderId)
public void ResetInsuranceTraderArray(MongoId sessionId, MongoId traderId)
{
_insured[sessionId][traderId] = [];
}
@@ -374,7 +374,7 @@ public class InsuranceService(
/// <param name="sessionId">Player id (session id)</param>
/// <param name="traderId">Trader item insured with</param>
/// <param name="itemToAdd">Insured item (with children)</param>
public void AddInsuranceItemToArray(string sessionId, string traderId, Item itemToAdd)
public void AddInsuranceItemToArray(MongoId sessionId, MongoId traderId, Item itemToAdd)
{
_insured[sessionId][traderId].Add(itemToAdd);
}
@@ -389,12 +389,12 @@ public class InsuranceService(
public double GetRoublePriceToInsureItemWithTrader(
PmcData? pmcData,
Item inventoryItem,
string traderId
MongoId traderId
)
{
var price =
_itemHelper.GetStaticItemPrice(inventoryItem.Template)
* (_traderHelper.GetLoyaltyLevel(traderId, pmcData).InsurancePriceCoefficient / 100);
itemHelper.GetStaticItemPrice(inventoryItem.Template)
* (traderHelper.GetLoyaltyLevel(traderId, pmcData).InsurancePriceCoefficient / 100);
return Math.Ceiling(price ?? 1);
}
@@ -11,9 +11,9 @@ namespace SPTarkov.Server.Core.Services;
/// </summary>
[Injectable(InjectionType.Singleton)]
public class ItemBaseClassService(
ISptLogger<ItemBaseClassService> _logger,
DatabaseService _databaseService,
ServerLocalisationService _serverLocalisationService
ISptLogger<ItemBaseClassService> logger,
DatabaseService databaseService,
ServerLocalisationService serverLocalisationService
)
{
private bool _cacheGenerated;
@@ -28,7 +28,7 @@ public class ItemBaseClassService(
// Clear existing cache
_itemBaseClassesCache = new Dictionary<MongoId, HashSet<MongoId>>();
var items = _databaseService.GetItems();
var items = databaseService.GetItems();
var filteredDbItems = items.Where(x =>
string.Equals(x.Value.Type, "Item", StringComparison.OrdinalIgnoreCase)
);
@@ -54,7 +54,7 @@ public class ItemBaseClassService(
protected void AddBaseItems(MongoId itemIdToUpdate, TemplateItem item)
{
_itemBaseClassesCache[itemIdToUpdate].Add(item.Parent);
_databaseService.GetItems().TryGetValue(item.Parent, out var parent);
databaseService.GetItems().TryGetValue(item.Parent, out var parent);
if (parent is not null && !parent.Parent.IsEmpty())
{
@@ -77,7 +77,7 @@ public class ItemBaseClassService(
if (itemTpl.IsEmpty())
{
_logger.Warning("Unable to check itemTpl base class as value passed is null");
logger.Warning("Unable to check itemTpl base class as value passed is null");
return false;
}
@@ -94,9 +94,9 @@ public class ItemBaseClassService(
return baseClassList.Overlaps(baseClasses);
}
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(_serverLocalisationService.GetText("baseclass-item_not_found", itemTpl));
logger.Debug(serverLocalisationService.GetText("baseclass-item_not_found", itemTpl));
}
// Not found in cache, Hydrate again - some mods add items late
@@ -108,8 +108,8 @@ public class ItemBaseClassService(
return value.Any(baseClasses.Contains);
}
_logger.Warning(
_serverLocalisationService.GetText("baseclass-item_not_found_failed", itemTpl)
logger.Warning(
serverLocalisationService.GetText("baseclass-item_not_found_failed", itemTpl)
);
return false;
@@ -123,7 +123,7 @@ public class ItemBaseClassService(
private bool CachedItemIsOfItemType(MongoId itemTemplateId)
{
return string.Equals(
_databaseService.GetItems()[itemTemplateId]?.Type,
databaseService.GetItems()[itemTemplateId]?.Type,
"Item",
StringComparison.OrdinalIgnoreCase
);
@@ -12,13 +12,13 @@ namespace SPTarkov.Server.Core.Services;
/// </summary>
[Injectable(InjectionType.Singleton)]
public class ItemFilterService(
ISptLogger<ItemFilterService> _logger,
ICloner _cloner,
ConfigServer _configServer
ISptLogger<ItemFilterService> logger,
ICloner cloner,
ConfigServer configServer
)
{
protected readonly HashSet<MongoId>? _itemBlacklistCache = [];
protected readonly ItemConfig _itemConfig = _configServer.GetConfig<ItemConfig>();
protected readonly ItemConfig _itemConfig = configServer.GetConfig<ItemConfig>();
protected readonly HashSet<MongoId>? _lootableItemBlacklistCache = [];
@@ -53,7 +53,7 @@ public class ItemFilterService(
/// <returns> HashSet of item tpls </returns>
public HashSet<MongoId> GetItemRewardBlacklist()
{
return _cloner.Clone(_itemConfig.RewardItemBlacklist);
return cloner.Clone(_itemConfig.RewardItemBlacklist);
}
/// <summary>
@@ -62,7 +62,7 @@ public class ItemFilterService(
/// <returns> HashSet of item base ids </returns>
public HashSet<MongoId> GetItemRewardBaseTypeBlacklist()
{
return _cloner.Clone(_itemConfig.RewardItemTypeBlacklist);
return cloner.Clone(_itemConfig.RewardItemTypeBlacklist);
}
/// <summary>
@@ -71,7 +71,7 @@ public class ItemFilterService(
/// <returns> HashSet of blacklisted template ids </returns>
public HashSet<MongoId> GetBlacklistedItems()
{
return _cloner.Clone(_itemConfig.Blacklist);
return cloner.Clone(_itemConfig.Blacklist);
}
/// <summary>
@@ -80,7 +80,7 @@ public class ItemFilterService(
/// <returns> HashSet of blacklisted template ids </returns>
public HashSet<MongoId> GetBlacklistedLootableItems()
{
return _cloner.Clone(_itemConfig.LootableItemBlacklist);
return cloner.Clone(_itemConfig.LootableItemBlacklist);
}
/// <summary>
@@ -99,7 +99,7 @@ public class ItemFilterService(
/// <returns> HashSet of boss item template ids </returns>
public HashSet<MongoId> GetBossItems()
{
return _cloner.Clone(_itemConfig.BossItems).ToHashSet();
return cloner.Clone(_itemConfig.BossItems).ToHashSet();
}
/// <summary>
@@ -8,12 +8,12 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class LocaleService(
ISptLogger<LocaleService> _logger,
DatabaseServer _databaseServer,
ConfigServer _configServer
ISptLogger<LocaleService> logger,
DatabaseServer databaseServer,
ConfigServer configServer
)
{
protected readonly LocaleConfig _localeConfig = _configServer.GetConfig<LocaleConfig>();
protected readonly LocaleConfig _localeConfig = configServer.GetConfig<LocaleConfig>();
private string _chosenServerLocale = string.Empty;
private string _chosenClientLocale = string.Empty;
@@ -50,7 +50,7 @@ public class LocaleService(
{
localeToReturn = null;
if (
!_databaseServer
!databaseServer
.GetTables()
.Locales.Global.TryGetValue(languageKey, out var keyedLocales)
)
@@ -132,7 +132,7 @@ public class LocaleService(
var platformLocale = GetPlatformLocale();
if (platformLocale == null)
{
_logger.Warning("System language not found, falling back to english");
logger.Warning("System language not found, falling back to english");
return "en";
}
@@ -162,7 +162,7 @@ public class LocaleService(
return "pt-pt";
}
_logger.Debug(
logger.Debug(
$"Unsupported system language found: {baseNameCode}, langCode: {languageCode} falling back to english for server locale"
);
@@ -178,11 +178,11 @@ public class LocaleService(
var platformLocale = GetPlatformLocale();
if (platformLocale == null)
{
_logger.Warning("System language not found, falling back to english");
logger.Warning("System language not found, falling back to english");
return "en";
}
var locales = _databaseServer.GetTables().Locales;
var locales = databaseServer.GetTables().Locales;
var baseNameCode = platformLocale.TwoLetterISOLanguageName.ToLowerInvariant();
if (locales.Global.ContainsKey(baseNameCode))
{
@@ -218,7 +218,7 @@ public class LocaleService(
return "cn";
}
_logger.Debug(
logger.Debug(
$"Unsupported system language found: {languageCode} baseLocale: {baseNameCode}, falling back to english for client locale"
);
return "en";
@@ -19,126 +19,54 @@ using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class LocationLifecycleService
public class LocationLifecycleService(
ISptLogger<LocationLifecycleService> logger,
RewardHelper rewardHelper,
ConfigServer configServer,
TimeUtil timeUtil,
DatabaseService databaseService,
ProfileHelper profileHelper,
ProfileActivityService profileActivityService,
BotNameService botNameService,
ICloner cloner,
RaidTimeAdjustmentService raidTimeAdjustmentService,
LocationLootGenerator locationLootGenerator,
ServerLocalisationService serverLocalisationService,
BotLootCacheService botLootCacheService,
LootGenerator lootGenerator,
MailSendService mailSendService,
TraderHelper traderHelper,
RandomUtil randomUtil,
InRaidHelper inRaidHelper,
PlayerScavGenerator playerScavGenerator,
SaveServer saveServer,
HealthHelper healthHelper,
PmcChatResponseService pmcChatResponseService,
PmcWaveGenerator pmcWaveGenerator,
QuestHelper questHelper,
InsuranceService insuranceService,
MatchBotDetailsCacheService matchBotDetailsCacheService,
BtrDeliveryService btrDeliveryService
)
{
protected ProfileActivityService _profileActivityService;
protected BotGenerationCacheService _botGenerationCacheService;
protected BotLootCacheService _botLootCacheService;
protected BotNameService _botNameService;
protected ICloner _cloner;
protected ConfigServer _configServer;
protected DatabaseService _databaseService;
protected HealthHelper _healthHelper;
protected HideoutConfig _hideoutConfig;
protected InRaidConfig _inRaidConfig;
protected InRaidHelper _inRaidHelper;
protected InsuranceService _insuranceService;
protected ServerLocalisationService _serverLocalisationService;
protected LocationConfig _locationConfig;
protected LocationLootGenerator _locationLootGenerator;
protected ISptLogger<LocationLifecycleService> _logger;
protected LootGenerator _lootGenerator;
protected MailSendService _mailSendService;
protected MatchBotDetailsCacheService _matchBotDetailsCacheService;
protected PlayerScavGenerator _playerScavGenerator;
protected PmcChatResponseService _pmcChatResponseService;
protected PmcConfig _pmcConfig;
protected PmcWaveGenerator _pmcWaveGenerator;
protected ProfileHelper _profileHelper;
protected QuestHelper _questHelper;
protected RagfairConfig _ragfairConfig;
protected RaidTimeAdjustmentService _raidTimeAdjustmentService;
protected RandomUtil _randomUtil;
protected RewardHelper _rewardHelper;
protected SaveServer _saveServer;
protected TimeUtil _timeUtil;
protected TraderConfig _traderConfig;
protected TraderHelper _traderHelper;
protected BtrDeliveryService _btrDeliveryService;
private readonly CounterTrackerHelper _counterTrackerHelper;
public LocationLifecycleService(
ISptLogger<LocationLifecycleService> logger,
RewardHelper rewardHelper,
ConfigServer configServer,
TimeUtil timeUtil,
DatabaseService databaseService,
ProfileHelper profileHelper,
HashUtil hashUtil,
ProfileActivityService profileActivityService,
BotGenerationCacheService botGenerationCacheService,
BotNameService botNameService,
ICloner cloner,
RaidTimeAdjustmentService raidTimeAdjustmentService,
LocationLootGenerator locationLootGenerator,
ServerLocalisationService localisationService,
BotLootCacheService botLootCacheService,
LootGenerator lootGenerator,
MailSendService mailSendService,
TraderHelper traderHelper,
RandomUtil randomUtil,
InRaidHelper inRaidHelper,
PlayerScavGenerator playerScavGenerator,
SaveServer saveServer,
HealthHelper healthHelper,
PmcChatResponseService pmcChatResponseService,
PmcWaveGenerator pmcWaveGenerator,
QuestHelper questHelper,
InsuranceService insuranceService,
MatchBotDetailsCacheService matchBotDetailsCacheService,
BtrDeliveryService btrDeliveryService,
CounterTrackerHelper counterTrackerHelper
)
{
_logger = logger;
_rewardHelper = rewardHelper;
_configServer = configServer;
_timeUtil = timeUtil;
_databaseService = databaseService;
_profileHelper = profileHelper;
_profileActivityService = profileActivityService;
_botGenerationCacheService = botGenerationCacheService;
_botNameService = botNameService;
_cloner = cloner;
_raidTimeAdjustmentService = raidTimeAdjustmentService;
_locationLootGenerator = locationLootGenerator;
_serverLocalisationService = localisationService;
_botLootCacheService = botLootCacheService;
_lootGenerator = lootGenerator;
_mailSendService = mailSendService;
_traderHelper = traderHelper;
_randomUtil = randomUtil;
_inRaidHelper = inRaidHelper;
_playerScavGenerator = playerScavGenerator;
_saveServer = saveServer;
_healthHelper = healthHelper;
_pmcChatResponseService = pmcChatResponseService;
_pmcWaveGenerator = pmcWaveGenerator;
_questHelper = questHelper;
_insuranceService = insuranceService;
_matchBotDetailsCacheService = matchBotDetailsCacheService;
_btrDeliveryService = btrDeliveryService;
_counterTrackerHelper = counterTrackerHelper;
_locationConfig = _configServer.GetConfig<LocationConfig>();
_inRaidConfig = _configServer.GetConfig<InRaidConfig>();
_traderConfig = _configServer.GetConfig<TraderConfig>();
_ragfairConfig = _configServer.GetConfig<RagfairConfig>();
_hideoutConfig = _configServer.GetConfig<HideoutConfig>();
_pmcConfig = _configServer.GetConfig<PmcConfig>();
}
protected LocationConfig _locationConfig = configServer.GetConfig<LocationConfig>();
protected InRaidConfig _inRaidConfig = configServer.GetConfig<InRaidConfig>();
protected TraderConfig _traderConfig = configServer.GetConfig<TraderConfig>();
protected RagfairConfig _ragfairConfig = configServer.GetConfig<RagfairConfig>();
protected HideoutConfig _hideoutConfig = configServer.GetConfig<HideoutConfig>();
protected PmcConfig _pmcConfig = configServer.GetConfig<PmcConfig>();
/// <summary>
/// Handle client/match/local/start
/// </summary>
public virtual StartLocalRaidResponseData StartLocalRaid(
string sessionId,
MongoId sessionId,
StartLocalRaidRequestData request
)
{
_logger.Debug($"Starting: {request.Location}");
logger.Debug($"Starting: {request.Location}");
var playerProfile = _profileHelper.GetFullProfile(sessionId);
var playerProfile = profileHelper.GetFullProfile(sessionId);
// Remove skill fatigue values
ResetSkillPointsEarnedDuringRaid(
@@ -154,8 +82,8 @@ public class LocationLifecycleService
var result = new StartLocalRaidResponseData
{
// PVE_OFFLINE_xxxxxxxx_27_06_2025_20_20_44
ServerId = $"{request.Location}.{request.PlayerSide} {_timeUtil.GetTimeStamp()}", // Only used for metrics in client
ServerSettings = _databaseService.GetLocationServices(), // TODO - is this per map or global?
ServerId = $"{request.Location}.{request.PlayerSide} {timeUtil.GetTimeStamp()}", // Only used for metrics in client
ServerSettings = databaseService.GetLocationServices(), // TODO - is this per map or global?
Profile = new ProfileInsuredItems
{
InsuredItems = playerProfile.CharacterData.PmcData.InsuredItems,
@@ -184,13 +112,13 @@ public class LocationLifecycleService
}
// Get data stored at end of previous raid (if any)
var transitionData = _profileActivityService
var transitionData = profileActivityService
.GetProfileActivityRaidData(sessionId)
?.LocationTransit;
if (transitionData is not null)
{
_logger.Success($"Player: {sessionId} is in transit to {request.Location}");
logger.Success($"Player: {sessionId} is in transit to {request.Location}");
result.Transition.TransitionType = TransitionType.COMMON;
result.Transition.TransitionRaidId = transitionData.TransitionRaidId;
result.Transition.TransitionCount += 1;
@@ -199,7 +127,7 @@ public class LocationLifecycleService
result.Transition.VisitedLocations.Add(transitionData.SptLastVisitedLocation);
// Complete, clean up as no longer needed
_profileActivityService.GetProfileActivityRaidData(sessionId).LocationTransit = null;
profileActivityService.GetProfileActivityRaidData(sessionId).LocationTransit = null;
}
// Apply changes from pmcConfig to bot hostility values
@@ -208,8 +136,7 @@ public class LocationLifecycleService
AdjustExtracts(request.PlayerSide, request.Location, result.LocationLoot);
// Clear bot cache ready for bot generation call that occurs after this
_botGenerationCacheService.ClearStoredBots();
_botNameService.ClearNameCache();
botNameService.ClearNameCache();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true);
@@ -231,10 +158,10 @@ public class LocationLifecycleService
}
// Get relevant extract data for map
var mapExtracts = _databaseService.GetLocation(location)?.AllExtracts;
var mapExtracts = databaseService.GetLocation(location)?.AllExtracts;
if (mapExtracts is null)
{
_logger.Warning($"Unable to find map: {location} extract data, no adjustments made");
logger.Warning($"Unable to find map: {location} extract data, no adjustments made");
return;
}
@@ -274,7 +201,7 @@ public class LocationLifecycleService
// No matching bot in config, skip
if (locationBotHostilityDetails is null)
{
_logger.Warning(
logger.Warning(
$"No bot: {botId} hostility values found on: {location.Id}, can only edit existing. Skipping"
);
@@ -367,16 +294,16 @@ public class LocationLifecycleService
/// <param name="generateLoot"> OPTIONAL - Should loot be generated for the map before being returned </param>
/// <returns>LocationBase with loot</returns>
public virtual LocationBase GenerateLocationAndLoot(
string sessionId,
MongoId sessionId,
string name,
bool generateLoot = true
)
{
var location = _databaseService.GetLocation(name);
var locationBaseClone = _cloner.Clone(location.Base);
var location = databaseService.GetLocation(name);
var locationBaseClone = cloner.Clone(location.Base);
// Update datetime property to now
locationBaseClone.UnixDateTime = _timeUtil.GetTimeStamp();
locationBaseClone.UnixDateTime = timeUtil.GetTimeStamp();
// Don't generate loot for hideout
if (string.Equals(name, "hideout", StringComparison.OrdinalIgnoreCase))
@@ -391,30 +318,30 @@ public class LocationLifecycleService
}
// Add custom PMCs to map every time its run
_pmcWaveGenerator.ApplyWaveChangesToMap(locationBaseClone);
pmcWaveGenerator.ApplyWaveChangesToMap(locationBaseClone);
// Adjust raid values based raid type (e.g. Scav or PMC)
LocationConfig? locationConfigClone = null;
var raidAdjustments = _profileActivityService
var raidAdjustments = profileActivityService
.GetProfileActivityRaidData(sessionId)
?.RaidAdjustments;
if (raidAdjustments is not null)
{
locationConfigClone = _cloner.Clone(_locationConfig); // Clone values so they can be used to reset originals later
_raidTimeAdjustmentService.MakeAdjustmentsToMap(raidAdjustments, locationBaseClone);
locationConfigClone = cloner.Clone(_locationConfig); // Clone values so they can be used to reset originals later
raidTimeAdjustmentService.MakeAdjustmentsToMap(raidAdjustments, locationBaseClone);
}
// Generate loot for location
locationBaseClone.Loot = _locationLootGenerator.GenerateLocationLoot(name);
locationBaseClone.Loot = locationLootGenerator.GenerateLocationLoot(name);
// Reset loot multipliers back to original values
if (raidAdjustments is not null && locationConfigClone is not null)
{
_logger.Debug("Resetting loot multipliers back to their original values");
logger.Debug("Resetting loot multipliers back to their original values");
_locationConfig.StaticLootMultiplier = locationConfigClone.StaticLootMultiplier;
_locationConfig.LooseLootMultiplier = locationConfigClone.LooseLootMultiplier;
_profileActivityService.GetProfileActivityRaidData(sessionId).RaidAdjustments = null;
profileActivityService.GetProfileActivityRaidData(sessionId).RaidAdjustments = null;
}
return locationBaseClone;
@@ -423,18 +350,18 @@ public class LocationLifecycleService
/// <summary>
/// Handle client/match/local/end
/// </summary>
public virtual void EndLocalRaid(string sessionId, EndLocalRaidRequestData request)
public virtual void EndLocalRaid(MongoId sessionId, EndLocalRaidRequestData request)
{
// Clear bot loot cache
_botLootCacheService.ClearCache();
botLootCacheService.ClearCache();
var fullProfile = _profileHelper.GetFullProfile(sessionId);
var fullProfile = profileHelper.GetFullProfile(sessionId);
var pmcProfile = fullProfile.CharacterData.PmcData;
var scavProfile = fullProfile.CharacterData.ScavData;
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Raid: {request.ServerId} outcome: {request.Results.Result}");
logger.Debug($"Raid: {request.ServerId} outcome: {request.Results.Result}");
}
// Reset flea interval time to out-of-raid value
@@ -451,7 +378,7 @@ public class LocationLifecycleService
var isSurvived = IsPlayerSurvived(request.Results);
// Handle items transferred via BTR or transit to player mailbox
_btrDeliveryService.HandleItemTransferEvent(sessionId, request);
btrDeliveryService.HandleItemTransferEvent(sessionId, request);
// Player is moving between maps
if (isTransfer && request.LocationTransit is not null)
@@ -461,7 +388,7 @@ public class LocationLifecycleService
// TODO - Persist each players last visited location history over multiple transits, e.g. using InMemoryCacheService, need to take care to not let data get stored forever
// Store transfer data for later use in `startLocalRaid()` when next raid starts
request.LocationTransit.SptExitName = request.Results.ExitName;
_profileActivityService.GetProfileActivityRaidData(sessionId).LocationTransit =
profileActivityService.GetProfileActivityRaidData(sessionId).LocationTransit =
request.LocationTransit;
}
@@ -513,10 +440,10 @@ public class LocationLifecycleService
/// After taking a COOP extract, send player a gift via mail
/// </summary>
/// <param name="sessionId">Player/Session id</param>
protected void SendCoopTakenFenceMessage(string sessionId)
protected void SendCoopTakenFenceMessage(MongoId sessionId)
{
// Generate randomised reward for taking coop extract
var loot = _lootGenerator.CreateRandomLoot(_traderConfig.Fence.CoopExtractGift);
var loot = lootGenerator.CreateRandomLoot(_traderConfig.Fence.CoopExtractGift);
var parentId = new MongoId();
foreach (var itemAndChildren in loot)
@@ -529,13 +456,13 @@ public class LocationLifecycleService
List<Item> mailableLoot = [.. loot.SelectMany(x => x)];
// Send message from fence giving player reward generated above
_mailSendService.SendLocalisedNpcMessageToPlayer(
mailSendService.SendLocalisedNpcMessageToPlayer(
sessionId,
Traders.FENCE,
MessageType.MessageWithItems,
_randomUtil.GetArrayValue(_traderConfig.Fence.CoopExtractGift.MessageLocaleIds),
randomUtil.GetArrayValue(_traderConfig.Fence.CoopExtractGift.MessageLocaleIds),
mailableLoot,
_timeUtil.GetHoursAsSeconds(_traderConfig.Fence.CoopExtractGift.GiftExpiryHours)
timeUtil.GetHoursAsSeconds(_traderConfig.Fence.CoopExtractGift.GiftExpiryHours)
);
}
@@ -566,7 +493,7 @@ public class LocationLifecycleService
/// <param name="extractName"> Name of the extract used </param>
/// <param name="pmcData"> Player profile </param>
/// <param name="sessionId"> Session ID </param>
protected void HandleCarExtract(string extractName, PmcData pmcData, string sessionId)
protected void HandleCarExtract(string extractName, PmcData pmcData, MongoId sessionId)
{
pmcData.CarExtractCounts?.TryAdd(extractName, 0);
@@ -583,18 +510,18 @@ public class LocationLifecycleService
pmcData.TradersInfo[fenceId].Standing = newFenceStanding;
// Check if new standing has leveled up trader
_traderHelper.LevelUp(fenceId, pmcData);
traderHelper.LevelUp(fenceId, pmcData);
pmcData.TradersInfo[fenceId].LoyaltyLevel = Math.Max(
(int)pmcData.TradersInfo[fenceId].LoyaltyLevel,
1
);
_logger.Debug(
logger.Debug(
$"Car extract: {extractName} used, total times taken: {pmcData.CarExtractCounts[extractName]}"
);
// Copy updated fence rep values into scav profile to ensure consistency
var scavData = _profileHelper.GetScavProfile(sessionId);
var scavData = profileHelper.GetScavProfile(sessionId);
scavData.TradersInfo[fenceId].Standing = pmcData.TradersInfo[fenceId].Standing;
scavData.TradersInfo[fenceId].LoyaltyLevel = pmcData.TradersInfo[fenceId].LoyaltyLevel;
}
@@ -605,7 +532,7 @@ public class LocationLifecycleService
/// <param name="sessionId"> Session/player id </param>
/// <param name="pmcData"> Player profile </param>
/// <param name="extractName"> Name of extract taken </param>
protected void HandleCoopExtract(string sessionId, PmcData pmcData, string extractName)
protected void HandleCoopExtract(MongoId sessionId, PmcData pmcData, string extractName)
{
pmcData.CoopExtractCounts?.TryAdd(extractName, 0);
@@ -621,16 +548,16 @@ public class LocationLifecycleService
pmcData.TradersInfo[fenceId].Standing = newFenceStanding;
// Check if new standing has leveled up trader
_traderHelper.LevelUp(fenceId, pmcData);
traderHelper.LevelUp(fenceId, pmcData);
pmcData.TradersInfo[fenceId].LoyaltyLevel = Math.Max(
(int)pmcData.TradersInfo[fenceId].LoyaltyLevel,
1
);
_logger.Debug($"COOP extract: {extractName} used");
logger.Debug($"COOP extract: {extractName} used");
// Copy updated fence rep values into scav profile to ensure consistency
var scavData = _profileHelper.GetScavProfile(sessionId);
var scavData = profileHelper.GetScavProfile(sessionId);
scavData.TradersInfo[fenceId].Standing = pmcData.TradersInfo[fenceId].Standing;
scavData.TradersInfo[fenceId].LoyaltyLevel = pmcData.TradersInfo[fenceId].LoyaltyLevel;
}
@@ -656,7 +583,7 @@ public class LocationLifecycleService
// Ensure fence loyalty level is not above/below the range -7 to 15
var newFenceStanding = Math.Min(Math.Max((double)fenceStanding, -7), 15);
_logger.Debug(
logger.Debug(
$"Old vs new fence standing: {pmcData.TradersInfo[fenceId].Standing}, {newFenceStanding}"
);
@@ -690,7 +617,7 @@ public class LocationLifecycleService
/// <param name="isSurvived">DId player get 'survived' exit status</param>
/// <param name="request">End raid request</param>
protected void HandlePostRaidPlayerScav(
string sessionId,
MongoId sessionId,
PmcData pmcProfile,
PmcData scavProfile,
bool isDead,
@@ -711,7 +638,7 @@ public class LocationLifecycleService
// We want scav inventory to persist into next raid when pscav is moving between maps
// Also adjust FiR status when exit was runthrough
_inRaidHelper.SetInventory(
inRaidHelper.SetInventory(
sessionId,
scavProfile,
postRaidProfile,
@@ -742,7 +669,7 @@ public class LocationLifecycleService
var fenceMin = _traderConfig.Fence.PlayerRepMin; //-7
if (!postRaidProfile.TradersInfo.TryGetValue(Traders.FENCE, out var postRaidFenceData))
{
_logger.Error($"post raid fence data not found for: {sessionId}");
logger.Error($"post raid fence data not found for: {sessionId}");
}
scavProfile.TradersInfo[Traders.FENCE].Standing = Math.Min(
@@ -775,14 +702,14 @@ public class LocationLifecycleService
// Scav died, regen scav loadout and reset timer
if (isDead)
{
_playerScavGenerator.Generate(sessionId);
playerScavGenerator.Generate(sessionId);
}
// Update last played property
pmcProfile.Info.LastTimePlayedAsSavage = _timeUtil.GetTimeStamp();
pmcProfile.Info.LastTimePlayedAsSavage = timeUtil.GetTimeStamp();
// Force a profile save
_saveServer.SaveProfileAsync(sessionId);
saveServer.SaveProfileAsync(sessionId);
}
/// <summary>
@@ -797,8 +724,8 @@ public class LocationLifecycleService
var pmcQuest = pmcProfile.Quests.FirstOrDefault(quest => quest.QId == scavQuest.QId);
if (pmcQuest is null)
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"inraid-unable_to_migrate_pmc_quest_not_found_in_profile",
scavQuest.QId
)
@@ -838,7 +765,7 @@ public class LocationLifecycleService
var transitSettings = _locationConfig.TransitSettings;
if (transitSettings == null)
{
_logger.Warning("Unable to find: _locationConfig.TransitSettings");
logger.Warning("Unable to find: _locationConfig.TransitSettings");
return;
}
@@ -852,7 +779,7 @@ public class LocationLifecycleService
)
{
// Limb has been destroyed, reset
hpValues.Health.Current = _randomUtil.GetPercentOfValue(
hpValues.Health.Current = randomUtil.GetPercentOfValue(
transitSettings.LimbHealPercent.GetValueOrDefault(30),
hpValues.Health.Maximum.Value
);
@@ -888,7 +815,7 @@ public class LocationLifecycleService
/// <param name="request"> Client request data </param>
/// <param name="locationName"> Current finished Raid location </param>
protected void HandlePostRaidPmc(
string sessionId,
MongoId sessionId,
SptProfile fullServerProfile,
PmcData scavProfile,
bool isDead,
@@ -900,14 +827,14 @@ public class LocationLifecycleService
{
var serverPmcProfile = fullServerProfile.CharacterData.PmcData;
var postRaidProfile = request.Results.Profile;
var preRaidProfileQuestDataClone = _cloner.Clone(serverPmcProfile.Quests);
var preRaidProfileQuestDataClone = cloner.Clone(serverPmcProfile.Quests);
// MUST occur BEFORE inventory actions (setInventory()) occur
// Player died, get quest items they lost for use later
var lostQuestItems = postRaidProfile.GetQuestItemsInProfile();
// Update inventory
_inRaidHelper.SetInventory(
inRaidHelper.SetInventory(
sessionId,
serverPmcProfile,
postRaidProfile,
@@ -961,7 +888,7 @@ public class LocationLifecycleService
MergePmcAndScavEncyclopedias(serverPmcProfile, scavProfile);
// Handle temp, hydration, limb hp/effects
_healthHelper.ApplyHealthChangesToProfile(
healthHelper.ApplyHealthChangesToProfile(
sessionId,
serverPmcProfile,
postRaidProfile.Health,
@@ -994,16 +921,16 @@ public class LocationLifecycleService
{
// get the aggressor ID from the client request body
postRaidProfile.Stats.Eft.Aggressor.ProfileId = request.Results.KillerId;
_pmcChatResponseService.SendKillerResponse(
pmcChatResponseService.SendKillerResponse(
sessionId,
serverPmcProfile,
postRaidProfile.Stats.Eft.Aggressor
);
}
_inRaidHelper.DeleteInventory(serverPmcProfile, sessionId);
inRaidHelper.DeleteInventory(serverPmcProfile, sessionId);
_inRaidHelper.RemoveFiRStatusFromItemsInContainer(
inRaidHelper.RemoveFiRStatusFromItemsInContainer(
sessionId,
serverPmcProfile,
"SecuredContainer"
@@ -1011,7 +938,7 @@ public class LocationLifecycleService
}
// Must occur AFTER killer messages have been sent
_matchBotDetailsCacheService.ClearCache();
matchBotDetailsCacheService.ClearCache();
var roles = new List<string> { "pmcbear", "pmcusec" };
@@ -1021,7 +948,7 @@ public class LocationLifecycleService
if (victims?.Count > 0)
// Player killed PMCs, send some mail responses to them
{
_pmcChatResponseService.SendVictimResponse(sessionId, victims, serverPmcProfile);
pmcChatResponseService.SendVictimResponse(sessionId, victims, serverPmcProfile);
}
}
@@ -1033,7 +960,7 @@ public class LocationLifecycleService
/// <param name="lostQuestItems"> Quest items lost on player death </param>
/// <param name="profileQuests"> Quest status data from player profile </param>
protected void CheckForAndFixPickupQuestsAfterDeath(
string sessionId,
MongoId sessionId,
List<Item> lostQuestItems,
List<QuestStatus> profileQuests
)
@@ -1048,7 +975,7 @@ public class LocationLifecycleService
.Select(status => status.QId);
// Get db details of quests we found above
var questDb = _databaseService
var questDb = databaseService
.GetQuests()
.Values.Where(quest => activeQuestIdsInProfile.Contains(quest.Id));
@@ -1083,7 +1010,7 @@ public class LocationLifecycleService
// Fail if multiple were found
if (matchingQuests.Count != 1)
{
_logger.Error(
logger.Error(
$"Unable to fix quest item: {lostItem}, {matchingQuests.Count} matching quests found, expected 1"
);
@@ -1118,7 +1045,7 @@ public class LocationLifecycleService
/// <param name="preRaidQuests"> Quest statuses pre-raid </param>
/// <param name="pmcProfile"> Players profile </param>
protected void LightkeeperQuestWorkaround(
string sessionId,
MongoId sessionId,
List<QuestStatus> postRaidQuests,
List<QuestStatus> preRaidQuests,
PmcData pmcProfile
@@ -1135,7 +1062,7 @@ public class LocationLifecycleService
preRaidQuest.Status != QuestStatusEnum.Success
)
&& // Completed quest was not completed before raid started
_databaseService.GetQuests().TryGetValue(postRaidQuest.QId, out var quest)
databaseService.GetQuests().TryGetValue(postRaidQuest.QId, out var quest)
&& quest?.TraderId == Traders.LIGHTHOUSEKEEPER
) // Quest is from LK
.ToList();
@@ -1143,7 +1070,7 @@ public class LocationLifecycleService
// Run server complete quest process to ensure player gets rewards
foreach (var questToComplete in newlyCompletedLightkeeperQuests)
{
_questHelper.CompleteQuest(
questHelper.CompleteQuest(
pmcProfile,
new CompleteQuestRequestData
{
@@ -1169,7 +1096,7 @@ public class LocationLifecycleService
);
foreach (var failedQuest in failedQuests)
{
var dbQuest = _databaseService.GetQuests()[failedQuest.QId];
var dbQuest = databaseService.GetQuests()[failedQuest.QId];
if (dbQuest is null)
{
continue;
@@ -1216,7 +1143,7 @@ public class LocationLifecycleService
}
protected void HandleInsuredItemLostEvent(
string sessionId,
MongoId sessionId,
PmcData preRaidPmcProfile,
EndLocalRaidRequestData request,
string locationName
@@ -1224,7 +1151,7 @@ public class LocationLifecycleService
{
if (request.LostInsuredItems?.Count > 0)
{
var mappedItems = _insuranceService.MapInsuredItemsToTrader(
var mappedItems = insuranceService.MapInsuredItemsToTrader(
sessionId,
request.LostInsuredItems,
preRaidPmcProfile
@@ -1236,9 +1163,9 @@ public class LocationLifecycleService
return;
}
_insuranceService.StoreGearLostInRaidToSendLater(sessionId, mappedItems);
insuranceService.StoreGearLostInRaidToSendLater(sessionId, mappedItems);
_insuranceService.StartPostRaidInsuranceLostProcess(
insuranceService.StartPostRaidInsuranceLostProcess(
preRaidPmcProfile,
sessionId,
locationName
@@ -1330,7 +1257,7 @@ public class LocationLifecycleService
);
// Get achievement data from db
var achievementsDb = _databaseService.GetTemplates().Achievements;
var achievementsDb = databaseService.GetTemplates().Achievements;
// Map the achievement ids player obtained in raid with matching achievement data from db
var achievements = achievementIdsAcquiredThisRaid.Select(achievementId =>
@@ -1344,7 +1271,7 @@ public class LocationLifecycleService
foreach (var achievement in achievements)
{
var rewardItems = _rewardHelper.ApplyRewards(
var rewardItems = rewardHelper.ApplyRewards(
achievement.Rewards,
CustomisationSource.ACHIEVEMENT,
fullProfile,
@@ -1354,12 +1281,12 @@ public class LocationLifecycleService
if (rewardItems?.Count > 0)
{
_mailSendService.SendLocalisedSystemMessageToPlayer(
sessionId,
mailSendService.SendLocalisedSystemMessageToPlayer(
sessionId.Value,
"670547bb5fa0b1a7c30d5836 0",
rewardItems,
[],
_timeUtil.GetHoursAsSeconds(24 * 7)
timeUtil.GetHoursAsSeconds(24 * 7)
);
}
}
@@ -16,16 +16,16 @@ namespace SPTarkov.Server.Core.Services;
[Injectable]
public class MailSendService(
ISptLogger<MailSendService> _logger,
TimeUtil _timeUtil,
SaveServer _saveServer,
DatabaseService _databaseService,
NotifierHelper _notifierHelper,
DialogueHelper _dialogueHelper,
NotificationSendHelper _notificationSendHelper,
ServerLocalisationService _serverLocalisationService,
ItemHelper _itemHelper,
ICloner _cloner
ISptLogger<MailSendService> logger,
TimeUtil timeUtil,
SaveServer saveServer,
DatabaseService databaseService,
NotifierHelper notifierHelper,
DialogueHelper dialogueHelper,
NotificationSendHelper notificationSendHelper,
ServerLocalisationService serverLocalisationService,
ItemHelper itemHelper,
ICloner cloner
)
{
private const string _systemSenderId = "59e7125688a45068a6249071";
@@ -48,7 +48,7 @@ public class MailSendService(
/// <param name="systemData"> </param>
/// <param name="ragfair"> </param>
public void SendDirectNpcMessageToPlayer(
string sessionId,
MongoId sessionId,
string? trader,
MessageType messageType,
string message,
@@ -60,8 +60,8 @@ public class MailSendService(
{
if (trader is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"mailsend-missing_trader",
new { messageType, sessionId }
)
@@ -112,7 +112,7 @@ public class MailSendService(
/// <param name="systemData"></param>
/// <param name="ragfair"></param>
public void SendLocalisedNpcMessageToPlayer(
string sessionId,
MongoId sessionId,
string? trader,
MessageType messageType,
string messageLocaleId,
@@ -124,8 +124,8 @@ public class MailSendService(
{
if (trader is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"mailsend-missing_trader",
new { messageType, sessionId }
)
@@ -175,7 +175,7 @@ public class MailSendService(
/// <param name="maxStorageTimeSeconds"> Optional time to collect items before they expire </param>
/// <param name="profileChangeEvents"></param>
public void SendSystemMessageToPlayer(
string sessionId,
MongoId sessionId,
string message,
List<Item>? items,
long? maxStorageTimeSeconds = 172800,
@@ -216,7 +216,7 @@ public class MailSendService(
/// <param name="profileChangeEvents"></param>
/// <param name="maxStorageTimeSeconds"> Optional time to collect items before they expire </param>
public void SendLocalisedSystemMessageToPlayer(
string sessionId,
MongoId sessionId,
string messageLocaleId,
List<Item>? items,
List<ProfileChangeEvent>? profileChangeEvents,
@@ -255,7 +255,7 @@ public class MailSendService(
/// <param name="items"> Optional items to send to player </param>
/// <param name="maxStorageTimeSeconds"> Optional time to collect items before they expire </param>
public void SendUserMessageToPlayer(
string sessionId,
MongoId sessionId,
UserDialogInfo senderDetails,
string message,
List<Item>? items = null,
@@ -329,17 +329,17 @@ public class MailSendService(
&& messageDetails?.RagfairDetails is not null
)
{
var offerSoldMessage = _notifierHelper.CreateRagfairOfferSoldNotification(
var offerSoldMessage = notifierHelper.CreateRagfairOfferSoldNotification(
message,
messageDetails.RagfairDetails
);
_notificationSendHelper.SendMessage(messageDetails.RecipientId, offerSoldMessage);
notificationSendHelper.SendMessage(messageDetails.RecipientId, offerSoldMessage);
message.MessageType = MessageType.MessageWithItems; // Should prevent getting the same notification popup twice
}
// Send message off to player so they get it in client
var notificationMessage = _notifierHelper.CreateNewMessageNotification(message);
_notificationSendHelper.SendMessage(messageDetails.RecipientId, notificationMessage);
var notificationMessage = notifierHelper.CreateNewMessageNotification(message);
notificationSendHelper.SendMessage(messageDetails.RecipientId, notificationMessage);
}
/// <summary>
@@ -348,16 +348,16 @@ public class MailSendService(
/// <param name="sessionId"> Session ID </param>
/// <param name="targetNpcId"> NPC message is sent to </param>
/// <param name="message"> Text to send to NPC </param>
public void SendPlayerMessageToNpc(string sessionId, string targetNpcId, string message)
public void SendPlayerMessageToNpc(MongoId sessionId, string targetNpcId, string message)
{
var playerProfile = _saveServer.GetProfile(sessionId);
var playerProfile = saveServer.GetProfile(sessionId);
if (
playerProfile.DialogueRecords is null
|| !playerProfile.DialogueRecords.TryGetValue(targetNpcId, out var dialogWithNpc)
)
{
_logger.Error(
_serverLocalisationService.GetText("mailsend-missing_npc_dialog", targetNpcId)
logger.Error(
serverLocalisationService.GetText("mailsend-missing_npc_dialog", targetNpcId)
);
return;
}
@@ -366,7 +366,7 @@ public class MailSendService(
new Message
{
Id = new MongoId(),
DateTime = _timeUtil.GetTimeStamp(),
DateTime = timeUtil.GetTimeStamp(),
HasRewards = false,
UserId = playerProfile.CharacterData.PmcData.Id,
MessageType = MessageType.UserMessage,
@@ -389,7 +389,7 @@ public class MailSendService(
Id = new MongoId(),
UserId = dialogId,
MessageType = messageDetails.Sender,
DateTime = _timeUtil.GetTimeStamp(),
DateTime = timeUtil.GetTimeStamp(),
Text = messageDetails.TemplateId is not null ? "" : messageDetails.MessageText,
TemplateId = messageDetails.TemplateId,
HasRewards = false,
@@ -427,11 +427,11 @@ public class MailSendService(
/// <returns> A new instance with data from the found message, otherwise undefined </returns>
protected ReplyTo? GetMessageToReplyTo(string recipientId, string replyToId, string dialogueId)
{
var currentDialogue = _dialogueHelper.GetDialogueFromProfile(recipientId, dialogueId);
var currentDialogue = dialogueHelper.GetDialogueFromProfile(recipientId, dialogueId);
if (currentDialogue is null)
{
_logger.Warning($"Unable to find dialogue: {dialogueId} from sender");
logger.Warning($"Unable to find dialogue: {dialogueId} from sender");
return null;
}
@@ -485,7 +485,7 @@ public class MailSendService(
SendMessageDetails messageDetails
)
{
var items = _databaseService.GetItems();
var items = databaseService.GetItems();
MessageItems itemsToSendToPlayer = new();
if ((messageDetails.Items?.Count ?? 0) > 0)
@@ -494,7 +494,7 @@ public class MailSendService(
var parentItem = GetBaseItemFromRewards(messageDetails.Items);
if (parentItem is null)
{
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"mailsend-missing_parent",
new { traderId = messageDetails.Trader, sender = messageDetails.Sender }
);
@@ -516,7 +516,7 @@ public class MailSendService(
};
// Ensure Ids are unique and cont collide with items in player inventory later
messageDetails.Items = _cloner.Clone(messageDetails.Items).ReplaceIDs().ToList();
messageDetails.Items = cloner.Clone(messageDetails.Items).ReplaceIDs().ToList();
// Ensure item exits in items db
foreach (var reward in messageDetails.Items)
@@ -524,8 +524,8 @@ public class MailSendService(
var itemTemplate = items[reward.Template];
if (itemTemplate is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"dialog-missing_item_template",
new { tpl = reward.Template, type = dialogType }
)
@@ -547,7 +547,7 @@ public class MailSendService(
}
// Boxes can contain sub-items
if (_itemHelper.IsOfBaseclass(itemTemplate.Id, BaseClasses.AMMO_BOX))
if (itemHelper.IsOfBaseclass(itemTemplate.Id, BaseClasses.AMMO_BOX))
{
// look for child cartridge objects
var childItems = messageDetails.Items?.Where(x => x.ParentId == reward.Id);
@@ -555,7 +555,7 @@ public class MailSendService(
{
// No cartridges found, generate and add to rewards
var boxAndCartridges = new List<Item> { reward };
_itemHelper.AddCartridgesToAmmoBox(boxAndCartridges, itemTemplate);
itemHelper.AddCartridgesToAmmoBox(boxAndCartridges, itemTemplate);
// Push box + cartridge children into array
itemsToSendToPlayer.Data.AddRange(boxAndCartridges);
@@ -570,8 +570,8 @@ public class MailSendService(
{
if (itemTemplate.Properties.StackSlots is not null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"mail-unable_to_give_gift_not_handled",
itemTemplate.Id
)
@@ -636,14 +636,14 @@ public class MailSendService(
if (senderId is null)
{
throw new Exception(
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"mail-unable_to_find_message_sender_by_id",
messageDetails.Sender
)
);
}
var dialogsInProfile = _dialogueHelper.GetDialogsForProfile(messageDetails.RecipientId);
var dialogsInProfile = dialogueHelper.GetDialogsForProfile(messageDetails.RecipientId);
// Does dialog exist
if (!dialogsInProfile.ContainsKey(senderId))
@@ -680,9 +680,9 @@ public class MailSendService(
|| messageDetails.DialogType == MessageType.NpcTraderMessage
)
{
if (messageDetails.Trader == null && _logger.IsLogEnabled(LogLevel.Debug))
if (messageDetails.Trader == null && logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Trader was null for {messageDetails.TemplateId}");
logger.Debug($"Trader was null for {messageDetails.TemplateId}");
}
return messageDetails.Trader;
@@ -703,7 +703,7 @@ public class MailSendService(
return messageDetails.Trader;
}
_logger.Warning($"Unable to handle message of type: {messageDetails.Sender}");
logger.Warning($"Unable to handle message of type: {messageDetails.Sender}");
return null;
}
}
@@ -8,7 +8,7 @@ using SPTarkov.Server.Core.Models.Utils;
namespace SPTarkov.Server.Core.Services;
[Injectable]
public class MapMarkerService(ISptLogger<MapMarkerService> _logger)
public class MapMarkerService(ISptLogger<MapMarkerService> logger)
{
/// <summary>
/// Add note to a map item in player inventory
@@ -74,7 +74,7 @@ public class MapMarkerService(ISptLogger<MapMarkerService> _logger)
if (markerToRemove is null)
{
_logger.Warning($"No marker found for item {request.Item}");
logger.Warning($"No marker found for item {request.Item}");
return null;
}
@@ -12,7 +12,7 @@ namespace SPTarkov.Server.Core.Services;
/// Cache bots in a dictionary, keyed by the bots ID
/// </summary>
[Injectable(InjectionType.Singleton)]
public class MatchBotDetailsCacheService(ISptLogger<MatchBotDetailsCacheService> _logger)
public class MatchBotDetailsCacheService(ISptLogger<MatchBotDetailsCacheService> logger)
{
private static readonly HashSet<string> _sidesToCache = [Sides.PmcUsec, Sides.PmcBear];
@@ -32,7 +32,7 @@ public class MatchBotDetailsCacheService(ISptLogger<MatchBotDetailsCacheService>
if (botToCache.Info?.Nickname is null)
{
_logger.Warning(
logger.Warning(
$"Unable to cache: {botToCache.Info?.Settings?.Role} bot with id: {botToCache.Id} as it lacks a nickname"
);
return;
@@ -83,7 +83,7 @@ public class MatchBotDetailsCacheService(ISptLogger<MatchBotDetailsCacheService>
var botInCache = BotDetailsCache.GetValueOrDefault(id, null);
if (botInCache is null)
{
_logger.Warning($"Bot not found in match bot cache: {id}");
logger.Warning($"Bot not found in match bot cache: {id}");
return null;
}
@@ -1,4 +1,5 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Ws;
namespace SPTarkov.Server.Core.Services;
@@ -6,19 +7,19 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class NotificationService
{
protected readonly Dictionary<string, List<WsNotificationEvent>> _messageQueue = new();
protected readonly Dictionary<MongoId, List<WsNotificationEvent>> _messageQueue = new();
public Dictionary<string, List<WsNotificationEvent>> GetMessageQueue()
public Dictionary<MongoId, List<WsNotificationEvent>> GetMessageQueue()
{
return _messageQueue;
}
public List<WsNotificationEvent>? GetMessageFromQueue(string sessionId)
public List<WsNotificationEvent>? GetMessageFromQueue(MongoId sessionId)
{
return _messageQueue.GetValueOrDefault(sessionId);
}
public void UpdateMessageOnQueue(string sessionId, List<WsNotificationEvent> value)
public void UpdateMessageOnQueue(MongoId sessionId, List<WsNotificationEvent> value)
{
if (_messageQueue.ContainsKey(sessionId))
{
@@ -26,7 +27,7 @@ public class NotificationService
}
}
public bool Has(string sessionID)
public bool Has(MongoId sessionID)
{
return _messageQueue.ContainsKey(sessionID);
}
@@ -34,7 +35,7 @@ public class NotificationService
/// <summary>
/// Pop first message from queue.
/// </summary>
public WsNotificationEvent Pop(string sessionID)
public WsNotificationEvent Pop(MongoId sessionID)
{
var result = Get(sessionID).First();
Get(sessionID).Remove(result);
@@ -44,7 +45,7 @@ public class NotificationService
/// <summary>
/// Add message to queue
/// </summary>
public void Add(string sessionID, WsNotificationEvent message)
public void Add(MongoId sessionID, WsNotificationEvent message)
{
Get(sessionID).Add(message);
}
@@ -53,9 +54,9 @@ public class NotificationService
/// Get message queue for session
/// </summary>
/// <param name="sessionID">Session/player id</param>
public List<WsNotificationEvent> Get(string sessionID)
public List<WsNotificationEvent> Get(MongoId sessionID)
{
if (sessionID is null)
if (sessionID.IsEmpty())
{
throw new Exception("sessionID missing");
}
@@ -10,13 +10,13 @@ namespace SPTarkov.Server.Core.Services;
/// </summary>
[Injectable(InjectionType.Singleton)]
public class OpenZoneService(
ISptLogger<OpenZoneService> _logger,
DatabaseService _databaseService,
ServerLocalisationService _serverLocalisationService,
ConfigServer _configServer
ISptLogger<OpenZoneService> logger,
DatabaseService databaseService,
ServerLocalisationService serverLocalisationService,
ConfigServer configServer
)
{
protected readonly LocationConfig _locationConfig = _configServer.GetConfig<LocationConfig>();
protected readonly LocationConfig _locationConfig = configServer.GetConfig<LocationConfig>();
/// <summary>
/// Add open zone to specified map
@@ -38,13 +38,13 @@ public class OpenZoneService(
/// </summary>
public void ApplyZoneChangesToAllMaps()
{
var dbLocations = _databaseService.GetLocations().GetDictionary();
var dbLocations = databaseService.GetLocations().GetDictionary();
foreach (var mapKvP in _locationConfig.OpenZones)
{
if (!dbLocations.ContainsKey(mapKvP.Key))
{
_logger.Error(
_serverLocalisationService.GetText("openzone-unable_to_find_map", mapKvP)
logger.Error(
serverLocalisationService.GetText("openzone-unable_to_find_map", mapKvP)
);
continue;
@@ -18,19 +18,18 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class PaymentService(
ISptLogger<PaymentService> _logger,
HttpResponseUtil _httpResponseUtil,
HandbookHelper _handbookHelper,
TraderHelper _traderHelper,
ItemHelper _itemHelper,
InventoryHelper _inventoryHelper,
ServerLocalisationService _serverLocalisationService,
PaymentHelper _paymentHelper,
ConfigServer _configServer
ISptLogger<PaymentService> logger,
HttpResponseUtil httpResponseUtil,
HandbookHelper handbookHelper,
TraderHelper traderHelper,
ItemHelper itemHelper,
InventoryHelper inventoryHelper,
ServerLocalisationService serverLocalisationService,
PaymentHelper paymentHelper,
ConfigServer configServer
)
{
protected readonly InventoryConfig _inventoryConfig =
_configServer.GetConfig<InventoryConfig>();
protected readonly InventoryConfig _inventoryConfig = configServer.GetConfig<InventoryConfig>();
/// <summary>
/// Take money and insert items into return to server request
@@ -42,13 +41,13 @@ public class PaymentService(
public void PayMoney(
PmcData pmcData,
ProcessBuyTradeRequestData request,
string sessionID,
MongoId sessionID,
ItemEventRouterResponse output
)
{
// May need to convert to trader currency
var trader = _traderHelper.GetTrader(request.TransactionId, sessionID);
var payToTrader = _traderHelper.TraderExists(request.TransactionId);
var trader = traderHelper.GetTrader(request.TransactionId, sessionID);
var payToTrader = traderHelper.TraderExists(request.TransactionId);
// Track the amounts of each type of currency involved in the trade.
var currencyAmounts = new Dictionary<string, double?>();
@@ -60,10 +59,10 @@ public class PaymentService(
var item = pmcData.Inventory.Items.FirstOrDefault(i => i.Id == itemRequest.Id);
if (item is not null)
{
if (!_paymentHelper.IsMoneyTpl(item.Template))
if (!paymentHelper.IsMoneyTpl(item.Template))
{
// If the item is not money, remove it from the inventory.
_inventoryHelper.RemoveItemByCount(
inventoryHelper.RemoveItemByCount(
pmcData,
item.Id,
(int)itemRequest.Count,
@@ -122,8 +121,8 @@ public class PaymentService(
if (payToTrader)
{
// Convert the amount to the trader's currency and update the sales sum.
var costOfPurchaseInCurrency = _handbookHelper.FromRUB(
_handbookHelper.InRUB(currencyAmount ?? 0, currencyTpl),
var costOfPurchaseInCurrency = handbookHelper.FromRUB(
handbookHelper.InRUB(currencyAmount ?? 0, currencyTpl),
trader.Currency.Value.GetCurrencyTpl()
);
@@ -135,10 +134,10 @@ public class PaymentService(
// If no currency-based payment is involved, handle it separately
if (totalCurrencyAmount == 0 && payToTrader)
{
_logger.Debug(_serverLocalisationService.GetText("payment-zero_price_no_payment"));
logger.Debug(serverLocalisationService.GetText("payment-zero_price_no_payment"));
// Convert the handbook price to the trader's currency and update the sales sum.
var costOfPurchaseInCurrency = _handbookHelper.FromRUB(
var costOfPurchaseInCurrency = handbookHelper.FromRUB(
GetTraderItemHandbookPriceRouble(request.ItemId, request.TransactionId) ?? 0,
trader.Currency.Value.GetCurrencyTpl()
);
@@ -148,12 +147,12 @@ public class PaymentService(
if (payToTrader)
{
_traderHelper.LevelUp(request.TransactionId, pmcData);
traderHelper.LevelUp(request.TransactionId, pmcData);
}
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug("Item(s) taken. Status OK.");
logger.Debug("Item(s) taken. Status OK.");
}
}
@@ -163,9 +162,9 @@ public class PaymentService(
/// <param name="traderAssortId"> ID of the assort to look up</param>
/// <param name="traderId"> ID of trader with assort </param>
/// <returns> Handbook rouble price of the item </returns>
private double? GetTraderItemHandbookPriceRouble(string? traderAssortId, string traderId)
private double? GetTraderItemHandbookPriceRouble(MongoId traderAssortId, MongoId traderId)
{
var purchasedAssortItem = _traderHelper.GetTraderAssortItemByAssortId(
var purchasedAssortItem = traderHelper.GetTraderAssortItemByAssortId(
traderId,
traderAssortId
);
@@ -174,10 +173,10 @@ public class PaymentService(
return 1;
}
var assortItemPriceRouble = _handbookHelper.GetTemplatePrice(purchasedAssortItem.Template);
var assortItemPriceRouble = handbookHelper.GetTemplatePrice(purchasedAssortItem.Template);
if (assortItemPriceRouble == 0)
{
_logger.Debug(
logger.Debug(
$"No item price found for {purchasedAssortItem.Template} on trader: {traderId} in assort: {traderAssortId}"
);
@@ -200,13 +199,13 @@ public class PaymentService(
double? amountToSend,
ProcessSellTradeRequestData request,
ItemEventRouterResponse output,
string sessionID
MongoId sessionID
)
{
var trader = _traderHelper.GetTrader(request.TransactionId, sessionID);
var trader = traderHelper.GetTrader(request.TransactionId, sessionID);
if (trader is null)
{
_logger.Error(
logger.Error(
$"Unable to add currency to profile as trader: {request.TransactionId} does not exist"
);
@@ -214,14 +213,14 @@ public class PaymentService(
}
var currencyTpl = trader.Currency.Value.GetCurrencyTpl();
var calcAmount = _handbookHelper.FromRUB(
_handbookHelper.InRUB(amountToSend ?? 0, currencyTpl),
var calcAmount = handbookHelper.FromRUB(
handbookHelper.InRUB(amountToSend ?? 0, currencyTpl),
currencyTpl
);
var currencyMaxStackSize = _itemHelper.GetItem(currencyTpl).Value.Properties?.StackMaxSize;
var currencyMaxStackSize = itemHelper.GetItem(currencyTpl).Value.Properties?.StackMaxSize;
if (currencyMaxStackSize is null)
{
_logger.Error(
logger.Error(
$"Unable to add currency: {currencyTpl} to profile as it lacks a _props property"
);
@@ -278,7 +277,7 @@ public class PaymentService(
};
// Ensure money is properly split to follow its max stack size limit
var rewards = _itemHelper.SplitStackIntoSeparateItems(rootCurrencyReward);
var rewards = itemHelper.SplitStackIntoSeparateItems(rootCurrencyReward);
if (!skipSendingMoneyToStash)
{
@@ -289,14 +288,14 @@ public class PaymentService(
Callback = null,
UseSortingTable = true,
};
_inventoryHelper.AddItemsToStash(sessionID, addItemToStashRequest, pmcData, output);
inventoryHelper.AddItemsToStash(sessionID, addItemToStashRequest, pmcData, output);
}
// Calcualte new total sale sum with trader item sold to
var saleSum = pmcData.TradersInfo[request.TransactionId].SalesSum + amountToSend;
pmcData.TradersInfo[request.TransactionId].SalesSum = saleSum;
_traderHelper.LevelUp(request.TransactionId, pmcData);
traderHelper.LevelUp(request.TransactionId, pmcData);
}
/// <summary>
@@ -309,16 +308,16 @@ public class PaymentService(
/// <param name="output"> Client response </param>
public void AddPaymentToOutput(
PmcData pmcData,
string currencyTpl,
MongoId currencyTpl,
double amountToPay,
string sessionID,
MongoId sessionID,
ItemEventRouterResponse output
)
{
var moneyItemsInInventory = GetSortedMoneyItemsInInventory(
pmcData,
currencyTpl,
pmcData.Inventory.Stash
pmcData.Inventory.Stash.Value
);
//Ensure all money items found have a upd
@@ -335,15 +334,15 @@ public class PaymentService(
// If no money in inventory or amount is not enough we return false
if (moneyItemsInInventory.Count <= 0 || amountAvailable < amountToPay)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"payment-not_enough_money_to_complete_transation", // Typo, needs locale updated if fixed
new { amountToPay, amountAvailable }
)
);
_httpResponseUtil.AppendErrorToOutput(
httpResponseUtil.AppendErrorToOutput(
output,
_serverLocalisationService.GetText(
serverLocalisationService.GetText(
"payment-not_enough_money_to_complete_transation_short",
amountToPay
), // Typo, needs locale updated if fixed
@@ -360,7 +359,7 @@ public class PaymentService(
if (leftToPay >= itemAmount)
{
leftToPay -= itemAmount ?? 0;
_inventoryHelper.RemoveItem(pmcData, profileMoneyItem.Id, sessionID, output);
inventoryHelper.RemoveItem(pmcData, profileMoneyItem.Id, sessionID, output);
}
else
{
@@ -388,19 +387,19 @@ public class PaymentService(
// TODO - ensure money in containers inside secure container are LAST
protected List<Item> GetSortedMoneyItemsInInventory(
PmcData pmcData,
string currencyTpl,
string playerStashId
MongoId currencyTpl,
MongoId playerStashId
)
{
// Get money stacks player has
var moneyItemsInInventory = _itemHelper.FindBarterItems(
var moneyItemsInInventory = itemHelper.FindBarterItems(
"tpl",
pmcData.Inventory.Items,
currencyTpl
);
if (moneyItemsInInventory.Count == 0)
{
_logger.Debug($"No {currencyTpl} money items found in inventory");
logger.Debug($"No {currencyTpl} money items found in inventory");
return moneyItemsInInventory;
}
@@ -432,12 +431,12 @@ public class PaymentService(
/// <param name="items">Inventory items to check</param>
/// <param name="playerStashId">Id of players stash</param>
/// <returns>Dictionary</returns>
protected IReadOnlyDictionary<string, InventoryLocation> GetItemInStashCache(
protected IReadOnlyDictionary<MongoId, InventoryLocation> GetItemInStashCache(
List<Item> items,
string playerStashId
MongoId playerStashId
)
{
var itemsInStashCache = new Dictionary<string, InventoryLocation>();
var itemsInStashCache = new Dictionary<MongoId, InventoryLocation>();
foreach (var inventoryItem in items)
{
itemsInStashCache.TryAdd(
@@ -464,7 +463,7 @@ public class PaymentService(
Item a,
Item b,
List<Item> inventoryItems,
IReadOnlyDictionary<string, InventoryLocation> itemInStashCache
IReadOnlyDictionary<MongoId, InventoryLocation> itemInStashCache
)
{
// Get the location of A and B
@@ -592,7 +591,7 @@ public class PaymentService(
protected InventoryLocation GetItemLocation(
MongoId itemId,
List<Item> inventoryItems,
string playerStashId
MongoId playerStashId
)
{
var inventoryItem = inventoryItems.FirstOrDefault(item => item.Id == itemId);
@@ -1,6 +1,7 @@
using System.Text.RegularExpressions;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Profile;
@@ -14,20 +15,20 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class PmcChatResponseService(
ISptLogger<OpenZoneService> _logger,
RandomUtil _randomUtil,
NotificationSendHelper _notificationSendHelper,
WeightedRandomHelper _weightedRandomHelper,
ServerLocalisationService _serverLocalisationService,
GiftService _giftService,
LocaleService _localeService,
MatchBotDetailsCacheService _matchBotDetailsCacheService,
ConfigServer _configServer
ISptLogger<OpenZoneService> logger,
RandomUtil randomUtil,
NotificationSendHelper notificationSendHelper,
WeightedRandomHelper weightedRandomHelper,
ServerLocalisationService serverLocalisationService,
GiftService giftService,
LocaleService localeService,
MatchBotDetailsCacheService matchBotDetailsCacheService,
ConfigServer configServer
)
{
protected GiftsConfig _giftConfig = _configServer.GetConfig<GiftsConfig>();
protected GiftsConfig _giftConfig = configServer.GetConfig<GiftsConfig>();
protected readonly PmcChatResponse _pmcResponsesConfig =
_configServer.GetConfig<PmcChatResponse>();
configServer.GetConfig<PmcChatResponse>();
/// <summary>
/// For each PMC victim of the player, have a chance to send a message to the player, can be positive or negative
@@ -35,18 +36,18 @@ public class PmcChatResponseService(
/// <param name="sessionId"> Session ID </param>
/// <param name="pmcVictims"> List of bots killed by player </param>
/// <param name="pmcData"> Player profile </param>
public void SendVictimResponse(string sessionId, List<Victim> pmcVictims, PmcData pmcData)
public void SendVictimResponse(MongoId sessionId, List<Victim> pmcVictims, PmcData pmcData)
{
foreach (var victim in pmcVictims)
{
if (!_randomUtil.GetChance100(_pmcResponsesConfig.Victim.ResponseChancePercent))
if (!randomUtil.GetChance100(_pmcResponsesConfig.Victim.ResponseChancePercent))
{
continue;
}
if (string.IsNullOrEmpty(victim.Name))
{
_logger.Warning(
logger.Warning(
$"Victim: {victim.ProfileId} does not have a nickname, skipping pmc response message send"
);
@@ -57,7 +58,7 @@ public class PmcChatResponseService(
var message = ChooseMessage(true, pmcData, victim);
if (message is not null)
{
_notificationSendHelper.SendMessageToPlayer(
notificationSendHelper.SendMessageToPlayer(
sessionId,
victimDetails,
message,
@@ -73,20 +74,20 @@ public class PmcChatResponseService(
/// <param name="sessionId"> Session id </param>
/// <param name="pmcData"> Players profile </param>
/// <param name="killer"> The bot who killed the player </param>
public void SendKillerResponse(string sessionId, PmcData pmcData, Aggressor killer)
public void SendKillerResponse(MongoId sessionId, PmcData pmcData, Aggressor killer)
{
if (killer is null)
{
return;
}
if (!_randomUtil.GetChance100(_pmcResponsesConfig.Killer.ResponseChancePercent))
if (!randomUtil.GetChance100(_pmcResponsesConfig.Killer.ResponseChancePercent))
{
return;
}
// find bot by id in cache
var killerDetailsInCache = _matchBotDetailsCacheService.GetBotById(killer.ProfileId);
var killerDetailsInCache = matchBotDetailsCacheService.GetBotById(killer.ProfileId);
if (killerDetailsInCache is null)
{
return;
@@ -115,7 +116,7 @@ public class PmcChatResponseService(
return;
}
_notificationSendHelper.SendMessageToPlayer(
notificationSendHelper.SendMessageToPlayer(
sessionId,
killerDetails,
message,
@@ -139,16 +140,16 @@ public class PmcChatResponseService(
var possibleResponseLocaleKeys = GetResponseLocaleKeys(responseType, isVictim);
if (possibleResponseLocaleKeys.Count == 0)
{
_logger.Warning(
_serverLocalisationService.GetText("pmcresponse-unable_to_find_key", responseType)
logger.Warning(
serverLocalisationService.GetText("pmcresponse-unable_to_find_key", responseType)
);
return null;
}
// Choose random response from above list and request it from localisation service
var responseText = _serverLocalisationService.GetText(
_randomUtil.GetArrayValue(possibleResponseLocaleKeys),
var responseText = serverLocalisationService.GetText(
randomUtil.GetArrayValue(possibleResponseLocaleKeys),
new
{
playerName = pmcData.Info.Nickname,
@@ -163,16 +164,16 @@ public class PmcChatResponseService(
// Give the player a gift code if they were killed and response is 'pity'.
if (responseType == "pity")
{
var giftKeys = _giftService.GetGiftIds();
var randomGiftKey = _randomUtil.GetArrayValue(giftKeys);
var giftKeys = giftService.GetGiftIds();
var randomGiftKey = randomUtil.GetArrayValue(giftKeys);
Regex.Replace(responseText, "/(%giftcode%)/gi", randomGiftKey); // TODO: does regex still work
}
if (AppendSuffixToMessageEnd(isVictim))
{
var suffixText = _serverLocalisationService.GetText(
_randomUtil.GetArrayValue(GetResponseSuffixLocaleKeys())
var suffixText = serverLocalisationService.GetText(
randomUtil.GetArrayValue(GetResponseSuffixLocaleKeys())
);
responseText += $" {suffixText}";
}
@@ -198,7 +199,7 @@ public class PmcChatResponseService(
/// <returns> Localised location name </returns>
protected string GetLocationName(string locationKey)
{
return _localeService.GetLocaleDb()[locationKey] ?? locationKey;
return localeService.GetLocaleDb()[locationKey] ?? locationKey;
}
/// <summary>
@@ -212,7 +213,7 @@ public class PmcChatResponseService(
? _pmcResponsesConfig.Victim.StripCapitalisationChancePercent
: _pmcResponsesConfig.Killer.StripCapitalisationChancePercent;
return _randomUtil.GetChance100(chance);
return randomUtil.GetChance100(chance);
}
/// <summary>
@@ -226,7 +227,7 @@ public class PmcChatResponseService(
? _pmcResponsesConfig.Victim.AllCapsChancePercent
: _pmcResponsesConfig.Killer.AllCapsChancePercent;
return _randomUtil.GetChance100(chance);
return randomUtil.GetChance100(chance);
}
/// <summary>
@@ -240,7 +241,7 @@ public class PmcChatResponseService(
? _pmcResponsesConfig.Victim.AppendBroToMessageEndChancePercent
: _pmcResponsesConfig.Killer.AppendBroToMessageEndChancePercent;
return _randomUtil.GetChance100(chance);
return randomUtil.GetChance100(chance);
}
/// <summary>
@@ -254,7 +255,7 @@ public class PmcChatResponseService(
? _pmcResponsesConfig.Victim.ResponseTypeWeights
: _pmcResponsesConfig.Killer.ResponseTypeWeights;
return _weightedRandomHelper.GetWeightedValue<string>(responseWeights);
return weightedRandomHelper.GetWeightedValue<string>(responseWeights);
}
/// <summary>
@@ -266,7 +267,7 @@ public class PmcChatResponseService(
protected List<string> GetResponseLocaleKeys(string keyType, bool isVictim = true)
{
var keyBase = isVictim ? "pmcresponse-victim_" : "pmcresponse-killer_";
var keys = _serverLocalisationService.GetLocaleKeys();
var keys = serverLocalisationService.GetLocaleKeys();
return keys.Where(x => x.StartsWith($"{keyBase}{keyType}")).ToList();
}
@@ -277,7 +278,7 @@ public class PmcChatResponseService(
/// <returns> List of keys </returns>
protected List<string> GetResponseSuffixLocaleKeys()
{
var keys = _serverLocalisationService.GetLocaleKeys();
var keys = serverLocalisationService.GetLocaleKeys();
return keys.Where(x => x.StartsWith("pmcresponse-suffix")).ToList();
}
@@ -290,7 +291,7 @@ public class PmcChatResponseService(
// TODO: is this used?
protected UserDialogInfo ChooseRandomVictim(List<Victim> pmcVictims)
{
var randomVictim = _randomUtil.GetArrayValue(pmcVictims);
var randomVictim = randomUtil.GetArrayValue(pmcVictims);
return GetVictimDetails(randomVictim);
}
@@ -315,7 +316,7 @@ public class PmcChatResponseService(
MemberCategory.Developer,
};
var chosenCategory = _randomUtil.GetArrayValue(categories);
var chosenCategory = randomUtil.GetArrayValue(categories);
return new UserDialogInfo
{
@@ -11,39 +11,39 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class PostDbLoadService(
ISptLogger<PostDbLoadService> _logger,
DatabaseService _databaseService,
ServerLocalisationService _serverLocalisationService,
SeasonalEventService _seasonalEventService,
CustomLocationWaveService _customLocationWaveService,
OpenZoneService _openZoneService,
ItemBaseClassService _itemBaseClassService,
RaidWeatherService _raidWeatherService,
ConfigServer _configServer,
ICloner _cloner
ISptLogger<PostDbLoadService> logger,
DatabaseService databaseService,
ServerLocalisationService serverLocalisationService,
SeasonalEventService seasonalEventService,
CustomLocationWaveService customLocationWaveService,
OpenZoneService openZoneService,
ItemBaseClassService itemBaseClassService,
RaidWeatherService raidWeatherService,
ConfigServer configServer,
ICloner cloner
)
{
protected readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
protected readonly CoreConfig _coreConfig = _configServer.GetConfig<CoreConfig>();
protected readonly HideoutConfig _hideoutConfig = _configServer.GetConfig<HideoutConfig>();
protected readonly ItemConfig _itemConfig = _configServer.GetConfig<ItemConfig>();
protected readonly LocationConfig _locationConfig = _configServer.GetConfig<LocationConfig>();
protected readonly LootConfig _lootConfig = _configServer.GetConfig<LootConfig>();
protected readonly PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
protected readonly RagfairConfig _ragfairConfig = _configServer.GetConfig<RagfairConfig>();
protected readonly BotConfig _botConfig = configServer.GetConfig<BotConfig>();
protected readonly CoreConfig _coreConfig = configServer.GetConfig<CoreConfig>();
protected readonly HideoutConfig _hideoutConfig = configServer.GetConfig<HideoutConfig>();
protected readonly ItemConfig _itemConfig = configServer.GetConfig<ItemConfig>();
protected readonly LocationConfig _locationConfig = configServer.GetConfig<LocationConfig>();
protected readonly LootConfig _lootConfig = configServer.GetConfig<LootConfig>();
protected readonly PmcConfig _pmcConfig = configServer.GetConfig<PmcConfig>();
protected readonly RagfairConfig _ragfairConfig = configServer.GetConfig<RagfairConfig>();
public void PerformPostDbLoadActions()
{
// Regenerate base cache now mods are loaded and game is starting
// Mods that add items and use the baseClass service generate the cache including their items, the next mod that
// add items gets left out,causing warnings
_itemBaseClassService.HydrateItemBaseClassCache();
itemBaseClassService.HydrateItemBaseClassCache();
// Validate that only mongoIds exist in items, quests, and traders
// Kill the startup if not.
// TODO: We can probably remove this in a couple versions
_databaseService.ValidateDatabase();
if (!_databaseService.IsDatabaseValid())
databaseService.ValidateDatabase();
if (!databaseService.IsDatabaseValid())
{
throw new Exception("Server start failure, database invalid");
}
@@ -61,7 +61,7 @@ public class PostDbLoadService(
if (_locationConfig.AddOpenZonesToAllMaps)
{
_openZoneService.ApplyZoneChangesToAllMaps();
openZoneService.ApplyZoneChangesToAllMaps();
}
if (_pmcConfig.RemoveExistingPmcWaves.GetValueOrDefault(false))
@@ -71,7 +71,7 @@ public class PostDbLoadService(
if (_locationConfig.AddCustomBotWavesToMaps)
{
_customLocationWaveService.ApplyWaveChangesToAllMaps();
customLocationWaveService.ApplyWaveChangesToAllMaps();
}
if (_locationConfig.EnableBotTypeLimits)
@@ -105,10 +105,10 @@ public class PostDbLoadService(
ValidateQuestAssortUnlocksExist();
if (_seasonalEventService.IsAutomaticEventDetectionEnabled())
if (seasonalEventService.IsAutomaticEventDetectionEnabled())
{
_seasonalEventService.CacheActiveEvents();
_seasonalEventService.EnableSeasonalEvents();
seasonalEventService.CacheActiveEvents();
seasonalEventService.EnableSeasonalEvents();
}
// Flea bsg blacklist is off
@@ -123,8 +123,8 @@ public class PostDbLoadService(
AddCustomItemPresetsToGlobals();
var currentSeason = _seasonalEventService.GetActiveWeatherSeason();
_raidWeatherService.GenerateWeather(currentSeason);
var currentSeason = seasonalEventService.GetActiveWeatherSeason();
raidWeatherService.GenerateWeather(currentSeason);
if (_botConfig.WeeklyBoss.Enabled)
{
@@ -165,7 +165,7 @@ public class PostDbLoadService(
protected void FlagMapAsGuaranteedBoss(WildSpawnType boss)
{
// Get the corresponding map for the provided boss
var locations = _databaseService.GetLocations();
var locations = databaseService.GetLocations();
Location? location;
switch (boss)
{
@@ -191,7 +191,7 @@ public class PostDbLoadService(
location = locations.Lighthouse;
break;
default:
_logger.Warning($"Unknown boss type: {boss}. Unable to set as weekly. Skipping");
logger.Warning($"Unknown boss type: {boss}. Unable to set as weekly. Skipping");
return;
}
@@ -200,11 +200,11 @@ public class PostDbLoadService(
);
if (bossSpawn is null)
{
_logger.Warning($"Boss: {boss} not found on map, unable to set as weekly. Skipping");
logger.Warning($"Boss: {boss} not found on map, unable to set as weekly. Skipping");
return;
}
_logger.Debug($"{boss} is boss of the week");
logger.Debug($"{boss} is boss of the week");
bossSpawn.BossChance = 100;
bossSpawn.ShowOnTarkovMap = true;
bossSpawn.ShowOnTarkovMapPvE = true;
@@ -212,13 +212,13 @@ public class PostDbLoadService(
private void MergeCustomHideoutAreas()
{
var hideout = _databaseService.GetHideout();
var hideout = databaseService.GetHideout();
foreach (var customArea in hideout.CustomAreas)
{
// Check if exists
if (hideout.Areas!.Exists(area => area.Id == customArea.Id))
{
_logger.Warning(
logger.Warning(
$"Unable to add new hideout area with Id: {customArea.Id} as ID is already in use, skipping"
);
@@ -234,12 +234,12 @@ public class PostDbLoadService(
/// </summary>
protected void MergeCustomAchievements()
{
var achievements = _databaseService.GetAchievements();
foreach (var customAchievement in _databaseService.GetCustomAchievements())
var achievements = databaseService.GetAchievements();
foreach (var customAchievement in databaseService.GetCustomAchievements())
{
if (achievements.Exists(a => a.Id == customAchievement.Id))
{
_logger.Debug(
logger.Debug(
$"Unable to add custom achievement as id: {customAchievement.Id} already exists"
);
continue;
@@ -251,7 +251,7 @@ public class PostDbLoadService(
private void RemoveNewBeginningRequirementFromPrestige()
{
var prestigeDb = _databaseService.GetTemplates().Prestige;
var prestigeDb = databaseService.GetTemplates().Prestige;
var newBeginningQuestId = new HashSet<string>
{
"6761f28a022f60bb320f3e95",
@@ -277,7 +277,7 @@ public class PostDbLoadService(
private void RemovePraporTestMessage()
{
foreach ((var locale, var lazyLoad) in _databaseService.GetLocales().Global)
foreach ((var locale, var lazyLoad) in databaseService.GetLocales().Global)
{
lazyLoad.AddTransformer(lazyloadedData =>
{
@@ -290,16 +290,16 @@ public class PostDbLoadService(
protected void CloneExistingCraftsAndAddNew()
{
var hideoutCraftDb = _databaseService.GetHideout().Production;
var hideoutCraftDb = databaseService.GetHideout().Production;
var craftsToAdd = _hideoutConfig.HideoutCraftsToAdd;
foreach (var craftToAdd in craftsToAdd)
{
var clonedCraft = _cloner.Clone(
var clonedCraft = cloner.Clone(
hideoutCraftDb.Recipes.FirstOrDefault(x => x.Id == craftToAdd.CraftIdToCopy)
);
if (clonedCraft is null)
{
_logger.Warning(
logger.Warning(
$"Unable to find hideout craft: {craftToAdd.CraftIdToCopy}, skipping"
);
@@ -317,7 +317,7 @@ public class PostDbLoadService(
protected void AdjustMinReserveRaiderSpawnChance()
{
// Get reserve base.json
var reserveBase = _databaseService.GetLocation(ELocationName.RezervBase.ToString()).Base;
var reserveBase = databaseService.GetLocation(ELocationName.RezervBase.ToString()).Base;
// Raiders are bosses, get only those from boss spawn array
foreach (
@@ -351,8 +351,8 @@ public class PostDbLoadService(
{
if (mapId is null)
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"location-unable_to_add_custom_loot_position",
mapId
)
@@ -361,14 +361,14 @@ public class PostDbLoadService(
continue;
}
_databaseService
databaseService
.GetLocation(mapId)
.LooseLoot.AddTransformer(looselootData =>
{
if (looselootData is null)
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"location-map_has_no_loose_loot_data",
mapId
)
@@ -408,7 +408,7 @@ public class PostDbLoadService(
// BSG have two values for shotgun dispersion, we make sure both have the same value
protected void FixShotgunDispersions()
{
var itemDb = _databaseService.GetItems();
var itemDb = databaseService.GetItems();
var shotguns = new List<string>
{
@@ -430,7 +430,7 @@ public class PostDbLoadService(
protected void RemoveExistingPmcWaves()
{
var locations = _databaseService.GetLocations().GetDictionary();
var locations = databaseService.GetLocations().GetDictionary();
var pmcTypes = new HashSet<string> { "pmcUSEC", "pmcBEAR" };
foreach (var locationkvP in locations)
@@ -453,7 +453,7 @@ public class PostDbLoadService(
/// </summary>
protected void AdjustMapBotLimits()
{
var mapsDb = _databaseService.GetLocations().GetDictionary();
var mapsDb = databaseService.GetLocations().GetDictionary();
if (_locationConfig.BotTypeLimits is null)
{
return;
@@ -463,8 +463,8 @@ public class PostDbLoadService(
{
if (!mapsDb.TryGetValue(mapId, out var map))
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"bot-unable_to_edit_limits_of_unknown_map",
mapId
)
@@ -509,14 +509,14 @@ public class PostDbLoadService(
foreach (var (mapId, mapAdjustments) in _lootConfig.LooseLootSpawnPointAdjustments)
{
_databaseService
databaseService
.GetLocation(mapId)
.LooseLoot.AddTransformer(looselootData =>
{
if (looselootData is null)
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"location-map_has_no_loose_loot_data",
mapId
)
@@ -532,8 +532,8 @@ public class PostDbLoadService(
);
if (lootPostionToAdjust is null)
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"location-unable_to_adjust_loot_position_on_map",
new { lootKey, mapId }
)
@@ -552,7 +552,7 @@ public class PostDbLoadService(
protected void AdjustLocationBotValues()
{
var mapsDb = _databaseService.GetLocations();
var mapsDb = databaseService.GetLocations();
var mapsDict = mapsDb.GetDictionary();
foreach (var (key, cap) in _botConfig.MaxBotCap)
{
@@ -578,7 +578,7 @@ public class PostDbLoadService(
var rogueSpawnDelaySeconds = _locationConfig
.RogueLighthouseSpawnTimeSettings
.WaitTimeSeconds;
var lighthouse = _databaseService.GetLocations().Lighthouse?.Base;
var lighthouse = databaseService.GetLocations().Lighthouse?.Base;
if (lighthouse is null)
// Just in case they remove this cursed map
{
@@ -600,7 +600,7 @@ public class PostDbLoadService(
/// </summary>
protected void AdjustLabsRaiderSpawnRate()
{
var labsBase = _databaseService.GetLocations().Laboratory.Base;
var labsBase = databaseService.GetLocations().Laboratory.Base;
// Find spawns with empty string for triggerId/TriggerName
var nonTriggerLabsBossSpawns = labsBase.BossLocationSpawn.Where(bossSpawn =>
@@ -621,7 +621,7 @@ public class PostDbLoadService(
return;
}
foreach (var craft in _databaseService.GetHideout().Production.Recipes)
foreach (var craft in databaseService.GetHideout().Production.Recipes)
// Only adjust crafts ABOVE the override
{
craft.ProductionTime = Math.Min(craft.ProductionTime.Value, overrideSeconds);
@@ -639,7 +639,7 @@ public class PostDbLoadService(
return;
}
foreach (var area in _databaseService.GetHideout().Areas)
foreach (var area in databaseService.GetHideout().Areas)
foreach (var (_, stage) in area.Stages)
// Only adjust crafts ABOVE the override
{
@@ -658,7 +658,7 @@ public class PostDbLoadService(
foreach (var craftId in hideoutLootBoxCraftIds)
{
var recipe = _databaseService
var recipe = databaseService
.GetHideout()
.Production.Recipes.FirstOrDefault(craft => craft.Id == craftId);
if (recipe is not null)
@@ -673,7 +673,7 @@ public class PostDbLoadService(
/// </summary>
protected void ValidateQuestAssortUnlocksExist()
{
var db = _databaseService.GetTables();
var db = databaseService.GetTables();
var traders = db.Traders;
var quests = db.Templates.Quests;
foreach (var (traderId, traderData) in traders)
@@ -704,8 +704,8 @@ public class PostDbLoadService(
traderName = traderId,
questName = quests[questKey]?.QuestName ?? "UNKNOWN",
};
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"assort-missing_quest_assort_unlock",
messageValues
)
@@ -717,7 +717,7 @@ public class PostDbLoadService(
protected void SetAllDbItemsAsSellableOnFlea()
{
var dbItems = _databaseService.GetItems().Values.ToList();
var dbItems = databaseService.GetItems().Values.ToList();
foreach (
var item in dbItems.Where(item =>
string.Equals(item.Type, "Item", StringComparison.OrdinalIgnoreCase)
@@ -732,7 +732,7 @@ public class PostDbLoadService(
protected void AddMissingTraderBuyRestrictionMaxValue()
{
var restrictions = _databaseService
var restrictions = databaseService
.GetGlobals()
.Configuration.TradingSettings.BuyRestrictionMaxBonus;
restrictions["unheard_edition"] = new BuyRestrictionMaxBonus
@@ -743,7 +743,7 @@ public class PostDbLoadService(
protected void ApplyFleaPriceOverrides()
{
var fleaPrices = _databaseService.GetPrices();
var fleaPrices = databaseService.GetPrices();
foreach (var (itemTpl, price) in _ragfairConfig.Dynamic.ItemPriceOverrideRouble)
{
fleaPrices[itemTpl] = price;
@@ -754,15 +754,15 @@ public class PostDbLoadService(
{
foreach (var presetToAdd in _itemConfig.CustomItemGlobalPresets)
{
if (_databaseService.GetGlobals().ItemPresets.ContainsKey(presetToAdd.Id))
if (databaseService.GetGlobals().ItemPresets.ContainsKey(presetToAdd.Id))
{
_logger.Warning(
logger.Warning(
$"Global ItemPreset with Id of: {presetToAdd.Id} already exists, unable to overwrite"
);
continue;
}
_databaseService.GetGlobals().ItemPresets.TryAdd(presetToAdd.Id, presetToAdd);
databaseService.GetGlobals().ItemPresets.TryAdd(presetToAdd.Id, presetToAdd);
}
}
}
@@ -1,5 +1,6 @@
using System.Collections.Concurrent;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Spt.Services;
using SPTarkov.Server.Core.Utils;
@@ -8,9 +9,9 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class ProfileActivityService(TimeUtil timeUtil)
{
private readonly ConcurrentDictionary<string, ProfileActivityData> _activeProfiles = [];
private readonly ConcurrentDictionary<MongoId, ProfileActivityData> _activeProfiles = [];
public void AddActiveProfile(string sessionId, long clientStartedTimestamp)
public void AddActiveProfile(MongoId sessionId, long clientStartedTimestamp)
{
_activeProfiles.AddOrUpdate(
sessionId,
@@ -31,7 +32,7 @@ public class ProfileActivityService(TimeUtil timeUtil)
);
}
public bool ContainsActiveProfile(string sessionId)
public bool ContainsActiveProfile(MongoId sessionId)
{
if (_activeProfiles.ContainsKey(sessionId))
{
@@ -52,7 +53,7 @@ public class ProfileActivityService(TimeUtil timeUtil)
return null;
}
public ProfileActivityRaidData GetProfileActivityRaidData(string sessionId)
public ProfileActivityRaidData GetProfileActivityRaidData(MongoId sessionId)
{
// Handle edge cases where people might close the server but keep the client alive
if (!ContainsActiveProfile(sessionId))
@@ -76,7 +77,7 @@ public class ProfileActivityService(TimeUtil timeUtil)
/// <param name="sessionId"> Profile to check </param>
/// <param name="minutes"> Minutes to check for activity in </param>
/// <returns> True when profile was active within past x minutes </returns>
public bool ActiveWithinLastMinutes(string sessionId, int minutes)
public bool ActiveWithinLastMinutes(MongoId sessionId, int minutes)
{
if (!_activeProfiles.TryGetValue(sessionId, out var profileActivity))
{
@@ -113,7 +114,7 @@ public class ProfileActivityService(TimeUtil timeUtil)
/// Update the timestamp a profile was last observed active
/// </summary>
/// <param name="sessionId"> Profile to update </param>
public void SetActivityTimestamp(string sessionId)
public void SetActivityTimestamp(MongoId sessionId)
{
if (_activeProfiles.TryGetValue(sessionId, out var currentActiveProfile))
{
@@ -18,19 +18,19 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class ProfileFixerService(
ISptLogger<ProfileFixerService> _logger,
JsonUtil _jsonUtil,
RewardHelper _rewardHelper,
TraderHelper _traderHelper,
HideoutHelper _hideoutHelper,
DatabaseService _databaseService,
ServerLocalisationService _serverLocalisationService,
ConfigServer _configServer,
InventoryHelper _inventoryHelper
ISptLogger<ProfileFixerService> logger,
JsonUtil jsonUtil,
RewardHelper rewardHelper,
TraderHelper traderHelper,
HideoutHelper hideoutHelper,
DatabaseService databaseService,
ServerLocalisationService serverLocalisationService,
ConfigServer configServer,
InventoryHelper inventoryHelper
)
{
protected readonly List<string> _areas = ["hideout", "main"];
protected readonly CoreConfig _coreConfig = _configServer.GetConfig<CoreConfig>();
protected readonly CoreConfig _coreConfig = configServer.GetConfig<CoreConfig>();
/// <summary>
/// Find issues in the pmc profile data that may cause issues and fix them
@@ -118,17 +118,17 @@ public class ProfileFixerService(
continue;
}
_logger.Warning(
logger.Warning(
$"{mappingKvP.Value.Count - 1} duplicate(s) found for item: {mappingKvP.Key}"
);
var itemAJson = _jsonUtil.Serialize(mappingKvP.Value[0]);
var itemBJson = _jsonUtil.Serialize(mappingKvP.Value[1]);
var itemAJson = jsonUtil.Serialize(mappingKvP.Value[0]);
var itemBJson = jsonUtil.Serialize(mappingKvP.Value[1]);
if (itemAJson == itemBJson)
{
// Both items match, we can safely delete one (A)
var indexOfItemToRemove = pmcProfile.Inventory.Items.IndexOf(mappingKvP.Value[0]);
pmcProfile.Inventory.Items.RemoveAt(indexOfItemToRemove);
_logger.Warning($"Deleted duplicate item: {mappingKvP.Key}");
logger.Warning($"Deleted duplicate item: {mappingKvP.Key}");
}
else
{
@@ -143,7 +143,7 @@ public class ProfileFixerService(
x.Id == mappingKvP.Key
);
itemToAdjust.Id = new MongoId();
_logger.Warning(
logger.Warning(
$"Replace duplicate item Id: {mappingKvP.Key} with {itemToAdjust.Id}"
);
}
@@ -163,14 +163,14 @@ public class ProfileFixerService(
var regxp = new Regex("[^a-zA-Z0-9 -]");
if (item.Upd.Tag?.Name is not null && !regxp.IsMatch(item.Upd.Tag.Name))
{
_logger.Warning($"Fixed item: {item.Id}s Tag value, removed invalid characters");
logger.Warning($"Fixed item: {item.Id}s Tag value, removed invalid characters");
item.Upd.Tag.Name = regxp.Replace(item.Upd.Tag.Name, "");
}
// Check items with StackObjectsCount (undefined)
if (item.Upd.StackObjectsCount is null)
{
_logger.Warning(
logger.Warning(
$"Fixed item: {item.Id}s undefined StackObjectsCount value, now set to 1"
);
item.Upd.StackObjectsCount = 1;
@@ -178,7 +178,7 @@ public class ProfileFixerService(
}
// Iterate over clothing
var customizationDb = _databaseService.GetTemplates().Customization;
var customizationDb = databaseService.GetTemplates().Customization;
var customizationDbArray = customizationDb.Values;
var playerIsUsec = string.Equals(
pmcProfile.Info.Side,
@@ -258,7 +258,7 @@ public class ProfileFixerService(
var taskConditionKeysToRemove = new List<string>();
var activeRepeatableQuests = GetActiveRepeatableQuests(pmcProfile.RepeatableQuests);
var achievements = _databaseService.GetAchievements();
var achievements = databaseService.GetAchievements();
// Loop over TaskConditionCounters objects and add once we want to remove to counterKeysToRemove
foreach (var TaskConditionCounterKvP in pmcProfile.TaskConditionCounters)
@@ -286,9 +286,9 @@ public class ProfileFixerService(
foreach (var counterKeyToRemove in taskConditionKeysToRemove)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Removed: {counterKeyToRemove} TaskConditionCounter object");
logger.Debug($"Removed: {counterKeyToRemove} TaskConditionCounter object");
}
pmcProfile.TaskConditionCounters.Remove(counterKeyToRemove);
@@ -319,7 +319,7 @@ public class ProfileFixerService(
/// <param name="pmcProfile">Profile to remove dead quests from</param>
protected void RemoveOrphanedQuests(PmcData pmcProfile)
{
var quests = _databaseService.GetQuests();
var quests = databaseService.GetQuests();
var profileQuests = pmcProfile.Quests;
var activeRepeatableQuests = GetActiveRepeatableQuests(pmcProfile.RepeatableQuests);
@@ -333,7 +333,7 @@ public class ProfileFixerService(
)
)
{
_logger.Info(
logger.Info(
$"Successfully removed orphaned quest: {profileQuests[i].QId} that doesn't exist in quest data"
);
profileQuests.RemoveAt(i);
@@ -347,7 +347,7 @@ public class ProfileFixerService(
/// <param name="pmcProfile">The profile to validate quest productions for</param>
protected void VerifyQuestProductionUnlocks(PmcData pmcProfile)
{
var quests = _databaseService.GetQuests();
var quests = databaseService.GetQuests();
var profileQuests = pmcProfile.Quests;
foreach (var profileQuest in profileQuests)
@@ -404,15 +404,15 @@ public class ProfileFixerService(
Quest questDetails
)
{
var matchingProductions = _rewardHelper.GetRewardProductionMatch(
var matchingProductions = rewardHelper.GetRewardProductionMatch(
productionUnlockReward,
questDetails.Id
);
if (matchingProductions.Count != 1)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"quest-unable_to_find_matching_hideout_production",
new
{
@@ -431,9 +431,9 @@ public class ProfileFixerService(
{
pmcProfile.UnlockedInfo.UnlockedProductionRecipe.Add(matchingProductionId);
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Added production: {matchingProductionId} to unlocked production recipes for: {questDetails.QuestName}"
);
}
@@ -462,7 +462,7 @@ public class ProfileFixerService(
/// <param name="pmcProfile">profile to add slots to</param>
protected void AddHideoutEliteSlots(PmcData pmcProfile)
{
var globals = _databaseService.GetGlobals();
var globals = databaseService.GetGlobals();
var generator = pmcProfile.Hideout.Areas.FirstOrDefault(area =>
area.Type == HideoutAreas.Generator
@@ -480,9 +480,9 @@ public class ProfileFixerService(
if (genSlots < 6 + extraGenSlots)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
"Updating generator area slots to a size of 6 + hideout management skill"
);
}
@@ -508,9 +508,9 @@ public class ProfileFixerService(
if (waterCollSlots < 1 + extraWaterCollSlots)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
"Updating water collector area slots to a size of 1 + hideout management skill"
);
}
@@ -535,9 +535,9 @@ public class ProfileFixerService(
if (filterSlots < 3 + extraFilterSlots)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
"Updating air filter area slots to a size of 3 + hideout management skill"
);
}
@@ -563,9 +563,9 @@ public class ProfileFixerService(
// BTC Farm doesnt have extra slots for hideout management, but we still check for modded stuff!!
if (btcFarmSlots < 50 + extraBtcSlots)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
"Updating bitcoin farm area slots to a size of 50 + hideout management skill"
);
}
@@ -582,9 +582,9 @@ public class ProfileFixerService(
.Slots.Count;
if (cultistAreaSlots < 1)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug("Updating cultist area slots to a size of 1");
logger.Debug("Updating cultist area slots to a size of 1");
}
AddEmptyObjectsToHideoutAreaSlots(HideoutAreas.CircleOfCultists, 1, pmcProfile);
@@ -639,9 +639,9 @@ public class ProfileFixerService(
/// </summary>
/// <param name="sessionId"> Session ID </param>
/// <param name="fullProfile"> Profile to check inventory of </param>
public void CheckForOrphanedModdedItems(string sessionId, SptProfile fullProfile)
public void CheckForOrphanedModdedItems(MongoId sessionId, SptProfile fullProfile)
{
var itemsDb = _databaseService.GetItems();
var itemsDb = databaseService.GetItems();
var pmcProfile = fullProfile.CharacterData.PmcData;
// Get items placed in root of stash
@@ -656,18 +656,18 @@ public class ProfileFixerService(
{
if (!itemsDb.ContainsKey(item.Template))
{
_logger.Error(
_serverLocalisationService.GetText("fixer-mod_item_found", item.Template)
logger.Error(
serverLocalisationService.GetText("fixer-mod_item_found", item.Template)
);
if (_coreConfig.Fixes.RemoveModItemsFromProfile)
{
_logger.Success(
logger.Success(
$"Deleting item from inventory and insurance with id: {item.Id} tpl: {item.Template}"
);
// also deletes from insured array
_inventoryHelper.RemoveItem(pmcProfile, item.Id, sessionId);
inventoryHelper.RemoveItem(pmcProfile, item.Id, sessionId);
}
}
}
@@ -732,18 +732,15 @@ public class ProfileFixerService(
// Check item exists in itemsDb
if (!itemsDb.ContainsKey(item.Template))
{
_logger.Error(
_serverLocalisationService.GetText(
"fixer-mod_item_found",
item.Template
)
logger.Error(
serverLocalisationService.GetText("fixer-mod_item_found", item.Template)
);
}
if (_coreConfig.Fixes.RemoveModItemsFromProfile)
{
dialog.Value.Messages.Remove(message);
_logger.Warning(
logger.Warning(
$"Item: {item.Template} has resulted in the deletion of message: {message.Id} from dialog {dialog}"
);
}
@@ -753,7 +750,7 @@ public class ProfileFixerService(
}
}
var clothingDb = _databaseService.GetTemplates().Customization;
var clothingDb = databaseService.GetTemplates().Customization;
foreach (
var clothingItem in fullProfile.CustomisationUnlocks.Where(customisation =>
customisation.Type == CustomisationType.SUITE
@@ -763,14 +760,14 @@ public class ProfileFixerService(
if (!clothingDb.ContainsKey(clothingItem.Id))
{
// Item in profile not found in db, not good
_logger.Error(
_serverLocalisationService.GetText("fixer-clothing_item_found", clothingItem)
logger.Error(
serverLocalisationService.GetText("fixer-clothing_item_found", clothingItem)
);
if (_coreConfig.Fixes.RemoveModItemsFromProfile)
{
fullProfile.CustomisationUnlocks.Remove(clothingItem);
_logger.Warning(
logger.Warning(
$"Non-default clothing purchase: {clothingItem} removed from profile"
);
}
@@ -789,17 +786,17 @@ public class ProfileFixerService(
foreach (var activeQuest in repeatable.ActiveQuests.ToArray())
{
if (!_traderHelper.TraderExists(activeQuest.TraderId))
if (!traderHelper.TraderExists(activeQuest.TraderId))
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"fixer-trader_found",
activeQuest.TraderId
)
);
if (_coreConfig.Fixes.RemoveModItemsFromProfile)
{
_logger.Warning(
logger.Warning(
$"Non-default quest: {activeQuest.Id} from trader: {activeQuest.TraderId} removed from RepeatableQuests list in profile"
);
repeatable.ActiveQuests.Remove(activeQuest);
@@ -823,7 +820,7 @@ public class ProfileFixerService(
{
if (!itemsDb.ContainsKey(item.Template))
{
_logger.Warning(
logger.Warning(
$"Non-default quest: {activeQuest.Id} from trader: {activeQuest.TraderId} removed from RepeatableQuests list in profile"
);
repeatable.ActiveQuests.Remove(activeQuest);
@@ -834,16 +831,16 @@ public class ProfileFixerService(
foreach (
var TraderPurchaseKvP in fullProfile.TraderPurchases.Where(TraderPurchase =>
!_traderHelper.TraderExists(TraderPurchase.Key)
!traderHelper.TraderExists(TraderPurchase.Key)
)
)
{
_logger.Error(
_serverLocalisationService.GetText("fixer-trader_found", TraderPurchaseKvP.Key)
logger.Error(
serverLocalisationService.GetText("fixer-trader_found", TraderPurchaseKvP.Key)
);
if (_coreConfig.Fixes.RemoveModItemsFromProfile)
{
_logger.Warning(
logger.Warning(
$"Non-default trader: {TraderPurchaseKvP.Key} purchase removed from traderPurchases list in profile"
);
fullProfile.TraderPurchases.Remove(TraderPurchaseKvP.Key);
@@ -873,13 +870,13 @@ public class ProfileFixerService(
)
)
{
_logger.Error(
_serverLocalisationService.GetText("fixer-mod_item_found", item.Template)
logger.Error(
serverLocalisationService.GetText("fixer-mod_item_found", item.Template)
);
if (_coreConfig.Fixes.RemoveModItemsFromProfile)
{
_logger.Warning(
logger.Warning(
$"Item: {item.Template} has resulted in the deletion of {buildType} build: {build.Name}"
);
@@ -901,13 +898,13 @@ public class ProfileFixerService(
)
)
{
_logger.Error(
_serverLocalisationService.GetText("fixer-mod_item_found", item.Template)
logger.Error(
serverLocalisationService.GetText("fixer-mod_item_found", item.Template)
);
if (_coreConfig.Fixes.RemoveModItemsFromProfile)
{
_logger.Warning(
logger.Warning(
$"Item: {item.Template} has resulted in the deletion of {buildType} build: {build.Name}"
);
@@ -944,13 +941,13 @@ public class ProfileFixerService(
// Check item exists in itemsDb
if (!itemsDb.ContainsKey(item.TemplateId))
{
_logger.Error(
_serverLocalisationService.GetText("fixer-mod_item_found", item.TemplateId)
logger.Error(
serverLocalisationService.GetText("fixer-mod_item_found", item.TemplateId)
);
if (_coreConfig.Fixes.RemoveModItemsFromProfile)
{
_logger.Warning(
logger.Warning(
$"Item: {item.TemplateId} has resulted in the deletion of magazine build: {magazineBuild.Name}"
);
@@ -1018,10 +1015,10 @@ public class ProfileFixerService(
if (profileBonus is null)
{
// no bonus, add to profile
_logger.Debug(
logger.Debug(
$"Profile has level {level} area {profileArea.Type} but no bonus found, adding {bonus.Type}"
);
_hideoutHelper.ApplyPlayerUpgradesBonuses(pmcProfile, bonus);
hideoutHelper.ApplyPlayerUpgradesBonuses(pmcProfile, bonus);
}
}
}
@@ -1061,12 +1058,12 @@ public class ProfileFixerService(
foreach (var traderKvP in fullProfile.CharacterData?.PmcData?.TradersInfo)
{
var traderId = traderKvP.Key;
if (!_traderHelper.TraderExists(traderId))
if (!traderHelper.TraderExists(traderId))
{
_logger.Error(_serverLocalisationService.GetText("fixer-trader_found", traderId));
logger.Error(serverLocalisationService.GetText("fixer-trader_found", traderId));
if (_coreConfig.Fixes.RemoveInvalidTradersFromProfile)
{
_logger.Warning(
logger.Warning(
$"Non - default trader: {traderId} removed from PMC TradersInfo in: {fullProfile.ProfileInfo?.ProfileId} profile"
);
fullProfile.CharacterData.PmcData.TradersInfo.Remove(traderId);
@@ -1077,12 +1074,12 @@ public class ProfileFixerService(
foreach (var traderKvP in fullProfile.CharacterData.ScavData?.TradersInfo)
{
var traderId = traderKvP.Key;
if (!_traderHelper.TraderExists(traderId))
if (!traderHelper.TraderExists(traderId))
{
_logger.Error(_serverLocalisationService.GetText("fixer-trader_found", traderId));
logger.Error(serverLocalisationService.GetText("fixer-trader_found", traderId));
if (_coreConfig.Fixes.RemoveInvalidTradersFromProfile)
{
_logger.Warning(
logger.Warning(
$"Non - default trader: {traderId} removed from Scav TradersInfo in: {fullProfile.ProfileInfo?.ProfileId} profile"
);
fullProfile.CharacterData.ScavData.TradersInfo.Remove(traderId);
@@ -9,8 +9,8 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class RagfairCategoriesService(
ISptLogger<RagfairCategoriesService> _logger,
PaymentHelper _paymentHelper
ISptLogger<RagfairCategoriesService> logger,
PaymentHelper paymentHelper
)
{
/// <summary>
@@ -47,7 +47,7 @@ public class RagfairCategoriesService(
&& searchRequestData.RemoveBartering.GetValueOrDefault(false)
&& (
offer.Requirements.Count > 1
|| !_paymentHelper.IsMoneyTpl(offer.Requirements.FirstOrDefault().Template)
|| !paymentHelper.IsMoneyTpl(offer.Requirements.FirstOrDefault().Template)
)
)
{
@@ -62,7 +62,7 @@ public class RagfairLinkedItemService(
/// </summary>
protected void BuildLinkedItemTable()
{
var linkedItems = new Dictionary<string, HashSet<MongoId>>();
var linkedItems = new Dictionary<MongoId, HashSet<MongoId>>();
foreach (var item in databaseService.GetItems().Values)
{
@@ -102,7 +102,7 @@ public class RagfairOfferService(
/// Remove all offers from ragfair made by trader
/// </summary>
/// <param name="traderId">Trader to remove offers for</param>
public void RemoveAllOffersByTrader(string traderId)
public void RemoveAllOffersByTrader(MongoId traderId)
{
ragfairOfferHolder.RemoveAllOffersByTrader(traderId);
}
@@ -112,7 +112,7 @@ public class RagfairOfferService(
/// </summary>
/// <param name="traderID"> Trader to check </param>
/// <returns> True if they do </returns>
public bool TraderOffersNeedRefreshing(string traderID)
public bool TraderOffersNeedRefreshing(MongoId traderID)
{
var trader = databaseService.GetTrader(traderID);
if (trader?.Base == null)
@@ -175,7 +175,7 @@ public class RagfairOfferService(
/// </summary>
/// <param name="staleOfferId"> Stale offer id to process </param>
/// <param name="flagOfferAsExpired">OPTIONAL - Flag the passed in offer as expired default = true</param>
protected void ProcessStaleOffer(string staleOfferId, bool flagOfferAsExpired = true)
protected void ProcessStaleOffer(MongoId staleOfferId, bool flagOfferAsExpired = true)
{
var staleOffer = ragfairOfferHolder.GetOfferById(staleOfferId);
if (staleOffer is null)
@@ -17,18 +17,18 @@ namespace SPTarkov.Server.Core.Services;
/// </summary>
[Injectable(InjectionType.Singleton)]
public class RagfairPriceService(
ISptLogger<RagfairPriceService> _logger,
RandomUtil _randomUtil,
HandbookHelper _handbookHelper,
TraderHelper _traderHelper,
PresetHelper _presetHelper,
ItemHelper _itemHelper,
DatabaseService _databaseService,
ServerLocalisationService _serverLocalisationService,
ConfigServer _configServer
ISptLogger<RagfairPriceService> logger,
RandomUtil randomUtil,
HandbookHelper handbookHelper,
TraderHelper traderHelper,
PresetHelper presetHelper,
ItemHelper itemHelper,
DatabaseService databaseService,
ServerLocalisationService serverLocalisationService,
ConfigServer configServer
)
{
private readonly RagfairConfig _ragfairConfig = _configServer.GetConfig<RagfairConfig>();
private readonly RagfairConfig _ragfairConfig = configServer.GetConfig<RagfairConfig>();
protected Dictionary<MongoId, double>? _staticPrices;
/// <summary>
@@ -52,14 +52,14 @@ public class RagfairPriceService(
{
_staticPrices = new Dictionary<MongoId, double>();
foreach (
var item in _databaseService
var item in databaseService
.GetItems()
.Values.Where(item =>
string.Equals(item.Type, "Item", StringComparison.OrdinalIgnoreCase)
)
)
{
_staticPrices[item.Id] = _handbookHelper.GetTemplatePrice(item.Id);
_staticPrices[item.Id] = handbookHelper.GetTemplatePrice(item.Id);
}
}
@@ -80,12 +80,12 @@ public class RagfairPriceService(
public double GetFleaPriceForItem(MongoId tplId)
{
// Get dynamic price (templates/prices), if that doesn't exist get price from static array (templates/handbook)
var itemPrice = _itemHelper.GetDynamicItemPrice(tplId) ?? GetStaticPriceForItem(tplId);
var itemPrice = itemHelper.GetDynamicItemPrice(tplId) ?? GetStaticPriceForItem(tplId);
if (itemPrice is null)
{
var itemFromDb = _itemHelper.GetItem(tplId);
_logger.Warning(
_serverLocalisationService.GetText(
var itemFromDb = itemHelper.GetItem(tplId);
logger.Warning(
serverLocalisationService.GetText(
"ragfair-unable_to_find_item_price_for_item_in_flea_handbook",
new { tpl = tplId, name = itemFromDb.Value.Name ?? "" }
)
@@ -109,7 +109,7 @@ public class RagfairPriceService(
public double GetFleaPriceForOfferItems(List<Item> offerItems)
{
// Preset weapons take the direct prices.json value, otherwise they're massively inflated
if (_itemHelper.IsOfBaseclass(offerItems[0].Template, BaseClasses.WEAPON))
if (itemHelper.IsOfBaseclass(offerItems[0].Template, BaseClasses.WEAPON))
{
return GetFleaPriceForItem(offerItems[0].Template);
}
@@ -124,7 +124,7 @@ public class RagfairPriceService(
/// <returns> Price in roubles </returns>
public double? GetDynamicPriceForItem(MongoId itemTpl)
{
_databaseService.GetPrices().TryGetValue(itemTpl, out var value);
databaseService.GetPrices().TryGetValue(itemTpl, out var value);
return value;
}
@@ -136,7 +136,7 @@ public class RagfairPriceService(
/// <returns>price in roubles</returns>
public double? GetStaticPriceForItem(MongoId itemTpl)
{
return _handbookHelper.GetTemplatePrice(itemTpl);
return handbookHelper.GetTemplatePrice(itemTpl);
}
/// <summary>
@@ -146,7 +146,7 @@ public class RagfairPriceService(
/// <returns>Dictionary of item tpls and rouble cost</returns>
public Dictionary<MongoId, double> GetAllFleaPrices()
{
var dynamicPrices = _databaseService.GetPrices();
var dynamicPrices = databaseService.GetPrices();
// Use dynamic prices first, fill in any gaps with data from static prices (handbook)
return dynamicPrices
.Concat(_staticPrices)
@@ -213,7 +213,7 @@ public class RagfairPriceService(
foreach (var item in offerItems)
{
// Skip over armor inserts as those are not factored into item prices.
if (_itemHelper.IsOfBaseclass(item.Template, BaseClasses.BUILT_IN_INSERTS))
if (itemHelper.IsOfBaseclass(item.Template, BaseClasses.BUILT_IN_INSERTS))
{
continue;
}
@@ -229,7 +229,7 @@ public class RagfairPriceService(
// Check if the item is a weapon preset.
if (
item?.Upd?.SptPresetId is not null
&& _presetHelper.IsPresetBaseClass(item.Upd.SptPresetId, BaseClasses.WEAPON)
&& presetHelper.IsPresetBaseClass(item.Upd.SptPresetId, BaseClasses.WEAPON)
)
// This is a weapon preset, which has it's own price calculation that takes into account the mods in the
// preset. Since we've already calculated the price for the preset entire preset in
@@ -252,7 +252,7 @@ public class RagfairPriceService(
/// <returns></returns>
public double? GetDynamicItemPrice(
MongoId itemTemplateId,
string desiredCurrency,
MongoId desiredCurrency,
Item? item = null,
List<Item>? offerItems = null,
bool? isPackOffer = null
@@ -270,7 +270,7 @@ public class RagfairPriceService(
// Use trader price if higher, based on config.
if (_ragfairConfig.Dynamic.UseTraderPriceForOffersIfHigher)
{
var traderPrice = _traderHelper.GetHighestSellToTraderPrice(itemTemplateId);
var traderPrice = traderHelper.GetHighestSellToTraderPrice(itemTemplateId);
if (traderPrice > price)
{
price = traderPrice;
@@ -281,7 +281,7 @@ public class RagfairPriceService(
if (
item?.Upd?.SptPresetId is not null
&& offerItems is not null
&& _presetHelper.IsPresetBaseClass(item.Upd.SptPresetId, BaseClasses.WEAPON)
&& presetHelper.IsPresetBaseClass(item.Upd.SptPresetId, BaseClasses.WEAPON)
)
{
price = GetWeaponPresetPrice(item, offerItems, price);
@@ -305,14 +305,14 @@ public class RagfairPriceService(
&& !_ragfairConfig.Dynamic.IgnoreQualityPriceVarianceBlacklist.Contains(itemTemplateId)
)
{
var qualityModifier = _itemHelper.GetItemQualityModifier(item);
var qualityModifier = itemHelper.GetItemQualityModifier(item);
price *= qualityModifier;
}
// Make adjustments for unreasonably priced items.
foreach (var (key, value) in _ragfairConfig.Dynamic.UnreasonableModPrices)
{
if (!_itemHelper.IsOfBaseclass(itemTemplateId, key) || !value.Enabled)
if (!itemHelper.IsOfBaseclass(itemTemplateId, key) || !value.Enabled)
{
continue;
}
@@ -327,7 +327,7 @@ public class RagfairPriceService(
// Convert to different currency if required.
if (desiredCurrency != Money.ROUBLES)
{
price = _handbookHelper.FromRUB(price, desiredCurrency);
price = handbookHelper.FromRUB(price, desiredCurrency);
}
if (price <= 0)
@@ -351,7 +351,7 @@ public class RagfairPriceService(
double price
)
{
var itemHandbookPrice = _handbookHelper.GetTemplatePrice(itemTpl);
var itemHandbookPrice = handbookHelper.GetTemplatePrice(itemTpl);
if (itemHandbookPrice > 0)
{
return price;
@@ -433,7 +433,7 @@ public class RagfairPriceService(
protected double RandomiseOfferPrice(double existingPrice, MinMax<double> rangeValues)
{
// Multiply by 100 to get 2 decimal places of precision
var multiplier = _randomUtil.GetBiasedRandomNumber(
var multiplier = randomUtil.GetBiasedRandomNumber(
rangeValues.Min * 100,
rangeValues.Max * 100,
2,
@@ -510,7 +510,7 @@ public class RagfairPriceService(
protected double? GetHighestHandbookOrTraderPriceAsRouble(MongoId itemTpl)
{
var price = GetStaticPriceForItem(itemTpl);
var traderPrice = _traderHelper.GetHighestSellToTraderPrice(itemTpl);
var traderPrice = traderHelper.GetHighestSellToTraderPrice(itemTpl);
if (traderPrice > price)
{
price = traderPrice;
@@ -527,17 +527,17 @@ public class RagfairPriceService(
/// <returns>Default preset object</returns>
protected WeaponPreset GetWeaponPreset(Item weapon)
{
var defaultPreset = _presetHelper.GetDefaultPreset(weapon.Template);
var defaultPreset = presetHelper.GetDefaultPreset(weapon.Template);
if (defaultPreset is not null)
{
return new WeaponPreset { IsDefault = true, Preset = defaultPreset };
}
var nonDefaultPresets = _presetHelper.GetPresets(weapon.Template);
var nonDefaultPresets = presetHelper.GetPresets(weapon.Template);
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
nonDefaultPresets.Count == 1
? $"Item Id: {weapon.Template} has no default encyclopedia entry but only one preset: ({nonDefaultPresets[0].Name}), choosing preset: ({nonDefaultPresets[0].Name})"
: $"Item Id: {weapon.Template} has no default encyclopedia entry, choosing first preset({nonDefaultPresets[0].Name}) of {nonDefaultPresets.Count}"
@@ -1,6 +1,7 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Ragfair;
@@ -13,11 +14,11 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class RagfairTaxService(
ISptLogger<RagfairTaxService> _logger,
DatabaseService _databaseService,
RagfairPriceService _ragfairPriceService,
ItemHelper _itemHelper,
ICloner _cloner
ISptLogger<RagfairTaxService> logger,
DatabaseService databaseService,
RagfairPriceService ragfairPriceService,
ItemHelper itemHelper,
ICloner cloner
)
{
protected readonly Dictionary<
@@ -26,7 +27,7 @@ public class RagfairTaxService(
> _playerOfferTaxCache = new();
public void StoreClientOfferTaxValue(
string sessionId,
MongoId sessionId,
StorePlayerOfferTaxAmountRequestData offer
)
{
@@ -73,9 +74,9 @@ public class RagfairTaxService(
return 0;
}
var globals = _databaseService.GetGlobals();
var globals = databaseService.GetGlobals();
var itemTemplate = _itemHelper.GetItem(item.Template).Value;
var itemTemplate = itemHelper.GetItem(item.Template).Value;
var itemWorth = CalculateItemWorth(item, itemTemplate, offerItemCount.Value, pmcData);
var requirementsPrice = requirementsValue * (sellInOnePiece ? 1 : offerItemCount);
@@ -114,7 +115,7 @@ public class RagfairTaxService(
if (item.Upd.Buff is not null)
{
var buffType = item.Upd.Buff.BuffType;
var itemEnhancementSettings = _databaseService
var itemEnhancementSettings = databaseService
.GetGlobals()
.Configuration.RepairSettings.ItemEnhancementSettings;
var priceModiferValue = buffType switch
@@ -138,9 +139,9 @@ public class RagfairTaxService(
var taxValue = Math.Round(discountedTax.Value * itemComissionMult);
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Tax Calculated to be: {taxValue}");
logger.Debug($"Tax Calculated to be: {taxValue}");
}
return taxValue;
@@ -164,7 +165,7 @@ public class RagfairTaxService(
bool isRootItem = true
)
{
var worth = _ragfairPriceService.GetFleaPriceForItem(item.Template);
var worth = ragfairPriceService.GetFleaPriceForItem(item.Template);
// In client, all item slots are traversed and any items contained within have their values added
if (isRootItem)
@@ -173,14 +174,14 @@ public class RagfairTaxService(
var itemChildren = pmcData.Inventory.Items.FindAndReturnChildrenAsItems(item.Id);
if (itemChildren.Count > 1)
{
var itemChildrenClone = _cloner.Clone(itemChildren); // Clone is expensive, only run if necessary
var itemChildrenClone = cloner.Clone(itemChildren); // Clone is expensive, only run if necessary
foreach (var child in itemChildrenClone.Where(child => child.Id != item.Id))
{
child.Upd ??= new Upd();
worth += CalculateItemWorth(
child,
_itemHelper.GetItem(child.Template).Value,
itemHelper.GetItem(child.Template).Value,
(int)(child.Upd.StackObjectsCount ?? 1),
pmcData,
false
@@ -198,7 +199,7 @@ public class RagfairTaxService(
if (itemTemplate.Properties is null)
{
_logger.Warning(
logger.Warning(
$"Item: {item.Id} lacks _props and cannot have its worth calculated properly"
);
@@ -1,5 +1,6 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Game;
using SPTarkov.Server.Core.Models.Enums;
@@ -13,15 +14,15 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class RaidTimeAdjustmentService(
ISptLogger<RaidTimeAdjustmentService> _logger,
DatabaseService _databaseService,
RandomUtil _randomUtil,
WeightedRandomHelper _weightedRandomHelper,
ProfileActivityService _profileActivityService,
ConfigServer _configServer
ISptLogger<RaidTimeAdjustmentService> logger,
DatabaseService databaseService,
RandomUtil randomUtil,
WeightedRandomHelper weightedRandomHelper,
ProfileActivityService profileActivityService,
ConfigServer configServer
)
{
protected readonly LocationConfig _locationConfig = _configServer.GetConfig<LocationConfig>();
protected readonly LocationConfig _locationConfig = configServer.GetConfig<LocationConfig>();
/// <summary>
/// Make alterations to the base map data passed in
@@ -33,7 +34,7 @@ public class RaidTimeAdjustmentService(
{
if (raidAdjustments.DynamicLootPercent < 100 || raidAdjustments.StaticLootPercent < 100)
{
_logger.Debug(
logger.Debug(
$"Adjusting dynamic loot multipliers to {raidAdjustments.DynamicLootPercent}% and static loot multipliers to {raidAdjustments.StaticLootPercent}% of original"
);
}
@@ -64,7 +65,7 @@ public class RaidTimeAdjustmentService(
var exitToChange = mapBase.Exits.FirstOrDefault(exit => exit.Name == exitChange.Name);
if (exitToChange is null)
{
_logger.Debug($"Exit with Id: {exitChange.Name} not found, skipping");
logger.Debug($"Exit with Id: {exitChange.Name} not found, skipping");
return;
}
@@ -105,7 +106,7 @@ public class RaidTimeAdjustmentService(
{
foreach (var location in mapLootMultipliers)
{
mapLootMultipliers[location.Key] = _randomUtil.GetPercentOfValue(
mapLootMultipliers[location.Key] = randomUtil.GetPercentOfValue(
mapLootMultipliers[location.Key],
loosePercent ?? 1
);
@@ -134,7 +135,7 @@ public class RaidTimeAdjustmentService(
wave.TimeMax -= (int)Math.Max(startSeconds, 0);
}
_logger.Debug(
logger.Debug(
$"Removed {originalWaveCount - mapBase.Waves.Count} wave from map due to simulated raid start time of {raidAdjustments.SimulatedRaidStartSeconds / 60} minutes"
);
}
@@ -145,10 +146,10 @@ public class RaidTimeAdjustmentService(
/// <param name="sessionId">Session id</param>
/// <param name="request">Raid adjustment request</param>
/// <returns>Response to send to client</returns>
public RaidChanges GetRaidAdjustments(string sessionId, GetRaidTimeRequest request)
public RaidChanges GetRaidAdjustments(MongoId sessionId, GetRaidTimeRequest request)
{
var globals = _databaseService.GetGlobals();
var mapBase = _databaseService.GetLocation(request.Location.ToLowerInvariant()).Base;
var globals = databaseService.GetGlobals();
var mapBase = databaseService.GetLocation(request.Location.ToLowerInvariant()).Base;
var baseEscapeTimeMinutes = mapBase.EscapeTimeLimit;
// Prep result object to return
@@ -177,7 +178,7 @@ public class RaidTimeAdjustmentService(
var mapSettings = GetMapSettings(request.Location);
// Chance of reducing raid time for scav, not guaranteed
if (!_randomUtil.GetChance100(mapSettings.ReducedChancePercent))
if (!randomUtil.GetChance100(mapSettings.ReducedChancePercent))
// Send default
{
return result;
@@ -185,13 +186,13 @@ public class RaidTimeAdjustmentService(
// Get the weighted percent to reduce the raid time by
var chosenRaidReductionPercent = int.Parse(
_weightedRandomHelper.GetWeightedValue(mapSettings.ReductionPercentWeights)
weightedRandomHelper.GetWeightedValue(mapSettings.ReductionPercentWeights)
);
var raidTimeRemainingPercent = 100 - chosenRaidReductionPercent;
// How many minutes raid will last
var newRaidTimeMinutes = Math.Floor(
_randomUtil.ReduceValueByPercent(baseEscapeTimeMinutes ?? 1, chosenRaidReductionPercent)
randomUtil.ReduceValueByPercent(baseEscapeTimeMinutes ?? 1, chosenRaidReductionPercent)
);
// Time player spawns into the raid if it was online
@@ -218,7 +219,7 @@ public class RaidTimeAdjustmentService(
);
}
_logger.Debug(
logger.Debug(
$"Reduced: {request.Location} raid time by: {chosenRaidReductionPercent}% to {newRaidTimeMinutes} minutes"
);
@@ -236,7 +237,7 @@ public class RaidTimeAdjustmentService(
}
// Store state to use in loot generation
_profileActivityService.GetProfileActivityRaidData(sessionId).RaidAdjustments = result;
profileActivityService.GetProfileActivityRaidData(sessionId).RaidAdjustments = result;
return result;
}
@@ -248,10 +249,10 @@ public class RaidTimeAdjustmentService(
/// <returns>ScavRaidTimeLocationSettings</returns>
protected ScavRaidTimeLocationSettings GetMapSettings(string location)
{
var mapSettings = _locationConfig.ScavRaidTimeSettings.Maps?[location.ToLowerInvariant()];
var mapSettings = _locationConfig.ScavRaidTimeSettings.Maps[location.ToLowerInvariant()];
if (mapSettings is null)
{
_logger.Warning(
logger.Warning(
$"Unable to find scav raid time settings for map: {location}, using defaults"
);
return new ScavRaidTimeLocationSettings();
@@ -325,7 +326,7 @@ public class RaidTimeAdjustmentService(
{
exitChange.Chance = 0;
_logger.Debug(
logger.Debug(
$"Train Exit: {exit.Name} disabled as new raid time {newRaidTimeMinutes} minutes is below {mostPossibleTimeRemainingAfterDeparture} minutes"
);
@@ -338,7 +339,7 @@ public class RaidTimeAdjustmentService(
exitChange.MinTime = Math.Max(exit.MinTime - reductionSeconds ?? 0, 0);
exitChange.MaxTime = Math.Max(exit.MaxTime - reductionSeconds ?? 0, 0);
_logger.Debug(
logger.Debug(
$"Train appears between: {exitChange.MinTime} and {exitChange.MaxTime} seconds raid time"
);
@@ -11,14 +11,14 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class RaidWeatherService(
TimeUtil _timeUtil,
WeatherGenerator _weatherGenerator,
SeasonalEventService _seasonalEventService,
WeightedRandomHelper _weightedRandomHelper,
ConfigServer _configServer
TimeUtil timeUtil,
WeatherGenerator weatherGenerator,
SeasonalEventService seasonalEventService,
WeightedRandomHelper weightedRandomHelper,
ConfigServer configServer
)
{
protected readonly WeatherConfig _weatherConfig = _configServer.GetConfig<WeatherConfig>();
protected readonly WeatherConfig _weatherConfig = configServer.GetConfig<WeatherConfig>();
protected readonly List<Weather> _weatherForecast = [];
/// <summary>
@@ -27,18 +27,18 @@ public class RaidWeatherService(
public void GenerateWeather(Season currentSeason)
{
// When to start generating weather from in milliseconds
var staringTimestamp = _timeUtil.GetTodayMidnightTimeStamp();
var staringTimestamp = timeUtil.GetTodayMidnightTimeStamp();
// How far into future do we generate weather
var futureTimestampToReach =
staringTimestamp
+ _timeUtil.GetHoursAsSeconds(_weatherConfig.Weather.GenerateWeatherAmountHours ?? 1);
+ timeUtil.GetHoursAsSeconds(_weatherConfig.Weather.GenerateWeatherAmountHours ?? 1);
// Keep adding new weather until we have reached desired future date
var nextTimestamp = staringTimestamp;
while (nextTimestamp <= futureTimestampToReach)
{
var newWeatherToAddToCache = _weatherGenerator.GenerateWeather(
var newWeatherToAddToCache = weatherGenerator.GenerateWeather(
currentSeason,
nextTimestamp
);
@@ -57,7 +57,7 @@ public class RaidWeatherService(
/// <returns>milliseconds</returns>
protected long GetWeightedWeatherTimePeriod()
{
var chosenTimePeriodMinutes = _weightedRandomHelper
var chosenTimePeriodMinutes = weightedRandomHelper
.WeightedRandom(
_weatherConfig.Weather.TimePeriod.Values,
_weatherConfig.Weather.TimePeriod.Weights
@@ -72,10 +72,10 @@ public class RaidWeatherService(
/// </summary>
public Weather GetCurrentWeather()
{
var currentSeason = _seasonalEventService.GetActiveWeatherSeason();
var currentSeason = seasonalEventService.GetActiveWeatherSeason();
ValidateWeatherDataExists(currentSeason);
return _weatherForecast.Find(weather => weather.Timestamp >= _timeUtil.GetTimeStamp());
return _weatherForecast.Find(weather => weather.Timestamp >= timeUtil.GetTimeStamp());
}
/// <summary>
@@ -83,10 +83,10 @@ public class RaidWeatherService(
/// </summary>
public IEnumerable<Weather> GetUpcomingWeather()
{
var currentSeason = _seasonalEventService.GetActiveWeatherSeason();
var currentSeason = seasonalEventService.GetActiveWeatherSeason();
ValidateWeatherDataExists(currentSeason);
return _weatherForecast.Where(weather => weather.Timestamp >= _timeUtil.GetTimeStamp());
return _weatherForecast.Where(weather => weather.Timestamp >= timeUtil.GetTimeStamp());
}
/// <summary>
@@ -95,11 +95,11 @@ public class RaidWeatherService(
protected void ValidateWeatherDataExists(Season currentSeason)
{
// Clear expired weather data
_weatherForecast.RemoveAll(weather => weather.Timestamp < _timeUtil.GetTimeStamp());
_weatherForecast.RemoveAll(weather => weather.Timestamp < timeUtil.GetTimeStamp());
// Check data exists for current time
var result = _weatherForecast.Where(weather =>
weather.Timestamp >= _timeUtil.GetTimeStamp()
weather.Timestamp >= timeUtil.GetTimeStamp()
);
if (!result.Any())
{
@@ -21,20 +21,20 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class RepairService(
ISptLogger<RepairService> _logger,
RandomUtil _randomUtil,
DatabaseService _databaseService,
ItemHelper _itemHelper,
TraderHelper _traderHelper,
PaymentService _paymentService,
ProfileHelper _profileHelper,
RepairHelper _repairHelper,
ServerLocalisationService _serverLocalisationService,
ConfigServer _configServer,
WeightedRandomHelper _weightedRandomHelper
ISptLogger<RepairService> logger,
RandomUtil randomUtil,
DatabaseService databaseService,
ItemHelper itemHelper,
TraderHelper traderHelper,
PaymentService paymentService,
ProfileHelper profileHelper,
RepairHelper repairHelper,
ServerLocalisationService serverLocalisationService,
ConfigServer configServer,
WeightedRandomHelper weightedRandomHelper
)
{
protected readonly RepairConfig _repairConfig = _configServer.GetConfig<RepairConfig>();
protected readonly RepairConfig _repairConfig = configServer.GetConfig<RepairConfig>();
/// <summary>
/// Use trader to repair an items durability
@@ -45,10 +45,10 @@ public class RepairService(
/// <param name="traderId">Trader being used to repair item</param>
/// <returns>RepairDetails object</returns>
public RepairDetails RepairItemByTrader(
string sessionID,
MongoId sessionID,
PmcData pmcData,
RepairItem repairItemDetails,
string traderId
MongoId traderId
)
{
var itemToRepair = pmcData.Inventory.Items.FirstOrDefault(item =>
@@ -56,20 +56,20 @@ public class RepairService(
);
if (itemToRepair is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"repair-unable_to_find_item_in_inventory_cant_repair",
repairItemDetails.Id
)
);
}
var priceCoef = _traderHelper.GetLoyaltyLevel(traderId, pmcData).RepairPriceCoefficient;
var traderRepairDetails = _traderHelper.GetTrader(traderId, sessionID)?.Repair;
var priceCoef = traderHelper.GetLoyaltyLevel(traderId, pmcData).RepairPriceCoefficient;
var traderRepairDetails = traderHelper.GetTrader(traderId, sessionID)?.Repair;
if (traderRepairDetails is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"repair-unable_to_find_trader_details_by_id",
traderId
)
@@ -79,11 +79,11 @@ public class RepairService(
var repairQualityMultiplier = traderRepairDetails.Quality;
var repairRate = priceCoef <= 0 ? 1 : priceCoef / 100 + 1;
var items = _databaseService.GetItems();
var items = databaseService.GetItems();
var itemToRepairDetails = items[itemToRepair.Template];
var repairItemIsArmor = itemToRepairDetails.Properties.ArmorMaterial is not null;
_repairHelper.UpdateItemDurability(
repairHelper.UpdateItemDurability(
itemToRepair,
itemToRepairDetails,
repairItemIsArmor,
@@ -97,8 +97,8 @@ public class RepairService(
var itemRepairCost = items[itemToRepair.Template].Properties.RepairCost;
if (itemRepairCost is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"repair-unable_to_find_item_repair_cost",
itemToRepair.Template
)
@@ -112,11 +112,11 @@ public class RepairService(
* _repairConfig.PriceMultiplier
);
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"item base repair cost: {itemRepairCost}");
_logger.Debug($"price multiplier: {_repairConfig.PriceMultiplier}");
_logger.Debug($"repair cost: {repairCost}");
logger.Debug($"item base repair cost: {itemRepairCost}");
logger.Debug($"price multiplier: {_repairConfig.PriceMultiplier}");
logger.Debug($"repair cost: {repairCost}");
}
return new RepairDetails
@@ -138,11 +138,11 @@ public class RepairService(
/// <param name="traderId">Id of the trader who repaired the item / who is paid</param>
/// <param name="output">Client response</param>
public void PayForRepair(
string sessionID,
MongoId sessionID,
PmcData pmcData,
string repairedItemId,
double repairCost,
string traderId,
MongoId traderId,
ItemEventRouterResponse output
)
{
@@ -157,7 +157,7 @@ public class RepairService(
SchemeId = 0,
};
_paymentService.PayMoney(pmcData, options, sessionID, output);
paymentService.PayMoney(pmcData, options, sessionID, output);
}
/// <summary>
@@ -166,20 +166,24 @@ public class RepairService(
/// <param name="sessionId">Session id</param>
/// <param name="repairDetails">Details of item repaired, cost/item</param>
/// <param name="pmcData">Profile to add points to</param>
public void AddRepairSkillPoints(string sessionId, RepairDetails repairDetails, PmcData pmcData)
public void AddRepairSkillPoints(
MongoId sessionId,
RepairDetails repairDetails,
PmcData pmcData
)
{
// Handle kit repair of weapon
if (
repairDetails.RepairedByKit.GetValueOrDefault(false)
&& _itemHelper.IsOfBaseclass(repairDetails.RepairedItem.Template, BaseClasses.WEAPON)
&& itemHelper.IsOfBaseclass(repairDetails.RepairedItem.Template, BaseClasses.WEAPON)
)
{
var skillPoints = GetWeaponRepairSkillPoints(repairDetails);
if (skillPoints > 0)
{
_logger.Debug($"Added: {skillPoints} WEAPON_TREATMENT points to skill");
_profileHelper.AddSkillPointsToPlayer(
logger.Debug($"Added: {skillPoints} WEAPON_TREATMENT points to skill");
profileHelper.AddSkillPointsToPlayer(
pmcData,
SkillTypes.WeaponTreatment,
skillPoints,
@@ -191,18 +195,18 @@ public class RepairService(
// Handle kit repair of armor
if (
repairDetails.RepairedByKit.GetValueOrDefault(false)
&& _itemHelper.IsOfBaseclasses(
&& itemHelper.IsOfBaseclasses(
repairDetails.RepairedItem.Template,
[BaseClasses.ARMOR_PLATE, BaseClasses.BUILT_IN_INSERTS]
)
)
{
var itemDetails = _itemHelper.GetItem(repairDetails.RepairedItem.Template);
var itemDetails = itemHelper.GetItem(repairDetails.RepairedItem.Template);
if (!itemDetails.Key)
{
// No item found
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"repair-unable_to_find_item_in_db",
repairDetails.RepairedItem.Template
)
@@ -215,8 +219,8 @@ public class RepairService(
var vestSkillToLevel = isHeavyArmor ? SkillTypes.HeavyVests : SkillTypes.LightVests;
if (repairDetails.RepairPoints is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"repair-item_has_no_repair_points",
repairDetails.RepairedItem.Template
)
@@ -227,20 +231,16 @@ public class RepairService(
repairDetails.RepairPoints
* _repairConfig.ArmorKitSkillPointGainPerRepairPointMultiplier;
_logger.Debug($"Added: {pointsToAddToVestSkill} {vestSkillToLevel} skill");
_profileHelper.AddSkillPointsToPlayer(
pmcData,
vestSkillToLevel,
pointsToAddToVestSkill
);
logger.Debug($"Added: {pointsToAddToVestSkill} {vestSkillToLevel} skill");
profileHelper.AddSkillPointsToPlayer(pmcData, vestSkillToLevel, pointsToAddToVestSkill);
}
// Handle giving INT to player - differs if using kit/trader and weapon vs armor
var intellectGainedFromRepair = GetIntellectGainedFromRepair(repairDetails);
if (intellectGainedFromRepair > 0)
{
_logger.Debug($"Added: {intellectGainedFromRepair} intellect skill");
_profileHelper.AddSkillPointsToPlayer(
logger.Debug($"Added: {intellectGainedFromRepair} intellect skill");
profileHelper.AddSkillPointsToPlayer(
pmcData,
SkillTypes.Intellect,
intellectGainedFromRepair
@@ -253,7 +253,7 @@ public class RepairService(
if (repairDetails.RepairedByKit.GetValueOrDefault(false))
{
// Weapons/armor have different multipliers
var intRepairMultiplier = _itemHelper.IsOfBaseclass(
var intRepairMultiplier = itemHelper.IsOfBaseclass(
repairDetails.RepairedItem.Template,
BaseClasses.WEAPON
)
@@ -263,8 +263,8 @@ public class RepairService(
// Limit gain to a max value defined in config.maxIntellectGainPerRepair
if (repairDetails.RepairPoints is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"repair-item_has_no_repair_points",
repairDetails.RepairedItem.Template
)
@@ -330,7 +330,7 @@ public class RepairService(
/// <param name="output">ItemEventRouterResponse</param>
/// <returns>Details of repair, item/price</returns>
public RepairDetails RepairItemByKit(
string sessionId,
MongoId sessionId,
PmcData pmcData,
List<RepairKitsInfo> repairKits,
MongoId itemToRepairId,
@@ -341,15 +341,15 @@ public class RepairService(
var itemToRepair = pmcData.Inventory.Items.FirstOrDefault(x => x.Id == itemToRepairId);
if (itemToRepair is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"repair-item_not_found_unable_to_repair",
itemToRepairId
)
);
}
var itemsDb = _databaseService.GetItems();
var itemsDb = databaseService.GetItems();
var itemToRepairDetails = itemsDb[itemToRepair.Template];
var repairItemIsArmor = itemToRepairDetails.Properties.ArmorMaterial is not null;
var repairAmount =
@@ -359,7 +359,7 @@ public class RepairService(
_repairConfig.ApplyRandomizeDurabilityLoss
);
_repairHelper.UpdateItemDurability(
repairHelper.UpdateItemDurability(
itemToRepair,
itemToRepairDetails,
repairItemIsArmor,
@@ -377,8 +377,8 @@ public class RepairService(
);
if (repairKitInInventory is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"repair-repair_kit_not_found_in_inventory",
repairKit.Id
)
@@ -415,7 +415,7 @@ public class RepairService(
/// <returns>Number to divide kit points by</returns>
protected double GetKitDivisor(TemplateItem itemToRepairDetails, bool isArmor, PmcData pmcData)
{
var globals = _databaseService.GetGlobals();
var globals = databaseService.GetGlobals();
var globalConfig = globals.Configuration;
var globalRepairSettings = globalConfig.RepairSettings;
@@ -487,11 +487,11 @@ public class RepairService(
if (shouldApplyDurabilityLoss)
{
// Random loss not disabled via config, perform charisma check
var hasEliteCharisma = _profileHelper.HasEliteSkillLevel(SkillTypes.Charisma, pmcData);
var hasEliteCharisma = profileHelper.HasEliteSkillLevel(SkillTypes.Charisma, pmcData);
if (hasEliteCharisma)
// 50/50 chance of loss being ignored at elite level
{
shouldApplyDurabilityLoss = _randomUtil.GetChance100(50);
shouldApplyDurabilityLoss = randomUtil.GetChance100(50);
}
}
@@ -511,9 +511,9 @@ public class RepairService(
var maxRepairAmount = repairKitDetails.Properties.MaxRepairResource;
if (repairKitInInventory.Upd is null)
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Repair kit: {repairKitInInventory.Id} in inventory lacks upd object, adding"
);
}
@@ -546,7 +546,7 @@ public class RepairService(
if (ShouldBuffItem(repairDetails, pmcData))
{
if (
_itemHelper.IsOfBaseclasses(
itemHelper.IsOfBaseclasses(
repairDetails.RepairedItem.Template,
[
BaseClasses.ARMOR,
@@ -561,7 +561,7 @@ public class RepairService(
AddBuff(armorConfig, repairDetails.RepairedItem);
}
else if (
_itemHelper.IsOfBaseclass(repairDetails.RepairedItem.Template, BaseClasses.WEAPON)
itemHelper.IsOfBaseclass(repairDetails.RepairedItem.Template, BaseClasses.WEAPON)
)
{
var weaponConfig = _repairConfig.RepairKit.Weapon;
@@ -578,15 +578,15 @@ public class RepairService(
/// <param name="item">Item to repair</param>
public void AddBuff(BonusSettings itemConfig, Item item)
{
var bonusRarityName = _weightedRandomHelper.GetWeightedValue(itemConfig.RarityWeight);
var bonusTypeName = _weightedRandomHelper.GetWeightedValue(itemConfig.BonusTypeWeight);
var bonusRarityName = weightedRandomHelper.GetWeightedValue(itemConfig.RarityWeight);
var bonusTypeName = weightedRandomHelper.GetWeightedValue(itemConfig.BonusTypeWeight);
var bonusRarity = bonusRarityName == "Rare" ? itemConfig.Rare : itemConfig.Common;
var bonusValues = bonusRarity[bonusTypeName].ValuesMinMax;
var bonusValue = _randomUtil.GetDouble(bonusValues.Min, bonusValues.Max);
var bonusValue = randomUtil.GetDouble(bonusValues.Min, bonusValues.Max);
var bonusThresholdPercents = bonusRarity[bonusTypeName].ActiveDurabilityPercentMinMax;
var bonusThresholdPercent = _randomUtil.GetDouble(
var bonusThresholdPercent = randomUtil.GetDouble(
bonusThresholdPercents.Min,
bonusThresholdPercents.Max
);
@@ -596,7 +596,7 @@ public class RepairService(
Rarity = bonusRarityName,
BuffType = Enum.Parse<BuffType>(bonusTypeName),
Value = bonusValue,
ThresholdDurability = _randomUtil.GetPercentOfValue(
ThresholdDurability = randomUtil.GetPercentOfValue(
bonusThresholdPercent,
item.Upd.Repairable.Durability.Value,
0
@@ -613,9 +613,9 @@ public class RepairService(
/// <returns>True if item should have buff applied</returns>
protected bool ShouldBuffItem(RepairDetails repairDetails, PmcData pmcData)
{
var globals = _databaseService.GetGlobals();
var globals = databaseService.GetGlobals();
var hasTemplate = _itemHelper.GetItem(repairDetails.RepairedItem.Template);
var hasTemplate = itemHelper.GetItem(repairDetails.RepairedItem.Template);
if (!hasTemplate.Key)
{
return false;
@@ -664,7 +664,7 @@ public class RepairService(
).BuffSettings;
break;
default:
_logger.Error($"Unhandled buff type: {itemSkillType}");
logger.Error($"Unhandled buff type: {itemSkillType}");
break;
}
@@ -678,8 +678,8 @@ public class RepairService(
if (repairDetails.RepairPoints is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"repair-item_has_no_repair_points",
repairDetails.RepairedItem.Template
)
@@ -707,7 +707,7 @@ public class RepairService(
/// <returns>Skill name</returns>
protected SkillTypes? GetItemSkillType(TemplateItem itemTemplate)
{
var isArmorRelated = _itemHelper.IsOfBaseclasses(
var isArmorRelated = itemHelper.IsOfBaseclasses(
itemTemplate.Id,
[BaseClasses.ARMOR, BaseClasses.VEST, BaseClasses.HEADWEAR, BaseClasses.ARMOR_PLATE]
);
@@ -726,12 +726,12 @@ public class RepairService(
}
}
if (_itemHelper.IsOfBaseclass(itemTemplate.Id, BaseClasses.WEAPON))
if (itemHelper.IsOfBaseclass(itemTemplate.Id, BaseClasses.WEAPON))
{
return SkillTypes.WeaponTreatment;
}
if (_itemHelper.IsOfBaseclass(itemTemplate.Id, BaseClasses.KNIFE))
if (itemHelper.IsOfBaseclass(itemTemplate.Id, BaseClasses.KNIFE))
{
return SkillTypes.Melee;
}
@@ -16,14 +16,14 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class SeasonalEventService(
ISptLogger<SeasonalEventService> _logger,
TimeUtil _timeUtil,
DatabaseService _databaseService,
GiftService _giftService,
ServerLocalisationService _serverLocalisationService,
ProfileHelper _profileHelper,
ConfigServer _configServer,
RandomUtil _randomUtil
ISptLogger<SeasonalEventService> logger,
TimeUtil timeUtil,
DatabaseService databaseService,
GiftService giftService,
ServerLocalisationService serverLocalisationService,
ProfileHelper profileHelper,
ConfigServer configServer,
RandomUtil randomUtil
)
{
private bool _christmasEventActive;
@@ -86,18 +86,18 @@ public class SeasonalEventService(
ItemTpl.RANDOMLOOTCONTAINER_PUMPKIN_RAND_LOOT_CONTAINER,
];
protected readonly HttpConfig _httpConfig = _configServer.GetConfig<HttpConfig>();
protected readonly LocationConfig _locationConfig = _configServer.GetConfig<LocationConfig>();
protected readonly HttpConfig _httpConfig = configServer.GetConfig<HttpConfig>();
protected readonly LocationConfig _locationConfig = configServer.GetConfig<LocationConfig>();
protected readonly HashSet<string> _lootContainersToFilter =
[
"Backpack",
"Pockets",
"TacticalVest",
];
protected readonly QuestConfig _questConfig = _configServer.GetConfig<QuestConfig>();
protected readonly QuestConfig _questConfig = configServer.GetConfig<QuestConfig>();
protected readonly SeasonalEventConfig _seasonalEventConfig =
_configServer.GetConfig<SeasonalEventConfig>();
protected readonly WeatherConfig _weatherConfig = _configServer.GetConfig<WeatherConfig>();
configServer.GetConfig<SeasonalEventConfig>();
protected readonly WeatherConfig _weatherConfig = configServer.GetConfig<WeatherConfig>();
/// <summary>
/// Get an array of christmas items found in bots inventories as loot
@@ -243,7 +243,7 @@ public class SeasonalEventService(
/// <param name="questId">Quest to look up</param>
/// <param name="eventType">event type (Christmas/Halloween/None)</param>
/// <returns>true if related</returns>
public bool IsQuestRelatedToEvent(string questId, SeasonalEventType eventType)
public bool IsQuestRelatedToEvent(MongoId questId, SeasonalEventType eventType)
{
var eventQuestData = _questConfig.EventQuests.GetValueOrDefault(questId, null);
return eventQuestData?.Season == eventType;
@@ -256,7 +256,7 @@ public class SeasonalEventService(
{
if (_currentlyActiveEvents.Any())
{
var globalConfig = _databaseService.GetGlobals().Configuration;
var globalConfig = databaseService.GetGlobals().Configuration;
foreach (var activeEvent in _currentlyActiveEvents)
{
UpdateGlobalEvents(globalConfig, activeEvent);
@@ -271,11 +271,11 @@ public class SeasonalEventService(
/// <returns>True if event was successfully force enabled</returns>
public bool ForceSeasonalEvent(SeasonalEventType eventType)
{
var globalConfig = _databaseService.GetGlobals().Configuration;
var globalConfig = databaseService.GetGlobals().Configuration;
var seasonEvent = _seasonalEventConfig.Events.FirstOrDefault(e => e.Type == eventType);
if (seasonEvent is null)
{
_logger.Warning(
logger.Warning(
$"Unable to force event: {eventType} as it cannot be found in events config"
);
return false;
@@ -330,7 +330,7 @@ public class SeasonalEventService(
return _weatherConfig.OverrideSeason.Value;
}
var currentDate = _timeUtil.GetDateTimeNow();
var currentDate = timeUtil.GetDateTimeNow();
foreach (var seasonRange in _weatherConfig.SeasonDates)
{
if (
@@ -346,8 +346,8 @@ public class SeasonalEventService(
}
}
_logger.Warning(
_serverLocalisationService.GetText("season-no_matching_season_found_for_date")
logger.Warning(
serverLocalisationService.GetText("season-no_matching_season_found_for_date")
);
return Season.SUMMER;
@@ -367,8 +367,8 @@ public class SeasonalEventService(
{
if (botInventory.Equipment[equipmentSlotKey] is null)
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"seasonal-missing_equipment_slot_on_bot",
new { equipmentSlot = equipmentSlotKey, botRole }
)
@@ -396,8 +396,8 @@ public class SeasonalEventService(
if (prop is null)
{
_logger.Warning(
_serverLocalisationService.GetText(
logger.Warning(
serverLocalisationService.GetText(
"seasonal-missing_loot_container_slot_on_bot",
new { lootContainer = lootContainerKey, botRole }
)
@@ -416,9 +416,7 @@ public class SeasonalEventService(
/// <param name="event">Name of the event to enable. e.g. Christmas</param>
private void UpdateGlobalEvents(Config globalConfig, SeasonalEvent eventType)
{
_logger.Success(
_serverLocalisationService.GetText("season-event_is_active", eventType.Type)
);
logger.Success(serverLocalisationService.GetText("season-event_is_active", eventType.Type));
_christmasEventActive = false;
_halloweenEventActive = false;
@@ -584,7 +582,7 @@ public class SeasonalEventService(
foreach (var botTypeKey in adjustments)
{
var botDb = _databaseService.GetBots().Types[botTypeKey.Key];
var botDb = databaseService.GetBots().Types[botTypeKey.Key];
if (botDb is null)
{
continue;
@@ -616,7 +614,7 @@ public class SeasonalEventService(
Dictionary<string, List<AdditionalHostilitySettings>> hostilitySettings
)
{
var locations = _databaseService.GetLocations().GetDictionary();
var locations = databaseService.GetLocations().GetDictionary();
var ignoreList = _locationConfig.NonMaps;
foreach (var (locationName, locationBase) in locations)
@@ -710,13 +708,13 @@ public class SeasonalEventService(
{
foreach (var locationId in locationIds)
{
var location = _databaseService.GetLocation(locationId);
var location = databaseService.GetLocation(locationId);
location.Base.AccessKeys = [];
location.Base.AccessKeysPvE = [];
}
}
public void GivePlayerSeasonalGifts(string sessionId)
public void GivePlayerSeasonalGifts(MongoId sessionId)
{
if (_currentlyActiveEvents is null)
{
@@ -743,7 +741,7 @@ public class SeasonalEventService(
/// </summary>
protected void AdjustZryachiyMeleeChance()
{
var zryachiyKvP = _databaseService
var zryachiyKvP = databaseService
.GetBots()
.Types.FirstOrDefault(x =>
string.Equals(x.Key, "bosszryachiy", StringComparison.OrdinalIgnoreCase)
@@ -769,19 +767,19 @@ public class SeasonalEventService(
/// </summary>
protected void EnableHalloweenSummonEvent()
{
_databaseService.GetGlobals().Configuration.EventSettings.EventActive = true;
databaseService.GetGlobals().Configuration.EventSettings.EventActive = true;
}
protected void ConfigureZombies(ZombieSettings zombieSettings)
{
// Flag zombies as being enabled
var botData = _databaseService.GetBots();
var botData = databaseService.GetBots();
if (!botData.Core.TryAdd("ACTIVE_HALLOWEEN_ZOMBIES_EVENT", true))
{
botData.Core["ACTIVE_HALLOWEEN_ZOMBIES_EVENT"] = true;
}
var globals = _databaseService.GetGlobals();
var globals = databaseService.GetGlobals();
var infectionHalloween = globals.Configuration.SeasonActivity.InfectionHalloween;
infectionHalloween.DisplayUIEnabled = true;
infectionHalloween.Enabled = true;
@@ -794,10 +792,10 @@ public class SeasonalEventService(
infectionPercentage == 100
? infectionPercentage
: Convert.ToDouble(
_randomUtil.GetInt(Convert.ToInt32(infectionPercentage), 100)
randomUtil.GetInt(Convert.ToInt32(infectionPercentage), 100)
);
if (_logger.IsLogEnabled(LogLevel.Debug))
_logger.Debug(
if (logger.IsLogEnabled(LogLevel.Debug))
logger.Debug(
$"Percent infected from map {locationId} is {randomInfectionPercentage}"
);
// Infection rates sometimes apply to multiple maps, e.g. Factory day/night or Sandbox/sandbox_high
@@ -806,7 +804,7 @@ public class SeasonalEventService(
var mappedLocations = GetLocationFromInfectedLocation(locationId);
foreach (var locationKey in mappedLocations)
{
_databaseService
databaseService
.GetLocation(locationKey)
.Base.Events.Halloween2024.InfectionPercentage = randomInfectionPercentage;
}
@@ -817,12 +815,12 @@ public class SeasonalEventService(
foreach (var locationId in zombieSettings.DisableBosses)
{
_databaseService.GetLocation(locationId).Base.BossLocationSpawn = [];
databaseService.GetLocation(locationId).Base.BossLocationSpawn = [];
}
foreach (var locationId in zombieSettings.DisableWaves)
{
_databaseService.GetLocation(locationId).Base.Waves = [];
databaseService.GetLocation(locationId).Base.Waves = [];
}
var locationsWithActiveInfection = GetLocationsWithZombies(
@@ -875,17 +873,17 @@ public class SeasonalEventService(
if (wavesToAddByMap is null)
{
_logger.Warning($"Unable to add: {eventType} waves, eventWaves is missing");
logger.Warning($"Unable to add: {eventType} waves, eventWaves is missing");
return;
}
var locations = _databaseService.GetLocations().GetAllPropsAsDict();
var locations = databaseService.GetLocations().GetAllPropsAsDict();
foreach (var map in wavesToAddByMap)
{
var wavesToAdd = wavesToAddByMap[map.Key];
if (wavesToAdd is null)
{
_logger.Warning($"Unable to add: {eventType} wave to: {map.Key}");
logger.Warning($"Unable to add: {eventType} wave to: {map.Key}");
continue;
}
@@ -908,11 +906,11 @@ public class SeasonalEventService(
)
)
{
_logger.Warning($"Unable to add: {eventType} bosses, eventBossSpawns is missing");
logger.Warning($"Unable to add: {eventType} bosses, eventBossSpawns is missing");
return;
}
var locations = _databaseService.GetLocations().GetAllPropsAsDict();
var locations = databaseService.GetLocations().GetAllPropsAsDict();
foreach (var (locationKey, bossesToAdd) in botsToAddPerMap)
{
if (bossesToAdd.Count == 0)
@@ -925,7 +923,7 @@ public class SeasonalEventService(
continue;
}
var locationName = _databaseService.GetLocations().GetMappedKey(locationKey);
var locationName = databaseService.GetLocations().GetMappedKey(locationKey);
var mapBosses = ((Location)locations[locationName]).Base.BossLocationSpawn;
foreach (var boss in bossesToAdd)
{
@@ -988,7 +986,7 @@ public class SeasonalEventService(
/// </summary>
protected void AddLootItemsToGifterDropItemsList()
{
var gifterBot = _databaseService.GetBots().Types["gifter"];
var gifterBot = databaseService.GetBots().Types["gifter"];
var itemsCSV = string.Join(",", gifterBot.BotInventory.Items.Backpack.Keys);
string[] difficulties = ["easy", "normal", "hard", "impossible"];
@@ -1008,9 +1006,7 @@ public class SeasonalEventService(
var botGearChanges = GetEventBotGear(eventType);
if (botGearChanges is null)
{
_logger.Warning(
_serverLocalisationService.GetText("gameevent-no_gear_data", eventType)
);
logger.Warning(serverLocalisationService.GetText("gameevent-no_gear_data", eventType));
return;
}
@@ -1018,11 +1014,11 @@ public class SeasonalEventService(
// Iterate over bots with changes to apply
foreach (var botKvP in botGearChanges)
{
var botToUpdate = _databaseService.GetBots().Types[botKvP.Key.ToLowerInvariant()];
var botToUpdate = databaseService.GetBots().Types[botKvP.Key.ToLowerInvariant()];
if (botToUpdate is null)
{
_logger.Warning(
_serverLocalisationService.GetText("gameevent-bot_not_found", botKvP)
logger.Warning(
serverLocalisationService.GetText("gameevent-bot_not_found", botKvP)
);
continue;
}
@@ -1058,9 +1054,7 @@ public class SeasonalEventService(
var botLootChanges = GetEventBotLoot(eventType);
if (botLootChanges is null)
{
_logger.Warning(
_serverLocalisationService.GetText("gameevent-no_gear_data", eventType)
);
logger.Warning(serverLocalisationService.GetText("gameevent-no_gear_data", eventType));
return;
}
@@ -1068,11 +1062,11 @@ public class SeasonalEventService(
// Iterate over bots with changes to apply
foreach (var botKvpP in botLootChanges)
{
var botToUpdate = _databaseService.GetBots().Types[botKvpP.Key.ToLowerInvariant()];
var botToUpdate = databaseService.GetBots().Types[botKvpP.Key.ToLowerInvariant()];
if (botToUpdate is null)
{
_logger.Warning(
_serverLocalisationService.GetText("gameevent-bot_not_found", botKvpP)
logger.Warning(
serverLocalisationService.GetText("gameevent-bot_not_found", botKvpP)
);
continue;
}
@@ -1097,14 +1091,14 @@ public class SeasonalEventService(
/// </summary>
protected void AddPumpkinsToScavBackpacks()
{
_databaseService.GetBots().Types["assault"].BotInventory.Items.Backpack[
databaseService.GetBots().Types["assault"].BotInventory.Items.Backpack[
ItemTpl.RANDOMLOOTCONTAINER_PUMPKIN_RAND_LOOT_CONTAINER
] = 400;
}
protected void RenameBitcoin()
{
if (_databaseService.GetLocales().Global.TryGetValue("en", out var lazyLoad))
if (databaseService.GetLocales().Global.TryGetValue("en", out var lazyLoad))
{
lazyLoad.AddTransformer(localeData =>
{
@@ -1121,7 +1115,7 @@ public class SeasonalEventService(
/// </summary>
protected void EnableDancingTree()
{
var maps = _databaseService.GetLocations();
var maps = databaseService.GetLocations();
HashSet<string> mapsToCheck = ["hideout", "base", "privatearea"];
foreach (var mapKvP in maps.GetDictionary())
{
@@ -1146,17 +1140,17 @@ public class SeasonalEventService(
protected void AddGifterBotToMaps()
{
var gifterSettings = _seasonalEventConfig.GifterSettings;
var maps = _databaseService.GetLocations().GetDictionary();
var maps = databaseService.GetLocations().GetDictionary();
foreach (var gifterMapSettings in gifterSettings)
{
if (
!maps.TryGetValue(
_databaseService.GetLocations().GetMappedKey(gifterMapSettings.Map),
databaseService.GetLocations().GetMappedKey(gifterMapSettings.Map),
out var mapData
)
)
{
_logger.Warning($"AddGifterBotToMaps() Map not found {gifterMapSettings.Map}");
logger.Warning($"AddGifterBotToMaps() Map not found {gifterMapSettings.Map}");
continue;
}
@@ -1252,18 +1246,18 @@ public class SeasonalEventService(
/// </summary>
/// <param name="playerId">Player to send gift to</param>
/// <param name="giftKey">Key of gift to give</param>
protected void GiveGift(string playerId, string giftKey)
protected void GiveGift(MongoId playerId, string giftKey)
{
var giftData = _giftService.GetGiftById(giftKey);
var giftData = giftService.GetGiftById(giftKey);
if (
!_profileHelper.PlayerHasReceivedMaxNumberOfGift(
!profileHelper.PlayerHasReceivedMaxNumberOfGift(
playerId,
giftKey,
giftData.MaxToSendPlayer ?? 5
)
)
{
_giftService.SendGiftToPlayer(playerId, giftKey);
giftService.SendGiftToPlayer(playerId, giftKey);
}
}
@@ -1,5 +1,6 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Profile;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Models.Utils;
@@ -10,15 +11,15 @@ namespace SPTarkov.Server.Core.Services;
[Injectable(InjectionType.Singleton)]
public class TraderPurchasePersisterService(
ISptLogger<TraderPurchasePersisterService> _logger,
RandomUtil _randomUtil,
TimeUtil _timeUtil,
ProfileHelper _profileHelper,
ServerLocalisationService _serverLocalisationService,
ConfigServer _configServer
ISptLogger<TraderPurchasePersisterService> logger,
RandomUtil randomUtil,
TimeUtil timeUtil,
ProfileHelper profileHelper,
ServerLocalisationService serverLocalisationService,
ConfigServer configServer
)
{
protected readonly TraderConfig _traderConfig = _configServer.GetConfig<TraderConfig>();
protected readonly TraderConfig _traderConfig = configServer.GetConfig<TraderConfig>();
/// <summary>
/// Get the purchases made from a trader for this profile before the last trader reset
@@ -27,11 +28,11 @@ public class TraderPurchasePersisterService(
/// <param name="traderId"> Trader to loop up purchases for </param>
/// <returns> Dictionary of assort id and count purchased </returns>
public Dictionary<string, TraderPurchaseData>? GetProfileTraderPurchases(
string sessionId,
string traderId
MongoId sessionId,
MongoId traderId
)
{
var profile = _profileHelper.GetFullProfile(sessionId);
var profile = profileHelper.GetFullProfile(sessionId);
return profile?.TraderPurchases?.GetValueOrDefault(traderId);
}
@@ -44,12 +45,12 @@ public class TraderPurchasePersisterService(
/// <param name="assortId"> ID of assort to get data for </param>
/// <returns> TraderPurchaseData </returns>
public TraderPurchaseData? GetProfileTraderPurchase(
string sessionId,
string traderId,
MongoId sessionId,
MongoId traderId,
string assortId
)
{
var profile = _profileHelper.GetFullProfile(sessionId);
var profile = profileHelper.GetFullProfile(sessionId);
if (profile.TraderPurchases is null)
{
@@ -75,10 +76,10 @@ public class TraderPurchasePersisterService(
/// Remove all trader purchase records from all profiles that exist
/// </summary>
/// <param name="traderId"> Traders ID </param>
public void ResetTraderPurchasesStoredInProfile(string traderId)
public void ResetTraderPurchasesStoredInProfile(MongoId traderId)
{
// Reset all profiles purchase dictionaries now a trader update has occured;
var profiles = _profileHelper.GetProfiles();
var profiles = profileHelper.GetProfiles();
foreach (var profile in profiles)
{
// Skip if no purchases
@@ -96,16 +97,16 @@ public class TraderPurchasePersisterService(
profile.Value.TraderPurchases[traderId] = new Dictionary<string, TraderPurchaseData>();
}
_logger.Debug($"Reset trader: {traderId} assort buy limits");
logger.Debug($"Reset trader: {traderId} assort buy limits");
}
/// <summary>
/// Iterate over all server profiles and remove specific trader purchase data that has passed the trader refresh time
/// </summary>
/// <param name="traderId"> Trader ID </param>
public void RemoveStalePurchasesFromProfiles(string traderId)
public void RemoveStalePurchasesFromProfiles(MongoId traderId)
{
var profiles = _profileHelper.GetProfiles();
var profiles = profileHelper.GetProfiles();
foreach (var profileKvP in profiles)
{
var profile = profileKvP.Value;
@@ -124,8 +125,8 @@ public class TraderPurchasePersisterService(
);
if (traderUpdateDetails is null)
{
_logger.Error(
_serverLocalisationService.GetText(
logger.Error(
serverLocalisationService.GetText(
"trader-unable_to_delete_stale_purchases",
new { profileId = profile.ProfileInfo.ProfileId, traderId }
)
@@ -137,14 +138,14 @@ public class TraderPurchasePersisterService(
var purchaseDetails = purchaseKvP.Value;
var resetTimeForItem =
purchaseDetails.PurchaseTimestamp
+ _randomUtil.GetDouble(
+ randomUtil.GetDouble(
traderUpdateDetails.Seconds.Min,
traderUpdateDetails.Seconds.Max
);
if (resetTimeForItem < _timeUtil.GetTimeStamp())
if (resetTimeForItem < timeUtil.GetTimeStamp())
{
// Item was purchased far enough in past a trader refresh would have occured, remove purchase record from profile
_logger.Debug(
logger.Debug(
$"Removed trader: {traderId} purchase: {purchaseKvP} from profile: {profile.ProfileInfo.ProfileId}"
);
@@ -1,6 +1,7 @@
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.DI;
using SPTarkov.Server.Core.Models;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Utils;
@@ -17,7 +18,7 @@ public class TraderStore(
ISptLogger<TraderStore> logger
) : IOnLoad
{
private readonly Dictionary<string, ITrader> _traders = new();
private readonly Dictionary<MongoId, ITrader> _traders = new();
public Task OnLoad()
{
@@ -71,7 +72,7 @@ public class TraderStore(
/// </summary>
/// <param name="traderId"></param>
/// <returns></returns>
public ITrader? GetTraderById(string traderId)
public ITrader? GetTraderById(MongoId traderId)
{
return _traders.GetValueOrDefault(traderId);
}