Update Random to be a bit more thread safe

Random isn't thread safe; users of PKHeX.Core.dll might run multithreaded operations (see PKSM + ALM), so we need to have a thread-specific RNG available.

Thread Local get; to improve performance, save the random object locally whenever it is used more than once in the method.

https://docs.microsoft.com/en-us/dotnet/api/system.threading.threadlocal-1?redirectedfrom=MSDN&view=netframework-4.8
https://stackoverflow.com/questions/18333885/threadstatic-v-s-threadlocalt-is-generic-better-than-attribute/18337158#18337158
This commit is contained in:
Kurt 2020-01-25 21:49:52 -08:00
parent 1520210e68
commit c301ce88ab
23 changed files with 128 additions and 77 deletions

View file

@ -66,8 +66,9 @@ namespace PKHeX.Core
/// <param name="gender">Desired <see cref="PKM.Gender"/>.</param>
public static void SetATKIVGender(this PKM pk, int gender)
{
var rnd = Util.Rand;
while (pk.Gender != gender)
pk.IV_ATK = Util.Rand.Next(pk.MaxIV + 1);
pk.IV_ATK = rnd.Next(16);
}
}
}

View file

@ -90,7 +90,7 @@ namespace PKHeX.Core
if (pk is PK5 pk5 && abilIndex == 2)
pk5.HiddenAbility = true;
else if (pk.Format <= 5)
pk.PID = PKX.GetRandomPID(pk.Species, pk.Gender, pk.Version, pk.Nature, pk.AltForm, (uint)(abilIndex * 0x10001));
pk.PID = PKX.GetRandomPID(Util.Rand, pk.Species, pk.Gender, pk.Version, pk.Nature, pk.AltForm, (uint)(abilIndex * 0x10001));
pk.RefreshAbility(abilIndex);
}

View file

@ -20,11 +20,12 @@ namespace PKHeX.Core
internal static int RandomValidTime(this EncounterTime t1)
{
int val = Util.Rand.Next(1, 4);
var rnd = Util.Rand;
int val = rnd.Next(1, 4);
if (t1 == EncounterTime.Any)
return val;
while (!t1.Contains(val))
val = Util.Rand.Next(1, 4);
val = rnd.Next(1, 4);
return val;
}
}

View file

@ -401,14 +401,15 @@ namespace PKHeX.Core
private static void SetRandomIVs(PKM pk)
{
var rng = Util.Rand;
pk.IVs = new[]
{
Util.Rand.Next(32),
Util.Rand.Next(32),
Util.Rand.Next(32),
Util.Rand.Next(32),
Util.Rand.Next(32),
Util.Rand.Next(32),
rng.Next(32),
rng.Next(32),
rng.Next(32),
rng.Next(32),
rng.Next(32),
rng.Next(32),
};
}
}

View file

