Exemple #1
0
        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;
            }
        }
Exemple #2
0
        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!");
            }
        }
Exemple #3
0
        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!");
            }
        }
Exemple #4
0
        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;
        }
Exemple #5
0
        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();
        }
Exemple #6
0
        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!");
            }
        }
Exemple #7
0
        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;
        }