private NetworkMessage SerializeSnapshot(ICommandSnapshot commandSnapshot)
        {
            SerializableNetworkCommand serializableCommand =
                new SerializableNetworkCommand(_sequenceIndex.index, new SerializableCommand(commandSnapshot));

            _sequenceIndex.index++;

            return(_networkMessageSerializer.Serialize(serializableCommand, MessageTags.kNetworkCommand));
        }
        private void UndoPreviousCommand()
        {
            ICommandSnapshot pastSnapshot = _pastCommands.Last.Value.CommandSnapshot;

            _logger.Log(LoggedFeature.Replays, "Undoing previous command: {0}", pastSnapshot.Command);
            pastSnapshot.Command.Undo();

            _futureCommands.AddFirst(_pastCommands.Last.Value);
            _pastCommands.RemoveLast();
        }
        private void RedoNextCommand()
        {
            ICommandSnapshot futureSnapshot = _futureCommands.First.Value.CommandSnapshot;

            _logger.Log(LoggedFeature.Replays, "Redoing next command: {0}", futureSnapshot.Command);
            futureSnapshot.Command.Run();

            _pastCommands.AddLast(_futureCommands.First.Value);
            _futureCommands.RemoveFirst();
        }
        public void HandleCommandQueued(ICommandSnapshot commandSnapshot)
        {
            // Record all commands we have queued, as they may need to be sent to other clients if
            // we become the room host.
            NetworkMessage networkMessage = SerializeSnapshot(commandSnapshot);

            _enqueuedCommands.Add(networkMessage);

            // For now, every player will broadcast all commands (not just the server)
            // So simply make sure we don't requeue commands that have been queued by other means.
            if (commandSnapshot.Source != CommandSource.Game)
            {
                return;
            }

            // Broadcast the message, adding it to the errored message queue if we fail to do so.
            _networkMessageHandler.BroadcastMessage(networkMessage)
            .Subscribe(unit => { }, error => _erroredCommands.Add(networkMessage));
        }
        public void HandleCommandQueued(ICommandSnapshot commandSnapshot)
        {
            // Make sure we do not have commands in future before we queue up past commands.
            // This is a safety net.
            // One should explicitly call Stop() or EraseFuture(), before any new command is queued.
            // to be dumped.
            // TODO: Use seek
            while (_isPlaying && _futureCommands.Count > 0)
            {
                RedoNextCommand();

                if (_futureCommands.Count == 0)
                {
                    PlaybackInterrupted.Invoke();
                }
            }

            TimeSpan       timeFromPreviousCommand = GetClippedTimeFromPreviousCommand(commandSnapshot);
            ReplaySnapshot replaySnapshot          = new ReplaySnapshot(commandSnapshot, timeFromPreviousCommand);

            _pastCommands.AddLast(replaySnapshot);
        }
        private TimeSpan GetClippedTimeFromPreviousCommand(ICommandSnapshot commandSnapshot)
        {
            if (_pastCommands.Count == 0)
            {
                return(TimeSpan.Zero);
            }

            if (commandSnapshot.Command.IsInitialGameStateCommand)
            {
                return(TimeSpan.Zero);
            }

            TimeSpan previousExecutionTime   = _pastCommands.Last.Value.CommandSnapshot.ExecutionTime;
            TimeSpan previousReplayTime      = _pastCommands.Last.Value.ReplayTime;
            TimeSpan timeFromPreviousCommand = commandSnapshot.ExecutionTime -
                                               previousExecutionTime;

            if (timeFromPreviousCommand > kMaxTimeBetweenCommands)
            {
                return(kMaxTimeBetweenCommands + previousReplayTime);
            }

            return(timeFromPreviousCommand + previousReplayTime);
        }
 public ReplaySnapshot(ICommandSnapshot commandSnapshot, TimeSpan replayTime)
 {
     CommandSnapshot = commandSnapshot;
     ReplayTime      = replayTime;
 }
 public void HandleCommandQueued(ICommandSnapshot commandSnapshot)
 {
     _serializableCommandHistory.AddCommandSnapshot(commandSnapshot);
 }
 public SerializableCommand(ICommandSnapshot commandSnapshot)
 {
     data        = commandSnapshot.Data;
     dataType    = commandSnapshot.Data.GetType();
     commandType = commandSnapshot.Command.GetType();
 }
 public void AddCommandSnapshot(ICommandSnapshot commandSnapshot)
 {
     _commands.Add(new SerializableCommand(commandSnapshot));
 }