public Building(byte id, byte x, byte y, SaveType saveType) { Id = id; //Despite what previous editors assume, I'm fairly certain that the X & Y location bytes are structured like this: //Upper Nibble = Acre //Lower Nibble = Position in Acre //I say this, as a town hall in New Leaf with location bytes of X = 0x28, Y = 0x19 is positioned on the third X acre and second Y acre at 0x8, 0x9. SaveDataManager.GetNibbles(x, out XPos, out AcreX); SaveDataManager.GetNibbles(y, out YPos, out AcreY); AcreIndex = (byte)((AcreY - 1) * 5 + (AcreX - 1)); // * 5 works here because both CF and NL use 5 X acres if (AcreIndex > 24) //Works for NL too, since the dock is located in the 5th Y acre row. { AcreIndex = 0; } switch (saveType) { case SaveType.CityFolk: Name = ItemData.CfBuildingNames[id]; Exists = AcreX > 0 && AcreY > 0; break; case SaveType.NewLeaf: Name = ItemData.NlBuildingNames[id]; Exists = Id != 0xF8; break; default: Name = ItemData.WaBuildingNames[id]; Exists = Id != 0xFC; break; } }
public Save(string File_Path) { if (File.Exists(File_Path)) { if (Save_File != null) { Save_Reader.Close(); Save_File.Close(); } bool Failed_to_Load = false; try { Save_File = new FileStream(File_Path, FileMode.Open); } catch { Failed_to_Load = true; } if (Save_File == null || Failed_to_Load || !Save_File.CanWrite) { MessageBox.Show(string.Format("Error: File {0} is being used by another process. Please close any process using it before editing!", Path.GetFileName(File_Path)), "File Opening Error"); try { Save_File.Close(); } catch { }; return; } Save_Reader = new BinaryReader(Save_File); Original_Save_Data = Save_Reader.ReadBytes((int)Save_File.Length); Working_Save_Data = new byte[Original_Save_Data.Length]; Buffer.BlockCopy(Original_Save_Data, 0, Working_Save_Data, 0, Original_Save_Data.Length); Save_Type = SaveDataManager.GetSaveType(Original_Save_Data); Game_System = SaveDataManager.GetGameSystem(Save_Type); Full_Save_Path = File_Path; Save_Name = Path.GetFileNameWithoutExtension(File_Path); Save_Path = Path.GetDirectoryName(File_Path) + Path.DirectorySeparatorChar; Save_Extension = Path.GetExtension(File_Path); Save_ID = SaveDataManager.GetGameID(Save_Type); Save_Data_Start_Offset = SaveDataManager.GetSaveDataOffset(Save_ID.ToLower(), Save_Extension.Replace(".", "").ToLower()); Save_Info = SaveDataManager.GetSaveInfo(Save_Type); if (Save_Type == SaveType.Doubutsu_no_Mori) { Original_Save_Data = SaveDataManager.ByteSwap(Original_Save_Data); Working_Save_Data = SaveDataManager.ByteSwap(Working_Save_Data); } if (Save_Type == SaveType.Wild_World || Save_Type == SaveType.New_Leaf || Save_Type == SaveType.Welcome_Amiibo) { Is_Big_Endian = false; } Save_Reader.Close(); Save_File.Close(); } else { MessageBox.Show("File doesn't exist!"); } }
public Save(string filePath) { if (File.Exists(filePath)) { if (_saveFile != null) { _saveReader.Close(); _saveFile.Close(); } try { _saveFile = new FileStream(filePath, FileMode.Open); } catch { SuccessfullyLoaded = false; } if (_saveFile == null || !SuccessfullyLoaded || !_saveFile.CanWrite) { MessageBox.Show( $"Error: File {Path.GetFileName(filePath)} is being used by another process. Please close any process using it before editing!", "File Opening Error", MessageBoxButtons.OK, MessageBoxIcon.Error); try { _saveFile?.Close(); } catch { // ignored } return; } _saveReader = new BinaryReader(_saveFile); if (_saveFile.Length == 0x20000) { var data = _saveReader.ReadBytes(0x20000); if (Encoding.ASCII.GetString(data, 4, 4) == "JFAN") // Check for DnM which is byteswapped { OriginalSaveData = SaveDataManager.ByteSwap(data); SaveType = SaveType.DoubutsuNoMori; } else { OriginalSaveData = data; SaveType = SaveType.AnimalForest; } } else { OriginalSaveData = _saveReader.ReadBytes((int)_saveFile.Length); } WorkingSaveData = new byte[OriginalSaveData.Length]; Buffer.BlockCopy(OriginalSaveData, 0, WorkingSaveData, 0, OriginalSaveData.Length); SaveType = SaveDataManager.GetSaveType(OriginalSaveData) ?? SaveType; SaveGeneration = SaveDataManager.GetSaveGeneration(SaveType); FullSavePath = filePath; SaveName = Path.GetFileNameWithoutExtension(filePath); SavePath = Path.GetDirectoryName(filePath) + Path.DirectorySeparatorChar; SaveExtension = Path.GetExtension(filePath); SaveId = SaveDataManager.GetGameId(SaveType); SaveDataStartOffset = SaveDataManager.GetSaveDataOffset(SaveId.ToLower(), SaveExtension.Replace(".", "").ToLower()); SaveInfo = SaveDataManager.GetSaveInfo(SaveType); if (SaveType == SaveType.WildWorld || SaveGeneration == SaveGeneration.N3DS) { IsBigEndian = false; } _saveReader.Close(); _saveFile.Close(); _saveReader.Dispose(); _saveFile.Dispose(); // Create a Backup if (Properties.Settings.Default.BackupFiles) { _backup = new Backup(this); } } else { MessageBox.Show("File doesn't exist!"); } }
public void Flush() { var fullSaveName = SavePath + Path.DirectorySeparatorChar + SaveName + SaveExtension; _saveFile = new FileStream(fullSaveName, FileMode.OpenOrCreate); _saveWriter = new BinaryWriter(_saveFile); if (SaveGeneration == SaveGeneration.N64 || SaveGeneration == SaveGeneration.GCN || SaveGeneration == SaveGeneration.NDS) { Write(SaveDataStartOffset + SaveInfo.SaveOffsets.Checksum, Checksum.Calculate(WorkingSaveData.Skip(SaveDataStartOffset).Take(SaveInfo.SaveOffsets.SaveSize).ToArray(), SaveInfo.SaveOffsets.Checksum, !IsBigEndian), IsBigEndian); WorkingSaveData.Skip(SaveDataStartOffset).Take(SaveInfo.SaveOffsets.SaveSize).ToArray().CopyTo(WorkingSaveData, SaveDataStartOffset + SaveInfo.SaveOffsets.SaveSize); //Update second save copy var checksum = Checksum.Calculate( WorkingSaveData.Skip(SaveDataStartOffset).Take(SaveInfo.SaveOffsets.SaveSize).ToArray(), SaveInfo.SaveOffsets.Checksum, !IsBigEndian); Console.WriteLine( $"Save file checksum calculated is: 0x{checksum:X4}"); } else { switch (SaveType) { case SaveType.CityFolk: for (var i = 0; i < 4; i++) { var playerDataOffset = SaveDataStartOffset + i * 0x86C0 + 0x1140; var playerCrc32 = Crc32.CalculateCrc32(WorkingSaveData.Skip(playerDataOffset + 4).Take(0x759C).ToArray()); Write(playerDataOffset, playerCrc32, true); } Write(SaveDataStartOffset + 0x5EC60, Crc32.CalculateCrc32(WorkingSaveData.Skip(SaveDataStartOffset + 0x5EC64).Take(0x1497C).ToArray()), true); Write(SaveDataStartOffset + 0x5EB04, Crc32.CalculateCrc32(WorkingSaveData.Skip(SaveDataStartOffset + 0x5EB08).Take(0x152).ToArray(), 0x12141018), true); Write(SaveDataStartOffset + 0x73600, Crc32.CalculateCrc32(WorkingSaveData.Skip(SaveDataStartOffset + 0x73604).Take(0x19BD1C).ToArray()), true); Write(SaveDataStartOffset, Crc32.CalculateCrc32(WorkingSaveData.Skip(SaveDataStartOffset + 4).Take(0x1C).ToArray()), true); Write(SaveDataStartOffset + 0x20, Crc32.CalculateCrc32(WorkingSaveData.Skip(SaveDataStartOffset + 0x24).Take(0x111C).ToArray()), true); break; case SaveType.NewLeaf: Write(SaveDataStartOffset, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 4).Take(0x1C).ToArray())); for (var i = 0; i < 4; i++) { var dataOffset = SaveDataStartOffset + 0x20 + i * 0x9F10; Write(dataOffset, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(dataOffset + 4).Take(0x6B64).ToArray())); var dataOffset2 = SaveDataStartOffset + 0x20 + 0x6B68 + i * 0x9F10; Write(dataOffset2, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(dataOffset2 + 4).Take(0x33A4).ToArray())); } Write(SaveDataStartOffset + 0x27C60, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 0x27C60 + 4).Take(0x218B0).ToArray())); Write(SaveDataStartOffset + 0x49520, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 0x49520 + 4).Take(0x44B8).ToArray())); Write(SaveDataStartOffset + 0x4D9DC, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 0x4D9DC + 4).Take(0x1E420).ToArray())); Write(SaveDataStartOffset + 0x6BE00, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 0x6BE00 + 4).Take(0x20).ToArray())); Write(SaveDataStartOffset + 0x6BE24, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 0x6BE24 + 4).Take(0x13AF8).ToArray())); break; case SaveType.WelcomeAmiibo: Write(SaveDataStartOffset, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 4).Take(0x1C).ToArray())); for (var i = 0; i < 4; i++) { var dataOffset = SaveDataStartOffset + 0x20 + i * 0xA480; Write(dataOffset, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(dataOffset + 4).Take(0x6B84).ToArray())); var dataOffset2 = SaveDataStartOffset + 0x20 + 0x6B88 + i * 0xA480; Write(dataOffset2, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(dataOffset2 + 4).Take(0x38F4).ToArray())); } Write(SaveDataStartOffset + 0x29220, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 0x29220 + 4).Take(0x22BC8).ToArray())); Write(SaveDataStartOffset + 0x4BE00, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 0x4BE00 + 4).Take(0x44B8).ToArray())); Write(SaveDataStartOffset + 0x533A4, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 0x533A4 + 4).Take(0x1E4D8).ToArray())); Write(SaveDataStartOffset + 0x71880, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 0x71880 + 4).Take(0x20).ToArray())); Write(SaveDataStartOffset + 0x718A4, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 0x718A4 + 4).Take(0xBE4).ToArray())); Write(SaveDataStartOffset + 0x738D4, NewLeaftCrc32.Calculate_CRC32Type1(WorkingSaveData.Skip(SaveDataStartOffset + 0x738D4 + 4).Take(0x16188).ToArray())); Write(SaveDataStartOffset + 0x502BC, NewLeaftCrc32.Calculate_CRC32Type2(WorkingSaveData.Skip(SaveDataStartOffset + 0x502BC + 4).Take(0x28F0).ToArray())); Write(SaveDataStartOffset + 0x52BB0, NewLeaftCrc32.Calculate_CRC32Type2(WorkingSaveData.Skip(SaveDataStartOffset + 0x52BB0 + 4).Take(0x7F0).ToArray())); Write(SaveDataStartOffset + 0x7248C, NewLeaftCrc32.Calculate_CRC32Type2(WorkingSaveData.Skip(SaveDataStartOffset + 0x7248C + 4).Take(0x1444).ToArray())); break; } } _saveWriter.Write(SaveType == SaveType.DoubutsuNoMori ? SaveDataManager.ByteSwap(WorkingSaveData) : WorkingSaveData); //Doubutsu no Mori is dword byteswapped _saveWriter.Flush(); _saveFile.Flush(); _saveWriter.Close(); _saveFile.Close(); _saveWriter.Dispose(); _saveFile.Dispose(); ChangesMade = false; }
public void Flush() { string Full_Save_Name = Save_Path + Path.DirectorySeparatorChar + Save_Name + Save_Extension; Save_File = new FileStream(Full_Save_Name, FileMode.OpenOrCreate); Save_Writer = new BinaryWriter(Save_File); if (Save_Type == SaveType.Animal_Crossing) { Write(Save_Data_Start_Offset + 0x12, Checksum.Calculate(Working_Save_Data.Skip(Save_Data_Start_Offset).Take(0x26000).ToArray(), 0x12), true); Working_Save_Data.Skip(Save_Data_Start_Offset).Take(0x26000).ToArray().CopyTo(Working_Save_Data, Save_Data_Start_Offset + 0x26000); //Update second save copy } else if (Save_Type == SaveType.Wild_World) { Write(Save_Data_Start_Offset + 0x15FDC, Checksum.Calculate(Working_Save_Data.Skip(Save_Data_Start_Offset).Take(0x15FE0).ToArray(), 0x15FDC, true)); Working_Save_Data.Skip(Save_Data_Start_Offset).Take(0x15FE0).ToArray().CopyTo(Working_Save_Data, Save_Data_Start_Offset + 0x15FE0); //Update both save copies on WW } else if (Save_Type == SaveType.City_Folk) { for (int i = 0; i < 4; i++) { int Player_Data_Offset = Save_Data_Start_Offset + i * 0x86C0 + 0x1140; uint Player_CRC32 = CRC32.GetCRC32(Working_Save_Data.Skip(Player_Data_Offset + 4).Take(0x759C).ToArray()); Write(Player_Data_Offset, Player_CRC32, true); } Write(Save_Data_Start_Offset + 0x5EC60, CRC32.GetCRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x5EC64).Take(0x1497C).ToArray()), true); Write(Save_Data_Start_Offset + 0x5EB04, CRC32.GetCRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x5EB08).Take(0x152).ToArray(), 0x12141018), true); Write(Save_Data_Start_Offset + 0x73600, CRC32.GetCRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x73604).Take(0x19BD1C).ToArray()), true); Write(Save_Data_Start_Offset, CRC32.GetCRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 4).Take(0x1C).ToArray()), true); Write(Save_Data_Start_Offset + 0x20, CRC32.GetCRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x24).Take(0x111C).ToArray()), true); } else if (Save_Type == SaveType.New_Leaf) { Write(Save_Data_Start_Offset, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 4).Take(0x1C).ToArray())); for (int i = 0; i < 4; i++) { int DataOffset = Save_Data_Start_Offset + 0x20 + i * 0x9F10; Write(DataOffset, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(DataOffset + 4).Take(0x6B64).ToArray())); int DataOffset2 = Save_Data_Start_Offset + 0x20 + 0x6B68 + i * 0x9F10; Write(DataOffset2, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(DataOffset2 + 4).Take(0x33A4).ToArray())); } Write(Save_Data_Start_Offset + 0x27C60, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x27C60 + 4).Take(0x218B0).ToArray())); Write(Save_Data_Start_Offset + 0x49520, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x49520 + 4).Take(0x44B8).ToArray())); Write(Save_Data_Start_Offset + 0x4D9DC, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x4D9DC + 4).Take(0x1E420).ToArray())); Write(Save_Data_Start_Offset + 0x6BE00, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x6BE00 + 4).Take(0x20).ToArray())); Write(Save_Data_Start_Offset + 0x6BE24, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x6BE24 + 4).Take(0x13AF8).ToArray())); } else if (Save_Type == SaveType.Welcome_Amiibo) { Write(Save_Data_Start_Offset, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 4).Take(0x1C).ToArray())); for (int i = 0; i < 4; i++) { int DataOffset = Save_Data_Start_Offset + 0x20 + i * 0xA480; Write(DataOffset, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(DataOffset + 4).Take(0x6B84).ToArray())); int DataOffset2 = Save_Data_Start_Offset + 0x20 + 0x6B88 + i * 0xA480; Write(DataOffset2, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(DataOffset2 + 4).Take(0x38F4).ToArray())); } Write(Save_Data_Start_Offset + 0x29220, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x29220 + 4).Take(0x22BC8).ToArray())); Write(Save_Data_Start_Offset + 0x4BE00, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x4BE00 + 4).Take(0x44B8).ToArray())); Write(Save_Data_Start_Offset + 0x533A4, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x533A4 + 4).Take(0x1E4D8).ToArray())); Write(Save_Data_Start_Offset + 0x71880, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x71880 + 4).Take(0x20).ToArray())); Write(Save_Data_Start_Offset + 0x718A4, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x718A4 + 4).Take(0xBE4).ToArray())); Write(Save_Data_Start_Offset + 0x738D4, NL_CRC32.Calculate_CRC32(Working_Save_Data.Skip(Save_Data_Start_Offset + 0x738D4 + 4).Take(0x16188).ToArray())); } Save_Writer.Write(Save_Type == SaveType.Doubutsu_no_Mori ? SaveDataManager.ByteSwap(Working_Save_Data) : Working_Save_Data); //Doubutsu no Mori is dword byteswapped Save_Writer.Flush(); Save_File.Flush(); Save_Writer.Close(); Save_File.Close(); }
public Save(string filePath) { if (File.Exists(filePath)) { if (_saveFile != null) { _saveReader.Close(); _saveFile.Close(); } try { _saveFile = new FileStream(filePath, FileMode.Open); } catch { SuccessfullyLoaded = false; } if (_saveFile == null || !SuccessfullyLoaded || !_saveFile.CanWrite) { MessageBox.Show( $"Error: File {Path.GetFileName(filePath)} is being used by another process. Please close any process using it before editing!", "File Opening Error", MessageBoxButtons.OK, MessageBoxIcon.Error); try { _saveFile?.Close(); } catch { // ignored } return; } _saveReader = new BinaryReader(_saveFile); SaveData = _saveReader.ReadBytes((int)_saveFile.Length); _byteswap = this.IsByteSwapped(); if (_byteswap) { SaveData = SaveDataManager.ByteSwap(SaveData); // Only byteswap the working data. } SaveType = this.GetSaveType(); SaveGeneration = SaveDataManager.GetSaveGeneration(SaveType); FullSavePath = filePath; SaveName = Path.GetFileNameWithoutExtension(filePath); SavePath = Path.GetDirectoryName(filePath) + Path.DirectorySeparatorChar; SaveExtension = Path.GetExtension(filePath); SaveId = SaveDataManager.GetGameId(SaveType); SaveDataStartOffset = SaveDataManager.GetSaveDataOffset(SaveId.ToLower(), SaveExtension?.Replace(".", "").ToLower()); SaveInfo = SaveDataManager.GetSaveInfo(SaveType); if (SaveType == SaveType.WildWorld || SaveGeneration == SaveGeneration.N3DS) { IsBigEndian = false; } _saveReader.Close(); _saveFile.Close(); _saveReader.Dispose(); _saveFile.Dispose(); // Create a Backup if (Properties.Settings.Default.BackupFiles) { _backup = new Backup(this); } } else { MessageBox.Show("File doesn't exist!"); } }
public void Flush() { var fullSaveName = SavePath + Path.DirectorySeparatorChar + SaveName + SaveExtension; _saveFile = new FileStream(fullSaveName, FileMode.OpenOrCreate); _saveWriter = new BinaryWriter(_saveFile); switch (SaveType) { case SaveType.DoubutsuNoMoriPlus: case SaveType.AnimalCrossing: case SaveType.DoubutsuNoMoriEPlus: case SaveType.AnimalForestEPlus: Write(SaveDataStartOffset + SaveInfo.SaveOffsets.Checksum, new UInt16BEChecksum().Calculate( SaveData.Skip(SaveDataStartOffset).Take(SaveInfo.SaveOffsets.SaveSize).ToArray(), (uint)SaveInfo.SaveOffsets.Checksum), IsBigEndian); SaveData.Skip(SaveDataStartOffset).Take(SaveInfo.SaveOffsets.SaveSize).ToArray().CopyTo( SaveData, SaveDataStartOffset + SaveInfo.SaveOffsets.SaveSize); break; case SaveType.WildWorld: Write(SaveDataStartOffset + SaveInfo.SaveOffsets.Checksum, new UInt16LEChecksum().Calculate( SaveData.Skip(SaveDataStartOffset).Take(SaveInfo.SaveOffsets.SaveSize).ToArray(), (uint)SaveInfo.SaveOffsets.Checksum), IsBigEndian); SaveData.Skip(SaveDataStartOffset).Take(SaveInfo.SaveOffsets.SaveSize).ToArray().CopyTo( SaveData, SaveDataStartOffset + SaveInfo.SaveOffsets.SaveSize); break; case SaveType.DoubutsuNoMori: case SaveType.AnimalForest: Write(SaveDataStartOffset + SaveInfo.SaveOffsets.Checksum, new UInt16BEChecksum().Calculate( SaveData.Skip(SaveDataStartOffset).Take(0xF980).ToArray(), (uint)SaveInfo.SaveOffsets.Checksum), IsBigEndian); SaveData.Skip(SaveDataStartOffset).Take(SaveInfo.SaveOffsets.SaveSize).ToArray().CopyTo( SaveData, SaveDataStartOffset + SaveInfo.SaveOffsets.SaveSize); break; case SaveType.CityFolk: var crc32 = new CRC32(); for (var i = 0; i < 4; i++) { var playerDataOffset = SaveDataStartOffset + i * 0x86C0 + 0x1140; var playerCrc32 = crc32.Calculate(SaveData.Skip(playerDataOffset + 4).Take(0x759C).ToArray()); Write(playerDataOffset, playerCrc32, true); } Write(SaveDataStartOffset + 0x5EC60, crc32.Calculate(SaveData.Skip(SaveDataStartOffset + 0x5EC64).Take(0x1497C).ToArray()), true); Write(SaveDataStartOffset + 0x5EB04, crc32.Calculate(SaveData.Skip(SaveDataStartOffset + 0x5EB08).Take(0x152).ToArray(), 0x12141018), true); Write(SaveDataStartOffset + 0x73600, crc32.Calculate(SaveData.Skip(SaveDataStartOffset + 0x73604).Take(0x19BD1C).ToArray()), true); Write(SaveDataStartOffset, crc32.Calculate(SaveData.Skip(SaveDataStartOffset + 4).Take(0x1C).ToArray()), true); Write(SaveDataStartOffset + 0x20, crc32.Calculate(SaveData.Skip(SaveDataStartOffset + 0x24).Take(0x111C).ToArray()), true); break; case SaveType.NewLeaf: var crc32Type1 = new NewLeafCRC32Type1(); Write(SaveDataStartOffset, crc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 4).Take(0x1C).ToArray())); for (var i = 0; i < 4; i++) { var dataOffset = SaveDataStartOffset + 0x20 + i * 0x9F10; Write(dataOffset, crc32Type1.Calculate(SaveData.Skip(dataOffset + 4).Take(0x6B64).ToArray())); var dataOffset2 = SaveDataStartOffset + 0x20 + 0x6B68 + i * 0x9F10; Write(dataOffset2, crc32Type1.Calculate(SaveData.Skip(dataOffset2 + 4).Take(0x33A4).ToArray())); } Write(SaveDataStartOffset + 0x27C60, crc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 0x27C60 + 4).Take(0x218B0) .ToArray())); Write(SaveDataStartOffset + 0x49520, crc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 0x49520 + 4).Take(0x44B8) .ToArray())); Write(SaveDataStartOffset + 0x4D9DC, crc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 0x4D9DC + 4).Take(0x1E420) .ToArray())); Write(SaveDataStartOffset + 0x6BE00, crc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 0x6BE00 + 4).Take(0x20) .ToArray())); Write(SaveDataStartOffset + 0x6BE24, crc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 0x6BE24 + 4).Take(0x13AF8) .ToArray())); break; case SaveType.WelcomeAmiibo: var waCrc32Type1 = new NewLeafCRC32Type1(); var waCrc32Type2 = new NewLeafCRC32Type2(); // CRC32 Implementation Type 1 Checksums Write(SaveDataStartOffset, waCrc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 4).Take(0x1C).ToArray())); for (var i = 0; i < 4; i++) { var dataOffset = SaveDataStartOffset + 0x20 + i * 0xA480; Write(dataOffset, waCrc32Type1.Calculate(SaveData.Skip(dataOffset + 4).Take(0x6B84).ToArray())); var dataOffset2 = SaveDataStartOffset + 0x20 + 0x6B88 + i * 0xA480; Write(dataOffset2, waCrc32Type1.Calculate(SaveData.Skip(dataOffset2 + 4).Take(0x38F4).ToArray())); } Write(SaveDataStartOffset + 0x29220, waCrc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 0x29220 + 4).Take(0x22BC8) .ToArray())); Write(SaveDataStartOffset + 0x4BE00, waCrc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 0x4BE00 + 4).Take(0x44B8) .ToArray())); Write(SaveDataStartOffset + 0x533A4, waCrc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 0x533A4 + 4).Take(0x1E4D8) .ToArray())); Write(SaveDataStartOffset + 0x71880, waCrc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 0x71880 + 4).Take(0x20) .ToArray())); Write(SaveDataStartOffset + 0x718A4, waCrc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 0x718A4 + 4).Take(0xBE4) .ToArray())); Write(SaveDataStartOffset + 0x738D4, waCrc32Type1.Calculate(SaveData.Skip(SaveDataStartOffset + 0x738D4 + 4).Take(0x16188) .ToArray())); // CRC32 Implementation Type 2 Checksums Write(SaveDataStartOffset + 0x502BC, waCrc32Type2.Calculate(SaveData.Skip(SaveDataStartOffset + 0x502BC + 4).Take(0x28F0) .ToArray())); Write(SaveDataStartOffset + 0x52BB0, waCrc32Type2.Calculate(SaveData.Skip(SaveDataStartOffset + 0x52BB0 + 4).Take(0x7F0) .ToArray())); Write(SaveDataStartOffset + 0x7248C, waCrc32Type2.Calculate(SaveData.Skip(SaveDataStartOffset + 0x7248C + 4).Take(0x1444) .ToArray())); break; } _saveWriter.Write(SaveType == SaveType.DoubutsuNoMori && _byteswap ? SaveDataManager.ByteSwap(SaveData) : SaveData); // Doubutsu no Mori is dword byteswapped _saveWriter.Flush(); _saveFile.Flush(); _saveWriter.Close(); _saveFile.Close(); _saveWriter.Dispose(); _saveFile.Dispose(); ChangesMade = false; }