Example #1
0
        public void Write(int offset, dynamic data, bool reversed = false, int stringLength = 0)
        {
            if (data == null)
            {
                return;
            }
            ChangesMade = true;
            Type dataType = data.GetType();

            MainForm.DebugManager.WriteLine(string.Format("Writing Data {2} of type {0} to offset 0x{1:X}", dataType.Name, offset, //recasting a value shows it as original type?
                                                          dataType.IsArray ? "" : " with value 0x" + (data.ToString("X"))), DebugLevel.Debug);
            if (!dataType.IsArray)
            {
                if (dataType == typeof(byte))
                {
                    WorkingSaveData[offset] = (byte)data;
                }
                else if (dataType == typeof(string))
                {
                    var stringByteBuff = AcString.GetBytes((string)data, stringLength);
                    Buffer.BlockCopy(stringByteBuff, 0, WorkingSaveData, offset, stringByteBuff.Length);
                }
                else
                {
                    byte[] byteArray = BitConverter.GetBytes(data);
                    if (reversed)
                    {
                        Array.Reverse(byteArray);
                    }
                    Buffer.BlockCopy(byteArray, 0, WorkingSaveData, offset, byteArray.Length);
                }
            }
            else
            {
                if (dataType == typeof(byte[]))
                {
                    for (var i = 0; i < data.Length; i++)
                    {
                        WorkingSaveData[offset + i] = data[i];
                    }
                }
                else
                {
                    int dataSize = Marshal.SizeOf(data[0]);
                    for (var i = 0; i < data.Length; i++)
                    {
                        byte[] byteArray = BitConverter.GetBytes(data[i]);
                        if (reversed)
                        {
                            Array.Reverse(byteArray);
                        }
                        byteArray.CopyTo(WorkingSaveData, offset + i * dataSize);
                    }
                }
            }
        }
Example #2
0
        public void Write(int offset, string value, int maxLength = 0, bool includeStartOffset = false)
        {
            if (includeStartOffset)
            {
                offset += SaveDataStartOffset;
            }

            var stringByteBuff = AcString.GetBytes(value, maxLength);

            Buffer.BlockCopy(stringByteBuff, 0, SaveData, offset, stringByteBuff.Length);
        }
Example #3
0
 public override void Write()
 {
     SaveFile.Write(Offset, AcString.GetBytes(PlayerName, 8));
     SaveFile.Write(Offset + 8, AcString.GetBytes(PlayerTownName, 8));
     SaveFile.Write(Offset + 0x10, PlayerId, true);
     SaveFile.Write(Offset + 0x12, PlayerTownId, true);
     // Met Date
     SaveFile.Write(Offset + 0x1C, AcString.GetBytes(MetTownName, 8));
     SaveFile.Write(Offset + 0x24, MetTownId, true);
     // Unknown 1
     SaveFile.Write(Offset + 0x30, Friendship);
     SaveFile.Write(Offset + 0x31, Flags);
     // Letter Data
 }
Example #4
0
        public void Write(byte[] newPatternData)
        {
            if (_saveFile.SaveGeneration == SaveGeneration.GCN)
            {
                var patternNameSize = _saveFile.SaveType == SaveType.AnimalCrossing ? 0x10 : 0x0A;
                _saveFile.Write(_offset, AcString.GetBytes(Name, patternNameSize));
                _saveFile.Write(_offset + patternNameSize, Palette);
                _saveFile.Write(_offset + 0x20, newPatternData);
            }
            else
            {
                switch (_saveFile.SaveType)
                {
                case SaveType.WildWorld:
                    _saveFile.Write(_offset, newPatternData);
                    // TODO: Town Name & Creator Name (Also for City Folk, New Leaf)
                    _saveFile.Write(_offset + 0x216, AcString.GetBytes(Name, 0x10));
                    _saveFile.Write(_offset + 0x226, (byte)(((Palette & 0x0F) << 4) | (Concept & 0x0F)));
                    break;

                case SaveType.CityFolk:
                    _saveFile.Write(_offset, newPatternData);
                    _saveFile.Write(_offset + 0x84C, AcString.GetBytes(Name, 0x20));
                    _saveFile.Write(_offset + 0x86F, Palette);
                    break;

                default:
                    if (_saveFile.SaveGeneration == SaveGeneration.N3DS)
                    {
                        _saveFile.Write(_offset, AcString.GetBytes(Name, 0x2A));
                        _saveFile.Write(_offset + 0x6C, newPatternData);
                        // TODO: Write Palette (since it's customizable)
                    }

                    break;
                }
            }
        }
