From ba2245d7d89d852a56eb8d9938d80edcee98dd86 Mon Sep 17 00:00:00 2001 From: Kurt Date: Sat, 7 Jun 2025 09:41:02 -0500 Subject: [PATCH] Add more xmldoc Updated PIDIV tests to use IV32 rather than IV sequence checks. Now marked as Obsolete to prevent myself from reusing PKM.IVs getter :) --- PKHeX.Core/Game/Enums/Nature.cs | 3 ++ PKHeX.Core/Legality/Verifiers/MiscVerifier.cs | 11 ++++---- PKHeX.Core/PKM/PKM.cs | 1 + PKHeX.Core/Saves/Substructures/Gen9/DXT1.cs | 28 +++++++++++++++++++ .../Gen9/PlayerFashionUnlock9.cs | 11 ++++++++ PKHeX.Core/Saves/Util/BinaryExportSetting.cs | 23 +++++++++++++++ PKHeX.Core/Saves/Util/IGCSaveFile.cs | 11 +++++--- PKHeX.Core/Saves/Util/ILangDeviantSave.cs | 6 +++- .../Recognition/SaveHandlerSplitResult.cs | 9 ++++++ PKHeX.Core/Saves/Util/SaveExtensions.cs | 2 +- Tests/PKHeX.Core.Tests/PKM/PIDIVTests.cs | 9 +++--- 11 files changed, 98 insertions(+), 16 deletions(-) diff --git a/PKHeX.Core/Game/Enums/Nature.cs b/PKHeX.Core/Game/Enums/Nature.cs index ab1d5e898..2f2d59446 100644 --- a/PKHeX.Core/Game/Enums/Nature.cs +++ b/PKHeX.Core/Game/Enums/Nature.cs @@ -58,6 +58,9 @@ public static class NatureUtil /// /// Checks if the provided is a possible mint nature. /// + /// + /// The only valid mint natures are those which have a stat amp applied, or neutral nature being Serious. + /// public static bool IsMint(this Nature value) => (value.IsFixed() && (byte)value % 6 != 0) || value == Nature.Serious; /// diff --git a/PKHeX.Core/Legality/Verifiers/MiscVerifier.cs b/PKHeX.Core/Legality/Verifiers/MiscVerifier.cs index 826ca2719..0f21f1bf3 100644 --- a/PKHeX.Core/Legality/Verifiers/MiscVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/MiscVerifier.cs @@ -841,13 +841,14 @@ private static bool CheckHeightWeightOdds(IEncounterTemplate enc) return true; } - private void VerifyStatNature(LegalityAnalysis data, PKM pk) + private void VerifyStatNature(LegalityAnalysis data, T pk) where T : PKM { - var sn = (byte)pk.StatNature; - if (sn == (byte)pk.Nature) + // No encounters innately come with a different Stat Nature... + // If it matches the Nature, it is valid. If it doesn't, it should be one of the mint natures. + var statNature = pk.StatNature; + if (statNature == pk.Nature) return; - // Only allow Serious nature (12); disallow all other neutral natures. - if (sn != 12 && (sn > 24 || sn % 6 == 0)) + if (!statNature.IsMint()) data.AddLine(GetInvalid(LStatNatureInvalid)); } diff --git a/PKHeX.Core/PKM/PKM.cs b/PKHeX.Core/PKM/PKM.cs index 2b796314b..118f3ecff 100644 --- a/PKHeX.Core/PKM/PKM.cs +++ b/PKHeX.Core/PKM/PKM.cs @@ -364,6 +364,7 @@ public int FlawlessIVCount public int[] IVs { + [Obsolete($"Use the {nameof(GetIVs)} method with stackalloc to not allocate.")] get => [IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD]; set => SetIVs(value); } diff --git a/PKHeX.Core/Saves/Substructures/Gen9/DXT1.cs b/PKHeX.Core/Saves/Substructures/Gen9/DXT1.cs index 3b99739fb..2248e68f0 100644 --- a/PKHeX.Core/Saves/Substructures/Gen9/DXT1.cs +++ b/PKHeX.Core/Saves/Substructures/Gen9/DXT1.cs @@ -3,11 +3,26 @@ namespace PKHeX.Core; +/// +/// Provides methods for working with DXT1 compressed texture data, including decompression and size calculations. +/// +/// +/// DXT1 is a lossy compression format commonly used for texture data in graphics applications. +/// This class includes methods to calculate the decompressed size of a texture and to decompress DXT1-compressed data into raw RGBA pixel data. +/// public static class DXT1 { private const int bpp = 4; + + /// + /// Calculates the total decompressed size of an image based on its dimensions. + /// + /// The width of the image, in pixels. Must be a positive integer. + /// The height of the image, in pixels. Must be a positive integer. + /// The total decompressed size of the image, in bytes. public static int GetDecompressedSize(int width, int height) => bpp * width * height; + /// public static byte[] Decompress(ReadOnlySpan data, int width, int height) { var result = new byte[GetDecompressedSize(width, height)]; @@ -15,6 +30,19 @@ public static byte[] Decompress(ReadOnlySpan data, int width, int height) return result; } + /// + /// Decompresses a block-compressed texture into raw pixel data. + /// + /// The decompressed pixel data is written in RGBA format, with each pixel represented by 4 bytes + /// (red, green, blue, and alpha channels). The input data is expected to be in a block-compressed format, where + /// each 4x4 pixel block is encoded in 8 bytes. + /// The input span containing the compressed texture data. The data must be in a block-compressed format. + /// The width of the texture in pixels. Must be a multiple of 4. + /// The height of the texture in pixels. Must be a multiple of 4. + /// + /// The output span where the decompressed pixel data will be written. + /// The span must have sufficient capacity to hold × × 4 bytes. + /// public static void Decompress(ReadOnlySpan data, int width, int height, Span result) { int blockCountX = width / bpp; diff --git a/PKHeX.Core/Saves/Substructures/Gen9/PlayerFashionUnlock9.cs b/PKHeX.Core/Saves/Substructures/Gen9/PlayerFashionUnlock9.cs index 27d59a193..68f6983c3 100644 --- a/PKHeX.Core/Saves/Substructures/Gen9/PlayerFashionUnlock9.cs +++ b/PKHeX.Core/Saves/Substructures/Gen9/PlayerFashionUnlock9.cs @@ -5,6 +5,9 @@ namespace PKHeX.Core; +/// +/// Collection of unlock-able fashion items for the player in Generation 9 games. +/// public static class PlayerFashionUnlock9 { private static ReadOnlySpan Eyewear => @@ -127,6 +130,10 @@ public static class PlayerFashionUnlock9 8076, 8077, ]; + /// + /// Adds the specified fashion items to the block data. + /// + /// The number of items added that were not already present. public static int Add(SCBlockAccessor acc, uint key, ReadOnlySpan add) { var block = acc.GetBlock(key); @@ -136,6 +143,7 @@ public static int Add(SCBlockAccessor acc, uint key, ReadOnlySpan add) private const int SIZE = 8; + /// public static int Add(Span data, ReadOnlySpan add) { var missing = new HashSet(add.Length); @@ -173,6 +181,9 @@ private static int AddItems(Span data, IEnumerable missing) return added; } + /// + /// Unlocks the fashion items for the player based on the requested gender. + /// public static int UnlockBase(SCBlockAccessor acc, byte gender) { int count = 0; diff --git a/PKHeX.Core/Saves/Util/BinaryExportSetting.cs b/PKHeX.Core/Saves/Util/BinaryExportSetting.cs index 8debef8b3..e5669644b 100644 --- a/PKHeX.Core/Saves/Util/BinaryExportSetting.cs +++ b/PKHeX.Core/Saves/Util/BinaryExportSetting.cs @@ -2,11 +2,34 @@ namespace PKHeX.Core; +/// +/// Flags to control the export of binary data. +/// [Flags] public enum BinaryExportSetting { + /// + /// Export the complete binary file with all sections included. + /// None, + + /// + /// Exclude the footer section from the exported file. + /// ExcludeFooter = 1 << 0, + + /// + /// Exclude the header section from the exported file. + /// ExcludeHeader = 1 << 1, + + /// + /// Do not perform finalization steps when exporting. + /// + /// + /// When this flag is set, the export skips any finalization logic such as updating the header or footer segments. + /// The exact steps skipped depend on the file type and export implementation. + /// See implementations for details. + /// ExcludeFinalize = 1 << 2, } diff --git a/PKHeX.Core/Saves/Util/IGCSaveFile.cs b/PKHeX.Core/Saves/Util/IGCSaveFile.cs index 4794dc43f..73eec3714 100644 --- a/PKHeX.Core/Saves/Util/IGCSaveFile.cs +++ b/PKHeX.Core/Saves/Util/IGCSaveFile.cs @@ -1,4 +1,4 @@ -namespace PKHeX.Core; +namespace PKHeX.Core; /// /// GameCube save file interface for memory cards. @@ -13,18 +13,21 @@ public interface IGCSaveFile public static class GCSaveExtensions { + private const string gci = ".gci"; + private const string raw = ".raw"; + /// /// Gets an export filter for a GameCube file. /// public static string GCFilter(this IGCSaveFile gc) { - const string regular = "GameCube Save File|*.gci|All Files|*.*"; - const string memcard = "Memory Card Raw File|*.raw|Memory Card Binary File|*.bin|"; + const string regular = $"GameCube Save File|*{gci}|All Files|*.*"; + const string memcard = $"Memory Card Raw File|*{raw}|Memory Card Binary File|*.bin|"; return gc.MemoryCard is not null ? memcard + regular : regular; } /// /// Gets the export extension for a GameCube file. /// - public static string GCExtension(this IGCSaveFile gc) => gc.MemoryCard is not null ? ".raw" : ".gci"; + public static string GCExtension(this IGCSaveFile gc) => gc.MemoryCard is not null ? raw : gci; } diff --git a/PKHeX.Core/Saves/Util/ILangDeviantSave.cs b/PKHeX.Core/Saves/Util/ILangDeviantSave.cs index a4e3bb7e1..4ddeff323 100644 --- a/PKHeX.Core/Saves/Util/ILangDeviantSave.cs +++ b/PKHeX.Core/Saves/Util/ILangDeviantSave.cs @@ -1,8 +1,12 @@ -namespace PKHeX.Core; +namespace PKHeX.Core; /// /// behaves differently for different languages (different structure layout). /// +/// +/// Save files that behave differently based on language are best to have an entirely separate class implementation, +/// but lack of complete information necessitates sharing implementations. +/// public interface ILangDeviantSave : ISaveFileRevision { bool Japanese { get; } diff --git a/PKHeX.Core/Saves/Util/Recognition/SaveHandlerSplitResult.cs b/PKHeX.Core/Saves/Util/Recognition/SaveHandlerSplitResult.cs index 2eaee1a29..21cd5d023 100644 --- a/PKHeX.Core/Saves/Util/Recognition/SaveHandlerSplitResult.cs +++ b/PKHeX.Core/Saves/Util/Recognition/SaveHandlerSplitResult.cs @@ -1,5 +1,14 @@ namespace PKHeX.Core; +/// +/// Represents the result of a save operation split into distinct components. +/// +/// This type encapsulates the data, header, and footer segments of a save operation, along with the +/// associated save handler responsible for processing the operation. +/// The main data segment of the save operation, typically containing the core save data. +/// The header segment of the save operation, which may contain metadata or other relevant information. +/// The footer segment of the save operation, which may contain additional metadata or checksums. +/// The save handler responsible for processing the save operation, providing methods for recognition and finalization. public sealed class SaveHandlerSplitResult(byte[] Data, byte[] Header, byte[] Footer, ISaveHandler Handler) { public readonly byte[] Header = Header; diff --git a/PKHeX.Core/Saves/Util/SaveExtensions.cs b/PKHeX.Core/Saves/Util/SaveExtensions.cs index 7f054dbf5..27aef8016 100644 --- a/PKHeX.Core/Saves/Util/SaveExtensions.cs +++ b/PKHeX.Core/Saves/Util/SaveExtensions.cs @@ -40,7 +40,7 @@ public static bool IsCompatiblePKM(this SaveFile sav, PKM pk) private static List GetSaveFileErrata(this SaveFile sav, PKM pk, IBasicStrings strings) { - var errata = new List(); + var errata = new List(0); // usually nothing wrong, so start with empty list ushort held = (ushort)pk.HeldItem; if (sav.Generation > 1 && held != 0) { diff --git a/Tests/PKHeX.Core.Tests/PKM/PIDIVTests.cs b/Tests/PKHeX.Core.Tests/PKM/PIDIVTests.cs index f70b21746..f56e98da6 100644 --- a/Tests/PKHeX.Core.Tests/PKM/PIDIVTests.cs +++ b/Tests/PKHeX.Core.Tests/PKM/PIDIVTests.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using FluentAssertions; using Xunit; @@ -24,7 +23,7 @@ public void PIDIVMatchingTest3() var gk1 = new PK3(); PIDGenerator.SetValuesFromSeed(gk1, ga1.Type, ga1.OriginSeed); gk1.PID.Should().Be(pk1.PID); - gk1.IVs.SequenceEqual(pk1.IVs).Should().BeTrue(); + gk1.IV32.Should().Be(pk1.IV32); } [Fact] @@ -61,7 +60,7 @@ public void PIDIVMatchingTest3MiscCXD() var gk3 = new PK3(); PIDGenerator.SetValuesFromSeed(gk3, PIDType.CXD, pv.OriginSeed); gk3.PID.Should().Be(pk3.PID); - gk3.IVs.SequenceEqual(pk3.IVs).Should().BeTrue(); + gk3.IV32.Should().Be(pk3.IV32); } [Fact] @@ -75,7 +74,7 @@ public void PIDIVMatchingTest3MiscChannel() var gkC = new PK3(); PIDGenerator.SetValuesFromSeed(gkC, PIDType.Channel, pv.OriginSeed); gkC.PID.Should().Be(pkC.PID); - gkC.IVs.SequenceEqual(pkC.IVs).Should().BeTrue(); + gkC.IV32.Should().Be(pkC.IV32); } [Fact] @@ -110,7 +109,7 @@ public void PIDIVMatchingTest3Event() var gkRS = new PK3 { TID16 = 30317, SID16 = 00000 }; PIDGenerator.SetValuesFromSeed(gkRS, PIDType.BACD_S, bfix); gkRS.PID.Should().Be(pkRS.PID); - gkRS.IVs.SequenceEqual(pkRS.IVs).Should().BeTrue(); + gkRS.IV32.Should().Be(pkRS.IV32); // Unrestricted Antishiny nyx var nyxUA = new PK3 {PID = 0xBD3DF676, IVs = [00, 15, 05, 04, 21, 05], TID16 = 00080, SID16 = 00000};