示例#1
0
        public void Capture(int frame, IStatable source, bool force = false)
        {
            if (frame <= Last)
            {
                CaptureHighPriority(frame, source);
            }

            _current.Capture(frame,
                             s => source.SaveStateBinary(new BinaryWriter(s)),
                             index =>
            {
                var state = _current.GetState(index);
                _recent.Capture(state.Frame,
                                s => state.GetReadStream().CopyTo(s),
                                index2 =>
                {
                    var state2 = _recent.GetState(index2);
                    var from   = _ancient.Count > 0 ? _ancient[_ancient.Count - 1].Key : 0;
                    if (state2.Frame - from >= _ancientInterval)
                    {
                        var ms = new MemoryStream();
                        state2.GetReadStream().CopyTo(ms);
                        _ancient.Add(new KeyValuePair <int, byte[]>(state2.Frame, ms.ToArray()));
                    }
                });
            },
                             force);
        }
示例#2
0
文件: Zwinder.cs 项目: gocha/BizHawk
 public void Capture(int frame)
 {
     if (!Active)
     {
         return;
     }
     _buffer.Capture(frame, s => _stateSource.SaveStateBinary(new BinaryWriter(s)));
 }
        private void CaptureGap(int frame, IStatable source)
        {
            // We need to do this here for the following scenario
            // We are currently far enough in the game that there is a large "ancient interval" section
            // The user navigates to a frame after ancient interval 2, replay happens and we start filling gaps
            // Then the user, still without having made an edit, navigates to a frame before ancient interval 2, but after ancient interval 1
            // Without this logic, we end up with out of order states
            // We cannot use InvalidateGaps because that does not address the state cache or check for reserved states.
            for (int i = _gapFiller.Count - 1; i >= 0; i--)
            {
                var lastGap = _gapFiller.GetState(i);
                if (lastGap.Frame < frame)
                {
                    break;
                }

                if (_reserveCallback(lastGap.Frame))
                {
                    AddToReserved(lastGap);
                }
                else
                {
                    StateCache.Remove(lastGap.Frame);
                }

                _gapFiller.InvalidateEnd(i);
            }

            _gapFiller.Capture(
                frame, s =>
            {
                AddStateCache(frame);
                source.SaveStateBinary(new BinaryWriter(s));
            },
                index =>
            {
                var state = _gapFiller.GetState(index);
                StateCache.Remove(state.Frame);

                if (_reserveCallback(state.Frame))
                {
                    AddToReserved(state);
                    return;
                }
            });
        }
示例#4
0
        private void CaptureGap(int frame, IStatable source)
        {
            // We need to do this here for the following scenario
            // We are currently far enough in the game that there is a large "ancient interval" section
            // The user navigates to a frame after ancient interval 2, replay happens and we start filling gaps
            // Then the user, still without having made an edit, navigates to a frame before ancient interval 2, but after ancient interval 1
            // Without this logic, we end up with out of order states
            if (_gapFiller.Count > 0 && frame < GapStates().First().Frame)
            {
                InvalidateGaps(frame);
            }

            _gapFiller.Capture(
                frame, s =>
            {
                StateCache.Add(frame);
                source.SaveStateBinary(new BinaryWriter(s));
            },
                index => StateCache.Remove(index));
        }
 private ZwinderBuffer UpdateBuffer(ZwinderBuffer buffer, RewindConfig newConfig, bool keepOldStates)
 {
     if (buffer == null)             // just make a new one, plain and simple
     {
         buffer = new ZwinderBuffer(newConfig);
     }
     else if (!buffer.MatchesSettings(newConfig))             // no need to do anything if these settings are already in use
     {
         if (keepOldStates)
         {
             // force capture all the old states, let the buffer handle decay if they don't all fit
             ZwinderBuffer old = buffer;
             buffer = new ZwinderBuffer(newConfig);
             for (int i = 0; i < old.Count; i++)
             {
                 ZwinderBuffer.StateInformation si = old.GetState(i);
                 // don't allow states that should be reserved to decay here, where we don't attempt re-capture
                 if (_reserveCallback(si.Frame))
                 {
                     AddToReserved(si);
                 }
                 else
                 {
                     buffer.Capture(si.Frame, s => si.GetReadStream().CopyTo(s), null, true);
                 }
             }
             old.Dispose();
         }
         else
         {
             buffer.Dispose();
             buffer = new ZwinderBuffer(newConfig);
         }
     }
     return(buffer);
 }