@ -183,9 +183,10 @@ namespace PKHeX.Core
public static int GetRandomFeeling(int memory, int max = 24)
{
var bits = MemoryFeelings[memory];
var rnd = Util.Rand;
while (true)
{
int feel = Util.Rand.Next(max);
int feel = rnd.Next(max);
if ((bits & (1 << feel)) != 0)
return feel;
}

View file

@ -38,9 +38,10 @@ namespace PKHeX.Core
const int max = (int) GameVersion.RB;
if ((int)ver.Version < max)
return ver.Version;
var rnd = Util.Rand;
while (true) // this isn't optimal, but is low maintenance
{
var game = (GameVersion)Util.Rand.Next(1, max);
var game = (GameVersion)rnd.Next(1, max);
if (ver.CanBeReceivedBy(game))
return game;
}

View file

@ -166,6 +166,8 @@ namespace PKHeX.Core
if (!IsPokémon)
throw new ArgumentException(nameof(IsPokémon));
var rnd = Util.Rand;
var dt = DateTime.Now;
if (Day == 0)
{
@ -174,14 +176,14 @@ namespace PKHeX.Core
Year = (byte)dt.Year;
}
int currentLevel = Level > 0 ? Level : Util.Rand.Next(100) + 1;
int currentLevel = Level > 0 ? Level : rnd.Next(1, 101);
var pi = PersonalTable.B2W2.GetFormeEntry(Species, Form);
PK5 pk = new PK5
{
Species = Species,
HeldItem = HeldItem,
Met_Level = currentLevel,
Nature = Nature != -1 ? Nature : Util.Rand.Next(25),
Nature = Nature != -1 ? Nature : rnd.Next(25),
AltForm = Form,
Version = OriginGame == 0 ? SAV.Game : OriginGame,
Language = Language == 0 ? SAV.Language : Language,
@ -223,7 +225,7 @@ namespace PKHeX.Core
FatefulEncounter = true,
};
if (SAV.Generation > 5 && OriginGame == 0) // Gen6+, give random gen5 game
pk.Version = (int)GameVersion.W + Util.Rand.Next(4);
pk.Version = (int)GameVersion.W + rnd.Next(4);
if (Move1 == 0) // No moves defined
pk.Moves = MoveLevelUp.GetEncounterMoves(Species, Form, Level, (GameVersion)pk.Version);
@ -304,7 +306,8 @@ namespace PKHeX.Core
pk.PID = Util.Rand32();
// Force Gender
do { pk.PID = (pk.PID & 0xFFFFFF00) | (uint)Util.Rand.Next(0x100); }
var rnd = Util.Rand;
do { pk.PID = (pk.PID & 0xFFFFFF00) | (uint)rnd.Next(0x100); }
while (!pk.IsGenderValid());
if (PIDType == 2) // Always
@ -327,8 +330,9 @@ namespace PKHeX.Core
private void SetIVs(PKM pk)
{
int[] finalIVs = new int[6];
var rnd = Util.Rand;
for (int i = 0; i < IVs.Length; i++)
finalIVs[i] = IVs[i] == 0xFF ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i];
finalIVs[i] = IVs[i] == 0xFF ? rnd.Next(32) : IVs[i];
pk.IVs = finalIVs;
}

View file

@ -317,7 +317,9 @@ namespace PKHeX.Core
if (!IsPokémon)
throw new ArgumentException(nameof(IsPokémon));
int currentLevel = Level > 0 ? Level : Util.Rand.Next(100) + 1;
var rnd = Util.Rand;
int currentLevel = Level > 0 ? Level : rnd.Next(1, 101);
int metLevel = MetLevel > 0 ? MetLevel : currentLevel;
var pi = PersonalTable.GG.GetFormeEntry(Species, Form);
var OT = GetOT(SAV.Language);
@ -370,7 +372,7 @@ namespace PKHeX.Core
if ((SAV.Generation > Format && OriginGame == 0) || !CanBeReceivedByVersion(pk.Version))
{
// give random valid game
do { pk.Version = (int)GameVersion.GP + Util.Rand.Next(2); }
do { pk.Version = (int)GameVersion.GP + rnd.Next(2); }
while (!CanBeReceivedByVersion(pk.Version));
}
@ -390,8 +392,8 @@ namespace PKHeX.Core
SetEggMetData(pk);
pk.CurrentFriendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship;
pk.HeightScalar = Util.Rand.Next(0x100);
pk.WeightScalar = Util.Rand.Next(0x100);
pk.HeightScalar = rnd.Next(0x100);
pk.WeightScalar = rnd.Next(0x100);
pk.ResetCalculatedValues(); // cp & dimensions
pk.RefreshChecksum();
@ -458,18 +460,19 @@ namespace PKHeX.Core
{
int[] finalIVs = new int[6];
var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3);
var rng = Util.Rand;
if (ivflag == 0) // Random IVs
{
for (int i = 0; i < 6; i++)
finalIVs[i] = IVs[i] > 31 ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i];
finalIVs[i] = IVs[i] > 31 ? rng.Next(32) : IVs[i];
}
else // 1/2/3 perfect IVs
{
int IVCount = ivflag - 0xFB;
do { finalIVs[Util.Rand.Next(6)] = 31; }
do { finalIVs[rng.Next(6)] = 31; }
while (finalIVs.Count(iv => iv == 31) < IVCount);
for (int i = 0; i < 6; i++)
finalIVs[i] = finalIVs[i] == 31 ? pk.MaxIV : Util.Rand.Next(pk.MaxIV + 1);
finalIVs[i] = finalIVs[i] == 31 ? 31 : rng.Next(32);
}
pk.IVs = finalIVs;
}

