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};