Skip to content

Commit

Permalink
Update Random to be a bit more thread safe
Browse files Browse the repository at this point in the history
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
  • Loading branch information
kwsch committed Jan 26, 2020
1 parent 1520210 commit c301ce8
Show file tree
Hide file tree
Showing 23 changed files with 128 additions and 77 deletions.
3 changes: 2 additions & 1 deletion PKHeX.Core/Editing/Applicators/GenderApplicator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ public static int GetSaneGender(this PKM pk)
/// <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);
}
}
}
2 changes: 1 addition & 1 deletion PKHeX.Core/Editing/CommonEdits.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public static void SetAbilityIndex(this PKM pk, int abilIndex)
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);
}

Expand Down
5 changes: 3 additions & 2 deletions PKHeX.Core/Legality/Enums/EncounterTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ internal static class EncounterTimeExtension

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;
}
}
Expand Down
13 changes: 7 additions & 6 deletions PKHeX.Core/Legality/RNG/PIDGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -401,14 +401,15 @@ private static void SetRandomWildPID(PKM pk, int nature, int ability, int gender

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),
};
}
}
Expand Down
3 changes: 2 additions & 1 deletion PKHeX.Core/Legality/Restrictions/Memories.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,10 @@ public static bool CanHaveIntensity(int memory, int intensity)
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;
}
Expand Down
3 changes: 2 additions & 1 deletion PKHeX.Core/Legality/Structures/IVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ private static GameVersion GetSingleVersion(this IVersion ver)
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;
}
Expand Down
14 changes: 9 additions & 5 deletions PKHeX.Core/MysteryGifts/PGF.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria)
if (!IsPokémon)
throw new ArgumentException(nameof(IsPokémon));

var rnd = Util.Rand;

var dt = DateTime.Now;
if (Day == 0)
{
Expand All @@ -174,14 +176,14 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria)
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,
Expand Down Expand Up @@ -223,7 +225,7 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria)
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);
Expand Down Expand Up @@ -304,7 +306,8 @@ private void SetPID(PKM pk, int av)

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
Expand All @@ -327,8 +330,9 @@ private void SetPID(PKM pk, int av)
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;
}

Expand Down
17 changes: 10 additions & 7 deletions PKHeX.Core/MysteryGifts/WB7.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,9 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria)
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);
Expand Down Expand Up @@ -370,7 +372,7 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria)
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));
}

Expand All @@ -390,8 +392,8 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria)
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();
Expand Down Expand Up @@ -458,18 +460,19 @@ private void SetIVs(PKM pk)
{
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;
}
Expand Down
13 changes: 8 additions & 5 deletions PKHeX.Core/MysteryGifts/WC6.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,9 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria)
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
{
Expand Down Expand Up @@ -342,7 +344,7 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria)
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));
}

Expand Down Expand Up @@ -438,18 +440,19 @@ private void SetIVs(PKM pk)
{
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;
}
Expand Down
13 changes: 8 additions & 5 deletions PKHeX.Core/MysteryGifts/WC7.cs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,9 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria)
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
Expand Down Expand Up @@ -384,7 +386,7 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria)
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));
}

Expand Down Expand Up @@ -469,18 +471,19 @@ private void SetIVs(PKM pk)
{
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;
}
Expand Down
12 changes: 7 additions & 5 deletions PKHeX.Core/MysteryGifts/WC8.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria)
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);
Expand Down Expand Up @@ -356,7 +356,8 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria)
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));
}

Expand Down Expand Up @@ -471,18 +472,19 @@ private void SetIVs(PKM pk)
{
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;
}
Expand Down
7 changes: 5 additions & 2 deletions PKHeX.Core/PKM/PK1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,11 @@ public PK7 ConvertToPK7()
// 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;

Expand Down
7 changes: 5 additions & 2 deletions PKHeX.Core/PKM/PK2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,11 @@ public PK7 ConvertToPK7()
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;

Expand Down
Loading

0 comments on commit c301ce8

Please sign in to comment.