Merge branch 'main' of https://github.com/sp-tarkov/server-csharp
This commit is contained in:
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -496,7 +496,7 @@ public class HideoutController(
|
||||
recipe.Requirements.Where((r) => r.Type == "Item" || r.Type == "Tool")
|
||||
);
|
||||
|
||||
List<IdWithCount> itemsToDelete = new List<IdWithCount>();
|
||||
List<IdWithCount> 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;
|
||||
|
||||
@@ -257,9 +257,9 @@ public class InventoryController(
|
||||
var rewards = new List<List<Item>>();
|
||||
var unlockedWeaponCrates = new List<string>
|
||||
{
|
||||
"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))
|
||||
|
||||
@@ -177,9 +177,8 @@ public class ProfileController(
|
||||
/**
|
||||
* Handle client/game/profile/search
|
||||
*/
|
||||
public List<SearchFriendResponse> GetFriends(SearchFriendRequestData info, string sessionID)
|
||||
public List<SearchFriendResponse> SearchProfiles(SearchProfilesRequestData info, string sessionID)
|
||||
{
|
||||
// TODO: We should probably rename this method in the next client update
|
||||
var result = new List<SearchFriendResponse>();
|
||||
|
||||
// Find any profiles with a nickname containing the entered name
|
||||
|
||||
@@ -140,7 +140,7 @@ public class RagfairController
|
||||
var traderAssorts = _ragfairHelper.GetDisplayableAssorts(sessionID);
|
||||
var result = new GetOffersResult
|
||||
{
|
||||
Offers = new List<RagfairOffer>(),
|
||||
Offers = [],
|
||||
OffersCount = searchRequest.Limit,
|
||||
SelectedCategory = searchRequest.HandbookId,
|
||||
};
|
||||
@@ -986,7 +986,7 @@ public class RagfairController
|
||||
)
|
||||
);
|
||||
|
||||
pmcData.RagfairInfo.Offers = new List<RagfairOffer>();
|
||||
pmcData.RagfairInfo.Offers = [];
|
||||
}
|
||||
|
||||
var playerOfferIndex = playerProfileOffers.FindIndex(offer => offer.Id == removeRequest.OfferId);
|
||||
|
||||
@@ -39,6 +39,20 @@ public class BotInventoryGenerator(
|
||||
{
|
||||
private BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
|
||||
// Slots handled individually inside `GenerateAndAddEquipmentToBot`
|
||||
List<EquipmentSlots> _excludedEquipmentSlots =
|
||||
[
|
||||
EquipmentSlots.Pockets,
|
||||
EquipmentSlots.FirstPrimaryWeapon,
|
||||
EquipmentSlots.SecondPrimaryWeapon,
|
||||
EquipmentSlots.Holster,
|
||||
EquipmentSlots.ArmorVest,
|
||||
EquipmentSlots.TacticalVest,
|
||||
EquipmentSlots.FaceCover,
|
||||
EquipmentSlots.Headwear,
|
||||
EquipmentSlots.Earpiece
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Add equipment/weapons/loot to bot
|
||||
/// </summary>
|
||||
@@ -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>()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<Item> { new Item() { Id = _hashUtil.Generate(), Template = chosenItem[0].Id } };
|
||||
var reward = new List<Item> { new() { Id = _hashUtil.Generate(), Template = chosenItem[0].Id } };
|
||||
|
||||
modRewards.Add(reward);
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ public class PlayerScavGenerator(
|
||||
var itemTemplate = itemResult.Value;
|
||||
var itemsToAdd = new List<Item>()
|
||||
{
|
||||
new Item()
|
||||
new()
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Template = itemTemplate.Id,
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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<ScavCaseConfig>();
|
||||
protected List<TemplateItem> _dbItemsCache = new List<TemplateItem>();
|
||||
protected List<TemplateItem> _dbAmmoItemsCache = new List<TemplateItem>();
|
||||
protected List<TemplateItem> _dbItemsCache = [];
|
||||
protected List<TemplateItem> _dbAmmoItemsCache = [];
|
||||
|
||||
/// <summary>
|
||||
/// Create an array of rewards that will be given to the player upon completing their scav case build
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
+3
-2
@@ -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)
|
||||
|
||||
@@ -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<Item>();
|
||||
return [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -96,10 +96,7 @@ public class DialogueHelper(
|
||||
public Dictionary<string, Models.Eft.Profile.Dialogue> 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)
|
||||
|
||||
@@ -40,6 +40,9 @@ public class InventoryHelper(
|
||||
{
|
||||
protected InventoryConfig _inventoryConfig = _configServer.GetConfig<InventoryConfig>();
|
||||
|
||||
// Item types to ignore inside `GetSizeByInventoryItemHash`
|
||||
List<string> _itemBaseTypesToIgnore = [BaseClasses.BACKPACK, BaseClasses.SEARCHABLE_ITEM, BaseClasses.SIMPLE_CONTAINER];
|
||||
|
||||
/// <summary>
|
||||
/// Add multiple items to player stash (assuming they all fit)
|
||||
/// </summary>
|
||||
@@ -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<string>
|
||||
{ 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
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -170,16 +170,16 @@ public class TradeHelper(
|
||||
|
||||
if (assortHasBuyRestrictions)
|
||||
{
|
||||
var itemPurchaseDat = new PurchaseDetails()
|
||||
var itemPurchaseDat = new PurchaseDetails
|
||||
{
|
||||
Items = new List<PurchaseItems>()
|
||||
{
|
||||
new PurchaseItems()
|
||||
Items =
|
||||
[
|
||||
new PurchaseItems
|
||||
{
|
||||
ItemId = buyRequestData.ItemId,
|
||||
Count = buyCount
|
||||
}
|
||||
},
|
||||
],
|
||||
TraderId = buyRequestData.TransactionId
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Core.Models.Enums;
|
||||
using Core.Utils.Json.Converters;
|
||||
|
||||
namespace Core.Models.Eft.Common.Tables;
|
||||
@@ -56,17 +57,21 @@ 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; }
|
||||
|
||||
// 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; }
|
||||
@@ -134,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; }
|
||||
|
||||
@@ -147,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; }
|
||||
@@ -201,8 +209,9 @@ public record Props
|
||||
[JsonPropertyName("UnlootableFromSide")]
|
||||
public List<string>? 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; }
|
||||
@@ -222,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; }
|
||||
@@ -457,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; }
|
||||
@@ -546,9 +556,10 @@ public record Props
|
||||
[JsonPropertyName("armorZone")]
|
||||
public List<string>? 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<string>? ArmorColliders { get; set; }
|
||||
@@ -683,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; }
|
||||
@@ -986,8 +997,9 @@ public record Props
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public Dictionary<string, EffectDamageProps>? 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; }
|
||||
@@ -1067,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; }
|
||||
@@ -1082,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<string>? TargetItemFilter { get; set; }
|
||||
@@ -1127,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; }
|
||||
|
||||
+1
-1
@@ -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; }
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<HandledRoute> GetHandledRoutes()
|
||||
{
|
||||
return new List<HandledRoute>() { new HandledRoute("spt-health", false) };
|
||||
return [new("spt-health", false)];
|
||||
}
|
||||
|
||||
public override SptProfile HandleLoad(SptProfile profile)
|
||||
|
||||
@@ -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<HandledRoute> GetHandledRoutes()
|
||||
{
|
||||
return new List<HandledRoute>() { new HandledRoute("spt-inraid", false) };
|
||||
return [new("spt-inraid", false)];
|
||||
}
|
||||
|
||||
public override SptProfile HandleLoad(SptProfile profile)
|
||||
|
||||
@@ -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<HandledRoute> GetHandledRoutes()
|
||||
{
|
||||
return new List<HandledRoute>() { new HandledRoute("spt-insurance", false) };
|
||||
return [new ("spt-insurance", false)];
|
||||
}
|
||||
|
||||
public override SptProfile HandleLoad(SptProfile profile)
|
||||
|
||||
@@ -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<HandledRoute> GetHandledRoutes()
|
||||
{
|
||||
return new List<HandledRoute>() { new HandledRoute("spt-profile", false) };
|
||||
return [new ("spt-profile", false)];
|
||||
}
|
||||
|
||||
public override SptProfile HandleLoad(SptProfile profile)
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Core.Utils;
|
||||
public class RandomUtil(ISptLogger<RandomUtil> _logger, ICloner _cloner)
|
||||
{
|
||||
public readonly Random Random = new();
|
||||
private const int DecimalPointRandomPrecision = 6;
|
||||
private static readonly int DecimalPointRandomPrecisionMultiplier = (int) Math.Pow(10, DecimalPointRandomPrecision);
|
||||
|
||||
/// <summary>
|
||||
/// 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<RandomUtil> _logger, ICloner _cloner)
|
||||
/// Generates a random integer between the specified minimum and maximum values, inclusive.
|
||||
/// </summary>
|
||||
/// <param name="min">The minimum value (inclusive).</param>
|
||||
/// <param name="max">The maximum value (inclusive).</param>
|
||||
/// <param name="max">The maximum value (optional).</param>
|
||||
/// <param name="exclusive">If max is exclusive or not.</param>
|
||||
/// <returns>A random integer between the specified minimum and maximum values.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="max">The upper bound (exclusive) for the random integer generation.</param>
|
||||
/// <returns>A random integer between 1 and max - 1, or 1 if max is less than or equal to 1.</returns>
|
||||
public int GetIntEx(int max)
|
||||
{
|
||||
return max > 2 ? Random.Next(1, max - 1) : 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a random floating-point number within the specified range ~6-9 digits (4 bytes).
|
||||
/// </summary>
|
||||
/// <param name="min">The minimum value of the range (inclusive).</param>
|
||||
/// <param name="max">The maximum value of the range (exclusive).</param>
|
||||
/// <returns>A random floating-point number between `min` (inclusive) and `max` (exclusive).</returns>
|
||||
public float GetFloat(float min, float max)
|
||||
{
|
||||
return (float)GetSecureRandomNumber() * (max - min) + min;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Generates a random floating-point number within the specified range ~15-17 digits (8 bytes).
|
||||
/// </summary>
|
||||
@@ -64,7 +46,13 @@ public class RandomUtil(ISptLogger<RandomUtil> _logger, ICloner _cloner)
|
||||
/// <returns>A random floating-point number between `min` (inclusive) and `max` (exclusive).</returns>
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -73,7 +61,7 @@ public class RandomUtil(ISptLogger<RandomUtil> _logger, ICloner _cloner)
|
||||
/// <returns>A random boolean value, where the probability of `true` and `false` is approximately equal.</returns>
|
||||
public bool GetBool()
|
||||
{
|
||||
return GetSecureRandomNumber() < 0.5;
|
||||
return Random.Next(0, 2) == 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -83,11 +71,11 @@ public class RandomUtil(ISptLogger<RandomUtil> _logger, ICloner _cloner)
|
||||
/// <param name="number">The number to calculate the percentage of.</param>
|
||||
/// <param name="toFixed">The number of decimal places to round the result to (default is 2).</param>
|
||||
/// <returns>The calculated percentage of the given number, rounded to the specified number of decimal places.</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -110,9 +98,9 @@ public class RandomUtil(ISptLogger<RandomUtil> _logger, ICloner _cloner)
|
||||
/// <returns>`true` if the event occurs, `false` otherwise.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -196,7 +184,7 @@ public class RandomUtil(ISptLogger<RandomUtil> _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<RandomUtil> _logger, ICloner _cloner)
|
||||
/// and MaxSignificantDigits(15), inclusive. If not provided, precision is determined by the input values.
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -436,23 +402,9 @@ public class RandomUtil(ISptLogger<RandomUtil> _logger, ICloner _cloner)
|
||||
/// produce a floating-point number in the range [0, 1).
|
||||
/// </summary>
|
||||
/// <returns>A secure random number between 0 (inclusive) and 1 (exclusive).</returns>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -462,11 +414,14 @@ public class RandomUtil(ISptLogger<RandomUtil> _logger, ICloner _cloner)
|
||||
/// <returns>The number of decimal places, or 0 if none exist.</returns>
|
||||
public int GetNumberPrecision(double num)
|
||||
{
|
||||
var parts = num.ToString($"G{MaxSignificantDigits}").Split('.');
|
||||
|
||||
return parts.Length > 1
|
||||
? parts[1].Length
|
||||
: 0;
|
||||
var preciseNum = (decimal)num;
|
||||
var factor = 0;
|
||||
while ((double)(preciseNum % 1) > double.Epsilon)
|
||||
{
|
||||
preciseNum *= 10M;
|
||||
factor++;
|
||||
}
|
||||
return factor;
|
||||
}
|
||||
|
||||
public T? GetArrayValue<T>(IEnumerable<T> list)
|
||||
|
||||
@@ -14,7 +14,7 @@ public class Test
|
||||
public void Setup()
|
||||
{
|
||||
|
||||
var importer = new ImporterUtil(new MockLogger<ImporterUtil>(), new FileUtil(), new JsonUtil());
|
||||
var importer = new ImporterUtil(new MockLogger<ImporterUtil>(), new FileUtil(new MockLogger<FileUtil>()), new JsonUtil());
|
||||
var loadTask = importer.LoadRecursiveAsync<Templates>("./TestAssets/");
|
||||
loadTask.Wait();
|
||||
_templates = loadTask.Result;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Core.Utils;
|
||||
using Core.Utils.Cloners;
|
||||
using System.Net.Mail;
|
||||
using UnitTests.Mock;
|
||||
|
||||
namespace UnitTests.Tests.Utils;
|
||||
@@ -7,52 +8,60 @@ namespace UnitTests.Tests.Utils;
|
||||
[TestClass]
|
||||
public class HashUtilTests
|
||||
{
|
||||
protected HashUtil _hashUtil = new(new RandomUtil(new MockLogger<RandomUtil>(), 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]
|
||||
public void IsValidMongoIdTest()
|
||||
{
|
||||
// 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");
|
||||
}
|
||||
protected HashUtil _hashUtil = new(new RandomUtil(new MockLogger<RandomUtil>(), 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)
|
||||
{
|
||||
var result = _hashUtil.IsValidMongoId(mongoId);
|
||||
Assert.AreEqual(
|
||||
passes,
|
||||
result,
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_000_000_000_000_1D, 25)]
|
||||
public void GetNumberPrecision_WithDoubles_ReturnsDecimalPoints(double value, int decimalPoints)
|
||||
{
|
||||
Assert.AreEqual(decimalPoints, _randomUtil.GetNumberPrecision(value));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user