+1
-1
@@ -1,3 +1,3 @@
|
||||
[lfs]
|
||||
url = https://lfs.sp-tarkov.com/sp-tarkov/server
|
||||
url = https://lfs.sp-tarkov.com/sp-tarkov/server-csharp
|
||||
locksverify = false
|
||||
|
||||
@@ -2666,9 +2666,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -5557,9 +5557,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -8817,9 +8817,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -12175,9 +12175,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -15893,9 +15893,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -19808,9 +19808,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -23577,9 +23577,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -27471,9 +27471,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -31977,9 +31977,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -36700,9 +36700,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -37693,9 +37693,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -38680,9 +38680,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -41828,9 +41828,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -44961,9 +44961,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -48389,9 +48389,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -51812,9 +51812,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -52795,9 +52795,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
@@ -53785,9 +53785,9 @@
|
||||
},
|
||||
"WishList": [],
|
||||
"karmaValue": 0.2,
|
||||
"_id": "__REPLACEME__",
|
||||
"_id": "000000000000000000000000",
|
||||
"aid": "__REPLACEME__",
|
||||
"savage": "__REPLACEME__"
|
||||
"savage": "000000000000000000000000"
|
||||
},
|
||||
"dialogues": {},
|
||||
"equipmentBuilds": {},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"templates": {
|
||||
"Elimination": {
|
||||
"_id": null,
|
||||
"_id": "68690637c1394a820efc27ca",
|
||||
"traderId": "5935c25fb3acc3127c3d8cd9",
|
||||
"location": null,
|
||||
"image": "/files/quest/icon/616d993bc8c5ad2ab30ff6ba.jpg",
|
||||
|
||||
@@ -30,7 +30,7 @@ public class BotCallbacks(BotController _botController, HttpResponseUtil _httpRe
|
||||
public ValueTask<string> GetBotDifficulty(string url, EmptyRequestData _, string sessionID)
|
||||
{
|
||||
var splitUrl = url.Split('/');
|
||||
var type = splitUrl[^2].ToLower();
|
||||
var type = splitUrl[^2].ToLowerInvariant();
|
||||
var difficulty = splitUrl[^1];
|
||||
if (difficulty == "core")
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.DI;
|
||||
using SPTarkov.Server.Core.Extensions;
|
||||
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;
|
||||
@@ -17,8 +18,7 @@ public class BtrDeliveryCallbacks(
|
||||
BtrDeliveryService _btrDeliveryService,
|
||||
TimeUtil _timeUtil,
|
||||
ConfigServer _configServer,
|
||||
SaveServer _saveServer,
|
||||
HashUtil _hashUtil
|
||||
SaveServer _saveServer
|
||||
) : IOnUpdate
|
||||
{
|
||||
private readonly BtrDeliveryConfig _btrDeliveryConfig =
|
||||
@@ -110,7 +110,7 @@ public class BtrDeliveryCallbacks(
|
||||
foreach (var package in packagesToBeDelivered)
|
||||
{
|
||||
// Create a new root parent ID for the message we'll be sending the player
|
||||
var rootItemParentId = _hashUtil.Generate();
|
||||
var rootItemParentId = new MongoId();
|
||||
|
||||
// Update the delivery items to have the new root parent ID for root/orphaned items
|
||||
package.Items = package.Items.AdoptOrphanedItems(rootItemParentId);
|
||||
|
||||
@@ -10,7 +10,6 @@ namespace SPTarkov.Server.Core.Callbacks;
|
||||
|
||||
[Injectable(TypePriority = OnUpdateOrder.DialogueCallbacks)]
|
||||
public class DialogueCallbacks(
|
||||
HashUtil _hashUtil,
|
||||
TimeUtil _timeUtil,
|
||||
HttpResponseUtil _httpResponseUtil,
|
||||
DialogueController _dialogueController
|
||||
@@ -47,7 +46,7 @@ public class DialogueCallbacks(
|
||||
{
|
||||
new()
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Id = new Models.Common.MongoId(),
|
||||
RegistrationId = 20,
|
||||
DateTime = _timeUtil.GetTimeStamp(),
|
||||
IsDeveloper = true,
|
||||
@@ -200,15 +199,13 @@ public class DialogueCallbacks(
|
||||
/// Handle client/mail/msg/send
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual ValueTask<string> SendMessage(
|
||||
public virtual async ValueTask<string> SendMessage(
|
||||
string url,
|
||||
SendMessageRequest request,
|
||||
string sessionID
|
||||
)
|
||||
{
|
||||
return new ValueTask<string>(
|
||||
_httpResponseUtil.GetBody(_dialogueController.SendMessage(sessionID, request))
|
||||
);
|
||||
return _httpResponseUtil.GetBody(await _dialogueController.SendMessage(sessionID, request));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,7 +6,6 @@ using SPTarkov.Server.Core.Models.Eft.Insurance;
|
||||
using SPTarkov.Server.Core.Models.Eft.ItemEvent;
|
||||
using SPTarkov.Server.Core.Models.Spt.Config;
|
||||
using SPTarkov.Server.Core.Servers;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
using SPTarkov.Server.Core.Utils;
|
||||
|
||||
namespace SPTarkov.Server.Core.Callbacks;
|
||||
@@ -14,7 +13,6 @@ namespace SPTarkov.Server.Core.Callbacks;
|
||||
[Injectable(TypePriority = OnUpdateOrder.InsuranceCallbacks)]
|
||||
public class InsuranceCallbacks(
|
||||
InsuranceController _insuranceController,
|
||||
InsuranceService _insuranceService,
|
||||
HttpResponseUtil _httpResponseUtil,
|
||||
ConfigServer _configServer
|
||||
) : IOnUpdate
|
||||
|
||||
@@ -17,7 +17,7 @@ public class SaveCallbacks(
|
||||
|
||||
public async Task OnLoad()
|
||||
{
|
||||
_backupService.StartBackupSystem();
|
||||
await _backupService.StartBackupSystem();
|
||||
await _saveServer.LoadAsync();
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ public class BotController(
|
||||
bool ignoreRaidSettings = false
|
||||
)
|
||||
{
|
||||
var difficulty = diffLevel.ToLower();
|
||||
var difficulty = diffLevel.ToLowerInvariant();
|
||||
|
||||
var raidConfig = _profileActivityService
|
||||
.GetProfileActivityRaidData(sessionId)
|
||||
@@ -107,7 +107,7 @@ public class BotController(
|
||||
// Check value chosen in pre-raid difficulty dropdown
|
||||
// If value is not 'asonline', change requested difficulty to be what was chosen in dropdown
|
||||
var botDifficultyDropDownValue =
|
||||
raidConfig?.WavesSettings?.BotDifficulty?.ToString().ToLower() ?? "asonline";
|
||||
raidConfig?.WavesSettings?.BotDifficulty?.ToString().ToLowerInvariant() ?? "asonline";
|
||||
if (botDifficultyDropDownValue != "asonline")
|
||||
{
|
||||
difficulty = _botDifficultyHelper.ConvertBotDifficultyDropdownToBotDifficulty(
|
||||
@@ -138,8 +138,8 @@ public class BotController(
|
||||
{
|
||||
// If bot is usec/bear, swap to different name
|
||||
var botTypeLower = botType.IsPmc()
|
||||
? (botType.GetPmcSideByRole() ?? "usec").ToLower()
|
||||
: botType.ToString().ToLower();
|
||||
? (botType.GetPmcSideByRole() ?? "usec").ToLowerInvariant()
|
||||
: botType.ToString().ToLowerInvariant();
|
||||
|
||||
// Get details from db
|
||||
if (!botTypesDb.TryGetValue(botTypeLower, out var botDetails))
|
||||
@@ -165,7 +165,7 @@ public class BotController(
|
||||
continue;
|
||||
}
|
||||
|
||||
var botNameKey = botType.ToString().ToLower();
|
||||
var botNameKey = botType.ToString().ToLowerInvariant();
|
||||
foreach (var (difficultyName, _) in botDetails.BotDifficulty)
|
||||
{
|
||||
// Bot doesn't exist in result, add
|
||||
@@ -378,7 +378,7 @@ public class BotController(
|
||||
protected MinMax<int> GetPmcLevelRangeForMap(string? location)
|
||||
{
|
||||
return _pmcConfig.LocationSpecificPmcLevelOverride!.GetValueOrDefault(
|
||||
location?.ToLower() ?? "",
|
||||
location?.ToLowerInvariant() ?? "",
|
||||
null
|
||||
);
|
||||
}
|
||||
@@ -430,7 +430,7 @@ public class BotController(
|
||||
/// <returns>bot cap for map</returns>
|
||||
public int GetBotCap(string location)
|
||||
{
|
||||
if (!_botConfig.MaxBotCap.TryGetValue(location.ToLower(), out var maxCap))
|
||||
if (!_botConfig.MaxBotCap.TryGetValue(location.ToLowerInvariant(), out var maxCap))
|
||||
{
|
||||
return _botConfig.MaxBotCap["default"];
|
||||
}
|
||||
@@ -440,7 +440,7 @@ public class BotController(
|
||||
_logger.Warning(
|
||||
_serverLocalisationService.GetText(
|
||||
"bot-no_bot_cap_found_for_location",
|
||||
location.ToLower()
|
||||
location.ToLowerInvariant()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -538,15 +538,22 @@ public class DialogueController(
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public virtual string SendMessage(string sessionId, SendMessageRequest request)
|
||||
public virtual async ValueTask<string> SendMessage(string sessionId, SendMessageRequest request)
|
||||
{
|
||||
_mailSendService.SendPlayerMessageToNpc(sessionId, request.DialogId!, request.Text!);
|
||||
|
||||
return (
|
||||
_dialogueChatBots
|
||||
.FirstOrDefault(cb => cb.GetChatBot().Id == request.DialogId)
|
||||
?.HandleMessage(sessionId, request) ?? request.DialogId
|
||||
) ?? string.Empty;
|
||||
var chatBot = _dialogueChatBots.FirstOrDefault(cb =>
|
||||
cb.GetChatBot().Id == request.DialogId
|
||||
);
|
||||
|
||||
if (chatBot is not null)
|
||||
{
|
||||
return await chatBot.HandleMessage(sessionId, request);
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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.Game;
|
||||
using SPTarkov.Server.Core.Models.Eft.Profile;
|
||||
@@ -82,12 +83,12 @@ public class GameController(
|
||||
return;
|
||||
}
|
||||
|
||||
fullProfile.CharacterData!.PmcData!.WishList ??= new DictionaryOrList<string, int>(
|
||||
new Dictionary<string, int>(),
|
||||
fullProfile.CharacterData!.PmcData!.WishList ??= new DictionaryOrList<MongoId, int>(
|
||||
new Dictionary<MongoId, int>(),
|
||||
[]
|
||||
);
|
||||
fullProfile.CharacterData.ScavData!.WishList ??= new DictionaryOrList<string, int>(
|
||||
new Dictionary<string, int>(),
|
||||
fullProfile.CharacterData.ScavData!.WishList ??= new DictionaryOrList<MongoId, int>(
|
||||
new Dictionary<MongoId, int>(),
|
||||
[]
|
||||
);
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ public class HealthController(
|
||||
InventoryHelper _inventoryHelper,
|
||||
ServerLocalisationService _serverLocalisationService,
|
||||
HttpResponseUtil _httpResponseUtil,
|
||||
HealthHelper _healthHelper,
|
||||
ICloner _cloner
|
||||
)
|
||||
{
|
||||
|
||||
@@ -908,7 +908,7 @@ public class HideoutController(
|
||||
var output = _eventOutputHolder.GetOutput(sessionID);
|
||||
var hideoutDb = _databaseService.GetHideout();
|
||||
|
||||
if (request.RecipeId == HideoutHelper.BitcoinFarm)
|
||||
if (request.RecipeId == HideoutHelper.BitcoinProductionId)
|
||||
{
|
||||
// Ensure server and client are in-sync when player presses 'get items' on farm
|
||||
_hideoutHelper.UpdatePlayerHideout(sessionID);
|
||||
@@ -1771,7 +1771,7 @@ public class HideoutController(
|
||||
foreach (var poseKvP in request.Poses)
|
||||
{
|
||||
// Nullguard
|
||||
pmcData.Hideout.MannequinPoses ??= new Dictionary<string, string>();
|
||||
pmcData.Hideout.MannequinPoses ??= new Dictionary<string, MongoId>();
|
||||
pmcData.Hideout.MannequinPoses[poseKvP.Key] = poseKvP.Value;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace SPTarkov.Server.Core.Controllers;
|
||||
public class InsuranceController(
|
||||
ISptLogger<InsuranceController> _logger,
|
||||
RandomUtil _randomUtil,
|
||||
MathUtil _mathUtil,
|
||||
HashUtil _hashUtil,
|
||||
TimeUtil _timeUtil,
|
||||
EventOutputHolder _eventOutputHolder,
|
||||
ItemHelper _itemHelper,
|
||||
@@ -122,7 +120,7 @@ public class InsuranceController(
|
||||
foreach (var insured in insuranceDetails)
|
||||
{
|
||||
// Create a new root parent ID for the message we'll be sending the player
|
||||
var rootItemParentId = _hashUtil.Generate();
|
||||
var rootItemParentId = new MongoId();
|
||||
|
||||
// Update the insured items to have the new root parent ID for root/orphaned items
|
||||
insured.Items = insured.Items.AdoptOrphanedItems(rootItemParentId);
|
||||
@@ -494,11 +492,11 @@ public class InsuranceController(
|
||||
);
|
||||
|
||||
// Create prob array and add all attachments with rouble price as the weight
|
||||
var attachmentsProbabilityArray = new ProbabilityObjectArray<string, double?>(_cloner);
|
||||
var attachmentsProbabilityArray = new ProbabilityObjectArray<MongoId, double?>(_cloner);
|
||||
foreach (var (itemTpl, price) in weightedAttachmentByPrice)
|
||||
{
|
||||
attachmentsProbabilityArray.Add(
|
||||
new ProbabilityObject<string, double?>(itemTpl, price, null)
|
||||
new ProbabilityObject<MongoId, double?>(itemTpl, price, null)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -527,9 +525,9 @@ public class InsuranceController(
|
||||
/// <param name="attachments"></param>
|
||||
/// <param name="attachmentPrices"></param>
|
||||
protected void LogAttachmentsBeingRemoved(
|
||||
List<string> attachmentIdsToRemove,
|
||||
List<MongoId> attachmentIdsToRemove,
|
||||
List<Item> attachments,
|
||||
Dictionary<string, double> attachmentPrices
|
||||
Dictionary<MongoId, double> attachmentPrices
|
||||
)
|
||||
{
|
||||
var index = 1;
|
||||
@@ -552,9 +550,9 @@ public class InsuranceController(
|
||||
/// </summary>
|
||||
/// <param name="attachments">Item attachments</param>
|
||||
/// <returns></returns>
|
||||
protected Dictionary<string, double> WeightAttachmentsByPrice(List<Item> attachments)
|
||||
protected Dictionary<MongoId, double> WeightAttachmentsByPrice(List<Item> attachments)
|
||||
{
|
||||
var result = new Dictionary<string, double>();
|
||||
var result = new Dictionary<MongoId, double>();
|
||||
|
||||
// Get a dictionary of item tpls + their rouble price
|
||||
foreach (var attachment in attachments)
|
||||
@@ -581,7 +579,7 @@ public class InsuranceController(
|
||||
/// <param name="traderId">Trader the attachment is insured against</param>
|
||||
/// <returns>Attachment count to remove</returns>
|
||||
protected double GetAttachmentCountToRemove(
|
||||
Dictionary<string, double> weightedAttachmentByPrice,
|
||||
Dictionary<MongoId, double> weightedAttachmentByPrice,
|
||||
string? traderId
|
||||
)
|
||||
{
|
||||
@@ -872,7 +870,7 @@ public class InsuranceController(
|
||||
{
|
||||
var softInsertSlots = pmcData.Inventory.Items.Where(item =>
|
||||
item.ParentId == itemWithSoftInserts.Id
|
||||
&& _itemHelper.IsSoftInsertId(item.SlotId.ToLower())
|
||||
&& _itemHelper.IsSoftInsertId(item.SlotId.ToLowerInvariant())
|
||||
);
|
||||
|
||||
foreach (var softInsertSlot in softInsertSlots)
|
||||
|
||||
@@ -19,15 +19,11 @@ namespace SPTarkov.Server.Core.Controllers;
|
||||
[Injectable]
|
||||
public class InventoryController(
|
||||
ISptLogger<InventoryController> _logger,
|
||||
HashUtil _hashUtil,
|
||||
RandomUtil _randomUtil,
|
||||
HttpResponseUtil _httpResponseUtil,
|
||||
PresetHelper _presetHelper,
|
||||
InventoryHelper _inventoryHelper,
|
||||
QuestHelper _questHelper,
|
||||
HideoutHelper _hideoutHelper,
|
||||
ProfileHelper _profileHelper,
|
||||
PaymentHelper _paymentHelper,
|
||||
TraderHelper _traderHelper,
|
||||
ItemHelper _itemHelper,
|
||||
DatabaseService _databaseService,
|
||||
@@ -165,7 +161,7 @@ public class InventoryController(
|
||||
if (itemToAdjust is null)
|
||||
{
|
||||
_logger.Error(
|
||||
$"Unable find item: {request.Item} to: {request.State} on player {sessionId}to: "
|
||||
$"Unable find item: {request.Item.Value.ToString()} to: {request.State} on player: {sessionId} to: "
|
||||
);
|
||||
|
||||
return;
|
||||
@@ -603,7 +599,7 @@ public class InventoryController(
|
||||
/// <param name="request"></param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns>Item tpl</returns>
|
||||
protected string? GetExaminedItemTpl(InventoryExamineRequestData request, string? sessionId)
|
||||
protected MongoId? GetExaminedItemTpl(InventoryExamineRequestData request, string? sessionId)
|
||||
{
|
||||
if (_presetHelper.IsPreset(request.Item))
|
||||
{
|
||||
@@ -1074,7 +1070,9 @@ public class InventoryController(
|
||||
}
|
||||
|
||||
destinationItem.Upd.StackObjectsCount += sourceItem.Upd.StackObjectsCount; // Add source stackcount to destination
|
||||
output.ProfileChanges[sessionID].Items.DeletedItems.Add(new Item { Id = sourceItem.Id }); // Inform client source item being deleted
|
||||
output
|
||||
.ProfileChanges[sessionID]
|
||||
.Items.DeletedItems.Add(new DeletedItem { Id = sourceItem.Id }); // Inform client source item being deleted
|
||||
|
||||
var indexOfItemToRemove = inventoryItems.From.FindIndex(x => x.Id == sourceItem.Id);
|
||||
if (indexOfItemToRemove == -1)
|
||||
|
||||
@@ -168,7 +168,7 @@ public class LauncherController(
|
||||
var timeStampStr = Convert.ToString(timeStamp, 16).PadLeft(8, '0');
|
||||
var counterStr = Convert.ToString(counter, 16).PadLeft(16, '0');
|
||||
|
||||
return timeStampStr.ToLower() + counterStr.ToLower();
|
||||
return timeStampStr.ToLowerInvariant() + counterStr.ToLowerInvariant();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -196,7 +196,7 @@ public class LauncherV2Controller(
|
||||
var timeStampStr = Convert.ToString(timeStamp, 16).PadLeft(8, '0');
|
||||
var counterStr = Convert.ToString(counter, 16).PadLeft(16, '0');
|
||||
|
||||
return timeStampStr.ToLower() + counterStr.ToLower();
|
||||
return timeStampStr.ToLowerInvariant() + counterStr.ToLowerInvariant();
|
||||
}
|
||||
|
||||
protected string? GetSessionId(LoginRequestData info)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
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.Location;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
using SPTarkov.Server.Core.Utils.Cloners;
|
||||
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
|
||||
|
||||
namespace SPTarkov.Server.Core.Controllers;
|
||||
@@ -13,8 +13,7 @@ namespace SPTarkov.Server.Core.Controllers;
|
||||
public class LocationController(
|
||||
ISptLogger<LocationController> _logger,
|
||||
DatabaseService _databaseService,
|
||||
AirdropService _airdropService,
|
||||
ICloner _cloner
|
||||
AirdropService _airdropService
|
||||
)
|
||||
{
|
||||
/// <summary>
|
||||
@@ -29,7 +28,7 @@ public class LocationController(
|
||||
var maps = locationsFromDb.GetDictionary();
|
||||
|
||||
// keyed by _id location property
|
||||
var locationResult = new Dictionary<string, LocationBase>();
|
||||
var locationResult = new Dictionary<MongoId, LocationBase>();
|
||||
|
||||
foreach (var (locationId, location) in maps)
|
||||
{
|
||||
@@ -47,7 +46,7 @@ public class LocationController(
|
||||
// Clear out loot array
|
||||
mapBase.Loot = [];
|
||||
// Add map base data to dictionary
|
||||
locationResult.Add(mapBase.IdField!, mapBase);
|
||||
locationResult.Add(mapBase.IdField, mapBase);
|
||||
}
|
||||
|
||||
return new LocationsGenerateAllResponse
|
||||
|
||||
@@ -5,7 +5,6 @@ using SPTarkov.Server.Core.Models.Spt.Config;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
using SPTarkov.Server.Core.Servers;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
using SPTarkov.Server.Core.Utils.Cloners;
|
||||
using static SPTarkov.Server.Core.Services.MatchLocationService;
|
||||
|
||||
namespace SPTarkov.Server.Core.Controllers;
|
||||
@@ -17,8 +16,7 @@ public class MatchController(
|
||||
ConfigServer _configServer,
|
||||
LocationLifecycleService _locationLifecycleService,
|
||||
ProfileActivityService _profileActivityService,
|
||||
WeatherHelper _weatherHelper,
|
||||
ICloner _cloner
|
||||
WeatherHelper _weatherHelper
|
||||
)
|
||||
{
|
||||
protected readonly MatchConfig _matchConfig = _configServer.GetConfig<MatchConfig>();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.Helpers;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
using SPTarkov.Server.Core.Models.Spt.Presets;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
@@ -19,7 +20,7 @@ public class PresetController(
|
||||
public void Initialize()
|
||||
{
|
||||
var presets = _databaseService.GetGlobals().ItemPresets;
|
||||
var result = new Dictionary<string, PresetCacheDetails>();
|
||||
var result = new Dictionary<MongoId, PresetCacheDetails>();
|
||||
foreach (var (presetId, preset) in presets)
|
||||
{
|
||||
if (presetId != preset.Id)
|
||||
@@ -33,9 +34,9 @@ public class PresetController(
|
||||
|
||||
// Get root items tpl
|
||||
var tpl = preset.Items.FirstOrDefault()?.Template;
|
||||
result.TryAdd(tpl, new PresetCacheDetails { PresetIds = [] });
|
||||
result.TryAdd(tpl.Value, new PresetCacheDetails { PresetIds = [] });
|
||||
|
||||
result.TryGetValue(tpl, out var details);
|
||||
result.TryGetValue(tpl.Value, out var details);
|
||||
details.PresetIds.Add(presetId);
|
||||
if (preset.Encyclopedia is not null)
|
||||
{
|
||||
|
||||
@@ -9,33 +9,17 @@ using SPTarkov.Server.Core.Models.Eft.Profile;
|
||||
using SPTarkov.Server.Core.Models.Enums;
|
||||
using SPTarkov.Server.Core.Models.Spt.Launcher;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
using SPTarkov.Server.Core.Routers;
|
||||
using SPTarkov.Server.Core.Servers;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
using SPTarkov.Server.Core.Utils;
|
||||
using SPTarkov.Server.Core.Utils.Cloners;
|
||||
|
||||
namespace SPTarkov.Server.Core.Controllers;
|
||||
|
||||
[Injectable]
|
||||
public class ProfileController(
|
||||
ISptLogger<ProfileController> _logger,
|
||||
HashUtil _hashUtil,
|
||||
ICloner _cloner,
|
||||
TimeUtil _timeUtil,
|
||||
SaveServer _saveServer,
|
||||
DatabaseService _databaseService,
|
||||
ItemHelper _itemHelper,
|
||||
ProfileFixerService _profileFixerService,
|
||||
ServerLocalisationService _serverLocalisationService,
|
||||
CreateProfileService _createProfileService,
|
||||
SeasonalEventService _seasonalEventService,
|
||||
PlayerScavGenerator _playerScavGenerator,
|
||||
EventOutputHolder _eventOutputHolder,
|
||||
TraderHelper _traderHelper,
|
||||
DialogueHelper _dialogueHelper,
|
||||
QuestHelper _questHelper,
|
||||
QuestRewardHelper _questRewardHelper,
|
||||
ProfileHelper _profileHelper
|
||||
)
|
||||
{
|
||||
@@ -187,7 +171,7 @@ public class ProfileController(
|
||||
var pmcData = _profileHelper.GetPmcProfile(sessionId);
|
||||
|
||||
pmcData.Info.Nickname = request.Nickname;
|
||||
pmcData.Info.LowerNickname = request.Nickname.ToLower();
|
||||
pmcData.Info.LowerNickname = request.Nickname.ToLowerInvariant();
|
||||
}
|
||||
|
||||
return output;
|
||||
@@ -223,7 +207,10 @@ public class ProfileController(
|
||||
foreach (var profile in allProfiles)
|
||||
{
|
||||
var pmcProfile = profile?.CharacterData?.PmcData;
|
||||
if (!pmcProfile?.Info?.LowerNickname?.Contains(request.Nickname.ToLower()) ?? false)
|
||||
if (
|
||||
!pmcProfile?.Info?.LowerNickname?.Contains(request.Nickname.ToLowerInvariant())
|
||||
?? false
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ public class QuestController(
|
||||
TimeUtil _timeUtil,
|
||||
HttpResponseUtil _httpResponseUtil,
|
||||
EventOutputHolder _eventOutputHolder,
|
||||
ItemHelper _itemHelper,
|
||||
MailSendService _mailSendService,
|
||||
QuestHelper _questHelper,
|
||||
QuestRewardHelper _questRewardHelper,
|
||||
@@ -151,7 +150,7 @@ public class QuestController(
|
||||
{
|
||||
if (pmcData.TaskConditionCounters.TryGetValue(condition.Id, out _))
|
||||
{
|
||||
_logger.Error(
|
||||
_logger.Warning(
|
||||
$"Unable to add new task condition counter: {condition.ConditionType} for quest: {questId} to profile: {pmcData.SessionId} as it already exists"
|
||||
);
|
||||
}
|
||||
@@ -320,7 +319,7 @@ public class QuestController(
|
||||
// Important: don't tell the client to remove the attachments, it will handle it
|
||||
output
|
||||
.ProfileChanges[sessionID]
|
||||
.Items.DeletedItems.Add(new Item { Id = itemHandover.Id });
|
||||
.Items.DeletedItems.Add(new DeletedItem { Id = itemHandover.Id });
|
||||
|
||||
// Important: loop backward when removing items from the array we're looping on
|
||||
while (index-- > 0)
|
||||
|
||||
@@ -1326,12 +1326,12 @@ public class RagfairController
|
||||
/// Get prices for all items on flea
|
||||
/// </summary>
|
||||
/// <returns>Dictionary of tpl and item price</returns>
|
||||
public Dictionary<string, double> GetAllFleaPrices()
|
||||
public Dictionary<MongoId, double> GetAllFleaPrices()
|
||||
{
|
||||
return _ragfairPriceService.GetAllFleaPrices();
|
||||
}
|
||||
|
||||
public Dictionary<string, double> GetStaticPrices()
|
||||
public Dictionary<MongoId, double> GetStaticPrices()
|
||||
{
|
||||
return _ragfairPriceService.GetAllStaticPrices();
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ public class RepeatableQuestController(
|
||||
}
|
||||
|
||||
// Subtype name of quest - daily/weekly/scav
|
||||
var repeatableTypeLower = repeatablesOfTypeInProfile.Name.ToLower();
|
||||
var repeatableTypeLower = repeatablesOfTypeInProfile.Name.ToLowerInvariant();
|
||||
|
||||
// Save for later standing loss calculation
|
||||
var replacedQuestTraderId = questToReplace.TraderId;
|
||||
@@ -575,7 +575,7 @@ public class RepeatableQuestController(
|
||||
repeatableConfig,
|
||||
pmcData
|
||||
);
|
||||
var repeatableTypeLower = repeatableConfig.Name.ToLower();
|
||||
var repeatableTypeLower = repeatableConfig.Name.ToLowerInvariant();
|
||||
|
||||
var canAccessRepeatables = CanProfileAccessRepeatableQuests(repeatableConfig, pmcData);
|
||||
if (!canAccessRepeatables)
|
||||
|
||||
@@ -44,7 +44,7 @@ public class TraderController(
|
||||
var traders = databaseService.GetTraders();
|
||||
foreach (var (traderId, trader) in traders)
|
||||
{
|
||||
if (traderId == Traders.LIGHTHOUSEKEEPER || traderId == "ragfair")
|
||||
if (traderId == Traders.LIGHTHOUSEKEEPER)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.Generators;
|
||||
using SPTarkov.Server.Core.Helpers;
|
||||
using SPTarkov.Server.Core.Models.Eft.Weather;
|
||||
using SPTarkov.Server.Core.Models.Enums;
|
||||
using SPTarkov.Server.Core.Models.Spt.Config;
|
||||
@@ -17,7 +16,6 @@ public class WeatherController(
|
||||
WeatherGenerator _weatherGenerator,
|
||||
SeasonalEventService _seasonalEventService,
|
||||
RaidWeatherService _raidWeatherService,
|
||||
WeatherHelper _weatherHelper,
|
||||
ConfigServer _configServer
|
||||
)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
using SPTarkov.Server.Core.Models.Spt.Inventory;
|
||||
|
||||
namespace SPTarkov.Server.Core.Extensions
|
||||
{
|
||||
public static class ContainerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds a slot for an item in a given 2D container map
|
||||
/// </summary>
|
||||
/// <param name="container2D">List of container with positions filled/free</param>
|
||||
/// <param name="itemWidthX">Width of item</param>
|
||||
/// <param name="itemHeightY">Height of item</param>
|
||||
/// <returns>Location to place item in container</returns>
|
||||
public static FindSlotResult FindSlotForItem(
|
||||
this int[,] container2D,
|
||||
int? itemWidthX,
|
||||
int? itemHeightY
|
||||
)
|
||||
{
|
||||
// Assume not rotated
|
||||
var rotation = false;
|
||||
|
||||
// Find the min volume the item will take up
|
||||
var minVolume = (itemWidthX < itemHeightY ? itemWidthX : itemHeightY) - 1;
|
||||
var containerY = container2D.GetLength(0); // rows
|
||||
var containerX = container2D.GetLength(1); // columns
|
||||
var limitY = containerY - minVolume;
|
||||
var limitX = containerX - minVolume;
|
||||
|
||||
// Every x+y slot taken up in container, exit
|
||||
if (ContainerIsFull(container2D))
|
||||
{
|
||||
return new FindSlotResult(false);
|
||||
}
|
||||
|
||||
// Down = y, iterate over rows
|
||||
for (var row = 0; row < limitY; row++)
|
||||
{
|
||||
if (RowIsFull(container2D, row))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Left to right across columns, look for free position
|
||||
for (var column = 0; column < limitX; column++)
|
||||
{
|
||||
// Does item fit
|
||||
if (
|
||||
CanItemBePlacedInContainerAtPosition(
|
||||
container2D,
|
||||
row,
|
||||
column,
|
||||
itemWidthX.Value,
|
||||
itemHeightY.Value
|
||||
)
|
||||
)
|
||||
{
|
||||
// Success, found a spot it fits
|
||||
return new FindSlotResult(true, column, row, rotation);
|
||||
}
|
||||
|
||||
if (!ItemBiggerThan1X1(itemWidthX.Value, itemHeightY.Value))
|
||||
{
|
||||
// Doesn't fit AND rotating won't help
|
||||
continue;
|
||||
}
|
||||
|
||||
// Rotate item by swapping x and y item values
|
||||
if (
|
||||
CanItemBePlacedInContainerAtPosition(
|
||||
container2D,
|
||||
row,
|
||||
column,
|
||||
itemHeightY.Value, // Swapped
|
||||
itemWidthX.Value // Swapped
|
||||
)
|
||||
)
|
||||
{
|
||||
// Found a position for the item when rotated
|
||||
rotation = true;
|
||||
return new FindSlotResult(true, column, row, rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tried all possible positions, nothing big enough for item
|
||||
return new FindSlotResult(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a free slot for an item to be placed at
|
||||
/// </summary>
|
||||
/// <param name="container2D">Container to place item in</param>
|
||||
/// <param name="columnStartPositionX">Container y size</param>
|
||||
/// <param name="rowStartPositionY">Container x size</param>
|
||||
/// <param name="itemXWidth">Items width</param>
|
||||
/// <param name="itemYHeight">Items height</param>
|
||||
/// <param name="isRotated">is item rotated</param>
|
||||
public static void FillContainerMapWithItem(
|
||||
this int[,] container2D,
|
||||
int columnStartPositionX,
|
||||
int rowStartPositionY,
|
||||
int? itemXWidth,
|
||||
int? itemYHeight,
|
||||
bool isRotated
|
||||
)
|
||||
{
|
||||
var containerY = container2D.GetLength(0); // rows
|
||||
var containerX = container2D.GetLength(1); // columns
|
||||
|
||||
// Swap height/width if item needs to be rotated to fit
|
||||
var itemWidth = isRotated ? itemYHeight : itemXWidth;
|
||||
var itemHeight = isRotated ? itemXWidth : itemYHeight;
|
||||
|
||||
var itemRowEndPosition = rowStartPositionY + (itemHeight - 1);
|
||||
var itemColumnEndPosition = columnStartPositionX + (itemWidth - 1);
|
||||
|
||||
//Item is a 1x1, flag slot as taken and exit early
|
||||
if (itemXWidth == 1 && itemYHeight == 1)
|
||||
{
|
||||
container2D[rowStartPositionY, columnStartPositionX] = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop over rows and columns and flag each as taken by item
|
||||
for (var y = rowStartPositionY; y <= itemRowEndPosition; y++)
|
||||
{
|
||||
for (var x = columnStartPositionX; x <= itemColumnEndPosition; x++)
|
||||
{
|
||||
if (container2D[y, x] == 0)
|
||||
{
|
||||
// Flag slot as used
|
||||
container2D[y, x] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(
|
||||
$"Slot at: ({containerX}, {containerY}) is already filled. Cannot fit: {itemXWidth} by {itemYHeight} item"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the requested row full
|
||||
/// </summary>
|
||||
/// <param name="container2D">Container to check</param>
|
||||
/// <param name="rowIndex">Index of row to check</param>
|
||||
/// <returns>True = full</returns>
|
||||
private static bool RowIsFull(int[,] container2D, int rowIndex)
|
||||
{
|
||||
var rowFull = true;
|
||||
var containerColumnCount = container2D.GetLength(1); // Column
|
||||
for (var col = 0; col < containerColumnCount; col++)
|
||||
{
|
||||
if (container2D[rowIndex, col] == 0)
|
||||
{
|
||||
rowFull = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rowFull;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is every slot in container full
|
||||
/// </summary>
|
||||
/// <param name="container2D">Container to check</param>
|
||||
/// <returns>True = full</returns>
|
||||
private static bool ContainerIsFull(int[,] container2D)
|
||||
{
|
||||
var containerY = container2D.GetLength(0); // rows
|
||||
var containerX = container2D.GetLength(1); // columns
|
||||
var containerFull = true;
|
||||
for (var y = 0; y < containerY; y++)
|
||||
{
|
||||
for (var x = 0; x < containerX; x++)
|
||||
{
|
||||
if (container2D[y, x] == 0)
|
||||
{
|
||||
containerFull = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!containerFull)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return containerFull;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the item size values passed in bigger than 1x1
|
||||
/// </summary>
|
||||
/// <param name="itemWidth">Width of item</param>
|
||||
/// <param name="itemHeight">Height of item</param>
|
||||
/// <returns>True = bigger than 1x1</returns>
|
||||
private static bool ItemBiggerThan1X1(int itemWidth, int itemHeight)
|
||||
{
|
||||
return itemWidth + itemHeight > 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can an item of specified size be placed inside a 2d container at a specific position
|
||||
/// </summary>
|
||||
/// <param name="container">Container to find space in</param>
|
||||
/// <param name="itemStartVerticalPos">Starting y position for item</param>
|
||||
/// <param name="itemStartHorizontalPos">Starting x position for item</param>
|
||||
/// <param name="itemWidth">Items width (y)</param>
|
||||
/// <param name="itemHeight">Items height (x)</param>
|
||||
/// <returns>True - slot found</returns>
|
||||
public static bool CanItemBePlacedInContainerAtPosition(
|
||||
this int[,] container,
|
||||
int itemStartVerticalPos,
|
||||
int itemStartHorizontalPos,
|
||||
int itemWidth,
|
||||
int itemHeight
|
||||
)
|
||||
{
|
||||
var containerHeight = container.GetLength(0); // Rows
|
||||
var containerWidth = container.GetLength(1); // Columns
|
||||
|
||||
var itemEndColPosition = itemStartHorizontalPos + itemWidth - 1;
|
||||
var itemEndRowPosition = itemStartVerticalPos + itemHeight - 1;
|
||||
|
||||
// Check item isn't bigger than container when at position
|
||||
if (itemEndColPosition > containerWidth - 1 || itemEndRowPosition > containerHeight - 1)
|
||||
{
|
||||
// Item is bigger than container, will never fit
|
||||
return false;
|
||||
}
|
||||
|
||||
// Early exit if exact spot is taken
|
||||
if (container[itemStartVerticalPos, itemStartHorizontalPos] == 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Single slot item, do direct check
|
||||
if (itemWidth == 1 && itemHeight == 1)
|
||||
{
|
||||
return container[itemStartVerticalPos, itemStartHorizontalPos] == 0;
|
||||
}
|
||||
|
||||
for (var row = itemStartVerticalPos; row <= itemEndRowPosition; row++)
|
||||
{
|
||||
for (var column = itemStartHorizontalPos; column <= itemEndColPosition; column++)
|
||||
{
|
||||
if (container[row, column] == 1)
|
||||
{
|
||||
// Occupied by something
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true; // Slot is free
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,7 +158,7 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
}
|
||||
|
||||
// Dev profile additions
|
||||
if (fullProfile.ProfileInfo.Edition.ToLower().Contains("developer"))
|
||||
if (fullProfile.ProfileInfo.Edition.ToLowerInvariant().Contains("developer"))
|
||||
// CyberTark background
|
||||
{
|
||||
fullProfile.CustomisationUnlocks.Add(
|
||||
@@ -185,7 +185,7 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
|
||||
// Edge case - profile not created yet, fall back to what launcher has set
|
||||
var launcherEdition = fullProfile.ProfileInfo.Edition;
|
||||
switch (launcherEdition.ToLower())
|
||||
switch (launcherEdition.ToLowerInvariant())
|
||||
{
|
||||
case "edge of darkness":
|
||||
return GameEditions.EDGE_OF_DARKNESS;
|
||||
@@ -215,5 +215,16 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
fullProfile.SptData.ExtraRepeatableQuests[repeatableId] += rewardValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the provided session id for a developer account
|
||||
/// </summary>
|
||||
/// <param name="fullProfile">Profile to check</param>
|
||||
/// <returns>True if account is developer</returns>
|
||||
public static bool IsDeveloperAccount(this SptProfile fullProfile)
|
||||
{
|
||||
return fullProfile?.ProfileInfo?.Edition?.ToLowerInvariant().StartsWith("spt developer")
|
||||
?? false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
using System.Text.Json;
|
||||
using SPTarkov.Common.Extensions;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
using SPTarkov.Server.Core.Models.Eft.Common;
|
||||
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
|
||||
|
||||
@@ -284,16 +286,16 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
/// <returns>list of Item objects</returns>
|
||||
public static List<Item> FindAndReturnChildrenAsItems(
|
||||
this IEnumerable<Item> items,
|
||||
string baseItemId,
|
||||
MongoId baseItemId,
|
||||
bool modsOnly = false
|
||||
)
|
||||
{
|
||||
// Use dictionary to make key lookup faster, convert to list before being returned
|
||||
OrderedDictionary<string, Item> result = [];
|
||||
OrderedDictionary<MongoId, Item> result = [];
|
||||
foreach (var childItem in items)
|
||||
{
|
||||
// Include itself
|
||||
if (string.Equals(childItem.Id, baseItemId, StringComparison.Ordinal))
|
||||
if (childItem.Id == baseItemId)
|
||||
{
|
||||
// Root item MUST be at 0 index for things like flea market offers
|
||||
result.Insert(0, childItem.Id, childItem);
|
||||
@@ -309,7 +311,8 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
// Items parentId matches root item AND returned items doesn't contain current child
|
||||
if (
|
||||
!result.ContainsKey(childItem.Id)
|
||||
&& string.Equals(childItem.ParentId, baseItemId, StringComparison.Ordinal)
|
||||
&& childItem.ParentId != "hideout"
|
||||
&& childItem.ParentId == baseItemId
|
||||
)
|
||||
{
|
||||
foreach (var item in FindAndReturnChildrenAsItems(items, childItem.Id))
|
||||
@@ -342,5 +345,42 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
ExtensionData = item.ExtensionData,
|
||||
};
|
||||
}
|
||||
|
||||
public static ItemLocation? GetParsedLocation(this Item item)
|
||||
{
|
||||
if (item.Location is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (item.Location is JsonElement element)
|
||||
{
|
||||
// TODO: when is this true
|
||||
return element.ToObject<ItemLocation>();
|
||||
}
|
||||
|
||||
return (ItemLocation)item.Location;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of the item IDs (NOT tpls) inside a secure container
|
||||
/// </summary>
|
||||
/// <param name="items">Inventory items to look for secure container in</param>
|
||||
/// <returns>List of ids</returns>
|
||||
public static List<string> GetSecureContainerItems(this List<Item> items)
|
||||
{
|
||||
var secureContainer = items.First(x => x.SlotId == "SecuredContainer");
|
||||
|
||||
// No container found, drop out
|
||||
if (secureContainer is null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var itemsInSecureContainer = items.FindAndReturnChildrenByItems(secureContainer.Id);
|
||||
|
||||
// Return all items returned and exclude the secure container item itself
|
||||
return itemsInSecureContainer.Where(x => x != secureContainer.Id).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,6 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
{
|
||||
public static class ProductionExtensions
|
||||
{
|
||||
private static readonly HashSet<string> _idCheck =
|
||||
[
|
||||
HideoutHelper.BitcoinFarm,
|
||||
HideoutHelper.CultistCircleCraftId,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Has the craft completed
|
||||
/// Ignores bitcoin farm/cultist circle as they're continuous crafts
|
||||
@@ -20,7 +14,9 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
/// <returns>True when craft is complete</returns>
|
||||
public static bool IsCraftComplete(this Production craft)
|
||||
{
|
||||
return craft.Progress >= craft.ProductionTime && !_idCheck.Contains(craft.RecipeId);
|
||||
return craft.Progress >= craft.ProductionTime
|
||||
&& !craft.IsCraftOfType(HideoutAreas.BitcoinFarm)
|
||||
&& !craft.IsCraftOfType(HideoutAreas.CircleOfCultists);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -34,9 +30,9 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
switch (hideoutType)
|
||||
{
|
||||
case HideoutAreas.WaterCollector:
|
||||
return craft.RecipeId == HideoutHelper.WaterCollector;
|
||||
return craft.RecipeId == HideoutHelper.WaterCollectorId;
|
||||
case HideoutAreas.BitcoinFarm:
|
||||
return craft.RecipeId == HideoutHelper.BitcoinFarm;
|
||||
return craft.RecipeId == HideoutHelper.BitcoinProductionId;
|
||||
case HideoutAreas.ScavCase:
|
||||
return craft.SptIsScavCase ?? false;
|
||||
case HideoutAreas.CircleOfCultists:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SPTarkov.Server.Core.Models.Eft.Common;
|
||||
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.Enums;
|
||||
|
||||
@@ -125,7 +126,7 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
return pmcData.IsParentInStash(itemToCheck.Id);
|
||||
}
|
||||
|
||||
public static bool IsParentInStash(this PmcData pmcData, string itemId)
|
||||
public static bool IsParentInStash(this PmcData pmcData, MongoId itemId)
|
||||
{
|
||||
// Item not found / has no parent
|
||||
var item = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == itemId);
|
||||
@@ -200,5 +201,45 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
|
||||
return pmcData.Info.Level;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does the provided item have a root item with the provided id
|
||||
/// </summary>
|
||||
/// <param name="pmcData">Profile with items</param>
|
||||
/// <param name="item">Item to check</param>
|
||||
/// <param name="rootId">Root item id to check for</param>
|
||||
/// <returns>True when item has rootId, false when not</returns>
|
||||
public static bool DoesItemHaveRootId(this PmcData pmcData, Item item, string rootId)
|
||||
{
|
||||
var currentItem = item;
|
||||
while (currentItem is not null)
|
||||
{
|
||||
// If we've found the equipment root ID, return true
|
||||
if (currentItem.Id == rootId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise get the parent item
|
||||
currentItem = pmcData.Inventory.Items.FirstOrDefault(item =>
|
||||
item.Id == currentItem.ParentId
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get status of a quest in player profile by its id
|
||||
/// </summary>
|
||||
/// <param name="pmcData">Profile to search</param>
|
||||
/// <param name="questId">Quest id to look up</param>
|
||||
/// <returns>QuestStatus enum</returns>
|
||||
public static QuestStatusEnum GetQuestStatus(this PmcData pmcData, string questId)
|
||||
{
|
||||
var quest = pmcData.Quests?.FirstOrDefault(q => q.QId == questId);
|
||||
|
||||
return quest?.Status ?? QuestStatusEnum.Locked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.Text;
|
||||
|
||||
namespace SPTarkov.Server.Core.Extensions
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string Encode(this string value, EncodeType encode)
|
||||
{
|
||||
return encode switch
|
||||
{
|
||||
EncodeType.BASE64 => Convert.ToBase64String(Encoding.Default.GetBytes(value)),
|
||||
EncodeType.HEX => Convert.ToHexString(Encoding.Default.GetBytes(value)),
|
||||
EncodeType.ASCII => Encoding.ASCII.GetString(Encoding.Default.GetBytes(value)),
|
||||
EncodeType.UTF8 => Encoding.UTF8.GetString(Encoding.Default.GetBytes(value)),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(encode), encode, null),
|
||||
};
|
||||
}
|
||||
|
||||
public static string Decode(this string value, EncodeType encode)
|
||||
{
|
||||
return encode switch
|
||||
{
|
||||
EncodeType.BASE64 => Encoding.UTF8.GetString(Convert.FromBase64String(value)),
|
||||
EncodeType.HEX => Encoding.UTF8.GetString(Convert.FromHexString(value)),
|
||||
EncodeType.ASCII => Encoding.ASCII.GetString(Encoding.Default.GetBytes(value)),
|
||||
EncodeType.UTF8 => Encoding.UTF8.GetString(Encoding.Default.GetBytes(value)),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(encode), encode, null),
|
||||
};
|
||||
}
|
||||
|
||||
public enum EncodeType
|
||||
{
|
||||
BASE64,
|
||||
HEX,
|
||||
ASCII,
|
||||
UTF8,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,5 +48,20 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
{
|
||||
return weaponTemplate.Properties.DefMagType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the default plate an armor has in its db item
|
||||
/// </summary>
|
||||
/// <param name="armorItem">Item to look up default plate</param>
|
||||
/// <param name="modSlot">front/back</param>
|
||||
/// <returns>Tpl of plate</returns>
|
||||
public static string? GetDefaultPlateTpl(this TemplateItem armorItem, string modSlot)
|
||||
{
|
||||
var relatedItemDbModSlot = armorItem.Properties.Slots?.FirstOrDefault(slot =>
|
||||
string.Equals(slot.Name, modSlot, StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
|
||||
return relatedItemDbModSlot?.Props?.Filters?.FirstOrDefault()?.Plate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
|
||||
|
||||
namespace SPTarkov.Server.Core.Extensions
|
||||
{
|
||||
@@ -14,7 +15,7 @@ namespace SPTarkov.Server.Core.Extensions
|
||||
/// <returns>Modified assort</returns>
|
||||
public static TraderAssort RemoveItemFromAssort(
|
||||
this TraderAssort assort,
|
||||
string itemId,
|
||||
MongoId itemId,
|
||||
bool isFlea = false
|
||||
)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Frozen;
|
||||
using System.Globalization;
|
||||
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;
|
||||
@@ -83,6 +84,17 @@ public class BotEquipmentModGenerator(
|
||||
"cartridges",
|
||||
];
|
||||
|
||||
const string modRecieverKey = "mod_reciever";
|
||||
const string modMount001Key = "mod_mount_001";
|
||||
const string modGasBlockKey = "mod_gas_block";
|
||||
const string modPistolGrip = "mod_pistol_grip";
|
||||
const string modStockKey = "mod_stock";
|
||||
const string modBarrelKey = "mod_barrel";
|
||||
const string modHandguardKey = "mod_handguard";
|
||||
const string modMountKey = "mod_mount";
|
||||
const string modScopeKey = "mod_scope";
|
||||
const string modScope000Key = "mod_scope_000";
|
||||
|
||||
protected readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
|
||||
/// <summary>
|
||||
@@ -118,7 +130,7 @@ public class BotEquipmentModGenerator(
|
||||
foreach (var (modSlotName, modPool) in compatibleModsPool ?? [])
|
||||
{
|
||||
// Get the templates slot object from db
|
||||
var itemSlotTemplate = GetModItemSlotFromDb(modSlotName, parentTemplate);
|
||||
var itemSlotTemplate = GetModItemSlotFromDbTemplate(modSlotName, parentTemplate);
|
||||
if (itemSlotTemplate is null)
|
||||
{
|
||||
_logger.Error(
|
||||
@@ -174,12 +186,12 @@ public class BotEquipmentModGenerator(
|
||||
// Slot can hold armor plates + we are filtering possible items by bot level, handle
|
||||
if (
|
||||
settings.BotEquipmentConfig.FilterPlatesByLevel.GetValueOrDefault(false)
|
||||
&& _itemHelper.IsRemovablePlateSlot(modSlotName.ToLower())
|
||||
&& _itemHelper.IsRemovablePlateSlot(modSlotName.ToLowerInvariant())
|
||||
)
|
||||
{
|
||||
var plateSlotFilteringOutcome = FilterPlateModsForSlotByLevel(
|
||||
settings,
|
||||
modSlotName.ToLower(),
|
||||
modSlotName.ToLowerInvariant(),
|
||||
compatibleModsPool.GetValueOrDefault(modSlotName),
|
||||
parentTemplate
|
||||
);
|
||||
@@ -206,7 +218,7 @@ public class BotEquipmentModGenerator(
|
||||
}
|
||||
|
||||
// Choose random mod from pool and check its compatibility
|
||||
string? modTpl = null;
|
||||
MongoId? modTpl = null;
|
||||
var found = false;
|
||||
var exhaustableModPool = CreateExhaustableArray(modPoolToChooseFrom);
|
||||
while (exhaustableModPool.HasValues())
|
||||
@@ -215,7 +227,7 @@ public class BotEquipmentModGenerator(
|
||||
if (
|
||||
modTpl is not null
|
||||
&& !_botGeneratorHelper
|
||||
.IsItemIncompatibleWithCurrentItems(equipment, modTpl, modSlotName)
|
||||
.IsItemIncompatibleWithCurrentItems(equipment, modTpl.Value, modSlotName)
|
||||
.Incompatible.GetValueOrDefault(false)
|
||||
)
|
||||
{
|
||||
@@ -243,7 +255,7 @@ public class BotEquipmentModGenerator(
|
||||
}
|
||||
|
||||
// Get chosen mods db template and check it fits into slot
|
||||
var modTemplate = _itemHelper.GetItem(modTpl);
|
||||
var modTemplate = _itemHelper.GetItem(modTpl.Value);
|
||||
if (
|
||||
!IsModValidForSlot(
|
||||
modTemplate,
|
||||
@@ -406,7 +418,7 @@ public class BotEquipmentModGenerator(
|
||||
);
|
||||
}
|
||||
|
||||
var defaultPlate = GetDefaultPlateTpl(armorItem, modSlot);
|
||||
var defaultPlate = armorItem.GetDefaultPlateTpl(modSlot);
|
||||
if (defaultPlate is not null)
|
||||
{
|
||||
// Return Default Plates cause couldn't get lowest level available from original selection
|
||||
@@ -474,21 +486,6 @@ public class BotEquipmentModGenerator(
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the default plate an armor has in its db item
|
||||
/// </summary>
|
||||
/// <param name="armorItem">Item to look up default plate</param>
|
||||
/// <param name="modSlot">front/back</param>
|
||||
/// <returns>Tpl of plate</returns>
|
||||
protected string? GetDefaultPlateTpl(TemplateItem armorItem, string modSlot)
|
||||
{
|
||||
var relatedItemDbModSlot = armorItem.Properties.Slots?.FirstOrDefault(slot =>
|
||||
string.Equals(slot.Name, modSlot, StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
|
||||
return relatedItemDbModSlot?.Props?.Filters.FirstOrDefault()?.Plate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the matching armor slot from the default preset matching passed in armor tpl
|
||||
/// </summary>
|
||||
@@ -555,7 +552,7 @@ public class BotEquipmentModGenerator(
|
||||
foreach (var modSlot in sortedModKeys)
|
||||
{
|
||||
// Check weapon has slot for mod to fit in
|
||||
var modsParentSlot = GetModItemSlotFromDb(modSlot, request.ParentTemplate);
|
||||
var modsParentSlot = GetModItemSlotFromDbTemplate(modSlot, request.ParentTemplate);
|
||||
if (modsParentSlot is null)
|
||||
{
|
||||
_logger.Error(
|
||||
@@ -634,12 +631,12 @@ public class BotEquipmentModGenerator(
|
||||
continue;
|
||||
}
|
||||
|
||||
var modToAddTemplate = modToAdd.Value;
|
||||
var modToAddTemplate = modToAdd.Value.Value;
|
||||
// Skip adding mod to weapon if type limit reached
|
||||
if (
|
||||
_botWeaponModLimitService.WeaponModHasReachedLimit(
|
||||
request.BotData.EquipmentRole,
|
||||
modToAddTemplate.Value,
|
||||
modToAddTemplate,
|
||||
request.ModLimits,
|
||||
request.ParentTemplate,
|
||||
request.Weapon
|
||||
@@ -650,7 +647,7 @@ public class BotEquipmentModGenerator(
|
||||
}
|
||||
|
||||
// If item is a mount for scopes, set scope chance to 100%, this helps fix empty mounts appearing on weapons
|
||||
if (ModSlotCanHoldScope(modSlot, modToAddTemplate.Value.Parent))
|
||||
if (ModSlotCanHoldScope(modSlot, modToAddTemplate.Parent))
|
||||
{
|
||||
// mod_mount was picked to be added to weapon, force scope chance to ensure its filled
|
||||
List<string> scopeSlots =
|
||||
@@ -669,7 +666,7 @@ public class BotEquipmentModGenerator(
|
||||
{
|
||||
AddCompatibleModsForProvidedMod(
|
||||
"mod_scope",
|
||||
modToAddTemplate.Value,
|
||||
modToAddTemplate,
|
||||
request.ModPool,
|
||||
botEquipBlacklist
|
||||
);
|
||||
@@ -677,7 +674,7 @@ public class BotEquipmentModGenerator(
|
||||
}
|
||||
|
||||
// If picked item is muzzle adapter that can hold a child, adjust spawn chance
|
||||
if (ModSlotCanHoldMuzzleDevices(modSlot, modToAddTemplate.Value.Parent))
|
||||
if (ModSlotCanHoldMuzzleDevices(modSlot, modToAddTemplate.Parent))
|
||||
{
|
||||
List<string> muzzleSlots = ["mod_muzzle", "mod_muzzle_000", "mod_muzzle_001"];
|
||||
// Make chance of muzzle devices 95%, nearly certain but not guaranteed
|
||||
@@ -685,7 +682,7 @@ public class BotEquipmentModGenerator(
|
||||
}
|
||||
|
||||
// If front/rear sight are to be added, set opposite to 100% chance
|
||||
if (ModIsFrontOrRearSight(modSlot, modToAddTemplate.Value.Id))
|
||||
if (ModIsFrontOrRearSight(modSlot, modToAddTemplate.Id))
|
||||
{
|
||||
request.ModSpawnChances["mod_sight_front"] = 100;
|
||||
request.ModSpawnChances["mod_sight_rear"] = 100;
|
||||
@@ -695,7 +692,7 @@ public class BotEquipmentModGenerator(
|
||||
// Force spawn chance to be 100% to ensure it gets added
|
||||
if (
|
||||
modSlot == "mod_handguard"
|
||||
&& modToAddTemplate.Value.Properties.Slots.Any(slot => slot.Name == "mod_handguard")
|
||||
&& modToAddTemplate.Properties.Slots.Any(slot => slot.Name == "mod_handguard")
|
||||
&& !request.Weapon.Any(item => item.SlotId == "mod_launcher")
|
||||
)
|
||||
// Needed for handguards with lower
|
||||
@@ -705,7 +702,7 @@ public class BotEquipmentModGenerator(
|
||||
|
||||
// If stock mod can take a sub stock mod, force spawn chance to be 100% to ensure sub-stock gets added
|
||||
// Or if bot has stock force enabled
|
||||
if (ShouldForceSubStockSlots(modSlot, botEquipConfig, modToAddTemplate.Value))
|
||||
if (ShouldForceSubStockSlots(modSlot, botEquipConfig, modToAddTemplate))
|
||||
{
|
||||
// Stock mod can take additional stocks, could be a locking device, force 100% chance
|
||||
List<string> subStockSlots =
|
||||
@@ -719,7 +716,7 @@ public class BotEquipmentModGenerator(
|
||||
}
|
||||
|
||||
// Gather stats on mods being added to weapon
|
||||
if (_itemHelper.IsOfBaseclass(modToAddTemplate.Value.Id, BaseClasses.IRON_SIGHT))
|
||||
if (_itemHelper.IsOfBaseclass(modToAddTemplate.Id, BaseClasses.IRON_SIGHT))
|
||||
{
|
||||
if (modSlot == "mod_sight_front")
|
||||
{
|
||||
@@ -732,7 +729,7 @@ public class BotEquipmentModGenerator(
|
||||
}
|
||||
else if (
|
||||
!(request.WeaponStats.HasOptic ?? false)
|
||||
&& _itemHelper.IsOfBaseclass(modToAddTemplate.Value.Id, BaseClasses.SIGHTS)
|
||||
&& _itemHelper.IsOfBaseclass(modToAddTemplate.Id, BaseClasses.SIGHTS)
|
||||
)
|
||||
{
|
||||
request.WeaponStats.HasOptic = true;
|
||||
@@ -742,16 +739,16 @@ public class BotEquipmentModGenerator(
|
||||
request.Weapon.Add(
|
||||
CreateModItem(
|
||||
modId,
|
||||
modToAddTemplate.Value.Id,
|
||||
modToAddTemplate.Id,
|
||||
request.WeaponId,
|
||||
modSlot,
|
||||
modToAddTemplate.Value,
|
||||
modToAddTemplate,
|
||||
request.BotData.Role
|
||||
)
|
||||
);
|
||||
|
||||
// Update conflicting item list now item has been chosen
|
||||
foreach (var conflictingItem in modToAddTemplate.Value.Properties.ConflictingItems)
|
||||
foreach (var conflictingItem in modToAddTemplate.Properties.ConflictingItems)
|
||||
{
|
||||
request.ConflictingItemTpls.Add(conflictingItem);
|
||||
}
|
||||
@@ -760,30 +757,30 @@ public class BotEquipmentModGenerator(
|
||||
// However, the recursion doesn't go over the slots of the parent mod but over the modPool which is given by the bot config
|
||||
// where we decided to keep cartridges instead of camoras. And since a CylinderMagazine only has one cartridge entry and
|
||||
// this entry is not to be filled, we need a special handling for the CylinderMagazine
|
||||
var modParentItem = _itemHelper.GetItem(modToAddTemplate.Value.Parent).Value;
|
||||
var modParentItem = _itemHelper.GetItem(modToAddTemplate.Parent).Value;
|
||||
if (_botWeaponGeneratorHelper.MagazineIsCylinderRelated(modParentItem.Name))
|
||||
{
|
||||
// We don't have child mods, we need to create the camoras for the magazines instead
|
||||
FillCamora(request.Weapon, request.ModPool, modId, modToAddTemplate.Value);
|
||||
FillCamora(request.Weapon, request.ModPool, modId, modToAddTemplate);
|
||||
}
|
||||
else
|
||||
{
|
||||
var containsModInPool = request.ModPool.ContainsKey(modToAddTemplate.Value.Id);
|
||||
var containsModInPool = request.ModPool.ContainsKey(modToAddTemplate.Id);
|
||||
|
||||
// Sometimes randomised slots are missing sub-mods, if so, get values from mod pool service
|
||||
// Check for a randomisable slot + without data in modPool + item being added as additional slots
|
||||
if (
|
||||
isRandomisableSlot
|
||||
&& !containsModInPool
|
||||
&& modToAddTemplate.Value.Properties.Slots.Any()
|
||||
&& modToAddTemplate.Properties.Slots.Any()
|
||||
)
|
||||
{
|
||||
var modFromService = _botEquipmentModPoolService.GetModsForWeaponSlot(
|
||||
modToAddTemplate.Value.Id
|
||||
modToAddTemplate.Id
|
||||
);
|
||||
if (modFromService?.Count > 0)
|
||||
{
|
||||
request.ModPool[modToAddTemplate.Value.Id] = modFromService.ToDictionary();
|
||||
request.ModPool[modToAddTemplate.Id] = modFromService.ToDictionary();
|
||||
containsModInPool = true;
|
||||
}
|
||||
}
|
||||
@@ -793,11 +790,11 @@ public class BotEquipmentModGenerator(
|
||||
{
|
||||
// Check for required mods the item we've added needs to be classified as 'valid'
|
||||
var modFromService = _botEquipmentModPoolService.GetRequiredModsForWeaponSlot(
|
||||
modToAddTemplate.Value.Id
|
||||
modToAddTemplate.Id
|
||||
);
|
||||
if (modFromService?.Count > 0)
|
||||
{
|
||||
request.ModPool[modToAddTemplate.Value.Id] = modFromService;
|
||||
request.ModPool[modToAddTemplate.Id] = modFromService;
|
||||
containsModInPool = true;
|
||||
}
|
||||
}
|
||||
@@ -809,7 +806,7 @@ public class BotEquipmentModGenerator(
|
||||
Weapon = request.Weapon,
|
||||
ModPool = request.ModPool,
|
||||
WeaponId = modId,
|
||||
ParentTemplate = modToAddTemplate.Value,
|
||||
ParentTemplate = modToAddTemplate,
|
||||
ModSpawnChances = request.ModSpawnChances,
|
||||
AmmoTpl = request.AmmoTpl,
|
||||
BotData = new BotData
|
||||
@@ -869,7 +866,7 @@ public class BotEquipmentModGenerator(
|
||||
/// <param name="modSlot">Slot to check</param>
|
||||
/// <param name="tpl"></param>
|
||||
/// <returns>true if it's a front/rear sight</returns>
|
||||
public bool ModIsFrontOrRearSight(string modSlot, string tpl)
|
||||
public bool ModIsFrontOrRearSight(string modSlot, MongoId tpl)
|
||||
{
|
||||
// Gas block /w front sight is special case, deem it a 'front sight' too
|
||||
if (modSlot == "mod_gas_block" && tpl == "5ae30e795acfc408fb139a0b")
|
||||
@@ -889,7 +886,7 @@ public class BotEquipmentModGenerator(
|
||||
/// <returns>true if it can hold a scope</returns>
|
||||
public bool ModSlotCanHoldScope(string modSlot, string modsParentId)
|
||||
{
|
||||
return _scopeIds.Contains(modSlot.ToLower()) && modsParentId == BaseClasses.MOUNT;
|
||||
return _scopeIds.Contains(modSlot.ToLowerInvariant()) && modsParentId == BaseClasses.MOUNT;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -932,7 +929,7 @@ public class BotEquipmentModGenerator(
|
||||
/// <returns>True if modSlot can have muzzle-related items</returns>
|
||||
public bool ModSlotCanHoldMuzzleDevices(string modSlot, string? modsParentId)
|
||||
{
|
||||
return _muzzleIds.Contains(modSlot.ToLower());
|
||||
return _muzzleIds.Contains(modSlot.ToLowerInvariant());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -943,7 +940,7 @@ public class BotEquipmentModGenerator(
|
||||
/// <returns>Sorted array</returns>
|
||||
public HashSet<string> SortModKeys(
|
||||
HashSet<string> unsortedSlotKeys,
|
||||
string itemTplWithKeysToSort
|
||||
MongoId itemTplWithKeysToSort
|
||||
)
|
||||
{
|
||||
// No need to sort with only 1 item in array
|
||||
@@ -955,16 +952,6 @@ public class BotEquipmentModGenerator(
|
||||
var isMount = _itemHelper.IsOfBaseclass(itemTplWithKeysToSort, BaseClasses.MOUNT);
|
||||
|
||||
HashSet<string> sortedKeys = [];
|
||||
const string modRecieverKey = "mod_reciever";
|
||||
const string modMount001Key = "mod_mount_001";
|
||||
const string modGasBlockKey = "mod_gas_block";
|
||||
const string modPistolGrip = "mod_pistol_grip";
|
||||
const string modStockKey = "mod_stock";
|
||||
const string modBarrelKey = "mod_barrel";
|
||||
const string modHandguardKey = "mod_handguard";
|
||||
const string modMountKey = "mod_mount";
|
||||
const string modScopeKey = "mod_scope";
|
||||
const string modScope000Key = "mod_scope_000";
|
||||
|
||||
// Mounts are a special case, they need scopes first before more mounts
|
||||
if (isMount)
|
||||
@@ -1055,9 +1042,9 @@ public class BotEquipmentModGenerator(
|
||||
/// <param name="modSlot">e.g patron_in_weapon</param>
|
||||
/// <param name="parentTemplate">item template</param>
|
||||
/// <returns>Slot item</returns>
|
||||
public Slot? GetModItemSlotFromDb(string modSlot, TemplateItem parentTemplate)
|
||||
public Slot? GetModItemSlotFromDbTemplate(string modSlot, TemplateItem parentTemplate)
|
||||
{
|
||||
var modSlotLower = modSlot.ToLower();
|
||||
var modSlotLower = modSlot.ToLowerInvariant();
|
||||
switch (modSlotLower)
|
||||
{
|
||||
case "patron_in_weapon":
|
||||
@@ -1100,7 +1087,7 @@ public class BotEquipmentModGenerator(
|
||||
}
|
||||
|
||||
var spawnMod = _randomUtil.RollChance(
|
||||
modSpawnChances.GetValueOrDefault(modSlotName.ToLower())
|
||||
modSpawnChances.GetValueOrDefault(modSlotName.ToLowerInvariant())
|
||||
);
|
||||
if (
|
||||
!spawnMod
|
||||
@@ -1317,7 +1304,7 @@ public class BotEquipmentModGenerator(
|
||||
/// <param name="request"></param>
|
||||
/// <param name="modPool">Pool of mods that can be picked from</param>
|
||||
/// <param name="parentSlot">Slot the picked mod will have as a parent</param>
|
||||
/// <param name="choiceTypeEnum">How should chosen tpl be treated: DEFAULT_MOD/SPAWN/SKIP</param>
|
||||
/// <param name="choiceTypeEnum">How should the chosen tpl be handled: DEFAULT_MOD/SPAWN/SKIP</param>
|
||||
/// <param name="weapon">Array of weapon items chosen item will be added to</param>
|
||||
/// <param name="modSlotName">Name of slot picked mod will be placed into</param>
|
||||
/// <returns>Chosen weapon details</returns>
|
||||
@@ -1556,8 +1543,8 @@ public class BotEquipmentModGenerator(
|
||||
var parentSlotCompatibleItems = request
|
||||
.ParentTemplate.Properties.Slots?.FirstOrDefault(slot =>
|
||||
string.Equals(
|
||||
slot.Name.ToLower(),
|
||||
request.ModSlot.ToLower(),
|
||||
slot.Name.ToLowerInvariant(),
|
||||
request.ModSlot.ToLowerInvariant(),
|
||||
StringComparison.Ordinal
|
||||
)
|
||||
)
|
||||
@@ -1719,7 +1706,7 @@ public class BotEquipmentModGenerator(
|
||||
/// <param name="modSlot">Slot to get mod to fill</param>
|
||||
/// <param name="items">Items to ensure picked mod is compatible with</param>
|
||||
/// <returns>Item tpl</returns>
|
||||
public string? GetRandomModTplFromItemDb(
|
||||
public MongoId? GetRandomModTplFromItemDb(
|
||||
string fallbackModTpl,
|
||||
Slot parentSlot,
|
||||
string modSlot,
|
||||
@@ -1856,7 +1843,7 @@ public class BotEquipmentModGenerator(
|
||||
|
||||
modPool.TryAdd(modTemplate.Id, new Dictionary<string, HashSet<MongoId>>());
|
||||
|
||||
modPool[modTemplate.Id][desiredSlotObject.Name] = supportedSubModsSet;
|
||||
modPool[modTemplate.Id][desiredSlotObject.Name] = filteredMods;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2064,7 +2051,7 @@ public class BotEquipmentModGenerator(
|
||||
public HashSet<MongoId> FilterSightsByWeaponType(
|
||||
Item weapon,
|
||||
HashSet<MongoId> scopes,
|
||||
Dictionary<string, List<string>> botWeaponSightWhitelist
|
||||
Dictionary<MongoId, List<MongoId>> botWeaponSightWhitelist
|
||||
)
|
||||
{
|
||||
var weaponDetails = _itemHelper.GetItem(weapon.Template);
|
||||
|
||||
@@ -188,7 +188,7 @@ public class BotGenerator(
|
||||
BotGenerationDetails botGenerationDetails
|
||||
)
|
||||
{
|
||||
var botRoleLowercase = botGenerationDetails.Role.ToLower();
|
||||
var botRoleLowercase = botGenerationDetails.Role.ToLowerInvariant();
|
||||
var botLevel = _botLevelGenerator.GenerateBotLevel(
|
||||
botJsonTemplate.BotExperience.Level,
|
||||
botGenerationDetails,
|
||||
@@ -215,7 +215,7 @@ public class BotGenerator(
|
||||
|
||||
// Only Pmcs should have a lower nickname
|
||||
bot.Info.LowerNickname = botGenerationDetails.IsPmc.GetValueOrDefault(false)
|
||||
? bot.Info.Nickname.ToLower()
|
||||
? bot.Info.Nickname.ToLowerInvariant()
|
||||
: string.Empty;
|
||||
|
||||
// Only run when generating a 'fake' playerscav, not actual player scav
|
||||
@@ -351,7 +351,7 @@ public class BotGenerator(
|
||||
string role
|
||||
)
|
||||
{
|
||||
if (!experiences.TryGetValue(botDifficulty.ToLower(), out var result))
|
||||
if (!experiences.TryGetValue(botDifficulty.ToLowerInvariant(), out var result))
|
||||
{
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
@@ -386,7 +386,7 @@ public class BotGenerator(
|
||||
string role
|
||||
)
|
||||
{
|
||||
if (!standingsForKill.TryGetValue(botDifficulty.ToLower(), out var result))
|
||||
if (!standingsForKill.TryGetValue(botDifficulty.ToLowerInvariant(), out var result))
|
||||
{
|
||||
_logger.Warning(
|
||||
$"Unable to find standing for kill value for: {role} {botDifficulty}, falling back to `normal`"
|
||||
@@ -411,7 +411,7 @@ public class BotGenerator(
|
||||
string role
|
||||
)
|
||||
{
|
||||
if (!aggressorBonuses.TryGetValue(botDifficulty.ToLower(), out var result))
|
||||
if (!aggressorBonuses.TryGetValue(botDifficulty.ToLowerInvariant(), out var result))
|
||||
{
|
||||
_logger.Warning(
|
||||
$"Unable to find aggressor bonus for kill value for: {role} {botDifficulty}, falling back to `normal`"
|
||||
@@ -474,7 +474,7 @@ public class BotGenerator(
|
||||
/// <param name="botInventory">Bot to filter</param>
|
||||
public void RemoveBlacklistedLootFromBotTemplate(BotTypeInventory botInventory)
|
||||
{
|
||||
var containersToProcess = new List<Dictionary<string, double>>
|
||||
var containersToProcess = new List<Dictionary<MongoId, double>>
|
||||
{
|
||||
botInventory.Items.Backpack,
|
||||
botInventory.Items.Pockets,
|
||||
|
||||
@@ -645,7 +645,7 @@ public class BotInventoryGenerator(
|
||||
/// <param name="equipmentBlacklist">Blacklist to filter mod pool with</param>
|
||||
/// <returns>Filtered pool of mods</returns>
|
||||
public Dictionary<string, HashSet<MongoId>> GetFilteredDynamicModsForItem(
|
||||
string itemTpl,
|
||||
MongoId itemTpl,
|
||||
Dictionary<string, HashSet<MongoId>> equipmentBlacklist
|
||||
)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace SPTarkov.Server.Core.Generators;
|
||||
public class BotLevelGenerator(
|
||||
ISptLogger<BotLevelGenerator> _logger,
|
||||
RandomUtil _randomUtil,
|
||||
MathUtil _mathUtil,
|
||||
DatabaseService _databaseService
|
||||
)
|
||||
{
|
||||
|
||||
@@ -115,7 +115,7 @@ public class BotLootGenerator(
|
||||
var grenadeCount = _weightedRandomHelper.GetWeightedValue(itemCounts.Grenades.Weights);
|
||||
|
||||
// If bot has been flagged as not having loot, set below counts to 0
|
||||
if (_botConfig.DisableLootOnBotTypes.Contains(botRole.ToLower()))
|
||||
if (_botConfig.DisableLootOnBotTypes.Contains(botRole.ToLowerInvariant()))
|
||||
{
|
||||
backpackLootCount = 0;
|
||||
pocketLootCount = 0;
|
||||
@@ -458,7 +458,7 @@ public class BotLootGenerator(
|
||||
{
|
||||
// surv12
|
||||
AddLootFromPool(
|
||||
new Dictionary<string, double> { { "5d02797c86f774203f38e30a", 1 } },
|
||||
new Dictionary<MongoId, double> { { "5d02797c86f774203f38e30a", 1 } },
|
||||
[EquipmentSlots.SecuredContainer],
|
||||
1,
|
||||
botInventory,
|
||||
@@ -470,7 +470,7 @@ public class BotLootGenerator(
|
||||
|
||||
// AFAK
|
||||
AddLootFromPool(
|
||||
new Dictionary<string, double> { { "60098ad7c2240c0fe85c570a", 1 } },
|
||||
new Dictionary<MongoId, double> { { "60098ad7c2240c0fe85c570a", 1 } },
|
||||
[EquipmentSlots.SecuredContainer],
|
||||
10,
|
||||
botInventory,
|
||||
@@ -494,7 +494,7 @@ public class BotLootGenerator(
|
||||
/// <param name="totalValueLimitRub">Total value of loot allowed in roubles</param>
|
||||
/// <param name="isPmc">Is bot being generated for a pmc</param>
|
||||
protected void AddLootFromPool(
|
||||
Dictionary<string, double> pool,
|
||||
Dictionary<MongoId, double> pool,
|
||||
HashSet<EquipmentSlots> equipmentSlots,
|
||||
double totalItemCount,
|
||||
BotBaseInventory inventoryToAddItemsTo,
|
||||
@@ -606,7 +606,7 @@ public class BotLootGenerator(
|
||||
var itemAddedResult = _botGeneratorHelper.AddItemWithChildrenToEquipmentSlot(
|
||||
equipmentSlots,
|
||||
newRootItemId,
|
||||
itemToAddTemplate?.Id,
|
||||
itemToAddTemplate.Id,
|
||||
itemWithChildrenToAdd,
|
||||
inventoryToAddItemsTo,
|
||||
containersIdFull
|
||||
@@ -945,9 +945,9 @@ public class BotLootGenerator(
|
||||
return _botConfig.ItemSpawnLimits["pmc"];
|
||||
}
|
||||
|
||||
if (_botConfig.ItemSpawnLimits.ContainsKey(botRole.ToLower()))
|
||||
if (_botConfig.ItemSpawnLimits.ContainsKey(botRole.ToLowerInvariant()))
|
||||
{
|
||||
return _botConfig.ItemSpawnLimits[botRole.ToLower()];
|
||||
return _botConfig.ItemSpawnLimits[botRole.ToLowerInvariant()];
|
||||
}
|
||||
|
||||
_logger.Warning(
|
||||
|
||||
@@ -545,7 +545,7 @@ public class BotWeaponGenerator(
|
||||
GenerationData ubglMinMax = new()
|
||||
{
|
||||
Weights = new Dictionary<double, double> { { 1, 1 }, { 2, 1 } },
|
||||
Whitelist = new Dictionary<string, double>(),
|
||||
Whitelist = new Dictionary<MongoId, double>(),
|
||||
};
|
||||
|
||||
// get ammo template from db
|
||||
@@ -794,6 +794,7 @@ public class BotWeaponGenerator(
|
||||
|
||||
var magazineTemplate = _itemHelper.GetItem(
|
||||
magazineSlot.Props?.Filters.FirstOrDefault()?.Filter?.FirstOrDefault()
|
||||
?? new MongoId(null)
|
||||
);
|
||||
if (!magazineTemplate.Key)
|
||||
{
|
||||
|
||||
@@ -21,10 +21,8 @@ namespace SPTarkov.Server.Core.Generators;
|
||||
public class LocationLootGenerator(
|
||||
ISptLogger<LocationLootGenerator> _logger,
|
||||
RandomUtil _randomUtil,
|
||||
HashUtil _hashUtil,
|
||||
ItemHelper _itemHelper,
|
||||
DatabaseService _databaseService,
|
||||
ContainerHelper _containerHelper,
|
||||
PresetHelper _presetHelper,
|
||||
ServerLocalisationService _serverLocalisationService,
|
||||
SeasonalEventService _seasonalEventService,
|
||||
@@ -60,7 +58,7 @@ public class LocationLootGenerator(
|
||||
|
||||
// Pull location-specific spawn limits from db
|
||||
var itemsWithSpawnCountLimitsClone = _cloner.Clone(
|
||||
_locationConfig.LootMaxSpawnLimits.GetValueOrDefault(locationId.ToLower())
|
||||
_locationConfig.LootMaxSpawnLimits.GetValueOrDefault(locationId.ToLowerInvariant())
|
||||
);
|
||||
|
||||
// Store items with spawn count limits inside so they can be accessed later inside static/dynamic loot spawn methods
|
||||
@@ -70,13 +68,13 @@ public class LocationLootGenerator(
|
||||
}
|
||||
|
||||
// Create containers with loot
|
||||
result.AddRange(GenerateStaticContainers(locationId.ToLower(), staticAmmoDist));
|
||||
result.AddRange(GenerateStaticContainers(locationId.ToLowerInvariant(), staticAmmoDist));
|
||||
|
||||
// Add dynamic loot to output loot
|
||||
var dynamicSpawnPoints = GenerateDynamicLoot(
|
||||
_cloner.Clone(locationDetails.LooseLoot.Value),
|
||||
staticAmmoDist,
|
||||
locationId.ToLower()
|
||||
locationId.ToLowerInvariant()
|
||||
);
|
||||
|
||||
// Merge dynamic spawns into result
|
||||
@@ -542,7 +540,7 @@ public class LocationLootGenerator(
|
||||
var containerTpl = containerClone.Template.Items.FirstOrDefault().Template;
|
||||
|
||||
// Create new unique parent id to prevent any collisions
|
||||
var parentId = _hashUtil.Generate();
|
||||
var parentId = new MongoId();
|
||||
containerClone.Template.Root = parentId;
|
||||
containerClone.Template.Items.FirstOrDefault().Id = parentId;
|
||||
|
||||
@@ -600,8 +598,7 @@ public class LocationLootGenerator(
|
||||
: chosenItemWithChildren.Items;
|
||||
|
||||
// look for open slot to put chosen item into
|
||||
var result = _containerHelper.FindSlotForItem(
|
||||
containerMap,
|
||||
var result = containerMap.FindSlotForItem(
|
||||
chosenItemWithChildren.Width,
|
||||
chosenItemWithChildren.Height
|
||||
);
|
||||
@@ -620,8 +617,7 @@ public class LocationLootGenerator(
|
||||
}
|
||||
|
||||
// Find somewhere for item inside container
|
||||
_containerHelper.FillContainerMapWithItem(
|
||||
containerMap,
|
||||
containerMap.FillContainerMapWithItem(
|
||||
result.X.Value,
|
||||
result.Y.Value,
|
||||
chosenItemWithChildren.Width,
|
||||
@@ -700,7 +696,7 @@ public class LocationLootGenerator(
|
||||
/// <param name="containerTypeId">Container to get possible loot for</param>
|
||||
/// <param name="staticLootDist">staticLoot.json</param>
|
||||
/// <returns>ProbabilityObjectArray of item tpls + probability</returns>
|
||||
protected ProbabilityObjectArray<string, float?> GetPossibleLootItemsForContainer(
|
||||
protected ProbabilityObjectArray<MongoId, float?> GetPossibleLootItemsForContainer(
|
||||
string containerTypeId,
|
||||
Dictionary<string, StaticLootDetails> staticLootDist
|
||||
)
|
||||
@@ -708,7 +704,7 @@ public class LocationLootGenerator(
|
||||
var seasonalEventActive = _seasonalEventService.SeasonalEventEnabled();
|
||||
var seasonalItemTplBlacklist = _seasonalEventService.GetInactiveSeasonalEventItems();
|
||||
|
||||
var itemDistribution = new ProbabilityObjectArray<string, float?>(_cloner);
|
||||
var itemDistribution = new ProbabilityObjectArray<MongoId, float?>(_cloner);
|
||||
|
||||
var itemContainerDistribution = staticLootDist[containerTypeId]?.ItemDistribution;
|
||||
if (itemContainerDistribution is null)
|
||||
@@ -738,7 +734,7 @@ public class LocationLootGenerator(
|
||||
}
|
||||
|
||||
itemDistribution.Add(
|
||||
new ProbabilityObject<string, float?>(icd.Tpl, icd.RelativeProbability.Value, null)
|
||||
new ProbabilityObject<MongoId, float?>(icd.Tpl, icd.RelativeProbability.Value, null)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ public class LootGenerator(
|
||||
/// </summary>
|
||||
/// <param name="forcedLootToAdd">Dictionary of item tpls with minmax values</param>
|
||||
/// <returns>Array of Item</returns>
|
||||
public List<List<Item>> CreateForcedLoot(Dictionary<string, MinMax<int>> forcedLootToAdd)
|
||||
public List<List<Item>> CreateForcedLoot(Dictionary<MongoId, MinMax<int>> forcedLootToAdd)
|
||||
{
|
||||
var result = new List<List<Item>>();
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ public class PMCLootGenerator(
|
||||
private readonly PmcConfig _pmcConfig = configServer.GetConfig<PmcConfig>();
|
||||
|
||||
// Store loot against its type, usec/bear
|
||||
private readonly Dictionary<string, Dictionary<string, double>>? _backpackLootPool = [];
|
||||
private readonly Dictionary<string, Dictionary<string, double>>? _pocketLootPool = [];
|
||||
private readonly Dictionary<string, Dictionary<string, double>>? _vestLootPool = [];
|
||||
private readonly Dictionary<string, Dictionary<MongoId, double>>? _backpackLootPool = [];
|
||||
private readonly Dictionary<string, Dictionary<MongoId, double>>? _pocketLootPool = [];
|
||||
private readonly Dictionary<string, Dictionary<MongoId, double>>? _vestLootPool = [];
|
||||
|
||||
protected readonly Lock BackpackLock = new();
|
||||
protected readonly Lock PocketLock = new();
|
||||
@@ -38,7 +38,7 @@ public class PMCLootGenerator(
|
||||
/// </summary>
|
||||
/// <param name="pmcRole">Role of PMC having loot generated (bear or usec)</param>
|
||||
/// <returns>Dictionary of string and number</returns>
|
||||
public Dictionary<string, double> GeneratePMCPocketLootPool(string pmcRole)
|
||||
public Dictionary<MongoId, double> GeneratePMCPocketLootPool(string pmcRole)
|
||||
{
|
||||
lock (PocketLock)
|
||||
{
|
||||
@@ -72,7 +72,7 @@ public class PMCLootGenerator(
|
||||
/// </summary>
|
||||
/// <param name="pmcRole">Role of PMC having loot generated (bear or usec)</param>
|
||||
/// <returns>Dictionary item template ids and a weighted chance of being picked</returns>
|
||||
public Dictionary<string, double> GeneratePMCVestLootPool(string pmcRole)
|
||||
public Dictionary<MongoId, double> GeneratePMCVestLootPool(string pmcRole)
|
||||
{
|
||||
lock (VestLock)
|
||||
{
|
||||
@@ -107,7 +107,7 @@ public class PMCLootGenerator(
|
||||
/// </summary>
|
||||
/// <param name="pmcRole">Role of PMC having loot generated (bear or usec)</param>
|
||||
/// <returns>Dictionary of string and number</returns>
|
||||
public Dictionary<string, double> GeneratePMCBackpackLootPool(string pmcRole)
|
||||
public Dictionary<MongoId, double> GeneratePMCBackpackLootPool(string pmcRole)
|
||||
{
|
||||
lock (BackpackLock)
|
||||
{
|
||||
@@ -137,14 +137,14 @@ public class PMCLootGenerator(
|
||||
/// <param name="itemTplAndParentBlacklist">Item and parent blacklist</param>
|
||||
/// <param name="genericItemCheck">An optional delegate to validate the TemplateItem object being processed</param>
|
||||
/// <returns>Dictionary of items and weights inversely tied to the items price</returns>
|
||||
protected Dictionary<string, double> GenerateLootPool(
|
||||
protected Dictionary<MongoId, double> GenerateLootPool(
|
||||
string pmcRole,
|
||||
HashSet<MongoId> allowedItemTypeWhitelist,
|
||||
HashSet<MongoId> itemTplAndParentBlacklist,
|
||||
Func<TemplateItem, bool>? genericItemCheck
|
||||
)
|
||||
{
|
||||
var lootPool = new Dictionary<string, double>();
|
||||
var lootPool = new Dictionary<MongoId, double>();
|
||||
var items = databaseService.GetItems();
|
||||
|
||||
// Grab price overrides if they exist for the pmcRole passed in
|
||||
@@ -207,7 +207,7 @@ public class PMCLootGenerator(
|
||||
/// </summary>
|
||||
/// <param name="pmcRole">role of PMC to look up</param>
|
||||
/// <returns>Dictionary of overrides</returns>
|
||||
protected Dictionary<string, double>? GetPMCPriceOverrides(string pmcRole)
|
||||
protected Dictionary<MongoId, double>? GetPMCPriceOverrides(string pmcRole)
|
||||
{
|
||||
var pmcType = string.Equals(pmcRole, "pmcbear", StringComparison.OrdinalIgnoreCase)
|
||||
? "bear"
|
||||
@@ -229,7 +229,10 @@ public class PMCLootGenerator(
|
||||
/// <param name="tpl">Item tpl to get price of</param>
|
||||
/// <param name="pmcPriceOverrides"></param>
|
||||
/// <returns>Rouble price</returns>
|
||||
protected double GetItemPrice(string tpl, Dictionary<string, double>? pmcPriceOverrides = null)
|
||||
protected double GetItemPrice(
|
||||
MongoId tpl,
|
||||
Dictionary<MongoId, double>? pmcPriceOverrides = null
|
||||
)
|
||||
{
|
||||
if (
|
||||
pmcPriceOverrides is not null
|
||||
|
||||
@@ -80,7 +80,7 @@ public class PlayerScavGenerator(
|
||||
|
||||
var scavData = _botGenerator.GeneratePlayerScav(
|
||||
sessionID,
|
||||
playerScavKarmaSettings.BotTypeForLoot.ToLower(),
|
||||
playerScavKarmaSettings.BotTypeForLoot.ToLowerInvariant(),
|
||||
"easy",
|
||||
baseBotNode,
|
||||
pmcDataClone
|
||||
@@ -113,12 +113,12 @@ public class PlayerScavGenerator(
|
||||
scavData.Quests = existingScavDataClone.Quests ?? [];
|
||||
scavData.TaskConditionCounters =
|
||||
existingScavDataClone.TaskConditionCounters
|
||||
?? new Dictionary<string, TaskConditionCounter>();
|
||||
?? new Dictionary<MongoId, TaskConditionCounter>();
|
||||
scavData.Notes = existingScavDataClone.Notes ?? new Notes { DataNotes = new List<Note>() };
|
||||
scavData.WishList =
|
||||
existingScavDataClone.WishList
|
||||
?? new DictionaryOrList<string, int>(new Dictionary<string, int>(), new List<int>());
|
||||
scavData.Encyclopedia = pmcDataClone.Encyclopedia ?? new Dictionary<string, bool>();
|
||||
?? new DictionaryOrList<MongoId, int>(new Dictionary<MongoId, int>(), []);
|
||||
scavData.Encyclopedia = pmcDataClone.Encyclopedia ?? new Dictionary<MongoId, bool>();
|
||||
|
||||
// Add additional items to player scav as loot
|
||||
AddAdditionalLootToPlayerScavContainers(
|
||||
|
||||
@@ -58,7 +58,12 @@ public class PmcWaveGenerator(
|
||||
/// <param name="location"> Location Object </param>
|
||||
public void ApplyWaveChangesToMap(LocationBase location)
|
||||
{
|
||||
if (!_pmcConfig.CustomPmcWaves.TryGetValue(location.Id.ToLower(), out var pmcWavesToAdd))
|
||||
if (
|
||||
!_pmcConfig.CustomPmcWaves.TryGetValue(
|
||||
location.Id.ToLowerInvariant(),
|
||||
out var pmcWavesToAdd
|
||||
)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
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.Enums;
|
||||
using SPTarkov.Server.Core.Models.Spt.Config;
|
||||
using SPTarkov.Server.Core.Servers;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
using SPTarkov.Server.Core.Utils;
|
||||
using SPTarkov.Server.Core.Utils.Cloners;
|
||||
|
||||
namespace SPTarkov.Server.Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class RagfairAssortGenerator(
|
||||
HashUtil hashUtil,
|
||||
ItemHelper itemHelper,
|
||||
PresetHelper presetHelper,
|
||||
SeasonalEventService seasonalEventService,
|
||||
@@ -23,7 +22,7 @@ public class RagfairAssortGenerator(
|
||||
{
|
||||
protected readonly RagfairConfig RagfairConfig = configServer.GetConfig<RagfairConfig>();
|
||||
|
||||
protected readonly List<string> RagfairItemInvalidBaseTypes =
|
||||
protected readonly List<MongoId> RagfairItemInvalidBaseTypes =
|
||||
[
|
||||
BaseClasses.LOOT_CONTAINER, // Safe, barrel cache etc
|
||||
BaseClasses.STASH, // Player inventory stash
|
||||
@@ -133,16 +132,16 @@ public class RagfairAssortGenerator(
|
||||
/// <param name="tplId"> tplid to add to item </param>
|
||||
/// <param name="id"> id to add to item </param>
|
||||
/// <returns> Hydrated Item object </returns>
|
||||
protected Item CreateRagfairAssortRootItem(string tplId, string? id = null)
|
||||
protected Item CreateRagfairAssortRootItem(MongoId tplId, MongoId? id = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
id = hashUtil.Generate();
|
||||
id = new MongoId();
|
||||
}
|
||||
|
||||
return new Item
|
||||
{
|
||||
Id = id,
|
||||
Id = id.Value,
|
||||
Template = tplId,
|
||||
ParentId = "hideout",
|
||||
SlotId = "hideout",
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Diagnostics;
|
||||
using SPTarkov.Common.Extensions;
|
||||
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.Eft.Ragfair;
|
||||
using SPTarkov.Server.Core.Models.Enums;
|
||||
@@ -148,7 +149,7 @@ public class RagfairOfferGenerator(
|
||||
|
||||
var offer = new RagfairOffer
|
||||
{
|
||||
Id = hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
InternalId = offerCounter,
|
||||
User = CreateUserDataForFleaOffer(userId, ragfairServerHelper.IsTrader(userId)),
|
||||
Root = rootItem.Id,
|
||||
@@ -467,7 +468,7 @@ public class RagfairOfferGenerator(
|
||||
clonedAssort[0].SlotId = null;
|
||||
|
||||
CreateSingleOfferForItem(
|
||||
hashUtil.Generate(),
|
||||
new MongoId(),
|
||||
clonedAssort,
|
||||
isPreset,
|
||||
itemToSellDetails.Value,
|
||||
@@ -494,7 +495,9 @@ public class RagfairOfferGenerator(
|
||||
}
|
||||
|
||||
var plateSlots = presetWithChildren
|
||||
.Where(item => itemHelper.GetRemovablePlateSlotIds().Contains(item.SlotId?.ToLower()))
|
||||
.Where(item =>
|
||||
itemHelper.GetRemovablePlateSlotIds().Contains(item.SlotId?.ToLowerInvariant())
|
||||
)
|
||||
.ToList();
|
||||
if (plateSlots.Count == 0)
|
||||
// Has no plate slots e.g. "front_plate", exit
|
||||
@@ -506,7 +509,7 @@ public class RagfairOfferGenerator(
|
||||
foreach (var plateSlot in plateSlots)
|
||||
{
|
||||
var plateDetails = itemHelper.GetItem(plateSlot.Template).Value;
|
||||
if (plateSettings.IgnoreSlots.Contains(plateSlot.SlotId.ToLower()))
|
||||
if (plateSettings.IgnoreSlots.Contains(plateSlot.SlotId.ToLowerInvariant()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -630,7 +633,7 @@ public class RagfairOfferGenerator(
|
||||
}
|
||||
|
||||
var offerItemPlatesToRemove = itemWithChildren.Where(item =>
|
||||
armorConfig.PlateSlotIdToRemovePool.Contains(item.SlotId?.ToLower())
|
||||
armorConfig.PlateSlotIdToRemovePool.Contains(item.SlotId?.ToLowerInvariant())
|
||||
);
|
||||
|
||||
// Latest first, to ensure we don't move later items off by 1 each time we remove an item below it
|
||||
@@ -783,7 +786,7 @@ public class RagfairOfferGenerator(
|
||||
/// </summary>
|
||||
/// <param name="tpl"> Item to look for matching condition object</param>
|
||||
/// <returns> Condition ID </returns>
|
||||
protected string? GetDynamicConditionIdForTpl(string tpl)
|
||||
protected string? GetDynamicConditionIdForTpl(MongoId tpl)
|
||||
{
|
||||
// Get keys from condition config dictionary
|
||||
var configConditions = ragfairConfig.Dynamic.Condition.Keys;
|
||||
|
||||
+3
-7
@@ -6,7 +6,6 @@ using SPTarkov.Server.Core.Models.Enums;
|
||||
using SPTarkov.Server.Core.Models.Spt.Config;
|
||||
using SPTarkov.Server.Core.Models.Spt.Repeatable;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
using SPTarkov.Server.Core.Servers;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
using SPTarkov.Server.Core.Utils;
|
||||
using SPTarkov.Server.Core.Utils.Json;
|
||||
@@ -21,23 +20,20 @@ public class CompletionQuestGenerator(
|
||||
DatabaseService databaseService,
|
||||
SeasonalEventService seasonalEventService,
|
||||
ServerLocalisationService localisationService,
|
||||
ConfigServer configServer,
|
||||
RandomUtil randomUtil,
|
||||
MathUtil mathUtil,
|
||||
HashUtil hashUtil,
|
||||
ItemHelper itemHelper
|
||||
) : IRepeatableQuestGenerator
|
||||
{
|
||||
protected const int MaxRandomNumberAttempts = 6;
|
||||
|
||||
protected QuestConfig QuestConfig = configServer.GetConfig<QuestConfig>();
|
||||
|
||||
/// <summary>
|
||||
/// Generates a valid Completion quest
|
||||
/// </summary>
|
||||
/// <param name="sessionId">session Id to generate the quest for</param>
|
||||
/// <param name="pmcLevel">player's level for requested items and reward generation</param>
|
||||
/// <param name="traderId">trader from which the quest will be provided</param>
|
||||
/// <param name="questTypePool"></param>
|
||||
/// <param name="repeatableConfig">
|
||||
/// The configuration for the repeatably kind (daily, weekly) as configured in QuestConfig
|
||||
/// for the requested quest
|
||||
@@ -398,7 +394,7 @@ public class CompletionQuestGenerator(
|
||||
/// <param name="completionConfig">Completion config from quest.json</param>
|
||||
/// <returns>object of "Completion"-condition</returns>
|
||||
protected QuestCondition GenerateCondition(
|
||||
string itemTpl,
|
||||
MongoId itemTpl,
|
||||
double value,
|
||||
Completion completionConfig
|
||||
)
|
||||
@@ -424,7 +420,7 @@ public class CompletionQuestGenerator(
|
||||
|
||||
return new QuestCondition
|
||||
{
|
||||
Id = hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
Index = 0,
|
||||
ParentId = "",
|
||||
DynamicLocale = true,
|
||||
|
||||
+4
-5
@@ -21,7 +21,6 @@ namespace SPTarkov.Server.Core.Generators.RepeatableQuestGeneration;
|
||||
public class EliminationQuestGenerator(
|
||||
ISptLogger<EliminationQuestGenerator> logger,
|
||||
RandomUtil randomUtil,
|
||||
HashUtil hashUtil,
|
||||
MathUtil mathUtil,
|
||||
RepeatableQuestHelper repeatableQuestHelper,
|
||||
ItemHelper itemHelper,
|
||||
@@ -277,7 +276,7 @@ public class EliminationQuestGenerator(
|
||||
}
|
||||
|
||||
var availableForFinishCondition = quest.Conditions.AvailableForFinish![0];
|
||||
availableForFinishCondition.Counter!.Id = hashUtil.Generate();
|
||||
availableForFinishCondition.Counter!.Id = new MongoId();
|
||||
availableForFinishCondition.Counter.Conditions = [];
|
||||
|
||||
// Only add specific location condition if specific map selected
|
||||
@@ -299,7 +298,7 @@ public class EliminationQuestGenerator(
|
||||
)
|
||||
);
|
||||
availableForFinishCondition.Value = desiredKillCount;
|
||||
availableForFinishCondition.Id = hashUtil.Generate();
|
||||
availableForFinishCondition.Id = new MongoId();
|
||||
|
||||
// Get the quest location, default to any if none exist
|
||||
quest.Location = repeatableQuestHelper.GetQuestLocationByMapId(locationKey) ?? "any";
|
||||
@@ -744,7 +743,7 @@ public class EliminationQuestGenerator(
|
||||
{
|
||||
return new QuestConditionCounterCondition
|
||||
{
|
||||
Id = hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
DynamicLocale = true,
|
||||
Target = new ListOrT<string>(location, null),
|
||||
ConditionType = "Location",
|
||||
@@ -770,7 +769,7 @@ public class EliminationQuestGenerator(
|
||||
{
|
||||
var killConditionProps = new QuestConditionCounterCondition
|
||||
{
|
||||
Id = hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
DynamicLocale = true,
|
||||
Target = new ListOrT<string>(null, target), // e,g, "AnyPmc"
|
||||
Value = 1,
|
||||
|
||||
+7
-12
@@ -7,7 +7,6 @@ using SPTarkov.Server.Core.Models.Enums;
|
||||
using SPTarkov.Server.Core.Models.Spt.Config;
|
||||
using SPTarkov.Server.Core.Models.Spt.Repeatable;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
using SPTarkov.Server.Core.Servers;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
using SPTarkov.Server.Core.Utils;
|
||||
using SPTarkov.Server.Core.Utils.Json;
|
||||
@@ -21,10 +20,8 @@ public class ExplorationQuestGenerator(
|
||||
RepeatableQuestRewardGenerator repeatableQuestRewardGenerator,
|
||||
DatabaseService databaseService,
|
||||
ServerLocalisationService localisationService,
|
||||
ConfigServer configServer,
|
||||
RandomUtil randomUtil,
|
||||
MathUtil mathUtil,
|
||||
HashUtil hashUtil
|
||||
MathUtil mathUtil
|
||||
) : IRepeatableQuestGenerator
|
||||
{
|
||||
protected record LocationInfo(
|
||||
@@ -34,8 +31,6 @@ public class ExplorationQuestGenerator(
|
||||
int NumOfExtractsRequired
|
||||
);
|
||||
|
||||
protected QuestConfig QuestConfig = configServer.GetConfig<QuestConfig>();
|
||||
|
||||
/// <summary>
|
||||
/// Generates a valid Exploration quest
|
||||
/// </summary>
|
||||
@@ -216,7 +211,7 @@ public class ExplorationQuestGenerator(
|
||||
/// <returns>List of Exit objects</returns>
|
||||
protected List<Exit>? GetLocationExitsForSide(string locationKey, PlayerGroup playerGroup)
|
||||
{
|
||||
var mapExtracts = databaseService.GetLocation(locationKey.ToLower())?.AllExtracts;
|
||||
var mapExtracts = databaseService.GetLocation(locationKey.ToLowerInvariant())?.AllExtracts;
|
||||
|
||||
return mapExtracts?.Where(exit => exit.Side == Enum.GetName(playerGroup)).ToList();
|
||||
}
|
||||
@@ -254,7 +249,7 @@ public class ExplorationQuestGenerator(
|
||||
|
||||
var exitStatusCondition = new QuestConditionCounterCondition
|
||||
{
|
||||
Id = hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
DynamicLocale = true,
|
||||
Status = ["Survived"],
|
||||
ConditionType = "ExitStatus",
|
||||
@@ -262,20 +257,20 @@ public class ExplorationQuestGenerator(
|
||||
|
||||
var locationCondition = new QuestConditionCounterCondition
|
||||
{
|
||||
Id = hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
DynamicLocale = true,
|
||||
Target = new ListOrT<string>(locationInfo.LocationTarget, null),
|
||||
ConditionType = "Location",
|
||||
};
|
||||
|
||||
quest.Conditions.AvailableForFinish![0].Counter!.Id = hashUtil.Generate();
|
||||
quest.Conditions.AvailableForFinish![0].Counter!.Id = new MongoId();
|
||||
quest.Conditions.AvailableForFinish![0].Counter!.Conditions =
|
||||
[
|
||||
exitStatusCondition,
|
||||
locationCondition,
|
||||
];
|
||||
quest.Conditions.AvailableForFinish[0].Value = locationInfo.NumOfExtractsRequired;
|
||||
quest.Conditions.AvailableForFinish[0].Id = hashUtil.Generate();
|
||||
quest.Conditions.AvailableForFinish[0].Id = new MongoId();
|
||||
|
||||
quest.Location = location;
|
||||
|
||||
@@ -357,7 +352,7 @@ public class ExplorationQuestGenerator(
|
||||
{
|
||||
return new QuestConditionCounterCondition
|
||||
{
|
||||
Id = hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
DynamicLocale = true,
|
||||
ExitName = exit.Name,
|
||||
ConditionType = "ExitName",
|
||||
|
||||
+9
-10
@@ -20,7 +20,6 @@ namespace SPTarkov.Server.Core.Generators.RepeatableQuestGeneration;
|
||||
public class RepeatableQuestRewardGenerator(
|
||||
ISptLogger<RepeatableQuestRewardGenerator> logger,
|
||||
RandomUtil randomUtil,
|
||||
HashUtil hashUtil,
|
||||
MathUtil mathUtil,
|
||||
DatabaseService databaseService,
|
||||
ItemHelper itemHelper,
|
||||
@@ -95,7 +94,7 @@ public class RepeatableQuestRewardGenerator(
|
||||
rewards.Success.Add(
|
||||
new Reward
|
||||
{
|
||||
Id = hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
Unknown = false,
|
||||
GameMode = [],
|
||||
AvailableInGameEditions = [],
|
||||
@@ -193,7 +192,7 @@ public class RepeatableQuestRewardGenerator(
|
||||
{
|
||||
Reward reward = new()
|
||||
{
|
||||
Id = hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
Unknown = false,
|
||||
GameMode = [],
|
||||
AvailableInGameEditions = [],
|
||||
@@ -219,7 +218,7 @@ public class RepeatableQuestRewardGenerator(
|
||||
var targetSkill = randomUtil.GetArrayValue(eliminationConfig.PossibleSkillRewards);
|
||||
Reward reward = new()
|
||||
{
|
||||
Id = hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
Unknown = false,
|
||||
GameMode = [],
|
||||
AvailableInGameEditions = [],
|
||||
@@ -657,17 +656,17 @@ public class RepeatableQuestRewardGenerator(
|
||||
/// <param name="foundInRaid"> If generated Item is found in raid, default True </param>
|
||||
/// <returns> Object of "Reward"-item-type </returns>
|
||||
protected Reward GeneratePresetReward(
|
||||
string tpl,
|
||||
MongoId tpl,
|
||||
int count,
|
||||
int index,
|
||||
List<Item>? preset,
|
||||
bool foundInRaid = true
|
||||
)
|
||||
{
|
||||
var id = hashUtil.Generate();
|
||||
var id = new MongoId();
|
||||
var questRewardItem = new Reward
|
||||
{
|
||||
Id = hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
Unknown = false,
|
||||
GameMode = [],
|
||||
AvailableInGameEditions = [],
|
||||
@@ -713,10 +712,10 @@ public class RepeatableQuestRewardGenerator(
|
||||
bool foundInRaid = true
|
||||
)
|
||||
{
|
||||
var id = hashUtil.Generate();
|
||||
var id = new MongoId();
|
||||
var questRewardItem = new Reward
|
||||
{
|
||||
Id = hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
Unknown = false,
|
||||
GameMode = [],
|
||||
AvailableInGameEditions = [],
|
||||
@@ -819,7 +818,7 @@ public class RepeatableQuestRewardGenerator(
|
||||
/// <param name="itemBaseWhitelist"> Default null, specific trader item base classes</param>
|
||||
/// <returns> True if item is valid reward </returns>
|
||||
public bool IsValidRewardItem(
|
||||
string tpl,
|
||||
MongoId tpl,
|
||||
HashSet<MongoId> itemTplBlacklist,
|
||||
HashSet<MongoId> itemTypeBlacklist,
|
||||
List<MongoId>? itemBaseWhitelist = null
|
||||
|
||||
@@ -4,7 +4,6 @@ using SPTarkov.Server.Core.Models.Eft.Common;
|
||||
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
|
||||
using SPTarkov.Server.Core.Models.Enums;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
using SPTarkov.Server.Core.Servers;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
|
||||
namespace SPTarkov.Server.Core.Helpers;
|
||||
@@ -12,10 +11,7 @@ namespace SPTarkov.Server.Core.Helpers;
|
||||
[Injectable]
|
||||
public class AssortHelper(
|
||||
ISptLogger<AssortHelper> _logger,
|
||||
ItemHelper _itemHelper,
|
||||
DatabaseServer _databaseServer,
|
||||
ServerLocalisationService _serverLocalisationService,
|
||||
QuestHelper _questHelper
|
||||
ServerLocalisationService _serverLocalisationService
|
||||
)
|
||||
{
|
||||
/// <summary>
|
||||
@@ -58,10 +54,7 @@ public class AssortHelper(
|
||||
}
|
||||
|
||||
// Remove assort if quest in profile does not have status that unlocks assort
|
||||
var questStatusInProfile = _questHelper.GetQuestStatus(
|
||||
pmcProfile,
|
||||
unlockValues.Value.Key
|
||||
);
|
||||
var questStatusInProfile = pmcProfile.GetQuestStatus(unlockValues.Value.Key);
|
||||
if (!unlockValues.Value.Value.Contains(questStatusInProfile))
|
||||
{
|
||||
strippedTraderAssorts = traderAssorts.RemoveItemFromAssort(assortId.Key, isFlea);
|
||||
|
||||
@@ -37,8 +37,8 @@ public class BotDifficultyHelper(
|
||||
)
|
||||
{
|
||||
var desiredType = _botHelper.IsBotPmc(type)
|
||||
? _botHelper.GetPmcSideByRole(type).ToLower()
|
||||
: type.ToLower();
|
||||
? _botHelper.GetPmcSideByRole(type).ToLowerInvariant()
|
||||
: type.ToLowerInvariant();
|
||||
if (!botDb.Types.ContainsKey(desiredType))
|
||||
{
|
||||
// No bot found, get fallback difficulty values
|
||||
@@ -85,7 +85,7 @@ public class BotDifficultyHelper(
|
||||
StringComparison.OrdinalIgnoreCase
|
||||
)
|
||||
? difficulty
|
||||
: _pmcConfig.Difficulty.ToLower();
|
||||
: _pmcConfig.Difficulty.ToLowerInvariant();
|
||||
|
||||
difficultySetting = ConvertBotDifficultyDropdownToBotDifficulty(difficultySetting);
|
||||
|
||||
@@ -101,14 +101,14 @@ public class BotDifficultyHelper(
|
||||
/// <returns>bot difficulty</returns>
|
||||
public string ConvertBotDifficultyDropdownToBotDifficulty(string dropDownDifficulty)
|
||||
{
|
||||
switch (dropDownDifficulty.ToLower())
|
||||
switch (dropDownDifficulty.ToLowerInvariant())
|
||||
{
|
||||
case "medium":
|
||||
return "normal";
|
||||
case "random":
|
||||
return ChooseRandomDifficulty();
|
||||
default:
|
||||
return dropDownDifficulty.ToLower();
|
||||
return dropDownDifficulty.ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Frozen;
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.Constants;
|
||||
using SPTarkov.Server.Core.Extensions;
|
||||
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;
|
||||
@@ -21,7 +22,6 @@ public class BotGeneratorHelper(
|
||||
DurabilityLimitsHelper _durabilityLimitsHelper,
|
||||
ItemHelper _itemHelper,
|
||||
InventoryHelper _inventoryHelper,
|
||||
ContainerHelper _containerHelper,
|
||||
ProfileActivityService _profileActivityService,
|
||||
ServerLocalisationService _serverLocalisationService,
|
||||
ConfigServer _configServer
|
||||
@@ -37,7 +37,11 @@ public class BotGeneratorHelper(
|
||||
EquipmentSlots.ArmBand.ToString(),
|
||||
];
|
||||
|
||||
private static readonly string[] _pmcTypes = [Sides.PmcBear.ToLower(), Sides.PmcUsec.ToLower()];
|
||||
private static readonly string[] _pmcTypes =
|
||||
[
|
||||
Sides.PmcBear.ToLowerInvariant(),
|
||||
Sides.PmcUsec.ToLowerInvariant(),
|
||||
];
|
||||
|
||||
private readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
|
||||
@@ -382,7 +386,7 @@ public class BotGeneratorHelper(
|
||||
/// <returns>false if no incompatibilities, also has incompatibility reason</returns>
|
||||
public ChooseRandomCompatibleModResult IsItemIncompatibleWithCurrentItems(
|
||||
List<Item> itemsEquipped,
|
||||
string tplToCheck,
|
||||
MongoId tplToCheck,
|
||||
string equipmentSlot
|
||||
)
|
||||
{
|
||||
@@ -596,15 +600,15 @@ public class BotGeneratorHelper(
|
||||
/// </summary>
|
||||
/// <param name="equipmentSlots">Slot to add item+children into</param>
|
||||
/// <param name="rootItemId">Root item id to use as mod items parentId</param>
|
||||
/// <param name="rootItemTplId">Root itms tpl id</param>
|
||||
/// <param name="rootItemTplId">Root items tpl id</param>
|
||||
/// <param name="itemWithChildren">Item to add</param>
|
||||
/// <param name="inventory">Inventory to add item+children into</param>
|
||||
/// <param name="containersIdFull"></param>
|
||||
/// <returns>ItemAddedResult result object</returns>
|
||||
public ItemAddedResult AddItemWithChildrenToEquipmentSlot(
|
||||
HashSet<EquipmentSlots> equipmentSlots,
|
||||
string rootItemId,
|
||||
string? rootItemTplId,
|
||||
MongoId rootItemId,
|
||||
MongoId rootItemTplId,
|
||||
List<Item> itemWithChildren,
|
||||
BotBaseInventory inventory,
|
||||
HashSet<string>? containersIdFull = null
|
||||
@@ -665,7 +669,7 @@ public class BotGeneratorHelper(
|
||||
}
|
||||
|
||||
// Get x/y grid size of item
|
||||
var itemSize = _inventoryHelper.GetItemSize(
|
||||
var (itemWidth, itemHeight) = _inventoryHelper.GetItemSize(
|
||||
rootItemTplId,
|
||||
rootItemId,
|
||||
itemWithChildren
|
||||
@@ -680,7 +684,7 @@ public class BotGeneratorHelper(
|
||||
if (
|
||||
slotGrid.Props?.CellsH == 0
|
||||
|| slotGrid.Props?.CellsV == 0
|
||||
|| itemSize[0] * itemSize[1] > slotGrid.Props?.CellsV * slotGrid.Props?.CellsH
|
||||
|| itemWidth * itemHeight > slotGrid.Props?.CellsV * slotGrid.Props?.CellsH
|
||||
)
|
||||
{
|
||||
continue;
|
||||
@@ -718,11 +722,7 @@ public class BotGeneratorHelper(
|
||||
);
|
||||
|
||||
// Try to fit item into grid
|
||||
var findSlotResult = _containerHelper.FindSlotForItem(
|
||||
slotGridMap,
|
||||
itemSize[0],
|
||||
itemSize[1]
|
||||
);
|
||||
var findSlotResult = slotGridMap.FindSlotForItem(itemWidth, itemHeight);
|
||||
|
||||
// Free slot found, add item
|
||||
if (findSlotResult.Success ?? false)
|
||||
@@ -768,7 +768,7 @@ public class BotGeneratorHelper(
|
||||
}
|
||||
|
||||
// if the item was a one by one, we know it must be full. Or if the maps cant find a slot for a one by one
|
||||
if (itemSize[0] == 1 && itemSize[1] == 1)
|
||||
if (itemWidth == 1 && itemHeight == 1)
|
||||
{
|
||||
containersIdFull.Add(equipmentSlotId.ToString());
|
||||
}
|
||||
@@ -796,7 +796,7 @@ public class BotGeneratorHelper(
|
||||
}
|
||||
|
||||
// Filter out all items without location prop, (child items)
|
||||
var itemsWithoutLocation = inventoryItems.Where(item => item.Location is null).ToList();
|
||||
var itemsWithoutLocation = inventoryItems.Where(item => item.Location is null);
|
||||
foreach (var rootItem in containerRootItems)
|
||||
{
|
||||
// Check item in container for children, store for later insertion into `containerItemsToCheck`
|
||||
@@ -817,7 +817,7 @@ public class BotGeneratorHelper(
|
||||
/// <param name="slotGrid">Items sub-grid we want to place item inside</param>
|
||||
/// <param name="itemTpl">Item tpl being placed</param>
|
||||
/// <returns>True if allowed</returns>
|
||||
protected bool ItemAllowedInContainer(Grid? slotGrid, string? itemTpl)
|
||||
protected bool ItemAllowedInContainer(Grid? slotGrid, MongoId itemTpl)
|
||||
{
|
||||
var propFilters = slotGrid?.Props?.Filters;
|
||||
var excludedFilter = propFilters?.FirstOrDefault()?.ExcludedFilter ?? [];
|
||||
|
||||
@@ -22,10 +22,10 @@ public class BotHelper(
|
||||
{
|
||||
private static readonly FrozenSet<string> _pmcTypeIds =
|
||||
[
|
||||
Sides.Usec.ToLower(),
|
||||
Sides.Bear.ToLower(),
|
||||
Sides.PmcBear.ToLower(),
|
||||
Sides.PmcUsec.ToLower(),
|
||||
Sides.Usec.ToLowerInvariant(),
|
||||
Sides.Bear.ToLowerInvariant(),
|
||||
Sides.PmcBear.ToLowerInvariant(),
|
||||
Sides.PmcUsec.ToLowerInvariant(),
|
||||
];
|
||||
|
||||
private readonly BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
@@ -39,7 +39,7 @@ public class BotHelper(
|
||||
/// <returns>BotType object</returns>
|
||||
public BotType? GetBotTemplate(string role)
|
||||
{
|
||||
if (!_databaseService.GetBots().Types.TryGetValue(role?.ToLower(), out var bot))
|
||||
if (!_databaseService.GetBots().Types.TryGetValue(role?.ToLowerInvariant(), out var bot))
|
||||
{
|
||||
_logger.Error($"Unable to get bot of type: {role} from DB");
|
||||
|
||||
@@ -56,7 +56,7 @@ public class BotHelper(
|
||||
/// <returns>true if is pmc</returns>
|
||||
public bool IsBotPmc(string? botRole)
|
||||
{
|
||||
return _pmcTypeIds.Contains(botRole?.ToLower());
|
||||
return _pmcTypeIds.Contains(botRole?.ToLowerInvariant());
|
||||
}
|
||||
|
||||
public bool IsBotBoss(string botRole)
|
||||
@@ -135,10 +135,10 @@ public class BotHelper(
|
||||
{
|
||||
HashSet<string> listToCheck =
|
||||
[
|
||||
_pmcConfig.UsecType.ToLower(),
|
||||
_pmcConfig.BearType.ToLower(),
|
||||
_pmcConfig.UsecType.ToLowerInvariant(),
|
||||
_pmcConfig.BearType.ToLowerInvariant(),
|
||||
];
|
||||
return listToCheck.Contains(botRole.ToLower());
|
||||
return listToCheck.Contains(botRole.ToLowerInvariant());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -227,7 +227,7 @@ public class BotHelper(
|
||||
)
|
||||
{
|
||||
_logger.Error($"Unknown faction: {chosenFaction} Defaulting to: {Sides.Usec}");
|
||||
chosenFaction = Sides.Usec.ToLower();
|
||||
chosenFaction = Sides.Usec.ToLowerInvariant();
|
||||
chosenFactionDetails = _databaseService.GetBots().Types[chosenFaction];
|
||||
}
|
||||
|
||||
|
||||
@@ -34,10 +34,11 @@ public class BotWeaponGeneratorHelper(
|
||||
double? chamberBulletCount = 0;
|
||||
if (MagazineIsCylinderRelated(parentItem.Name))
|
||||
{
|
||||
var firstSlotAmmoTpl = magTemplate
|
||||
.Properties.Cartridges.FirstOrDefault()
|
||||
?.Props.Filters[0]
|
||||
.Filter.FirstOrDefault();
|
||||
var firstSlotAmmoTpl =
|
||||
magTemplate
|
||||
.Properties.Cartridges.FirstOrDefault()
|
||||
?.Props.Filters[0]
|
||||
.Filter.FirstOrDefault() ?? new MongoId(null);
|
||||
var ammoMaxStackSize =
|
||||
_itemHelper.GetItem(firstSlotAmmoTpl).Value?.Properties?.StackMaxSize ?? 1;
|
||||
chamberBulletCount =
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using SPTarkov.DI.Annotations;
|
||||
|
||||
namespace SPTarkov.Server.Core.Helpers;
|
||||
|
||||
[Injectable]
|
||||
public class ContainerHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds a slot for an item in a given 2D container map
|
||||
/// </summary>
|
||||
/// <param name="container2D">List of container with positions filled/free</param>
|
||||
/// <param name="itemX">Width of item</param>
|
||||
/// <param name="itemY">Height of item</param>
|
||||
/// <returns>Location to place item in container</returns>
|
||||
public FindSlotResult FindSlotForItem(int[][] container2D, int? itemX, int? itemY)
|
||||
{
|
||||
// Assume not rotated
|
||||
var rotation = false;
|
||||
|
||||
var minVolume = (itemX < itemY ? itemX : itemY) - 1;
|
||||
var containerY = container2D.Length;
|
||||
var containerX = container2D[0].Length;
|
||||
var limitY = containerY - minVolume;
|
||||
var limitX = containerX - minVolume;
|
||||
|
||||
// Every x+y slot taken up in container, exit
|
||||
if (container2D.All(x => x.All(y => y == 1)))
|
||||
{
|
||||
return new FindSlotResult(false);
|
||||
}
|
||||
|
||||
// Down = y
|
||||
for (var y = 0; y < limitY; y++)
|
||||
{
|
||||
if (container2D[y].All(x => x == 1))
|
||||
// Every item in row is full, skip row
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Go left to right across x-axis looking for free position
|
||||
for (var x = 0; x < limitX; x++)
|
||||
{
|
||||
if (
|
||||
CanItemBePlacedInContainerAtPosition(
|
||||
container2D,
|
||||
containerX,
|
||||
containerY,
|
||||
x,
|
||||
y,
|
||||
itemX!.Value,
|
||||
itemY!.Value
|
||||
)
|
||||
)
|
||||
{
|
||||
// Success, return result
|
||||
return new FindSlotResult(true, x, y, rotation);
|
||||
}
|
||||
|
||||
if (ItemBiggerThan1X1(itemX!.Value, itemY!.Value))
|
||||
{
|
||||
// Pointless rotating a 1x1, try next position across
|
||||
continue;
|
||||
}
|
||||
|
||||
// Bigger than 1x1, try rotating by swapping x and y values
|
||||
if (
|
||||
!CanItemBePlacedInContainerAtPosition(
|
||||
container2D,
|
||||
containerX,
|
||||
containerY,
|
||||
x,
|
||||
y,
|
||||
itemY!.Value,
|
||||
itemX!.Value
|
||||
)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found a position for item when rotated
|
||||
rotation = true;
|
||||
|
||||
return new FindSlotResult(true, x, y, rotation);
|
||||
}
|
||||
}
|
||||
|
||||
// Tried all possible positions, nothing big enough for item
|
||||
return new FindSlotResult(false);
|
||||
}
|
||||
|
||||
protected static bool ItemBiggerThan1X1(int itemWidth, int itemHeight)
|
||||
{
|
||||
return itemWidth + itemHeight > 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can an item of specified size be placed inside a 2d container at a specific position
|
||||
/// </summary>
|
||||
/// <param name="container">Container to find space in</param>
|
||||
/// <param name="containerWidth">Container x size</param>
|
||||
/// <param name="containerHeight">Container y size</param>
|
||||
/// <param name="startXPos">Starting x position for item</param>
|
||||
/// <param name="startYPos">Starting y position for item</param>
|
||||
/// <param name="itemWidth">Items width</param>
|
||||
/// <param name="itemHeight">Items height</param>
|
||||
/// <returns>True - slot found</returns>
|
||||
protected bool CanItemBePlacedInContainerAtPosition(
|
||||
int[][] container,
|
||||
int containerWidth,
|
||||
int containerHeight,
|
||||
int startXPos,
|
||||
int startYPos,
|
||||
int itemWidth,
|
||||
int itemHeight
|
||||
)
|
||||
{
|
||||
// Check item isn't bigger than container when at position
|
||||
if (startXPos + itemWidth > containerWidth || startYPos + itemHeight > containerHeight)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check each position item will take up in container, go across and then down
|
||||
for (var itemY = startYPos; itemY < startYPos + itemHeight; itemY++)
|
||||
{
|
||||
for (var itemX = startXPos; itemX < startXPos + itemWidth; itemX++)
|
||||
{
|
||||
// e,g for a 2x2 item; [0,0] then [0,1] then [1,0] then [1,1]
|
||||
if (container[itemY][itemX] != 0)
|
||||
{
|
||||
// x,y Position blocked, can't place
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a free slot for an item to be placed at
|
||||
/// </summary>
|
||||
/// <param name="container2D">Container to place item in</param>
|
||||
/// <param name="x">Container x size</param>
|
||||
/// <param name="y">Container y size</param>
|
||||
/// <param name="itemW">Items width</param>
|
||||
/// <param name="itemH">Items height</param>
|
||||
/// <param name="rotate">is item rotated</param>
|
||||
public void FillContainerMapWithItem(
|
||||
int[][] container2D,
|
||||
int x,
|
||||
int y,
|
||||
int? itemW,
|
||||
int? itemH,
|
||||
bool rotate
|
||||
)
|
||||
{
|
||||
// Swap height/width if we want to fit it in rotated
|
||||
var itemWidth = rotate ? itemH : itemW;
|
||||
var itemHeight = rotate ? itemW : itemH;
|
||||
|
||||
for (var tmpY = y; tmpY < y + itemHeight; tmpY++)
|
||||
for (var tmpX = x; tmpX < x + itemWidth; tmpX++)
|
||||
{
|
||||
if (container2D[tmpY][tmpX] == 0)
|
||||
// Flag slot as used
|
||||
{
|
||||
container2D[tmpY][tmpX] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(
|
||||
$"Slot at({x}, {y}) is already filled. Cannot fit a {itemW} by {itemH} item"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FindSlotResult
|
||||
{
|
||||
public FindSlotResult(bool success)
|
||||
{
|
||||
Success = success;
|
||||
}
|
||||
|
||||
public FindSlotResult(bool success, int x, int y, bool rotation)
|
||||
{
|
||||
Success = success;
|
||||
X = x;
|
||||
Y = y;
|
||||
Rotation = rotation;
|
||||
}
|
||||
|
||||
public FindSlotResult() { }
|
||||
|
||||
[JsonPropertyName("success")]
|
||||
public bool? Success { get; set; }
|
||||
|
||||
[JsonPropertyName("x")]
|
||||
public int? X { get; set; }
|
||||
|
||||
[JsonPropertyName("y")]
|
||||
public int? Y { get; set; }
|
||||
|
||||
[JsonPropertyName("rotation")]
|
||||
public bool? Rotation { get; set; }
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
|
||||
namespace SPTarkov.Server.Core.Helpers
|
||||
{
|
||||
[Injectable]
|
||||
public class CounterTrackerHelper
|
||||
{
|
||||
private Dictionary<string, int> _maxCounts = new();
|
||||
private readonly Dictionary<string, int> _trackedCounts = new();
|
||||
private Dictionary<MongoId, int> _maxCounts = new();
|
||||
private readonly Dictionary<MongoId, int> _trackedCounts = new();
|
||||
|
||||
/// <summary>
|
||||
/// Add dictionary of keys and their matching limits to track
|
||||
/// </summary>
|
||||
/// <param name="maxCounts">Values to store</param>
|
||||
public void AddDataToTrack(Dictionary<string, int> maxCounts)
|
||||
public void AddDataToTrack(Dictionary<MongoId, int> maxCounts)
|
||||
{
|
||||
_maxCounts = maxCounts;
|
||||
}
|
||||
@@ -23,7 +24,7 @@ namespace SPTarkov.Server.Core.Helpers
|
||||
/// <param name="key"></param>
|
||||
/// <param name="countToIncrementBy"></param>
|
||||
/// <returns>True = above max count</returns>
|
||||
public bool IncrementCount(string key, int countToIncrementBy = 1)
|
||||
public bool IncrementCount(MongoId key, int countToIncrementBy = 1)
|
||||
{
|
||||
// Not tracked, skip
|
||||
if (!_maxCounts.Any() || !_maxCounts.ContainsKey(key))
|
||||
|
||||
@@ -3,7 +3,6 @@ using SPTarkov.Server.Core.Models.Eft.Dialog;
|
||||
using SPTarkov.Server.Core.Models.Eft.Profile;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
using SPTarkov.Server.Core.Utils.Callbacks;
|
||||
|
||||
namespace SPTarkov.Server.Core.Helpers.Dialogue;
|
||||
|
||||
@@ -20,7 +19,7 @@ public abstract class AbstractDialogChatBot(
|
||||
|
||||
public abstract UserDialogInfo GetChatBot();
|
||||
|
||||
public string? HandleMessage(string sessionId, SendMessageRequest request)
|
||||
public async ValueTask<string> HandleMessage(string sessionId, SendMessageRequest request)
|
||||
{
|
||||
if ((request.Text ?? "").Length == 0)
|
||||
{
|
||||
@@ -37,14 +36,14 @@ public abstract class AbstractDialogChatBot(
|
||||
&& commando.GetCommands().Contains(splitCommand[1])
|
||||
)
|
||||
{
|
||||
return commando.Handle(splitCommand[1], GetChatBot(), sessionId, request);
|
||||
return await commando.Handle(splitCommand[1], GetChatBot(), sessionId, request);
|
||||
}
|
||||
|
||||
if (
|
||||
string.Equals(splitCommand.FirstOrDefault(), "help", StringComparison.OrdinalIgnoreCase)
|
||||
)
|
||||
{
|
||||
return SendPlayerHelpMessage(sessionId, request);
|
||||
return await SendPlayerHelpMessage(sessionId, request);
|
||||
}
|
||||
|
||||
_mailSendService.SendUserMessageToPlayer(
|
||||
@@ -55,10 +54,13 @@ public abstract class AbstractDialogChatBot(
|
||||
null
|
||||
);
|
||||
|
||||
return null;
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
protected string? SendPlayerHelpMessage(string sessionId, SendMessageRequest request)
|
||||
protected async ValueTask<string> SendPlayerHelpMessage(
|
||||
string sessionId,
|
||||
SendMessageRequest request
|
||||
)
|
||||
{
|
||||
_mailSendService.SendUserMessageToPlayer(
|
||||
sessionId,
|
||||
@@ -67,40 +69,34 @@ public abstract class AbstractDialogChatBot(
|
||||
[],
|
||||
null
|
||||
);
|
||||
// due to BSG being dumb with messages we need a mandatory timeout between messages so they get out on the right order
|
||||
TimeoutCallback.RunInTimespan(
|
||||
() =>
|
||||
{
|
||||
foreach (var chatCommand in _chatCommands.Values)
|
||||
{
|
||||
_mailSendService.SendUserMessageToPlayer(
|
||||
sessionId,
|
||||
GetChatBot(),
|
||||
$"Commands available for \"{chatCommand.GetCommandPrefix()}\" prefix:",
|
||||
[],
|
||||
null
|
||||
);
|
||||
foreach (var chatCommand in _chatCommands.Values)
|
||||
{
|
||||
// due to BSG being dumb with messages we need a mandatory timeout between messages so they get out on the right order
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
|
||||
TimeoutCallback.RunInTimespan(
|
||||
() =>
|
||||
{
|
||||
foreach (var subCommand in chatCommand.GetCommands())
|
||||
{
|
||||
_mailSendService.SendUserMessageToPlayer(
|
||||
sessionId,
|
||||
GetChatBot(),
|
||||
$"Subcommand {subCommand}:\n{chatCommand.GetCommandHelp(subCommand)}",
|
||||
[],
|
||||
null
|
||||
);
|
||||
}
|
||||
},
|
||||
TimeSpan.FromSeconds(1)
|
||||
);
|
||||
}
|
||||
},
|
||||
TimeSpan.FromSeconds(1)
|
||||
);
|
||||
_mailSendService.SendUserMessageToPlayer(
|
||||
sessionId,
|
||||
GetChatBot(),
|
||||
$"Commands available for \"{chatCommand.GetCommandPrefix()}\" prefix:",
|
||||
[],
|
||||
null
|
||||
);
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
|
||||
foreach (var subCommand in chatCommand.GetCommands())
|
||||
{
|
||||
_mailSendService.SendUserMessageToPlayer(
|
||||
sessionId,
|
||||
GetChatBot(),
|
||||
$"Subcommand {subCommand}:\n{chatCommand.GetCommandHelp(subCommand)}",
|
||||
[],
|
||||
null
|
||||
);
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
return request.DialogId;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ public interface IChatCommand
|
||||
public string GetCommandPrefix();
|
||||
public string GetCommandHelp(string command);
|
||||
public List<string> GetCommands();
|
||||
public string Handle(
|
||||
public ValueTask<string> Handle(
|
||||
string command,
|
||||
UserDialogInfo commandHandler,
|
||||
string sessionId,
|
||||
|
||||
@@ -50,14 +50,14 @@ public class SptCommandoCommands : IChatCommand
|
||||
return _sptCommands.Keys.ToList();
|
||||
}
|
||||
|
||||
public string Handle(
|
||||
public async ValueTask<string> Handle(
|
||||
string command,
|
||||
UserDialogInfo commandHandler,
|
||||
string sessionId,
|
||||
SendMessageRequest request
|
||||
)
|
||||
{
|
||||
return _sptCommands[command].PerformAction(commandHandler, sessionId, request);
|
||||
return await _sptCommands[command].PerformAction(commandHandler, sessionId, request);
|
||||
}
|
||||
|
||||
public void RegisterSptCommandoCommand(ISptCommand command)
|
||||
|
||||
+12
-11
@@ -52,7 +52,7 @@ public class GiveSptCommand(
|
||||
+ "give [locale] [\"item name\"] [quantity]\n\t\tEx: spt give fr \"figurine de chat\" 3";
|
||||
}
|
||||
|
||||
public string PerformAction(
|
||||
public ValueTask<string> PerformAction(
|
||||
UserDialogInfo commandHandler,
|
||||
string sessionId,
|
||||
SendMessageRequest request
|
||||
@@ -65,7 +65,7 @@ public class GiveSptCommand(
|
||||
commandHandler,
|
||||
"Invalid use of give command. Use 'help' for more information."
|
||||
);
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
var result = _commandRegex.Match(request.Text);
|
||||
@@ -86,7 +86,7 @@ public class GiveSptCommand(
|
||||
commandHandler,
|
||||
"Invalid use of give command. Use 'help' for more information."
|
||||
);
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
_savedCommand.TryGetValue(sessionId, out var savedCommand);
|
||||
@@ -98,7 +98,7 @@ public class GiveSptCommand(
|
||||
commandHandler,
|
||||
"Invalid selection. Outside of bounds! Use 'help' for more information."
|
||||
);
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
item = savedCommand.PotentialItemNames[locationSixValue - 1];
|
||||
@@ -128,7 +128,7 @@ public class GiveSptCommand(
|
||||
commandHandler,
|
||||
"Invalid quantity! Must be 1 or higher. Use 'help' for more information."
|
||||
);
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
if (isItemName)
|
||||
@@ -157,7 +157,7 @@ public class GiveSptCommand(
|
||||
.Select(i =>
|
||||
localizedGlobal
|
||||
.GetValueOrDefault($"{i.Id} Name", i.Properties.Name)
|
||||
?.ToLower()
|
||||
?.ToLowerInvariant()
|
||||
)
|
||||
.Where(i => !string.IsNullOrEmpty(i));
|
||||
|
||||
@@ -197,7 +197,7 @@ public class GiveSptCommand(
|
||||
$"Could not find exact match. Closest are:\n{string.Join("\n", itemList)}\n\nUse 'spt give [above number]' to select one."
|
||||
);
|
||||
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,7 +210,8 @@ public class GiveSptCommand(
|
||||
.GetItems()
|
||||
.Where(IsItemAllowed)
|
||||
.FirstOrDefault(i =>
|
||||
(localizedGlobal[$"{i?.Id} Name"]?.ToLower() ?? i.Properties.Name) == item
|
||||
(localizedGlobal[$"{i?.Id} Name"]?.ToLowerInvariant() ?? i.Properties.Name)
|
||||
== item
|
||||
)
|
||||
.Id
|
||||
: item;
|
||||
@@ -223,7 +224,7 @@ public class GiveSptCommand(
|
||||
commandHandler,
|
||||
"That item could not be found. Please refine your request and try again."
|
||||
);
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
List<Item> itemsToSend = [];
|
||||
@@ -285,7 +286,7 @@ public class GiveSptCommand(
|
||||
"Too many items requested. Please lower the amount and try again."
|
||||
);
|
||||
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,7 +300,7 @@ public class GiveSptCommand(
|
||||
itemsToSend
|
||||
);
|
||||
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
+2
-2
@@ -14,8 +14,8 @@ public static class StringSimilarity
|
||||
{
|
||||
if (!caseSensitive)
|
||||
{
|
||||
str1 = str1.ToLower();
|
||||
str2 = str2.ToLower();
|
||||
str1 = str1.ToLowerInvariant();
|
||||
str2 = str2.ToLowerInvariant();
|
||||
}
|
||||
|
||||
if (str1.Length < substringLength || str2.Length < substringLength)
|
||||
|
||||
@@ -7,7 +7,7 @@ public interface ISptCommand
|
||||
{
|
||||
public string GetCommand();
|
||||
public string GetCommandHelp();
|
||||
public string PerformAction(
|
||||
public ValueTask<string> PerformAction(
|
||||
UserDialogInfo commandHandler,
|
||||
string sessionId,
|
||||
SendMessageRequest request
|
||||
|
||||
+8
-10
@@ -9,14 +9,12 @@ using SPTarkov.Server.Core.Models.Enums;
|
||||
using SPTarkov.Server.Core.Models.Spt.Dialog;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
using SPTarkov.Server.Core.Utils;
|
||||
|
||||
namespace SPTarkov.Server.Core.Helpers.Dialogue.Commando.SptCommands.ProfileCommand;
|
||||
|
||||
[Injectable]
|
||||
public class ProfileSptCommand(
|
||||
ISptLogger<ProfileSptCommand> _logger,
|
||||
HashUtil _hashUtil,
|
||||
MailSendService _mailSendService,
|
||||
ProfileHelper _profileHelper
|
||||
) : ISptCommand
|
||||
@@ -44,7 +42,7 @@ public class ProfileSptCommand(
|
||||
+ "spt profile skill metabolism 51";
|
||||
}
|
||||
|
||||
public string PerformAction(
|
||||
public ValueTask<string> PerformAction(
|
||||
UserDialogInfo commandHandler,
|
||||
string sessionId,
|
||||
SendMessageRequest request
|
||||
@@ -60,7 +58,7 @@ public class ProfileSptCommand(
|
||||
commandHandler,
|
||||
"Invalid use of trader command. Use 'help' for more information."
|
||||
);
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
var result = _commandRegex.Match(request.Text);
|
||||
@@ -84,7 +82,7 @@ public class ProfileSptCommand(
|
||||
commandHandler,
|
||||
"Invalid use of profile command, the level was outside bounds: 1 to 70. Use 'help' for more information."
|
||||
);
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
profileChangeEvent = HandleLevelCommand(quantity);
|
||||
@@ -104,7 +102,7 @@ public class ProfileSptCommand(
|
||||
commandHandler,
|
||||
"Invalid use of profile command, the skill was not found. Use 'help' for more information."
|
||||
);
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
if (quantity is < 0 or > 51)
|
||||
@@ -114,7 +112,7 @@ public class ProfileSptCommand(
|
||||
commandHandler,
|
||||
"Invalid use of profile command, the skill level was outside bounds: 1 to 51. Use 'help' for more information."
|
||||
);
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
profileChangeEvent = HandleSkillCommand(enumSkill, quantity);
|
||||
@@ -131,7 +129,7 @@ public class ProfileSptCommand(
|
||||
commandHandler,
|
||||
$"If you are reading this, this is bad. Please report this to SPT staff with a screenshot. Command: {command}."
|
||||
);
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
_mailSendService.SendSystemMessageToPlayer(
|
||||
@@ -143,7 +141,7 @@ public class ProfileSptCommand(
|
||||
Id = new MongoId(),
|
||||
Template = Money.ROUBLES,
|
||||
Upd = new Upd { StackObjectsCount = 1 },
|
||||
ParentId = _hashUtil.Generate(),
|
||||
ParentId = new MongoId(),
|
||||
SlotId = "main",
|
||||
},
|
||||
],
|
||||
@@ -151,7 +149,7 @@ public class ProfileSptCommand(
|
||||
[profileChangeEvent]
|
||||
);
|
||||
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
protected ProfileChangeEvent HandleSkillCommand(SkillTypes? skill, int level)
|
||||
|
||||
+6
-8
@@ -10,14 +10,12 @@ using SPTarkov.Server.Core.Models.Enums;
|
||||
using SPTarkov.Server.Core.Models.Spt.Dialog;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
using SPTarkov.Server.Core.Utils;
|
||||
|
||||
namespace SPTarkov.Server.Core.Helpers.Dialogue.Commando.SptCommands.TraderCommand;
|
||||
|
||||
[Injectable]
|
||||
public class TraderSptCommand(
|
||||
ISptLogger<TraderSptCommand> _logger,
|
||||
HashUtil _hashUtil,
|
||||
TraderHelper _traderHelper,
|
||||
MailSendService _mailSendService
|
||||
) : ISptCommand
|
||||
@@ -36,7 +34,7 @@ public class TraderSptCommand(
|
||||
return "spt trader \n ======== \n Sets the reputation or money spent to the input quantity through the message system.\n\n\tspt trader [trader] rep [quantity]\n\t\tEx: spt trader prapor rep 2\n\n\tspt trader [trader] spend [quantity]\n\t\tEx: spt trader therapist spend 1000000";
|
||||
}
|
||||
|
||||
public string PerformAction(
|
||||
public ValueTask<string> PerformAction(
|
||||
UserDialogInfo commandHandler,
|
||||
string sessionId,
|
||||
SendMessageRequest request
|
||||
@@ -49,7 +47,7 @@ public class TraderSptCommand(
|
||||
commandHandler,
|
||||
"Invalid use of trader command. Use 'help' for more information."
|
||||
);
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
var result = _commandRegex.Match(request.Text);
|
||||
@@ -77,7 +75,7 @@ public class TraderSptCommand(
|
||||
"Invalid use of trader command, the trader was not found. Use 'help' for more information."
|
||||
);
|
||||
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
NotificationEventType profileChangeEventType;
|
||||
@@ -98,7 +96,7 @@ public class TraderSptCommand(
|
||||
"Invalid use of trader command, ProfileChangeEventType was not found. Use 'help' for more information."
|
||||
);
|
||||
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +109,7 @@ public class TraderSptCommand(
|
||||
Id = new MongoId(),
|
||||
Template = Money.ROUBLES,
|
||||
Upd = new Upd { StackObjectsCount = 1 },
|
||||
ParentId = _hashUtil.Generate(),
|
||||
ParentId = new MongoId(),
|
||||
SlotId = "main",
|
||||
},
|
||||
],
|
||||
@@ -119,7 +117,7 @@ public class TraderSptCommand(
|
||||
[CreateProfileChangeEvent(profileChangeEventType, quantity, dbTrader.Id)]
|
||||
);
|
||||
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
protected ProfileChangeEvent CreateProfileChangeEvent(
|
||||
|
||||
@@ -6,5 +6,10 @@ namespace SPTarkov.Server.Core.Helpers.Dialogue;
|
||||
public interface IDialogueChatBot
|
||||
{
|
||||
public UserDialogInfo GetChatBot();
|
||||
public string? HandleMessage(string sessionId, SendMessageRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Handles messages for the chatbot. If a message can't be handled, <see cref="string.Empty"/> should be used.
|
||||
/// </summary>
|
||||
/// <returns>The response of the bot, or <see cref="string.Empty"/> if the request could not be handled.</returns>
|
||||
public ValueTask<string> HandleMessage(string sessionId, SendMessageRequest request);
|
||||
}
|
||||
|
||||
@@ -13,9 +13,7 @@ namespace SPTarkov.Server.Core.Helpers.Dialogue;
|
||||
|
||||
[Injectable]
|
||||
public class SptDialogueChatBot(
|
||||
ISptLogger<AbstractDialogChatBot> _logger,
|
||||
MailSendService _mailSendService,
|
||||
IEnumerable<IChatCommand> _chatCommands,
|
||||
ConfigServer _configServer,
|
||||
ProfileHelper _profileHelper,
|
||||
IEnumerable<IChatMessageHandler> chatMessageHandlers
|
||||
@@ -42,7 +40,7 @@ public class SptDialogueChatBot(
|
||||
};
|
||||
}
|
||||
|
||||
public string? HandleMessage(string sessionId, SendMessageRequest request)
|
||||
public ValueTask<string> HandleMessage(string sessionId, SendMessageRequest request)
|
||||
{
|
||||
var sender = _profileHelper.GetPmcProfile(sessionId);
|
||||
var sptFriendUser = GetChatBot();
|
||||
@@ -57,7 +55,7 @@ public class SptDialogueChatBot(
|
||||
{
|
||||
handler.Process(sessionId, sptFriendUser, sender, request);
|
||||
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
_mailSendService.SendUserMessageToPlayer(
|
||||
@@ -68,7 +66,7 @@ public class SptDialogueChatBot(
|
||||
null
|
||||
);
|
||||
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
|
||||
protected static List<IChatMessageHandler> ChatMessageHandlerSetup(
|
||||
@@ -86,7 +84,7 @@ public class SptDialogueChatBot(
|
||||
return "Unknown command.";
|
||||
}
|
||||
|
||||
protected string? SendPlayerHelpMessage(string sessionId, SendMessageRequest request)
|
||||
protected ValueTask<string> SendPlayerHelpMessage(string sessionId, SendMessageRequest request)
|
||||
{
|
||||
_mailSendService.SendUserMessageToPlayer(
|
||||
sessionId,
|
||||
@@ -96,6 +94,6 @@ public class SptDialogueChatBot(
|
||||
null
|
||||
);
|
||||
|
||||
return request.DialogId;
|
||||
return new ValueTask<string>(request.DialogId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
|
||||
using SPTarkov.Server.Core.Models.Eft.Profile;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
@@ -46,7 +47,7 @@ public class DialogueHelper(ISptLogger<DialogueHelper> logger, ProfileHelper pro
|
||||
/// <param name="sessionID">Session/player id</param>
|
||||
/// <param name="itemId">Item being moved to inventory</param>
|
||||
/// <returns>Collection of items from message</returns>
|
||||
public List<Item> GetMessageItemContents(string messageID, string sessionID, string itemId)
|
||||
public List<Item> GetMessageItemContents(string messageID, string sessionID, MongoId itemId)
|
||||
{
|
||||
var fullProfile = profileHelper.GetFullProfile(sessionID);
|
||||
var dialogueData = fullProfile.DialogueRecords;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
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.Config;
|
||||
@@ -88,7 +89,7 @@ public class HandbookHelper(
|
||||
/// </summary>
|
||||
/// <param name="tpl">Item tpl to look up price for</param>
|
||||
/// <returns>price in roubles</returns>
|
||||
public double GetTemplatePrice(string tpl)
|
||||
public double GetTemplatePrice(MongoId tpl)
|
||||
{
|
||||
if (HandbookPriceCache.Items.ById.TryGetValue(tpl, out var itemPrice))
|
||||
{
|
||||
@@ -211,11 +212,11 @@ public class HandbookHelper(
|
||||
{
|
||||
public LookupItem()
|
||||
{
|
||||
ById = new Dictionary<string, T>();
|
||||
ById = new Dictionary<MongoId, T>();
|
||||
ByParent = new Dictionary<string, List<I>>();
|
||||
}
|
||||
|
||||
public Dictionary<string, T> ById { get; set; }
|
||||
public Dictionary<MongoId, T> ById { get; set; }
|
||||
|
||||
public Dictionary<string, List<I>> ByParent { get; set; }
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ public class HideoutHelper(
|
||||
ISptLogger<HideoutHelper> _logger,
|
||||
TimeUtil _timeUtil,
|
||||
ServerLocalisationService _serverLocalisationService,
|
||||
HashUtil _hashUtil,
|
||||
DatabaseService _databaseService,
|
||||
EventOutputHolder _eventOutputHolder,
|
||||
HttpResponseUtil _httpResponseUtil,
|
||||
@@ -31,10 +30,8 @@ public class HideoutHelper(
|
||||
ICloner _cloner
|
||||
)
|
||||
{
|
||||
public const string BitcoinFarm = "5d5c205bd582a50d042a3c0e";
|
||||
public const string CultistCircleCraftId = "66827062405f392b203a44cf";
|
||||
public const string BitcoinProductionId = "5d5c205bd582a50d042a3c0e";
|
||||
public const string WaterCollector = "5d5589c1f934db045e6c5492";
|
||||
public static readonly MongoId BitcoinProductionId = new("5d5c205bd582a50d042a3c0e");
|
||||
public static readonly MongoId WaterCollectorId = new("5d5589c1f934db045e6c5492");
|
||||
public const int MaxSkillPoint = 5000;
|
||||
|
||||
/// <summary>
|
||||
@@ -599,8 +596,7 @@ public class HideoutHelper(
|
||||
* GetTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn);
|
||||
|
||||
// Get all fuel consumption bonuses, returns an empty array if none found
|
||||
var profileFuelConsomptionBonusSum = _profileHelper.GetBonusValueFromProfile(
|
||||
pmcData,
|
||||
var profileFuelConsomptionBonusSum = pmcData.GetBonusValueFromProfile(
|
||||
BonusType.FuelConsumption
|
||||
);
|
||||
|
||||
@@ -733,7 +729,7 @@ public class HideoutHelper(
|
||||
|
||||
// Canister with purified water craft exists
|
||||
if (
|
||||
pmcData.Hideout.Production.TryGetValue(WaterCollector, out var purifiedWaterCraft)
|
||||
pmcData.Hideout.Production.TryGetValue(WaterCollectorId, out var purifiedWaterCraft)
|
||||
&& purifiedWaterCraft.GetType() == typeof(Production)
|
||||
)
|
||||
{
|
||||
@@ -752,7 +748,7 @@ public class HideoutHelper(
|
||||
// seem to not trigger consistently
|
||||
var recipe = new HideoutSingleProductionStartRequestData
|
||||
{
|
||||
RecipeId = WaterCollector,
|
||||
RecipeId = WaterCollectorId,
|
||||
Action = "HideoutSingleProductionStart",
|
||||
Items = [],
|
||||
Tools = [],
|
||||
@@ -793,7 +789,7 @@ public class HideoutHelper(
|
||||
var timeReductionSeconds = 0D;
|
||||
|
||||
// Bitcoin farm is excluded from crafting skill cooldown reduction
|
||||
if (recipeId != BitcoinFarm)
|
||||
if (recipeId != BitcoinProductionId)
|
||||
// Seconds to deduct from crafts total time
|
||||
{
|
||||
timeReductionSeconds += GetSkillProductionTimeReduction(
|
||||
@@ -845,7 +841,7 @@ public class HideoutHelper(
|
||||
)
|
||||
{
|
||||
var filterDrainRate = GetWaterFilterDrainRate(pmcData);
|
||||
var craftProductionTime = GetTotalProductionTimeSeconds(WaterCollector);
|
||||
var craftProductionTime = GetTotalProductionTimeSeconds(WaterCollectorId);
|
||||
var secondsSinceServerTick = GetTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn);
|
||||
|
||||
filterDrainRate = GetTimeAdjustedWaterFilterDrainRate(
|
||||
@@ -1286,7 +1282,7 @@ public class HideoutHelper(
|
||||
{
|
||||
var bitcoinProductions = _databaseService
|
||||
.GetHideout()
|
||||
.Production.Recipes.FirstOrDefault(production => production.Id == BitcoinFarm);
|
||||
.Production.Recipes.FirstOrDefault(production => production.Id == BitcoinProductionId);
|
||||
var productionSlots = bitcoinProductions?.ProductionLimitCount ?? 3; // Default to 3 if none found
|
||||
var hasManagementSkillSlots = _profileHelper.HasEliteSkillLevel(
|
||||
SkillTypes.HideoutManagement,
|
||||
@@ -1401,7 +1397,7 @@ public class HideoutHelper(
|
||||
)
|
||||
{
|
||||
// Get how many coins were crafted and ready to pick up
|
||||
pmcData.Hideout.Production.TryGetValue(BitcoinFarm, out var bitcoinCraft);
|
||||
pmcData.Hideout.Production.TryGetValue(BitcoinProductionId, out var bitcoinCraft);
|
||||
var craftedCoinCount = bitcoinCraft?.Products?.Count;
|
||||
if (bitcoinCraft is null || craftedCoinCount is null)
|
||||
{
|
||||
@@ -1446,15 +1442,16 @@ public class HideoutHelper(
|
||||
|
||||
// Is at max capacity + we collected all coins - reset production start time
|
||||
var coinSlotCount = GetBTCSlots(pmcData);
|
||||
if (pmcData.Hideout.Production[BitcoinFarm].Products.Count >= coinSlotCount)
|
||||
if (pmcData.Hideout.Production[BitcoinProductionId].Products.Count >= coinSlotCount)
|
||||
// Set start to now
|
||||
{
|
||||
pmcData.Hideout.Production[BitcoinFarm].StartTimestamp = _timeUtil.GetTimeStamp();
|
||||
pmcData.Hideout.Production[BitcoinProductionId].StartTimestamp =
|
||||
_timeUtil.GetTimeStamp();
|
||||
}
|
||||
|
||||
// Remove crafted coins from production in profile now they've been collected
|
||||
// Can only collect all coins, not individually
|
||||
pmcData.Hideout.Production[BitcoinFarm].Products = [];
|
||||
pmcData.Hideout.Production[BitcoinProductionId].Products = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace SPTarkov.Server.Core.Helpers;
|
||||
[Injectable]
|
||||
public class InRaidHelper(
|
||||
InventoryHelper _inventoryHelper,
|
||||
ItemHelper _itemHelper,
|
||||
ConfigServer _configServer,
|
||||
ICloner _cloner,
|
||||
DatabaseService _databaseService
|
||||
@@ -66,23 +65,27 @@ public class InRaidHelper(
|
||||
var insured = _cloner.Clone(serverProfile.InsuredItems);
|
||||
|
||||
// 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, 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,
|
||||
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.FindAndReturnChildrenAsItems(
|
||||
postRaidProfile.Inventory.Equipment
|
||||
postRaidProfile.Inventory.Equipment.Value
|
||||
);
|
||||
|
||||
// Get all items that have a parent of `serverProfile.Inventory.questRaidItems` (Quest items player had on them at end of raid)
|
||||
var postRaidQuestItems = postRaidProfile.Inventory.Items.FindAndReturnChildrenAsItems(
|
||||
postRaidProfile.Inventory.QuestRaidItems
|
||||
postRaidProfile.Inventory.QuestRaidItems.Value
|
||||
);
|
||||
|
||||
// Handle Removing of FIR status if player did not survive + not transferring
|
||||
@@ -243,14 +246,10 @@ public class InRaidHelper(
|
||||
}
|
||||
|
||||
// Pocket items are lost on death
|
||||
// Ensure we dont pick up pocket items from manniquins
|
||||
// Ensure we don't pick up pocket items from mannequins
|
||||
if (
|
||||
item.SlotId.StartsWith("pocket")
|
||||
&& _inventoryHelper.DoesItemHaveRootId(
|
||||
pmcProfile,
|
||||
item,
|
||||
pmcProfile.Inventory.Equipment
|
||||
)
|
||||
&& pmcProfile.DoesItemHaveRootId(item, pmcProfile.Inventory.Equipment)
|
||||
)
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Collections.Frozen;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using SPTarkov.Common.Extensions;
|
||||
using SPTarkov.DI.Annotations;
|
||||
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.Eft.Inventory;
|
||||
@@ -24,10 +23,8 @@ namespace SPTarkov.Server.Core.Helpers;
|
||||
[Injectable]
|
||||
public class InventoryHelper(
|
||||
ISptLogger<InventoryHelper> _logger,
|
||||
HashUtil _hashUtil,
|
||||
HttpResponseUtil _httpResponseUtil,
|
||||
DialogueHelper _dialogueHelper,
|
||||
ContainerHelper _containerHelper,
|
||||
EventOutputHolder _eventOutputHolder,
|
||||
ProfileHelper _profileHelper,
|
||||
ItemHelper _itemHelper,
|
||||
@@ -36,7 +33,7 @@ public class InventoryHelper(
|
||||
ICloner _cloner
|
||||
)
|
||||
{
|
||||
private static readonly FrozenSet<string> _variableSizeItemTypes =
|
||||
private static readonly FrozenSet<MongoId> _variableSizeItemTypes =
|
||||
[
|
||||
BaseClasses.WEAPON,
|
||||
BaseClasses.FUNCTIONAL_MOD,
|
||||
@@ -108,7 +105,7 @@ public class InventoryHelper(
|
||||
var itemWithModsToAddClone = _cloner.Clone(request.ItemWithModsToAdd);
|
||||
|
||||
// Get stash layouts ready for use
|
||||
var stashFS2D = GetStashSlotMap(pmcData, sessionId);
|
||||
var stashFS2D = GetStashSlotMap(pmcData);
|
||||
if (stashFS2D is null)
|
||||
{
|
||||
_logger.Error($"Unable to get stash map for players: {sessionId} stash");
|
||||
@@ -145,10 +142,7 @@ public class InventoryHelper(
|
||||
// Run callback
|
||||
try
|
||||
{
|
||||
if (request.Callback is not null)
|
||||
{
|
||||
request.Callback((int)(itemWithModsToAddClone[0].Upd.StackObjectsCount ?? 0));
|
||||
}
|
||||
request.Callback?.Invoke((int)(itemWithModsToAddClone[0].Upd.StackObjectsCount ?? 0));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -168,7 +162,7 @@ public class InventoryHelper(
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug(
|
||||
$"Added {itemWithModsToAddClone[0].Upd?.StackObjectsCount ?? 1} item: {itemWithModsToAddClone[0].Template} with: {itemWithModsToAddClone.Count - 1} mods to inventory"
|
||||
$"Added: {itemWithModsToAddClone[0].Upd?.StackObjectsCount ?? 1} item: {itemWithModsToAddClone[0].Template} with: {itemWithModsToAddClone.Count - 1} mods to inventory"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -224,7 +218,7 @@ public class InventoryHelper(
|
||||
{
|
||||
var pmcData = _profileHelper.GetPmcProfile(sessionId);
|
||||
|
||||
var stashFS2D = _cloner.Clone(GetStashSlotMap(pmcData, sessionId));
|
||||
var stashFS2D = _cloner.Clone(GetStashSlotMap(pmcData));
|
||||
if (stashFS2D is null)
|
||||
{
|
||||
_logger.Error($"Unable to get stash map for players: {sessionId} stash");
|
||||
@@ -244,7 +238,7 @@ public class InventoryHelper(
|
||||
/// <param name="containerFS2D">Container grid to fit items into</param>
|
||||
/// <param name="itemsWithChildren">Items to try and fit into grid</param>
|
||||
/// <returns>True all fit</returns>
|
||||
public bool CanPlaceItemsInContainer(int[][] containerFS2D, List<List<Item>> itemsWithChildren)
|
||||
public bool CanPlaceItemsInContainer(int[,] containerFS2D, List<List<Item>> itemsWithChildren)
|
||||
{
|
||||
return itemsWithChildren.All(itemWithChildren =>
|
||||
CanPlaceItemInContainer(containerFS2D, itemWithChildren)
|
||||
@@ -257,28 +251,23 @@ public class InventoryHelper(
|
||||
/// <param name="containerFS2D">Container grid</param>
|
||||
/// <param name="itemWithChildren">Item to check fits</param>
|
||||
/// <returns>True it fits</returns>
|
||||
public bool CanPlaceItemInContainer(int[][] containerFS2D, List<Item> itemWithChildren)
|
||||
public bool CanPlaceItemInContainer(int[,] containerFS2D, List<Item> itemWithChildren)
|
||||
{
|
||||
// Get x/y size of item
|
||||
var rootItem = itemWithChildren[0];
|
||||
var itemSize = GetItemSize(rootItem.Template, rootItem.Id, itemWithChildren);
|
||||
var (sizeX, sizeY) = GetItemSize(rootItem.Template, rootItem.Id, itemWithChildren);
|
||||
|
||||
// Look for a place to slot item into
|
||||
var findSlotResult = _containerHelper.FindSlotForItem(
|
||||
containerFS2D,
|
||||
itemSize[0],
|
||||
itemSize[1]
|
||||
);
|
||||
var findSlotResult = containerFS2D.FindSlotForItem(sizeX, sizeY);
|
||||
if (findSlotResult.Success.GetValueOrDefault(false))
|
||||
{
|
||||
try
|
||||
{
|
||||
_containerHelper.FillContainerMapWithItem(
|
||||
containerFS2D,
|
||||
containerFS2D.FillContainerMapWithItem(
|
||||
findSlotResult.X.Value,
|
||||
findSlotResult.Y.Value,
|
||||
itemSize[0],
|
||||
itemSize[1],
|
||||
sizeX,
|
||||
sizeY,
|
||||
findSlotResult.Rotation.Value
|
||||
);
|
||||
}
|
||||
@@ -309,7 +298,7 @@ public class InventoryHelper(
|
||||
/// <param name="containerId">Id of the container we're fitting item into</param>
|
||||
/// <param name="desiredSlotId">Slot id value to use, default is "hideout"</param>
|
||||
public void PlaceItemInContainer(
|
||||
int[][] containerFS2D,
|
||||
int[,] containerFS2D,
|
||||
List<Item> itemWithChildren,
|
||||
string containerId,
|
||||
string desiredSlotId = "hideout"
|
||||
@@ -317,24 +306,23 @@ public class InventoryHelper(
|
||||
{
|
||||
// Get x/y size of item
|
||||
var rootItemAdded = itemWithChildren[0];
|
||||
var itemSize = GetItemSize(rootItemAdded.Template, rootItemAdded.Id, itemWithChildren);
|
||||
var (sizeX, sizeY) = GetItemSize(
|
||||
rootItemAdded.Template,
|
||||
rootItemAdded.Id,
|
||||
itemWithChildren
|
||||
);
|
||||
|
||||
// Look for a place to slot item into
|
||||
var findSlotResult = _containerHelper.FindSlotForItem(
|
||||
containerFS2D,
|
||||
itemSize[0],
|
||||
itemSize[1]
|
||||
);
|
||||
var findSlotResult = containerFS2D.FindSlotForItem(sizeX, sizeY);
|
||||
if (findSlotResult.Success.GetValueOrDefault(false))
|
||||
{
|
||||
try
|
||||
{
|
||||
_containerHelper.FillContainerMapWithItem(
|
||||
containerFS2D,
|
||||
containerFS2D.FillContainerMapWithItem(
|
||||
findSlotResult.X.Value,
|
||||
findSlotResult.Y.Value,
|
||||
itemSize[0],
|
||||
itemSize[1],
|
||||
sizeX,
|
||||
sizeY,
|
||||
findSlotResult.Rotation.Value
|
||||
);
|
||||
}
|
||||
@@ -370,15 +358,15 @@ public class InventoryHelper(
|
||||
/// <summary>
|
||||
/// Find a location to place an item into inventory and place it
|
||||
/// </summary>
|
||||
/// <param name="stashFS2D">2-dimensional representation of the container slots</param>
|
||||
/// <param name="stashFS2D">2-dimensional representation of the container</param>
|
||||
/// <param name="sortingTableFS2D">2-dimensional representation of the sorting table slots</param>
|
||||
/// <param name="itemWithChildren">Item to place with children</param>
|
||||
/// <param name="playerInventory">Players inventory</param>
|
||||
/// <param name="useSortingTable">Should sorting table to be used if main stash has no space</param>
|
||||
/// <param name="output">Output to send back to client</param>
|
||||
protected void PlaceItemInInventory(
|
||||
int[][] stashFS2D,
|
||||
int[][] sortingTableFS2D,
|
||||
int[,] stashFS2D,
|
||||
int[,] sortingTableFS2D,
|
||||
List<Item> itemWithChildren,
|
||||
BotBaseInventory playerInventory,
|
||||
bool useSortingTable,
|
||||
@@ -387,20 +375,19 @@ public class InventoryHelper(
|
||||
{
|
||||
// Get x/y size of item
|
||||
var rootItem = itemWithChildren[0];
|
||||
var itemSize = GetItemSize(rootItem.Template, rootItem.Id, itemWithChildren);
|
||||
var (sizeX, sizeY) = GetItemSize(rootItem.Template, rootItem.Id, itemWithChildren);
|
||||
|
||||
// Look for a place to slot item into
|
||||
var findSlotResult = _containerHelper.FindSlotForItem(stashFS2D, itemSize[0], itemSize[1]);
|
||||
var findSlotResult = stashFS2D.FindSlotForItem(sizeX, sizeY);
|
||||
if (findSlotResult.Success.Value)
|
||||
{
|
||||
try
|
||||
{
|
||||
_containerHelper.FillContainerMapWithItem(
|
||||
stashFS2D,
|
||||
stashFS2D.FillContainerMapWithItem(
|
||||
findSlotResult.X.Value,
|
||||
findSlotResult.Y.Value,
|
||||
itemSize[0],
|
||||
itemSize[1],
|
||||
sizeX,
|
||||
sizeY,
|
||||
findSlotResult.Rotation.Value
|
||||
);
|
||||
}
|
||||
@@ -411,7 +398,7 @@ public class InventoryHelper(
|
||||
return;
|
||||
}
|
||||
|
||||
// Store details for object, incuding container item will be placed in
|
||||
// Store details for object, including container item will be placed in
|
||||
rootItem.ParentId = playerInventory.Stash;
|
||||
rootItem.SlotId = "hideout";
|
||||
rootItem.Location = new ItemLocation
|
||||
@@ -429,20 +416,15 @@ public class InventoryHelper(
|
||||
// Space not found in main stash, use sorting table
|
||||
if (useSortingTable)
|
||||
{
|
||||
var findSortingSlotResult = _containerHelper.FindSlotForItem(
|
||||
sortingTableFS2D,
|
||||
itemSize[0],
|
||||
itemSize[1]
|
||||
);
|
||||
var findSortingSlotResult = sortingTableFS2D.FindSlotForItem(sizeX, sizeY);
|
||||
|
||||
try
|
||||
{
|
||||
_containerHelper.FillContainerMapWithItem(
|
||||
sortingTableFS2D,
|
||||
sortingTableFS2D.FillContainerMapWithItem(
|
||||
findSortingSlotResult.X.Value,
|
||||
findSortingSlotResult.Y.Value,
|
||||
itemSize[0],
|
||||
itemSize[1],
|
||||
sizeX,
|
||||
sizeY,
|
||||
findSortingSlotResult.Rotation.Value
|
||||
);
|
||||
}
|
||||
@@ -498,12 +480,12 @@ public class InventoryHelper(
|
||||
/// <param name="output">OPTIONAL - ItemEventRouterResponse</param>
|
||||
public void RemoveItem(
|
||||
PmcData profile,
|
||||
string? itemId,
|
||||
MongoId itemId,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse? output = null
|
||||
)
|
||||
{
|
||||
if (itemId is null)
|
||||
if (itemId.IsEmpty())
|
||||
{
|
||||
_logger.Warning(
|
||||
_serverLocalisationService.GetText("inventory-unable_to_remove_item_no_id_given")
|
||||
@@ -533,10 +515,7 @@ public class InventoryHelper(
|
||||
var insuredItems = profile.InsuredItems;
|
||||
|
||||
// We have output object, inform client of root item deletion, not children
|
||||
if (output is not null)
|
||||
{
|
||||
output.ProfileChanges[sessionId].Items.DeletedItems.Add(new Item { Id = itemId });
|
||||
}
|
||||
output?.ProfileChanges[sessionId].Items.DeletedItems.Add(new DeletedItem { Id = itemId });
|
||||
|
||||
foreach (var item in itemAndChildrenToRemove)
|
||||
{
|
||||
@@ -638,13 +617,13 @@ public class InventoryHelper(
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
public ItemEventRouterResponse RemoveItemByCount(
|
||||
PmcData pmcData,
|
||||
string? itemId,
|
||||
MongoId itemId,
|
||||
int countToRemove,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse? output
|
||||
)
|
||||
{
|
||||
if (itemId is null)
|
||||
if (itemId.IsEmpty())
|
||||
{
|
||||
return output;
|
||||
}
|
||||
@@ -689,7 +668,7 @@ public class InventoryHelper(
|
||||
/// <param name="itemId">Items id to get size of</param>
|
||||
/// <param name="inventoryItems"></param>
|
||||
/// <returns>[width, height]</returns>
|
||||
public List<int> GetItemSize(string? itemTpl, string itemId, List<Item> inventoryItems)
|
||||
public (int, int) GetItemSize(MongoId itemTpl, MongoId itemId, List<Item> inventoryItems)
|
||||
{
|
||||
// -> Prepares item Width and height returns [sizeX, sizeY]
|
||||
return GetSizeByInventoryItemHash(itemTpl, itemId, GetInventoryItemHash(inventoryItems));
|
||||
@@ -703,9 +682,9 @@ public class InventoryHelper(
|
||||
/// <param name="itemId">Items id</param>
|
||||
/// <param name="inventoryItemHash">Hashmap of inventory items</param>
|
||||
/// <returns>An array representing the [width, height] of the item</returns>
|
||||
protected List<int> GetSizeByInventoryItemHash(
|
||||
string itemTpl,
|
||||
string itemId,
|
||||
protected (int, int) GetSizeByInventoryItemHash(
|
||||
MongoId itemTpl,
|
||||
MongoId itemId,
|
||||
InventoryItemHash inventoryItemHash
|
||||
)
|
||||
{
|
||||
@@ -738,7 +717,7 @@ public class InventoryHelper(
|
||||
_serverLocalisationService.GetText("inventory-return_default_size", itemTpl)
|
||||
);
|
||||
|
||||
return [1, 1]; // Invalid input data, return defaults
|
||||
return (1, 1); // Invalid input data, return defaults
|
||||
}
|
||||
|
||||
if (!inventoryItemHash.ByItemId.TryGetValue(itemId, out var rootItem))
|
||||
@@ -747,7 +726,7 @@ public class InventoryHelper(
|
||||
$"Unable to get root item with Id: {itemId} from player inventory. Defaulting to 1x1"
|
||||
);
|
||||
|
||||
return [1, 1]; // Invalid input data, return defaults
|
||||
return (1, 1); // Invalid input data, return defaults
|
||||
}
|
||||
|
||||
// Does root item support being folded
|
||||
@@ -869,104 +848,118 @@ public class InventoryHelper(
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
[
|
||||
return (
|
||||
outX.Value + sizeLeft + sizeRight + forcedLeft + forcedRight,
|
||||
outY.Value + sizeUp + sizeDown + forcedUp + forcedDown,
|
||||
];
|
||||
outY.Value + sizeUp + sizeDown + forcedUp + forcedDown
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a 2d mapping of a container with what grid slots are filled
|
||||
/// </summary>
|
||||
/// <param name="sizeX">Horizontal size of container</param>
|
||||
/// <param name="sizeY">Vertical size of container</param>
|
||||
/// <param name="containerSizeHorizontalX">Horizontal (Column) size of container</param>
|
||||
/// <param name="containerSizeVerticalY">Vertical (Row) size of container</param>
|
||||
/// <param name="itemList">Players inventory items</param>
|
||||
/// <param name="containerId">Id of the container</param>
|
||||
/// <returns>Two-dimensional representation of container</returns>
|
||||
public int[][] GetContainerMap(int sizeX, int sizeY, List<Item> itemList, string containerId)
|
||||
public int[,] GetContainerMap(
|
||||
int containerSizeHorizontalX,
|
||||
int containerSizeVerticalY,
|
||||
List<Item> itemList,
|
||||
string containerId
|
||||
)
|
||||
{
|
||||
// Create blank 2d map of container
|
||||
var containerYX = _itemHelper.GetBlankContainerMap(sizeY, sizeX);
|
||||
var container = _itemHelper.GetBlankContainerMap(
|
||||
containerSizeHorizontalX, // Column count
|
||||
containerSizeVerticalY // Row count
|
||||
);
|
||||
|
||||
// Get all items in players inventory keyed by their parentId and by ItemId
|
||||
var inventoryItemHash = GetInventoryItemHash(itemList);
|
||||
|
||||
// Get subset of items that belong to the desired container
|
||||
if (!inventoryItemHash.ByParentId.TryGetValue(containerId, out var rootItemsInContainer))
|
||||
// No items in container, exit early
|
||||
{
|
||||
return containerYX;
|
||||
// No items in container, exit early and return the blank container map
|
||||
return container;
|
||||
}
|
||||
|
||||
// Check each item in container
|
||||
foreach (var item in rootItemsInContainer)
|
||||
// Add every root items size (with mods attached) found in container
|
||||
foreach (var rootItem in rootItemsInContainer)
|
||||
{
|
||||
ItemLocation? itemLocation;
|
||||
if (item.Location is JsonElement element)
|
||||
{
|
||||
// TODO: is this ever true?
|
||||
itemLocation = element.ToObject<ItemLocation>();
|
||||
}
|
||||
else
|
||||
{
|
||||
itemLocation = (ItemLocation?)item.Location;
|
||||
}
|
||||
|
||||
var itemLocation = rootItem.GetParsedLocation();
|
||||
if (itemLocation is null)
|
||||
{
|
||||
// Item has no location property
|
||||
_logger.Error(
|
||||
$"Unable to find 'location' property on item with id: {item.Id}, skipping"
|
||||
$"Unable to find 'location' property on item with id: {rootItem.Id}, skipping"
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get x/y size of item
|
||||
var tmpSize = GetSizeByInventoryItemHash(item.Template, item.Id, inventoryItemHash);
|
||||
var iW = tmpSize[0]; // x
|
||||
var iH = tmpSize[1]; // y
|
||||
var fH = itemLocation.IsVertical() ? iW : iH;
|
||||
var fW = itemLocation.IsVertical() ? iH : iW;
|
||||
// Get x/y size of item (without rotation)
|
||||
var (rawItemXWidth, rawItemYHeight) = GetSizeByInventoryItemHash(
|
||||
rootItem.Template,
|
||||
rootItem.Id,
|
||||
inventoryItemHash
|
||||
);
|
||||
// Items horizontal size
|
||||
var itemHeight = itemLocation.IsVertical() ? rawItemXWidth : rawItemYHeight;
|
||||
|
||||
for (var y = 0; y < fH; y++)
|
||||
// Items vertical size
|
||||
var itemWidth = itemLocation.IsVertical() ? rawItemYHeight : rawItemXWidth;
|
||||
|
||||
// vertical (row)
|
||||
for (var yOffset = 0; yOffset < itemHeight; yOffset++)
|
||||
{
|
||||
try
|
||||
// horizontal (column)
|
||||
for (var xOffset = 0; xOffset < itemWidth; xOffset++)
|
||||
{
|
||||
var rowIndex = itemLocation.Y + y;
|
||||
var containerX = containerYX.ElementAtOrDefault(rowIndex.Value);
|
||||
if (containerX is null)
|
||||
{
|
||||
_logger.Error(
|
||||
$"Unable to find container: {containerId} row line: {itemLocation.Y + y}"
|
||||
);
|
||||
}
|
||||
var currentY = itemLocation.Y.Value + yOffset;
|
||||
var currentX = itemLocation.X.Value + xOffset;
|
||||
|
||||
// Fill the corresponding cells in the container map to show the slot is taken
|
||||
Array.Fill(containerX, 1, itemLocation.X.Value, fW);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(
|
||||
_serverLocalisationService.GetText(
|
||||
"inventory-unable_to_fill_container",
|
||||
new { id = item.Id, error = $"{ex.Message} {ex.StackTrace}" }
|
||||
)
|
||||
);
|
||||
// Check still in containers bounds
|
||||
if (
|
||||
currentY >= 0
|
||||
&& currentY < containerSizeVerticalY
|
||||
&& currentX >= 0
|
||||
&& currentX < containerSizeHorizontalX
|
||||
)
|
||||
{
|
||||
// mark slot used
|
||||
container[currentY, currentX] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Out of bounds
|
||||
var message =
|
||||
$"Item: {rootItem.Id} at: {itemLocation.X}, {itemLocation.Y} size: {itemHeight}x{itemWidth} extends outside the containers bounds";
|
||||
|
||||
_logger.Error(
|
||||
_serverLocalisationService.GetText(
|
||||
"inventory-unable_to_fill_container",
|
||||
new { id = rootItem.Id, error = $"{message}" }
|
||||
)
|
||||
);
|
||||
|
||||
// Stop and try next row
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return containerYX;
|
||||
return container;
|
||||
}
|
||||
|
||||
protected InventoryItemHash GetInventoryItemHash(List<Item> inventoryItems)
|
||||
{
|
||||
var inventoryItemHash = new InventoryItemHash
|
||||
{
|
||||
ByItemId = new Dictionary<string, Item>(),
|
||||
ByParentId = new Dictionary<string, HashSet<Item>>(),
|
||||
ByItemId = new Dictionary<MongoId, Item>(),
|
||||
ByParentId = new Dictionary<MongoId, HashSet<Item>>(),
|
||||
};
|
||||
foreach (var item in inventoryItems)
|
||||
{
|
||||
@@ -977,6 +970,11 @@ public class InventoryHelper(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.ParentId == "hideout")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inventoryItemHash.ByParentId.ContainsKey(item.ParentId))
|
||||
{
|
||||
inventoryItemHash.ByParentId[item.ParentId] = [];
|
||||
@@ -994,12 +992,12 @@ public class InventoryHelper(
|
||||
/// Based on the item action, determine whose inventories we should be looking at for from and to.
|
||||
/// </summary>
|
||||
/// <param name="request">Item interaction request</param>
|
||||
/// <param name="item">Item being moved/split/etc to inventory</param>
|
||||
/// <param name="itemId">Item being moved/split/etc to inventory</param>
|
||||
/// <param name="sessionId">Session id / players Id</param>
|
||||
/// <returns>OwnerInventoryItems with inventory of player/scav to adjust</returns>
|
||||
public OwnerInventoryItems GetOwnerInventoryItems(
|
||||
InventoryBaseActionRequestData request,
|
||||
string? item,
|
||||
MongoId itemId,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
@@ -1023,7 +1021,7 @@ public class InventoryHelper(
|
||||
fromInventoryItems = _dialogueHelper.GetMessageItemContents(
|
||||
request.FromOwner.Id,
|
||||
sessionId,
|
||||
item
|
||||
itemId
|
||||
);
|
||||
fromType = "mail";
|
||||
}
|
||||
@@ -1058,14 +1056,13 @@ public class InventoryHelper(
|
||||
/// 0 value = free, 1 = taken
|
||||
/// </summary>
|
||||
/// <param name="pmcData">Player profile</param>
|
||||
/// <param name="sessionID">session id</param>
|
||||
/// <returns>2-dimensional array</returns>
|
||||
protected int[][]? GetStashSlotMap(PmcData pmcData, string sessionID)
|
||||
protected int[,] GetStashSlotMap(PmcData pmcData)
|
||||
{
|
||||
var playerStashSize = GetPlayerStashSize(sessionID);
|
||||
var (horizontal, vertical) = GetPlayerStashSize(pmcData);
|
||||
return GetContainerMap(
|
||||
playerStashSize[0],
|
||||
playerStashSize[1],
|
||||
horizontal,
|
||||
vertical,
|
||||
pmcData.Inventory.Items,
|
||||
pmcData.Inventory.Stash
|
||||
);
|
||||
@@ -1076,15 +1073,18 @@ public class InventoryHelper(
|
||||
/// </summary>
|
||||
/// <param name="containerTpl">Container to get data for</param>
|
||||
/// <returns>blank two-dimensional array</returns>
|
||||
public int[][] GetContainerSlotMap(string containerTpl)
|
||||
public int[,] GetContainerSlotMap(string containerTpl)
|
||||
{
|
||||
var containerTemplate = _itemHelper.GetItem(containerTpl).Value;
|
||||
|
||||
var firstContainerGrid = containerTemplate.Properties.Grids.FirstOrDefault();
|
||||
var containerH = firstContainerGrid.Props.CellsH;
|
||||
var containerV = firstContainerGrid.Props.CellsV;
|
||||
var containerRowCount = firstContainerGrid.Props.CellsH;
|
||||
var containerColumnCount = firstContainerGrid.Props.CellsV;
|
||||
|
||||
return _itemHelper.GetBlankContainerMap(containerH.Value, containerV.Value);
|
||||
return _itemHelper.GetBlankContainerMap(
|
||||
containerColumnCount.Value,
|
||||
containerRowCount.Value
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1092,7 +1092,7 @@ public class InventoryHelper(
|
||||
/// </summary>
|
||||
/// <param name="pmcData">Player profile</param>
|
||||
/// <returns>two-dimensional array</returns>
|
||||
protected int[][] GetSortingTableSlotMap(PmcData pmcData)
|
||||
protected int[,] GetSortingTableSlotMap(PmcData pmcData)
|
||||
{
|
||||
return GetContainerMap(10, 45, pmcData.Inventory.Items, pmcData.Inventory.SortingTable);
|
||||
}
|
||||
@@ -1100,57 +1100,59 @@ public class InventoryHelper(
|
||||
/// <summary>
|
||||
/// Get Players Stash Size
|
||||
/// </summary>
|
||||
/// <param name="sessionId">Players id</param>
|
||||
/// <returns>Dictionary of 2 values, horizontal and vertical stash size</returns>
|
||||
protected List<int> GetPlayerStashSize(string sessionId)
|
||||
/// <param name="pmcData">Profile to get stash size of</param>
|
||||
/// <returns>Horizontal and vertical size of stash</returns>
|
||||
protected (int, int) GetPlayerStashSize(PmcData pmcData)
|
||||
{
|
||||
var profile = _profileHelper.GetPmcProfile(sessionId);
|
||||
var stashRowBonus = profile.Bonuses.FirstOrDefault(bonus =>
|
||||
bonus.Type == BonusType.StashRows
|
||||
);
|
||||
|
||||
// this sets automatically a stash size from items.json (it's not added anywhere yet because we still use base stash)
|
||||
var stashTPL = GetStashType(sessionId);
|
||||
if (stashTPL is null)
|
||||
// TODO: what??
|
||||
// This sets automatically a stash size from items.json (it's not added anywhere yet because we still use base stash)
|
||||
var stashTpl = GetProfileStashTpl(pmcData);
|
||||
if (stashTpl is null)
|
||||
{
|
||||
_logger.Error(_serverLocalisationService.GetText("inventory-missing_stash_size"));
|
||||
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
var stashItemResult = _itemHelper.GetItem(stashTPL);
|
||||
if (!stashItemResult.Key)
|
||||
// Look up details of stash in db
|
||||
var (isValidItem, stashItemDbItem) = _itemHelper.GetItem(stashTpl);
|
||||
if (!isValidItem)
|
||||
{
|
||||
_logger.Error(
|
||||
_serverLocalisationService.GetText("inventory-stash_not_found", stashTPL)
|
||||
_serverLocalisationService.GetText("inventory-stash_not_found", stashTpl)
|
||||
);
|
||||
|
||||
return new List<int>();
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
var stashItemDetails = stashItemResult.Value;
|
||||
var firstStashItemGrid = stashItemDetails.Properties.Grids[0];
|
||||
// Find the main 'grid' of the stash we can use to get size
|
||||
var firstStashItemGrid = stashItemDbItem?.Properties?.Grids?.FirstOrDefault();
|
||||
|
||||
// Get horizontal and vertical size
|
||||
var stashH = firstStashItemGrid.Props.CellsH != 0 ? firstStashItemGrid.Props.CellsH : 10;
|
||||
var stashV = firstStashItemGrid.Props.CellsV != 0 ? firstStashItemGrid.Props.CellsV : 66;
|
||||
|
||||
// Player has a bonus, apply to vertical size
|
||||
var stashRowBonus = pmcData.Bonuses.FirstOrDefault(bonus =>
|
||||
bonus.Type == BonusType.StashRows
|
||||
);
|
||||
if (stashRowBonus is not null)
|
||||
{
|
||||
stashV += (int)stashRowBonus.Value;
|
||||
}
|
||||
|
||||
return [stashH.Value, stashV.Value];
|
||||
return (stashH.Value, stashV.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the players stash items tpl
|
||||
/// </summary>
|
||||
/// <param name="sessionId">Player id</param>
|
||||
/// <param name="profile">Profile to get tpl</param>
|
||||
/// <returns>Stash tpl</returns>
|
||||
protected string? GetStashType(string sessionId)
|
||||
protected string? GetProfileStashTpl(PmcData profile)
|
||||
{
|
||||
var pmcData = _profileHelper.GetPmcProfile(sessionId);
|
||||
var stashObj = pmcData.Inventory.Items.FirstOrDefault(item =>
|
||||
item.Id == pmcData.Inventory.Stash
|
||||
var stashObj = profile.Inventory.Items.FirstOrDefault(item =>
|
||||
item.Id == profile.Inventory.Stash
|
||||
);
|
||||
if (stashObj is null)
|
||||
{
|
||||
@@ -1172,7 +1174,7 @@ public class InventoryHelper(
|
||||
InventoryMoveRequestData request
|
||||
)
|
||||
{
|
||||
HandleCartridges(sourceItems, request);
|
||||
HandleCartridgeMove(sourceItems, request);
|
||||
|
||||
// Get all children item has, they need to move with item
|
||||
var idsToMove = sourceItems.FindAndReturnChildrenByItems(request.Item);
|
||||
@@ -1229,7 +1231,7 @@ public class InventoryHelper(
|
||||
)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
HandleCartridges(inventoryItems, moveRequest);
|
||||
HandleCartridgeMove(inventoryItems, moveRequest);
|
||||
|
||||
// Find item we want to 'move'
|
||||
var matchingInventoryItem = inventoryItems.FirstOrDefault(item =>
|
||||
@@ -1322,7 +1324,7 @@ public class InventoryHelper(
|
||||
// Reset fast panel value if item was moved to a container other than pocket/rig (cant be used from fastpanel)
|
||||
HashSet<string> slots = ["pockets", "tacticalvest"];
|
||||
var wasMovedToFastPanelAccessibleContainer = slots.Contains(
|
||||
itemParent?.SlotId?.ToLower() ?? ""
|
||||
itemParent?.SlotId?.ToLowerInvariant() ?? ""
|
||||
);
|
||||
if (!wasMovedToFastPanelAccessibleContainer)
|
||||
{
|
||||
@@ -1331,9 +1333,11 @@ public class InventoryHelper(
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal helper function to handle cartridges in inventory if any of them exist.
|
||||
/// Helper function to handle cartridges in inventory if any of them exist.
|
||||
/// </summary>
|
||||
protected void HandleCartridges(List<Item> items, InventoryMoveRequestData request)
|
||||
/// <param name="items"></param>
|
||||
/// <param name="request"></param>
|
||||
protected void HandleCartridgeMove(List<Item> items, InventoryMoveRequestData request)
|
||||
{
|
||||
// Not moving item into a cartridge slot, skip
|
||||
if (request.To.Container != "cartridges")
|
||||
@@ -1352,9 +1356,11 @@ public class InventoryHelper(
|
||||
/// </summary>
|
||||
/// <param name="itemTpl">Container being opened</param>
|
||||
/// <returns>Reward details</returns>
|
||||
public RewardDetails GetRandomLootContainerRewardDetails(string itemTpl)
|
||||
public RewardDetails? GetRandomLootContainerRewardDetails(MongoId itemTpl)
|
||||
{
|
||||
return _inventoryConfig.RandomLootContainers[itemTpl];
|
||||
_inventoryConfig.RandomLootContainers.TryGetValue(itemTpl, out var result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1369,7 +1375,7 @@ public class InventoryHelper(
|
||||
public void ValidateInventoryUsesMongoIds(List<Item> itemsToValidate)
|
||||
{
|
||||
var errors = itemsToValidate
|
||||
.Where(item => !_hashUtil.IsValidMongoId(item.Id))
|
||||
.Where(item => !item.Id.IsValidMongoId())
|
||||
.Select(item => $"Id: {item.Id} - tpl: {item.Template}")
|
||||
.ToList();
|
||||
foreach (var message in errors)
|
||||
@@ -1381,40 +1387,13 @@ public class InventoryHelper(
|
||||
"This profile is not compatible with SPT, See above for a list of incompatible IDs that is not compatible. Loading of SPT has been halted, use another profile or create a new one"
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does the provided item have a root item with the provided id
|
||||
/// </summary>
|
||||
/// <param name="pmcData">Profile with items</param>
|
||||
/// <param name="item">Item to check</param>
|
||||
/// <param name="rootId">Root item id to check for</param>
|
||||
/// <returns>True when item has rootId, false when not</returns>
|
||||
public bool DoesItemHaveRootId(PmcData pmcData, Item item, string rootId)
|
||||
{
|
||||
var currentItem = item;
|
||||
while (currentItem is not null)
|
||||
{
|
||||
// If we've found the equipment root ID, return true
|
||||
if (currentItem.Id == rootId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise get the parent item
|
||||
currentItem = pmcData.Inventory.Items.FirstOrDefault(item =>
|
||||
item.Id == currentItem.ParentId
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class InventoryItemHash
|
||||
{
|
||||
[JsonPropertyName("byItemId")]
|
||||
public Dictionary<string, Item> ByItemId { get; set; }
|
||||
public Dictionary<MongoId, Item> ByItemId { get; set; }
|
||||
|
||||
[JsonPropertyName("byParentId")]
|
||||
public Dictionary<string, HashSet<Item>> ByParentId { get; set; }
|
||||
public Dictionary<MongoId, HashSet<Item>> ByParentId { get; set; }
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class ItemHelper(
|
||||
ICloner _cloner
|
||||
)
|
||||
{
|
||||
protected static readonly FrozenSet<string> _defaultInvalidBaseTypes =
|
||||
protected static readonly FrozenSet<MongoId> _defaultInvalidBaseTypes =
|
||||
[
|
||||
BaseClasses.LOOT_CONTAINER,
|
||||
BaseClasses.MOB_CONTAINER,
|
||||
@@ -57,7 +57,7 @@ public class ItemHelper(
|
||||
nameof(EquipmentSlots.Scabbard),
|
||||
];
|
||||
|
||||
protected static readonly FrozenSet<string> _dogTagTpls =
|
||||
protected static readonly FrozenSet<MongoId> _dogTagTpls =
|
||||
[
|
||||
ItemTpl.BARTER_DOGTAG_BEAR,
|
||||
ItemTpl.BARTER_DOGTAG_BEAR_EOD,
|
||||
@@ -97,7 +97,7 @@ public class ItemHelper(
|
||||
"right_side_plate",
|
||||
];
|
||||
|
||||
protected static readonly FrozenSet<string> _armorSlotsThatCanHoldMods =
|
||||
protected static readonly FrozenSet<MongoId> _armorSlotsThatCanHoldMods =
|
||||
[
|
||||
BaseClasses.HEADWEAR,
|
||||
BaseClasses.VEST,
|
||||
@@ -108,21 +108,21 @@ public class ItemHelper(
|
||||
/// Does the provided pool of items contain the desired item
|
||||
/// </summary>
|
||||
/// <param name="itemPool">Item collection to check</param>
|
||||
/// <param name="item">Item to look for</param>
|
||||
/// <param name="itemTpl">Item to look for</param>
|
||||
/// <param name="slotId">OPTIONAL - slotId of desired item</param>
|
||||
/// <returns>True if pool contains item</returns>
|
||||
public bool HasItemWithTpl(IEnumerable<Item> itemPool, string item, string slotId = "")
|
||||
public bool HasItemWithTpl(IEnumerable<Item> itemPool, MongoId itemTpl, string slotId = "")
|
||||
{
|
||||
// Filter the pool by slotId if provided
|
||||
var filteredPool = string.IsNullOrEmpty(slotId)
|
||||
? itemPool
|
||||
: itemPool.Where(item =>
|
||||
item.SlotId?.StartsWith(slotId, StringComparison.OrdinalIgnoreCase) ?? false
|
||||
: itemPool.Where(itemInPool =>
|
||||
itemInPool.SlotId?.StartsWith(slotId, StringComparison.OrdinalIgnoreCase) ?? false
|
||||
);
|
||||
|
||||
// Check if any item in the filtered pool matches the provided item
|
||||
return filteredPool.Any(poolItem =>
|
||||
string.Equals(poolItem.Template, item, StringComparison.OrdinalIgnoreCase)
|
||||
string.Equals(poolItem.Template, itemTpl, StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ public class ItemHelper(
|
||||
/// <param name="tpl">Item tpl to find</param>
|
||||
/// <param name="slotId">OPTIONAL - slotId of desired item</param>
|
||||
/// <returns>Item or null if no item found</returns>
|
||||
public Item GetItemFromPoolByTpl(IEnumerable<Item> itemPool, string tpl, string slotId = "")
|
||||
public Item GetItemFromPoolByTpl(IEnumerable<Item> itemPool, MongoId tpl, string slotId = "")
|
||||
{
|
||||
// Filter the pool by slotId if provided
|
||||
var filteredPool = string.IsNullOrEmpty(slotId)
|
||||
@@ -143,7 +143,7 @@ public class ItemHelper(
|
||||
);
|
||||
|
||||
// Check if any item in the filtered pool matches the provided item
|
||||
return filteredPool.FirstOrDefault(poolItem => poolItem.Template.Equals(tpl));
|
||||
return filteredPool.FirstOrDefault(poolItem => poolItem.Template == tpl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -283,7 +283,7 @@ public class ItemHelper(
|
||||
/// <param name="tpl">Template id to check</param>
|
||||
/// <param name="invalidBaseTypes">OPTIONAL - Base types deemed invalid</param>
|
||||
/// <returns>true for items that may be in player possession and not quest items</returns>
|
||||
public bool IsValidItem(string tpl, ICollection<string>? invalidBaseTypes = null)
|
||||
public bool IsValidItem(MongoId tpl, ICollection<MongoId>? invalidBaseTypes = null)
|
||||
{
|
||||
var baseTypes = invalidBaseTypes ?? _defaultInvalidBaseTypes;
|
||||
var itemDetails = GetItem(tpl);
|
||||
@@ -306,7 +306,7 @@ public class ItemHelper(
|
||||
/// <param name="tpl">Item template id to check</param>
|
||||
/// <param name="baseClassTpl">Baseclass to check for</param>
|
||||
/// <returns>is the tpl a descendant</returns>
|
||||
public bool IsOfBaseclass(MongoId tpl, string baseClassTpl)
|
||||
public bool IsOfBaseclass(MongoId tpl, MongoId baseClassTpl)
|
||||
{
|
||||
return _itemBaseClassService.ItemHasBaseClass(tpl, [baseClassTpl]);
|
||||
}
|
||||
@@ -317,29 +317,11 @@ public class ItemHelper(
|
||||
/// <param name="tpl">Item to check base classes of</param>
|
||||
/// <param name="baseClassTpls">Base classes to check for</param>
|
||||
/// <returns>True if any supplied base classes match</returns>
|
||||
public bool IsOfBaseclasses(string tpl, ICollection<string> baseClassTpls)
|
||||
public bool IsOfBaseclasses(MongoId tpl, ICollection<MongoId> baseClassTpls)
|
||||
{
|
||||
return _itemBaseClassService.ItemHasBaseClass(tpl, baseClassTpls);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Temporary until we have better MongoId handling
|
||||
/// </summary>
|
||||
/// <param name="tpl"></param>
|
||||
/// <param name="baseClassTpls"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsOfBaseclasses(string tpl, ICollection<MongoId> baseClassTpls)
|
||||
{
|
||||
List<string> MongoList = [];
|
||||
|
||||
foreach (var baseTpl in baseClassTpls)
|
||||
{
|
||||
MongoList.Add(baseTpl);
|
||||
}
|
||||
|
||||
return _itemBaseClassService.ItemHasBaseClass(tpl, MongoList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does the provided item have the chance to require soft armor inserts
|
||||
/// Only applies to helmets/vest/armors
|
||||
@@ -347,7 +329,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="itemTpl">Tpl to check</param>
|
||||
/// <returns>Does item have the possibility ot need soft inserts</returns>
|
||||
public bool ArmorItemCanHoldMods(string itemTpl)
|
||||
public bool ArmorItemCanHoldMods(MongoId itemTpl)
|
||||
{
|
||||
return IsOfBaseclasses(itemTpl, _armorSlotsThatCanHoldMods);
|
||||
}
|
||||
@@ -357,7 +339,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="itemTpl">Armor item</param>
|
||||
/// <returns>True if item needs some kind of insert</returns>
|
||||
public bool ArmorItemHasRemovableOrSoftInsertSlots(string itemTpl)
|
||||
public bool ArmorItemHasRemovableOrSoftInsertSlots(MongoId itemTpl)
|
||||
{
|
||||
if (!ArmorItemCanHoldMods(itemTpl))
|
||||
{
|
||||
@@ -372,12 +354,12 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="itemTpl">Item tpl to check for plate support</param>
|
||||
/// <returns>True when armor can hold plates</returns>
|
||||
public bool ArmorItemHasRemovablePlateSlots(string itemTpl)
|
||||
public bool ArmorItemHasRemovablePlateSlots(MongoId itemTpl)
|
||||
{
|
||||
var itemTemplate = GetItem(itemTpl);
|
||||
|
||||
return itemTemplate.Value.Properties.Slots.Any(slot =>
|
||||
_removablePlateSlotIds.Contains(slot.Name.ToLower())
|
||||
_removablePlateSlotIds.Contains(slot.Name.ToLowerInvariant())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -386,7 +368,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="itemTpl">Item tpl to check</param>
|
||||
/// <returns>True if it needs armor inserts</returns>
|
||||
public bool ItemRequiresSoftInserts(string itemTpl)
|
||||
public bool ItemRequiresSoftInserts(MongoId itemTpl)
|
||||
{
|
||||
// Not a slot that takes soft-inserts
|
||||
if (!ArmorItemCanHoldMods(itemTpl))
|
||||
@@ -408,7 +390,11 @@ public class ItemHelper(
|
||||
}
|
||||
|
||||
// Check if item has slots that match soft insert name ids
|
||||
if (itemDbDetails.Value.Properties.Slots.Any(slot => IsSoftInsertId(slot.Name.ToLower())))
|
||||
if (
|
||||
itemDbDetails.Value.Properties.Slots.Any(slot =>
|
||||
IsSoftInsertId(slot.Name.ToLowerInvariant())
|
||||
)
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -456,7 +442,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="tpl">Item to look price up of</param>
|
||||
/// <returns>Price in roubles</returns>
|
||||
public double? GetItemPrice(string tpl)
|
||||
public double? GetItemPrice(MongoId tpl)
|
||||
{
|
||||
var handbookPrice = GetStaticItemPrice(tpl);
|
||||
if (handbookPrice >= 1)
|
||||
@@ -473,7 +459,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="tpl">Item to look price up of</param>
|
||||
/// <returns>Price in roubles</returns>
|
||||
public double GetItemMaxPrice(string tpl)
|
||||
public double GetItemMaxPrice(MongoId tpl)
|
||||
{
|
||||
var staticPrice = GetStaticItemPrice(tpl);
|
||||
var dynamicPrice = GetDynamicItemPrice(tpl);
|
||||
@@ -486,7 +472,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="tpl">Items tpl id to look up price</param>
|
||||
/// <returns>Price in roubles (0 if not found)</returns>
|
||||
public double GetStaticItemPrice(string tpl)
|
||||
public double GetStaticItemPrice(MongoId tpl)
|
||||
{
|
||||
var handbookPrice = _handbookHelper.GetTemplatePrice(tpl);
|
||||
if (handbookPrice >= 1)
|
||||
@@ -502,7 +488,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="tpl">Items tpl id to look up price</param>
|
||||
/// <returns>Price in roubles (undefined if not found)</returns>
|
||||
public double? GetDynamicItemPrice(string tpl)
|
||||
public double? GetDynamicItemPrice(MongoId tpl)
|
||||
{
|
||||
if (_databaseService.GetPrices().TryGetValue(tpl, out var price))
|
||||
{
|
||||
@@ -526,7 +512,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="itemTpl">template id to look up</param>
|
||||
/// <returns>KvP, key = bool, value = template item object</returns>
|
||||
public KeyValuePair<bool, TemplateItem?> GetItem(string itemTpl)
|
||||
public KeyValuePair<bool, TemplateItem?> GetItem(MongoId itemTpl)
|
||||
{
|
||||
// -> Gets item from <input: _tpl>
|
||||
if (_databaseService.GetItems().TryGetValue(itemTpl, out var item))
|
||||
@@ -542,7 +528,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="itemTpl">Template id of the item to check</param>
|
||||
/// <returns>True if the item has slots</returns>
|
||||
public bool ItemHasSlots(string itemTpl)
|
||||
public bool ItemHasSlots(MongoId itemTpl)
|
||||
{
|
||||
if (_databaseService.GetItems().TryGetValue(itemTpl, out var item))
|
||||
{
|
||||
@@ -557,7 +543,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="itemTpl">Id of the item to check</param>
|
||||
/// <returns>true if the item is in the database</returns>
|
||||
public bool IsItemInDb(string itemTpl)
|
||||
public bool IsItemInDb(MongoId itemTpl)
|
||||
{
|
||||
return _databaseService.GetItems().ContainsKey(itemTpl);
|
||||
}
|
||||
@@ -731,7 +717,7 @@ public class ItemHelper(
|
||||
/// <param name="itemIdToFind">Template id of item to check for</param>
|
||||
/// <param name="assort">List of items to check in</param>
|
||||
/// <returns>List of children of requested item</returns>
|
||||
public List<Item> FindAndReturnChildrenByAssort(string itemIdToFind, List<Item> assort)
|
||||
public List<Item> FindAndReturnChildrenByAssort(MongoId itemIdToFind, List<Item> assort)
|
||||
{
|
||||
List<Item> list = [];
|
||||
foreach (var itemFromAssort in assort)
|
||||
@@ -762,7 +748,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="tpl">Template id to check.</param>
|
||||
/// <returns>True if it is a dogtag.</returns>
|
||||
public bool IsDogtag(string tpl)
|
||||
public bool IsDogtag(MongoId tpl)
|
||||
{
|
||||
return _dogTagTpls.Contains(tpl);
|
||||
}
|
||||
@@ -772,7 +758,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="tpl">Item to check.</param>
|
||||
/// <returns>True if it can be stacked.</returns>
|
||||
public bool? IsItemTplStackable(string tpl)
|
||||
public bool? IsItemTplStackable(MongoId tpl)
|
||||
{
|
||||
if (!_databaseService.GetItems().TryGetValue(tpl, out var item))
|
||||
{
|
||||
@@ -1192,7 +1178,7 @@ public class ItemHelper(
|
||||
/// <param name="tpl">Items tpl to check parents of</param>
|
||||
/// <param name="tplsToCheck">Tpl values to check if parents of item match</param>
|
||||
/// <returns>bool Match found</returns>
|
||||
public bool DoesItemOrParentsIdMatch(string tpl, List<string> tplsToCheck)
|
||||
public bool DoesItemOrParentsIdMatch(MongoId tpl, List<MongoId> tplsToCheck)
|
||||
{
|
||||
var itemDetails = GetItem(tpl);
|
||||
var itemExists = itemDetails.Key;
|
||||
@@ -1277,7 +1263,7 @@ public class ItemHelper(
|
||||
/// <param name="itemId">The unique identifier of the item for which to find the main parent.</param>
|
||||
/// <param name="itemsMap">A Dictionary containing item IDs mapped to their corresponding Item objects for quick lookup.</param>
|
||||
/// <returns>The Item object representing the top-most parent of the given item, or null if no such parent exists.</returns>
|
||||
public Item? GetAttachmentMainParent(string itemId, Dictionary<MongoId, Item> itemsMap)
|
||||
public Item? GetAttachmentMainParent(MongoId itemId, Dictionary<MongoId, Item> itemsMap)
|
||||
{
|
||||
var currentItem = itemsMap.FirstOrDefault(x => x.Key == itemId).Value;
|
||||
|
||||
@@ -1323,7 +1309,7 @@ public class ItemHelper(
|
||||
/// <param name="itemId">The unique identifier of the item for which to find the equipment parent.</param>
|
||||
/// <param name="itemsMap">A Dictionary containing item IDs mapped to their corresponding Item objects for quick lookup.</param>
|
||||
/// <returns>The Item object representing the equipment parent of the given item, or `null` if no such parent exists</returns>
|
||||
public Item? GetEquipmentParent(string itemId, Dictionary<string, Item> itemsMap)
|
||||
public Item? GetEquipmentParent(MongoId itemId, Dictionary<MongoId, Item> itemsMap)
|
||||
{
|
||||
var currentItem = itemsMap.GetValueOrDefault(itemId);
|
||||
|
||||
@@ -1345,11 +1331,9 @@ public class ItemHelper(
|
||||
/// <param name="items">Item with children</param>
|
||||
/// <param name="rootItemId">The base items root id</param>
|
||||
/// <returns>ItemSize object (width and height)</returns>
|
||||
public ItemSize GetItemSize(ICollection<Item> items, string rootItemId)
|
||||
public ItemSize GetItemSize(ICollection<Item> items, MongoId rootItemId)
|
||||
{
|
||||
var rootTemplate = GetItem(
|
||||
items.Where(x => x.Id.Equals(rootItemId)).ToList()[0].Template
|
||||
).Value;
|
||||
var rootTemplate = GetItem(items.FirstOrDefault(x => x.Id == rootItemId).Template).Value;
|
||||
var width = rootTemplate.Properties.Width;
|
||||
var height = rootTemplate.Properties.Height;
|
||||
|
||||
@@ -1364,9 +1348,9 @@ public class ItemHelper(
|
||||
var forcedRight = 0;
|
||||
|
||||
var children = items.FindAndReturnChildrenAsItems(rootItemId);
|
||||
foreach (var ci in children)
|
||||
foreach (var child in children)
|
||||
{
|
||||
var itemTemplate = GetItem(ci.Template).Value;
|
||||
var itemTemplate = GetItem(child.Template).Value;
|
||||
|
||||
// Calculating child ExtraSize
|
||||
if (itemTemplate.Properties.ExtraSizeForceAdd ?? false)
|
||||
@@ -1747,7 +1731,7 @@ public class ItemHelper(
|
||||
/// </summary>
|
||||
/// <param name="itemTpl">Tpl of item to get name of</param>
|
||||
/// <returns>Full name, short name if not found</returns>
|
||||
public string GetItemName(string itemTpl)
|
||||
public string GetItemName(MongoId itemTpl)
|
||||
{
|
||||
var localeDb = _localeService.GetLocaleDb();
|
||||
var result = localeDb[$"{itemTpl} Name"];
|
||||
@@ -1802,9 +1786,9 @@ public class ItemHelper(
|
||||
if (modSpawnChanceDict is not null && !(slot.Required ?? false))
|
||||
{
|
||||
// only roll chance to not include mod if dict exists and has value for this mod type (e.g. front_plate)
|
||||
if (modSpawnChanceDict.ContainsKey(slot.Name.ToLower()))
|
||||
if (modSpawnChanceDict.ContainsKey(slot.Name.ToLowerInvariant()))
|
||||
{
|
||||
if (!_randomUtil.GetChance100(modSpawnChanceDict[slot.Name.ToLower()]))
|
||||
if (!_randomUtil.GetChance100(modSpawnChanceDict[slot.Name.ToLowerInvariant()]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1905,7 +1889,7 @@ public class ItemHelper(
|
||||
/// <returns>True if it is a slot that holds a removable plate</returns>
|
||||
public bool IsRemovablePlateSlot(string slotName)
|
||||
{
|
||||
return GetRemovablePlateSlotIds().Contains(slotName.ToLower());
|
||||
return GetRemovablePlateSlotIds().Contains(slotName.ToLowerInvariant());
|
||||
}
|
||||
|
||||
// Get a list of slot names that hold removable plates
|
||||
@@ -2023,7 +2007,7 @@ public class ItemHelper(
|
||||
|
||||
// Return all tpls from Money enum
|
||||
// Returns string tpls
|
||||
public List<string> GetMoneyTpls()
|
||||
public List<MongoId> GetMoneyTpls()
|
||||
{
|
||||
return [Money.ROUBLES, Money.DOLLARS, Money.EUROS, Money.GP];
|
||||
}
|
||||
@@ -2042,7 +2026,7 @@ public class ItemHelper(
|
||||
);
|
||||
}
|
||||
|
||||
public string? GetItemBaseType(string tpl, bool rootOnly = true)
|
||||
public string? GetItemBaseType(MongoId tpl, bool rootOnly = true)
|
||||
{
|
||||
var result = GetItem(tpl);
|
||||
if (!result.Key)
|
||||
@@ -2077,7 +2061,7 @@ public class ItemHelper(
|
||||
/// Get a 2D grid of a container's item slots
|
||||
/// </summary>
|
||||
/// <param name="containerTpl">Tpl id of the container</param>
|
||||
public int[][] GetContainerMapping(string containerTpl)
|
||||
public int[,] GetContainerMapping(string containerTpl)
|
||||
{
|
||||
// Get template from db
|
||||
var containerTemplate = GetItem(containerTpl).Value;
|
||||
@@ -2086,25 +2070,18 @@ public class ItemHelper(
|
||||
var height = containerTemplate.Properties.Grids[0].Props.CellsV;
|
||||
var width = containerTemplate.Properties.Grids[0].Props.CellsH;
|
||||
|
||||
return GetBlankContainerMap(height.Value, width.Value);
|
||||
return GetBlankContainerMap(width.Value, height.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a blank two-dimensional representation of a container
|
||||
/// </summary>
|
||||
/// <param name="containerY">Horizontal size of container</param>
|
||||
/// <param name="containerX">Vertical size of container</param>
|
||||
/// <param name="horizontalSizeX">Width of container (columns)</param>
|
||||
/// <param name="verticalSizeY">Height of container (rows)</param>
|
||||
/// <returns>Two-dimensional representation of container</returns>
|
||||
public int[][] GetBlankContainerMap(int containerY, int containerX)
|
||||
public int[,] GetBlankContainerMap(int horizontalSizeX, int verticalSizeY)
|
||||
{
|
||||
//var x = new int[containerY][];
|
||||
//for (int i = 0; i < containerY; i++)
|
||||
//{
|
||||
// x[i] = new int[containerH];
|
||||
//}
|
||||
|
||||
//return x;
|
||||
|
||||
return Enumerable.Range(0, containerY).Select(_ => new int[containerX]).ToArray();
|
||||
// Rows / Columns
|
||||
return new int[verticalSizeY, horizontalSizeX];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,17 +5,8 @@ using SPTarkov.Server.Core.Utils;
|
||||
namespace SPTarkov.Server.Core.Helpers;
|
||||
|
||||
[Injectable]
|
||||
public class ModHelper
|
||||
public class ModHelper(FileUtil fileUtil, JsonUtil jsonUtil)
|
||||
{
|
||||
private readonly FileUtil _fileUtil;
|
||||
private readonly JsonUtil _jsonUtil;
|
||||
|
||||
public ModHelper(FileUtil fileUtil, JsonUtil jsonUtil)
|
||||
{
|
||||
_fileUtil = fileUtil;
|
||||
_jsonUtil = jsonUtil;
|
||||
}
|
||||
|
||||
public string GetAbsolutePathToModFolder(Assembly modAssembly)
|
||||
{
|
||||
// The full path to the mod folder
|
||||
@@ -25,15 +16,15 @@ public class ModHelper
|
||||
public string GetRawFileData(string pathToFile, string fileName)
|
||||
{
|
||||
// Read the content of the config file as a string
|
||||
return _fileUtil.ReadFile(Path.Combine(pathToFile, fileName));
|
||||
return fileUtil.ReadFile(Path.Combine(pathToFile, fileName));
|
||||
}
|
||||
|
||||
public T GetJsonDataFromFile<T>(string pathToFile, string fileName)
|
||||
{
|
||||
// Read the content of the config file as a string
|
||||
var rawContent = _fileUtil.ReadFile(Path.Combine(pathToFile, fileName));
|
||||
var rawContent = fileUtil.ReadFile(Path.Combine(pathToFile, fileName));
|
||||
|
||||
// Take the string above and deserialise it into a file with a type (defined between the diamond brackets)
|
||||
return _jsonUtil.Deserialize<T>(rawContent);
|
||||
return jsonUtil.Deserialize<T>(rawContent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
using SPTarkov.Server.Core.Models.Eft.Profile;
|
||||
using SPTarkov.Server.Core.Models.Eft.Ws;
|
||||
using SPTarkov.Server.Core.Models.Enums;
|
||||
@@ -15,7 +16,6 @@ namespace SPTarkov.Server.Core.Helpers;
|
||||
public class NotificationSendHelper(
|
||||
ISptLogger<NotificationSendHelper> _logger,
|
||||
SptWebSocketConnectionHandler _sptWebSocketConnectionHandler,
|
||||
HashUtil _hashUtil,
|
||||
SaveServer _saveServer,
|
||||
NotificationService _notificationService,
|
||||
TimeUtil _timeUtil,
|
||||
@@ -76,7 +76,7 @@ public class NotificationSendHelper(
|
||||
dialog.New += 1;
|
||||
var message = new Message
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
UserId = dialog.Id,
|
||||
MessageType = messageType,
|
||||
DateTime = _timeUtil.GetTimeStamp(),
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
using SPTarkov.Server.Core.Models.Eft.Profile;
|
||||
using SPTarkov.Server.Core.Models.Eft.Ws;
|
||||
using SPTarkov.Server.Core.Utils;
|
||||
|
||||
namespace SPTarkov.Server.Core.Helpers;
|
||||
|
||||
[Injectable(InjectionType.Singleton)]
|
||||
public class NotifierHelper(HttpServerHelper httpServerHelper, HashUtil hashUtil)
|
||||
public class NotifierHelper(HttpServerHelper httpServerHelper)
|
||||
{
|
||||
protected static readonly WsPing ping = new();
|
||||
|
||||
@@ -57,7 +57,7 @@ public class NotifierHelper(HttpServerHelper httpServerHelper, HashUtil hashUtil
|
||||
return new WsRagfairNewRating
|
||||
{
|
||||
EventType = NotificationEventType.RagfairNewRating,
|
||||
EventIdentifier = hashUtil.Generate(),
|
||||
EventIdentifier = new MongoId(),
|
||||
Rating = rating,
|
||||
IsRatingGrowing = isGrowing,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
using SPTarkov.Server.Core.Models.Enums;
|
||||
using SPTarkov.Server.Core.Models.Spt.Config;
|
||||
using SPTarkov.Server.Core.Servers;
|
||||
@@ -10,7 +11,7 @@ public class PaymentHelper(ConfigServer configServer)
|
||||
{
|
||||
protected bool _addedCustomMoney;
|
||||
protected readonly InventoryConfig _inventoryConfig = configServer.GetConfig<InventoryConfig>();
|
||||
protected readonly HashSet<string> _moneyTpls =
|
||||
protected readonly HashSet<MongoId> _moneyTpls =
|
||||
[
|
||||
Money.DOLLARS,
|
||||
Money.EUROS,
|
||||
@@ -23,7 +24,7 @@ public class PaymentHelper(ConfigServer configServer)
|
||||
/// </summary>
|
||||
/// <param name="tpl">Item Tpl to check</param>
|
||||
/// <returns></returns>
|
||||
public bool IsMoneyTpl(string tpl)
|
||||
public bool IsMoneyTpl(MongoId tpl)
|
||||
{
|
||||
// Add custom currency first time this method is accessed
|
||||
if (!_addedCustomMoney)
|
||||
|
||||
@@ -17,9 +17,9 @@ public class PresetHelper(DatabaseService _databaseService, ItemHelper _itemHelp
|
||||
/// <summary>
|
||||
/// Preset cache - key = item tpl, value = preset ids
|
||||
/// </summary>
|
||||
protected Dictionary<string, PresetCacheDetails> _lookup = new();
|
||||
protected Dictionary<MongoId, PresetCacheDetails> _lookup = new();
|
||||
|
||||
public void HydratePresetStore(Dictionary<string, PresetCacheDetails> input)
|
||||
public void HydratePresetStore(Dictionary<MongoId, PresetCacheDetails> input)
|
||||
{
|
||||
_lookup = input;
|
||||
}
|
||||
@@ -113,7 +113,7 @@ public class PresetHelper(DatabaseService _databaseService, ItemHelper _itemHelp
|
||||
* @param baseClass The BaseClasses enum to check against
|
||||
* @returns True if the preset is of the given base class, false otherwise
|
||||
*/
|
||||
public bool IsPresetBaseClass(string id, string baseClass)
|
||||
public bool IsPresetBaseClass(string id, MongoId baseClass)
|
||||
{
|
||||
return IsPreset(id) && _itemHelper.IsOfBaseclass(GetPreset(id).Encyclopedia, baseClass);
|
||||
}
|
||||
@@ -123,7 +123,7 @@ public class PresetHelper(DatabaseService _databaseService, ItemHelper _itemHelp
|
||||
/// </summary>
|
||||
/// <param name="templateId">Tpl id to check</param>
|
||||
/// <returns>True if preset exists for tpl</returns>
|
||||
public bool HasPreset(string templateId)
|
||||
public bool HasPreset(MongoId templateId)
|
||||
{
|
||||
return _lookup.ContainsKey(templateId);
|
||||
}
|
||||
@@ -169,7 +169,7 @@ public class PresetHelper(DatabaseService _databaseService, ItemHelper _itemHelp
|
||||
/// </summary>
|
||||
/// <param name="templateId">Items tpl to get preset for</param>
|
||||
/// <returns>null if no default preset, otherwise Preset</returns>
|
||||
public Preset? GetDefaultPreset(string templateId)
|
||||
public Preset? GetDefaultPreset(MongoId templateId)
|
||||
{
|
||||
// look in main cache for presets for this tpl
|
||||
if (!_lookup.TryGetValue(templateId, out var presetDetails))
|
||||
@@ -202,7 +202,7 @@ public class PresetHelper(DatabaseService _databaseService, ItemHelper _itemHelp
|
||||
/// </summary>
|
||||
/// <param name="presetId">Preset id to look up</param>
|
||||
/// <returns>tpl mongoid</returns>
|
||||
public string GetBaseItemTpl(string presetId)
|
||||
public MongoId GetBaseItemTpl(MongoId presetId)
|
||||
{
|
||||
if (!_databaseService.GetGlobals().ItemPresets.TryGetValue(presetId, out var preset))
|
||||
{
|
||||
@@ -225,7 +225,7 @@ public class PresetHelper(DatabaseService _databaseService, ItemHelper _itemHelp
|
||||
/// </summary>
|
||||
/// <param name="tpl">The item template to get the price of</param>
|
||||
/// <returns>The price of the given item preset, or base item if no preset exists</returns>
|
||||
public double GetDefaultPresetOrItemPrice(string tpl)
|
||||
public double GetDefaultPresetOrItemPrice(MongoId tpl)
|
||||
{
|
||||
// Get default preset if it exists
|
||||
var defaultPreset = GetDefaultPreset(tpl);
|
||||
|
||||
@@ -123,8 +123,8 @@ public class ProfileHelper(
|
||||
&& !StringsMatch(p.ProfileInfo.ProfileId, sessionID)
|
||||
&& // SessionIds dont match
|
||||
StringsMatch(
|
||||
p.CharacterData.PmcData.Info.LowerNickname.ToLower(),
|
||||
nicknameRequest.Nickname.ToLower()
|
||||
p.CharacterData.PmcData.Info.LowerNickname.ToLowerInvariant(),
|
||||
nicknameRequest.Nickname.ToLowerInvariant()
|
||||
)
|
||||
); // Nicknames do
|
||||
}
|
||||
@@ -564,7 +564,7 @@ public class ProfileHelper(
|
||||
public bool IsDeveloperAccount(string sessionID)
|
||||
{
|
||||
return GetFullProfile(sessionID)
|
||||
?.ProfileInfo?.Edition?.ToLower()
|
||||
?.ProfileInfo?.Edition?.ToLowerInvariant()
|
||||
.StartsWith("spt developer") ?? false;
|
||||
}
|
||||
|
||||
@@ -602,24 +602,6 @@ public class ProfileHelper(
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterate over all bonuses and sum up all bonuses of desired type in provided profile
|
||||
/// </summary>
|
||||
/// <param name="pmcProfile">Player profile</param>
|
||||
/// <param name="desiredBonus">Bonus to sum up</param>
|
||||
/// <returns>Summed bonus value or 0 if no bonus found</returns>
|
||||
public double GetBonusValueFromProfile(PmcData pmcProfile, BonusType desiredBonus)
|
||||
{
|
||||
var bonuses = pmcProfile?.Bonuses?.Where(b => b.Type == desiredBonus);
|
||||
if (bonuses is null || !bonuses.Any())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sum all bonuses found above
|
||||
return bonuses?.Sum(bonus => bonus?.Value ?? 0) ?? 0;
|
||||
}
|
||||
|
||||
public bool HasAccessToRepeatableFreeRefreshSystem(PmcData pmcProfile)
|
||||
{
|
||||
return _gameEditionsWithFreeRefresh.Contains(pmcProfile.Info.GameVersion);
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Globalization;
|
||||
using SPTarkov.Common.Extensions;
|
||||
using SPTarkov.DI.Annotations;
|
||||
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.Eft.ItemEvent;
|
||||
@@ -57,19 +58,6 @@ public class QuestHelper(
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get status of a quest in player profile by its id
|
||||
/// </summary>
|
||||
/// <param name="pmcData">Profile to search</param>
|
||||
/// <param name="questId">Quest id to look up</param>
|
||||
/// <returns>QuestStatus enum</returns>
|
||||
public QuestStatusEnum GetQuestStatus(PmcData pmcData, string questId)
|
||||
{
|
||||
var quest = pmcData.Quests?.FirstOrDefault(q => q.QId == questId);
|
||||
|
||||
return quest?.Status ?? QuestStatusEnum.Locked;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// returns true if the level condition is satisfied
|
||||
/// </summary>
|
||||
@@ -636,7 +624,7 @@ public class QuestHelper(
|
||||
/// <param name="output">ItemEvent router response</param>
|
||||
public void ChangeItemStack(
|
||||
PmcData pmcData,
|
||||
string itemId,
|
||||
MongoId itemId,
|
||||
int newStackSize,
|
||||
string sessionID,
|
||||
ItemEventRouterResponse output
|
||||
@@ -666,7 +654,9 @@ public class QuestHelper(
|
||||
{
|
||||
// this case is probably dead Code right now, since the only calling function
|
||||
// checks explicitly for Value > 0.
|
||||
output.ProfileChanges[sessionID].Items.DeletedItems.Add(new Item { Id = itemId });
|
||||
output
|
||||
.ProfileChanges[sessionID]
|
||||
.Items.DeletedItems.Add(new DeletedItem { Id = itemId });
|
||||
pmcData.Inventory.Items.RemoveAt(inventoryItemIndex);
|
||||
}
|
||||
}
|
||||
@@ -965,7 +955,7 @@ public class QuestHelper(
|
||||
/// <param name="pmcData">Profile to update</param>
|
||||
/// <param name="newQuestState">New state the quest should be in</param>
|
||||
/// <param name="questId">Id of the quest to alter the status of</param>
|
||||
public void UpdateQuestState(PmcData pmcData, QuestStatusEnum newQuestState, string questId)
|
||||
protected void UpdateQuestState(PmcData pmcData, QuestStatusEnum newQuestState, string questId)
|
||||
{
|
||||
// Find quest in profile, update status to desired status
|
||||
var questToUpdate = pmcData.Quests.FirstOrDefault(quest => quest.QId == questId);
|
||||
@@ -1021,8 +1011,8 @@ public class QuestHelper(
|
||||
/// <param name="allQuests">All quests to check</param>
|
||||
/// <returns>quest id with 'FindItem' condition id</returns>
|
||||
public Dictionary<string, string> GetFindItemConditionByQuestItem(
|
||||
string itemTpl,
|
||||
string[] questIds,
|
||||
MongoId itemTpl,
|
||||
MongoId[] questIds,
|
||||
List<Quest> allQuests
|
||||
)
|
||||
{
|
||||
@@ -1604,12 +1594,12 @@ public class QuestHelper(
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for newly available quests after completing a quest with a requirement to wait x minutes (time-locked) before being available and add data to profile
|
||||
* @param pmcData Player profile to update
|
||||
* @param quests Quests to look for wait conditions in
|
||||
* @param completedQuestId Quest just completed
|
||||
*/
|
||||
/// <summary>
|
||||
/// Look for newly available quests after completing a quest with a requirement to wait x minutes (time-locked) before being available and add data to profile
|
||||
/// </summary>
|
||||
/// <param name="pmcData">Player profile to update</param>
|
||||
/// <param name="quests">Quests to look for wait conditions in</param>
|
||||
/// <param name="completedQuestId">Quest just completed</param>
|
||||
protected void AddTimeLockedQuestsToProfile(
|
||||
PmcData pmcData,
|
||||
List<Quest> quests,
|
||||
|
||||
@@ -15,7 +15,6 @@ public class RagfairHelper(
|
||||
TraderAssortHelper traderAssortHelper,
|
||||
DatabaseService databaseService,
|
||||
HandbookHelper handbookHelper,
|
||||
ItemHelper itemHelper,
|
||||
RagfairLinkedItemService ragfairLinkedItemService,
|
||||
ConfigServer configServer,
|
||||
ICloner cloner
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using SPTarkov.Common.Extensions;
|
||||
using SPTarkov.DI.Annotations;
|
||||
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.Eft.ItemEvent;
|
||||
@@ -20,7 +21,6 @@ namespace SPTarkov.Server.Core.Helpers;
|
||||
public class RagfairOfferHelper(
|
||||
ISptLogger<RagfairOfferHelper> _logger,
|
||||
TimeUtil _timeUtil,
|
||||
HashUtil _hashUtil,
|
||||
BotHelper _botHelper,
|
||||
RagfairSortHelper _ragfairSortHelper,
|
||||
PresetHelper _presetHelper,
|
||||
@@ -112,7 +112,7 @@ public class RagfairOfferHelper(
|
||||
protected void CheckAndLockOfferFromPlayerTieredFlea(
|
||||
TieredFlea tieredFlea,
|
||||
RagfairOffer offer,
|
||||
List<string> tieredFleaLimitTypes,
|
||||
List<MongoId> tieredFleaLimitTypes,
|
||||
int playerLevel
|
||||
)
|
||||
{
|
||||
@@ -819,7 +819,7 @@ public class RagfairOfferHelper(
|
||||
// Create an item template item
|
||||
var requestedItem = new Item
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Id = new MongoId(),
|
||||
Template = requirement.Template,
|
||||
Upd = new Upd { StackObjectsCount = requirement.Count * boughtAmount },
|
||||
};
|
||||
@@ -881,7 +881,7 @@ public class RagfairOfferHelper(
|
||||
* @param boughtAmount How many were purchased
|
||||
* @returns Localised message text
|
||||
*/
|
||||
protected string GetLocalisedOfferSoldMessage(string itemTpl, int boughtAmount)
|
||||
protected string GetLocalisedOfferSoldMessage(MongoId itemTpl, int boughtAmount)
|
||||
{
|
||||
// Generate a message to inform that item was sold
|
||||
var globalLocales = _localeService.GetLocaleDb();
|
||||
@@ -896,7 +896,7 @@ public class RagfairOfferHelper(
|
||||
}
|
||||
|
||||
// Used to replace tokens in sold message sent to player
|
||||
var messageKey = $"{itemTpl} Name";
|
||||
var messageKey = $"{itemTpl.ToString()} Name";
|
||||
var hasKey = globalLocales.TryGetValue(messageKey, out var value);
|
||||
|
||||
var tplVars = new SystemData
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.Extensions;
|
||||
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.Config;
|
||||
@@ -18,7 +19,6 @@ public class RagfairServerHelper(
|
||||
TimeUtil timeUtil,
|
||||
DatabaseService databaseService,
|
||||
ItemHelper itemHelper,
|
||||
TraderHelper traderHelper,
|
||||
WeightedRandomHelper weightedRandomHelper,
|
||||
MailSendService mailSendService,
|
||||
ServerLocalisationService localisationService,
|
||||
@@ -99,7 +99,7 @@ public class RagfairServerHelper(
|
||||
* @param itemTemplateId Item tpl to check is blacklisted
|
||||
* @returns True if its blacklisted
|
||||
*/
|
||||
protected bool IsItemOnCustomFleaBlacklist(string itemTemplateId)
|
||||
protected bool IsItemOnCustomFleaBlacklist(MongoId itemTemplateId)
|
||||
{
|
||||
return ragfairConfig.Dynamic.Blacklist.Custom.Contains(itemTemplateId);
|
||||
}
|
||||
@@ -146,7 +146,7 @@ public class RagfairServerHelper(
|
||||
);
|
||||
}
|
||||
|
||||
public int CalculateDynamicStackCount(string tplId, bool isPreset)
|
||||
public int CalculateDynamicStackCount(MongoId tplId, bool isPreset)
|
||||
{
|
||||
var config = ragfairConfig.Dynamic;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ using SPTarkov.Server.Core.Models.Spt.Config;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
using SPTarkov.Server.Core.Servers;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
using SPTarkov.Server.Core.Utils;
|
||||
using SPTarkov.Server.Core.Utils.Cloners;
|
||||
|
||||
namespace SPTarkov.Server.Core.Helpers;
|
||||
@@ -16,7 +15,6 @@ public class RepeatableQuestHelper(
|
||||
ISptLogger<RepeatableQuestHelper> logger,
|
||||
DatabaseService databaseService,
|
||||
ServerLocalisationService serverLocalisationService,
|
||||
HashUtil hashUtil,
|
||||
ICloner cloner,
|
||||
ConfigServer configServer
|
||||
)
|
||||
@@ -88,7 +86,7 @@ public class RepeatableQuestHelper(
|
||||
return null;
|
||||
}
|
||||
|
||||
quest.Id = hashUtil.Generate();
|
||||
quest.Id = new MongoId();
|
||||
quest.TraderId = traderId;
|
||||
|
||||
return quest;
|
||||
@@ -202,7 +200,7 @@ public class RepeatableQuestHelper(
|
||||
return null;
|
||||
}
|
||||
|
||||
questData.QuestStatus.Id = hashUtil.Generate();
|
||||
questData.QuestStatus.Id = new MongoId();
|
||||
questData.QuestStatus.Uid = sessionId; // Needs to match user id
|
||||
questData.QuestStatus.QId = questData.Id; // Needs to match quest id
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.Extensions;
|
||||
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
|
||||
|
||||
namespace SPTarkov.Server.Core.Helpers;
|
||||
|
||||
[Injectable]
|
||||
public class SecureContainerHelper(ItemHelper _itemHelper)
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a list of the item IDs (NOT tpls) inside a secure container
|
||||
/// </summary>
|
||||
/// <param name="items">Inventory items to look for secure container in</param>
|
||||
/// <returns>List of ids</returns>
|
||||
public List<string> GetSecureContainerItems(List<Item> items)
|
||||
{
|
||||
var secureContainer = items.First(x => x.SlotId == "SecuredContainer");
|
||||
|
||||
// No container found, drop out
|
||||
if (secureContainer is null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var itemsInSecureContainer = items.FindAndReturnChildrenByItems(secureContainer.Id);
|
||||
|
||||
// Return all items returned and exclude the secure container item itself
|
||||
return itemsInSecureContainer.Where(x => x != secureContainer.Id).ToList();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using SPTarkov.DI.Annotations;
|
||||
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.Eft.Inventory;
|
||||
@@ -19,7 +20,6 @@ namespace SPTarkov.Server.Core.Helpers;
|
||||
[Injectable]
|
||||
public class TradeHelper(
|
||||
ISptLogger<TradeHelper> _logger,
|
||||
DatabaseService _databaseService,
|
||||
TraderHelper _traderHelper,
|
||||
ItemHelper _itemHelper,
|
||||
QuestHelper _questHelper,
|
||||
@@ -415,7 +415,7 @@ public record PurchaseDetails
|
||||
|
||||
public record PurchaseItems
|
||||
{
|
||||
public string ItemId { get; set; }
|
||||
public MongoId ItemId { get; set; }
|
||||
|
||||
public double Count { get; set; }
|
||||
}
|
||||
|
||||
@@ -526,7 +526,7 @@ public class TraderHelper(
|
||||
/// </summary>
|
||||
/// <param name="tpl">Item to look up highest price for</param>
|
||||
/// <returns>highest rouble cost for item</returns>
|
||||
public double GetHighestTraderPriceRouble(string tpl)
|
||||
public double GetHighestTraderPriceRouble(MongoId tpl)
|
||||
{
|
||||
if (_highestTraderPriceItems is not null)
|
||||
{
|
||||
@@ -580,7 +580,7 @@ public class TraderHelper(
|
||||
/// </summary>
|
||||
/// <param name="tpl">Item to look up best trader sell-to price</param>
|
||||
/// <returns>Rouble price</returns>
|
||||
public double GetHighestSellToTraderPrice(string tpl)
|
||||
public double GetHighestSellToTraderPrice(MongoId tpl)
|
||||
{
|
||||
// Find largest trader price for item
|
||||
var highestPrice = 1d; // Default price
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
using SPTarkov.Server.Core.Models.Spt.Helper;
|
||||
using SPTarkov.Server.Core.Models.Utils;
|
||||
using SPTarkov.Server.Core.Services;
|
||||
@@ -111,7 +112,7 @@ public class WeightedRandomHelper(
|
||||
/// Find the greated common divisor of all weights and use it on the passed in dictionary
|
||||
/// </summary>
|
||||
/// <param name="weightedDict">Values to reduce</param>
|
||||
public void ReduceWeightValues(IDictionary<string, double> weightedDict)
|
||||
public void ReduceWeightValues(IDictionary<MongoId, double> weightedDict)
|
||||
{
|
||||
// No values, nothing to reduce
|
||||
if (weightedDict.Count == 0)
|
||||
|
||||
@@ -11,7 +11,7 @@ public record IdWithCount
|
||||
/// ID of stack to take money from
|
||||
/// </summary>
|
||||
[JsonPropertyName("id")]
|
||||
public string? Id { get; set; }
|
||||
public MongoId Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Amount of money to take off player for treatment
|
||||
|
||||
@@ -1,39 +1,32 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using SPTarkov.Server.Core.Extensions;
|
||||
|
||||
namespace SPTarkov.Server.Core.Models.Common;
|
||||
|
||||
public readonly partial struct MongoId : IEquatable<MongoId>
|
||||
public readonly struct MongoId : IEquatable<MongoId>
|
||||
{
|
||||
private readonly string _stringId;
|
||||
private readonly string? _stringId;
|
||||
|
||||
public MongoId(
|
||||
string id,
|
||||
// TODO: TEMPORARY REMOVE ME WHEN DONE!!!!
|
||||
[CallerFilePath] string callerFilePath = "",
|
||||
[CallerMemberName] string methodName = "",
|
||||
[CallerLineNumber] int callerLineNumber = 0
|
||||
)
|
||||
public MongoId(string? id)
|
||||
{
|
||||
// This is temporary, otherwise item buying is broken as when LINQ searches for string id's it's possible null is passed
|
||||
if (id == null)
|
||||
// Handle null strings, various id's are null either by BSG or by our own doing with LINQ
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
id = string.Empty;
|
||||
_stringId = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (id.Length != 24)
|
||||
{
|
||||
// TODO: Items.json root item has an empty parentId property
|
||||
Console.WriteLine(
|
||||
$"Critical MongoId error [{callerFilePath}::{methodName} L{callerLineNumber}]: Incorrect length. id: {id}"
|
||||
);
|
||||
Console.WriteLine($"Critical MongoId error: Incorrect length. id: {id}");
|
||||
}
|
||||
|
||||
if (!IsValidMongoId(id))
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"Critical MongoId error [{callerFilePath}::{methodName} L{callerLineNumber}]: Incorrect format. Must be a hexadecimal [a-f0-9] of 24 characters. id: {id}"
|
||||
$"Critical MongoId error: Incorrect format. Must be a hexadecimal [a-f0-9] of 24 characters. id: {id}"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -92,7 +85,7 @@ public readonly partial struct MongoId : IEquatable<MongoId>
|
||||
{
|
||||
if (other is null)
|
||||
{
|
||||
return other == this;
|
||||
return this == null;
|
||||
}
|
||||
|
||||
return other.Equals(ToString(), StringComparison.InvariantCultureIgnoreCase);
|
||||
@@ -135,7 +128,7 @@ public readonly partial struct MongoId : IEquatable<MongoId>
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _stringId.GetHashCode();
|
||||
return (_stringId ?? string.Empty).GetHashCode();
|
||||
}
|
||||
|
||||
public bool IsEmpty()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
using SPTarkov.Server.Core.Utils.Json;
|
||||
|
||||
namespace SPTarkov.Server.Core.Models.Eft.Common;
|
||||
@@ -147,7 +148,7 @@ public record StaticForced
|
||||
public string ContainerId { get; set; }
|
||||
|
||||
[JsonPropertyName("itemTpl")]
|
||||
public string ItemTpl { get; set; }
|
||||
public MongoId ItemTpl { get; set; }
|
||||
}
|
||||
|
||||
public record StaticContainerData
|
||||
|
||||
@@ -291,7 +291,7 @@ public record LocationBase
|
||||
public long? UnixDateTime { get; set; }
|
||||
|
||||
[JsonPropertyName("_Id")]
|
||||
public string? IdField { get; set; }
|
||||
public MongoId IdField { get; set; }
|
||||
|
||||
[JsonPropertyName("doors")]
|
||||
public List<object>? Doors { get; set; }
|
||||
|
||||
@@ -14,7 +14,7 @@ public record BotBase
|
||||
public Dictionary<string, object>? ExtensionData { get; set; }
|
||||
|
||||
[JsonPropertyName("_id")]
|
||||
public string? Id { get; set; }
|
||||
public MongoId? Id { get; set; }
|
||||
|
||||
[JsonPropertyName("aid")]
|
||||
[JsonConverter(typeof(StringToNumberFactoryConverter))]
|
||||
@@ -28,7 +28,7 @@ public record BotBase
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
[JsonPropertyName("savage")]
|
||||
public string? Savage { get; set; }
|
||||
public MongoId? Savage { get; set; }
|
||||
|
||||
[JsonPropertyName("karmaValue")]
|
||||
public double? KarmaValue { get; set; }
|
||||
@@ -53,10 +53,10 @@ public record BotBase
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
[JsonPropertyName("Encyclopedia")]
|
||||
public Dictionary<string, bool>? Encyclopedia { get; set; }
|
||||
public Dictionary<MongoId, bool>? Encyclopedia { get; set; }
|
||||
|
||||
[JsonPropertyName("TaskConditionCounters")]
|
||||
public Dictionary<string, TaskConditionCounter>? TaskConditionCounters { get; set; }
|
||||
public Dictionary<MongoId, TaskConditionCounter>? TaskConditionCounters { get; set; }
|
||||
|
||||
[JsonPropertyName("InsuredItems")]
|
||||
public List<InsuredItem>? InsuredItems { get; set; }
|
||||
@@ -82,7 +82,7 @@ public record BotBase
|
||||
/// </summary>
|
||||
[JsonPropertyName("Achievements")]
|
||||
[JsonConverter(typeof(ArrayToObjectFactoryConverter))]
|
||||
public Dictionary<string, long>? Achievements { get; set; }
|
||||
public Dictionary<MongoId, long>? Achievements { get; set; }
|
||||
|
||||
[JsonPropertyName("RepeatableQuests")]
|
||||
public List<PmcDataRepeatableQuest>? RepeatableQuests { get; set; }
|
||||
@@ -105,7 +105,7 @@ public record BotBase
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
[JsonPropertyName("WishList")]
|
||||
[JsonConverter(typeof(ArrayToObjectFactoryConverter))]
|
||||
public DictionaryOrList<string, int>? WishList { get; set; }
|
||||
public DictionaryOrList<MongoId, int>? WishList { get; set; }
|
||||
|
||||
[JsonPropertyName("moneyTransferLimitData")]
|
||||
public MoneyTransferLimits? MoneyTransferLimitData { get; set; }
|
||||
@@ -571,7 +571,7 @@ public record DroppedItem
|
||||
|
||||
public string? QuestId { get; set; }
|
||||
|
||||
public string? ItemId { get; set; }
|
||||
public MongoId? ItemId { get; set; }
|
||||
|
||||
public string? ZoneId { get; set; }
|
||||
}
|
||||
@@ -583,7 +583,7 @@ public record FoundInRaidItem
|
||||
|
||||
public string? QuestId { get; set; }
|
||||
|
||||
public string? ItemId { get; set; }
|
||||
public MongoId? ItemId { get; set; }
|
||||
}
|
||||
|
||||
public record Victim
|
||||
@@ -826,7 +826,7 @@ public record Hideout
|
||||
/// </summary>
|
||||
public string? Seed { get; set; }
|
||||
|
||||
public Dictionary<string, string>? MannequinPoses { get; set; }
|
||||
public Dictionary<string, MongoId>? MannequinPoses { get; set; }
|
||||
|
||||
[JsonPropertyName("sptUpdateLastRunTimestamp")]
|
||||
public long? SptUpdateLastRunTimestamp { get; set; }
|
||||
@@ -938,7 +938,7 @@ public record Production // use this instead of productive and scavcase
|
||||
[JsonPropertyName("sptIsCultistCircle")]
|
||||
public bool? SptIsCultistCircle { get; set; }
|
||||
|
||||
public string? RecipeId { get; set; }
|
||||
public MongoId RecipeId { get; set; }
|
||||
}
|
||||
|
||||
public record BotHideoutArea
|
||||
@@ -1094,7 +1094,7 @@ public record Bonus
|
||||
public Dictionary<string, object>? ExtensionData { get; set; }
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public MongoId? Id { get; set; }
|
||||
public MongoId Id { get; set; }
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
|
||||
@@ -358,7 +358,7 @@ public record GenerationData
|
||||
/// </summary>
|
||||
[JsonPropertyName("whitelist")]
|
||||
[JsonConverter(typeof(ArrayToObjectFactoryConverter))]
|
||||
public Dictionary<string, double>? Whitelist { get; set; }
|
||||
public Dictionary<MongoId, double>? Whitelist { get; set; }
|
||||
}
|
||||
|
||||
public record GenerationWeightingItems
|
||||
@@ -496,15 +496,15 @@ public record ItemPools
|
||||
[JsonExtensionData]
|
||||
public Dictionary<string, object>? ExtensionData { get; set; }
|
||||
|
||||
public Dictionary<string, double>? Backpack { get; set; }
|
||||
public Dictionary<MongoId, double>? Backpack { get; set; }
|
||||
|
||||
public Dictionary<string, double>? Pockets { get; set; }
|
||||
public Dictionary<MongoId, double>? Pockets { get; set; }
|
||||
|
||||
public Dictionary<string, double>? SecuredContainer { get; set; }
|
||||
public Dictionary<MongoId, double>? SecuredContainer { get; set; }
|
||||
|
||||
public Dictionary<string, double>? SpecialLoot { get; set; }
|
||||
public Dictionary<MongoId, double>? SpecialLoot { get; set; }
|
||||
|
||||
public Dictionary<string, double>? TacticalVest { get; set; }
|
||||
public Dictionary<MongoId, double>? TacticalVest { get; set; }
|
||||
}
|
||||
|
||||
public record BotDbSkills
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
|
||||
namespace SPTarkov.Server.Core.Models.Eft.Common.Tables;
|
||||
|
||||
@@ -20,11 +21,11 @@ public record HandbookCategory
|
||||
public Dictionary<string, object>? ExtensionData { get; set; }
|
||||
|
||||
[JsonPropertyName("Id")]
|
||||
public string? Id { get; set; }
|
||||
public MongoId Id { get; set; }
|
||||
|
||||
[JsonPropertyName("ParentId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public string? ParentId { get; set; }
|
||||
public MongoId? ParentId { get; set; }
|
||||
|
||||
[JsonPropertyName("Icon")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
@@ -43,11 +44,11 @@ public record HandbookItem
|
||||
public Dictionary<string, object>? ExtensionData { get; set; }
|
||||
|
||||
[JsonPropertyName("Id")]
|
||||
public string? Id { get; set; }
|
||||
public MongoId Id { get; set; }
|
||||
|
||||
[JsonPropertyName("ParentId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public string? ParentId { get; set; }
|
||||
public MongoId ParentId { get; set; }
|
||||
|
||||
[JsonPropertyName("Price")]
|
||||
public double? Price { get; set; }
|
||||
|
||||
@@ -58,19 +58,11 @@ public record HideoutItem
|
||||
public MongoId _Id
|
||||
{
|
||||
get { return Id; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Id = value;
|
||||
}
|
||||
set { Id = value; }
|
||||
}
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public required MongoId Id { get; set; }
|
||||
public MongoId Id { get; set; }
|
||||
|
||||
[JsonPropertyName("_tpl")]
|
||||
public required MongoId Template { get; set; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
using SPTarkov.Server.Core.Models.Enums;
|
||||
using SPTarkov.Server.Core.Utils.Json.Converters;
|
||||
|
||||
@@ -72,7 +73,7 @@ public record TraderService
|
||||
public Dictionary<string, ServiceItemCostDetails>? ServiceItemCost { get; set; }
|
||||
|
||||
[JsonPropertyName("UniqueItems")]
|
||||
public List<string>? UniqueItems { get; set; }
|
||||
public List<MongoId>? UniqueItems { get; set; }
|
||||
}
|
||||
|
||||
public record ServiceRequirements
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
|
||||
namespace SPTarkov.Server.Core.Models.Eft.Common.Tables;
|
||||
|
||||
@@ -8,7 +9,7 @@ public record LocationsGenerateAllResponse
|
||||
public Dictionary<string, object>? ExtensionData { get; set; }
|
||||
|
||||
[JsonPropertyName("locations")]
|
||||
public Dictionary<string, LocationBase> Locations { get; set; }
|
||||
public Dictionary<MongoId, LocationBase> Locations { get; set; }
|
||||
|
||||
[JsonPropertyName("paths")]
|
||||
public List<Path>? Paths { get; set; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
using SPTarkov.Server.Core.Models.Enums;
|
||||
using SPTarkov.Server.Core.Utils.Json;
|
||||
using SPTarkov.Server.Core.Utils.Json.Converters;
|
||||
@@ -20,7 +21,7 @@ public record Quest
|
||||
/// _id
|
||||
/// </summary>
|
||||
[JsonPropertyName("_id")]
|
||||
public required string Id { get; set; }
|
||||
public required MongoId Id { get; set; }
|
||||
|
||||
[JsonPropertyName("canShowNotificationsInGame")]
|
||||
public required bool CanShowNotificationsInGame { get; set; }
|
||||
@@ -144,7 +145,7 @@ public record QuestStatus
|
||||
public Dictionary<string, object>? ExtensionData { get; set; }
|
||||
|
||||
[JsonPropertyName("qid")]
|
||||
public required string QId { get; set; }
|
||||
public required MongoId QId { get; set; }
|
||||
|
||||
[JsonPropertyName("startTime")]
|
||||
public required double StartTime { get; set; }
|
||||
@@ -189,7 +190,7 @@ public record QuestCondition
|
||||
public Dictionary<string, object>? ExtensionData { get; set; }
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public required string Id { get; set; }
|
||||
public required MongoId Id { get; set; }
|
||||
|
||||
[JsonPropertyName("index")]
|
||||
public int? Index { get; set; }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user