예제 #1
0
        /// <summary>
        /// Rewind from the current event in the timeline to the most recent bookmark, and begin a new timeline branch from there.
        /// </summary>
        public void JumpToMostRecentBookmark()
        {
            HistoryEvent lastBookmarkEvent = _history.CurrentEvent;

            while (lastBookmarkEvent != null)
            {
                if (lastBookmarkEvent is BookmarkHistoryEvent b && !b.Bookmark.System && b.Ticks != Core.Ticks)
                {
                    TimeSpan before = Helpers.GetTimeSpanFromTicks(Core.Ticks);
                    JumpToBookmark(lastBookmarkEvent);
                    TimeSpan after = Helpers.GetTimeSpanFromTicks(Core.Ticks);
                    Status = String.Format("Rewound to {0} (-{1})", after.ToString(@"hh\:mm\:ss"), (after - before).ToString(@"hh\:mm\:ss"));
                    return;
                }

                lastBookmarkEvent = lastBookmarkEvent.Parent;
            }

            // No bookmarks? Go all the way back to the root!
            JumpToBookmark(_history.RootEvent);
            Status = "Rewound to start";
        }
예제 #2
0
        private void SeekToBookmark(int bookmarkEventIndex)
        {
            Core core;

            int startIndex = 0;

            // First find the bookmark.
            if (bookmarkEventIndex == -1)
            {
                core = Core.Create(Core.LatestVersion, Core.Type.CPC6128);
                Display.GetFromBookmark(null);
            }
            else
            {
                Bookmark bookmark = (_historyEvents[bookmarkEventIndex] as BookmarkHistoryEvent).Bookmark;
                core = Core.Create(bookmark.Version, bookmark.State.GetBytes());
                Display.GetFromBookmark(bookmark);
                startIndex = bookmarkEventIndex;
            }

            for (int i = startIndex; i < _historyEvents.Count; i++)
            {
                HistoryEvent historyEvent = _historyEvents[i];
                if (historyEvent is CoreActionHistoryEvent coreActionHistoryEvent)
                {
                    core.PushRequest(CoreRequest.RunUntil(coreActionHistoryEvent.Ticks));
                    core.PushRequest(coreActionHistoryEvent.CoreAction);
                }
            }

            core.PushRequest(CoreRequest.RunUntil(_endTicks));

            Core              = core;
            Core.Auditors     = RequestProcessed;
            Core.IdleRequest += IdleRequest;

            SetCoreRunning();
        }
예제 #3
0
        private void SelectBookmark(IJumpableMachine jumpableMachine)
        {
            if (jumpableMachine == null)
            {
                return;
            }

            using ((jumpableMachine as IPausableMachine)?.AutoPause())
            {
                PromptForBookmarkEventArgs args = new PromptForBookmarkEventArgs();
                PromptForBookmark?.Invoke(this, args);

                HistoryEvent historyEvent = args.SelectedBookmark;
                if (historyEvent != null)
                {
                    jumpableMachine.JumpToBookmark(historyEvent);
                    if (jumpableMachine is IMachine machine)
                    {
                        machine.Status = String.Format("Jumped to {0}", Helpers.GetTimeSpanFromTicks(historyEvent.Ticks).ToString(@"hh\:mm\:ss"));
                    }
                }
            }
        }
예제 #4
0
 public bool IsEqualToOrAncestorOf(HistoryEvent ancestor)
 {
     return(Node.IsEqualToOrAncestorOf(ancestor?.Node));
 }
예제 #5
0
 public bool DeleteBookmark(HistoryEvent e)
 {
     return(_history.DeleteBookmark(e));
 }