示例#6
0
        public unsafe void Capture(int frame)
        {
            Sync();
            if (!_active)
            {
                return;
            }
            if (_masterFrame == -1)
            {
                var sss = new SaveStateStream(this);
                _stateSource.SaveStateBinary(new BinaryWriter(sss));
                (_master, _scratch) = (_scratch, _master);
                _masterLength       = (int)sss.Position;
                _masterFrame        = frame;
                _count++;
                return;
            }
            if (!_buffer.WillCapture(_masterFrame))
            {
                return;
            }

            {
                var sss = new SaveStateStream(this);
                _stateSource.SaveStateBinary(new BinaryWriter(sss));

                Work(() =>
                {
                    _buffer.Capture(_masterFrame, underlyingStream_ =>
                    {
                        var zeldas = SpanStream.GetOrBuild(underlyingStream_);
                        if (_master.Length < _scratch.Length)
                        {
                            var replacement = new byte[_scratch.Length];
                            Array.Copy(_master, replacement, _master.Length);
                            _master = replacement;
                        }

                        var lengthHolder     = _masterLength;
                        var lengthHolderSpan = new ReadOnlySpan <byte>(&lengthHolder, 4);

                        zeldas.Write(lengthHolderSpan);

                        fixed(byte *older_ = _master)
                        fixed(byte *newer_ = _scratch)
                        {
                            int *older       = (int *)older_;
                            int *newer       = (int *)newer_;
                            int lastIndex    = (Math.Min(_masterLength, (int)sss.Position) + 3) / 4;
                            int lastOldIndex = (_masterLength + 3) / 4;
                            int *olderEnd    = older + lastIndex;

                            int *from = older;
                            int *to   = older;

                            while (older < olderEnd)
                            {
                                if (*older++ == *newer++)
                                {
                                    if (to < from)
                                    {
                                        // Save on [to, from]
                                        lengthHolder = (int)(from - to);
                                        zeldas.Write(lengthHolderSpan);
                                        zeldas.Write(new ReadOnlySpan <byte>(to, lengthHolder * 4));
                                    }
                                    to = older;
                                }
                                else
                                {
                                    if (from < to)
                                    {
                                        // encode gap [from, to]
                                        lengthHolder = (int)(to - from) | IS_GAP;
                                        zeldas.Write(lengthHolderSpan);
                                    }
                                    from = older;
                                }
                            }
                            if (from < to)
                            {
                                // encode gap [from, to]
                                lengthHolder = (int)(to - from) | IS_GAP;
                                zeldas.Write(lengthHolderSpan);
                            }
                            if (lastOldIndex > lastIndex)
                            {
                                from += lastOldIndex - lastIndex;
                            }
                            if (to < from)
                            {
                                // Save on [to, from]
                                lengthHolder = (int)(from - to);
                                zeldas.Write(lengthHolderSpan);
                                zeldas.Write(new ReadOnlySpan <byte>(to, lengthHolder * 4));
                            }
                        }

                        (_master, _scratch) = (_scratch, _master);
                        _masterLength       = (int)sss.Position;
                        _masterFrame        = frame;
                        _count++;
                    });
                });
            }
        }
        public void Capture(int frame, IStatable source, bool force = false)
        {
            // We already have this state, no need to capture
            if (StateCache.Contains(frame))
            {
                return;
            }

            if (_reserveCallback(frame))
            {
                CaptureReserved(frame, source);
                return;
            }

            // We do not want to consider reserved states for a notion of Last
            // reserved states can include future states in the case of branch states
            if ((frame <= LastRing && NeedsGap(frame)) || force)
            {
                // We use the gap buffer for forced capture to avoid crowding the "current" buffer and thus reducing it's actual span of covered frames.
                CaptureGap(frame, source);
                return;
            }

            _current.Capture(frame,
                             s =>
            {
                source.SaveStateBinary(new BinaryWriter(s));
                AddStateCache(frame);
            },
                             index =>
            {
                var state = _current.GetState(index);
                StateCache.Remove(state.Frame);

                // If this is a reserved state, go ahead and reserve instead of potentially trying to force it into recent, for further eviction logic later
                if (_reserveCallback(state.Frame))
                {
                    AddToReserved(state);
                    return;
                }

                _recent.Capture(state.Frame,
                                s =>
                {
                    state.GetReadStream().CopyTo(s);
                    AddStateCache(state.Frame);
                },
                                index2 =>
                {
                    var state2 = _recent.GetState(index2);
                    StateCache.Remove(state2.Frame);

                    var isReserved = _reserveCallback(state2.Frame);

                    // Add to reserved if reserved, or if it matches an "ancient" state consideration
                    if (isReserved || !HasNearByReserved(state2.Frame))
                    {
                        AddToReserved(state2);
                    }
                });
            },
                             force);
        }
示例#8
0
 public void CaptureHighPriority(int frame, IStatable source)
 {
     _highPriority.Capture(frame, s => source.SaveStateBinary(new BinaryWriter(s)));
 }