Repository navigation
Random
Seeded random source plus dice and coin helpers. All helpers take an IRandom so you can swap implementations (domain ManeRandom, the shared GlobalRandom, Unity-backed UnityRandom from ManeTools-Unity, or a fake in tests).
using Mane.DotNet;
IRandom rng = new ManeRandom(42); // deterministic
int d20 = RandomDice.Roll20(rng); // 1..20 inclusive
bool heads = RandomCoin.Flip(rng);
float t = rng.Range01(); // [0, 1)| Member | Range |
|---|---|
Seed |
Stored seed |
Next(min, max) |
[min, max) — same as System.Random.Next
|
Range01() |
[0, 1) float |
Range01Inc() |
[0, 1] float, 1 included (like Unity's Random.value) |
Range01Double() |
[0, 1) double |
Use Range01() to scale into an index ((int)(rng.Range01() * count) never reaches count), and Range01Inc() when both ends are valid results, like a lerp factor or a probability that should be able to hit 100%.
Shared IRandom slot with the same lifecycle as ManeSingleton: Instance, IsReady, SetInstance, ClearInstance. It does not inherit ManeSingleton<T>, because that slot can only store the singleton type itself. Here _instance is the IRandom.
The first access to Instance stores a ManeRandom with a random seed, which I do not recommend. Use SetInstance with your own instance and the seed you want. That is good practice in game development when you need to control and reproduce random-based logic. SetInstance replaces whatever is stored. Null throws. ClearInstance drops it; the next Instance access stores a new ManeRandom.
Calls through Instance are serialized, so overlapping draws are safe even when the stored source is not. A reference kept to the inner object bypasses that lock.
GlobalRandom.SetInstance(new ManeRandom(42));
int roll = RandomDice.Roll20(GlobalRandom.Instance);Pass GlobalRandom.Instance anywhere an IRandom is required, including Unity helpers. Swap in UnityRandom the same way when you want Unity's RNG in that slot.
Wraps System.Random. Overlapping Next / Range01 / Range01Inc / Range01Double calls on one instance are serialized. Reading Seed does not take the lock.
Note
System.Random does not allow overlapping calls on one instance. Two threads drawing at the same time can interleave its internal update: duplicate numbers, a sequence that no longer matches the seed, or a generator that sticks on 0. A later call on the same object after the previous one has returned is fine.
ManeRandom takes a lock around those draws, so one instance is safe to share. GlobalRandom.Instance does the same for whatever source is stored, including a custom IRandom that has no lock of its own. A reference you kept to that inner object does not take the GlobalRandom lock.
-
new ManeRandom(int seed)— deterministic. -
new ManeRandom()— seed fromRandomNumberGenerator(crypto).Seedstill exposes the chosen int.
Pass a null IRandom into dice/coin helpers and they throw ArgumentNullException.
RandomDice.Roll(sides, random) returns [1, sides] inclusive (sides >= 1). Presets: Roll4, Roll6, Roll8, Roll10, Roll12, Roll20.
RandomCoin.Flip(random) is Roll(2) == 1.
Unity-side sampling (RandomPoint, RandomColor, RandomDirection) is documented in the Unity wiki.
openupm add com.manefunction.tools-dotnet