From 468867ba3df52b695479697594f64ffa50b5581f Mon Sep 17 00:00:00 2001 From: Cj <161484149+CJ-SPT@users.noreply.github.com> Date: Mon, 6 Jan 2025 06:09:12 -0500 Subject: [PATCH] Start porting RandomUtil.cs, not yet done. --- Core/Utils/RandomUtil.cs | 169 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 168 insertions(+), 1 deletion(-) diff --git a/Core/Utils/RandomUtil.cs b/Core/Utils/RandomUtil.cs index ded07f39..dd8c41e4 100644 --- a/Core/Utils/RandomUtil.cs +++ b/Core/Utils/RandomUtil.cs @@ -1,6 +1,173 @@ -namespace Core.Utils; +using System.Security.Cryptography; +using Core.Annotations; +namespace Core.Utils; + +// TODO: Finish porting this class +[Injectable(InjectionType.Singleton)] public class RandomUtil { + private readonly Random _random = new(); + /// + /// Generates a random integer between the specified minimum and maximum values, inclusive. + /// + /// The minimum value (inclusive). + /// The maximum value (inclusive). + /// A random integer between the specified minimum and maximum values. + public int GetInt(int min, int max) + { + // Prevents a potential integer overflow. + if (max == int.MaxValue) + { + max -= 1; + } + + // maxVal is exclusive of the passed value, so add 1 + return max > min ? _random.Next(min, 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. + /// + /// 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 boolean value. + /// + /// A random boolean value, where the probability of `true` and `false` is approximately equal. + public bool GetBool() + { + return GetSecureRandomNumber() < 0.5; + } + + /// + /// Calculates the percentage of a given number and returns the result. + /// + /// The percentage to calculate. + /// 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(float percent, float number, int toFixed = 2) + { + var num = percent * number / 100; + + return (float)Math.Round(num, toFixed); + } + + /// + /// Reduces a given number by a specified percentage. + /// + /// The original number to be reduced. + /// The percentage by which to reduce the number. + /// The reduced number after applying the percentage reduction. + public float ReduceValueByPercent(float number, float percentage) + { + var reductionAmount = number * percentage / 100; + + return number - reductionAmount; + } + + /// + /// Determines if a random event occurs based on the given chance percentage. + /// + /// The percentage chance (0-100) that the event will occur. + /// `true` if the event occurs, `false` otherwise. + public bool GetChance100(float chancePercent) + { + chancePercent = Math.Clamp(chancePercent, 0f, 100f); + + return GetIntEx(100) <= chancePercent; + } + + /// + /// Returns a random string from the provided collection of strings. + /// + /// This method is separate from GetCollectionValue so we can use a generic inference with GetCollectionValue. + /// + /// The collection of strings to select a random value from. + /// A randomly selected string from the array. + public string GetStringCollectionValue(IEnumerable collection) + { + return collection.ElementAt(GetInt(0, collection.Count() - 1)); + } + + /// + /// Returns a random string from the provided collection of strings. + /// + /// + /// The type of elements in the collection. + /// A random element from the collection. + /// This was formerly getArrayValue() in the node server + public T GetCollectionValue(IEnumerable collection) + { + return collection.ElementAt(GetInt(0, collection.Count() - 1)); + } + + /// + /// Gets a random key from the given dictionary + /// + /// The dictionary from which to retrieve a key. + /// Type of key + /// Type of Value + /// A random TKey representing one of the keys of the dictionary. + public TKey GetKey(Dictionary dictionary) where TKey : notnull + { + return GetCollectionValue(dictionary.Keys); + } + + /// + /// Generates a secure random number between 0 (inclusive) and 1 (exclusive). + /// + /// This method uses the `crypto` module to generate a 48-bit random integer, + /// which is then divided by the maximum possible 48-bit integer value to + /// produce a floating-point number in the range [0, 1). + /// + /// A secure random number between 0 (inclusive) and 1 (exclusive). + private static double GetSecureRandomNumber() + { + var buffer = new byte[6]; + + using var rng = RandomNumberGenerator.Create(); + + // Fill buffer with random bytes + rng.GetBytes(buffer); + + var integer = 0; + for (var i = 0; i < 6; i++) + { + integer = (integer << 8) | buffer[i]; + } + + const ulong maxInt = 1UL << 48; + + return (double)integer / maxInt; + } + + /// + /// Determines the number of decimal places in a number. + /// + /// The number to analyze. + /// The number of decimal places, or 0 if none exist. + private static int GetNumberPrecision(double num) + { + return num.ToString().Split('.')[1]?.Length ?? 0; + } } \ No newline at end of file