From 7c060fdf8601bba3a7b114043561584bc1560dc9 Mon Sep 17 00:00:00 2001 From: clodan Date: Wed, 29 Jan 2025 11:47:42 +0000 Subject: [PATCH 1/8] RandomUtil fixes --- .../Generators/RepeatableQuestGenerator.cs | 2 +- .../RepeatableQuestRewardGenerator.cs | 8 +- Libraries/Core/Helpers/RepairHelper.cs | 4 +- Libraries/Core/Helpers/TraderHelper.cs | 4 +- .../Core/Services/CircleOfCultistService.cs | 6 +- Libraries/Core/Services/RepairService.cs | 4 +- Libraries/Core/Utils/RandomUtil.cs | 128 ++++++------------ UnitTests/Tests/Test.cs | 2 +- UnitTests/Tests/Utils/RandomUtilTests.cs | 43 +++--- 9 files changed, 81 insertions(+), 120 deletions(-) diff --git a/Libraries/Core/Generators/RepeatableQuestGenerator.cs b/Libraries/Core/Generators/RepeatableQuestGenerator.cs index 5ffb0e9b..26533f68 100644 --- a/Libraries/Core/Generators/RepeatableQuestGenerator.cs +++ b/Libraries/Core/Generators/RepeatableQuestGenerator.cs @@ -515,7 +515,7 @@ public class RepeatableQuestGenerator( ); // Be fair, don't var the items be more expensive than the reward - var multi = _randomUtil.GetFloat((float)0.5, 1); + var multi = _randomUtil.GetDouble(0.5, 1); var roublesBudget = Math.Floor( (double)(_mathUtil.Interp1(pmcLevel, levelsConfig, roublesConfig) * multi) ); diff --git a/Libraries/Core/Generators/RepeatableQuestRewardGenerator.cs b/Libraries/Core/Generators/RepeatableQuestRewardGenerator.cs index cfffd78c..79f96ec6 100644 --- a/Libraries/Core/Generators/RepeatableQuestRewardGenerator.cs +++ b/Libraries/Core/Generators/RepeatableQuestRewardGenerator.cs @@ -264,7 +264,7 @@ public class RepeatableQuestRewardGenerator( return Math.Floor( effectiveDifficulty * _mathUtil.Interp1(pmcLevel, levelsConfig, xpConfig) * - _randomUtil.GetFloat((float)(1 - rewardSpreadConfig), (float)(1 + rewardSpreadConfig)) ?? + _randomUtil.GetDouble((double)(1 - rewardSpreadConfig), (double)(1 + rewardSpreadConfig)) ?? 0 ); } @@ -276,7 +276,7 @@ public class RepeatableQuestRewardGenerator( return Math.Ceiling( effectiveDifficulty * _mathUtil.Interp1(pmcLevel, levelsConfig, gpCoinConfig) * - _randomUtil.GetFloat((float)(1 - rewardSpreadConfig), (float)(1 + rewardSpreadConfig)) ?? + _randomUtil.GetDouble((double)(1 - rewardSpreadConfig), (double)(1 + rewardSpreadConfig)) ?? 0 ); } @@ -289,7 +289,7 @@ public class RepeatableQuestRewardGenerator( 100 * effectiveDifficulty * _mathUtil.Interp1(pmcLevel, levelsConfig, reputationConfig) * - _randomUtil.GetFloat((float)(1 - rewardSpreadConfig), (float)(1 + rewardSpreadConfig)) ?? + _randomUtil.GetDouble((double)(1 - rewardSpreadConfig), (double)(1 + rewardSpreadConfig)) ?? 0 ) / 100; @@ -307,7 +307,7 @@ public class RepeatableQuestRewardGenerator( return Math.Floor( effectiveDifficulty * _mathUtil.Interp1(pmcLevel, levelsConfig, roublesConfig) * - _randomUtil.GetFloat((float)(1 - rewardSpreadConfig), (float)(1 + rewardSpreadConfig)) ?? + _randomUtil.GetDouble((double)(1 - rewardSpreadConfig), (double)(1 + rewardSpreadConfig)) ?? 0 ); } diff --git a/Libraries/Core/Helpers/RepairHelper.cs b/Libraries/Core/Helpers/RepairHelper.cs index a1c87609..04c2af26 100644 --- a/Libraries/Core/Helpers/RepairHelper.cs +++ b/Libraries/Core/Helpers/RepairHelper.cs @@ -124,7 +124,7 @@ public class RepairHelper( ? armorMaterialSettings.MaxRepairKitDegradation : armorMaterialSettings.MaxRepairDegradation; - var duraLossPercent = _randomUtil.GetFloat((float)minMultiplier, (float)maxMultiplier); + var duraLossPercent = _randomUtil.GetDouble((double)minMultiplier, (double)maxMultiplier); var duraLossMultipliedByTraderMultiplier = duraLossPercent * armorMax * traderQualityMultipler; return Math.Round(duraLossMultipliedByTraderMultiplier, 2); @@ -153,7 +153,7 @@ public class RepairHelper( maxRepairDeg = itemProps.MaxRepairDegradation; } - var duraLossPercent = _randomUtil.GetFloat((float)minRepairDeg, (float)maxRepairDeg); + var duraLossPercent = _randomUtil.GetDouble((double)minRepairDeg, (double)maxRepairDeg); var duraLossMultipliedByTraderMultiplier = duraLossPercent * weaponMax * traderQualityMultipler; return Math.Round(duraLossMultipliedByTraderMultiplier, 2); diff --git a/Libraries/Core/Helpers/TraderHelper.cs b/Libraries/Core/Helpers/TraderHelper.cs index 387f30ac..0721608b 100644 --- a/Libraries/Core/Helpers/TraderHelper.cs +++ b/Libraries/Core/Helpers/TraderHelper.cs @@ -582,9 +582,7 @@ public class TraderHelper( var traderBuyBackPricePercent = traderBase.LoyaltyLevels.FirstOrDefault().BuyPriceCoefficient; var itemHandbookPrice = _handbookHelper.GetTemplatePrice(tpl); - var priceTraderBuysItemAt = Math.Round( - _randomUtil.GetPercentOfValue(traderBuyBackPricePercent ?? 0, itemHandbookPrice ?? 0) - ); + var priceTraderBuysItemAt = _randomUtil.GetPercentOfValue(traderBuyBackPricePercent ?? 0, itemHandbookPrice ?? 0, 0); // Price from this trader is higher than highest found, update if (priceTraderBuysItemAt > highestPrice) diff --git a/Libraries/Core/Services/CircleOfCultistService.cs b/Libraries/Core/Services/CircleOfCultistService.cs index 6b2ebba3..c8f66a1a 100644 --- a/Libraries/Core/Services/CircleOfCultistService.cs +++ b/Libraries/Core/Services/CircleOfCultistService.cs @@ -126,9 +126,9 @@ public class CircleOfCultistService( private double GetRewardAmountMultiplier(PmcData pmcData, CultistCircleSettings cultistCircleSettings) { // Get a randomised value to multiply the sacrificed rouble cost by - var rewardAmountMultiplier = _randomUtil.GetFloat( - (float)cultistCircleSettings.RewardPriceMultiplerMinMax.Min, - (float)cultistCircleSettings.RewardPriceMultiplerMinMax.Max + var rewardAmountMultiplier = _randomUtil.GetDouble( + (double)cultistCircleSettings.RewardPriceMultiplerMinMax.Min, + (double)cultistCircleSettings.RewardPriceMultiplerMinMax.Max ); // Adjust value generated by the players hideout management skill diff --git a/Libraries/Core/Services/RepairService.cs b/Libraries/Core/Services/RepairService.cs index d012a00e..7a848c72 100644 --- a/Libraries/Core/Services/RepairService.cs +++ b/Libraries/Core/Services/RepairService.cs @@ -529,9 +529,7 @@ public class RepairService( Rarity = bonusRarityName, BuffType = bonusTypeName, Value = bonusValue, - ThresholdDurability = Math.Round( - _randomUtil.GetPercentOfValue(bonusThresholdPercent, item.Upd.Repairable.Durability.Value) - ) + ThresholdDurability = _randomUtil.GetPercentOfValue(bonusThresholdPercent, item.Upd.Repairable.Durability.Value, 0) }; } diff --git a/Libraries/Core/Utils/RandomUtil.cs b/Libraries/Core/Utils/RandomUtil.cs index c64c44fd..06a8cd9d 100644 --- a/Libraries/Core/Utils/RandomUtil.cs +++ b/Libraries/Core/Utils/RandomUtil.cs @@ -11,6 +11,8 @@ namespace Core.Utils; public class RandomUtil(ISptLogger _logger, ICloner _cloner) { public readonly Random Random = new(); + private const int DecimalPointRandomPrecision = 6; + private static readonly int DecimalPointRandomPrecisionMultiplier = (int) Math.Pow(10, DecimalPointRandomPrecision); /// /// The IEEE-754 standard for double-precision floating-point numbers limits the number of digits (including both @@ -22,40 +24,20 @@ public class RandomUtil(ISptLogger _logger, ICloner _cloner) /// Generates a random integer between the specified minimum and maximum values, inclusive. /// /// The minimum value (inclusive). - /// The maximum value (inclusive). + /// The maximum value (optional). + /// If max is exclusive or not. /// A random integer between the specified minimum and maximum values. - public int GetInt(int min, int max) + public int GetInt(int min, int max = int.MaxValue, bool exclusive = false) { // Prevents a potential integer overflow. - if (max == int.MaxValue) max -= 1; + if (exclusive && max == int.MaxValue) + { + max -= 1; + } - // maxVal is exclusive of the passed value, so add 1 - return max > min ? Random.Next(min, max + 1) : min; + return max > min ? Random.Next(min, exclusive ? max : max + 1) : min; } - - /// - /// Generates a random integer between 1 (inclusive) and the specified maximum value (exclusive). - /// If the maximum value is less than or equal to 1, it returns 1. - /// - /// The upper bound (exclusive) for the random integer generation. - /// A random integer between 1 and max - 1, or 1 if max is less than or equal to 1. - public int GetIntEx(int max) - { - return max > 2 ? Random.Next(1, max - 1) : 1; - } - - /// - /// Generates a random floating-point number within the specified range ~6-9 digits (4 bytes). - /// - /// The minimum value of the range (inclusive). - /// The maximum value of the range (exclusive). - /// A random floating-point number between `min` (inclusive) and `max` (exclusive). - public float GetFloat(float min, float max) - { - return (float)GetSecureRandomNumber() * (max - min) + min; - } - - + /// /// Generates a random floating-point number within the specified range ~15-17 digits (8 bytes). /// @@ -64,7 +46,13 @@ public class RandomUtil(ISptLogger _logger, ICloner _cloner) /// A random floating-point number between `min` (inclusive) and `max` (exclusive). public double GetDouble(double min, double max) { - return GetSecureRandomNumber() * (max - min) + min; + var realMin = (long) (min * DecimalPointRandomPrecisionMultiplier); + var realMax = (long) (max * DecimalPointRandomPrecisionMultiplier); + + return Math.Round( + Random.NextInt64(realMin, realMax) / (double)DecimalPointRandomPrecisionMultiplier, + DecimalPointRandomPrecision + ); } /// @@ -73,7 +61,7 @@ public class RandomUtil(ISptLogger _logger, ICloner _cloner) /// A random boolean value, where the probability of `true` and `false` is approximately equal. public bool GetBool() { - return GetSecureRandomNumber() < 0.5; + return Random.Next(0, 2) == 1; } /// @@ -83,11 +71,11 @@ public class RandomUtil(ISptLogger _logger, ICloner _cloner) /// The number to calculate the percentage of. /// The number of decimal places to round the result to (default is 2). /// The calculated percentage of the given number, rounded to the specified number of decimal places. - public float GetPercentOfValue(double percent, double number, int toFixed = 2) + public double GetPercentOfValue(double percent, double number, int toFixed = 2) { var num = percent * number / 100; - return (float)Math.Round(num, toFixed); + return Math.Round(num, toFixed); } /// @@ -110,9 +98,9 @@ public class RandomUtil(ISptLogger _logger, ICloner _cloner) /// `true` if the event occurs, `false` otherwise. public bool GetChance100(double? chancePercent) { - chancePercent = Math.Clamp(chancePercent ?? 0, 0f, 100f); + chancePercent = Math.Clamp(chancePercent ?? 0, 0D, 100D); - return GetIntEx(100) <= chancePercent; + return GetInt(0, 100) <= chancePercent; } /// @@ -196,7 +184,7 @@ public class RandomUtil(ISptLogger _logger, ICloner _cloner) // Check if the generated value is valid if (valueDrawn < 0) return attempt > 100 - ? GetDouble(0.01f, mean * 2f) + ? GetDouble(0.01D, mean * 2D) : GetNormallyDistributedRandomNumber(mean, sigma, attempt + 1); return valueDrawn; @@ -229,42 +217,20 @@ public class RandomUtil(ISptLogger _logger, ICloner _cloner) /// and MaxSignificantDigits(15), inclusive. If not provided, precision is determined by the input values. /// /// - public double RandNum(double val1, double val2 = 0, byte? precision = null) + public double RandNum(double val1, double val2 = 0, int precision = DecimalPointRandomPrecision) { if (!double.IsFinite(val1) || !double.IsFinite(val2)) throw new ArgumentException("RandNum() parameters 'value1' and 'value2' must be finite numbers."); // Determine the range var min = Math.Min(val1, val2); var max = Math.Max(val1, val2); - - // Validate and adjust precision - if (precision is not null) - { - if (precision > MaxSignificantDigits) - throw new ArgumentOutOfRangeException( - nameof(precision), "Must be less than 16"); - - // Calculate the number of whole-number digits in the maximum absolute value of the range - var maxAbsoluteValue = Math.Max(Math.Abs(min), Math.Abs(max)); - var wholeNumberDigits = (int)Math.Floor(Math.Log10(maxAbsoluteValue)) + 1; - - var maxAllowedPrecision = Math.Max(0, MaxSignificantDigits - wholeNumberDigits); - - if (precision > maxAllowedPrecision) - throw new ArgumentException( - $"RandNum() precision of {precision} exceeds the allowable precision ({maxAllowedPrecision}) for the given values." - ); - } - - var result = GetSecureRandomNumber() * (max - min) + min; - - // Determine effective precision - var maxPrecision = Math.Max(GetNumberPrecision(val1), GetNumberPrecision(val2)); - var effectivePrecision = precision ?? maxPrecision; - - var factor = Math.Pow(2, effectivePrecision); - - return Math.Round(result * factor) / factor; + + var realPrecision = (long) Math.Pow(10, precision); + + var minInt = (long) (min * realPrecision); + var maxInt = (long) (max * realPrecision); + + return Math.Round(Random.NextInt64(minInt, maxInt) / (double) realPrecision, precision); } /// @@ -436,23 +402,9 @@ public class RandomUtil(ISptLogger _logger, ICloner _cloner) /// produce a floating-point number in the range [0, 1). /// /// A secure random number between 0 (inclusive) and 1 (exclusive). - private static double GetSecureRandomNumber() + private double GetSecureRandomNumber() { - var buffer = new byte[6]; // 48 bits - using (var rng = RandomNumberGenerator.Create()) - { - rng.GetBytes(buffer); - } - - // Convert byte array to unsigned long - ulong value = 0; - for (var i = 0; i < buffer.Length; i++) - { - value |= (ulong)buffer[i] << (8 * (buffer.Length - 1 - i)); - } - - const ulong maxInteger = 281474976710656; // 2^48 - return (double)value / maxInteger; + return Random.NextSingle(); } /// @@ -462,11 +414,13 @@ public class RandomUtil(ISptLogger _logger, ICloner _cloner) /// The number of decimal places, or 0 if none exist. public int GetNumberPrecision(double num) { - var parts = num.ToString($"G{MaxSignificantDigits}").Split('.'); - - return parts.Length > 1 - ? parts[1].Length - : 0; + var factor = 0; + while (num % 1 > double.Epsilon) + { + num *= 10D; + factor++; + } + return factor; } public T? GetArrayValue(IEnumerable list) diff --git a/UnitTests/Tests/Test.cs b/UnitTests/Tests/Test.cs index 72e3b20d..0b88ab2a 100644 --- a/UnitTests/Tests/Test.cs +++ b/UnitTests/Tests/Test.cs @@ -14,7 +14,7 @@ public class Test public void Setup() { - var importer = new ImporterUtil(new MockLogger(), new FileUtil(), new JsonUtil()); + var importer = new ImporterUtil(new MockLogger(), new FileUtil(new MockLogger()), new JsonUtil()); var loadTask = importer.LoadRecursiveAsync("./TestAssets/"); loadTask.Wait(); _templates = loadTask.Result; diff --git a/UnitTests/Tests/Utils/RandomUtilTests.cs b/UnitTests/Tests/Utils/RandomUtilTests.cs index 170d18a9..2a52e541 100644 --- a/UnitTests/Tests/Utils/RandomUtilTests.cs +++ b/UnitTests/Tests/Utils/RandomUtilTests.cs @@ -12,8 +12,8 @@ public sealed class RandomUtilTests [TestMethod] public void GetIntTest() { - // Run 100 test cases - for (var i = 0; i < 100; i++) + // Run 10000 test cases + for (var i = 0; i < 10000; i++) { var result = _randomUtil.GetInt(0, 10); @@ -27,10 +27,10 @@ public sealed class RandomUtilTests [TestMethod] public void GetIntExTest() { - // Run 100 test cases - for (var i = 0; i < 100; i++) + // Run 10000 test cases + for (var i = 0; i < 10000; i++) { - var result = _randomUtil.GetIntEx(10); + var result = _randomUtil.GetInt(1, 10, true); if (result < 1 || result > 9) { @@ -40,16 +40,16 @@ public sealed class RandomUtilTests } [TestMethod] - public void GetFloatTest() + public void GetDoubleTest() { - // Run 100 test cases - for (var i = 0; i < 100; i++) + // Run 10000 test cases + for (var i = 0; i < 10000; i++) { - var result = _randomUtil.GetFloat(0f, 10f); + var result = _randomUtil.GetDouble(0D, 10D); - if (result < 0f || result >= 9f) + if (result is < 0d or >= 10d) { - Assert.Fail($"GetFloat(0f, 10f) out of range. Expected range [0.0f, 9.999f] but was {result}."); + Assert.Fail($"GetDouble(0d, 10d) out of range. Expected range [0.0d, 9.999d] but was {result}."); } } } @@ -135,11 +135,11 @@ public sealed class RandomUtilTests [TestMethod] public void RandNumTest() { - for (var i = 0; i < 100; i++) + for (var i = 0; i < 10000; i++) { - var result = _randomUtil.RandNum(0, 10); + var result = _randomUtil.RandNum(0, 10, 15); - if (result < 0 || result > 9) + if (result < 0 || result >= 10) { Assert.Fail($"RandNum(0, 10) out of range. Expected range [0, 9.999d] but was {result}."); } @@ -150,11 +150,11 @@ public sealed class RandomUtilTests } } - for (var i = 0; i < 100; i++) + for (var i = 0; i < 10000; i++) { var result = _randomUtil.RandNum(10); - if (result < 0 || result > 9) + if (result < 0 || result >= 10) { Assert.Fail($"RandNum(10) out of range. Expected range [0, 9.999d] but was {result}."); } @@ -182,4 +182,15 @@ public sealed class RandomUtilTests result.SequenceEqual(orig), $"Shuffle test failed. Expected: {string.Join(", ", orig)}, but got {string.Join(", ", result)}"); } + + [TestMethod] + [DataRow(0.1, 1)] + [DataRow(0.0001, 4)] + [DataRow(0, 0)] + [DataRow(10000000, 0)] + [DataRow(0.000_000_000_000_1D, 13)] + public void GetNumberPrecision_WithDoubles_ReturnsDecimalPoints(double value, int decimalPoints) + { + Assert.AreEqual(decimalPoints, _randomUtil.GetNumberPrecision(value)); + } } From 1b5f1c5784dabf2d98901e85fa1f984adee2488b Mon Sep 17 00:00:00 2001 From: Chomp Date: Wed, 29 Jan 2025 11:53:11 +0000 Subject: [PATCH 2/8] Replaced magic strings inside `OpenRandomLootContainer` --- Libraries/Core/Controllers/InventoryController.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Libraries/Core/Controllers/InventoryController.cs b/Libraries/Core/Controllers/InventoryController.cs index af4c5e5d..132f4861 100644 --- a/Libraries/Core/Controllers/InventoryController.cs +++ b/Libraries/Core/Controllers/InventoryController.cs @@ -257,9 +257,9 @@ public class InventoryController( var rewards = new List>(); var unlockedWeaponCrates = new List { - "665829424de4820934746ce6", - "665732e7ac60f009f270d1ef", - "665888282c4a1b73af576b77" + ItemTpl.RANDOMLOOTCONTAINER_ARENA_WEAPONCRATE_VIOLET_OPEN, + ItemTpl.RANDOMLOOTCONTAINER_ARENA_WEAPONCRATE_BLUE_OPEN, + ItemTpl.RANDOMLOOTCONTAINER_ARENA_WEAPONCRATE_GREEN_OPEN }; // Temp fix for unlocked weapon crate hideout craft if (isSealedWeaponBox || unlockedWeaponCrates.Contains(containerDetailsDb.Value.Id)) From 73cb11c47d7d8b92c10d9f9c12bc8ce811179467 Mon Sep 17 00:00:00 2001 From: Chomp Date: Wed, 29 Jan 2025 12:12:01 +0000 Subject: [PATCH 3/8] Various changes --- Libraries/Core/Callbacks/ProfileCallbacks.cs | 6 ++-- .../Core/Controllers/HideoutController.cs | 4 +-- .../Core/Controllers/ProfileController.cs | 3 +- .../Core/Controllers/RagfairController.cs | 4 +-- .../Core/Generators/BotInventoryGenerator.cs | 30 +++++++++---------- Libraries/Core/Generators/LootGenerator.cs | 2 +- .../Core/Generators/PlayerScavGenerator.cs | 2 +- .../Generators/ScavCaseRewardGenerator.cs | 6 ++-- Libraries/Core/Helpers/DialogueHelper.cs | 9 ++---- Libraries/Core/Helpers/InventoryHelper.cs | 17 +++++------ Libraries/Core/Helpers/ItemHelper.cs | 4 +-- Libraries/Core/Helpers/TradeHelper.cs | 10 +++---- .../Models/Eft/Common/Tables/TemplateItem.cs | 6 ++-- Libraries/Core/Routers/HttpRouter.cs | 3 ++ .../Routers/SaveLoad/HealthSaveLoadRouter.cs | 4 +-- .../Routers/SaveLoad/InraidSaveLoadRouter.cs | 4 +-- .../SaveLoad/InsuranceSaveLoadRouter.cs | 4 +-- .../Routers/SaveLoad/ProfileSaveLoadRouter.cs | 4 +-- .../Routers/Static/ProfileStaticRouter.cs | 4 +-- 19 files changed, 63 insertions(+), 63 deletions(-) diff --git a/Libraries/Core/Callbacks/ProfileCallbacks.cs b/Libraries/Core/Callbacks/ProfileCallbacks.cs index 6bb922ec..5688c21f 100644 --- a/Libraries/Core/Callbacks/ProfileCallbacks.cs +++ b/Libraries/Core/Callbacks/ProfileCallbacks.cs @@ -1,4 +1,4 @@ -using SptCommon.Annotations; +using SptCommon.Annotations; using Core.Controllers; using Core.Helpers; using Core.Models.Eft.Common; @@ -131,9 +131,9 @@ public class ProfileCallbacks( /** * Handle client/game/profile/search */ - public string SearchFriend(string url, SearchFriendRequestData info, string sessionID) + public string SearchProfiles(string url, SearchProfilesRequestData info, string sessionID) { - return _httpResponse.GetBody(_profileController.GetFriends(info, sessionID)); + return _httpResponse.GetBody(_profileController.SearchProfiles(info, sessionID)); } /** diff --git a/Libraries/Core/Controllers/HideoutController.cs b/Libraries/Core/Controllers/HideoutController.cs index d55da0f9..41ce333a 100644 --- a/Libraries/Core/Controllers/HideoutController.cs +++ b/Libraries/Core/Controllers/HideoutController.cs @@ -496,7 +496,7 @@ public class HideoutController( recipe.Requirements.Where((r) => r.Type == "Item" || r.Type == "Tool") ); - List itemsToDelete = new List(); + List itemsToDelete = []; var output = _eventOutputHolder.GetOutput(sessionID); itemsToDelete.AddRange(body.Tools); itemsToDelete.AddRange(body.Items); @@ -789,7 +789,7 @@ public class HideoutController( hoursCrafting += recipe.ProductionTime; if (hoursCrafting / _hideoutConfig.HoursForSkillCrafting >= 1) { - // Spent enough time crafting to get a bonus xp multipler + // Spent enough time crafting to get a bonus xp multiplier var multiplierCrafting = Math.Floor((double)hoursCrafting / _hideoutConfig.HoursForSkillCrafting); craftingExpAmount += (int)(1 * multiplierCrafting); hoursCrafting -= _hideoutConfig.HoursForSkillCrafting * multiplierCrafting; diff --git a/Libraries/Core/Controllers/ProfileController.cs b/Libraries/Core/Controllers/ProfileController.cs index a45ddde6..e16cd686 100644 --- a/Libraries/Core/Controllers/ProfileController.cs +++ b/Libraries/Core/Controllers/ProfileController.cs @@ -177,9 +177,8 @@ public class ProfileController( /** * Handle client/game/profile/search */ - public List GetFriends(SearchFriendRequestData info, string sessionID) + public List SearchProfiles(SearchProfilesRequestData info, string sessionID) { - // TODO: We should probably rename this method in the next client update var result = new List(); // Find any profiles with a nickname containing the entered name diff --git a/Libraries/Core/Controllers/RagfairController.cs b/Libraries/Core/Controllers/RagfairController.cs index 877869cc..9dc592f3 100644 --- a/Libraries/Core/Controllers/RagfairController.cs +++ b/Libraries/Core/Controllers/RagfairController.cs @@ -140,7 +140,7 @@ public class RagfairController var traderAssorts = _ragfairHelper.GetDisplayableAssorts(sessionID); var result = new GetOffersResult { - Offers = new List(), + Offers = [], OffersCount = searchRequest.Limit, SelectedCategory = searchRequest.HandbookId, }; @@ -986,7 +986,7 @@ public class RagfairController ) ); - pmcData.RagfairInfo.Offers = new List(); + pmcData.RagfairInfo.Offers = []; } var playerOfferIndex = playerProfileOffers.FindIndex(offer => offer.Id == removeRequest.OfferId); diff --git a/Libraries/Core/Generators/BotInventoryGenerator.cs b/Libraries/Core/Generators/BotInventoryGenerator.cs index 1e9d3fb3..98206814 100644 --- a/Libraries/Core/Generators/BotInventoryGenerator.cs +++ b/Libraries/Core/Generators/BotInventoryGenerator.cs @@ -39,6 +39,20 @@ public class BotInventoryGenerator( { private BotConfig _botConfig = _configServer.GetConfig(); + // Slots handled individually inside `GenerateAndAddEquipmentToBot` + List _excludedEquipmentSlots = + [ + EquipmentSlots.Pockets, + EquipmentSlots.FirstPrimaryWeapon, + EquipmentSlots.SecondPrimaryWeapon, + EquipmentSlots.Holster, + EquipmentSlots.ArmorVest, + EquipmentSlots.TacticalVest, + EquipmentSlots.FaceCover, + EquipmentSlots.Headwear, + EquipmentSlots.Earpiece + ]; + /// /// Add equipment/weapons/loot to bot /// @@ -142,20 +156,6 @@ public class BotInventoryGenerator( public void GenerateAndAddEquipmentToBot(string sessionId, BotTypeInventory templateInventory, Chances wornItemChances, string botRole, BotBaseInventory botInventory, int botLevel, string chosenGameVersion, GetRaidConfigurationRequestData raidConfig) { - // These will be handled later - var excludedSlots = new List() - { - EquipmentSlots.Pockets, - EquipmentSlots.FirstPrimaryWeapon, - EquipmentSlots.SecondPrimaryWeapon, - EquipmentSlots.Holster, - EquipmentSlots.ArmorVest, - EquipmentSlots.TacticalVest, - EquipmentSlots.FaceCover, - EquipmentSlots.Headwear, - EquipmentSlots.Earpiece - }; - _botConfig.Equipment.TryGetValue(_botGeneratorHelper.GetBotEquipmentRole(botRole), out var botEquipConfig); var randomistionDetails = _botHelper.GetBotRandomizationDetails(botLevel, botEquipConfig); @@ -188,7 +188,7 @@ public class BotInventoryGenerator( { // Skip some slots as they need to be done in a specific order + with specific parameter values // e.g. Weapons - if (excludedSlots.Contains(equipmentSlot)) + if (_excludedEquipmentSlots.Contains(equipmentSlot)) { continue; } diff --git a/Libraries/Core/Generators/LootGenerator.cs b/Libraries/Core/Generators/LootGenerator.cs index 6cbd5bc0..f62838e3 100644 --- a/Libraries/Core/Generators/LootGenerator.cs +++ b/Libraries/Core/Generators/LootGenerator.cs @@ -586,7 +586,7 @@ public class LootGenerator( // Find a random item of the desired type and add as reward for (var index = 0; index < rewardCount; index++) { var chosenItem = _randomUtil.DrawRandomFromList(relatedItems.ToList()); - var reward = new List { new Item() { Id = _hashUtil.Generate(), Template = chosenItem[0].Id } }; + var reward = new List { new() { Id = _hashUtil.Generate(), Template = chosenItem[0].Id } }; modRewards.Add(reward); } diff --git a/Libraries/Core/Generators/PlayerScavGenerator.cs b/Libraries/Core/Generators/PlayerScavGenerator.cs index 7013b042..ce180cef 100644 --- a/Libraries/Core/Generators/PlayerScavGenerator.cs +++ b/Libraries/Core/Generators/PlayerScavGenerator.cs @@ -151,7 +151,7 @@ public class PlayerScavGenerator( var itemTemplate = itemResult.Value; var itemsToAdd = new List() { - new Item() + new() { Id = _hashUtil.Generate(), Template = itemTemplate.Id, diff --git a/Libraries/Core/Generators/ScavCaseRewardGenerator.cs b/Libraries/Core/Generators/ScavCaseRewardGenerator.cs index 9cc71f1a..8297357a 100644 --- a/Libraries/Core/Generators/ScavCaseRewardGenerator.cs +++ b/Libraries/Core/Generators/ScavCaseRewardGenerator.cs @@ -1,4 +1,4 @@ -using Core.Helpers; +using Core.Helpers; using Core.Models.Common; using SptCommon.Annotations; using Core.Models.Eft.Common.Tables; @@ -32,8 +32,8 @@ public class ScavCaseRewardGenerator( ) { protected ScavCaseConfig _scavCaseConfig = _configServer.GetConfig(); - protected List _dbItemsCache = new List(); - protected List _dbAmmoItemsCache = new List(); + protected List _dbItemsCache = []; + protected List _dbAmmoItemsCache = []; /// /// Create an array of rewards that will be given to the player upon completing their scav case build diff --git a/Libraries/Core/Helpers/DialogueHelper.cs b/Libraries/Core/Helpers/DialogueHelper.cs index cf58324f..bed3a3c6 100644 --- a/Libraries/Core/Helpers/DialogueHelper.cs +++ b/Libraries/Core/Helpers/DialogueHelper.cs @@ -72,7 +72,7 @@ public class DialogueHelper( // Check reward count when item being moved isn't in reward list // If count is 0, it means after this move occurs the reward array will be empty and all rewards collected if (message.Items.Data is null) - message.Items.Data = new(); + message.Items.Data = []; var rewardItems = message.Items.Data?.Where(x => x.Id != itemId); if (rewardItems.Count() == 0) @@ -85,7 +85,7 @@ public class DialogueHelper( } } - return new List(); + return []; } /// @@ -96,10 +96,7 @@ public class DialogueHelper( public Dictionary GetDialogsForProfile(string sessionId) { var profile = _profileHelper.GetFullProfile(sessionId); - if (profile.DialogueRecords is null) - profile.DialogueRecords = new(); - - return profile.DialogueRecords; + return profile.DialogueRecords ?? (profile.DialogueRecords = new()); } public Models.Eft.Profile.Dialogue? GetDialogueFromProfile(string profileId, string dialogueId) diff --git a/Libraries/Core/Helpers/InventoryHelper.cs b/Libraries/Core/Helpers/InventoryHelper.cs index 92b566cc..afa0c7cc 100644 --- a/Libraries/Core/Helpers/InventoryHelper.cs +++ b/Libraries/Core/Helpers/InventoryHelper.cs @@ -40,6 +40,9 @@ public class InventoryHelper( { protected InventoryConfig _inventoryConfig = _configServer.GetConfig(); + // Item types to ignore inside `GetSizeByInventoryItemHash` + List _itemBaseTypesToIgnore = [BaseClasses.BACKPACK, BaseClasses.SEARCHABLE_ITEM, BaseClasses.SIMPLE_CONTAINER]; + /// /// Add multiple items to player stash (assuming they all fit) /// @@ -655,12 +658,8 @@ public class InventoryHelper( var forcedDown = 0; var forcedLeft = 0; var forcedRight = 0; - var outX = (int)tmpItem.Properties.Width; - var outY = (int)tmpItem.Properties.Height; - - // Item types to ignore - var skipThisItems = new List - { BaseClasses.BACKPACK, BaseClasses.SEARCHABLE_ITEM, BaseClasses.SIMPLE_CONTAINER }; + var outX = tmpItem.Properties.Width; + var outY = tmpItem.Properties.Height; var rootIsFolded = rootItem?.Upd?.Foldable?.Folded == true; @@ -669,7 +668,7 @@ public class InventoryHelper( outX -= tmpItem.Properties.SizeReduceRight.Value; // Calculate size contribution from child items/attachments - if (!skipThisItems.Contains(tmpItem.Parent)) + if (!_itemBaseTypesToIgnore.Contains(tmpItem.Parent)) while (toDo.Count > 0) { if (inventoryItemHash.ByParentId.ContainsKey(toDo[0])) @@ -726,8 +725,8 @@ public class InventoryHelper( return [ - outX + sizeLeft + sizeRight + forcedLeft + forcedRight, - outY + sizeUp + sizeDown + forcedUp + forcedDown + outX.Value + sizeLeft + sizeRight + forcedLeft + forcedRight, + outY.Value + sizeUp + sizeDown + forcedUp + forcedDown ]; } diff --git a/Libraries/Core/Helpers/ItemHelper.cs b/Libraries/Core/Helpers/ItemHelper.cs index 04cb0d36..90b69d9e 100644 --- a/Libraries/Core/Helpers/ItemHelper.cs +++ b/Libraries/Core/Helpers/ItemHelper.cs @@ -2045,8 +2045,8 @@ public class ItemHelper( public class ItemSize { [JsonPropertyName("width")] - public double Width { get; set; } + public int Width { get; set; } [JsonPropertyName("height")] - public double Height { get; set; } + public int Height { get; set; } } diff --git a/Libraries/Core/Helpers/TradeHelper.cs b/Libraries/Core/Helpers/TradeHelper.cs index 54a03abf..0dbdc6d5 100644 --- a/Libraries/Core/Helpers/TradeHelper.cs +++ b/Libraries/Core/Helpers/TradeHelper.cs @@ -170,16 +170,16 @@ public class TradeHelper( if (assortHasBuyRestrictions) { - var itemPurchaseDat = new PurchaseDetails() + var itemPurchaseDat = new PurchaseDetails { - Items = new List() - { - new PurchaseItems() + Items = + [ + new PurchaseItems { ItemId = buyRequestData.ItemId, Count = buyCount } - }, + ], TraderId = buyRequestData.TransactionId }; diff --git a/Libraries/Core/Models/Eft/Common/Tables/TemplateItem.cs b/Libraries/Core/Models/Eft/Common/Tables/TemplateItem.cs index 20ee6d3e..2c4bef2d 100644 --- a/Libraries/Core/Models/Eft/Common/Tables/TemplateItem.cs +++ b/Libraries/Core/Models/Eft/Common/Tables/TemplateItem.cs @@ -56,11 +56,13 @@ public record Props [JsonPropertyName("BackgroundColor")] public string? BackgroundColor { get; set; } + // Type confirmed via client [JsonPropertyName("Width")] - public double? Width { get; set; } + public int? Width { get; set; } + // Type confirmed via client [JsonPropertyName("Height")] - public double? Height { get; set; } + public int? Height { get; set; } [JsonPropertyName("StackMaxSize")] public int? StackMaxSize { get; set; } diff --git a/Libraries/Core/Routers/HttpRouter.cs b/Libraries/Core/Routers/HttpRouter.cs index 6ff60783..f7c809c0 100644 --- a/Libraries/Core/Routers/HttpRouter.cs +++ b/Libraries/Core/Routers/HttpRouter.cs @@ -48,6 +48,9 @@ public class HttpRouter wrapper.Output = wrapper.Output.Replace(sessionID, sessionID); } + //var filepath = $"c:\\SharpServer\\{req.Path.ToString().Substring(1).Replace("/", ".")}.json"; + //File.WriteAllText(filepath, wrapper.Output); + return wrapper.Output; } diff --git a/Libraries/Core/Routers/SaveLoad/HealthSaveLoadRouter.cs b/Libraries/Core/Routers/SaveLoad/HealthSaveLoadRouter.cs index ba545ae7..43626bca 100644 --- a/Libraries/Core/Routers/SaveLoad/HealthSaveLoadRouter.cs +++ b/Libraries/Core/Routers/SaveLoad/HealthSaveLoadRouter.cs @@ -1,4 +1,4 @@ -using SptCommon.Annotations; +using SptCommon.Annotations; using Core.DI; using Core.Helpers; using Core.Models.Eft.Common.Tables; @@ -11,7 +11,7 @@ public class HealthSaveLoadRouter() : SaveLoadRouter { protected override List GetHandledRoutes() { - return new List() { new HandledRoute("spt-health", false) }; + return [new("spt-health", false)]; } public override SptProfile HandleLoad(SptProfile profile) diff --git a/Libraries/Core/Routers/SaveLoad/InraidSaveLoadRouter.cs b/Libraries/Core/Routers/SaveLoad/InraidSaveLoadRouter.cs index dcd46ab1..3bbef904 100644 --- a/Libraries/Core/Routers/SaveLoad/InraidSaveLoadRouter.cs +++ b/Libraries/Core/Routers/SaveLoad/InraidSaveLoadRouter.cs @@ -1,4 +1,4 @@ -using SptCommon.Annotations; +using SptCommon.Annotations; using Core.DI; using Core.Models.Eft.Profile; @@ -9,7 +9,7 @@ public class InraidSaveLoadRouter : SaveLoadRouter { protected override List GetHandledRoutes() { - return new List() { new HandledRoute("spt-inraid", false) }; + return [new("spt-inraid", false)]; } public override SptProfile HandleLoad(SptProfile profile) diff --git a/Libraries/Core/Routers/SaveLoad/InsuranceSaveLoadRouter.cs b/Libraries/Core/Routers/SaveLoad/InsuranceSaveLoadRouter.cs index ecf2c54d..acaa8559 100644 --- a/Libraries/Core/Routers/SaveLoad/InsuranceSaveLoadRouter.cs +++ b/Libraries/Core/Routers/SaveLoad/InsuranceSaveLoadRouter.cs @@ -1,4 +1,4 @@ -using SptCommon.Annotations; +using SptCommon.Annotations; using Core.DI; using Core.Models.Eft.Profile; @@ -9,7 +9,7 @@ public class InsuranceSaveLoadRouter : SaveLoadRouter { protected override List GetHandledRoutes() { - return new List() { new HandledRoute("spt-insurance", false) }; + return [new ("spt-insurance", false)]; } public override SptProfile HandleLoad(SptProfile profile) diff --git a/Libraries/Core/Routers/SaveLoad/ProfileSaveLoadRouter.cs b/Libraries/Core/Routers/SaveLoad/ProfileSaveLoadRouter.cs index ddc24c25..90ae39a7 100644 --- a/Libraries/Core/Routers/SaveLoad/ProfileSaveLoadRouter.cs +++ b/Libraries/Core/Routers/SaveLoad/ProfileSaveLoadRouter.cs @@ -1,4 +1,4 @@ -using SptCommon.Annotations; +using SptCommon.Annotations; using Core.DI; using Core.Models.Eft.Profile; @@ -9,7 +9,7 @@ public class ProfileSaveLoadRouter : SaveLoadRouter { protected override List GetHandledRoutes() { - return new List() { new HandledRoute("spt-profile", false) }; + return [new ("spt-profile", false)]; } public override SptProfile HandleLoad(SptProfile profile) diff --git a/Libraries/Core/Routers/Static/ProfileStaticRouter.cs b/Libraries/Core/Routers/Static/ProfileStaticRouter.cs index f71787ca..9b7a693b 100644 --- a/Libraries/Core/Routers/Static/ProfileStaticRouter.cs +++ b/Libraries/Core/Routers/Static/ProfileStaticRouter.cs @@ -103,8 +103,8 @@ public class ProfileStaticRouter : StaticRouter info, sessionID, output - ) => profileCallbacks.SearchFriend(url, info as SearchFriendRequestData, sessionID), - typeof(SearchFriendRequestData)), + ) => profileCallbacks.SearchProfiles(url, info as SearchProfilesRequestData, sessionID), + typeof(SearchProfilesRequestData)), new RouteAction( "/launcher/profile/info", (url, info, sessionID, output) => From 102f2979aaf7280f0fae5c86a04de3c10e048bb2 Mon Sep 17 00:00:00 2001 From: Chomp Date: Wed, 29 Jan 2025 12:12:21 +0000 Subject: [PATCH 4/8] Added new request file --- ...{SearchFriendRequestData.cs => SearchProfilesRequestData.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Libraries/Core/Models/Eft/Profile/{SearchFriendRequestData.cs => SearchProfilesRequestData.cs} (76%) diff --git a/Libraries/Core/Models/Eft/Profile/SearchFriendRequestData.cs b/Libraries/Core/Models/Eft/Profile/SearchProfilesRequestData.cs similarity index 76% rename from Libraries/Core/Models/Eft/Profile/SearchFriendRequestData.cs rename to Libraries/Core/Models/Eft/Profile/SearchProfilesRequestData.cs index 2e1c98e5..158ae9d9 100644 --- a/Libraries/Core/Models/Eft/Profile/SearchFriendRequestData.cs +++ b/Libraries/Core/Models/Eft/Profile/SearchProfilesRequestData.cs @@ -3,7 +3,7 @@ using Core.Models.Utils; namespace Core.Models.Eft.Profile; -public record SearchFriendRequestData : IRequestData +public record SearchProfilesRequestData : IRequestData { [JsonPropertyName("nickname")] public string? Nickname { get; set; } From 9ddeb1f3631dcdc037db5a9f189e5f88e1298e97 Mon Sep 17 00:00:00 2001 From: Chomp Date: Wed, 29 Jan 2025 12:51:19 +0000 Subject: [PATCH 5/8] Improved item types --- .../Core/Generators/BotWeaponGenerator.cs | 4 +- .../Implementations/BarrelInvetoryMagGen.cs | 5 ++- .../ExternalInventoryMagGen.cs | 4 +- .../InternalMagazineInventoryMagGen.cs | 5 ++- .../Models/Eft/Common/Tables/TemplateItem.cs | 41 ++++++++++++------- 5 files changed, 37 insertions(+), 22 deletions(-) diff --git a/Libraries/Core/Generators/BotWeaponGenerator.cs b/Libraries/Core/Generators/BotWeaponGenerator.cs index afb34577..5ae6cd7f 100644 --- a/Libraries/Core/Generators/BotWeaponGenerator.cs +++ b/Libraries/Core/Generators/BotWeaponGenerator.cs @@ -394,7 +394,7 @@ public class BotWeaponGenerator( return; } - var isInternalMag = magTemplate.Properties.ReloadMagType == "InternalMagazine"; + var isInternalMag = magTemplate.Properties.ReloadMagType == ReloadMode.InternalMagazine; var ammoTemplate = _itemHelper.GetItem(generatedWeaponResult.ChosenAmmoTemplate).Value; if (ammoTemplate is null) { @@ -508,7 +508,7 @@ public class BotWeaponGenerator( { // Edge case - magazineless chamber loaded weapons dont have magazines, e.g. mp18 // return default mag tpl - if (weaponTemplate.Properties.ReloadMode == "OnlyBarrel") + if (weaponTemplate.Properties.ReloadMode == ReloadMode.OnlyBarrel) { return _botWeaponGeneratorHelper.GetWeaponsDefaultMagazineTpl(weaponTemplate); } diff --git a/Libraries/Core/Generators/WeaponGen/Implementations/BarrelInvetoryMagGen.cs b/Libraries/Core/Generators/WeaponGen/Implementations/BarrelInvetoryMagGen.cs index 740eb96c..36c08929 100644 --- a/Libraries/Core/Generators/WeaponGen/Implementations/BarrelInvetoryMagGen.cs +++ b/Libraries/Core/Generators/WeaponGen/Implementations/BarrelInvetoryMagGen.cs @@ -1,5 +1,6 @@ -using SptCommon.Annotations; +using SptCommon.Annotations; using Core.Helpers; +using Core.Models.Enums; using Core.Utils; namespace Core.Generators.WeaponGen.Implementations; @@ -17,7 +18,7 @@ public class BarrelInvetoryMagGen( public bool CanHandleInventoryMagGen(InventoryMagGen inventoryMagGen) { - return inventoryMagGen.GetWeaponTemplate().Properties.ReloadMode == "OnlyBarrel"; + return inventoryMagGen.GetWeaponTemplate().Properties.ReloadMode == ReloadMode.OnlyBarrel; } public void Process(InventoryMagGen inventoryMagGen) diff --git a/Libraries/Core/Generators/WeaponGen/Implementations/ExternalInventoryMagGen.cs b/Libraries/Core/Generators/WeaponGen/Implementations/ExternalInventoryMagGen.cs index a5028fb0..0a9292f5 100644 --- a/Libraries/Core/Generators/WeaponGen/Implementations/ExternalInventoryMagGen.cs +++ b/Libraries/Core/Generators/WeaponGen/Implementations/ExternalInventoryMagGen.cs @@ -118,7 +118,7 @@ public class ExternalInventoryMagGen( } // Edge case - some weapons (SKS + shotguns) have an internal magazine as default, choose random non-internal magazine to add to bot instead - if (magTemplate.Properties.ReloadMagType == "InternalMagazine") + if (magTemplate.Properties.ReloadMagType == ReloadMode.InternalMagazine) { var result = GetRandomExternalMagazineForInternalMagazineGun( inventoryMagGen.GetWeaponTemplate().Id, @@ -179,7 +179,7 @@ public class ExternalInventoryMagGen( } // Non-internal magazines that fit into the weapon - var externalMagazineOnlyPool = magazinePool.Where((x) => x.Properties.ReloadMagType != "InternalMagazine"); + var externalMagazineOnlyPool = magazinePool.Where((x) => x.Properties.ReloadMagType != ReloadMode.InternalMagazine); if (externalMagazineOnlyPool is null || externalMagazineOnlyPool?.Count() == 0) { return null; diff --git a/Libraries/Core/Generators/WeaponGen/Implementations/InternalMagazineInventoryMagGen.cs b/Libraries/Core/Generators/WeaponGen/Implementations/InternalMagazineInventoryMagGen.cs index e185ab56..fc147dc7 100644 --- a/Libraries/Core/Generators/WeaponGen/Implementations/InternalMagazineInventoryMagGen.cs +++ b/Libraries/Core/Generators/WeaponGen/Implementations/InternalMagazineInventoryMagGen.cs @@ -1,5 +1,6 @@ -using SptCommon.Annotations; +using SptCommon.Annotations; using Core.Helpers; +using Core.Models.Enums; namespace Core.Generators.WeaponGen.Implementations; @@ -15,7 +16,7 @@ public class InternalMagazineInventoryMagGen( public bool CanHandleInventoryMagGen(InventoryMagGen inventoryMagGen) { - return inventoryMagGen.GetMagazineTemplate().Properties.ReloadMagType == "InternalMagazine"; + return inventoryMagGen.GetMagazineTemplate().Properties.ReloadMagType == ReloadMode.InternalMagazine; } public void Process(InventoryMagGen inventoryMagGen) diff --git a/Libraries/Core/Models/Eft/Common/Tables/TemplateItem.cs b/Libraries/Core/Models/Eft/Common/Tables/TemplateItem.cs index 2c4bef2d..72e32fbe 100644 --- a/Libraries/Core/Models/Eft/Common/Tables/TemplateItem.cs +++ b/Libraries/Core/Models/Eft/Common/Tables/TemplateItem.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using Core.Models.Enums; using Core.Utils.Json.Converters; namespace Core.Models.Eft.Common.Tables; @@ -64,11 +65,13 @@ public record Props [JsonPropertyName("Height")] public int? Height { get; set; } + // Type confirmed via client [JsonPropertyName("StackMaxSize")] public int? StackMaxSize { get; set; } + // Type confirmed via client [JsonPropertyName("Rarity")] - public string? Rarity { get; set; } + public LootRarity? Rarity { get; set; } [JsonPropertyName("SpawnChance")] public double? SpawnChance { get; set; } @@ -136,10 +139,11 @@ public record Props [JsonPropertyName("QuestStashMaxCount")] public double? QuestStashMaxCount { get; set; } + // Type confirmed via client [JsonPropertyName("LootExperience")] - public double? LootExperience { get; set; } + public int? LootExperience { get; set; } - // Checked on live + // Type confirmed via client [JsonPropertyName("ExamineExperience")] public int? ExamineExperience { get; set; } @@ -149,11 +153,13 @@ public record Props [JsonPropertyName("InsuranceDisabled")] public bool? InsuranceDisabled { get; set; } + // Type confirmed via client [JsonPropertyName("RepairCost")] - public double? RepairCost { get; set; } + public int? RepairCost { get; set; } + // Type confirmed via client [JsonPropertyName("RepairSpeed")] - public double? RepairSpeed { get; set; } + public int? RepairSpeed { get; set; } [JsonPropertyName("ExtraSizeLeft")] public int? ExtraSizeLeft { get; set; } @@ -203,8 +209,9 @@ public record Props [JsonPropertyName("UnlootableFromSide")] public List? UnlootableFromSide { get; set; } + // Type confirmed via client [JsonPropertyName("AnimationVariantsNumber")] - public double? AnimationVariantsNumber { get; set; } + public int? AnimationVariantsNumber { get; set; } [JsonPropertyName("DiscardingBlock")] public bool? DiscardingBlock { get; set; } @@ -224,8 +231,9 @@ public record Props [JsonPropertyName("DiscardLimit")] public double? DiscardLimit { get; set; } + // Type confirmed via client [JsonPropertyName("MaxResource")] - public double? MaxResource { get; set; } + public int? MaxResource { get; set; } [JsonPropertyName("Resource")] public double? Resource { get; set; } @@ -459,7 +467,7 @@ public record Props public double? CheckOverride { get; set; } [JsonPropertyName("ReloadMagType")] - public string? ReloadMagType { get; set; } + public ReloadMode? ReloadMagType { get; set; } [JsonPropertyName("VisibleAmmoRangesString")] public string? VisibleAmmoRangesString { get; set; } @@ -548,9 +556,10 @@ public record Props [JsonPropertyName("armorZone")] public List? ArmorZone { get; set; } + // Type confirmed via client [JsonPropertyName("armorClass")] [JsonConverter(typeof(StringToNumberFactoryConverter))] - public double? ArmorClass { get; set; } // TODO: object here + public int? ArmorClass { get; set; } [JsonPropertyName("armorColliders")] public List? ArmorColliders { get; set; } @@ -685,7 +694,7 @@ public record Props public double? CameraToWeaponAngleStep { get; set; } [JsonPropertyName("ReloadMode")] - public string? ReloadMode { get; set; } + public ReloadMode? ReloadMode { get; set; } [JsonPropertyName("AimPlane")] public double? AimPlane { get; set; } @@ -988,8 +997,9 @@ public record Props [JsonIgnore(Condition = JsonIgnoreCondition.Never)] public Dictionary? EffectsDamage { get; set; } + // Confirmed in client [JsonPropertyName("MaximumNumberOfUsage")] - public double? MaximumNumberOfUsage { get; set; } + public int? MaximumNumberOfUsage { get; set; } [JsonPropertyName("knifeHitDelay")] public double? KnifeHitDelay { get; set; } @@ -1069,8 +1079,9 @@ public record Props [JsonPropertyName("medEffectType")] public string? MedEffectType { get; set; } + // Confirmed in client [JsonPropertyName("MaxHpResource")] - public double? MaxHpResource { get; set; } + public int? MaxHpResource { get; set; } [JsonPropertyName("hpResourceRate")] public double? HpResourceRate { get; set; } @@ -1084,8 +1095,9 @@ public record Props [JsonPropertyName("MaxOpticZoom")] public double? MaxOpticZoom { get; set; } + // Confirmed in client [JsonPropertyName("MaxRepairResource")] - public double? MaxRepairResource { get; set; } + public int? MaxRepairResource { get; set; } [JsonPropertyName("TargetItemFilter")] public List? TargetItemFilter { get; set; } @@ -1129,8 +1141,9 @@ public record Props [JsonPropertyName("buckshotBullets")] public double? BuckshotBullets { get; set; } + // Confirmed in client [JsonPropertyName("PenetrationPower")] - public double? PenetrationPower { get; set; } + public int? PenetrationPower { get; set; } [JsonPropertyName("PenetrationPowerDeviation")] public double? PenetrationPowerDeviation { get; set; } From 06bfa78a627dc67795f15b6e229be8b232368ab6 Mon Sep 17 00:00:00 2001 From: Chomp Date: Wed, 29 Jan 2025 13:30:31 +0000 Subject: [PATCH 6/8] Improved `IsValidMongoIdTest` --- UnitTests/Tests/Utils/HashUtilTests.cs | 33 +++++++------------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/UnitTests/Tests/Utils/HashUtilTests.cs b/UnitTests/Tests/Utils/HashUtilTests.cs index e685cbbb..c56f1d6a 100644 --- a/UnitTests/Tests/Utils/HashUtilTests.cs +++ b/UnitTests/Tests/Utils/HashUtilTests.cs @@ -29,30 +29,15 @@ public class HashUtilTests } [TestMethod] - public void IsValidMongoIdTest() + [DataRow("677ddb67406e9918a0264bbz", false, "677ddb67406e9918a0264bbz contains invalid char `z`, but result was true")] + [DataRow("677ddb67406e9918a0264bbcc", false, "677ddb67406e9918a0264bbcc is 25 characters, but result was true")] + [DataRow("677ddb67406e9918a0264bbc", true, "IsValidMongoId() `677ddb67406e9918a0264bbc` is a valid mongoId, but result was false")] +public void IsValidMongoIdTest(string mongoId, bool passes, string failMessage) { - // Invalid mongoId character - var ResultBadChar = _hashUtil.IsValidMongoId("677ddb67406e9918a0264bbz"); - - Assert.AreEqual( - false, - ResultBadChar, - "IsValidMongoId() `677ddb67406e9918a0264bbz` contains invalid char `z`, but result was true"); - - // Invalid mongoId length - var resultBadLength = _hashUtil.IsValidMongoId("677ddb67406e9918a0264bbcc"); - - Assert.AreEqual( - false, - resultBadLength, - "IsValidMongoId() `677ddb67406e9918a0264bbcc` is 25 characters, but result was true"); - - // Valid mongoId - var resultPass = _hashUtil.IsValidMongoId("677ddb67406e9918a0264bbc"); - - Assert.AreEqual( - true, - resultPass, - "IsValidMongoId() `677ddb67406e9918a0264bbc` is a valid mongoId, but result was false"); + var result = _hashUtil.IsValidMongoId(mongoId); + Assert.AreEqual( + passes, + result, + failMessage); } } From dbf30716645dbfb04c14d62ca329eefdcd94a4d7 Mon Sep 17 00:00:00 2001 From: clodan Date: Wed, 29 Jan 2025 13:30:52 +0000 Subject: [PATCH 7/8] Improved precision for smaller decimals --- Libraries/Core/Utils/RandomUtil.cs | 5 +++-- UnitTests/Tests/Utils/RandomUtilTests.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Libraries/Core/Utils/RandomUtil.cs b/Libraries/Core/Utils/RandomUtil.cs index 06a8cd9d..feb3338b 100644 --- a/Libraries/Core/Utils/RandomUtil.cs +++ b/Libraries/Core/Utils/RandomUtil.cs @@ -414,10 +414,11 @@ public class RandomUtil(ISptLogger _logger, ICloner _cloner) /// The number of decimal places, or 0 if none exist. public int GetNumberPrecision(double num) { + var preciseNum = (decimal)num; var factor = 0; - while (num % 1 > double.Epsilon) + while ((double)(preciseNum % 1) > double.Epsilon) { - num *= 10D; + preciseNum *= 10M; factor++; } return factor; diff --git a/UnitTests/Tests/Utils/RandomUtilTests.cs b/UnitTests/Tests/Utils/RandomUtilTests.cs index 2a52e541..51d0f4b1 100644 --- a/UnitTests/Tests/Utils/RandomUtilTests.cs +++ b/UnitTests/Tests/Utils/RandomUtilTests.cs @@ -188,7 +188,7 @@ public sealed class RandomUtilTests [DataRow(0.0001, 4)] [DataRow(0, 0)] [DataRow(10000000, 0)] - [DataRow(0.000_000_000_000_1D, 13)] + [DataRow(0.000_000_000_000_000_000_000_000_1D, 25)] public void GetNumberPrecision_WithDoubles_ReturnsDecimalPoints(double value, int decimalPoints) { Assert.AreEqual(decimalPoints, _randomUtil.GetNumberPrecision(value)); From 91ccc7a7713f4668cb0ec2dfcb7f6895da5ca74a Mon Sep 17 00:00:00 2001 From: Chomp Date: Wed, 29 Jan 2025 13:36:18 +0000 Subject: [PATCH 8/8] Added `GenerateValidMd5Test` --- UnitTests/Tests/Utils/HashUtilTests.cs | 80 +++++++++++++++++--------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/UnitTests/Tests/Utils/HashUtilTests.cs b/UnitTests/Tests/Utils/HashUtilTests.cs index c56f1d6a..7c4e8c5e 100644 --- a/UnitTests/Tests/Utils/HashUtilTests.cs +++ b/UnitTests/Tests/Utils/HashUtilTests.cs @@ -1,5 +1,6 @@ using Core.Utils; using Core.Utils.Cloners; +using System.Net.Mail; using UnitTests.Mock; namespace UnitTests.Tests.Utils; @@ -7,37 +8,60 @@ namespace UnitTests.Tests.Utils; [TestClass] public class HashUtilTests { - protected HashUtil _hashUtil = new(new RandomUtil(new MockLogger(), new JsonCloner(new JsonUtil()))); - - [TestMethod] - public void GenerateTest() - { - // Generate 100 MongoId's - for (var i = 0; i < 100; i++) - { - // Invalid mongoId character - var result = _hashUtil.Generate(); - - // Invalid mongoId length - var test = _hashUtil.IsValidMongoId(result); - - Assert.AreEqual( - true, - test, - $"IsValidMongoId() `{result}` is not a valid MongoId."); - } - } - - [TestMethod] - [DataRow("677ddb67406e9918a0264bbz", false, "677ddb67406e9918a0264bbz contains invalid char `z`, but result was true")] + protected HashUtil _hashUtil = new(new RandomUtil(new MockLogger(), new JsonCloner(new JsonUtil()))); + + [TestMethod] + public void GenerateTest() + { + // Generate 100 MongoId's + for (var i = 0; i < 100; i++) + { + // Invalid mongoId character + var result = _hashUtil.Generate(); + + // Invalid mongoId length + var test = _hashUtil.IsValidMongoId(result); + + Assert.AreEqual( + true, + test, + $"IsValidMongoId() `{result}` is not a valid MongoId." + ); + } + } + + [TestMethod] + [DataRow( + "677ddb67406e9918a0264bbz", + false, + "677ddb67406e9918a0264bbz contains invalid char `z`, but result was true" + )] [DataRow("677ddb67406e9918a0264bbcc", false, "677ddb67406e9918a0264bbcc is 25 characters, but result was true")] - [DataRow("677ddb67406e9918a0264bbc", true, "IsValidMongoId() `677ddb67406e9918a0264bbc` is a valid mongoId, but result was false")] -public void IsValidMongoIdTest(string mongoId, bool passes, string failMessage) - { + [DataRow( + "677ddb67406e9918a0264bbc", + true, + "IsValidMongoId() `677ddb67406e9918a0264bbc` is a valid mongoId, but result was false" + )] + public void IsValidMongoIdTest(string mongoId, bool passes, string failMessage) + { var result = _hashUtil.IsValidMongoId(mongoId); Assert.AreEqual( passes, result, - failMessage); - } + failMessage + ); + } + + + [TestMethod] + [DataRow("123456789", "25F9E794323B453885F5181F1B624D0B", "Not valid output, expected '25F9E794323B453885F5181F1B624D0B'")] + public void GenerateValidMd5Test(string input, string expectedOutput, string failMessage) + { + var result = _hashUtil.GenerateMd5ForData(input); + Assert.AreEqual( + expectedOutput, + result, + failMessage + ); + } }