Example #5
0
        public virtual void Write()
        {
            var saveData = Save.SaveInstance;
            var offsets  = HouseInfo.GetHouseOffsets(saveData.SaveType);

            // Set House TownID & Name
            if (Owner != null)
            {
                if (offsets.OwningPlayerName != -1 && offsets.TownId != -1)
                {
                    Data.TownId =
                        saveData.ReadUInt16(saveData.SaveDataStartOffset + Save.SaveInstance.SaveInfo.SaveOffsets.TownId,
                                            saveData.IsBigEndian); // Might not be UInt16 in all games
                }

                if (offsets.OwningPlayerName != -1 && offsets.TownName != -1)
                {
                    Data.TownName = saveData.ReadString(
                        saveData.SaveDataStartOffset + Save.SaveInstance.SaveInfo.SaveOffsets.TownName,
                        Save.SaveInstance.SaveInfo.SaveOffsets.TownNameSize);
                }

                if (offsets.OwningPlayerName != -1)
                {
                    Data.OwningPlayerName = Owner.Data.Name;
                }

                if (offsets.OwningPlayerId != -1)
                {
                    Data.OwningPlayerId = Owner.Data.Identifier;
                }
            }

            var houseOffsetData = typeof(HouseOffsets);
            var houseDataType   = typeof(HouseData);

            foreach (var field in houseOffsetData.GetFields(BindingFlags.Public | BindingFlags.Instance))
            {
                if (field.GetValue(offsets) == null || field.Name.Contains("Count") ||
                    field.Name.Contains("Size"))
                {
                    continue;
                }
                if (houseDataType.GetField(field.Name) == null)
                {
                    continue;
                }
                if (field.FieldType != typeof(int) || (int)field.GetValue(offsets) == -1)
                {
                    continue;
                }
                var fieldType  = houseDataType.GetField(field.Name).FieldType;
                var dataOffset = Offset + (int)field.GetValue(offsets);
                //MessageBox.Show("Field Name: " + Field.Name + " | Data Offset: " + DataOffset.ToString("X"));
                if (fieldType == typeof(string))
                {
                    saveData.Write(dataOffset, AcString.GetBytes((string)houseDataType.GetField(field.Name).GetValue(Data),
                                                                 (int)houseOffsetData.GetField(field.Name + "Size").GetValue(offsets)));
                }
                else if (fieldType == typeof(byte))
                {
                    saveData.Write(dataOffset, (byte)houseDataType.GetField(field.Name).GetValue(Data));
                }
                else if (fieldType == typeof(byte[]))
                {
                    saveData.Write(dataOffset, (byte[])houseDataType.GetField(field.Name).GetValue(Data));
                }
                else if (fieldType == typeof(ushort))
                {
                    saveData.Write(dataOffset, (ushort)houseDataType.GetField(field.Name).GetValue(Data), saveData.IsBigEndian);
                }
                else if (fieldType == typeof(Item))
                {
                    if (saveData.SaveGeneration == SaveGeneration.N3DS)
                    {
                        saveData.Write(dataOffset, ItemData.EncodeItem((Item)houseDataType.GetField(field.Name).GetValue(Data)), saveData.IsBigEndian);
                    }
                    else
                    {
                        saveData.Write(dataOffset, ((Item)houseDataType.GetField(field.Name).GetValue(Data)).ItemId, saveData.IsBigEndian);
                    }
                }
            }

            foreach (var r in Data.Rooms)
            {
                r.Write();
            }
        }
