예제 #1
0
        public Signature(Span <byte> bytes)
        {
            if (bytes.Length != 65)
            {
                throw new ArgumentException();
            }

            bytes.Slice(0, 64).CopyTo(Bytes.AsSpan());
            V = bytes[64];
        }
예제 #2
0
        public Signature(ReadOnlySpan <byte> bytes, int recoveryId)
        {
            if (bytes.Length != 64)
            {
                throw new ArgumentException();
            }

            bytes.CopyTo(Bytes.AsSpan());
            V = (ulong)recoveryId + VOffset;
        }
예제 #3
0
            private void WriteBytes(MemoryHolder address, int offset, Bytes bytes)
            {
                SimpleType st = (SimpleType)_type;

                Debug.Assert(st._type == SimpleTypeKind.Char && bytes.Count <= _length);
                address.WriteSpan(offset, bytes.AsSpan());
                if (bytes.Count < _length)
                {
                    address.WriteByte(checked (offset + bytes.Count), 0);
                }
            }
예제 #4
0
        public Signature(ReadOnlySpan <byte> r, ReadOnlySpan <byte> s, ulong v)
        {
            if (v < VOffset)
            {
                throw new ArgumentException(nameof(v));
            }

            r.CopyTo(Bytes.AsSpan().Slice(32 - r.Length, r.Length));
            s.CopyTo(Bytes.AsSpan().Slice(64 - s.Length, s.Length));
            V = v;
        }
예제 #5
0
        public Signature(Span <byte> r, Span <byte> s, int v)
        {
            if (v < 27)
            {
                throw new ArgumentException(nameof(v));
            }

            r.CopyTo(Bytes.AsSpan().Slice(32 - r.Length, r.Length));
            s.CopyTo(Bytes.AsSpan().Slice(64 - s.Length, s.Length));
            V = v;
        }
예제 #6
0
        public Signature(UInt256 r, UInt256 s, ulong v)
        {
            if (v < VOffset)
            {
                throw new ArgumentException(nameof(v));
            }

            r.ToBigEndian(Bytes.AsSpan().Slice(0, 32));
            s.ToBigEndian(Bytes.AsSpan().Slice(32, 32));

            V = v;
        }
