public void Initialize(IStatable statableCore, RewindConfig rewindConfig) { Uninitialize(); _statableCore = statableCore; int stateSize = _statableCore.CloneSavestate().Length; if (stateSize >= rewindConfig.LargeStateSize) { RewindEnabled = rewindConfig.EnabledLarge; RewindFrequency = rewindConfig.FrequencyLarge; } else if (stateSize >= rewindConfig.MediumStateSize) { RewindEnabled = rewindConfig.EnabledMedium; RewindFrequency = rewindConfig.FrequencyMedium; } else { RewindEnabled = rewindConfig.EnabledSmall; RewindFrequency = rewindConfig.FrequencySmall; } _rewindDeltaEnable = rewindConfig.UseDelta; if (RewindActive) { var capacity = rewindConfig.BufferSize * 1024L * 1024L; _rewindBuffer = new StreamBlobDatabase(rewindConfig.OnDisk, capacity, BufferManage); _rewindThread = new RewindThreader(CaptureInternal, RewindInternal, rewindConfig.IsThreaded); } }
private int _stateSizeCategory = 1; // 1 = small, 2 = med, 3 = large // TODO: enum public RewindConfig(Rewinder rewinder, Config config, IStatable statableCore) { _rewinder = rewinder; _config = config; _statableCore = statableCore; InitializeComponent(); }
public void Attach(IEmulator emulator) { if (!_emulator.IsNull()) { throw new InvalidOperationException("A core has already been attached!"); } if (!emulator.HasSavestates()) { throw new InvalidOperationException($"A core must be able to provide an {nameof(IStatable)} service"); } _emulator = emulator; _core = emulator.AsStatable(); _decay = new StateManagerDecay(_movie, this); _expectedStateSizeInMb = _core.CloneSavestate().Length / (double)(1024 * 1024); if (_expectedStateSizeInMb.HawkFloatEquality(0)) { throw new InvalidOperationException("Savestate size can not be zero!"); } // don't erase states if they exist already (already loaded) if ((_states == null) || (_states.Capacity == 0)) { _states = new SortedList <int, byte[]>(MaxStates); } UpdateStateFrequency(); }
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); }
public void Attach(IEmulator emulator) { // TODO: we aren't ready for this, attach is called when converting a bk2 to tasproj and again to officially load the emulator //if (!_emulator.IsNull()) //{ // throw new InvalidOperationException("A core has already been attached!"); //} if (!emulator.HasSavestates()) { throw new InvalidOperationException($"A core must be able to provide an {nameof(IStatable)} service"); } _emulator = emulator; _core = emulator.AsStatable(); _decay = new StateManagerDecay(_movie, this); _expectedStateSizeInMb = _core.CloneSavestate().Length / (double)(1024 * 1024); if (_expectedStateSizeInMb.HawkFloatEquality(0)) { throw new InvalidOperationException("Savestate size can not be zero!"); } _states = new SortedList <int, byte[]>(MaxStates); UpdateStateFrequency(); }
public RewindConfig(Config config, Action recreateRewinder, Func <IRewinder> getRewinder, IStatable statableCore) { _config = config; _recreateRewinder = recreateRewinder; _getRewinder = getRewinder; _statableCore = statableCore; InitializeComponent(); btnResetCompression.Image = Properties.Resources.reboot; }
public static byte[] CloneSavestate(this IStatable core) { using var ms = new MemoryStream(); using var bw = new BinaryWriter(ms); core.SaveStateBinary(bw); bw.Flush(); var stateBuffer = ms.ToArray(); bw.Close(); return(stateBuffer); }
public static void SaveStateText(this IStatable core, TextWriter writer) { if (core is ITextStatable textCore) { textCore.SaveStateText(writer); } var temp = core.CloneSavestate(); temp.SaveAsHexFast(writer); }
internal void CaptureReserved(int frame, IStatable source) { if (_reserved.ContainsKey(frame)) { return; } var ms = new MemoryStream(); source.SaveStateBinary(new BinaryWriter(ms)); _reserved.Add(frame, ms.ToArray()); AddStateCache(frame); }
public SavestateFile(IEmulator emulator, IMovieSession movieSession, IDictionary <string, object> userBag) { if (!emulator.HasSavestates()) { throw new InvalidOperationException("The provided core must have savestates"); } _emulator = emulator; _statable = emulator.AsStatable(); if (emulator.HasVideoProvider()) { _videoProvider = emulator.AsVideoProvider(); } _movieSession = movieSession; _userBag = userBag; }
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; } }); }
public static void LoadStateText(this IStatable core, TextReader reader) { if (core is ITextStatable textCore) { textCore.LoadStateText(reader); } string hex = reader.ReadLine(); if (hex != null) { var state = new byte[hex.Length / 2]; state.ReadFromHexFast(hex); using var ms = new MemoryStream(state); using var br = new BinaryReader(ms); core.LoadStateBinary(br); } }
private ZwinderStateManager CreateSmallZwinder(IStatable ss) { var zw = new ZwinderStateManager(new ZwinderStateManagerSettings { CurrentBufferSize = 1, CurrentTargetFrameLength = 10000, RecentBufferSize = 1, RecentTargetFrameLength = 100000, AncientStateInterval = 50000 }, f => false); var ms = new MemoryStream(); ss.SaveStateBinary(new BinaryWriter(ms)); zw.Engage(ms.ToArray()); return(zw); }
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)); }
public Zwinder(IStatable stateSource, IRewindSettings settings) { _buffer = new ZwinderBuffer(settings); _stateSource = stateSource; Active = true; }
public void CaptureHighPriority(int frame, IStatable source) { _highPriority.Capture(frame, s => source.SaveStateBinary(new BinaryWriter(s))); }
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); }
public static void LoadStateBinary(this IStatable core, byte[] state) { using var ms = new MemoryStream(state, false); using var br = new BinaryReader(ms); core.LoadStateBinary(br); }
public static void LoadStateText(this IStatable core, string textState) { core.LoadStateText(new StringReader(textState)); }
/// <summary> /// /// </summary> /// <param name="stateble"></param> public StateController(IStatable statable) { this.Statable = statable; }
public float ChanceOfApply(IStatable target) { //more AGL RET STB you have, more chance to dodge this shit return ((float)(90 * Math.Pow(2.7, -(target.Aglity + target.Reticence + target.Stability)))); }