From 0e0d812d83d3c7e008ecff248120d97df5e081d3 Mon Sep 17 00:00:00 2001 From: Kurt Date: Sat, 3 May 2025 23:55:06 -0500 Subject: [PATCH] Add more xmldoc --- .../Templates/Gen4/EncounterArea4.cs | 12 +--- .../Templates/Gen4/EncounterSlot4.cs | 2 +- PKHeX.Core/Legality/MoveSourceType.cs | 4 ++ .../RNG/ClassicEra/Gen4/RuinsOfAlph4.cs | 8 +++ .../RNG/ClassicEra/Gen4/SolaceonRuins4.cs | 8 +++ PKHeX.Core/PKM/PKM.cs | 14 ++--- PKHeX.Core/PKM/Strings/IStringConverter.cs | 28 +++++++++ PKHeX.Core/PKM/Strings/StringConverter2.cs | 4 ++ PKHeX.Core/PKM/Strings/StringConverter8.cs | 2 +- .../PKM/Strings/Trash/ITrashIntrospection.cs | 25 ++++++++ PKHeX.Core/PKM/Util/EntityCharacteristic.cs | 61 +++++++++++-------- PKHeX.Core/PKM/Util/EntityDetection.cs | 45 +++++++++----- PKHeX.Core/PKM/Util/EntityFormat.cs | 6 ++ PKHeX.Core/PKM/Util/EntityGender.cs | 7 +++ .../PersonalInfo/Interfaces/IPersonalTable.cs | 14 +++++ .../Encryption/SwishCrypto/SCTypeCode.cs | 34 +++++++++++ 16 files changed, 218 insertions(+), 56 deletions(-) diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterArea4.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterArea4.cs index 3fe1ee095..fda55b063 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterArea4.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterArea4.cs @@ -128,15 +128,9 @@ private static bool IsMunchlaxTree(ReadOnlySpan trees, ushort location) 58, // 20 Floaroma Meadow ]; - /// - /// Checks if the Unown form is valid for the given . - /// - public static bool IsUnownFormValid(PKM pk, byte form) - { - return pk.HGSS - ? RuinsOfAlph4.IsFormValid(pk, form) - : SolaceonRuins4.IsFormValid(pk, form); - } + public static bool IsUnownFormValid(PKM pk, byte form, bool isRuinsOfAlph) => isRuinsOfAlph + ? RuinsOfAlph4.IsFormValid(pk, form) + : SolaceonRuins4.IsFormValid(pk, form); } /// diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterSlot4.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterSlot4.cs index 8ed0c322d..6ab898637 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterSlot4.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterSlot4.cs @@ -165,7 +165,7 @@ public EncounterMatchRating GetMatchRating(PKM pk) } if (IsDeferredWurmple(pk)) return EncounterMatchRating.PartialMatch; - if (pk.Species == (int)Core.Species.Unown && !EncounterArea4.IsUnownFormValid(pk, pk.Form)) + if (Species == (int)Core.Species.Unown && !EncounterArea4.IsUnownFormValid(pk, pk.Form, Location is RuinsOfAlph4.Location)) return EncounterMatchRating.PartialMatch; return EncounterMatchRating.Match; } diff --git a/PKHeX.Core/Legality/MoveSourceType.cs b/PKHeX.Core/Legality/MoveSourceType.cs index 73bdc262b..84cc07c46 100644 --- a/PKHeX.Core/Legality/MoveSourceType.cs +++ b/PKHeX.Core/Legality/MoveSourceType.cs @@ -5,6 +5,10 @@ namespace PKHeX.Core; /// /// Indicates the source of a for a . /// +/// +/// This enum is mostly a "lumping" enum to pivot searching logic. +/// See for the more-specific tracking enumeration. +/// [Flags] public enum MoveSourceType { diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/RuinsOfAlph4.cs b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/RuinsOfAlph4.cs index 904eb45fe..e78839fff 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/RuinsOfAlph4.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/RuinsOfAlph4.cs @@ -2,8 +2,16 @@ namespace PKHeX.Core; +/// +/// Logic for Ruins of Alph Unown forms. +/// public static class RuinsOfAlph4 { + /// + /// Met location for the Ruins of Alph. + /// + public const ushort Location = 209; + /// /// Checks if the requested is valid for the given seed. /// diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/SolaceonRuins4.cs b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/SolaceonRuins4.cs index 61c7337b7..99ba0993e 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/SolaceonRuins4.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/SolaceonRuins4.cs @@ -2,8 +2,16 @@ namespace PKHeX.Core; +/// +/// Logic for Solaceon Ruins Unown forms. +/// public static class SolaceonRuins4 { + /// + /// Met location for the Solaceon Ruins. + /// + public const ushort Location = 53; + /// /// Checks if the requested is valid for the given seed. /// diff --git a/PKHeX.Core/PKM/PKM.cs b/PKHeX.Core/PKM/PKM.cs index be2e82490..b943c678e 100644 --- a/PKHeX.Core/PKM/PKM.cs +++ b/PKHeX.Core/PKM/PKM.cs @@ -296,12 +296,12 @@ public ushort ShinyXor public bool VC => VC1 || VC2; public bool GG => LGPE || GO_LGPE; public bool Gen9 => SV; - public bool Gen8 => Version is >= SW and <= SP || GO_HOME; - public bool Gen7 => Version is >= SN and <= UM || GG; - public bool Gen6 => Version is >= X and <= OR; - public bool Gen5 => Version is >= W and <= B2; - public bool Gen4 => Version is HG or SS or D or P or GameVersion.Pt; - public bool Gen3 => Version is (>= S and <= LG) or CXD; + public bool Gen8 => Version.IsGen8() || GO_HOME; + public bool Gen7 => Version.IsGen7(); + public bool Gen6 => Version.IsGen6(); + public bool Gen5 => Version.IsGen5(); + public bool Gen4 => Version.IsGen4(); + public bool Gen3 => Version.IsGen3(); public bool Gen2 => Version == GSC; // Fixed value set by the Gen2 PKM classes public bool Gen1 => Version == RBY; // Fixed value set by the Gen1 PKM classes public bool GenU => Generation <= 0; @@ -312,7 +312,7 @@ public byte Generation { if (Gen9) return 9; if (Gen8) return 8; - if (Gen7) return 7; + if (Gen7 || GG) return 7; if (Gen6) return 6; if (Gen5) return 5; if (Gen4) return 4; diff --git a/PKHeX.Core/PKM/Strings/IStringConverter.cs b/PKHeX.Core/PKM/Strings/IStringConverter.cs index f0affee29..384c3a5de 100644 --- a/PKHeX.Core/PKM/Strings/IStringConverter.cs +++ b/PKHeX.Core/PKM/Strings/IStringConverter.cs @@ -2,9 +2,37 @@ namespace PKHeX.Core; +/// +/// Interface for converting between byte arrays and strings. +/// +/// +/// Different implementations are used for different string encodings. +/// These vary across . +/// public interface IStringConverter { + /// + /// Reads a string from a byte array. + /// + /// Source data to decode. string GetString(ReadOnlySpan data); + + /// + /// Loads a string character by character into the array until a terminator is found or the end of the buffer is reached. + /// + /// Source data to decode. + /// Resulting string buffer. + /// Count of characters written to . int LoadString(ReadOnlySpan data, Span text); + + /// + /// Converts a string to a byte array. + /// + /// Destination data to store the encoded string. + /// Source string to encode. + /// Maximum length of the to encode. + /// Buffer conditioning option. + /// Count of bytes written to . + int SetString(Span data, ReadOnlySpan text, int length, StringConverterOption option); } diff --git a/PKHeX.Core/PKM/Strings/StringConverter2.cs b/PKHeX.Core/PKM/Strings/StringConverter2.cs index e8cdf0aa9..e2ae0f0c3 100644 --- a/PKHeX.Core/PKM/Strings/StringConverter2.cs +++ b/PKHeX.Core/PKM/Strings/StringConverter2.cs @@ -2,6 +2,10 @@ namespace PKHeX.Core; +/// +/// Logic for converting a for Generation 2. +/// +/// Slight differences when compared to . public static class StringConverter2 { public const byte TerminatorCode = StringConverter1.TerminatorCode; diff --git a/PKHeX.Core/PKM/Strings/StringConverter8.cs b/PKHeX.Core/PKM/Strings/StringConverter8.cs index dec1c3d86..475d42cdf 100644 --- a/PKHeX.Core/PKM/Strings/StringConverter8.cs +++ b/PKHeX.Core/PKM/Strings/StringConverter8.cs @@ -169,7 +169,7 @@ public static void TransferGlyphs78(Span str) private static void TrimHalfSpaces(Span u16) { - // If a replacement is made, any leading or trailing halfwidth spaces are trimmed. + // If a replacement is made, any leading or trailing half-width spaces are trimmed. // This allows nicknames/OT names that are the empty string or consist entirely of fullwidth spaces. int length = u16.IndexOf((char)TerminatorNull); if (length == -1) diff --git a/PKHeX.Core/PKM/Strings/Trash/ITrashIntrospection.cs b/PKHeX.Core/PKM/Strings/Trash/ITrashIntrospection.cs index 31185ef9a..4ec8caf16 100644 --- a/PKHeX.Core/PKM/Strings/Trash/ITrashIntrospection.cs +++ b/PKHeX.Core/PKM/Strings/Trash/ITrashIntrospection.cs @@ -2,9 +2,34 @@ namespace PKHeX.Core; +/// +/// Interface for introspection of trash data. +/// +/// +/// Implementation abstractions for accessing results from +/// , +/// , +/// +/// depending on the type's string encoding. +/// public interface ITrashIntrospection { + /// + /// Gets the index of the string terminator in the given data. + /// + /// The data to search. + /// Character index of the string terminator. int GetStringTerminatorIndex(ReadOnlySpan data); + + /// + /// Gets the length of the string based on the terminator or end of the data. + /// + /// Span of data to check the length of. + /// Count of characters in the string. int GetStringLength(ReadOnlySpan data); + + /// + /// Gets the amount of bytes per character in the string encoding. + /// int GetBytesPerChar(); } diff --git a/PKHeX.Core/PKM/Util/EntityCharacteristic.cs b/PKHeX.Core/PKM/Util/EntityCharacteristic.cs index 4a84df60b..45ee88ab7 100644 --- a/PKHeX.Core/PKM/Util/EntityCharacteristic.cs +++ b/PKHeX.Core/PKM/Util/EntityCharacteristic.cs @@ -24,7 +24,38 @@ public static class EntityCharacteristic public static int GetCharacteristic(uint ec, uint iv32) { int index = (int)(ec % 6); + var (maxStatIndex, maxStatValue) = GetMaxStat(iv32, index); + return GetCharacteristic(maxStatIndex, maxStatValue); + } + /// + /// Gets the characteristic index of the given unpacked IVs. + /// + /// Encryption Constant. + /// Unpacked IVs. + /// Characteristic index. + public static int GetCharacteristic(uint ec, Span ivs) + { + int index = (int)(ec % 6); + var (maxStatIndex, maxStatValue) = GetMaxStat(ivs, index); + return GetCharacteristic(maxStatIndex, maxStatValue); + } + + /// + /// Gets the characteristic index of the given IVs when the IVs are stored in reverse order (HP highest bits). + /// + /// Encryption Constant. + /// Lumped IVs with HP occupying the highest bits. + /// Characteristic index. + public static int GetCharacteristicInvertFields(uint ec, uint iv32) + { + int index = (int)(ec % 6); + var (maxStatIndex, maxStatValue) = GetMaxStat32Invert(iv32, index); + return GetCharacteristic(maxStatIndex, maxStatValue); + } + + private static (int MaxStatIndex, int MaxStatValue) GetMaxStat(uint iv32, int index) + { // Get individual IVs from the lumped value. // The IVs are stored in the following order: HP, Atk, Def, Spe, SpA, SpD // Check all IVs, get the highest IV and its index. If there are multiple highest IVs, the first index checked is chosen. @@ -44,19 +75,11 @@ public static int GetCharacteristic(uint ec, uint iv32) index = 0; } while (maxStatIndex != index); - return GetCharacteristic(maxStatIndex, (int)maxStatValue); + return (maxStatIndex, (int)maxStatValue); } - /// - /// Gets the characteristic index of the given unpacked IVs. - /// - /// Encryption Constant. - /// Unpacked IVs. - /// Characteristic index. - public static int GetCharacteristic(uint ec, Span ivs) + private static (int MaxStatIndex, int MaxStatValue) GetMaxStat(Span ivs, int index) { - int index = (int)(ec % 6); - // Get individual IVs from the lumped value. // The IVs are stored in the following order: HP, Atk, Def, Spe, SpA, SpD // Check all IVs, get the highest IV and its index. If there are multiple highest IVs, the first index checked is chosen. @@ -76,22 +99,12 @@ public static int GetCharacteristic(uint ec, Span ivs) index = 0; } while (maxStatIndex != index); - return GetCharacteristic(maxStatIndex, maxStatValue); + return (maxStatIndex, maxStatValue); } - /// - /// Gets the characteristic index of the given IVs in Big Endian format. - /// - /// Encryption Constant. - /// Lumped IVs in Big Endian format. - /// Characteristic index. - public static int GetCharacteristicInvertFields(uint ec, uint iv32) + private static (int MaxStatIndex, int MaxStatValue) GetMaxStat32Invert(uint iv32, int index) { - int index = (int)(ec % 6); - - // Get individual IVs from the lumped value. - // The IVs are stored in the following order: SpD, SpA, Spe, Def, Atk, HP - // Check all IVs, get the highest IV and its index. If there are multiple highest IVs, the first index checked is chosen. + // Same as GetMaxStat, but for formats where the IVs are stored in reverse order. int maxStatIndex = index; var maxStatValue = 0u; do @@ -109,6 +122,6 @@ public static int GetCharacteristicInvertFields(uint ec, uint iv32) index = 0; } while (maxStatIndex != index); - return GetCharacteristic(maxStatIndex, (int)maxStatValue); + return (maxStatIndex, (int)maxStatValue); } } diff --git a/PKHeX.Core/PKM/Util/EntityDetection.cs b/PKHeX.Core/PKM/Util/EntityDetection.cs index 51fc060e5..dfd4ca686 100644 --- a/PKHeX.Core/PKM/Util/EntityDetection.cs +++ b/PKHeX.Core/PKM/Util/EntityDetection.cs @@ -26,10 +26,28 @@ SIZE_5PARTY or SIZE_8ASTORED or SIZE_8APARTY ; - public static bool IsPresentGB(ReadOnlySpan data) => data[0] != 0; // Species non-zero - public static bool IsPresentGC(ReadOnlySpan data) => ReadUInt16BigEndian(data) != 0; // Species non-zero + /// + /// Checks the first byte of the span to see if the species is non-zero. + /// + public static bool IsPresentGB(ReadOnlySpan data) => data[0] != 0; + + /// + /// Checks the first two bytes of the span to see if the species is non-zero. + /// + public static bool IsPresentGC(ReadOnlySpan data) => ReadUInt16BigEndian(data) != 0; + + /// + /// Checks the flag status of the span to see if it has the indicator. + /// public static bool IsPresentGBA(ReadOnlySpan data) => (data[0x13] & 0xFB) == 2; // ignore egg flag, must be FlagHasSpecies. - public static bool IsPresentSAV4Ranch(ReadOnlySpan data) => ReadUInt32LittleEndian(data) != 0 && ReadUInt32BigEndian(data) != 0x28; // Species non-zero, ignore file end marker + + /// + /// Checks if the species is non-zero and the entity PID is not the "file end" marker of the save file. + /// + /// + /// Only useful when called from a file, not for a entity dump. + /// + public static bool IsPresentSAV4Ranch(ReadOnlySpan data) => IsPresent(data) && ReadUInt32BigEndian(data) != 0x28; // Species non-zero, ignore file end marker public static bool IsPresent(ReadOnlySpan data) { @@ -40,18 +58,17 @@ public static bool IsPresent(ReadOnlySpan data) } /// - /// Gets a function that can check a byte array (at an offset) to see if a is possibly present. + /// Gets a function that can check a span to see if a is possibly present. /// /// - /// Function that checks if a byte array (at an offset) has a present - public static Func GetFuncIsPresent(PKM blank) + /// Function that checks if a span has a present + public static Func, bool> GetFuncIsPresent(PKM blank) => blank switch { - if (blank.Format >= 4) - return x => IsPresent(x); - if (blank.Format <= 2) - return x => IsPresentGB(x); - if (blank.Data.Length <= SIZE_3PARTY) - return x => IsPresentGBA(x); - return x => IsPresentGC(x); - } + { Format: >= 4 } => IsPresent, + { Format: <= 2 } => IsPresentGB, + + // Gen3; ^above handles all other formats. + PK3 => IsPresentGBA, + _ => IsPresentGC, + }; } diff --git a/PKHeX.Core/PKM/Util/EntityFormat.cs b/PKHeX.Core/PKM/Util/EntityFormat.cs index 4e42c0b78..7fa6afe84 100644 --- a/PKHeX.Core/PKM/Util/EntityFormat.cs +++ b/PKHeX.Core/PKM/Util/EntityFormat.cs @@ -211,6 +211,12 @@ private static EntityFormatDetected IsFormatReally8b(PK8 pk) } } +/// +/// Enum representing the detected format of a Pokémon entity. +/// +/// +/// Roughly correlated to derived types, besides the "one-of" range of enum values. +/// public enum EntityFormatDetected { None, diff --git a/PKHeX.Core/PKM/Util/EntityGender.cs b/PKHeX.Core/PKM/Util/EntityGender.cs index 86ee94f48..f5b408445 100644 --- a/PKHeX.Core/PKM/Util/EntityGender.cs +++ b/PKHeX.Core/PKM/Util/EntityGender.cs @@ -46,6 +46,13 @@ public static byte GetFromPID(ushort species, uint pid) return GetFromPIDAndRatio(pid, gt); } + /// + /// Gets the gender from the and values. + /// + /// Personality ID. + /// Gender Ratio. + /// Gender ID (0/1/2) + /// This method should only be used for Generations 3-5 origin. public static byte GetFromPIDAndRatio(uint pid, byte gr) => gr switch { PersonalInfo.RatioMagicGenderless => Genderless, diff --git a/PKHeX.Core/PersonalInfo/Interfaces/IPersonalTable.cs b/PKHeX.Core/PersonalInfo/Interfaces/IPersonalTable.cs index 4048e9ddb..bcc16bdd2 100644 --- a/PKHeX.Core/PersonalInfo/Interfaces/IPersonalTable.cs +++ b/PKHeX.Core/PersonalInfo/Interfaces/IPersonalTable.cs @@ -61,7 +61,21 @@ public interface IPersonalTable /// Specific type of the table contains. public interface IPersonalTable where T : IPersonalInfo { + /// + /// Gets the entry from the table based on absolute index, not species/form. + /// + /// + /// Only use this if not requesting based on Form. + /// T this[int index] { get; } + + /// + /// Gets the entry from the table based on species/form. + /// T this[ushort species, byte form] { get; } + + /// + /// Gets the entry from the table based on species/form. + /// T GetFormEntry(ushort species, byte form); } diff --git a/PKHeX.Core/Saves/Encryption/SwishCrypto/SCTypeCode.cs b/PKHeX.Core/Saves/Encryption/SwishCrypto/SCTypeCode.cs index 554baff57..fdc6bcd99 100644 --- a/PKHeX.Core/Saves/Encryption/SwishCrypto/SCTypeCode.cs +++ b/PKHeX.Core/Saves/Encryption/SwishCrypto/SCTypeCode.cs @@ -34,6 +34,11 @@ public static class SCTypeCodeExtensions { public static bool IsBoolean(this SCTypeCode type) => unchecked((uint)type - 1u) < 3; + /// + /// Gets the number of bytes occupied by a variable of a given type. + /// + /// Type of the value + /// public static int GetTypeSize(this SCTypeCode type) => type switch { SCTypeCode.Bool3 => sizeof(bool), @@ -54,6 +59,12 @@ public static class SCTypeCodeExtensions _ => throw new ArgumentOutOfRangeException(nameof(type), type.ToString()), }; + /// + /// Gets the runtime of the value. + /// + /// Type of the value + /// If , use . + /// public static Type GetType(this SCTypeCode type) => type switch { SCTypeCode.Byte => typeof(byte), @@ -72,6 +83,29 @@ public static class SCTypeCodeExtensions _ => throw new ArgumentOutOfRangeException(nameof(type), type.ToString()), }; + /// + /// Gets the runtime of the array. + /// + /// Type of the array + /// + public static Type GetTypeArray(this SCTypeCode type) => type switch + { + SCTypeCode.Byte => typeof(byte[]), + SCTypeCode.UInt16 => typeof(ushort[]), + SCTypeCode.UInt32 => typeof(uint[]), + SCTypeCode.UInt64 => typeof(ulong[]), + + SCTypeCode.SByte => typeof(sbyte[]), + SCTypeCode.Int16 => typeof(short[]), + SCTypeCode.Int32 => typeof(int[]), + SCTypeCode.Int64 => typeof(long[]), + + SCTypeCode.Single => typeof(float[]), + SCTypeCode.Double => typeof(double[]), + + _ => throw new ArgumentOutOfRangeException(nameof(type), type.ToString()), + }; + public static object GetValue(this SCTypeCode type, ReadOnlySpan data) { // don't use a switch expression here, we want to box our underlying type rather than the last type (double)