Example #6
0
        public void Write()
        {
            // Set City Folk Bed first
            if (_saveData.SaveGeneration == SaveGeneration.Wii && House != null && Data.Bed != null)
            {
                House.Data.Bed = Data.Bed;
                Data.Bed       = null;
            }

            var playerSaveInfoType = typeof(PlayerSaveInfo);
            var playerDataType     = typeof(PlayerData);

            foreach (var field in playerSaveInfoType.GetFields(BindingFlags.Public | BindingFlags.Instance))
            {
                if (field.GetValue(Offsets) == null || field.Name.Contains("Count") ||
                    field.Name.Contains("Size"))
                {
                    continue;
                }
                if (playerDataType.GetField(field.Name) == null)
                {
                    continue;
                }
                if (field.FieldType != typeof(int) || (int)field.GetValue(Offsets) == -1)
                {
                    continue;
                }

                var fieldType  = typeof(PlayerData).GetField(field.Name).FieldType;
                var dataOffset = Offset + (int)field.GetValue(Offsets);
                switch (field.Name)
                {
                case "TownPassCardImage" when _saveData.SaveGeneration == SaveGeneration.N3DS:
                    _saveData.Write(dataOffset, Data.TownPassCardData);
                    break;

                case "Reset" when _saveData.SaveGeneration == SaveGeneration.GCN:
                    _saveData.Write(dataOffset, Data.Reset ? (uint)0x250C : (uint)0, _saveData.IsBigEndian);
                    break;

                default:
                    if (fieldType == typeof(string))
                    {
                        _saveData.Write(dataOffset, AcString.GetBytes((string)playerDataType.GetField(field.Name).GetValue(Data),
                                                                      (int)playerSaveInfoType.GetField(field.Name + "Size").GetValue(Offsets)));
                    }
                    else if (fieldType == typeof(byte))
                    {
                        if (_saveData.SaveType == SaveType.WildWorld)
                        {
                            switch (field.Name)
                            {
                            case "HairColor":
                            {
                                var condensedData = (byte)(Data.HairColor & 0x0F);       //Remove upper nibble just incase
                                condensedData += (byte)((Data.Tan & 0x0F) << 4);         //Add in tan to the byte
                                _saveData.Write(dataOffset, condensedData);
                                break;
                            }

                            case "HairType":
                            {
                                var condensedData = (byte)(Data.FaceType & 0x0F);
                                condensedData += (byte)((Data.HairType & 0x0F) << 4);
                                _saveData.Write(dataOffset, condensedData);
                                break;
                            }

                            default:
                                _saveData.Write(dataOffset, (byte)playerDataType.GetField(field.Name).GetValue(Data));
                                break;
                            }
                        }
                        else if (_saveData.SaveType == SaveType.CityFolk)
                        {
                            switch (field.Name)
                            {
                            case "Tan":
                                var shiftedData = (byte)(Data.Tan << 1);         //ACToolkit does this
                                _saveData.Write(dataOffset, shiftedData);
                                break;

                            case "FaceType":
                                _saveData.Write(dataOffset, (byte)(Data.EyeColor + Data.FaceType));
                                break;

                            default:
                                _saveData.Write(dataOffset, (byte)playerDataType.GetField(field.Name).GetValue(Data));
                                break;
                            }
                        }
                        else
                        {
                            _saveData.Write(dataOffset, (byte)playerDataType.GetField(field.Name).GetValue(Data));
                        }
                    }
                    else if (fieldType == typeof(ushort))
                    {
                        _saveData.Write(dataOffset, (ushort)playerDataType.GetField(field.Name).GetValue(Data), _saveData.IsBigEndian);
                    }
                    else if (fieldType == typeof(uint))
                    {
                        _saveData.Write(dataOffset, (uint)playerDataType.GetField(field.Name).GetValue(Data), _saveData.IsBigEndian);
                    }
                    else if (fieldType == typeof(Inventory))
                    {
                        if (_saveData.SaveGeneration == SaveGeneration.N3DS)
                        {
                            var items = new uint[Offsets.PocketsCount];
                            for (var i = 0; i < items.Length; i++)
                            {
                                items[i] = ItemData.EncodeItem(Data.Pockets.Items[i]);
                            }
                            _saveData.Write(dataOffset, items);
                        }
                        else
                        {
                            var items = new ushort[Offsets.PocketsCount];
                            for (var i = 0; i < items.Length; i++)
                            {
                                items[i] = Data.Pockets.Items[i].ItemId;
                            }
                            _saveData.Write(dataOffset, items, _saveData.IsBigEndian);
                        }
                    }
                    else if (fieldType == typeof(Item))
                    {
                        var item = (Item)playerDataType.GetField(field.Name).GetValue(Data);
                        if (_saveData.SaveGeneration == SaveGeneration.N3DS)
                        {
                            _saveData.Write(dataOffset, item.ToUInt32());
                        }
                        else
                        {
                            if (field.Name.Equals("Shirt") &&
                                (_saveData.SaveGeneration == SaveGeneration.N64 || _saveData.SaveGeneration == SaveGeneration.GCN ||
                                 _saveData.SaveGeneration == SaveGeneration.iQue))     // For some reason, the shirt lower byte is also stored before the actual item id.
                            {
                                _saveData.Write(dataOffset - 1, new[] { (byte)item.ItemId, (byte)(item.ItemId >> 8), (byte)item.ItemId }, _saveData.IsBigEndian);
                            }
                            else
                            {
                                _saveData.Write(dataOffset, item.ItemId, _saveData.IsBigEndian);
                            }
                        }
                    }
                    else if (fieldType == typeof(Item[]))
                    {
                        var itemArray = (Item[])playerDataType.GetField(field.Name).GetValue(Data);
                        if (field.Name.Equals("Dressers"))
                        {
                            switch (_saveData.SaveGeneration)
                            {
                            case SaveGeneration.NDS:
                                dataOffset = _saveData.SaveDataStartOffset + 0x15430 + 0xB4 * Index;         // Terrible hack
                                break;

                            case SaveGeneration.Wii:
                                dataOffset = _saveData.SaveDataStartOffset + 0x1F3038 + 0x140 * Index;
                                break;
                            }
                        }

                        for (var i = 0; i < itemArray.Length; i++)
                        {
                            if (_saveData.SaveGeneration == SaveGeneration.N3DS)
                            {
                                _saveData.Write(dataOffset + i * 4, itemArray[i].ToUInt32());
                            }
                            else
                            {
                                _saveData.Write(dataOffset + i * 2, itemArray[i].ItemId, _saveData.IsBigEndian);
                            }
                        }
                    }
                    else if (fieldType == typeof(NewLeafInt32))
                    {
                        if (_saveData.SaveGeneration == SaveGeneration.NDS)
                        {
                            var encryptedInt = (NewLeafInt32)playerDataType.GetField(field.Name).GetValue(Data);
                            _saveData.Write(dataOffset, encryptedInt.Int1);
                            _saveData.Write(dataOffset + 4, encryptedInt.Int2);
                        }
                    }
                    else if (fieldType == typeof(AcDate) && (_saveData.SaveGeneration == SaveGeneration.GCN ||
                                                             _saveData.SaveGeneration == SaveGeneration.NDS ||
                                                             _saveData.SaveGeneration == SaveGeneration.Wii))
                    {
                        if (field.Name.Equals("Birthday"))
                        {
                            _saveData.Write(dataOffset, ((AcDate)playerDataType.GetField(field.Name).GetValue(Data)).ToMonthDayDateData());
                        }
                    }

                    break;
                }
            }
        }