View file

@ -270,7 +270,9 @@ namespace PKHeX.Core
if (!IsPokémon)
throw new ArgumentException(nameof(IsPokémon));
int currentLevel = Level > 0 ? Level : Util.Rand.Next(100) + 1;
var rnd = Util.Rand;
int currentLevel = Level > 0 ? Level : rnd.Next(1, 101);
var pi = PersonalTable.AO.GetFormeEntry(Species, Form);
PK6 pk = new PK6
{
@ -342,7 +344,7 @@ namespace PKHeX.Core
if ((SAV.Generation > Format && OriginGame == 0) || !CanBeReceivedByVersion(pk.Version))
{
// give random valid game
do { pk.Version = (int)GameVersion.X + Util.Rand.Next(4); }
do { pk.Version = (int)GameVersion.X + rnd.Next(4); }
while (!CanBeReceivedByVersion(pk.Version));
}
@ -438,18 +440,19 @@ namespace PKHeX.Core
{
int[] finalIVs = new int[6];
var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3);
var rnd = Util.Rand;
if (ivflag == 0) // Random IVs
{
for (int i = 0; i < 6; i++)
finalIVs[i] = IVs[i] > 31 ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i];
finalIVs[i] = IVs[i] > 31 ? rnd.Next(32) : IVs[i];
}
else // 1/2/3 perfect IVs
{
int IVCount = ivflag - 0xFB;
do { finalIVs[Util.Rand.Next(6)] = 31; }
do { finalIVs[rnd.Next(6)] = 31; }
while (finalIVs.Count(iv => iv == 31) < IVCount);
for (int i = 0; i < 6; i++)
finalIVs[i] = finalIVs[i] == 31 ? pk.MaxIV : Util.Rand.Next(pk.MaxIV + 1);
finalIVs[i] = finalIVs[i] == 31 ? 31 : rnd.Next(32);
}
pk.IVs = finalIVs;
}

View file

@ -313,7 +313,9 @@ namespace PKHeX.Core
if (!IsPokémon)
throw new ArgumentException(nameof(IsPokémon));
int currentLevel = Level > 0 ? Level : Util.Rand.Next(100) + 1;
var rnd = Util.Rand;
int currentLevel = Level > 0 ? Level : rnd.Next(1, 101);
int metLevel = MetLevel > 0 ? MetLevel : currentLevel;
var pi = PersonalTable.USUM.GetFormeEntry(Species, Form);
PK7 pk = new PK7
@ -384,7 +386,7 @@ namespace PKHeX.Core
if ((SAV.Generation > Format && OriginGame == 0) || !CanBeReceivedByVersion(pk.Version))
{
// give random valid game
do { pk.Version = (int)GameVersion.SN + Util.Rand.Next(4); }
do { pk.Version = (int)GameVersion.SN + rnd.Next(4); }
while (!CanBeReceivedByVersion(pk.Version));
}
@ -469,18 +471,19 @@ namespace PKHeX.Core
{
int[] finalIVs = new int[6];
var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3);
var rng = Util.Rand;
if (ivflag == 0) // Random IVs
{
for (int i = 0; i < 6; i++)
finalIVs[i] = IVs[i] > 31 ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i];
finalIVs[i] = IVs[i] > 31 ? rng.Next(32) : IVs[i];
}
else // 1/2/3 perfect IVs
{
int IVCount = ivflag - 0xFB;
do { finalIVs[Util.Rand.Next(6)] = 31; }
do { finalIVs[rng.Next(6)] = 31; }
while (finalIVs.Count(iv => iv == 31) < IVCount);
for (int i = 0; i < 6; i++)
finalIVs[i] = finalIVs[i] == 31 ? pk.MaxIV : Util.Rand.Next(pk.MaxIV + 1);
finalIVs[i] = finalIVs[i] == 31 ? 31 : rng.Next(32);
}
pk.IVs = finalIVs;
}

