Beispiel #1
0
        private void RewindOne()
        {
            if (!Global.Emulator.HasSavestates())
            {
                return;
            }

            var ms = _rewindBuffer.PopMemoryStream();

            byte[] buf       = ms.GetBuffer();
            var    reader    = new BinaryReader(ms);
            var    fullstate = reader.ReadBoolean();

            if (fullstate)
            {
                if (_rewindDeltaEnable)
                {
                    UpdateLastState(buf, 1, buf.Length - 1);
                }

                Global.Emulator.AsStatable().LoadStateBinary(reader);
            }
            else
            {
                var output = new MemoryStream(_lastState);
                int index  = 1;
                int offset = 0;

                while (index < buf.Length)
                {
                    int offsetDelta = (int)VLInteger.ReadUnsigned(buf, ref index);
                    int length      = (int)VLInteger.ReadUnsigned(buf, ref index);

                    offset += offsetDelta;

                    output.Position = offset;
                    output.Write(buf, index, length);
                    index += length;
                }

                output.Position = 0;
                Global.Emulator.AsStatable().LoadStateBinary(new BinaryReader(output));
                output.Close();
            }
            reader.Close();
        }
Beispiel #2
0
        private void LoadPreviousState()
        {
            using (var reader = new BinaryReader(GetPreviousStateMemoryStream()))
            {
                byte[] buf       = ((MemoryStream)reader.BaseStream).GetBuffer();
                bool   fullState = reader.ReadByte() == 1;
                if (_rewindDeltaEnable)
                {
                    if (fullState)
                    {
                        UpdateLastState(buf, 1, buf.Length - 1);
                    }
                    else
                    {
                        int index  = 1;
                        int offset = 0;

                        while (index < buf.Length)
                        {
                            int offsetDelta = (int)VLInteger.ReadUnsigned(buf, ref index);
                            int length      = (int)VLInteger.ReadUnsigned(buf, ref index);

                            offset += offsetDelta;

                            Buffer.BlockCopy(buf, index, _lastState, offset, length);
                            index += length;
                        }
                    }

                    using (var lastStateReader = new BinaryReader(new MemoryStream(_lastState)))
                    {
                        Global.Emulator.AsStatable().LoadStateBinary(lastStateReader);
                    }
                }
                else
                {
                    if (!fullState)
                    {
                        throw new InvalidOperationException();
                    }

                    Global.Emulator.AsStatable().LoadStateBinary(reader);
                }
            }
        }
Beispiel #3
0
        private unsafe void CaptureStateDelta(byte[] currentState)
        {
            // Keep in mind that everything captured here is intended to be played back in
            // reverse. The goal is, given the current state, how to get back to the previous
            // state. That's why the data portion of the delta comes from the previous state,
            // and also why the previous state is used if we have to bail out and capture the
            // full state instead.
            if (currentState.Length != _lastState.Length)
            {
                // If the state sizes mismatch, capture a full state rather than trying to do anything clever
                goto CaptureFullState;
            }

            if (currentState.Length == 0)
            {
                // handle empty states as a "full" (empty) state
                goto CaptureFullState;
            }

            int  index                         = 0;
            int  stateLength                   = Math.Min(currentState.Length, _lastState.Length);
            bool inChangeSequence              = false;
            int  changeSequenceStartOffset     = 0;
            int  lastChangeSequenceStartOffset = 0;

            if (_deltaBuffer.Length < stateLength + 1)
            {
                _deltaBuffer = new byte[stateLength + 1];
            }

            _deltaBuffer[index++] = 0;             // Full state = false (i.e. delta)

            fixed(byte *pCurrentState = &currentState[0])
            fixed(byte *pLastState = &_lastState[0])
            for (int i = 0; i < stateLength; i++)
            {
                bool thisByteMatches = *(pCurrentState + i) == *(pLastState + i);

                if (inChangeSequence == false)
                {
                    if (thisByteMatches)
                    {
                        continue;
                    }

                    inChangeSequence          = true;
                    changeSequenceStartOffset = i;
                }

                if (thisByteMatches || i == stateLength - 1)
                {
                    const int MaxHeaderSize = 10;
                    int       length        = i - changeSequenceStartOffset + (thisByteMatches ? 0 : 1);

                    if (index + length + MaxHeaderSize >= stateLength)
                    {
                        // If the delta ends up being larger than the full state, capture the full state instead
                        goto CaptureFullState;
                    }

                    // Offset Delta
                    VLInteger.WriteUnsigned((uint)(changeSequenceStartOffset - lastChangeSequenceStartOffset), _deltaBuffer, ref index);

                    // Length
                    VLInteger.WriteUnsigned((uint)length, _deltaBuffer, ref index);

                    // Data
                    Buffer.BlockCopy(_lastState, changeSequenceStartOffset, _deltaBuffer, index, length);
                    index += length;

                    inChangeSequence = false;
                    lastChangeSequenceStartOffset = changeSequenceStartOffset;
                }
            }

            _rewindBuffer.Push(new ArraySegment <byte>(_deltaBuffer, 0, index));

            UpdateLastState(currentState);
            return;

CaptureFullState:
            CaptureStateNonDelta(_lastState);
            UpdateLastState(currentState);
        }
Beispiel #4
0
        private unsafe void CaptureRewindStateDelta(byte[] currentState)
        {
            // in case the state sizes mismatch, capture a full state rather than trying to do anything clever
            if (currentState.Length != _lastState.Length)
            {
                CaptureRewindStateNonDelta(_lastState);
                UpdateLastState(currentState);
                return;
            }

            int  index                         = 0;
            int  stateLength                   = Math.Min(currentState.Length, _lastState.Length);
            bool inChangeSequence              = false;
            int  changeSequenceStartOffset     = 0;
            int  lastChangeSequenceStartOffset = 0;

            if (_deltaBuffer.Length < stateLength)
            {
                _deltaBuffer = new byte[stateLength];
            }

            _deltaBuffer[index++] = 0;             // Full state = false (i.e. delta)

            fixed(byte *pCurrentState = &currentState[0])
            fixed(byte *pLastState = &_lastState[0])
            for (int i = 0; i < stateLength; i++)
            {
                bool thisByteMatches = *(pCurrentState + i) == *(pLastState + i);

                if (inChangeSequence == false)
                {
                    if (thisByteMatches)
                    {
                        continue;
                    }

                    inChangeSequence          = true;
                    changeSequenceStartOffset = i;
                }

                if (thisByteMatches || i == stateLength - 1)
                {
                    const int maxHeaderSize = 10;
                    int       length        = i - changeSequenceStartOffset + (thisByteMatches ? 0 : 1);

                    if (index + length + maxHeaderSize >= stateLength)
                    {
                        // If the delta ends up being larger than the full state, capture the full state instead
                        CaptureRewindStateNonDelta(_lastState);
                        UpdateLastState(currentState);
                        return;
                    }

                    // Offset Delta
                    VLInteger.WriteUnsigned((uint)(changeSequenceStartOffset - lastChangeSequenceStartOffset), _deltaBuffer, ref index);

                    // Length
                    VLInteger.WriteUnsigned((uint)length, _deltaBuffer, ref index);

                    // Data
                    Buffer.BlockCopy(_lastState, changeSequenceStartOffset, _deltaBuffer, index, length);
                    index += length;

                    inChangeSequence = false;
                    lastChangeSequenceStartOffset = changeSequenceStartOffset;
                }
            }

            _rewindBuffer.Push(new ArraySegment <byte>(_deltaBuffer, 0, index));

            UpdateLastState(currentState);
        }