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 (Game_System == SaveGeneration.GCN) // TODO: Condense Wild World and GCN save logic into one if statement { Write(Save_Data_Start_Offset + 0x12, Checksum.Calculate(Working_Save_Data.Skip(Save_Data_Start_Offset).Take(Save_Info.Save_Offsets.Save_Size).ToArray(), 0x12), true); Working_Save_Data.Skip(Save_Data_Start_Offset).Take(Save_Info.Save_Offsets.Save_Size).ToArray().CopyTo(Working_Save_Data, Save_Data_Start_Offset + Save_Info.Save_Offsets.Save_Size); //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 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.DongwuSenlin: 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; }