예제 #7
0
        public GameSave(string fileName)
        {
            Bytes      = File.ReadAllBytes(FileName = fileName);
            IsRemaster = BitConverter.ToInt32(Bytes, 8) == 0;
            if (IsRemaster && !Path.GetFileNameWithoutExtension(fileName).StartsWith("svd_fmt_5_"))
            {
                throw new NotSupportedException("Save file is not a user save and changing them can lead to the game infinite looping. The editor only supports saves that start with svd_fmt_5.");
            }
            _header      = new GameSaveHeader(this);
            Body         = Bytes.AsSpan(BodyStart, BodyDataLength).ToArray();
            IsCompressed = Encoding.Default.GetString(Body, 0, 4) == "zlib";
            if (IsCompressed)
            {
                throw new NotSupportedException("Save file uses compression.");
            }
            _originalBodyLength = Body.Length;
            Stash = Stash.TryCreateStash(this);
            ReadOnlySpan <byte> data = Body;

            _bagOffset         = GetBagOffset(data);
            _dataLengthOffsets = new[] {
                data.IndexOf(new byte[5] {
                    0x0C, 0xAE, 0x32, 0x00, 0x00
                }) + 5,                                                         // unknown length 1
                data.IndexOf(new byte[5] {
                    0xF7, 0x5D, 0x3C, 0x00, 0x0A
                }) + 5,                                                         // unknown length 2
                data.IndexOf(new byte[5] {
                    0x23, 0xCC, 0x58, 0x00, 0x03
                }) + 5,                                                         // type section length
            };
            _itemContainer = new Container(this, data.IndexOf(new byte[5] {
                0xD3, 0x34, 0x43, 0x00, 0x00
            }), 0x00_24_D5_68_00_00_00_0Bul);
            _itemBuffsContainer = new Container(this, data.IndexOf(new byte[5] {
                0xBB, 0xD5, 0x43, 0x00, 0x00
            }), 0x00_28_60_84_00_00_00_0Bul);
            _itemSocketsContainer = new Container(this, data.IndexOf(new byte[5] {
                0x93, 0xCC, 0x80, 0x00, 0x00
            }), 0x00_59_36_38_00_00_00_0Bul);
            var itemLocs = _itemContainer.ToDictionary(x => x.id, x => (x.offset, x.dataLength));
            var itemBuffsLocs = _itemBuffsContainer.ToDictionary(x => x.id, x => (x.offset, x.dataLength));
            var itemSocketsLocs = _itemSocketsContainer.ToDictionary(x => x.id, x => (x.offset, x.dataLength));
            int dataLength, playerActor = 0;
            var candidates = new List <(int id, int typeIdOffset, QuestItemDefinition?questItemDef)>();

            for (int ixOfActor = _dataLengthOffsets[^ 1] + 4; BitConverter.ToInt32(Body, ixOfActor) == 0x00_75_2D_06; ixOfActor += dataLength)
예제 #8
0
        public void GetRange()
        {
            var key = "TestGetRange_null";

            cli.Set(key, Null);
            Assert.Equal("", cli.GetRange(key, 10, 20));

            key = "TestGetRange_string";
            cli.Set(key, "abcdefg");
            Assert.Equal("cde", cli.GetRange(key, 2, 4));
            Assert.Equal("abcdefg", cli.GetRange(key, 0, -1));

            key = "TestGetRange_bytes";
            cli.Set(key, Bytes);
            Assert.Equal(Bytes.AsSpan(2, 3).ToArray(), cli.GetRange <byte[]>(key, 2, 4));
            Assert.Equal(Bytes, cli.GetRange <byte[]>(key, 0, -1));
        }
예제 #9
0
    public Item(GameSave gameSave, int typeIdOffset, int offset, int dataLength, int itemBuffsOffset, int itemBuffsLength, int itemGemsOffset, int itemGemsLength)
    {
        (_gameSave, TypeIdOffset, ItemOffset) = (gameSave, typeIdOffset, offset);
        _levelShiftOffset = (byte)(8 * gameSave.Body[TypeIdOffset + 10]);
        Bytes             = _gameSave.Body.AsSpan(offset, dataLength).ToArray();
        ItemSockets       = new(gameSave, itemGemsOffset, itemGemsLength);
        ItemBuffs         = new(gameSave, this, itemBuffsOffset, itemBuffsLength);
        var span = Bytes.AsSpan(Offsets.BuffCount);

        foreach (var(buffId, _) in BuffDuration.ReadList(ref span))
        {
            PlayerBuffs.Add(Amalur.GetBuff(buffId));
        }
        if (HasCustomName)
        {
            ItemName = _gameSave.Encoding.GetString(Bytes, Offsets.Name, NameLength);
        }
    }
예제 #10
0
    public StashItem(GameSave gameSave, int offset, int dataLength, Gem[] gems)
    {
        ItemOffset = offset;
        Bytes      = gameSave.Body.AsSpan(offset, dataLength).ToArray();
        var span = Bytes.AsSpan(Offsets.BuffCount);

        foreach (var(buffId, _) in BuffDuration.ReadList(ref span))
        {
            PlayerBuffs.Add(Amalur.GetBuff(buffId));
        }
        if (HasCustomName)
        {
            ItemName = gameSave.Encoding.GetString(Bytes, Offsets.Name, NameLength);
        }
        Gems = gems;
        // socket section is either FF
        // or 20 02, followed by int32 count, and int32 handle per gem.
        int socketsStart = gems.Length == 0
            ? Bytes.Length - 1
            : gems[0].ItemOffset - offset - (4 * (1 + gems.Length)) - 2;

        ItemBuffs = Bytes[Offsets.HasItemBuffs] == 0x14 ? new ItemBuffMemory(this, socketsStart) : Definition.ItemBuffs;
    }
예제 #11
0
    public GameSave(string fileName)
    {
        Bytes      = File.ReadAllBytes(FileName = fileName);
        IsRemaster = BitConverter.ToInt32(Bytes, 8) == 0;
        SaveType   = IsRemaster switch
        {
            true when Path.GetExtension(fileName) is "" => SaveType.Switch,
            true => SaveType.Remaster,
            false => SaveType.Original,
        };
        var pattern = SaveType == SaveType.Switch ? SwitchFilePattern : RemasterFilePattern;

        if (IsRemaster && Path.GetExtension(fileName) != ".bin" && !Path.GetFileNameWithoutExtension(fileName).StartsWith(pattern))
        {
            throw new NotSupportedException($"Save file is not a user save and changing them can lead to the game infinite looping. The editor only supports saves that start with {pattern}.");
        }
        _header         = new(this);
        Buffs           = FilterToApplicable(Amalur.Buffs.Values, _header.IsFateswornAware);
        ItemDefinitions = FilterToApplicable(Amalur.ItemDefinitions.Values, _header.IsFateswornAware);

        if (BitConverter.ToInt32(Bytes, BodyStart) == CompressedFlag)
        {
            Body = new byte[BitConverter.ToInt32(Bytes, BodyStart + 4)];
            if (Body.Length != _header.BodyDataLength)
            {
                throw new NotSupportedException($"Save file appears corrupted. The header states that the body should have {_header.BodyDataLength} bytes, but the decompressed size is {Body.Length}");
            }
            var bundleInfoStart = BodyStart + 12;
            var bundleInfoSize  = BitConverter.ToInt32(Bytes, bundleInfoStart - 4);
            using var bundleInfoData = new ZLibStream(new MemoryStream(Bytes, bundleInfoStart, bundleInfoSize), CompressionMode.Decompress);
            var endOfBundle    = bundleInfoData.ReadAll(Body);
            var gameStateStart = bundleInfoStart + bundleInfoSize + 4;
            var gameStateSize  = BitConverter.ToInt32(Bytes, gameStateStart - 4);
            using var gameStateData = new ZLibStream(new MemoryStream(Bytes, gameStateStart, gameStateSize), CompressionMode.Decompress);
            gameStateData.ReadAll(Body.AsSpan(endOfBundle, Body.Length - endOfBundle));
        }
        else
        {
            Body = Bytes.AsSpan(BodyStart, BodyDataLength).ToArray();
        }
        _originalBodyLength = Body.Length;
        Stash = Stash.TryCreateStash(this);
        ReadOnlySpan <byte> data = Body;

        _bagOffset            = GetBagOffset(data);
        _gameStateStartOffset = data.IndexOf(new byte[5] {
            0xF7, 0x5D, 0x3C, 0x00, 0x0A
        });
        var typeSectionOffset =
            data.IndexOf(new byte[5] {
            0x23, 0xCC, 0x58, 0x00, 0x06
        }) is int ix and > -1
            ? ix
            : data.IndexOf(new byte[5] {
            0x23, 0xCC, 0x58, 0x00, 0x04
        }) is int pix and > -1
                ? pix
                : data.IndexOf(new byte[5] {
            0x23, 0xCC, 0x58, 0x00, 0x03
        });

        _dataLengthOffsets = new[] {
            _gameStateStartOffset + 5,     // gameStateSize
            data.IndexOf(new byte[5] {
                0x0C, 0xAE, 0x32, 0x00, 0x00
            }) + 5,                    // unknown length 1
            typeSectionOffset + 5,     // type section length
        };
        _itemContainer        = new(this, data.IndexOf(new byte[5] {
            0xD3, 0x34, 0x43, 0x00, 0x00
        }), 0x00_24_D5_68_00_00_00_0Bul);
        _itemBuffsContainer   = new(this, data.IndexOf(new byte[5] {
            0xBB, 0xD5, 0x43, 0x00, 0x00
        }), 0x00_28_60_84_00_00_00_0Bul);
        _itemSocketsContainer = new(this, data.IndexOf(new byte[5] {
            0x93, 0xCC, 0x80, 0x00, 0x00
        }), 0x00_59_36_38_00_00_00_0Bul);
        var itemLocs = _itemContainer.ToDictionary(x => x.id, x => (x.offset, x.dataLength));
        var itemBuffsLocs = _itemBuffsContainer.ToDictionary(x => x.id, x => (x.offset, x.dataLength));
        var itemSocketsLocs = _itemSocketsContainer.ToDictionary(x => x.id, x => (x.offset, x.dataLength));
        int dataLength, playerActor = 0;
        var candidates = new List <(int id, int typeIdOffset, QuestItemDefinition?questItemDef)>();

        for (int ixOfActor = _dataLengthOffsets[^ 1] + 4; BitConverter.ToInt32(Body, ixOfActor) == 0x00_75_2D_06; ixOfActor += dataLength)