View file

@ -299,7 +299,7 @@ namespace PKHeX.Core
if (!IsPokémon)
throw new ArgumentException(nameof(IsPokémon));
int currentLevel = Level > 0 ? Level : Util.Rand.Next(100) + 1;
int currentLevel = Level > 0 ? Level : Util.Rand.Next(1, 101);
int metLevel = MetLevel > 0 ? MetLevel : currentLevel;
var pi = PersonalTable.SWSH.GetFormeEntry(Species, Form);
var OT = GetOT(SAV.Language);
@ -356,7 +356,8 @@ namespace PKHeX.Core
if ((SAV.Generation > Format && OriginGame == 0) || !CanBeReceivedByVersion(pk.Version))
{
// give random valid game
do { pk.Version = (int)GameVersion.SW + Util.Rand.Next(2); }
var rnd = Util.Rand;
do { pk.Version = (int)GameVersion.SW + rnd.Next(2); }
while (!CanBeReceivedByVersion(pk.Version));
}
@ -471,18 +472,19 @@ namespace PKHeX.Core
{
int[] finalIVs = new int[6];
var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3);
var rng = Util.Rand;
if (ivflag == 0) // Random IVs
{
for (int i = 0; i < 6; i++)
finalIVs[i] = IVs[i] > 31 ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i];
finalIVs[i] = IVs[i] > 31 ? rng.Next(32) : IVs[i];
}
else // 1/2/3 perfect IVs
{
int IVCount = ivflag - 0xFB;
do { finalIVs[Util.Rand.Next(6)] = 31; }
do { finalIVs[rng.Next(6)] = 31; }
while (finalIVs.Count(iv => iv == 31) < IVCount);
for (int i = 0; i < 6; i++)
finalIVs[i] = finalIVs[i] == 31 ? pk.MaxIV : Util.Rand.Next(pk.MaxIV + 1);
finalIVs[i] = finalIVs[i] == 31 ? 31 : rng.Next(32);
}
pk.IVs = finalIVs;
}

View file

@ -167,8 +167,11 @@ namespace PKHeX.Core
// IVs
var new_ivs = new int[6];
int flawless = Species == (int)Core.Species.Mew ? 5 : 3;
for (var i = 0; i < new_ivs.Length; i++) new_ivs[i] = Util.Rand.Next(pk7.MaxIV + 1);
for (var i = 0; i < flawless; i++) new_ivs[i] = 31;
var rnd = Util.Rand;
for (var i = 0; i < new_ivs.Length; i++)
new_ivs[i] = rnd.Next(pk7.MaxIV + 1);
for (var i = 0; i < flawless; i++)
new_ivs[i] = 31;
Util.Shuffle(new_ivs);
pk7.IVs = new_ivs;

View file

@ -167,8 +167,11 @@ namespace PKHeX.Core
var special = Species == 151 || Species == 251;
var new_ivs = new int[6];
int flawless = special ? 5 : 3;
for (var i = 0; i < new_ivs.Length; i++) new_ivs[i] = Util.Rand.Next(pk7.MaxIV + 1);
for (var i = 0; i < flawless; i++) new_ivs[i] = 31;
var rnd = Util.Rand;
for (var i = 0; i < new_ivs.Length; i++)
new_ivs[i] = rnd.Next(pk7.MaxIV + 1);
for (var i = 0; i < flawless; i++)
new_ivs[i] = 31;
Util.Shuffle(new_ivs);
pk7.IVs = new_ivs;

View file

