From e5c3c43bdaac0b0861d6befe18e2406d7159a10d Mon Sep 17 00:00:00 2001 From: Kurt Date: Tue, 1 Oct 2024 00:00:19 -0500 Subject: [PATCH] EncounterCriteria: sbyte IVs Narrow fields to reduce allocation < 16 bytes (maybe make this a struct?) Add method to get combined IVs (gen3/4 format) for RNG purposes use ^ method in RNG methods Change GetExpectedLevel to be generic rather than interface, better codegen Change Gender to enum for clarity breaks ALM and potentially other plugins, just need to recompile if using IVs --- PKHeX.Core/Editing/IBattleTemplate.cs | 2 +- PKHeX.Core/Editing/Showdown/ShowdownSet.cs | 6 +-- .../Encounters/Generator/EncounterCriteria.cs | 54 ++++++++++--------- PKHeX.Core/Legality/RNG/CXD/MethodCXD.cs | 11 +--- .../RNG/ClassicEra/Gen3/GenerateMethodH.cs | 11 +--- .../Legality/RNG/ClassicEra/Gen3/MethodH.cs | 7 +-- .../RNG/ClassicEra/Gen4/GenerateMethodJ.cs | 9 +--- .../RNG/ClassicEra/Gen4/GenerateMethodK.cs | 9 +--- .../Legality/RNG/ClassicEra/Gen4/MethodJ.cs | 7 +-- .../Legality/RNG/ClassicEra/Gen4/MethodK.cs | 7 +-- PKHeX.WinForms/Subforms/SAV_Encounters.cs | 2 +- 11 files changed, 53 insertions(+), 72 deletions(-) diff --git a/PKHeX.Core/Editing/IBattleTemplate.cs b/PKHeX.Core/Editing/IBattleTemplate.cs index 1fa1577e1..c91c5a80e 100644 --- a/PKHeX.Core/Editing/IBattleTemplate.cs +++ b/PKHeX.Core/Editing/IBattleTemplate.cs @@ -53,7 +53,7 @@ public interface IBattleTemplate : ISpeciesForm, IGigantamaxReadOnly, IDynamaxLe /// /// of the Set entity. /// - int HiddenPowerType { get; } + sbyte HiddenPowerType { get; } /// /// of the Set entity. diff --git a/PKHeX.Core/Editing/Showdown/ShowdownSet.cs b/PKHeX.Core/Editing/Showdown/ShowdownSet.cs index 1229f71e5..0fd1e6e4f 100644 --- a/PKHeX.Core/Editing/Showdown/ShowdownSet.cs +++ b/PKHeX.Core/Editing/Showdown/ShowdownSet.cs @@ -68,7 +68,7 @@ public sealed class ShowdownSet : IBattleTemplate public int[] IVs { get; } = [31, 31, 31, 31, 31, 31]; /// - public int HiddenPowerType { get; private set; } = -1; + public sbyte HiddenPowerType { get; private set; } = -1; public MoveType TeraType { get; private set; } = MoveType.Any; @@ -512,7 +512,7 @@ public ShowdownSet(PKM pk) var moves = Moves.AsSpan(); pk.GetMoves(moves); if (moves.Contains((ushort)Move.HiddenPower)) - HiddenPowerType = HiddenPower.GetType(IVs, Context); + HiddenPowerType = (sbyte)HiddenPower.GetType(IVs, Context); Nature = pk.StatNature; Gender = pk.Gender < 2 ? pk.Gender : (byte)2; @@ -719,7 +719,7 @@ private ReadOnlySpan ParseLineMove(ReadOnlySpan line) if (hpVal == -1) return hiddenPowerName; - HiddenPowerType = hpVal; + HiddenPowerType = (sbyte)hpVal; if (!Array.TrueForAll(IVs, z => z == 31)) { if (!HiddenPower.SetIVsForType(hpVal, IVs, Context)) diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs index 40fe6336d..48788258b 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs @@ -14,8 +14,8 @@ public sealed record EncounterCriteria : IFixedNature, IFixedAbilityNumber, IShi public static readonly EncounterCriteria Unrestricted = new(); /// End result's gender. - /// Leave as null to not restrict gender. - public byte? Gender { get; init; } + /// Leave as to not restrict gender. + public Gender Gender { get; init; } = Gender.Random; /// End result's ability numbers permitted. /// Leave as to not restrict ability. @@ -29,12 +29,12 @@ public sealed record EncounterCriteria : IFixedNature, IFixedAbilityNumber, IShi /// Leave as to not restrict shininess. public Shiny Shiny { get; init; } - public int IV_HP { get; init; } = RandomIV; - public int IV_ATK { get; init; } = RandomIV; - public int IV_DEF { get; init; } = RandomIV; - public int IV_SPA { get; init; } = RandomIV; - public int IV_SPD { get; init; } = RandomIV; - public int IV_SPE { get; init; } = RandomIV; + public sbyte IV_HP { get; init; } = RandomIV; + public sbyte IV_ATK { get; init; } = RandomIV; + public sbyte IV_DEF { get; init; } = RandomIV; + public sbyte IV_SPA { get; init; } = RandomIV; + public sbyte IV_SPD { get; init; } = RandomIV; + public sbyte IV_SPE { get; init; } = RandomIV; /// /// If the Encounter yields variable level ranges (e.g. RNG correlation), force the minimum level instead of yielding first match. @@ -44,7 +44,7 @@ public sealed record EncounterCriteria : IFixedNature, IFixedAbilityNumber, IShi public sbyte TeraType { get; init; } = -1; // unused - public int HPType { get; init; } = -1; + public sbyte HPType { get; init; } = -1; private const int RandomIV = -1; @@ -102,12 +102,12 @@ public static EncounterCriteria GetCriteria(IBattleTemplate s, IPersonalTable t) public static EncounterCriteria GetCriteria(IBattleTemplate s, IPersonalInfo pi) => new() { Gender = GetGenderPermissions(s.Gender, pi), - IV_HP = s.IVs[0], - IV_ATK = s.IVs[1], - IV_DEF = s.IVs[2], - IV_SPE = s.IVs[3], - IV_SPA = s.IVs[4], - IV_SPD = s.IVs[5], + IV_HP = (sbyte)s.IVs[0], + IV_ATK = (sbyte)s.IVs[1], + IV_DEF = (sbyte)s.IVs[2], + IV_SPE = (sbyte)s.IVs[3], + IV_SPA = (sbyte)s.IVs[4], + IV_SPD = (sbyte)s.IVs[5], HPType = s.HiddenPowerType, Ability = GetAbilityPermissions(s.Ability, pi), @@ -116,14 +116,14 @@ public static EncounterCriteria GetCriteria(IBattleTemplate s, IPersonalInfo pi) TeraType = (sbyte)s.TeraType, }; - private static byte? GetGenderPermissions(byte? gender, IGenderDetail pi) + private static Gender GetGenderPermissions(byte? gender, IGenderDetail pi) { if (gender is not <= 1) - return null; + return Gender.Random; if (pi.IsDualGender) - return gender; + return (Gender)gender; var g = pi.FixedGender(); - return g <= 1 ? g : null; + return g <= 1 ? (Gender)g : Gender.Random; } private static AbilityPermission GetAbilityPermissions(int ability, IPersonalAbility pi) @@ -169,12 +169,12 @@ public Nature GetNature() /// /// Indicates if the is specified. /// - public bool IsGenderSpecified => Gender != null; + public bool IsGenderSpecified => Gender != Gender.Random; /// /// Indicates if the requested gender matches the criteria. /// - public bool IsGenderSatisfied(byte gender) => !IsGenderSpecified || gender == Gender; + public bool IsGenderSatisfied(byte gender) => !IsGenderSpecified || (Gender)gender == Gender; /// /// Gets the gender to generate, random if unspecified by the template or criteria. @@ -189,7 +189,7 @@ public byte GetGender(byte gender, IGenderDetail pkPersonalInfo) /// public byte GetGender(Gender gender, IGenderDetail pkPersonalInfo) { - if (gender == Core.Gender.Random) + if (gender == Gender.Random) return GetGender(pkPersonalInfo); return (byte)gender; } @@ -203,8 +203,8 @@ public byte GetGender(IGenderDetail pkPersonalInfo) return pkPersonalInfo.FixedGender(); if (pkPersonalInfo.Genderless) return 2; - if (Gender is { } request and (0 or 1)) - return request; + if (Gender is not Gender.Random) + return (byte)Gender; return pkPersonalInfo.RandomGender(); } @@ -356,4 +356,10 @@ public bool IsCompatibleIVs(ReadOnlySpan ivs) return false; return true; } + + public void GetCombinedIVs(out uint iv1, out uint iv2) + { + iv1 = (byte)IV_HP | (uint)IV_ATK << 5 | (uint)IV_DEF << 10; + iv2 = (byte)IV_SPE | (uint)IV_SPA << 5 | (uint)IV_SPD << 10; + } } diff --git a/PKHeX.Core/Legality/RNG/CXD/MethodCXD.cs b/PKHeX.Core/Legality/RNG/CXD/MethodCXD.cs index 64ce9b899..868525f12 100644 --- a/PKHeX.Core/Legality/RNG/CXD/MethodCXD.cs +++ b/PKHeX.Core/Legality/RNG/CXD/MethodCXD.cs @@ -14,7 +14,7 @@ public static class MethodCXD public static bool SetFromIVs(this T enc, G3PKM pk, EncounterCriteria criteria, PersonalInfo3 pi, bool noShiny = false) where T : IShadow3 { var gr = pi.Gender; - (uint iv1, uint iv2) = GetCombinedIVs(criteria); + criteria.GetCombinedIVs(out var iv1, out var iv2); Span all = stackalloc uint[XDRNG.MaxCountSeedsIV]; var count = XDRNG.GetSeedsIVs(all, iv1 << 16, iv2 << 16); var seeds = all[..count]; @@ -52,7 +52,7 @@ public static class MethodCXD public static bool SetFromIVsCXD(G3PKM pk, EncounterCriteria criteria, PersonalInfo3 pi, bool noShiny = true) { var gr = pi.Gender; - (uint iv1, uint iv2) = GetCombinedIVs(criteria); + criteria.GetCombinedIVs(out var iv1, out var iv2); Span all = stackalloc uint[XDRNG.MaxCountSeedsIV]; var count = XDRNG.GetSeedsIVs(all, iv1 << 16, iv2 << 16); var seeds = all[..count]; @@ -174,13 +174,6 @@ private static uint GetPIDStarterMale(ref uint seed, uint id32) private static uint GetPIDRegular(uint a, uint b) => a << 16 | b; - private static (uint iv1, uint iv2) GetCombinedIVs(EncounterCriteria criteria) - { - uint iv1 = (uint)criteria.IV_HP | (uint)criteria.IV_ATK << 5 | (uint)criteria.IV_DEF << 10; - uint iv2 = (uint)criteria.IV_SPE | (uint)criteria.IV_SPA << 5 | (uint)criteria.IV_SPD << 10; - return (iv1, iv2); - } - private static void SetIVs(G3PKM pk, uint iv1, uint iv2) { Span ivs = stackalloc int[6]; diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/Gen3/GenerateMethodH.cs b/PKHeX.Core/Legality/RNG/ClassicEra/Gen3/GenerateMethodH.cs index 2693c518b..d77389523 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/Gen3/GenerateMethodH.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/Gen3/GenerateMethodH.cs @@ -95,7 +95,7 @@ public static bool SetFromIVs(this T enc, PK3 pk, EncounterCriteria criteria) where T : IEncounterSlot3 { var gr = pk.PersonalInfo.Gender; - (uint iv1, uint iv2) = GetCombinedIVs(criteria); + criteria.GetCombinedIVs(out var iv1, out var iv2); Span all = stackalloc uint[LCRNG.MaxCountSeedsIV]; var count = LCRNGReversal.GetSeedsIVs(all, iv1 << 16, iv2 << 16); var seeds = all[..count]; @@ -163,7 +163,7 @@ public static bool SetFromIVs(this T enc, PK3 pk, EncounterCriteria criteria) public static bool SetFromIVsUnown(this T enc, PK3 pk, EncounterCriteria criteria) where T : IEncounterSlot3 { - (uint iv1, uint iv2) = GetCombinedIVs(criteria); + criteria.GetCombinedIVs(out var iv1, out var iv2); Span all = stackalloc uint[LCRNG.MaxCountSeedsIV]; var count = LCRNGReversal.GetSeedsIVs(all, iv1 << 16, iv2 << 16); var seeds = all[..count]; @@ -235,11 +235,4 @@ private static void SetPIDIVSequential(PK3 pk, uint pid, uint rand) pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF); pk.RefreshAbility((int)(pid & 1)); } - - private static (uint iv1, uint iv2) GetCombinedIVs(EncounterCriteria criteria) - { - uint iv1 = (uint)criteria.IV_HP | (uint)criteria.IV_ATK << 5 | (uint)criteria.IV_DEF << 10; - uint iv2 = (uint)criteria.IV_SPE | (uint)criteria.IV_SPA << 5 | (uint)criteria.IV_SPD << 10; - return (iv1, iv2); - } } diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/Gen3/MethodH.cs b/PKHeX.Core/Legality/RNG/ClassicEra/Gen3/MethodH.cs index fb2e48ad6..eb54e5e4e 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/Gen3/MethodH.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/Gen3/MethodH.cs @@ -564,10 +564,11 @@ private static bool IsOriginalLevelValid(byte min, byte max, byte format, uint l return LevelRangeExtensions.IsLevelWithinRange((int)level, min, max); } - private static uint GetExpectedLevel(ILevelRange enc, uint u16LevelRand) + private static uint GetExpectedLevel(T enc, uint u16LevelRand) where T : ILevelRange { - uint mod = 1u + enc.LevelMax - enc.LevelMin; - return (u16LevelRand % mod) + enc.LevelMin; + var min = enc.LevelMin; + uint mod = 1u + enc.LevelMax - min; + return (u16LevelRand % mod) + min; } private static bool IsRockSmashPossible(byte areaRate, ref uint seed) diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/GenerateMethodJ.cs b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/GenerateMethodJ.cs index 2ac010489..0ab0c9923 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/GenerateMethodJ.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/GenerateMethodJ.cs @@ -89,7 +89,7 @@ public static bool SetFromIVsJ(this T enc, PK4 pk, PersonalInfo4 pi, Encounte where T : IEncounterSlot4 { var gr = pi.Gender; - (uint iv1, uint iv2) = GetCombinedIVs(criteria); + criteria.GetCombinedIVs(out var iv1, out var iv2); Span all = stackalloc uint[LCRNG.MaxCountSeedsIV]; var count = LCRNGReversal.GetSeedsIVs(all, iv1 << 16, iv2 << 16); var seeds = all[..count]; @@ -124,11 +124,4 @@ public static bool SetFromIVsJ(this T enc, PK4 pk, PersonalInfo4 pi, Encounte } public static uint GetPIDRegular(uint a, uint b) => b << 16 | a; - - private static (uint iv1, uint iv2) GetCombinedIVs(EncounterCriteria criteria) - { - uint iv1 = (uint)criteria.IV_HP | (uint)criteria.IV_ATK << 5 | (uint)criteria.IV_DEF << 10; - uint iv2 = (uint)criteria.IV_SPE | (uint)criteria.IV_SPA << 5 | (uint)criteria.IV_SPD << 10; - return (iv1, iv2); - } } diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/GenerateMethodK.cs b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/GenerateMethodK.cs index 4c87a8c4c..b25846318 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/GenerateMethodK.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/GenerateMethodK.cs @@ -88,7 +88,7 @@ public static bool SetFromIVsK(this T enc, PK4 pk, PersonalInfo4 pi, Encounte where T : IEncounterSlot4 { var gr = pi.Gender; - (uint iv1, uint iv2) = GetCombinedIVs(criteria); + criteria.GetCombinedIVs(out var iv1, out var iv2); Span all = stackalloc uint[LCRNG.MaxCountSeedsIV]; var count = LCRNGReversal.GetSeedsIVs(all, iv1 << 16, iv2 << 16); var seeds = all[..count]; @@ -123,11 +123,4 @@ public static bool SetFromIVsK(this T enc, PK4 pk, PersonalInfo4 pi, Encounte } public static uint GetPIDRegular(uint a, uint b) => b << 16 | a; - - private static (uint iv1, uint iv2) GetCombinedIVs(EncounterCriteria criteria) - { - uint iv1 = (uint)criteria.IV_HP | (uint)criteria.IV_ATK << 5 | (uint)criteria.IV_DEF << 10; - uint iv2 = (uint)criteria.IV_SPE | (uint)criteria.IV_SPA << 5 | (uint)criteria.IV_SPD << 10; - return (iv1, iv2); - } } diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodJ.cs b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodJ.cs index 2644e30f2..a66384bb4 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodJ.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodJ.cs @@ -456,10 +456,11 @@ private static bool IsOriginalLevelValid(byte min, byte max, byte format, uint l return LevelRangeExtensions.IsLevelWithinRange((int)level, min, max); } - private static uint GetExpectedLevel(ILevelRange enc, uint u16LevelRand) + private static uint GetExpectedLevel(T enc, uint u16LevelRand) where T : ILevelRange { - uint mod = 1u + enc.LevelMax - enc.LevelMin; - return (u16LevelRand % mod) + enc.LevelMin; + var min = enc.LevelMin; + uint mod = 1u + enc.LevelMax - min; + return (u16LevelRand % mod) + min; } /// diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodK.cs b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodK.cs index a85c7a2c4..8367e21f1 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodK.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodK.cs @@ -482,10 +482,11 @@ private static bool IsOriginalLevelValid(byte min, byte max, byte format, uint l return LevelRangeExtensions.IsLevelWithinRange((int)level, min, max); } - private static uint GetExpectedLevel(ILevelRange enc, uint u16LevelRand) + private static uint GetExpectedLevel(T enc, uint u16LevelRand) where T : ILevelRange { - uint mod = 1u + enc.LevelMax - enc.LevelMin; - return (u16LevelRand % mod) + enc.LevelMin; + var min = enc.LevelMin; + uint mod = 1u + enc.LevelMax - min; + return (u16LevelRand % mod) + min; } private static bool IsBugContestPossibleDeadlock(uint areaRate, ref uint result) diff --git a/PKHeX.WinForms/Subforms/SAV_Encounters.cs b/PKHeX.WinForms/Subforms/SAV_Encounters.cs index ef365a362..01f40a093 100644 --- a/PKHeX.WinForms/Subforms/SAV_Encounters.cs +++ b/PKHeX.WinForms/Subforms/SAV_Encounters.cs @@ -187,7 +187,7 @@ private EncounterCriteria GetCriteria(ISpeciesForm enc, EncounterDatabaseSetting var set = new ShowdownSet(editor); var criteria = EncounterCriteria.GetCriteria(set, editor.PersonalInfo); if (!isInChain) - criteria = criteria with { Gender = default }; // Genderless tabs and a gendered enc -> let's play safe. + criteria = criteria with { Gender = Gender.Random }; // Genderless tabs and a gendered enc -> let's play safe. return criteria; }