Pokémon save files vary significantly across generations, from simple binary structures in Gen 1-2 to complex encrypted block systems in Gen 8-9. Understanding these structures helps you work effectively with save data.
var sav3 = SaveUtil.GetSaveFile("emerald.sav") as SAV3;if (sav3 != null){ // Gen 3 has two save slots (A and B) Console.WriteLine($"Game: {sav3.Version}"); // RS, E, or FRLG Console.WriteLine($"Security Key: {sav3.SecurityKey:X8}");}
var sav5 = SaveUtil.GetSaveFile("white2.sav") as SAV5B2W2;if (sav5 != null){ Console.WriteLine($"Game: {sav5.Version}"); // B2W2 has larger save size than BW}
var sav7 = SaveUtil.GetSaveFile("ultra_sun.sav") as SAV7USUM;if (sav7 != null){ Console.WriteLine($"Trainer: {sav7.OT}"); Console.WriteLine($"Festival Plaza Rank: {sav7.FestaCoins}");}
if (sav is SAV8SWSH swsh){ // Get typed values from blocks uint money = swsh.GetValue<uint>(0x00000001); // Example key // Access through typed accessors var myStatus = swsh.MyStatus; Console.WriteLine($"Money: {myStatus.Money}");}
if (sav is SAV9SV sv){ // Strongly-typed access to save data var myStatus = sv.Blocks.MyStatus; var items = sv.Blocks.Items; var zukan = sv.Blocks.Zukan; var boxLayout = sv.Blocks.BoxLayout; var played = sv.Blocks.Played; var config = sv.Blocks.Config; // Access nested data Console.WriteLine($"Trainer: {myStatus.OT}"); Console.WriteLine($"Play Time: {played.PlayedHours}h {played.PlayedMinutes}m"); Console.WriteLine($"Boxes Unlocked: {boxLayout.BoxesUnlocked}");}
var sav = SaveUtil.GetSaveFile("save.sav");if (sav != null){ var meta = sav.Metadata; // File information Console.WriteLine($"File Name: {meta.FileName}"); Console.WriteLine($"File Path: {meta.FilePath}"); // Handler information (if special format) if (meta.Handler != null) { Console.WriteLine($"Handler: {meta.Handler.GetType().Name}"); } // Exportability Console.WriteLine($"Exportable: {sav.State.Exportable}"); Console.WriteLine($"Edited: {sav.State.Edited}");}
var sav1 = new SAV1();// Gen 1 uses simple fixed offsets// Party: 0x2F2C (INT) or 0x2ED5 (JPN)// Current Box: 0x30C0 (INT) or 0x302D (JPN)// Checksum: Inverse sum validation
var sav3 = new SAV3E();// Gen 3 divides data into 14 sectors// Each sector: 4KB (0x1000 bytes)// Sector IDs: 0-13// Each sector has:// - Data (0xFF4 bytes)// - ID (2 bytes)// - Checksum (2 bytes)// - Signature (4 bytes)// - Save Index (4 bytes)