@ -937,7 +937,8 @@ namespace PKHeX.Core
/// </remarks>
public virtual void SetShiny()
{
do { PID = PKX.GetRandomPID(Species, Gender, Version, Nature, AltForm, PID); }
var rnd = Util.Rand;
do { PID = PKX.GetRandomPID(rnd, Species, Gender, Version, Nature, AltForm, PID); }
while (!IsShiny);
if (Format >= 6 && (Gen3 || Gen4 || Gen5))
EncryptionConstant = PID;
@ -948,7 +949,8 @@ namespace PKHeX.Core
/// </summary>
public void SetShinySID()
{
if (IsShiny) return;
if (IsShiny)
return;
var xor = TID ^ (PID >> 16) ^ (PID & 0xFFFF);
SID = (int)(xor & 0xFFF8) | Util.Rand.Next(8);
}
@ -962,7 +964,9 @@ namespace PKHeX.Core
/// </remarks>
public void SetPIDGender(int gender)
{
do PID = PKX.GetRandomPID(Species, gender, Version, Nature, AltForm, PID); while (IsShiny);
var rnd = Util.Rand;
do PID = PKX.GetRandomPID(rnd, Species, gender, Version, Nature, AltForm, PID);
while (IsShiny);
if (Format >= 6 && (Gen3 || Gen4 || Gen5))
EncryptionConstant = PID;
}
@ -976,7 +980,9 @@ namespace PKHeX.Core
/// </remarks>
public void SetPIDNature(int nature)
{
do PID = PKX.GetRandomPID(Species, Gender, Version, nature, AltForm, PID); while (IsShiny);
var rnd = Util.Rand;
do PID = PKX.GetRandomPID(rnd, Species, Gender, Version, nature, AltForm, PID);
while (IsShiny);
if (Format >= 6 && (Gen3 || Gen4 || Gen5))
EncryptionConstant = PID;
}
@ -1007,8 +1013,9 @@ namespace PKHeX.Core
return SetRandomIVsGO();
int[] ivs = new int[6];
var rnd = Util.Rand;
for (int i = 0; i < 6; i++)
ivs[i] = Util.Rand.Next(MaxIV + 1);
ivs[i] = rnd.Next(MaxIV + 1);
int count = flawless ?? GetFlawlessIVCount();
if (count != 0)
@ -1023,10 +1030,11 @@ namespace PKHeX.Core
private int[] SetRandomIVsGO()
{
int[] ivs = new int[6];
ivs[0] = (Util.Rand.Next(16) << 1) | 1; // hp
ivs[1] = ivs[4] = (Util.Rand.Next(16) << 1) | 1; // attack
ivs[2] = ivs[5] = (Util.Rand.Next(16) << 1) | 1; // defense
ivs[3] = Util.Rand.Next(MaxIV + 1); // speed
var rnd = Util.Rand;
ivs[0] = (rnd.Next(16) << 1) | 1; // hp
ivs[1] = ivs[4] = (rnd.Next(16) << 1) | 1; // attack
ivs[2] = ivs[5] = (rnd.Next(16) << 1) | 1; // defense
ivs[3] = rnd.Next(MaxIV + 1); // speed
return IVs = ivs;
}
@ -1040,10 +1048,11 @@ namespace PKHeX.Core
{
int count = flawless ?? GetFlawlessIVCount();
int[] ivs = new int[6];
var rnd = Util.Rand;
do
{
for (int i = 0; i < 6; i++)
ivs[i] = template[i] < 0 ? Util.Rand.Next(MaxIV + 1) : template[i];
ivs[i] = template[i] < 0 ? rnd.Next(MaxIV + 1) : template[i];
} while (ivs.Count(z => z == MaxIV) < count);
IVs = ivs;

View file

@ -45,6 +45,10 @@
/// <summary>
/// Gets a random size scalar with a triangular distribution (copying official implementation).
/// </summary>
public static int GetRandomScalar() => Util.Rand.Next(0x81) + Util.Rand.Next(0x80);
public static int GetRandomScalar()
{
var rnd = Util.Rand;
return rnd.Next(0x81) + rnd.Next(0x80);
}
}
}

