public CoreActionHistoryEvent AddCoreAction(CoreAction coreAction, int id) { // Instead of continually adding "RunUntil" actions, just keep updating the // current one if it's a RunUntil, and only notify once we've finished. That // happens either when we add a non-RunUntil node after a RunUntil node, or // when we change the current node and the current node is a RunUntil. See // SetCurrentNode for that case. bool notify = coreAction.Type != CoreRequest.Types.RunUntil; if (!notify) { if (_currentNode is CoreActionHistoryNode currentCoreActionNode && currentCoreActionNode.Children.Count == 0 && currentCoreActionNode.CoreAction.Type == CoreRequest.Types.RunUntil) { currentCoreActionNode.CoreAction.StopTicks = coreAction.StopTicks; return(currentCoreActionNode.HistoryEvent as CoreActionHistoryEvent); } } CoreActionHistoryNode historyNode = new CoreActionHistoryNode(id, coreAction.Ticks, coreAction, _currentNode, DateTime.Now); _nextId = Math.Max(_nextId, id) + 1; AddChildNode(historyNode, notify); return(historyNode.HistoryEvent as CoreActionHistoryEvent); }
private void ReceiveSelectMachine(string machineName) { IMachine machine = _machines.Where(m => m.Name == machineName).FirstOrDefault(); if (machine == _machine) { return; } if (_machine != null) { // Quit sending to the client. _machine.Auditors -= MachineAuditor; _machine = null; } _machine = machine; if (_machine != null) { using ((machine as IPausableMachine)?.AutoPause()) { byte[] state = _machine.Core.GetState(); CoreAction loadCoreAction = CoreAction.LoadCore(0, new MemoryBlob(state)); _remote.SendName(_machine.Name); _remote.SendCoreAction(loadCoreAction); _machine.Auditors += MachineAuditor; } } }
private void SetCurrentEvent(HistoryEvent historyEvent) { if (historyEvent is BookmarkHistoryEvent bookmarkHistoryEvent) { Core core = Core.Create(Core.LatestVersion, bookmarkHistoryEvent.Bookmark.State.GetBytes()); SetCore(core); Display.GetFromBookmark(bookmarkHistoryEvent.Bookmark); Auditors?.Invoke(CoreAction.LoadCore(historyEvent.Ticks, bookmarkHistoryEvent.Bookmark.State)); } else if (historyEvent is RootHistoryEvent rootHistoryEvent) { Core core = Core.Create(Core.LatestVersion, Core.Type.CPC6128); SetCore(core); Display.GetFromBookmark(null); Auditors?.Invoke(CoreAction.Reset(rootHistoryEvent.Ticks)); } else { throw new Exception("Can't set current event to an event that isn't the root or doesn't have a bookmark."); } _history.CurrentEvent = historyEvent; }
private CoreAction RunForAWhile(UInt64 stopTicks) { UInt64 ticks = Ticks; // Only proceed on an audio buffer underrun. if (!_audioBuffer.WaitForUnderrun(20)) { return(null); } // Limit how long we can run for to reduce audio lag. stopTicks = Math.Min(stopTicks, Ticks + 1000); List <UInt16> audioSamples = new List <UInt16>(); byte stopReason = RunUntil(stopTicks, StopReasons.VSync, audioSamples); foreach (UInt16 sample in audioSamples) { _audioBuffer.Write(sample); } if ((stopReason & StopReasons.VSync) != 0) { OnPropertyChanged("Ticks"); BeginVSync?.Invoke(this); } return(CoreAction.RunUntil(ticks, Ticks, audioSamples)); }
protected HistoryNode(int id, UInt64 ticks, CoreAction action, Bookmark bookmark, HistoryNode parent, DateTime createDate) { Id = id; Ticks = ticks; Parent = parent; CreateDate = createDate; Children = new List <HistoryNode>(); }
private void OnNewMessage(byte[] msg) { MemoryByteStream bs = new MemoryByteStream(msg); byte id = bs.ReadByte(); switch (id) { case _idSelectMachine: { string machineName = Serializer.SelectMachineFromBytes(bs); ReceiveSelectMachine?.Invoke(machineName); } break; case _idAvailableMachines: { List <string> machines = Serializer.AvailableMachinesFromBytes(bs); ReceiveAvailableMachines?.Invoke(machines); } break; case _idCoreAction: { CoreAction coreAction = Serializer.CoreActionFromBytes(bs); ReceiveCoreAction?.Invoke(coreAction); } break; case _idPing: { bool response = bs.ReadBool(); UInt64 pid = bs.ReadUInt64(); ReceivePing?.Invoke(response, pid); } break; case _idRequestAvailableMachines: { ReceiveRequestAvailableMachines?.Invoke(); } break; case _idName: { string machineName = bs.ReadString(); ReceiveName?.Invoke(machineName); } break; case _idCoreRequest: { CoreRequest coreRequest = Serializer.CoreRequestFromBytes(bs); ReceiveCoreRequest?.Invoke(coreRequest); } break; } }
static public CoreAction LoadTape(UInt64 ticks, IBlob tape) { CoreAction action = new CoreAction(Types.LoadTape, ticks) { MediaBuffer = tape }; return(action); }
static public CoreAction CoreVersion(UInt64 ticks, int version) { CoreAction action = new CoreAction(Types.CoreVersion, ticks) { Version = version }; return(action); }
public void SendCoreAction(CoreAction coreAction) { MemoryByteStream bs = new MemoryByteStream(); bs.Write(_idCoreAction); Serializer.CoreActionToBytes(bs, coreAction); SendMessage(bs.AsBytes()); }
static public CoreAction CreateSnapshot(UInt64 ticks, int id) { CoreAction action = new CoreAction(Types.CreateSnapshot, ticks) { SnapshotId = id }; return(action); }
static public CoreAction LoadCore(UInt64 ticks, IBlob state) { CoreAction action = new CoreAction(Types.LoadCore, ticks) { CoreState = state }; return(action); }
static public CoreAction LoadDisc(UInt64 ticks, byte drive, IBlob disc) { CoreAction action = new CoreAction(Types.LoadDisc, ticks) { Drive = drive, MediaBuffer = disc }; return(action); }
static public CoreAction RunUntil(UInt64 ticks, UInt64 stopTicks, List <UInt16> audioSamples) { CoreAction action = new CoreAction(Types.RunUntil, ticks) { StopTicks = stopTicks, AudioSamples = audioSamples }; return(action); }
static public CoreAction KeyPress(UInt64 ticks, byte keycode, bool down) { CoreAction action = new CoreAction(Types.KeyPress, ticks) { KeyCode = keycode, KeyDown = down }; return(action); }
private void ReadReset(string line) { string[] tokens = line.Split(','); int id = Convert.ToInt32(tokens[0]); UInt64 ticks = Convert.ToUInt64(tokens[1]); CoreAction action = CoreAction.Reset(ticks); AddCoreAction(id, action); }
private CoreAction DeleteSnapshot(int id) { bool result = _coreCLR.DeleteSnapshot(id); if (!result) { return(null); } return(CoreAction.DeleteSnapshot(Ticks, id)); }
private void RequestProcessed(Core core, CoreRequest request, CoreAction action) { if (core == _core && action != null) { if (action.Type == CoreAction.Types.RevertToSnapshot) { // Ensure to update the display. Display.CopyScreenAsync(); } } }
private void ReadRunUntil(string line) { string[] tokens = line.Split(','); int id = Convert.ToInt32(tokens[0]); UInt64 ticks = Convert.ToUInt64(tokens[1]); UInt64 stopTicks = Convert.ToUInt64(tokens[2]); CoreAction action = CoreAction.RunUntil(ticks, stopTicks, null); AddCoreAction(id, action); }
private void ReadLoadTape(string line) { string[] tokens = line.Split(','); int id = Convert.ToInt32(tokens[0]); UInt64 ticks = Convert.ToUInt64(tokens[1]); IBlob mediaBlob = new MemoryBlob(Helpers.BytesFromStr(tokens[2])); CoreAction action = CoreAction.LoadTape(ticks, mediaBlob); AddCoreAction(id, action); }
public void ReceiveCoreAction(CoreAction coreAction) { if (_core == null) { Close(); return; } Auditors?.Invoke(coreAction); _core.PushRequest(coreAction); }
private void ReadKey(string line) { string[] tokens = line.Split(','); int id = Convert.ToInt32(tokens[0]); UInt64 ticks = Convert.ToUInt64(tokens[1]); byte keyCode = Convert.ToByte(tokens[2]); bool keyDown = Convert.ToBoolean(tokens[3]); CoreAction action = CoreAction.KeyPress(ticks, keyCode, keyDown); AddCoreAction(id, action); }
private CoreAction RevertToSnapshot(int id) { bool result = _coreCLR.RevertToSnapshot(id); if (!result) { return(null); } OnPropertyChanged("Ticks"); return(CoreAction.RevertToSnapshot(Ticks, id)); }
private HistoryEvent AddCoreAction(int id, CoreAction coreAction) { if (_idToHistoryEvent.ContainsKey(id)) { throw new InvalidOperationException(String.Format("Id {0} has already been processed!", id)); } HistoryEvent historyEvent = _machineHistory.AddCoreAction(coreAction, id); _idToHistoryEvent[id] = historyEvent; _nextLineId = Math.Max(_nextLineId, id + 1); return(historyEvent); }
public CoreAction Clone() { switch (Type) { case Types.CoreVersion: return(CoreAction.CoreVersion(Ticks, Version)); case Types.KeyPress: return(CoreAction.KeyPress(Ticks, KeyCode, KeyDown)); case Types.LoadDisc: return(CoreAction.LoadDisc(Ticks, Drive, (MediaBuffer != null) ? (new MemoryBlob(MediaBuffer.GetBytes())) : null)); case Types.LoadTape: return(CoreAction.LoadTape(Ticks, (MediaBuffer != null) ? (new MemoryBlob(MediaBuffer.GetBytes())) : null)); case Types.Reset: return(CoreAction.Reset(Ticks)); case Types.RunUntil: { List <UInt16> samples = null; if (AudioSamples != null) { samples = new List <UInt16>(AudioSamples); } return(CoreAction.RunUntil(Ticks, StopTicks, samples)); } case Types.LoadCore: return(CoreAction.LoadCore(Ticks, CoreState)); case Types.CreateSnapshot: return(CoreAction.CreateSnapshot(Ticks, SnapshotId)); case Types.RevertToSnapshot: return(CoreAction.RevertToSnapshot(Ticks, SnapshotId)); default: return(null); } }
static public CoreAction CoreActionFromBytes(MemoryByteStream stream) { byte type = stream.ReadByte(); switch (type) { case _coreActionKeyPress: { UInt64 ticks = stream.ReadUInt64(); byte keyCode = stream.ReadByte(); bool keyDown = stream.ReadBool(); return(CoreAction.KeyPress(ticks, keyCode, keyDown)); } case _coreActionReset: { UInt64 ticks = stream.ReadUInt64(); return(CoreAction.Reset(ticks)); } case _coreActionLoadDisc: { UInt64 ticks = stream.ReadUInt64(); byte drive = stream.ReadByte(); byte[] media = stream.ReadArray(); return(CoreAction.LoadDisc(ticks, drive, new MemoryBlob(media))); } case _coreActionLoadTape: { UInt64 ticks = stream.ReadUInt64(); byte[] media = stream.ReadArray(); return(CoreAction.LoadTape(ticks, new MemoryBlob(media))); } case _coreActionRunUntil: { UInt64 ticks = stream.ReadUInt64(); UInt64 stopTicks = stream.ReadUInt64(); return(CoreAction.RunUntil(ticks, stopTicks, null)); } case _coreActionLoadCore: { UInt64 ticks = stream.ReadUInt64(); byte[] state = stream.ReadArray(); return(CoreAction.LoadCore(ticks, new MemoryBlob(state))); } case _coreActionCoreVersion: { UInt64 ticks = stream.ReadUInt64(); Int32 version = stream.ReadInt32(); return(CoreAction.CoreVersion(ticks, version)); } case _coreActionCreateSnapshot: { UInt64 ticks = stream.ReadUInt64(); Int32 snapshotId = stream.ReadInt32(); return(CoreAction.CreateSnapshot(ticks, snapshotId)); } case _coreActionDeleteSnapshot: { UInt64 ticks = stream.ReadUInt64(); Int32 snapshotId = stream.ReadInt32(); return(CoreAction.DeleteSnapshot(ticks, snapshotId)); } case _coreActionRevertToSnapshot: { UInt64 ticks = stream.ReadUInt64(); Int32 snapshotId = stream.ReadInt32(); return(CoreAction.RevertToSnapshot(ticks, snapshotId)); } } throw new Exception(String.Format("Unknown CoreAction type {0}!", type)); }
static public void CoreActionToBytes(MemoryByteStream stream, CoreAction action) { switch (action.Type) { case CoreRequest.Types.KeyPress: stream.Write(_coreActionKeyPress); stream.Write(action.Ticks); stream.Write(action.KeyCode); stream.Write(action.KeyDown); break; case CoreRequest.Types.Reset: stream.Write(_coreActionReset); stream.Write(action.Ticks); break; case CoreRequest.Types.LoadDisc: stream.Write(_coreActionLoadDisc); stream.Write(action.Ticks); stream.Write(action.Drive); stream.WriteArray(action.MediaBuffer.GetBytes()); break; case CoreRequest.Types.LoadTape: stream.Write(_coreActionLoadTape); stream.Write(action.Ticks); stream.WriteArray(action.MediaBuffer.GetBytes()); break; case CoreRequest.Types.RunUntil: stream.Write(_coreActionRunUntil); stream.Write(action.Ticks); stream.Write(action.StopTicks); break; case CoreRequest.Types.LoadCore: stream.Write(_coreActionLoadCore); stream.Write(action.Ticks); stream.WriteArray(action.CoreState.GetBytes()); break; case CoreRequest.Types.CoreVersion: stream.Write(_coreActionCoreVersion); stream.Write(action.Ticks); stream.Write(action.Version); break; case CoreRequest.Types.CreateSnapshot: stream.Write(_coreActionCreateSnapshot); stream.Write(action.Ticks); stream.Write(action.SnapshotId); break; case CoreRequest.Types.DeleteSnapshot: stream.Write(_coreActionDeleteSnapshot); stream.Write(action.Ticks); stream.Write(action.SnapshotId); break; case CoreRequest.Types.RevertToSnapshot: stream.Write(_coreActionRevertToSnapshot); stream.Write(action.Ticks); stream.Write(action.SnapshotId); break; default: throw new Exception(String.Format("Unknown CoreAction type {0}!", action.Type)); } }
/// <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) { Auditors?.Invoke(action); }
/// <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)); } } } } } }
public CoreActionHistoryEvent AddCoreAction(CoreAction coreAction) { return(AddCoreAction(coreAction, _nextId)); }
internal CoreActionHistoryNode(int id, UInt64 ticks, CoreAction action, HistoryNode parent, DateTime createDate) : base(id, ticks, action, null, parent, createDate) { CoreAction = action; HistoryEvent = new CoreActionHistoryEvent(this); }