From ecfaa68ae6ac96fe7e92f988b89011e824e4dc99 Mon Sep 17 00:00:00 2001 From: Moony Date: Sun, 8 Feb 2026 14:09:48 +0100 Subject: [PATCH] Deprecate System.Random leakage --- Robust.Shared/Map/ITileDefinitionManager.cs | 5 ++++- Robust.Shared/Random/IRobustRandom.cs | 6 +++++ Robust.Shared/Random/RandomExtensions.cs | 17 +++++++++++++- Robust.Shared/Random/RobustRandom.cs | 25 +++++++++++++++------ 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/Robust.Shared/Map/ITileDefinitionManager.cs b/Robust.Shared/Map/ITileDefinitionManager.cs index 02c087408..708639ebe 100644 --- a/Robust.Shared/Map/ITileDefinitionManager.cs +++ b/Robust.Shared/Map/ITileDefinitionManager.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Robust.Shared.Random; @@ -12,10 +13,12 @@ namespace Robust.Shared.Map { Tile GetVariantTile(string name, IRobustRandom random); + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] Tile GetVariantTile(string name, System.Random random); Tile GetVariantTile(ITileDefinition tileDef, IRobustRandom random); + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] Tile GetVariantTile(ITileDefinition tileDef, System.Random random); /// diff --git a/Robust.Shared/Random/IRobustRandom.cs b/Robust.Shared/Random/IRobustRandom.cs index 488903592..a052f4b8d 100644 --- a/Robust.Shared/Random/IRobustRandom.cs +++ b/Robust.Shared/Random/IRobustRandom.cs @@ -176,8 +176,10 @@ public interface IRobustRandom } } +[Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static class RandomHelpers { + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static void Shuffle(this System.Random random, IList list) { var n = list.Count; @@ -189,24 +191,28 @@ public static class RandomHelpers } } + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static bool Prob(this System.Random random, double chance) { return random.NextDouble() < chance; } [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static byte NextByte(this System.Random random, byte maxValue) { return NextByte(random, 0, maxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static byte NextByte(this System.Random random) { return NextByte(random, byte.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static byte NextByte(this System.Random random, byte minValue, byte maxValue) { return (byte)random.Next(minValue, maxValue); diff --git a/Robust.Shared/Random/RandomExtensions.cs b/Robust.Shared/Random/RandomExtensions.cs index 36d60a4eb..12a8da8a0 100644 --- a/Robust.Shared/Random/RandomExtensions.cs +++ b/Robust.Shared/Random/RandomExtensions.cs @@ -19,7 +19,13 @@ public static class RandomExtensions /// The standard deviation of the normal distribution. public static double NextGaussian(this IRobustRandom random, double μ = 0, double σ = 1) { - return random.GetRandom().NextGaussian(μ, σ); + // https://stackoverflow.com/a/218600 + var α = random.NextDouble(); + var β = random.NextDouble(); + + var randStdNormal = Math.Sqrt(-2.0 * Math.Log(α)) * Math.Sin(2.0 * Math.PI * β); + + return μ + σ * randStdNormal; } /// Picks a random element from a collection. @@ -78,6 +84,7 @@ public static class RandomExtensions /// Picks a random element from a set and returns it. /// This is O(n) as it has to iterate the collection until the target index. /// + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static T Pick(this System.Random random, ICollection collection) { var index = random.Next(collection.Count); @@ -97,6 +104,7 @@ public static class RandomExtensions /// Picks a random from a collection then removes it and returns it. /// This is O(n) as it has to iterate the collection until the target index. /// + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static T PickAndTake(this System.Random random, ICollection set) { var tile = Pick(random, set); @@ -110,6 +118,7 @@ public static class RandomExtensions /// The random object to generate the number from. /// The average or "center" of the normal distribution. /// The standard deviation of the normal distribution. + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static double NextGaussian(this System.Random random, double μ = 0, double σ = 1) { // https://stackoverflow.com/a/218600 @@ -121,17 +130,21 @@ public static class RandomExtensions return μ + σ * randStdNormal; } + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static Angle NextAngle(this System.Random random) => NextFloat(random) * MathF.Tau; + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static Angle NextAngle(this System.Random random, Angle minAngle, Angle maxAngle) { DebugTools.Assert(minAngle < maxAngle); return minAngle + (maxAngle - minAngle) * random.NextDouble(); } + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static Vector2 NextPolarVector2(this System.Random random, float minMagnitude, float maxMagnitude) => random.NextAngle().RotateVec(new Vector2(random.NextFloat(minMagnitude, maxMagnitude), 0)); + [Obsolete("Exists as a method directly on IRobustRandom.")] public static float NextFloat(this IRobustRandom random) { // This is pretty much the CoreFX implementation. @@ -140,11 +153,13 @@ public static class RandomExtensions return random.Next() * 4.6566128752458E-10f; } + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static float NextFloat(this System.Random random) { return random.Next() * 4.6566128752458E-10f; } + [Obsolete("Always use RobustRandom/IRobustRandom, System.Random does not provide any extra functionality.")] public static float NextFloat(this System.Random random, float minValue, float maxValue) => random.NextFloat() * (maxValue - minValue) + minValue; diff --git a/Robust.Shared/Random/RobustRandom.cs b/Robust.Shared/Random/RobustRandom.cs index 7cbbb32ce..9745156d0 100644 --- a/Robust.Shared/Random/RobustRandom.cs +++ b/Robust.Shared/Random/RobustRandom.cs @@ -4,15 +4,23 @@ using Robust.Shared.Utility; namespace Robust.Shared.Random; /// -/// Wrapper for . +/// Provides random numbers, can be constructed in user code or used as a dependency in the form of +/// . Methods that take RNG as input should take an IRobustRandom instead. /// -/// -/// This should not contain any logic, not directly related to calling specific methods of . -/// To write additional logic, attached to random roll, please create interface-implemented methods on -/// or add it to . -/// +/// +/// +/// var myRng = new RobustRandom(); +/// // Optionally, seed your RNG. By default, the RNG is seeded randomly. +/// myRng.SetSeed(17); +///
+/// var fairDiceRoll = myRng.Next(1, 6); // Will be 4 with this seed. +///
+///
public sealed class RobustRandom : IRobustRandom { + // This should not contain any logic, not directly related to calling specific methods of . + // To write additional logic, attached to random roll, please create interface-implemented methods on + // or add it to . private System.Random _random = new(); public System.Random GetRandom() => _random; @@ -24,7 +32,10 @@ public sealed class RobustRandom : IRobustRandom public float NextFloat() { - return _random.NextFloat(); + // This is pretty much the CoreFX implementation. + // So credits to that. + // Except using float instead of double. + return Next() * 4.6566128752458E-10f; } public int Next()