View file

@ -37,15 +37,15 @@ namespace PKHeX.Core
/// <returns>Array containing randomized EVs (H/A/B/S/C/D)</returns>
public static int[] GetRandomEVs(int generation = Generation)
{
var rnd = Util.Rand;
if (generation > 2)
{
var evs = new int[6];
do
{
int max = 510;
int randomEV() => (byte)Math.Min(Util.Rand.Next(Math.Min(300, max)), 252);
for (int i = 0; i < evs.Length - 1; i++)
max -= evs[i] = randomEV();
max -= evs[i] = (byte)Math.Min(rnd.Next(Math.Min(300, max)), 252);
evs[5] = max;
} while (evs[5] > 252);
Util.Shuffle(evs);
@ -55,7 +55,7 @@ namespace PKHeX.Core
{
var evs = new int[6];
for (int i = 0; i < evs.Length; i++)
evs[i] = Util.Rand.Next(ushort.MaxValue + 1);
evs[i] = rnd.Next(ushort.MaxValue + 1);
return evs;
}
}
@ -107,6 +107,7 @@ namespace PKHeX.Core
/// <summary>
/// Gets a random PID according to specifications.
/// </summary>
/// <param name="rnd">RNG to use</param>
/// <param name="species">National Dex ID</param>
/// <param name="cg">Current Gender</param>
/// <param name="origin">Origin Generation</param>
@ -115,17 +116,17 @@ namespace PKHeX.Core
/// <param name="OLDPID">Current PID</param>
/// <remarks>Used to retain ability bits.</remarks>
/// <returns>Rerolled PID.</returns>
public static uint GetRandomPID(int species, int cg, int origin, int nature, int form, uint OLDPID)
public static uint GetRandomPID(Random rnd, int species, int cg, int origin, int nature, int form, uint OLDPID)
{
uint bits = OLDPID & 0x00010001;
int gt = Personal[species].Gender;
if (origin >= 24)
return Util.Rand32();
return Util.Rand32(rnd);
bool g3unown = origin <= 5 && species == (int)Species.Unown;
while (true) // Loop until we find a suitable PID
{
uint pid = Util.Rand32();
uint pid = Util.Rand32(rnd);
// Gen 3/4: Nature derived from PID
if (origin <= 15 && pid%25 != nature)

View file

@ -35,16 +35,17 @@ namespace PKHeX.Core
public void MaxCheat(bool special = false)
{
var rnd = Util.Rand;
if (special)
{
for (int i = 0; i < PuffSlots; i++)
Data[Offset + i] = (byte)(21 + Util.Rand.Next(2)); // Supreme Wish or Honor
Data[Offset + i] = (byte)(21 + rnd.Next(2)); // Supreme Wish or Honor
}
else
{
for (int i = 0; i < PuffSlots; i++)
Data[Offset + i] = (byte)((i % MaxPuffID) + 1);
Util.Shuffle(Data, Offset, Offset + PuffSlots);
Util.Shuffle(Data, Offset, Offset + PuffSlots, rnd);
}
PuffCount = PuffSlots;
}

View file

@ -21,10 +21,11 @@ namespace PKHeX.Core
public void ActivateAllRaids(bool rare, bool isEvent)
{
var rnd = Util.Rand;
for (int i = 0; i < RaidCount; i++)
{
var star = (byte)Util.Rand.Next(0, 5);
var rand = (byte)Util.Rand.Next(0, 100);
var star = (byte)rnd.Next(0, 5);
var rand = (byte)rnd.Next(0, 100);
GetRaid(i).Activate(star, rand, rare, isEvent);
}
}

View file

@ -1,23 +1,25 @@
using System;
using System.Collections.Generic;
using System.Threading;
namespace PKHeX.Core
{
public static partial class Util
{
public static readonly Random Rand = new Random();
// Multithread safe rand, ha
public static Random Rand => _local.Value;
public static uint Rand32()
{
return (uint)Rand.Next(1 << 30) << 2 | (uint)Rand.Next(1 << 2);
}
private static readonly ThreadLocal<Random> _local = new ThreadLocal<Random>(() => new Random());
public static uint Rand32() => Rand32(Rand);
public static uint Rand32(Random rnd) => (uint)rnd.Next(1 << 30) << 2 | (uint)rnd.Next(1 << 2);
/// <summary>
/// Shuffles the order of items within a collection of items.
/// </summary>
/// <typeparam name="T">Item type</typeparam>
/// <param name="items">Item collection</param>
public static void Shuffle<T>(IList<T> items) => Shuffle(items, 0, items.Count);
public static void Shuffle<T>(IList<T> items) => Shuffle(items, 0, items.Count, Rand);
/// <summary>
/// Shuffles the order of items within a collection of items.
@ -26,11 +28,12 @@ namespace PKHeX.Core
/// <param name="items">Item collection</param>
/// <param name="start">Starting position</param>
/// <param name="end">Ending position</param>
public static void Shuffle<T>(IList<T> items, int start, int end)
/// <param name="rnd">RNG object to use</param>
public static void Shuffle<T>(IList<T> items, int start, int end, Random rnd)
{
for (int i = start; i < end; i++)
{
int index = i + Rand.Next(end - i);
int index = i + rnd.Next(end - i);
T t = items[index];
items[index] = items[i];
items[i] = t;

View file

@ -364,8 +364,9 @@ namespace PKHeX.WinForms.Controls
a.AwakeningSetAllTo(0);
break;
default:
var rnd = Util.Rand;
foreach (var index in Enumerable.Range(0, 6))
a.SetAV(index, Util.Rand.Next(Legal.AwakeningMax + 1));
a.SetAV(index, rnd.Next(Legal.AwakeningMax + 1));
break;
}
LoadAVs(a);

View file

@ -23,7 +23,10 @@ namespace PKHeX.WinForms
public partial class Main : Form
{
private static readonly Version CurrentProgramVersion = Assembly.GetExecutingAssembly().GetName().Version;
static async Task<LegalityAnalysis> GetLegal(PKM pkm)
{
return await Task.Run(() => new LegalityAnalysis(pkm));
}
public Main()
{
Form splash = null; // popup a splash screen in another thread

View file

@ -672,14 +672,15 @@ namespace PKHeX.WinForms
private void B_RandForest_Click(object sender, EventArgs e)
{
var source = (SAV is SAV5B2W2 ? Encounters5.B2W2_DreamWorld : Encounters5.BW_DreamWorld).ToList();
var rnd = Util.Rand;
foreach (var s in AllSlots)
{
int index = Util.Rand.Next(source.Count);
int index = rnd.Next(source.Count);
var slot = source[index];
source.Remove(slot);
s.Species = slot.Species;
s.Form = slot.Form;
s.Move = slot.Moves[Util.Rand.Next(slot.Moves.Count)];
s.Move = slot.Moves[rnd.Next(slot.Moves.Count)];
s.Gender = slot.Gender == -1 ? PersonalTable.B2W2[slot.Species].RandomGender() : slot.Gender;
}
ChangeArea(null, EventArgs.Empty); // refresh

View file

@ -47,9 +47,10 @@ namespace PKHeX.WinForms
// Randomize the trees.
byte[] tree = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x80, 0x40, 0x01, 0x00, 0x00, 0x00, };
var plantable = Legal.Pouch_Berry_XY; // 0 index is None, skip with rand
var rnd = Util.Rand;
for (int i = 0; i < 90; i++) // amount of plots in the game
{
ushort berry = plantable[Util.Rand.Next(1, plantable.Length)]; // get random berry item ID from list
ushort berry = plantable[rnd.Next(1, plantable.Length)]; // get random berry item ID from list
BitConverter.GetBytes(berry).CopyTo(tree, 6); // put berry into tree.
tree.CopyTo(SAV.Data, SAV.BerryField + (0x10 * i)); // put tree into plot
}