Example #7
0
        public void Write(string townName)
        {
            // Set Villager TownID & Name when villager exists.
            if (Exists && _saveData.SaveGeneration != SaveGeneration.iQue) // TODO: Once iQue text is implemented, remove this.
            {
                if (Offsets.TownId != -1)
                {
                    Data.TownId = _saveData.ReadUInt16(_saveData.SaveDataStartOffset + MainForm.CurrentSaveInfo.SaveOffsets.TownId, _saveData.IsBigEndian); // Might not be UInt16 in all games
                }
                if (!string.IsNullOrWhiteSpace(townName) && Offsets.TownName != -1)
                {
                    Data.TownName = townName;
                }
            }

            if (!Exists)
            {
                return;          // TODO: Do I need this? it overwrites important stuff in Animal Forest iQue if I don't have it.
            }
            var villagerOffsetData = typeof(VillagerOffsets);
            var villagerDataType   = typeof(VillagerDataStruct);

            foreach (var field in villagerOffsetData.GetFields(BindingFlags.Public | BindingFlags.Instance))
            {
                if (field.GetValue(Offsets) == null || field.Name.Contains("Count") ||
                    field.Name.Contains("Size"))
                {
                    continue;
                }
                if (villagerDataType.GetField(field.Name) == null)
                {
                    continue;
                }
                if (field.FieldType != typeof(int) || (int)field.GetValue(Offsets) == -1)
                {
                    continue;
                }

                var     fieldType  = villagerDataType.GetField(field.Name).FieldType;
                var     dataOffset = Offset + (int)field.GetValue(Offsets);
                dynamic dataObject = villagerDataType.GetField(field.Name).GetValue(Data);

                switch (field.Name)
                {
                case "VillagerId" when _saveData.SaveType == SaveType.WildWorld:
                    _saveData.Write(dataOffset, Convert.ToByte(dataObject));
                    break;

                //Might not encompass City Folk
                case "VillagerId":
                    _saveData.Write(dataOffset, dataObject, _saveData.IsBigEndian);
                    break;

                default:
                    if (fieldType == typeof(string))
                    {
                        _saveData.Write(dataOffset, AcString.GetBytes(dataObject, (int)villagerOffsetData.GetField(field.Name + "Size").GetValue(Offsets)));
                    }
                    else if (fieldType == typeof(byte[]))
                    {
                        _saveData.Write(dataOffset, dataObject, false);
                    }
                    else if (fieldType == typeof(Item))
                    {
                        switch (_saveData.SaveGeneration)
                        {
                        case SaveGeneration.N3DS:
                            _saveData.Write(dataOffset, ItemData.EncodeItem((Item)dataObject));
                            break;

                        default:
                            _saveData.Write(dataOffset, ((Item)dataObject).ItemId, _saveData.IsBigEndian);
                            break;
                        }
                    }
                    else if (fieldType == typeof(Item[]))
                    {
                        if (dataObject is Item[] collection)
                        {
                            for (var i = 0; i < collection.Length; i++)
                            {
                                switch (_saveData.SaveGeneration)
                                {
                                case SaveGeneration.N3DS:
                                    _saveData.Write(dataOffset + i * 4, ItemData.EncodeItem(collection[i]));
                                    break;

                                default:
                                    _saveData.Write(dataOffset + i * 2, collection[i].ItemId,
                                                    _saveData.IsBigEndian);
                                    break;
                                }
                            }
                        }
                    }
                    else if (!fieldType.IsClass)     // Don't write classes. If we're here, the that means that we haven't handled saving the class.
                    {
                        _saveData.Write(dataOffset, dataObject, _saveData.IsBigEndian);
                    }

                    break;
                }
            }

            // Write PlayerRelations
            if (Exists && PlayerRelations != null)
            {
                foreach (var relation in PlayerRelations)
                {
                    if (relation.Exists)
                    {
                        relation.Write();
                    }
                }
            }

            // Write the NameId for N64/GC/iQue games, & name for e+. TODO: Check if Wild World also has this.
            if (_saveData.SaveGeneration != SaveGeneration.N64 && _saveData.SaveGeneration != SaveGeneration.GCN &&
                _saveData.SaveGeneration != SaveGeneration.iQue)
            {
                return;
            }

            switch (_saveData.SaveType)
            {
            case SaveType.DoubutsuNoMoriPlus:
            case SaveType.AnimalCrossing:
                _saveData.Write(Offset + Offsets.NameId, Index == 15 ? (byte)0xFF : (byte)Data.VillagerId);
                break;

            case SaveType.DoubutsuNoMoriEPlus:     // e+ doesn't set this byte, as they changed the SetNameID function
                _saveData.Write(Offset + 0xC, AcString.GetBytes(Name, 6), false);
                break;

            case SaveType.AnimalForestEPlus:
                _saveData.Write(Offset + 0xC, AcString.GetBytes(Name, 8), false);
                break;

            default:
                _saveData.Write(Offset + Offsets.NameId, (byte)Data.VillagerId);
                break;
            }
        }