예제 #6
0
        /// <summary>
        /// Delegate for logging core actions.
        /// </summary>
        /// <param name="core">The core the request was made for.</param>
        /// <param name="request">The original request.</param>
        /// <param name="action">The action taken.</param>
        private void RequestProcessed(Core core, CoreRequest request, CoreAction action)
        {
            if (core == _core)
            {
                if (action != null)
                {
                    Auditors?.Invoke(action);

                    if (action.Type != CoreAction.Types.CreateSnapshot &&
                        action.Type != CoreAction.Types.DeleteSnapshot &&
                        action.Type != CoreAction.Types.RevertToSnapshot)
                    {
                        HistoryEvent e = _history.AddCoreAction(action);

                        switch (action.Type)
                        {
                        case CoreRequest.Types.LoadDisc:
                            Status = (action.MediaBuffer.GetBytes() != null) ? "Loaded disc" : "Ejected disc";
                            break;

                        case CoreRequest.Types.LoadTape:
                            Status = (action.MediaBuffer.GetBytes() != null) ? "Loaded tape" : "Ejected tape";
                            break;

                        case CoreRequest.Types.Reset:
                            Status = "Reset";
                            break;
                        }
                    }

                    if (action.Type == CoreAction.Types.RunUntil)
                    {
                        lock (_snapshots)
                        {
                            SnapshotInfo newSnapshot = _snapshots.LastOrDefault();
                            if (newSnapshot != null && action.AudioSamples != null)
                            {
                                newSnapshot.AudioBuffer.Write(action.AudioSamples);
                            }
                        }
                    }
                    else if (action.Type == CoreAction.Types.RevertToSnapshot)
                    {
                        HistoryEvent historyEvent = ((SnapshotInfo)request.UserData).HistoryEvent;
                        if (_history.CurrentEvent != historyEvent)
                        {
                            _history.CurrentEvent = historyEvent;
                        }

                        Display.CopyScreenAsync();
                    }
                    else if (action.Type == CoreAction.Types.CreateSnapshot)
                    {
                        lock (_snapshots)
                        {
                            // Figure out what history event should be set as current if we revert to this snapshot.
                            // If the current event is a RunUntil, it may not be "finalized" yet (i.e. it may still
                            // be updated), so go with its parent.
                            HistoryEvent historyEvent = _history.MostRecentClosedEvent(_history.CurrentEvent);

                            SnapshotInfo newSnapshot = new SnapshotInfo(action.SnapshotId, historyEvent);
                            _snapshots.Add(newSnapshot);

                            while (_snapshots.Count > _snapshotLimit)
                            {
                                SnapshotInfo snapshot = _snapshots[0];
                                _snapshots.RemoveAt(0);
                                _core.PushRequest(CoreRequest.DeleteSnapshot(snapshot.Id));
                            }
                        }
                    }
                }
            }
        }
예제 #7
0
 public SnapshotInfo(int id, HistoryEvent historyEvent)
 {
     Id           = id;
     AudioBuffer  = new AudioBuffer(-1);
     HistoryEvent = historyEvent;
 }
예제 #8
0
 private void Notify(HistoryEvent historyEvent, HistoryChangedAction action)
 {
     Auditors?.Invoke(historyEvent, action);
 }
예제 #9
0
        public void WriteHistory(string name)
        {
            List <string> lines = new List <string>
            {
                NameCommand(name)
            };

            // As the history tree could be very deep, keep a "stack" of history events in order to avoid recursive calls.
            List <HistoryEvent> historyEvents = new List <HistoryEvent>();

            historyEvents.AddRange(History.RootEvent.Children);

            HistoryEvent previousEvent = null;

            while (historyEvents.Count > 0)
            {
                HistoryEvent currentEvent = historyEvents[0];

                if (previousEvent != currentEvent.Parent && previousEvent != null)
                {
                    lines.Add(CurrentCommand(currentEvent.Parent.Id));
                }

                GetLines(currentEvent, lines);

                historyEvents.RemoveAt(0);
                previousEvent = currentEvent;

                // Place the current event's children at the top of the "stack". This effectively means we're doing a depth-first traversion of the history tree.
                historyEvents.InsertRange(0, currentEvent.Children);
            }

            lines.Add(CurrentCommand(History.CurrentEvent.Id));

            // If we have any "arg" commands, stick them in a "args" command and put them at the start of the file.
            // Putting them in a single command should allow them to be better compressed than individually.
            Dictionary <int, string> args = new Dictionary <int, string>();
            int i = 0;

            while (i < lines.Count)
            {
                string[] tokens = lines[i].Split(':');
                if (tokens[0] == _idArg)
                {
                    lines.RemoveAt(i);

                    MachineFileReader.ReadArgCommand(tokens[1], args);
                }
                else
                {
                    i++;
                }
            }

            // Write the file.
            if (args.Count > 0)
            {
                lines.Insert(0, ArgsCommand(args, true));
            }

            foreach (string line in lines)
            {
                _textFile.WriteLine(line);
            }
        }
예제 #10
0
 private int EventAncestorIndex(HistoryEvent historyEvent)
 {
     return(Events.FindIndex(descendant => historyEvent?.IsEqualToOrAncestorOf(descendant) ?? false));
 }
예제 #11
0
 private int EventIndex(HistoryEvent historyEvent)
 {
     return(Events.IndexOf(historyEvent));
 }