Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace SPTarkov.Server.Core.Exceptions.Helpers;

public class InRaidHelperException : Exception
{
public InRaidHelperException(string message)
: base(message) { }

public InRaidHelperException(string message, Exception innerException)
: base(message, innerException) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace SPTarkov.Server.Core.Exceptions.Helpers;

public class InventoryHelperException : Exception
{
public InventoryHelperException(string message)
: base(message) { }

public InventoryHelperException(string message, Exception innerException)
: base(message, innerException) { }
}
10 changes: 5 additions & 5 deletions Libraries/SPTarkov.Server.Core/Helpers/HttpServerHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ namespace SPTarkov.Server.Core.Helpers;
[Injectable(InjectionType.Singleton)]
public class HttpServerHelper(ConfigServer configServer)
{
protected readonly HttpConfig _httpConfig = configServer.GetConfig<HttpConfig>();
protected readonly HttpConfig HttpConfig = configServer.GetConfig<HttpConfig>();

protected readonly FrozenDictionary<string, string> mime = new Dictionary<string, string>
protected readonly FrozenDictionary<string, string> Mime = new Dictionary<string, string>
{
{ "css", "text/css" },
{ "bin", "application/octet-stream" },
Expand All @@ -26,7 +26,7 @@ public class HttpServerHelper(ConfigServer configServer)

public string? GetMimeText(string key)
{
return mime.GetValueOrDefault(key);
return Mime.GetValueOrDefault(key);
}

/// <summary>
Expand All @@ -35,7 +35,7 @@ public class HttpServerHelper(ConfigServer configServer)
/// <returns>URI</returns>
public string BuildUrl()
{
return $"{_httpConfig.BackendIp}:{_httpConfig.BackendPort}";
return $"{HttpConfig.BackendIp}:{HttpConfig.BackendPort}";
}

/// <summary>
Expand All @@ -58,7 +58,7 @@ public string GetWebsocketUrl()

public void SendTextJson(HttpResponse resp, object output)
{
resp.Headers.Append("Content-Type", mime["json"]);
resp.Headers.Append("Content-Type", Mime["json"]);
resp.StatusCode = 200;
// TODO: figure this one out
// resp.writeHead(200, "OK", {
Expand Down
109 changes: 73 additions & 36 deletions Libraries/SPTarkov.Server.Core/Helpers/InRaidHelper.cs
Original file line number Diff line number Diff line change
@@ -1,57 +1,86 @@
using System.Collections.Frozen;
using SPTarkov.Common.Extensions;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Exceptions.Helpers;
using SPTarkov.Server.Core.Extensions;
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.Spt.Config;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
using SPTarkov.Server.Core.Utils.Cloners;

namespace SPTarkov.Server.Core.Helpers;

[Injectable]
public class InRaidHelper(InventoryHelper inventoryHelper, ConfigServer configServer, ICloner cloner, DatabaseService databaseService)
public class InRaidHelper(
ISptLogger<InRaidHelper> logger,
InventoryHelper inventoryHelper,
ConfigServer configServer,
ICloner cloner,
DatabaseService databaseService
)
{
protected static readonly FrozenSet<string> _pocketSlots = ["pocket1", "pocket2", "pocket3", "pocket4"];
protected readonly InRaidConfig _inRaidConfig = configServer.GetConfig<InRaidConfig>();
protected readonly LostOnDeathConfig _lostOnDeathConfig = configServer.GetConfig<LostOnDeathConfig>();

/// <summary>
/// Deprecated. Reset the skill points earned in a raid to 0, ready for next raid.
/// </summary>
/// <param name="profile">Profile to update</param>
protected void ResetSkillPointsEarnedDuringRaid(PmcData profile)
{
foreach (var skill in profile.Skills.Common)
{
skill.PointsEarnedDuringSession = 0.0;
}
}
protected static readonly FrozenSet<string> PocketSlots = ["pocket1", "pocket2", "pocket3", "pocket4"];
protected readonly InRaidConfig InRaidConfig = configServer.GetConfig<InRaidConfig>();
protected readonly LostOnDeathConfig LostOnDeathConfig = configServer.GetConfig<LostOnDeathConfig>();

/// <summary>
/// Update a player's inventory post-raid.
/// Remove equipped items from pre-raid.
/// Add new items found in raid to profile.
/// Store insurance items in profile.
/// </summary>
/// <param name="sessionID">Session id</param>
/// <param name="sessionId">Session id</param>
/// <param name="serverProfile">Profile to update</param>
/// <param name="postRaidProfile">Profile returned by client after a raid</param>
/// <param name="isSurvived">Indicates if the player survived the raid</param>
/// <param name="isTransfer">Indicates if it is a transfer operation</param>
public void SetInventory(MongoId sessionID, PmcData serverProfile, PmcData postRaidProfile, bool isSurvived, bool isTransfer)
public void SetInventory(MongoId sessionId, PmcData serverProfile, PmcData postRaidProfile, bool isSurvived, bool isTransfer)
{
if (serverProfile.InsuredItems is null)
{
throw new InRaidHelperException("Insured items are null when trying to set inventory post raid");
}

if (
serverProfile.Inventory?.Items is null
|| serverProfile.Inventory.QuestRaidItems is null
|| serverProfile.Inventory?.Equipment is null
)
{
throw new InRaidHelperException(
"Server profile inventory items, quest raid items, or equipment are null when trying to set inventory post raid"
);
}

if (
postRaidProfile.Inventory?.Items is null
|| postRaidProfile.Inventory.QuestRaidItems is null
|| postRaidProfile.Inventory.Equipment is null
)
{
throw new InRaidHelperException(
"Post raid profile inventory items, quest raid items, or equipment are null when trying to set inventory post raid"
);
}

// Store insurance (as removeItem() removes insured items)
var insured = cloner.Clone(serverProfile.InsuredItems);
if (insured is null)
{
const string message = "Cloned insured items are null when trying to set inventory post raid";
logger.Error(message);
throw new InRaidHelperException(message);
}

// Remove equipment and loot items stored on player from server profile in preparation for data from client being added
inventoryHelper.RemoveItem(serverProfile, serverProfile.Inventory.Equipment.Value, sessionID);
inventoryHelper.RemoveItem(serverProfile, serverProfile.Inventory.Equipment.Value, sessionId);

// Remove quest items stored on player from server profile in preparation for data from client being added
inventoryHelper.RemoveItem(serverProfile, serverProfile.Inventory.QuestRaidItems.Value, sessionID);
inventoryHelper.RemoveItem(serverProfile, serverProfile.Inventory.QuestRaidItems.Value, sessionId);

// Get all items that have a parent of `serverProfile.Inventory.equipment` (All items player had on them at end of raid)
var postRaidInventoryItems = postRaidProfile.Inventory.Items.GetItemWithChildren(postRaidProfile.Inventory.Equipment.Value);
Expand All @@ -61,7 +90,7 @@ public void SetInventory(MongoId sessionID, PmcData serverProfile, PmcData postR

// Handle Removing of FIR status if player did not survive + not transferring
// Do after above filtering code to reduce work done
if (!isSurvived && !isTransfer && !_inRaidConfig.AlwaysKeepFoundInRaidOnRaidEnd)
if (!isSurvived && !isTransfer && !InRaidConfig.AlwaysKeepFoundInRaidOnRaidEnd)
{
RemoveFiRStatusFromItems(postRaidProfile.Inventory.Items);
}
Expand All @@ -85,12 +114,10 @@ protected void RemoveFiRStatusFromItems(IEnumerable<Item> items)
var dbItems = databaseService.GetItems();

var itemsToRemovePropertyFrom = items.Where(item =>
{
// Has upd object + upd.SpawnedInSession property + not a quest item
return (item.Upd?.SpawnedInSession ?? false)
&& !(dbItems[item.Template].Properties.QuestItem ?? false)
&& !(_inRaidConfig.KeepFiRSecureContainerOnDeath && item.ItemIsInsideContainer("SecuredContainer", items));
});
(item.Upd?.SpawnedInSession ?? false)
&& !(dbItems[item.Template].Properties?.QuestItem ?? false)
&& !(InRaidConfig.KeepFiRSecureContainerOnDeath && item.ItemIsInsideContainer("SecuredContainer", items))
);

foreach (var item in itemsToRemovePropertyFrom)
{
Expand Down Expand Up @@ -131,6 +158,11 @@ protected void AddItemsToInventory(IEnumerable<Item> itemsToAdd, List<Item> serv
/// <param name="sessionId">Player/Session id</param>
public void DeleteInventory(PmcData pmcData, MongoId sessionId)
{
if (pmcData.Inventory is null)
{
throw new InRaidHelperException("Pmc profile inventory is null when trying to delete inventory");
}

// Get inventory items to remove from players profile
var itemsToDeleteFromProfile = GetInventoryItemsLostOnDeath(pmcData).ToList();

Expand All @@ -141,7 +173,7 @@ public void DeleteInventory(PmcData pmcData, MongoId sessionId)
}

// Remove contents of fast panel
pmcData.Inventory.FastPanel = new();
pmcData.Inventory.FastPanel = new Dictionary<string, MongoId>();
}

/// <summary>
Expand All @@ -151,9 +183,9 @@ public void DeleteInventory(PmcData pmcData, MongoId sessionId)
/// <returns>List of items lost on death</returns>
protected IEnumerable<Item> GetInventoryItemsLostOnDeath(PmcData pmcProfile)
{
var inventoryItems = pmcProfile.Inventory.Items ?? [];
var equipmentRootId = pmcProfile?.Inventory?.Equipment;
var questRaidItemContainerId = pmcProfile?.Inventory?.QuestRaidItems;
var inventoryItems = pmcProfile.Inventory?.Items ?? [];
var equipmentRootId = pmcProfile.Inventory?.Equipment;
var questRaidItemContainerId = pmcProfile.Inventory?.QuestRaidItems;

return inventoryItems.Where(item =>
{
Expand All @@ -171,7 +203,7 @@ protected IEnumerable<Item> GetInventoryItemsLostOnDeath(PmcData pmcProfile)

// Pocket items are lost on death
// Ensure we don't pick up pocket items from mannequins
if (item.SlotId.StartsWith("pocket") && pmcProfile.DoesItemHaveRootId(item, pmcProfile.Inventory.Equipment.Value))
if ((item.SlotId?.StartsWith("pocket") ?? false) && pmcProfile.DoesItemHaveRootId(item, pmcProfile.Inventory!.Equipment!.Value))
{
return true;
}
Expand All @@ -188,6 +220,11 @@ protected IEnumerable<Item> GetInventoryItemsLostOnDeath(PmcData pmcProfile)
/// <returns>true if item is kept after death</returns>
protected bool IsItemKeptAfterDeath(PmcData pmcData, Item itemToCheck)
{
if (pmcData.Inventory is null)
{
throw new InRaidHelperException("Pmc profile inventory is null when checking if an item is kept on death");
}

// Base inventory items are always kept
if (itemToCheck.ParentId is null)
{
Expand All @@ -198,7 +235,7 @@ protected bool IsItemKeptAfterDeath(PmcData pmcData, Item itemToCheck)
if (itemToCheck.ParentId == pmcData.Inventory.Equipment)
{
// Check slot id against config, true = delete, false = keep, undefined = delete
var discard = _lostOnDeathConfig.Equipment.GetByJsonProp<bool>(itemToCheck.SlotId);
var discard = LostOnDeathConfig.Equipment.GetByJsonProp<bool>(itemToCheck.SlotId);
if (discard)
// Lost on death
{
Expand All @@ -209,19 +246,19 @@ protected bool IsItemKeptAfterDeath(PmcData pmcData, Item itemToCheck)
}

// Should we keep items in pockets on death
if (!_lostOnDeathConfig.Equipment.PocketItems && _pocketSlots.Contains(itemToCheck.SlotId))
if (!LostOnDeathConfig.Equipment.PocketItems && PocketSlots.Contains(itemToCheck.SlotId ?? string.Empty))
{
return true;
}

// Is quest item + quest item not lost on death
if (itemToCheck.ParentId == pmcData.Inventory.QuestRaidItems && !_lostOnDeathConfig.QuestItems)
if (itemToCheck.ParentId == pmcData.Inventory.QuestRaidItems && !LostOnDeathConfig.QuestItems)
{
return true;
}

// special slots are always kept after death
if ((itemToCheck.SlotId?.Contains("SpecialSlot") ?? false) && _lostOnDeathConfig.SpecialSlotItems)
if ((itemToCheck.SlotId?.Contains("SpecialSlot") ?? false) && LostOnDeathConfig.SpecialSlotItems)
{
return true;
}
Expand Down
Loading