Use this file to discover all available pages before exploring further.
This guide will walk you through the essential operations in PKHeX.Core: loading save files, accessing Pokémon data, making modifications, and saving changes.
Use the SaveUtil class to detect and load save files from any generation:
3
using PKHeX.Core;// Load a save file from diskstring savePath = "path/to/your/save.sav";if (SaveUtil.TryGetSaveFile(savePath, out SaveFile? sav)){ Console.WriteLine($"Loaded {sav.Version} save file!"); Console.WriteLine($"Trainer: {sav.OT}"); Console.WriteLine($"Generation: {sav.Generation}");}else{ Console.WriteLine("Failed to load save file.");}
4
SaveUtil automatically detects the save file type and returns the appropriate SaveFile subclass (e.g., SAV7SM, SAV8SWSH, SAV9SV).
5
Load from Byte Array
6
You can also load save data from a byte array:
7
byte[] saveData = File.ReadAllBytes("save.sav");Memory<byte> data = new Memory<byte>(saveData);if (SaveUtil.TryGetSaveFile(data, out SaveFile? sav, savePath)){ Console.WriteLine($"Game Version: {sav.Version}"); Console.WriteLine($"Playtime: {sav.PlayTimeString}");}
8
Access Pokémon Data
9
Once you have a save file loaded, you can access Pokémon from boxes or the party:
10
Box Pokémon
// Get all Pokémon from all boxesIList<PKM> allPokemon = sav.BoxData;Console.WriteLine($"Total box slots: {allPokemon.Count}");// Get Pokémon from a specific box (0-indexed)PKM[] boxPokemon = sav.GetBoxData(box: 0);foreach (var pk in boxPokemon){ if (pk.Species != 0) // Non-empty slot { Console.WriteLine($"{pk.Nickname} (#{pk.Species}) Lv. {pk.Stat_Level}"); }}// Get a specific Pokémon from box and slotPKM pokemon = sav.GetBoxSlotAtIndex(box: 0, slot: 0);if (pokemon.Species != 0){ Console.WriteLine($"Species: {pokemon.Species}"); Console.WriteLine($"Nickname: {pokemon.Nickname}"); Console.WriteLine($"Level: {pokemon.Stat_Level}"); Console.WriteLine($"OT: {pokemon.OriginalTrainerName}");}
Party Pokémon
// Get all party PokémonIList<PKM> party = sav.PartyData;Console.WriteLine($"Party count: {sav.PartyCount}");for (int i = 0; i < sav.PartyCount; i++){ PKM pk = sav.GetPartySlotAtIndex(i); Console.WriteLine($"Party #{i + 1}: {pk.Nickname} Lv. {pk.Stat_Level}"); Console.WriteLine($" HP: {pk.Stat_HPCurrent}/{pk.Stat_HPMax}"); Console.WriteLine($" Moves: {pk.Move1}, {pk.Move2}, {pk.Move3}, {pk.Move4}");}
11
Modify Pokémon Properties
12
PKHeX.Core provides full access to all Pokémon properties:
Always validate modifications using PKHeX.Core’s legality checker to ensure your Pokémon are legal for online play.
15
Write Pokémon Back to Save
16
After modifying a Pokémon, write it back to the save file:
17
// Write the modified Pokémon back to its slotsav.SetBoxSlotAtIndex(pk, box: 0, slot: 0);// Or write to a different slotsav.SetBoxSlotAtIndex(pk, box: 1, slot: 5);// Mark the save as edited (usually automatic)Console.WriteLine($"Save edited: {sav.State.Edited}");
18
Save Changes to File
19
Finally, write the modified save file back to disk:
20
// Get the final save data with checksums updatedMemory<byte> finalData = sav.Write();// Write to filestring outputPath = "path/to/modified_save.sav";File.WriteAllBytes(outputPath, finalData.ToArray());Console.WriteLine($"Save file written to {outputPath}");Console.WriteLine($"Checksums valid: {sav.ChecksumsValid}");
21
The Write() method automatically updates checksums before returning the data, ensuring the save file is valid.
PKM pokemon = sav.GetBoxSlotAtIndex(0, 0);// Get the encrypted box data (standard format)byte[] data = pokemon.EncryptedBoxData;// Save to file with appropriate extensionstring ext = pokemon.Extension; // e.g., "pk9" for Gen 9File.WriteAllBytes($"{pokemon.Nickname}.{ext}", data);
byte[] pkData = File.ReadAllBytes("Charizard.pk9");Memory<byte> memory = new Memory<byte>(pkData);// Create PKM object based on save contextPKM imported = EntityFormat.GetFromBytes(memory.Span, sav.Context);if (imported != null){ // Add to the first empty slot int emptySlot = sav.NextOpenBoxSlot(); if (emptySlot >= 0) { sav.SetBoxSlotAtIndex(imported, emptySlot); Console.WriteLine($"Imported {imported.Nickname} to slot {emptySlot}"); }}