示例#1
0
 /// <inheritdoc />
 protected override Task UpdateQueuedMessage(QueuedMessage queuedMessage, DateTime?abandoned, CancellationToken cancellationToken = default(CancellationToken))
 {
     CheckDisposed();
     return(_commandExecutor.Execute(
                () => base.UpdateQueuedMessage(queuedMessage, abandoned, cancellationToken),
                cancellationToken));
 }
示例#2
0
 public void playMessageImmediately(QueuedMessage queuedMessage)
 {
     if (disableImmediateMessages)
     {
         return;
     }
     if (queuedMessage.canBePlayed)
     {
         lock (immediateClips)
         {
             if (immediateClips.Contains(queuedMessage.messageName))
             {
                 Console.WriteLine("Clip for event " + queuedMessage.messageName + " is already queued, ignoring");
                 return;
             }
             else
             {
                 lastImmediateMessageName            = queuedMessage.messageName;
                 lastImmediateMessageTime            = DateTime.Now;
                 this.useShortBeepWhenOpeningChannel = false;
                 this.holdChannelOpen = false;
                 immediateClips.Add(queuedMessage.messageName, queuedMessage);
             }
         }
     }
 }
示例#3
0
        /// <summary>
        /// Updates a queued message in the database i.e. in response to an acknowledgement failure
        /// </summary>
        /// <param name="queuedMessage">The queued message to delete</param>
        /// <param name="abandoned">The date/time the message was abandoned (if applicable)</param>
        /// <param name="cancellationToken">(Optional) A cancellation token through which the
        ///     caller can request cancellation of the update operation</param>
        /// <returns>Returns a task that completes when the update operation completes</returns>
        protected virtual async Task UpdateQueuedMessage(QueuedMessage queuedMessage, DateTime?abandoned, CancellationToken cancellationToken = default(CancellationToken))
        {
            var connection = ConnectionProvider.GetConnection();

            try
            {
                var message        = queuedMessage.Message;
                var headers        = message.Headers;
                var commandBuilder = CommandBuilders.NewUpdateQueuedMessageCommandBuilder();
                commandBuilder.MessageId = headers.MessageId;
                commandBuilder.QueueName = QueueName;
                commandBuilder.Abandoned = abandoned;
                commandBuilder.Attempts  = queuedMessage.Attempts;

                using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled))
                {
                    using (var command = commandBuilder.BuildDbCommand(connection))
                    {
                        await command.ExecuteNonQueryAsync(cancellationToken);
                    }
                    scope.Complete();
                }
            }
            finally
            {
                ConnectionProvider.ReleaseConnection(connection);
            }
        }
示例#4
0
 /// <inheritdoc />
 protected override Task DeleteQueuedMessage(QueuedMessage queuedMessage, CancellationToken cancellationToken = default(CancellationToken))
 {
     CheckDisposed();
     return(_commandExecutor.Execute(
                () => base.DeleteQueuedMessage(queuedMessage, cancellationToken),
                cancellationToken));
 }
示例#5
0
 public void playMessage(QueuedMessage queuedMessage, PearlsOfWisdom.PearlType pearlType, double pearlMessageProbability)
 {
     if (queuedMessage.canBePlayed)
     {
         lock (queuedClips)
         {
             if (queuedClips.Contains(queuedMessage.messageName))
             {
                 Console.WriteLine("Clip for event " + queuedMessage.messageName + " is already queued, ignoring");
                 return;
             }
             else
             {
                 PearlsOfWisdom.PearlMessagePosition pearlPosition = PearlsOfWisdom.PearlMessagePosition.NONE;
                 if (pearlType != PearlsOfWisdom.PearlType.NONE && checkPearlOfWisdomValid(pearlType))
                 {
                     pearlPosition = pearlsOfWisdom.getMessagePosition(pearlMessageProbability);
                 }
                 if (pearlPosition == PearlsOfWisdom.PearlMessagePosition.BEFORE)
                 {
                     QueuedMessage pearlQueuedMessage = new QueuedMessage(queuedMessage.abstractEvent);
                     pearlQueuedMessage.dueTime = queuedMessage.dueTime;
                     queuedClips.Add(PearlsOfWisdom.getMessageFolder(pearlType), pearlQueuedMessage);
                 }
                 queuedClips.Add(queuedMessage.messageName, queuedMessage);
                 if (pearlPosition == PearlsOfWisdom.PearlMessagePosition.AFTER)
                 {
                     QueuedMessage pearlQueuedMessage = new QueuedMessage(queuedMessage.abstractEvent);
                     pearlQueuedMessage.dueTime = queuedMessage.dueTime;
                     queuedClips.Add(PearlsOfWisdom.getMessageFolder(pearlType), pearlQueuedMessage);
                 }
             }
         }
     }
 }
示例#6
0
        /// <inheritdoc />
        protected override async Task <IEnumerable <QueuedMessage> > GetPendingMessages(CancellationToken cancellationToken = default(CancellationToken))
        {
            var queuedMessages = new List <QueuedMessage>();
            var connection     = ConnectionProvider.GetConnection();

            try
            {
                var commandBuilder = CommandBuilders.NewSelectPendingMessagesCommandBuilder();
                commandBuilder.QueueName = QueueName;

                using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled))
                {
                    using (var command = commandBuilder.BuildDbCommand(connection))
                    {
                        using (var reader = await command.ExecuteReaderAsync(cancellationToken))
                        {
                            while (await reader.ReadAsync(cancellationToken))
                            {
                                try
                                {
                                    var record         = commandBuilder.BuildQueuedMessageRecord(reader);
                                    var messageContent = record.Content;
                                    var headers        = DeserializeHeaders(record.Headers);
                                    var message        = new Message(headers, messageContent);
                                    if (message.IsEncrypted() && MessageEncryptionService != null)
                                    {
                                        message = await MessageEncryptionService.Decrypt(message);
                                    }
#pragma warning disable 612
                                    var principal = await ResolvePrincipal(headers, record.SenderPrincipal);

#pragma warning restore 612
                                    message = message.WithoutSecurityToken();
                                    var attempts      = record.Attempts;
                                    var queuedMessage = new QueuedMessage(message, principal, attempts);
                                    queuedMessages.Add(queuedMessage);
                                }
                                catch (Exception ex)
                                {
                                    DiagnosticService.Emit(new SQLEventBuilder(this, SQLEventType.SQLMessageRecordFormatError)
                                    {
                                        Detail    = "Error reading previously queued message record; skipping",
                                        Exception = ex
                                    }.Build());
                                }
                            }
                        }
                    }
                    scope.Complete();
                }
            }
            finally
            {
                ConnectionProvider.ReleaseConnection(connection);
            }

            // SQL calls are not async to avoid the need for TransactionAsyncFlowOption
            // and dependency on .NET 4.5.1 and later
            return(queuedMessages.AsEnumerable());
        }
示例#7
0
 private void RaiseMessageQueuedEvent(QueuedMessage queuedMessage)
 {
     if (this.MessageQueued != null)
     {
         this.MessageQueued(queuedMessage);
     }
 }
示例#8
0
        private void MoveToDeadLetterDirectory(QueuedMessage queuedMessage)
        {
            string pattern = "";

            try
            {
                var message = queuedMessage.Message;
                var headers = message.Headers;
                pattern = headers.MessageId + "*.pmsg";
                var matchingFiles = _directory.EnumerateFiles(pattern);
                foreach (var matchingFile in matchingFiles)
                {
                    MoveToDeadLetterDirectory(matchingFile);
                }
            }
            catch (Exception ex)
            {
                DiagnosticService.Emit(
                    new FilesystemEventBuilder(this, DiagnosticEventType.DeadLetterError)
                {
                    Detail    = "Error moving message file(s) to dead letter directory",
                    Queue     = QueueName,
                    Path      = Path.Combine(_directory.FullName, pattern),
                    Exception = ex
                }.Build());
            }
        }
示例#9
0
 public Task Enqueue(Message message, IPrincipal senderPrincipal)
 {
     CheckDisposed();
     var queuedMessage = new QueuedMessage(message, senderPrincipal);
     return _queuedMessages.SendAsync(queuedMessage);
     // TODO: handle accepted == false
 }
示例#10
0
        /// <inheritdoc />
        protected override async Task <IEnumerable <QueuedMessage> > GetPendingMessages(CancellationToken cancellationToken = new CancellationToken())
        {
            var pendingMessages = new List <QueuedMessage>();
            var files           = _directory.EnumerateFiles("*.pmsg");

            foreach (var file in files)
            {
                try
                {
                    var messageFile = new MessageFile(file);
                    var message     = await messageFile.ReadMessage(cancellationToken);

                    if (message.IsEncrypted() && _messageEncryptionService != null)
                    {
                        message = await _messageEncryptionService.Decrypt(message);
                    }
                    var principal = await _securityTokenService.NullSafeValidate(message.Headers.SecurityToken);

                    var queuedMessage = new QueuedMessage(message, principal);
                    pendingMessages.Add(queuedMessage);
                }
                catch (Exception ex)
                {
                    DiagnosticService.Emit(new FilesystemEventBuilder(this, FilesystemEventType.MessageFileFormatError)
                    {
                        Detail    = "Error reading previously queued message file; skipping",
                        Path      = file.FullName,
                        Exception = ex
                    }.Build());
                }
            }
            return(pendingMessages);
        }
示例#11
0
        /// <summary>
        /// Transport a <see cref="QueuedMessage"/>.
        /// </summary>
        /// <param name="message">The <see cref="IMessage"/> to transport.</param>
        /// <returns>An awaitable object representing the send operation.</returns>
        public async Task SendMessageAsync(QueuedMessage message)
        {
            const string action = "message";

            try
            {
                var fullActionPath = new Uri(message.Envelope.Recipient.PeerAddress, Path.Combine(ActionBase, action));

                var serialisedMessage = this.Serialiser.Serialise(message.Envelope);

                var result = await this.ExecutePostRequest(fullActionPath, serialisedMessage);

                if (result.IsSuccessStatusCode && this.MessageSent != null)
                {
                    this.MessageSent(message, serialisedMessage);
                }
                else
                {
                    throw new HttpRequestException(result.Content.ReadAsStringAsync().Result);
                }
            }
            catch (Exception exception)
            {
                if (this.MessageFailedToSend != null)
                {
                    this.MessageFailedToSend(exception, message);
                }
            }
        }
示例#12
0
        private void readStatus()
        {
            if (CrewChief.gameDefinition.gameEnum != GameEnum.IRACING)
            {
                List <QueuedMessage> damageMessages = new List <QueuedMessage>();
                switch (lastReportedPunctureCorner)
                {
                case CornerData.Corners.FRONT_LEFT:
                    damageMessages.Add(new QueuedMessage(folderLeftFrontPuncture, 0));
                    break;

                case CornerData.Corners.FRONT_RIGHT:
                    damageMessages.Add(new QueuedMessage(folderRightFrontPuncture, 0));
                    break;

                case CornerData.Corners.REAR_LEFT:
                    damageMessages.Add(new QueuedMessage(folderLeftRearPuncture, 0));
                    break;

                case CornerData.Corners.REAR_RIGHT:
                    damageMessages.Add(new QueuedMessage(folderRightRearPuncture, 0));
                    break;
                }
                QueuedMessage aero = getDamageMessage(Component.AERO, false);
                if (aero != null)
                {
                    damageMessages.Add(aero);
                }
                QueuedMessage tranny = getDamageMessage(Component.TRANNY, false);
                if (tranny != null)
                {
                    damageMessages.Add(tranny);
                }
                QueuedMessage engine = getDamageMessage(Component.ENGINE, false);
                if (engine != null)
                {
                    damageMessages.Add(engine);
                }
                QueuedMessage sus = getDamageMessage(Component.SUSPENSION, false);
                if (sus != null)
                {
                    damageMessages.Add(sus);
                }
                QueuedMessage brakes = getDamageMessage(Component.BRAKES, false);
                if (brakes != null)
                {
                    damageMessages.Add(brakes);
                }
                if (damageMessages.Count == 0)
                {
                    // no damage
                    damageMessages.Add(new QueuedMessage(folderNoDamageOnAnyComponent, 0));
                }
                foreach (QueuedMessage message in damageMessages)
                {
                    audioPlayer.playMessageImmediately(message);
                }
            }
        }
示例#13
0
        /// <inheritdoc cref="Producer.ProduceCoreAsync" />
        protected override Task <IOffset?> ProduceCoreAsync(IOutboundEnvelope envelope)
        {
            var queuedMessage = new QueuedMessage(envelope);

            _queue.Add(queuedMessage);

            return(queuedMessage.TaskCompletionSource.Task);
        }
示例#14
0
 /// <summary>
 /// Update: Unity callback invoked on every frame.  Used here to process
 /// messages on our message queue (on the main thread).
 /// </summary>
 protected void Update()
 {
     while (messageQueue.Count > 0)
     {
         QueuedMessage qm = messageQueue.Dequeue();
         HandleMessage(qm.client, qm.message);
     }
 }
示例#15
0
        public void NewMessage(byte[] message, IPEndPoint endpoint)
        {
            QueuedMessage queuedMessage = new QueuedMessage();

            queuedMessage.messageData = message;
            queuedMessage.source      = endpoint;
            mMessageQueue.Enqueue(queuedMessage);
        }
示例#16
0
        internal override Task <T> ExecuteAsync <T>(Message message, ResultProcessor <T> processor, ServerEndPoint server = null)
        {
            if (message == null)
            {
                return(CompletedTask <T> .Default(asyncState));
            }
            multiplexer.CheckMessage(message);

            multiplexer.Trace("Wrapping " + message.Command, "Transaction");
            // prepare the inner command as a task
            Task <T> task;

            if (message.IsFireAndForget)
            {
                task = CompletedTask <T> .Default(null); // F+F explicitly does not get async-state
            }
            else
            {
                var tcs    = TaskSource.Create <T>(asyncState);
                var source = ResultBox <T> .Get(tcs);

                message.SetSource(source, processor);
                task = tcs.Task;
            }

            // prepare an outer-command that decorates that, but expects QUEUED
            var queued    = new QueuedMessage(message);
            var wasQueued = ResultBox <bool> .Get(null);

            queued.SetSource(wasQueued, QueuedProcessor.Default);

            // store it, and return the task of the *outer* command
            // (there is no task for the inner command)
            lock (SyncLock)
            {
                (_pending ?? (_pending = new List <QueuedMessage>())).Add(queued);

                switch (message.Command)
                {
                case RedisCommand.UNKNOWN:
                case RedisCommand.EVAL:
                case RedisCommand.EVALSHA:
                    // people can do very naughty things in an EVAL
                    // including change the DB; change it back to what we
                    // think it should be!
                    var sel = PhysicalConnection.GetSelectDatabaseCommand(message.Db);
                    queued    = new QueuedMessage(sel);
                    wasQueued = ResultBox <bool> .Get(null);

                    queued.SetSource(wasQueued, QueuedProcessor.Default);
                    _pending.Add(queued);
                    break;
                }
            }
            return(task);
        }
示例#17
0
 /// <summary>
 /// Deletes a queued message from the database
 /// </summary>
 /// <param name="queuedMessage">The queued message to delete</param>
 /// <param name="cancellationToken">(Optional) A cancellation token through which the
 /// caller can request cancellation of the delete operation</param>
 /// <returns>Returns a task that completes when the delete operation completes</returns>
 protected virtual async Task DeleteQueuedMessage(QueuedMessage queuedMessage, CancellationToken cancellationToken = default(CancellationToken))
 {
     var message        = queuedMessage.Message;
     var messageHeaders = message.Headers;
     var messageId      = messageHeaders.MessageId;
     var fb             = Builders <QueuedMessageDocument> .Filter;
     var filter         = fb.Eq(qm => qm.Queue, (string)QueueName) &
                          fb.Eq(qm => qm.MessageId, (string)messageId);
     await _queuedMessages.DeleteOneAsync(filter, cancellationToken);
 }
        public void SetResetPassword(User user)
        {
            user.ResetPasswordExpiry = CurrentRequestData.Now.AddDays(1);
            user.ResetPasswordGuid   = Guid.NewGuid();
            _userManagementService.SaveUser(user);

            QueuedMessage queuedMessage = _messageParser.GetMessage(user);

            _messageParser.QueueMessage(queuedMessage);
        }
        /// <summary>
        /// Create a path to sent queue for the given <paramref name="message"/>.
        /// </summary>
        /// <param name="message">The instance of <see cref="QueuedMessage"/>.</param>
        /// <returns>A path to sent queue for the given message.</returns>
        public static string SentLocation(this QueuedMessage message)
        {
            var messageLocation = string.Format(
                CultureInfo.InvariantCulture,
                "/{0}/sent/{1}",
                message.Envelope.Recipient.EscapePeerAddress(),
                message.QueuedAt.ToFileTimeUtc());

            return(messageLocation);
        }
        public void OnCompleted()
        {
            var completed = new QueuedMessage <StreamMessage <TKey, TPayload> > {
                Kind = MessageKind.Completed
            };

            this.serializer.Serialize(this.destination, completed);
            this.destination.Flush();
            this.done.Set();
        }
示例#21
0
        /// <summary>
        /// Mark a message as sent.
        /// </summary>
        /// <param name="message">The <see cref="T:ServiceBus.Queueing.QueuedMessage"/> that was sent.</param>
        /// <param name="messageContent">The raw message content.</param>
        public void Dequeue(QueuedMessage message, string messageContent)
        {
            message.HasSent = true;

            this._ftpClient.CreatePeerDirectoryIfNotExist(message.Envelope.Recipient);

            this._ftpClient.DeleteMessage(new Uri(message.MessageLocation(), UriKind.Relative));

            this._ftpClient.PutMessage(new Uri(message.SentLocation(), UriKind.Relative), messageContent);
        }
 internal void LogMessageFailedToSend(Exception ex, QueuedMessage failedMessage)
 {
     this._serviceBus.Log.InfoFormat(
         CultureInfo.CurrentCulture,
         "Message of type [{0}] could not be sent to [{1}] at [{2}].  Reason [{3}]",
         failedMessage.Envelope.Message.MessageType,
         failedMessage.Envelope.Recipient.PeerAddress,
         DateTime.Now,
         this.GetInnerMostException(ex).Message);
 }
示例#23
0
        public async Task <string> SendAsync(FakeSocket receiver, string message)
        {
            QueuedMessage          = new QueuedMessage();
            QueuedMessage.Target   = receiver;
            QueuedMessage.Message  = message;
            QueuedMessage.Received = false;
            await _fakeSocketProvider.Send(this);

            return("OK");
        }
示例#24
0
 public void Queue(QueuedMessage queuedMessage, List <AttachmentData> attachments = null, bool trySendImmediately = true)
 {
     if (queuedMessage != null)
     {
         _emailSender.AddToQueue(queuedMessage, attachments);
         if (trySendImmediately)
         {
             _emailSender.SendMailMessage(queuedMessage);
         }
     }
 }
示例#25
0
        async Task SendMessage(Message message)
        {
            var queued = new QueuedMessage(message);

            while (!cancelCts.IsCancellationRequested)
            {
                var old = Interlocked.CompareExchange(ref currentMessage, queued, null);
                if (old == null)
                {
                    break;
                }

                await old.Task.Task;
            }

            cancelCts.Token.ThrowIfCancellationRequested();

            var doc = message.Write(this);

            var sb       = new StringBuilder();
            var settings = new XmlWriterSettings();

            settings.OmitXmlDeclaration = true;

            using (var writer = XmlWriter.Create(sb, settings)) {
                doc.WriteTo(writer);
            }

            var bytes = new UTF8Encoding().GetBytes(sb.ToString());

            var header = BitConverter.GetBytes(bytes.Length);

            if (bytes.Length == 0)
            {
                throw new ServerErrorException();
            }

            await stream.WriteAsync(header, 0, 4).ConfigureAwait(false);

            await stream.FlushAsync();

            await stream.WriteAsync(bytes, 0, bytes.Length);

            await stream.FlushAsync();

            var old2 = Interlocked.CompareExchange(ref currentMessage, null, queued);

            if (old2 != queued)
            {
                throw new ServerErrorException();
            }

            queued.Task.SetResult(true);
        }
示例#26
0
 public void Queue(QueuedMessage queuedMessage, bool trySendImmediately = true)
 {
     if (queuedMessage != null)
     {
         if (trySendImmediately)
         {
             _emailSender.SendMailMessage(queuedMessage);
         }
         _emailSender.AddToQueue(queuedMessage);
     }
 }
示例#27
0
 public override void respond(String voiceMessage)
 {
     if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.CAR_STATUS) ||
         SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.DAMAGE_REPORT) ||
         SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.STATUS))
     {
         readStatus();
     }
     else
     {
         QueuedMessage damageMessage = null;
         if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.HOWS_MY_AERO))
         {
             damageMessage = getDamageMessage(Component.AERO, true);
         }
         if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.HOWS_MY_TRANSMISSION))
         {
             damageMessage = getDamageMessage(Component.TRANNY, true);
         }
         if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.HOWS_MY_ENGINE))
         {
             damageMessage = getDamageMessage(Component.ENGINE, true);
         }
         if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.HOWS_MY_SUSPENSION))
         {
             damageMessage = getDamageMessage(Component.SUSPENSION, true);
         }
         if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.HOWS_MY_BRAKES))
         {
             damageMessage = getDamageMessage(Component.BRAKES, true);
         }
         if (CrewChief.gameDefinition.gameEnum != GameEnum.IRACING && damageMessage != null)
         {
             // play this immediately or play "stand by", and queue it to be played in a few seconds
             if (delayResponses && Utilities.random.Next(10) >= 2 && SoundCache.availableSounds.Contains(AudioPlayer.folderStandBy))
             {
                 audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderStandBy, 0));
                 int secondsDelay = Math.Max(5, Utilities.random.Next(11));
                 audioPlayer.pauseQueue(secondsDelay);
                 damageMessage.dueTime = (DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond) + (1000 * secondsDelay);
                 audioPlayer.playDelayedImmediateMessage(damageMessage);
             }
             else
             {
                 audioPlayer.playMessageImmediately(damageMessage);
             }
         }
         else
         {
             audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderNoData, 0));
         }
     }
 }
        private void EnqueueSend(ILowProtocol sender, byte[] data)
        {
            QueuedMessage message = new QueuedMessage(sender, data);

            if (m_outgoingMessages.Count == 0)
            {
                Monitor.PulseAll(m_outgoingMessages);
            }

            m_outgoingMessagesFrequency.Increment();
            m_outgoingMessages.Enqueue(message);
        }
 /// <summary>
 /// Safely dequeues an item from the queue if there are any
 /// </summary>
 /// <param name="message"></param>
 /// <returns></returns>
 private bool TryRead(out QueuedMessage message)
 {
     if (client.sendQueue.Count > 0)
     {
         lock (client.sendSyncRoot)
         {
             return(client.sendQueue.TryDequeue(out message));
         }
     }
     message = default(QueuedMessage);
     return(false);
 }
示例#30
0
        public void ResetPasswordService_SetResetPassword_ShouldSaveAQueuedMessage()
        {
            var user          = new User();
            var queuedMessage = new QueuedMessage();

            A.CallTo(() => _messageParser.GetMessage(user, null, null, null, null, null, null))
            .Returns(queuedMessage);

            _resetPasswordService.SetResetPassword(user);

            A.CallTo(() => _messageParser.QueueMessage(queuedMessage, null, true)).MustHaveHappened();
        }
    public void QueueMessage(PacketId eventName, byte[] data, bool needsAck = false)
    {
        var qm = new QueuedMessage
        {
            id       = eventName,
            data     = data,
            needsAck = needsAck
        };

        lock (m_OutboundQueue)
        {
            m_OutboundQueue.Add(qm);
        }
    }
示例#32
0
        /// <summary>
        /// Dispatches a notification message produced by a subscription.
        /// </summary>
        private void DispatchMessage(Subscription subscription, NotificationMessage notification)
        {
            lock (m_messages)
            {
                for (LinkedListNode<QueuedRequest> node = m_requests.First; node != null; node = node.Next)
                {
                    // wake up timed out requests and force them to return a fault.
                    if (node.Value.Timeout < DateTime.UtcNow)
                    {
                        node.Value.Signal.Set();
                        m_requests.Remove(node);
                        continue;
                    }

                    // check for a request that matches the session.
                    if (Object.ReferenceEquals(subscription.Session, node.Value.Session))
                    {
                        // pass the message to the request and wake up the request thread.
                        node.Value.SubscriptionId = subscription.Id;
                        node.Value.Message = notification;
                        node.Value.Signal.Set();
                        m_requests.Remove(node);
                        return;
                    }
                }

                // messages only go on the publish queue if no threads are waiting.
                QueuedMessage message = new QueuedMessage();

                message.Session = subscription.Session;
                message.Subscription = subscription;
                message.Message = notification;
                m_messages.AddLast(message);

                // ensure queue does not grow too large.
                while (m_messages.Count > 50)
                {
                    m_messages.RemoveFirst();
                }
            }
        }
示例#33
0
        public override void respond(String voiceMessage)
        {
            Boolean gotData = false;
            if (currentGameState != null)
            {
                if (voiceMessage.StartsWith(SpeechRecogniser.WHAT_TYRE_IS) || voiceMessage.StartsWith(SpeechRecogniser.WHAT_TYRES_IS))
                {
                    Object opponentKey = getOpponentKey(voiceMessage, " on");
                    if (opponentKey != null)
                    {
                        OpponentData opponentData = currentGameState.OpponentData[opponentKey];
                        if (opponentData.CurrentTyres == TyreType.Option)
                        {
                            gotData = true;
                            audioPlayer.playClipImmediately(new QueuedMessage(MandatoryPitStops.folderMandatoryPitStopsOptionTyres, 0, null), false);
                            audioPlayer.closeChannel();
                        }
                        else if (opponentData.CurrentTyres == TyreType.Prime)
                        {
                            gotData = true;
                            audioPlayer.playClipImmediately(new QueuedMessage(MandatoryPitStops.folderMandatoryPitStopsPrimeTyres, 0, null), false);
                            audioPlayer.closeChannel();
                        }
                    }
                }

                if (voiceMessage.StartsWith(SpeechRecogniser.WHATS) &&
                    (voiceMessage.EndsWith(SpeechRecogniser.LAST_LAP) || voiceMessage.EndsWith(SpeechRecogniser.BEST_LAP)))
                {
                    if (voiceMessage.EndsWith(SpeechRecogniser.LAST_LAP))
                    {
                        float lastLap = getOpponentLastLap(getOpponentKey(voiceMessage, "'s "));
                        if (lastLap != -1)
                        {
                            gotData = true;
                            audioPlayer.playClipImmediately(new QueuedMessage("opponentLastLap", MessageContents(
                                TimeSpanWrapper.FromSeconds(lastLap, true)), 0, null), false);
                            audioPlayer.closeChannel();
                        }
                    }
                    else
                    {
                        float bestLap = getOpponentBestLap(getOpponentKey(voiceMessage, "'s "));
                        if (bestLap != -1)
                        {
                            gotData = true;
                            audioPlayer.playClipImmediately(new QueuedMessage("opponentBestLap", MessageContents(
                                TimeSpanWrapper.FromSeconds(bestLap, true)), 0, null), false);
                            audioPlayer.closeChannel();
                        }
                    }
                }
                else if (voiceMessage.StartsWith(SpeechRecogniser.WHERE_IS))
                {
                    foreach (KeyValuePair<Object, OpponentData> entry in currentGameState.OpponentData)
                    {
                        String usableDriverName = DriverNameHelper.getUsableNameForRawName(entry.Value.DriverRawName);
                        if (voiceMessage.Contains(usableDriverName))
                        {
                            Console.WriteLine("Got opponent name, raw name = " + entry.Value.DriverRawName + ", using " + usableDriverName);
                            if (entry.Value.IsActive)
                            {
                                int position = entry.Value.Position;
                                OpponentData.OpponentDelta opponentDelta = entry.Value.getTimeDifferenceToPlayer(currentGameState.SessionData);
                                audioPlayer.playClipImmediately(new QueuedMessage("opponentPosition",
                                    MessageContents(Position.folderStub, QueuedMessage.folderNameNumbersStub + position), 0, null), false);
                                if (opponentDelta != null && (opponentDelta.lapDifference != 0 || Math.Abs(opponentDelta.time) > 0.05))
                                {
                                    if (opponentDelta.lapDifference == 1)
                                    {
                                        audioPlayer.playClipImmediately(new QueuedMessage(Position.folderOneLapBehind, 0, null), false);
                                    }
                                    else if (opponentDelta.lapDifference > 1)
                                    {
                                        audioPlayer.playClipImmediately(new QueuedMessage("opponentTimeDelta",
                                            MessageContents(QueuedMessage.folderNameNumbersStub + opponentDelta.lapDifference, Position.folderLapsBehind), 0, null), false);
                                    }
                                    else if (opponentDelta.lapDifference == -1)
                                    {
                                        audioPlayer.playClipImmediately(new QueuedMessage(Position.folderOneLapAhead, 0, null), false);
                                    }
                                    else if (opponentDelta.lapDifference < -1)
                                    {
                                        audioPlayer.playClipImmediately(new QueuedMessage("opponentTimeDelta",
                                            MessageContents(QueuedMessage.folderNameNumbersStub + opponentDelta.lapDifference, Position.folderLapsAhead), 0, null), false);
                                    }
                                    else
                                    {
                                        TimeSpanWrapper delta = TimeSpanWrapper.FromSeconds(Math.Abs(opponentDelta.time), true);
                                        String aheadOrBehind = Position.folderAhead;
                                        if (opponentDelta.time < 0)
                                        {
                                            aheadOrBehind = Position.folderBehind;
                                        }
                                        audioPlayer.playClipImmediately(new QueuedMessage("opponentTimeDelta",
                                            MessageContents(delta, aheadOrBehind), 0, null), false);
                                    }
                                }
                                audioPlayer.closeChannel();
                                gotData = true;
                            }
                            else
                            {
                                Console.WriteLine("Driver "+ entry.Value.DriverRawName + " is no longer active in this session");
                            }
                            break;
                        }
                    }
                }
                else if (voiceMessage.StartsWith(SpeechRecogniser.WHOS_BEHIND_ON_TRACK))
                {
                    Object opponentKey = currentGameState.getOpponentKeyBehindOnTrack();
                    if (opponentKey != null)
                    {
                        OpponentData opponent = currentGameState.OpponentData[opponentKey];
                        QueuedMessage queuedMessage = new QueuedMessage("opponentNameAndPosition", MessageContents(currentGameState.OpponentData[opponentKey],
                            Position.folderStub, QueuedMessage.folderNameNumbersStub + opponent.Position),
                            MessageContents(Position.folderStub, QueuedMessage.folderNameNumbersStub + opponent.Position, folderCantPronounceName), 0, null);
                        if (queuedMessage.canBePlayed)
                        {
                            audioPlayer.playClipImmediately(queuedMessage, false);
                            audioPlayer.closeChannel();
                            gotData = true;
                        }
                    }
                }
                else if (voiceMessage.StartsWith(SpeechRecogniser.WHOS_IN_FRONT_ON_TRACK) || voiceMessage.StartsWith(SpeechRecogniser.WHOS_AHEAD_ON_TRACK))
                {
                    Object opponentKey = currentGameState.getOpponentKeyInFrontOnTrack();
                    if (opponentKey != null)
                    {
                        OpponentData opponent = currentGameState.OpponentData[opponentKey];
                        QueuedMessage queuedMessage = new QueuedMessage("opponentName", MessageContents(currentGameState.OpponentData[opponentKey],
                            Position.folderStub, QueuedMessage.folderNameNumbersStub + opponent.Position),
                            MessageContents(Position.folderStub, QueuedMessage.folderNameNumbersStub + opponent.Position, folderCantPronounceName), 0, null);
                        if (queuedMessage.canBePlayed)
                        {
                            audioPlayer.playClipImmediately(queuedMessage, false);
                            audioPlayer.closeChannel();
                            gotData = true;
                        }
                    }
                }
                else if (voiceMessage.StartsWith(SpeechRecogniser.WHOS_BEHIND_IN_THE_RACE) || voiceMessage.StartsWith(SpeechRecogniser.WHOS_BEHIND))
                {
                    if (currentGameState.isLast())
                    {
                        audioPlayer.playClipImmediately(new QueuedMessage(Position.folderLast, 0, null), false);
                        audioPlayer.closeChannel();
                        gotData = true;
                    }
                    else
                    {
                        OpponentData opponent = currentGameState.getOpponentAtPosition(currentGameState.SessionData.Position + 1, false);
                        if (opponent != null)
                        {
                            QueuedMessage queuedMessage = new QueuedMessage("opponentName", MessageContents(opponent), MessageContents(folderCantPronounceName), 0, null);
                            if (queuedMessage.canBePlayed)
                            {
                                audioPlayer.playClipImmediately(queuedMessage, false);
                                audioPlayer.closeChannel();
                                gotData = true;
                            }
                        }
                    }
                }
                else if (voiceMessage.StartsWith(SpeechRecogniser.WHOS_IN_FRONT_IN_THE_RACE) || voiceMessage.StartsWith(SpeechRecogniser.WHOS_AHEAD_IN_THE_RACE)
                    || voiceMessage.StartsWith(SpeechRecogniser.WHOS_IN_FRONT) || voiceMessage.StartsWith(SpeechRecogniser.WHOS_AHEAD))
                {
                    if (currentGameState.SessionData.Position == 1)
                    {
                        audioPlayer.playClipImmediately(new QueuedMessage(Position.folderLeading, 0, null), false);
                        audioPlayer.closeChannel();
                        gotData = true;
                    }
                    else
                    {
                        OpponentData opponent = currentGameState.getOpponentAtPosition(currentGameState.SessionData.Position - 1, false);
                        if (opponent != null)
                        {
                            QueuedMessage queuedMessage = new QueuedMessage("opponentName", MessageContents(opponent), MessageContents(folderCantPronounceName), 0, null);
                            if (queuedMessage.canBePlayed)
                            {
                                audioPlayer.playClipImmediately(queuedMessage, false);
                                audioPlayer.closeChannel();
                                gotData = true;
                            }
                        }
                    }
                }
                else if (voiceMessage.StartsWith(SpeechRecogniser.WHOS_LEADING) && currentGameState.SessionData.Position > 1)
                {
                    OpponentData opponent = currentGameState.getOpponentAtPosition(1, false);
                    if (opponent != null)
                    {
                        QueuedMessage queuedMessage = new QueuedMessage("opponentName", MessageContents(opponent), MessageContents(folderCantPronounceName), 0, null);
                        if (queuedMessage.canBePlayed)
                        {
                            audioPlayer.playClipImmediately(queuedMessage, false);
                            audioPlayer.closeChannel();
                            gotData = true;
                        }
                    }
                }
                else if (voiceMessage.StartsWith(SpeechRecogniser.WHOS_IN))
                {
                    Object opponentKey = getOpponentKey(voiceMessage, "");
                    if (opponentKey != null)
                    {
                        if (opponentKey == positionIsPlayerKey)
                        {
                            audioPlayer.playClipImmediately(new QueuedMessage(folderWeAre, 0, null), false);
                            audioPlayer.closeChannel();
                            gotData = true;
                        }
                        else if (currentGameState.OpponentData.ContainsKey(opponentKey))
                        {
                            OpponentData opponent = currentGameState.OpponentData[opponentKey];
                            QueuedMessage queuedMessage = new QueuedMessage("opponentName", MessageContents(opponent), MessageContents(folderCantPronounceName), 0, null);
                            if (queuedMessage.canBePlayed)
                            {
                                audioPlayer.playClipImmediately(queuedMessage, false);
                                audioPlayer.closeChannel();
                                gotData = true;
                            }
                        }
                    }
                }
            }
            if (!gotData)
            {
                audioPlayer.playClipImmediately(new QueuedMessage(AudioPlayer.folderNoData, 0, null), false);
                audioPlayer.closeChannel();
            }
        }
示例#34
0
        protected override void triggerInternal(Shared lastState, Shared currentState)
        {
            float currentSpeed = currentState.CarSpeed;
            float previousSpeed = lastState.CarSpeed;
            if ((CommonData.isRaceStarted || (enableInQualAndPractice && CommonData.isSessionRunning)) &&
                currentState.Player.GameSimulationTime > timeAfterRaceStartToActivate &&
                currentState.ControlType == (int)Constant.Control.Player && currentSpeed > minSpeedForSpotterToOperate)
            {
                float deltaFront = Math.Abs(currentState.TimeDeltaFront);
                float deltaBehind = Math.Abs(currentState.TimeDeltaBehind);

                // if we think there's already a car along side, add a little to the car length so we're
                // sure it's gone before calling clear
                float carLengthToUse = carLength;
                if (channelOpen)
                {
                    carLengthToUse += gapNeededForClear;
                }

                // initialise to some large value and put the real value in here only if the
                // time gap suggests we're overlapping
                float closingSpeedInFront = 9999;
                float closingSpeedBehind = 9999;

                Boolean carAlongSideInFront = carLengthToUse / currentSpeed > deltaFront;
                Boolean carAlongSideInFrontPrevious = carLengthToUse / previousSpeed > Math.Abs(lastState.TimeDeltaFront);
                Boolean carAlongSideBehind = carLengthToUse / currentSpeed > deltaBehind;
                Boolean carAlongSideBehindPrevious = carLengthToUse / previousSpeed > Math.Abs(lastState.TimeDeltaBehind);

                // only say a car is overlapping if it's been overlapping for 2 game state updates
                // and the closing speed isn't too high
                if (carAlongSideInFront)
                {
                    // check the closing speed before warning
                    closingSpeedInFront = getClosingSpeed(lastState, currentState, true);
                }
                if (carAlongSideBehind)
                {
                    // check the closing speed before warning
                    closingSpeedBehind = getClosingSpeed(lastState, currentState, false);
                }

                DateTime now = DateTime.Now;

                if (channelOpen && !carAlongSideInFront && (!require2ClearsForClear || !carAlongSideInFrontPrevious) &&
                    !carAlongSideBehind && (!require2ClearsForClear || !carAlongSideBehindPrevious))
                {
                    newlyOverlapping = true;
                    Console.WriteLine("think we're clear, deltaFront = " + deltaFront + " time gap = " + carLengthToUse / currentSpeed);
                    Console.WriteLine("deltaBehind = " + deltaBehind + " time gap = " + carLengthToUse / currentSpeed);
                    Console.WriteLine("race time = " + currentState.Player.GameSimulationTime);

                    if (newlyClear)
                    {
                        Console.WriteLine("Waiting " + clearMessageDelay);
                        newlyClear = false;
                        timeWhenWeThinkWeAreClear = now;
                    }
                    else if (now > timeWhenWeThinkWeAreClear.Add(clearMessageDelay))
                    {
                        channelOpen = false;
                        audioPlayer.removeImmediateClip(folderHoldYourLine);
                        audioPlayer.removeImmediateClip(folderStillThere);
                        QueuedMessage clearMessage = new QueuedMessage(0, this);
                        clearMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + clearMessageExpiresAfter;
                        audioPlayer.playClipImmediately(folderClear, clearMessage);
                        audioPlayer.closeChannel();
                    }
                }
                else if ((carAlongSideInFront && (!require2OverlapsForHold || carAlongSideInFrontPrevious) && Math.Abs(closingSpeedInFront) < maxClosingSpeed) ||
                    (carAlongSideBehind && (!require2OverlapsForHold || carAlongSideBehindPrevious) && Math.Abs(closingSpeedBehind) < maxClosingSpeed))
                {
                    Boolean frontOverlapIsReducing = carAlongSideInFront && closingSpeedInFront > 0;
                    Boolean rearOverlapIsReducing =  carAlongSideBehind && closingSpeedBehind > 0;
                    if (channelOpen && now > timeOfLastHoldMessage.Add(repeatHoldFrequency))
                    {
                        // channel's already open, still there
                        Console.WriteLine("Still there...");
                        timeOfLastHoldMessage = now;
                        audioPlayer.removeImmediateClip(folderHoldYourLine);
                        audioPlayer.removeImmediateClip(folderClear);
                        QueuedMessage stillThereMessage = new QueuedMessage(0, this);
                        stillThereMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + holdMessageExpiresAfter;
                        audioPlayer.playClipImmediately(folderStillThere, stillThereMessage);
                    }
                    else if (!channelOpen &&
                        (rearOverlapIsReducing || (frontOverlapIsReducing && !spotterOnlyWhenBeingPassed)))
                    {
                        newlyClear = true;
                        if (newlyOverlapping)
                        {
                            timeWhenWeThinkWeAreOverlapping = now;
                            newlyOverlapping = false;
                        }
                        else if (now > timeWhenWeThinkWeAreOverlapping.Add(overlapMessageDelay))
                        {
                            Console.WriteLine("race time = " + currentState.Player.GameSimulationTime);
                            if (carAlongSideInFront)
                            {
                                Console.WriteLine("new overlap in front, deltaFront = " + deltaFront + " time gap = " +
                                carLengthToUse / currentSpeed + " closing speed = " + closingSpeedInFront);
                            }
                            if (carAlongSideBehind)
                            {
                                Console.WriteLine("new overlap behind, deltaBehind = " + deltaBehind + " time gap = " +
                                carLengthToUse / currentSpeed + " closing speed = " + closingSpeedBehind);
                            }
                            timeOfLastHoldMessage = now;
                            channelOpen = true;
                            audioPlayer.removeImmediateClip(folderClear);
                            audioPlayer.removeImmediateClip(folderStillThere);
                            audioPlayer.openChannel();
                            QueuedMessage holdMessage = new QueuedMessage(0, this);
                            holdMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + holdMessageExpiresAfter;
                            audioPlayer.playClipImmediately(folderHoldYourLine, holdMessage);
                        }
                    }
                }
            }
            else if (channelOpen)
            {
                channelOpen = false;
                audioPlayer.closeChannel();
            }
        }
示例#35
0
 private void playEstimatedTypeLifeMinutes(int minutesRemainingOnTheseTyres, Boolean immediate)
 {
     if (immediate)
     {
         if (minutesRemainingOnTheseTyres > 59 || minutesRemainingOnTheseTyres > (timeInSession - timeElapsed) / 60)
         {
             audioPlayer.playClipImmediately(new QueuedMessage(folderGoodWear, 0, null), false);
             audioPlayer.closeChannel();
             return;
         }
         else if (minutesRemainingOnTheseTyres < 1)
         {
             audioPlayer.playClipImmediately(new QueuedMessage(folderKnackeredAllRound, 0, null), false);
             audioPlayer.closeChannel();
             return;
         }
     }
     if (minutesRemainingOnTheseTyres < 59 && minutesRemainingOnTheseTyres > 1 &&
                 minutesRemainingOnTheseTyres <= (timeInSession - timeElapsed) / 60)
     {
         QueuedMessage queuedMessage = new QueuedMessage("minutes_on_current_tyres",
             MessageContents(folderMinutesOnCurrentTyresIntro, QueuedMessage.folderNameNumbersStub + minutesRemainingOnTheseTyres, folderMinutesOnCurrentTyresOutro), 0, null);
         if (immediate)
         {
             audioPlayer.playClipImmediately(queuedMessage, false);
             audioPlayer.closeChannel();
         }
         else
         {
             audioPlayer.queueClip(queuedMessage);
         }
     }
     else if (immediate)
     {
         audioPlayer.playClipImmediately(new QueuedMessage(AudioPlayer.folderNoData, 0, null), false);
         audioPlayer.closeChannel();
     }
 }
示例#36
0
 private void playEstimatedTypeLifeLaps(int lapsRemainingOnTheseTyres, Boolean immediate)
 {
     if (immediate)
     {
         if (lapsRemainingOnTheseTyres > 59 || lapsRemainingOnTheseTyres > lapsInSession - completedLaps)
         {
             audioPlayer.playClipImmediately(new QueuedMessage(folderGoodWear, 0, null), false);
             audioPlayer.closeChannel();
             return;
         }
         else if (lapsRemainingOnTheseTyres < 1)
         {
             audioPlayer.playClipImmediately(new QueuedMessage(folderKnackeredAllRound, 0, null), false);
             audioPlayer.closeChannel();
             return;
         }
     }
     if (lapsRemainingOnTheseTyres < 59 && lapsRemainingOnTheseTyres > 1 &&
                 lapsRemainingOnTheseTyres <= lapsInSession - completedLaps)
     {
         QueuedMessage queuedMessage = new QueuedMessage("laps_on_current_tyres",
             MessageContents(folderLapsOnCurrentTyresIntro, QueuedMessage.folderNameNumbersStub + lapsRemainingOnTheseTyres, folderLapsOnCurrentTyresOutro), 0, null);
         if (immediate)
         {
             audioPlayer.playClipImmediately(queuedMessage, false);
             audioPlayer.closeChannel();
         }
         else
         {
             audioPlayer.queueClip(queuedMessage);
         }
     }
     else if (immediate)
     {
         audioPlayer.playClipImmediately(new QueuedMessage(AudioPlayer.folderNoData, 0, null), false);
         audioPlayer.closeChannel();
     }
 }
示例#37
0
        protected override void triggerInternal(GameStateData previousGameState, GameStateData currentGameState)
        {
            sessionType = currentGameState.SessionData.SessionType;
            this.currentGameState = currentGameState;
            if (currentGameState.SessionData.IsNewLap)
            {
                if (currentGameState.SessionData.LapTimePrevious > 0)
                {
                    if (currentGameState.OpponentData.Count > 0)
                    {
                        if (currentGameState.SessionData.OpponentsLapTimeSessionBestPlayerClass > 0)
                        {
                            deltaPlayerLastToSessionBestInClass = TimeSpan.FromSeconds(
                                currentGameState.SessionData.LapTimePrevious - currentGameState.SessionData.OpponentsLapTimeSessionBestPlayerClass);
                        }
                        if (currentGameState.SessionData.OpponentsLapTimeSessionBestOverall > 0)
                        {
                            deltaPlayerLastToSessionBestOverall = TimeSpan.FromSeconds(
                                currentGameState.SessionData.LapTimePrevious - currentGameState.SessionData.OpponentsLapTimeSessionBestOverall);
                        }
                    }
                    else if (currentGameState.SessionData.PlayerLapTimeSessionBest > 0)
                    {
                        deltaPlayerLastToSessionBestOverall = TimeSpan.FromSeconds(currentGameState.SessionData.LapTimePrevious - currentGameState.SessionData.PlayerLapTimeSessionBest);
                        deltaPlayerLastToSessionBestInClass = deltaPlayerLastToSessionBestOverall;
                    }
                    if (currentGameState.SessionData.LapTimePrevious <= currentGameState.SessionData.PlayerLapTimeSessionBest)
                    {
                        deltaPlayerBestToSessionBestInClass = deltaPlayerLastToSessionBestInClass;
                        deltaPlayerBestToSessionBestOverall = deltaPlayerLastToSessionBestOverall;
                    }
                }
                else
                {
                    // the last lap was invalid so the delta is undefined
                    deltaPlayerLastToSessionBestInClass = TimeSpan.MaxValue;
                    deltaPlayerLastToSessionBestOverall = TimeSpan.MaxValue;
                }
            }
            currentPosition = currentGameState.SessionData.Position;

            // check the current lap is still valid
            if (lapIsValid && currentGameState.SessionData.CompletedLaps > 0 &&
                !currentGameState.SessionData.IsNewLap && !currentGameState.SessionData.CurrentLapIsValid)
            {
                lapIsValid = false;
            }
            if (currentGameState.SessionData.IsNewLap)
            {
                lastLapTime = currentGameState.SessionData.LapTimePrevious;
                if (lastLapTime > 0 && lapIsValid) {
                    if (bestLapTime == 0 || lastLapTime < bestLapTime) {
                        bestLapTime = lastLapTime;
                    }
                }
            }

            float[] lapAndSectorsComparisonData = new float[] { -1, -1, -1, -1 };
            if (currentGameState.SessionData.IsNewSector)
            {
                isHotLapping = currentGameState.SessionData.SessionType == SessionType.HotLap || (currentGameState.OpponentData.Count == 0 || (
                    currentGameState.OpponentData.Count == 1 && currentGameState.OpponentData.First().Value.DriverRawName == currentGameState.SessionData.DriverRawName));
                if (isHotLapping)
                {
                    lapAndSectorsComparisonData[1] = currentGameState.SessionData.PlayerBestLapSector1Time;
                    lapAndSectorsComparisonData[2] = currentGameState.SessionData.PlayerBestLapSector2Time;
                    lapAndSectorsComparisonData[3] = currentGameState.SessionData.PlayerBestLapSector3Time;
                }
                else
                {
                    if (currentGameState.SessionData.SessionType == SessionType.Race)
                    {
                        lapAndSectorsComparisonData = currentGameState.getTimeAndSectorsForBestOpponentLapInWindow(paceCheckLapsWindowForRace, currentGameState.carClass.carClassEnum);
                    }
                    else if (currentGameState.SessionData.SessionType == SessionType.Qualify || currentGameState.SessionData.SessionType == SessionType.Practice)
                    {
                        lapAndSectorsComparisonData = currentGameState.getTimeAndSectorsForBestOpponentLapInWindow(-1, currentGameState.carClass.carClassEnum);
                    }
                }
            }

            if (!currentGameState.PitData.OnInLap && !currentGameState.PitData.OnOutLap)
            {
                Boolean sectorsReportedForLap = false;
                if (currentGameState.SessionData.IsNewLap &&
                    ((currentGameState.SessionData.SessionType == SessionType.HotLap && currentGameState.SessionData.CompletedLaps > 0) || currentGameState.SessionData.CompletedLaps > 1))
                {
                    if (lapTimesWindow == null)
                    {
                        lapTimesWindow = new List<float>(lapTimesWindowSize);
                    }
                    lastLapRating = getLastLapRating(currentGameState, lapAndSectorsComparisonData);

                    if (currentGameState.SessionData.PreviousLapWasValid)
                    {
                        lapTimesWindow.Insert(0, currentGameState.SessionData.LapTimePrevious);
                        if (lapIsValid)
                        {
                            Boolean playedLapTime = false;
                            if (isHotLapping)
                            {
                                // always play the laptime in hotlap mode
                                audioPlayer.queueClip(new QueuedMessage("laptime",
                                        MessageContents(folderLapTimeIntro, TimeSpan.FromSeconds(currentGameState.SessionData.LapTimePrevious)), 0, this));
                                playedLapTime = true;
                            }
                            else if (((currentGameState.SessionData.SessionType == SessionType.Qualify || currentGameState.SessionData.SessionType == SessionType.Practice) && frequencyOfPlayerQualAndPracLapTimeReports > random.NextDouble() * 10)
                                || (currentGameState.SessionData.SessionType == SessionType.Race && frequencyOfPlayerRaceLapTimeReports > random.NextDouble() * 10))
                            {
                                // usually play it in practice / qual mode, occasionally play it in race mode
                                QueuedMessage gapFillerLapTime = new QueuedMessage("laptime",
                                    MessageContents(folderLapTimeIntro, TimeSpan.FromSeconds(currentGameState.SessionData.LapTimePrevious)), 0, this);
                                if (currentGameState.SessionData.SessionType == SessionType.Race)
                                {
                                    gapFillerLapTime.maxPermittedQueueLengthForMessage = maxQueueLengthForRaceLapTimeReports;
                                }
                                audioPlayer.queueClip(gapFillerLapTime);
                                playedLapTime = true;
                            }

                            if (currentGameState.SessionData.SessionType == SessionType.Qualify || currentGameState.SessionData.SessionType == SessionType.Practice ||
                                currentGameState.SessionData.SessionType == SessionType.HotLap)
                            {
                                if (currentGameState.SessionData.SessionType == SessionType.HotLap || currentGameState.OpponentData.Count == 0)
                                {
                                    if (lastLapRating == LastLapRating.BEST_IN_CLASS || deltaPlayerLastToSessionBestOverall <= TimeSpan.Zero)
                                    {
                                        audioPlayer.queueClip(new QueuedMessage(folderPersonalBest, 0, this));
                                    }
                                    else if (deltaPlayerLastToSessionBestOverall < TimeSpan.FromMilliseconds(50))
                                    {
                                        audioPlayer.queueClip(new QueuedMessage(folderLessThanATenthOffThePace, 0, this));
                                    }
                                    else if (deltaPlayerLastToSessionBestOverall < TimeSpan.MaxValue)
                                    {
                                        audioPlayer.queueClip(new QueuedMessage("lapTimeNotRaceGap",
                                            MessageContents(folderGapIntro, deltaPlayerLastToSessionBestOverall, folderGapOutroOffPace), 0, this));
                                    }
                                    if (practiceAndQualSectorReportsLapEnd && frequencyOfPracticeAndQualSectorDeltaReports > random.NextDouble() * 10)
                                    {
                                        List<MessageFragment> sectorMessageFragments = getSectorDeltaMessages(SectorReportOption.COMBINED, currentGameState.SessionData.LastSector1Time, lapAndSectorsComparisonData[1],
                                            currentGameState.SessionData.LastSector2Time, lapAndSectorsComparisonData[2], currentGameState.SessionData.LastSector3Time, lapAndSectorsComparisonData[3], true);
                                        if (sectorMessageFragments.Count > 0)
                                        {
                                            audioPlayer.queueClip(new QueuedMessage("sectorsHotLap", sectorMessageFragments, 0, this));
                                            sectorsReportedForLap = true;
                                        }
                                    }
                                }
                                    // need to be careful with the rating here as it's based on the known opponent laps, and we may have joined the session part way through
                                else if (currentGameState.SessionData.Position == 1)
                                {
                                    Boolean newGapToSecond = false;
                                    if (previousGameState != null && previousGameState.SessionData.Position > 1)
                                    {
                                        newGapToSecond = true;
                                        if (currentGameState.SessionData.SessionType == SessionType.Qualify)
                                        {
                                            audioPlayer.queueClip(new QueuedMessage(Position.folderPole, 0, this));
                                        }
                                        else if (currentGameState.SessionData.SessionType == SessionType.Practice)
                                        {
                                            audioPlayer.queueClip(new QueuedMessage(Position.folderStub + 1, 0, this));
                                        }
                                    }
                                    else if (deltaPlayerLastToSessionBestOverall < lastGapToSecondWhenLeadingPracOrQual)
                                    {
                                        newGapToSecond = true;
                                        lastGapToSecondWhenLeadingPracOrQual = deltaPlayerLastToSessionBestOverall;
                                    }
                                    if (newGapToSecond)
                                    {
                                        lastGapToSecondWhenLeadingPracOrQual = deltaPlayerLastToSessionBestOverall;
                                        TimeSpan gapBehind = deltaPlayerLastToSessionBestOverall.Negate();
                                        // only play qual / prac deltas for Raceroom as the PCars data is inaccurate for sessions joined part way through
                                        if ((!disablePCarspracAndQualPoleDeltaReports ||
                                            CrewChief.gameDefinition.gameEnum == GameDefinition.raceRoom.gameEnum) &&
                                            ((gapBehind.Seconds > 0 || gapBehind.Milliseconds > 50) &&
                                            gapBehind.Seconds < 60))
                                        {
                                            // delay this a bit...
                                            audioPlayer.queueClip(new QueuedMessage("lapTimeNotRaceGap",
                                                MessageContents(folderGapIntro, gapBehind, folderQuickerThanSecondPlace), random.Next(0, 20), this));
                                        }
                                    }
                                }
                                else
                                {
                                    if (lastLapRating == LastLapRating.PERSONAL_BEST_STILL_SLOW || lastLapRating == LastLapRating.PERSONAL_BEST_CLOSE_TO_CLASS_LEADER ||
                                        lastLapRating == LastLapRating.PERSONAL_BEST_CLOSE_TO_OVERALL_LEADER)
                                    {
                                        audioPlayer.queueClip(new QueuedMessage(folderPersonalBest, 0, this));
                                    }
                                    // don't read this message if the rounded time gap is 0.0 seconds or it's more than 59 seconds
                                    // only play qual / prac deltas for Raceroom as the PCars data is inaccurate for sessions joined part way through
                                    if ((!disablePCarspracAndQualPoleDeltaReports || CrewChief.gameDefinition.gameEnum == GameDefinition.raceRoom.gameEnum) &&
                                        (deltaPlayerLastToSessionBestInClass.Seconds > 0 || deltaPlayerLastToSessionBestInClass.Milliseconds > 50) &&
                                        deltaPlayerLastToSessionBestInClass.Seconds < 60)
                                    {
                                        // delay this a bit...
                                        audioPlayer.queueClip(new QueuedMessage("lapTimeNotRaceGap",
                                            MessageContents(folderGapIntro, deltaPlayerLastToSessionBestInClass, folderGapOutroOffPace), random.Next(0, 20), this));
                                    }
                                    if (practiceAndQualSectorReportsLapEnd && frequencyOfPracticeAndQualSectorDeltaReports > random.NextDouble() * 10)
                                    {
                                        List<MessageFragment> sectorMessageFragments = getSectorDeltaMessages(SectorReportOption.COMBINED, currentGameState.SessionData.LastSector1Time, lapAndSectorsComparisonData[1],
                                            currentGameState.SessionData.LastSector2Time, lapAndSectorsComparisonData[2], currentGameState.SessionData.LastSector3Time, lapAndSectorsComparisonData[3], true);
                                        if (sectorMessageFragments.Count > 0)
                                        {
                                            audioPlayer.queueClip(new QueuedMessage("sectorsQual", sectorMessageFragments, 0, this));
                                            sectorsReportedForLap = true;
                                        }
                                    }
                                }
                            }
                            else if (currentGameState.SessionData.SessionType == SessionType.Race)
                            {
                                Boolean playedLapMessage = false;
                                if (frequencyOfPlayerRaceLapTimeReports > random.NextDouble() * 10)
                                {
                                    float pearlLikelihood = 0.8f;
                                    switch (lastLapRating)
                                    {
                                        case LastLapRating.BEST_OVERALL:
                                            playedLapMessage = true;
                                            audioPlayer.queueClip(new QueuedMessage(folderBestLapInRace, 0, this), PearlsOfWisdom.PearlType.GOOD, pearlLikelihood);
                                            break;
                                        case LastLapRating.BEST_IN_CLASS:
                                            playedLapMessage = true;
                                            audioPlayer.queueClip(new QueuedMessage(folderBestLapInRaceForClass, 0, this), PearlsOfWisdom.PearlType.GOOD, pearlLikelihood);
                                            break;
                                        case LastLapRating.SETTING_CURRENT_PACE:
                                            playedLapMessage = true;
                                            audioPlayer.queueClip(new QueuedMessage(folderSettingCurrentRacePace, 0, this), PearlsOfWisdom.PearlType.GOOD, pearlLikelihood);
                                            break;
                                        case LastLapRating.CLOSE_TO_CURRENT_PACE:
                                            // don't keep playing this one
                                            if (random.NextDouble() < 0.5)
                                            {
                                                playedLapMessage = true;
                                                audioPlayer.queueClip(new QueuedMessage(folderMatchingCurrentRacePace, 0, this), PearlsOfWisdom.PearlType.GOOD, pearlLikelihood);
                                            }
                                            break;
                                        case LastLapRating.PERSONAL_BEST_CLOSE_TO_OVERALL_LEADER:
                                        case LastLapRating.PERSONAL_BEST_CLOSE_TO_CLASS_LEADER:
                                            playedLapMessage = true;
                                            audioPlayer.queueClip(new QueuedMessage(folderGoodLap, 0, this), PearlsOfWisdom.PearlType.GOOD, pearlLikelihood);
                                            break;
                                        case LastLapRating.PERSONAL_BEST_STILL_SLOW:
                                            playedLapMessage = true;
                                            audioPlayer.queueClip(new QueuedMessage(folderPersonalBest, 0, this), PearlsOfWisdom.PearlType.NEUTRAL, pearlLikelihood);
                                            break;
                                        case LastLapRating.CLOSE_TO_OVERALL_LEADER:
                                        case LastLapRating.CLOSE_TO_CLASS_LEADER:
                                            // this is an OK lap but not a PB. We only want to say "decent lap" occasionally here
                                            if (random.NextDouble() < 0.2)
                                            {
                                                playedLapMessage = true;
                                                audioPlayer.queueClip(new QueuedMessage(folderGoodLap, 0, this), PearlsOfWisdom.PearlType.NEUTRAL, pearlLikelihood);
                                            }
                                            break;
                                        default:
                                            break;
                                    }
                                }

                                if (raceSectorReportsAtLapEnd && frequencyOfRaceSectorDeltaReports > random.NextDouble() * 10)
                                {
                                    double r = random.NextDouble();
                                    SectorReportOption reportOption = SectorReportOption.COMBINED;
                                    if (playedLapTime && playedLapMessage)
                                    {
                                        // if we've already played a laptime and lap rating, use the short sector message.
                                        reportOption = SectorReportOption.WORST_ONLY;
                                    }
                                    else if (r > 0.6 || ((playedLapTime || playedLapMessage) && r > 0.3))
                                    {
                                        // if we've played one of these, usually use the abbrieviated version. If we've played neither, sometimes use the abbrieviated version
                                        reportOption = SectorReportOption.BEST_AND_WORST;
                                    }

                                    List<MessageFragment> sectorMessageFragments = getSectorDeltaMessages(reportOption, currentGameState.SessionData.LastSector1Time, lapAndSectorsComparisonData[1],
                                            currentGameState.SessionData.LastSector2Time, lapAndSectorsComparisonData[2], currentGameState.SessionData.LastSector3Time, lapAndSectorsComparisonData[3], false);
                                    if (sectorMessageFragments.Count > 0)
                                    {
                                        QueuedMessage message = new QueuedMessage("sectorsRace", sectorMessageFragments, 0, this);
                                        message.maxPermittedQueueLengthForMessage = maxQueueLengthForRaceSectorDeltaReports;
                                        audioPlayer.queueClip(message);
                                        sectorsReportedForLap = true;
                                    }
                                }

                                // play the consistency message if we've not played the good lap message, or sometimes
                                // play them both
                                Boolean playConsistencyMessage = !playedLapMessage || random.NextDouble() < 0.25;
                                if (playConsistencyMessage && currentGameState.SessionData.CompletedLaps >= lastConsistencyUpdate + lapTimesWindowSize &&
                                    lapTimesWindow.Count >= lapTimesWindowSize)
                                {
                                    ConsistencyResult consistency = checkAgainstPreviousLaps();
                                    if (consistency == ConsistencyResult.CONSISTENT)
                                    {
                                        lastConsistencyUpdate = currentGameState.SessionData.CompletedLaps;
                                        audioPlayer.queueClip(new QueuedMessage(folderConsistentTimes, random.Next(0, 20), this));
                                    }
                                    else if (consistency == ConsistencyResult.IMPROVING)
                                    {
                                        lastConsistencyUpdate = currentGameState.SessionData.CompletedLaps;
                                        audioPlayer.queueClip(new QueuedMessage(folderImprovingTimes, random.Next(0, 20), this));
                                    }
                                    else if (consistency == ConsistencyResult.WORSENING)
                                    {
                                        // don't play the worsening message if the lap rating is good
                                        if (lastLapRating == LastLapRating.BEST_IN_CLASS || lastLapRating == LastLapRating.BEST_OVERALL ||
                                            lastLapRating == LastLapRating.SETTING_CURRENT_PACE || lastLapRating == LastLapRating.CLOSE_TO_CURRENT_PACE)
                                        {
                                            Console.WriteLine("Skipping 'worsening' laptimes message - inconsistent with lap rating");
                                        }
                                        else
                                        {
                                            lastConsistencyUpdate = currentGameState.SessionData.CompletedLaps;
                                            audioPlayer.queueClip(new QueuedMessage(folderWorseningTimes, random.Next(0, 20), this));
                                        }
                                    }
                                }
                            }
                        }
                    }
                    lapIsValid = true;
                }
                // report sector delta at the completion of a sector?
                if (!sectorsReportedForLap && currentGameState.SessionData.IsNewSector &&
                    ((currentGameState.SessionData.SessionType == SessionType.Race && raceSectorReportsAtEachSector) ||
                     (currentGameState.SessionData.SessionType != SessionType.Race && practiceAndQualSectorReportsAtEachSector)))
                {
                    double r = random.NextDouble() * 10;
                    Boolean canPlayForRace = frequencyOfRaceSectorDeltaReports > r;
                    Boolean canPlayForPracAndQual = frequencyOfPracticeAndQualSectorDeltaReports > r;
                    if ((currentGameState.SessionData.SessionType == SessionType.Race && canPlayForRace) ||
                        ((currentGameState.SessionData.SessionType == SessionType.Practice || currentGameState.SessionData.SessionType == SessionType.Qualify ||
                        currentGameState.SessionData.SessionType == SessionType.HotLap) && canPlayForPracAndQual))
                    {
                        float playerSector = -1;
                        float comparisonSector = -1;
                        SectorSet sectorEnum = SectorSet.NONE;
                        switch (currentGameState.SessionData.SectorNumber)
                        {
                            case 1:
                                playerSector = currentGameState.SessionData.LastSector3Time;
                                comparisonSector = lapAndSectorsComparisonData[3];
                                sectorEnum = SectorSet.THREE;
                                break;
                            case 2:
                                playerSector = currentGameState.SessionData.LastSector1Time;
                                comparisonSector = lapAndSectorsComparisonData[1];
                                sectorEnum = SectorSet.ONE;
                                break;
                            case 3:
                                playerSector = currentGameState.SessionData.LastSector2Time;
                                comparisonSector = lapAndSectorsComparisonData[2];
                                sectorEnum = SectorSet.TWO;
                                break;
                        }
                        if (playerSector > 0 && comparisonSector > 0)
                        {
                            String folder = getFolderForSectorCombination(getEnumForSectorDelta(playerSector - comparisonSector, currentGameState.SessionData.SessionType != SessionType.Race), sectorEnum);
                            if (folder != null)
                            {
                                audioPlayer.queueClip(new QueuedMessage(folder, random.Next(2, 4), this));
                            }
                        }
                    }
                }
            }
        }
示例#38
0
        // ReSharper disable once UnusedMethodReturnValue.Local
        private async Task ProcessQueuedMessage(QueuedMessage queuedMessage, CancellationToken cancellationToken)
        {
            var attemptsRemaining = _maxAttempts;
            while (attemptsRemaining > 0)
            {
                attemptsRemaining--;
                var message = queuedMessage.Message;
                var context = new InMemoryQueuedMessageContext(message, queuedMessage.SenderPrincipal);
                cancellationToken.ThrowIfCancellationRequested();

                await _concurrentMessageProcessingSlot.WaitAsync(cancellationToken);
                cancellationToken.ThrowIfCancellationRequested();
                try
                {
                    await _listener.MessageReceived(message, context, cancellationToken);
                    if (_autoAcknowledge && !context.Acknowledged)
                    {
                        await context.Acknowledge();
                    }
                }
                catch (Exception ex)
                {
                    Log.WarnFormat("Unhandled exception handling queued message {0}", ex,
                        queuedMessage.Message.Headers.MessageId);
                }
                finally
                {
                    _concurrentMessageProcessingSlot.Release();
                }

                if (context.Acknowledged)
                {
                    // TODO: Implement journaling
                    break;
                }
                if (attemptsRemaining > 0)
                {
                    await Task.Delay(_retryDelay, cancellationToken);
                }
            }
        }
示例#39
0
        protected override void triggerInternal(GameStateData previousGameState, GameStateData currentGameState)
        {
            isLeading = currentGameState.SessionData.Position == 1;
            isLast = currentGameState.isLast();
            isRace = currentGameState.SessionData.SessionType == SessionType.Race;
            currentGapInFront = currentGameState.SessionData.TimeDeltaFront;
            currentGapBehind = currentGameState.SessionData.TimeDeltaBehind;

            if (currentGameState.SessionData.IsNewLap)
            {
                playedGapBehindForThisLap = false;
            }

            if (gapsInFront == null || gapsBehind == null)
            {
                clearState();
            }
            if (!currentGameState.SessionData.IsRacingSameCarInFront)
            {
                gapsInFront.Clear();
            }
            if (!currentGameState.SessionData.IsRacingSameCarBehind)
            {
                gapsBehind.Clear();
            }
            if (!currentGameState.PitData.InPitlane && enableGapMessages)
            {
                if (isRace && !CrewChief.readOpponentDeltasForEveryLap &&
                    currentGameState.SessionData.IsNewSector)
                {
                    sectorsSinceLastGapAheadReport++;
                    sectorsSinceLastGapBehindReport++;
                    sectorsSinceLastCloseCarAheadReport++;
                    sectorsSinceLastCloseCarBehindReport++;
                    GapStatus gapInFrontStatus = GapStatus.NONE;
                    GapStatus gapBehindStatus = GapStatus.NONE;
                    if (currentGameState.SessionData.Position != 1)
                    {
                        gapsInFront.Insert(0, currentGameState.SessionData.TimeDeltaFront);
                        gapInFrontStatus = getGapStatus(gapsInFront, gapInFrontAtLastReport);
                    }
                    if (!isLast)
                    {
                        gapsBehind.Insert(0, currentGameState.SessionData.TimeDeltaBehind);
                        gapBehindStatus = getGapStatus(gapsBehind, gapBehindAtLastReport);
                    }

                    // Play which ever is the smaller gap, but we're not interested if the gap is < 0.5 or > 20 seconds or hasn't changed:
                    Boolean playGapInFront = gapInFrontStatus != GapStatus.NONE &&
                        (gapBehindStatus == GapStatus.NONE || (gapsInFront.Count() > 0 && gapsBehind.Count() > 0 && gapsInFront[0] < gapsBehind[0]));

                    Boolean playGapBehind = !playGapInFront && gapBehindStatus != GapStatus.NONE;
                    if (playGapInFront)
                    {
                        if (gapInFrontStatus == GapStatus.CLOSE)
                        {
                            if (sectorsSinceLastCloseCarAheadReport >= sectorsUntilNextCloseCarAheadReport)
                            {
                                sectorsSinceLastCloseCarAheadReport = 0;
                                sectorsUntilNextCloseCarAheadReport = adjustForMidLapPreference(currentGameState.SessionData.SectorNumber,
                                    rand.Next(closeAheadMinSectorWait, closeAheadMaxSectorWait));
                                audioPlayer.queueClip(new QueuedMessage(folderBeingHeldUp, 0, this, new Dictionary<string, object> { { "position", currentGameState.SessionData.Position } }));
                                gapInFrontAtLastReport = gapsInFront[0];
                            }
                        }
                        else if (gapInFrontStatus != GapStatus.NONE && sectorsSinceLastGapAheadReport >= sectorsUntilNextGapAheadReport)
                        {
                            sectorsSinceLastGapAheadReport = 0;
                            sectorsUntilNextGapAheadReport = adjustForMidLapPreference(currentGameState.SessionData.SectorNumber,
                                rand.Next(gapAheadMinSectorWait, gapAheadMaxSectorWait));
                            TimeSpanWrapper gapInFront = TimeSpanWrapper.FromMilliseconds(gapsInFront[0] * 1000, true);
                            Boolean readGap = gapInFront.timeSpan.Seconds > 0 || gapInFront.timeSpan.Milliseconds > 50;
                            if (readGap)
                            {
                                if (gapInFrontStatus == GapStatus.INCREASING)
                                {
                                    audioPlayer.queueClip(new QueuedMessage("Timings/gap_in_front",
                                        MessageContents(folderTheGapTo, currentGameState.getOpponentAtPosition(currentGameState.SessionData.Position - 1, false), folderAheadIsIncreasing,
                                        gapInFront), MessageContents(folderGapInFrontIncreasing, gapInFront), 0, this, new Dictionary<string, object> { { "position", currentGameState.SessionData.Position } }));
                                }
                                else if (gapInFrontStatus == GapStatus.DECREASING)
                                {
                                    audioPlayer.queueClip(new QueuedMessage("Timings/gap_in_front",
                                        MessageContents(folderYoureReeling, currentGameState.getOpponentAtPosition(currentGameState.SessionData.Position - 1, false),
                                        folderInTheGapIsNow, gapInFront), MessageContents(folderGapInFrontDecreasing, gapInFront), 0, this, new Dictionary<string, object> { { "position", currentGameState.SessionData.Position } }));
                                }
                                else if (gapInFrontStatus == GapStatus.OTHER)
                                {
                                    audioPlayer.queueClip(new QueuedMessage("Timings/gap_in_front",
                                        MessageContents(folderTheGapTo, currentGameState.getOpponentAtPosition(currentGameState.SessionData.Position - 1, false),
                                        folderAheadIsNow, gapInFront), MessageContents(folderGapInFrontIsNow, gapInFront), 0, this, new Dictionary<string, object> { { "position", currentGameState.SessionData.Position } }));
                                }
                            }
                            gapInFrontAtLastReport = gapsInFront[0];
                        }
                    }
                    else if (playGapBehind)
                    {
                        if (gapBehindStatus == GapStatus.CLOSE)
                        {
                            if (sectorsSinceLastCloseCarBehindReport >= sectorsUntilNextCloseCarBehindReport)
                            {
                                sectorsSinceLastCloseCarBehindReport = 0;
                                sectorsUntilNextCloseCarBehindReport = adjustForMidLapPreference(currentGameState.SessionData.SectorNumber,
                                    rand.Next(closeBehindMinSectorWait, closeBehindMaxSectorWait));
                                audioPlayer.queueClip(new QueuedMessage(folderBeingPressured, 0, this, new Dictionary<string, object> { { "position", currentGameState.SessionData.Position } }));
                                gapBehindAtLastReport = gapsBehind[0];
                            }
                        }
                        else if (gapBehindStatus != GapStatus.NONE && sectorsSinceLastGapBehindReport >= sectorsUntilNextGapBehindReport)
                        {
                            sectorsSinceLastGapBehindReport = 0;
                            sectorsUntilNextGapBehindReport = adjustForMidLapPreference(currentGameState.SessionData.SectorNumber,
                                rand.Next(gapBehindMinSectorWait, gapBehindMaxSectorWait));
                            TimeSpanWrapper gapBehind = TimeSpanWrapper.FromMilliseconds(gapsBehind[0] * 1000, true);
                            Boolean readGap = gapBehind.timeSpan.Seconds > 0 || gapBehind.timeSpan.Milliseconds > 50;
                            if (readGap)
                            {
                                if (gapBehindStatus == GapStatus.INCREASING)
                                {
                                    audioPlayer.queueClip(new QueuedMessage("Timings/gap_behind",
                                        MessageContents(folderTheGapTo, currentGameState.getOpponentAtPosition(currentGameState.SessionData.Position + 1, false),
                                        folderBehindIsIncreasing, gapBehind), MessageContents(folderGapBehindIncreasing, gapBehind), 0, this, new Dictionary<string, object> { { "position", currentGameState.SessionData.Position } }));
                                }
                                else if (gapBehindStatus == GapStatus.DECREASING)
                                {
                                    audioPlayer.queueClip(new QueuedMessage("Timings/gap_behind",
                                        MessageContents(currentGameState.getOpponentAtPosition(currentGameState.SessionData.Position + 1, false), folderIsReelingYouIn, gapBehind),
                                        MessageContents(folderGapBehindDecreasing, gapBehind), 0, this, new Dictionary<string, object> { { "position", currentGameState.SessionData.Position } }));
                                }
                                else if (gapBehindStatus == GapStatus.OTHER)
                                {
                                    audioPlayer.queueClip(new QueuedMessage("Timings/gap_behind",
                                        MessageContents(folderTheGapTo, currentGameState.getOpponentAtPosition(currentGameState.SessionData.Position + 1, false),
                                        folderBehindIsNow, gapBehind), MessageContents(folderGapBehindIsNow, gapBehind), 0, this, new Dictionary<string, object> { { "position", currentGameState.SessionData.Position } }));
                                }
                            }
                            gapBehindAtLastReport = gapsBehind[0];
                        }
                    }
                }
                if (isRace && CrewChief.readOpponentDeltasForEveryLap && currentGameState.SessionData.CompletedLaps > 0)
                {
                    if (currentGameState.SessionData.Position > 1 && currentGameState.SessionData.IsNewLap)
                    {
                        if (currentGapInFront > 0.05)
                        {
                            TimeSpanWrapper gap = TimeSpanWrapper.FromSeconds(currentGapInFront, true);
                            QueuedMessage message = new QueuedMessage("Timings/gap_ahead", MessageContents(folderTheGapTo,
                                currentGameState.getOpponentAtPosition(currentGameState.SessionData.Position - 1, false), folderAheadIsNow, gap),
                                MessageContents(folderGapInFrontIsNow, gap), 0, this, new Dictionary<string,object>{ {"position", currentGameState.SessionData.Position} });
                            message.playEvenWhenSilenced = true;
                            audioPlayer.queueClip(message);
                        }
                    }
                    if (!currentGameState.isLast())
                    {
                        if (!playedGapBehindForThisLap && currentGapBehind > 0.05 && currentGameState.SessionData.LapTimeCurrent > 0 &&
                            currentGameState.SessionData.LapTimeCurrent >= currentGapBehind &&
                            currentGameState.SessionData.LapTimeCurrent <= currentGapBehind + CrewChief._timeInterval.TotalSeconds)
                        {
                            playedGapBehindForThisLap = true;
                            TimeSpanWrapper gap = TimeSpanWrapper.FromSeconds(currentGapBehind, true);
                            QueuedMessage message = new QueuedMessage("Timings/gap_behind", MessageContents(folderTheGapTo,
                                currentGameState.getOpponentAtPosition(currentGameState.SessionData.Position + 1, false), folderBehindIsNow, gap),
                                MessageContents(folderGapBehindIsNow, gap), 0, this, new Dictionary<string, object> { { "position", currentGameState.SessionData.Position } });
                            message.playEvenWhenSilenced = true;
                            audioPlayer.queueClip(message);
                        }
                    }
                }
            }
        }
示例#40
0
        protected override void triggerInternal(Data.Shared lastState, Data.Shared currentState)
        {
            if (currentState.LapTimeBest > 0)
            {
                sessionBestLapTimeDeltaToLeader = TimeSpan.FromSeconds(currentState.LapTimeBest - getLapTimeBestForClassLeader(currentState));
            }
            else
            {
                sessionBestLapTimeDeltaToLeader = TimeSpan.MaxValue;
            }
            if (currentState.LapTimePrevious > 0)
            {
                currentLapTimeDeltaToLeadersBest = TimeSpan.FromSeconds(currentState.LapTimePrevious - getLapTimeBestForClassLeader(currentState));
            }
            else
            {
                // the last lap was invalid so the delta is undefined
                currentLapTimeDeltaToLeadersBest = TimeSpan.MaxValue;
            }
            currentPosition = currentState.Position;
            // in race sessions (race only) the LapTimePrevious isn't set to -1 if that lap was invalid, so
            // we need to record that it's invalid while we're actually on the lap
            if (CommonData.isSessionRunning && lapIsValid && currentState.CompletedLaps > 0 &&
                !CommonData.isNewLap && currentState.LapTimeCurrent == -1)
            {
                lapIsValid = false;
            }
            if (CommonData.isSessionRunning && CommonData.isNewLap)
            {
                lastLapTime = currentState.LapTimePrevious;
            }
            if (CommonData.isSessionRunning && CommonData.isNewLap && !CommonData.isInLap && !CommonData.isOutLap &&
                ((CommonData.isHotLapping && currentState.CompletedLaps > 0) || currentState.CompletedLaps > 1))
            {
                if (lapTimesWindow == null)
                {
                    lapTimesWindow = new List<float>(lapTimesWindowSize);
                }
                // this might be NO_DATA
                lastLapRating = getLastLapRating(currentState);

                if (currentState.LapTimePrevious > 0)
                {
                    lapTimesWindow.Insert(0, currentState.LapTimePrevious);
                    if (lapIsValid)
                    {
                        // queue the actual laptime as a 'gap filler' - this is only played if the
                        // queue would otherwise be empty

                        if (enableLapTimeMessages && readLapTimes && !CommonData.isHotLapping)
                        {
                            QueuedMessage gapFillerLapTime = new QueuedMessage(folderLapTimeIntro, null,
                            TimeSpan.FromSeconds(currentState.LapTimePrevious), 0, this);
                            gapFillerLapTime.gapFiller = true;
                            audioPlayer.queueClip(QueuedMessage.compoundMessageIdentifier + "laptime", gapFillerLapTime);
                        }

                        if (enableLapTimeMessages && currentState.SessionType == (int)Constant.Session.Qualify || currentState.SessionType == (int)Constant.Session.Practice)
                        {
                            if (CommonData.isHotLapping)
                            {
                                // special case for hot lapping - read best lap message and the laptime
                                audioPlayer.queueClip(QueuedMessage.compoundMessageIdentifier + "laptime", new QueuedMessage(folderLapTimeIntro, null,
                                    TimeSpan.FromSeconds(currentState.LapTimePrevious), 0, this));
                                if (lastLapRating == LastLapRating.BEST_IN_CLASS || currentLapTimeDeltaToLeadersBest <= TimeSpan.Zero)
                                {
                                    audioPlayer.queueClip(folderPersonalBest, 0, this);
                                }
                                else if (currentLapTimeDeltaToLeadersBest < TimeSpan.FromMilliseconds(50))
                                {
                                    audioPlayer.queueClip(folderLessThanATenthOffThePace, 0, this);
                                }
                                else if (currentLapTimeDeltaToLeadersBest < TimeSpan.MaxValue)
                                {
                                    audioPlayer.queueClip(QueuedMessage.compoundMessageIdentifier + "_lapTimeNotRaceGap",
                                        new QueuedMessage(folderGapIntro, folderGapOutroOffPace, currentLapTimeDeltaToLeadersBest, 0, this));
                                }
                            }
                            else if (lastLapRating == LastLapRating.BEST_IN_CLASS)
                            {
                                audioPlayer.queueClip(folderFastestInClass, 0, this);
                                if (sessionBestLapTimeDeltaToLeader < TimeSpan.Zero)
                                {
                                    TimeSpan gapBehind = sessionBestLapTimeDeltaToLeader.Negate();
                                    if ((gapBehind.Seconds > 0 || gapBehind.Milliseconds > 50) &&
                                        gapBehind.Seconds < 60)
                                    {
                                        // delay this a bit...
                                        audioPlayer.queueClip(QueuedMessage.compoundMessageIdentifier + "_lapTimeNotRaceGap",
                                                new QueuedMessage(folderGapIntro, folderQuickerThanSecondPlace, gapBehind,
                                                    random.Next(0, 20), this));
                                    }
                                }
                            }
                            else if (lastLapRating == LastLapRating.BEST_OVERALL)
                            {
                                if (currentState.SessionType == (int)Constant.Session.Qualify)
                                {
                                    audioPlayer.queueClip(Position.folderPole, 0, this);
                                }
                                else if (currentState.SessionType == (int)Constant.Session.Practice)
                                {
                                    audioPlayer.queueClip(Position.folderStub + currentState.Position, 0, this);
                                }
                                if (sessionBestLapTimeDeltaToLeader < TimeSpan.Zero)
                                {
                                    TimeSpan gapBehind = sessionBestLapTimeDeltaToLeader.Negate();
                                    if ((gapBehind.Seconds > 0 || gapBehind.Milliseconds > 50) &&
                                        gapBehind.Seconds < 60)
                                    {
                                        // delay this a bit...
                                        audioPlayer.queueClip(QueuedMessage.compoundMessageIdentifier + "_lapTimeNotRaceGap",
                                                new QueuedMessage(folderGapIntro, folderQuickerThanSecondPlace, gapBehind,
                                                    random.Next(0, 20), this));
                                    }
                                }
                            }
                            else
                            {
                                if (lastLapRating == LastLapRating.PERSONAL_BEST_STILL_SLOW || lastLapRating == LastLapRating.PERSONAL_BEST_CLOSE_TO_CLASS_LEADER ||
                                    lastLapRating == LastLapRating.PERSONAL_BEST_CLOSE_TO_OVERALL_LEADER)
                                {
                                    audioPlayer.queueClip(folderPersonalBest, 0, this);
                                }
                                if (getLapTimeBestForClassLeader(currentState) > 0)
                                {
                                    // don't read this message if the rounded time gap is 0.0 seconds or it's more than 59 seconds
                                    if ((sessionBestLapTimeDeltaToLeader.Seconds > 0 || sessionBestLapTimeDeltaToLeader.Milliseconds > 50) &&
                                        sessionBestLapTimeDeltaToLeader.Seconds < 60)
                                    {
                                        // delay this a bit...
                                        audioPlayer.queueClip(QueuedMessage.compoundMessageIdentifier + "_lapTimeNotRaceGap",
                                                new QueuedMessage(folderGapIntro, folderGapOutroOffPace, sessionBestLapTimeDeltaToLeader,
                                                    random.Next(0, 20), this));
                                    }
                                }
                            }
                        }
                        else if (enableLapTimeMessages && CommonData.isRaceRunning)
                        {
                            Boolean playedLapMessage = false;
                            float pearlLikelihood = 0.8f;
                            switch (lastLapRating)
                            {
                                case LastLapRating.BEST_OVERALL:
                                    playedLapMessage = true;
                                    audioPlayer.queueClip(folderBestLapInRace, 0, this, PearlsOfWisdom.PearlType.GOOD, pearlLikelihood);
                                    break;
                                case LastLapRating.BEST_IN_CLASS:
                                    playedLapMessage = true;
                                    audioPlayer.queueClip(folderBestLapInRaceForClass, 0, this, PearlsOfWisdom.PearlType.GOOD, pearlLikelihood);
                                    break;
                                case LastLapRating.PERSONAL_BEST_CLOSE_TO_OVERALL_LEADER:
                                case LastLapRating.PERSONAL_BEST_CLOSE_TO_CLASS_LEADER:
                                    playedLapMessage = true;
                                    audioPlayer.queueClip(folderGoodLap, 0, this, PearlsOfWisdom.PearlType.GOOD, pearlLikelihood);
                                    break;
                                case LastLapRating.PERSONAL_BEST_STILL_SLOW:
                                    playedLapMessage = true;
                                    audioPlayer.queueClip(folderPersonalBest, 0, this, PearlsOfWisdom.PearlType.NEUTRAL, pearlLikelihood);
                                    break;
                                case LastLapRating.CLOSE_TO_OVERALL_LEADER:
                                case LastLapRating.CLOSE_TO_CLASS_LEADER:
                                    // this is an OK lap but not a PB. We only want to say "decent lap" occasionally here
                                    if (random.NextDouble() > 0.8)
                                    {
                                        playedLapMessage = true;
                                        audioPlayer.queueClip(folderGoodLap, 0, this, PearlsOfWisdom.PearlType.NEUTRAL, pearlLikelihood);
                                    }
                                    break;
                                default:
                                    break;
                            }
                            // play the consistency message if we've not played the good lap message, or sometimes
                            // play them both
                            Boolean playConsistencyMessage = !playedLapMessage || random.NextDouble() < 0.25;
                            if (playConsistencyMessage && currentState.CompletedLaps >= lastConsistencyUpdate + lapTimesWindowSize &&
                                lapTimesWindow.Count >= lapTimesWindowSize)
                            {
                                ConsistencyResult consistency = checkAgainstPreviousLaps();
                                if (consistency == ConsistencyResult.CONSISTENT)
                                {
                                    lastConsistencyUpdate = currentState.CompletedLaps;
                                    audioPlayer.queueClip(folderConsistentTimes, 0, this);
                                }
                                else if (consistency == ConsistencyResult.IMPROVING)
                                {
                                    lastConsistencyUpdate = currentState.CompletedLaps;
                                    audioPlayer.queueClip(folderImprovingTimes, 0, this);
                                }
                                if (consistency == ConsistencyResult.WORSENING)
                                {
                                    lastConsistencyUpdate = currentState.CompletedLaps;
                                    audioPlayer.queueClip(folderWorseningTimes, 0, this);
                                }
                            }
                        }
                    }
                }
                lapIsValid = true;
            }
        }
示例#41
0
        protected override void triggerInternal(Data.Shared lastState, Data.Shared currentState)
        {
            // in race sessions (race only) the previousLapTime isn't set to -1 if that lap was invalid, so
            // we need to record that it's invalid while we're actually on the lap
            if (CommonData.isSessionRunning && lapIsValid && currentState.CompletedLaps > 0 &&
                !CommonData.isNewLap && currentState.LapTimeCurrent == -1)
            {
                lapIsValid = false;
            }
            if (CommonData.isSessionRunning && CommonData.isNewLap && currentState.CompletedLaps > 1 &&
                currentState.LapTimePrevious > 0)
            {
                if (lapTimesWindow == null)
                {
                    lapTimesWindow = new List<float>(lapTimesWindowSize);
                }

                lapTimesWindow.Insert(0, currentState.LapTimePrevious);
                Boolean playedLapMessage = false;
                if (lapIsValid)
                {
                    // queue the actual laptime as a 'gap filler' - this is only played if the
                    // queue would otherwise be empty
                    if (readLapTimes)
                    {
                        QueuedMessage gapFillerLapTime = new QueuedMessage(folderLapTimeIntro, null,
                        TimeSpan.FromSeconds(currentState.LapTimePrevious), 0, this);
                        gapFillerLapTime.gapFiller = true;
                        audioPlayer.queueClip(QueuedMessage.compoundMessageIdentifier + "laptime", gapFillerLapTime);
                    }

                    LastLapRating lastLapRating = getLastLapRating(currentState);
                    float currentLapTimeDeltaToLeader = getLapTimeDeltaToClassLeader(currentState);
                    if (lapDeltaToClassLeaderAtLastLap != -1 && (currentState.SessionType == (int)Constant.Session.Qualify ||
                        currentState.SessionType == (int)Constant.Session.Practice))
                    {
                        if (readLapTimes)
                        {
                            audioPlayer.queueClip(QueuedMessage.compoundMessageIdentifier + "_lapTimeNotRaceTime",
                                    new QueuedMessage(folderLapTimeIntro, null, TimeSpan.FromSeconds(currentState.LapTimePrevious), 0, this));
                        }
                        // time delta to leader has changed to report it
                        if (lapDeltaToClassLeaderAtLastLap != currentLapTimeDeltaToLeader)
                        {
                            if (lastLapRating == LastLapRating.BEST_IN_CLASS)
                            {
                                audioPlayer.queueClip(folderFastestInClass, 0, this);
                            }
                            else if (lastLapRating == LastLapRating.BEST_OVERALL)
                            {
                                if (currentState.SessionType == (int)Constant.Session.Qualify)
                                {
                                    audioPlayer.queueClip(Position.folderPole, 0, this);
                                }
                            }
                            else if (getLapTimeBestForClassLeader(currentState) > 0)
                            {
                                // don't read this message if the rounded time gap is 0.0 seconds
                                TimeSpan gap = TimeSpan.FromSeconds(currentState.LapTimeBest - getLapTimeBestForClassLeader(currentState));
                                if (gap.Seconds > 0 || gap.Milliseconds > 50)
                                {
                                    // delay this a bit...
                                    audioPlayer.queueClip(QueuedMessage.compoundMessageIdentifier + "_lapTimeNotRaceGap",
                                            new QueuedMessage(folderGapIntro, folderGapOutroOffPace, gap,
                                                new Random().Next(0, 20), this));
                                }
                            }
                        }
                        else if (lastLapRating == LastLapRating.PERSONAL_BEST_STILL_SLOW || lastLapRating == LastLapRating.PERSONAL_BEST_CLOSE_TO_CLASS_LEADER ||
                                lastLapRating == LastLapRating.PERSONAL_BEST_CLOSE_TO_OVERALL_LEADER)
                        {
                            audioPlayer.queueClip(folderPersonalBest, 0, this);
                        }
                    }
                    else
                    {
                        float pearlLikelihood = 0f;
                        if (CommonData.isRaceStarted)
                        {
                            pearlLikelihood = 0.8f;
                        }
                        switch (lastLapRating)
                        {
                            case LastLapRating.BEST_OVERALL:
                                audioPlayer.queueClip(folderBestLapInRace, 0, this, PearlsOfWisdom.PearlType.GOOD, pearlLikelihood);
                                playedLapMessage = true;
                                break;
                            case LastLapRating.BEST_IN_CLASS:
                                audioPlayer.queueClip(folderBestLapInRaceForClass, 0, this, PearlsOfWisdom.PearlType.GOOD, pearlLikelihood);
                                playedLapMessage = true;
                                break;
                            case LastLapRating.PERSONAL_BEST_CLOSE_TO_OVERALL_LEADER:
                            case LastLapRating.PERSONAL_BEST_CLOSE_TO_CLASS_LEADER:
                                audioPlayer.queueClip(folderGoodLap, 0, this, PearlsOfWisdom.PearlType.GOOD, pearlLikelihood);
                                playedLapMessage = true;
                                break;
                            case LastLapRating.PERSONAL_BEST_STILL_SLOW:
                                audioPlayer.queueClip(folderPersonalBest, 0, this, PearlsOfWisdom.PearlType.NEUTRAL, pearlLikelihood);
                                playedLapMessage = true;
                                break;
                            case LastLapRating.CLOSE_TO_OVERALL_LEADER:
                            case LastLapRating.CLOSE_TO_CLASS_LEADER:
                                audioPlayer.queueClip(folderGoodLap, 0, this, PearlsOfWisdom.PearlType.NEUTRAL, pearlLikelihood);
                                playedLapMessage = true;
                                break;
                            default:
                                break;
                        }
                    }
                    lapDeltaToClassLeaderAtLastLap = currentLapTimeDeltaToLeader;
                }
                if (currentState.SessionType == (int)Constant.Session.Race && !playedLapMessage &&
                    currentState.CompletedLaps >= lastConsistencyUpdate + lapTimesWindowSize && lapTimesWindow.Count >= lapTimesWindowSize)
                {
                    ConsistencyResult consistency = checkAgainstPreviousLaps();
                    if (consistency == ConsistencyResult.CONSISTENT)
                    {
                        lastConsistencyUpdate = currentState.CompletedLaps;
                        audioPlayer.queueClip(folderConsistentTimes, 0, this);
                    }
                    else if (consistency == ConsistencyResult.IMPROVING)
                    {
                        lastConsistencyUpdate = currentState.CompletedLaps;
                        audioPlayer.queueClip(folderImprovingTimes, 0, this);
                    }
                    if (consistency == ConsistencyResult.WORSENING)
                    {
                        lastConsistencyUpdate = currentState.CompletedLaps;
                        audioPlayer.queueClip(folderWorseningTimes, 0, this);
                    }
                }
                lapIsValid = true;
            }
        }
示例#42
0
 private void playNextMessage(int carsOnLeftCount, int carsOnRightCount, DateTime now)
 {
     if (nextMessageType != NextMessageType.none && now > nextMessageDue)
     {
         if (messageIsValid(nextMessageType, carsOnLeftCount, carsOnRightCount))
         {
             switch (nextMessageType)
             {
                 case NextMessageType.threeWide:
                     audioPlayer.removeImmediateClip(folderStillThere);
                     audioPlayer.removeImmediateClip(folderCarLeft);
                     audioPlayer.removeImmediateClip(folderCarRight);
                     audioPlayer.removeImmediateClip(folderClearAllRound);
                     audioPlayer.removeImmediateClip(folderClearLeft);
                     audioPlayer.removeImmediateClip(folderClearRight);
                     QueuedMessage inTheMiddleMessage = new QueuedMessage(folderInTheMiddle, 0, null);
                     inTheMiddleMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + inTheMiddleMessageExpiresAfter;
                     audioPlayer.playClipImmediately(inTheMiddleMessage, true, true);
                     nextMessageType = NextMessageType.stillThere;
                     nextMessageDue = now.Add(repeatHoldFrequency);
                     reportedOverlapLeft = true;
                     reportedOverlapRight = true;
                     wasInMiddle = true;
                     break;
                 case NextMessageType.carLeft:
                     audioPlayer.removeImmediateClip(folderStillThere);
                     audioPlayer.removeImmediateClip(folderInTheMiddle);
                     audioPlayer.removeImmediateClip(folderCarRight);
                     audioPlayer.removeImmediateClip(folderClearAllRound);
                     audioPlayer.removeImmediateClip(folderClearLeft);
                     audioPlayer.removeImmediateClip(folderClearRight);
                     QueuedMessage carLeftMessage = new QueuedMessage(folderCarLeft, 0, null);
                     carLeftMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + holdMessageExpiresAfter;
                     audioPlayer.playClipImmediately(carLeftMessage, true, true);
                     nextMessageType = NextMessageType.stillThere;
                     nextMessageDue = now.Add(repeatHoldFrequency);
                     reportedOverlapLeft = true;
                     break;
                 case NextMessageType.carRight:
                     audioPlayer.removeImmediateClip(folderStillThere);
                     audioPlayer.removeImmediateClip(folderCarLeft);
                     audioPlayer.removeImmediateClip(folderInTheMiddle);
                     audioPlayer.removeImmediateClip(folderClearAllRound);
                     audioPlayer.removeImmediateClip(folderClearLeft);
                     audioPlayer.removeImmediateClip(folderClearRight);
                     QueuedMessage carRightMessage = new QueuedMessage(folderCarRight, 0, null);
                     carRightMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + holdMessageExpiresAfter;
                     audioPlayer.playClipImmediately(carRightMessage, true, true);
                     nextMessageType = NextMessageType.stillThere;
                     nextMessageDue = now.Add(repeatHoldFrequency);
                     reportedOverlapRight = true;
                     break;
                 case NextMessageType.clearAllRound:
                     if (reportedOverlapLeft || reportedOverlapRight)
                     {
                         QueuedMessage clearAllRoundMessage = new QueuedMessage(folderClearAllRound, 0, null);
                         clearAllRoundMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + clearAllRoundMessageExpiresAfter;
                         audioPlayer.removeImmediateClip(folderCarLeft);
                         audioPlayer.removeImmediateClip(folderStillThere);
                         audioPlayer.removeImmediateClip(folderCarRight);
                         audioPlayer.removeImmediateClip(folderInTheMiddle);
                         audioPlayer.removeImmediateClip(folderClearLeft);
                         audioPlayer.removeImmediateClip(folderClearRight);
                         audioPlayer.playClipImmediately(clearAllRoundMessage, false);
                         nextMessageType = NextMessageType.none;
                     }
                     audioPlayer.closeChannel();
                     reportedOverlapLeft = false;
                     reportedOverlapRight = false;
                     wasInMiddle = false;
                     break;
                 case NextMessageType.clearLeft:
                     if (reportedOverlapLeft)
                     {
                         if (carsOnRightCount == 0 && wasInMiddle)
                         {
                             QueuedMessage clearAllRoundMessage = new QueuedMessage(folderClearAllRound, 0, null);
                             clearAllRoundMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + clearMessageExpiresAfter;
                             audioPlayer.removeImmediateClip(folderCarLeft);
                             audioPlayer.removeImmediateClip(folderStillThere);
                             audioPlayer.removeImmediateClip(folderCarRight);
                             audioPlayer.removeImmediateClip(folderInTheMiddle);
                             audioPlayer.removeImmediateClip(folderClearRight);
                             audioPlayer.removeImmediateClip(folderClearLeft);
                             audioPlayer.playClipImmediately(clearAllRoundMessage, false);
                             nextMessageType = NextMessageType.none;
                             audioPlayer.closeChannel();
                             reportedOverlapRight = false;
                             wasInMiddle = false;
                         }
                         else
                         {
                             QueuedMessage clearLeftMessage = new QueuedMessage(folderClearLeft, 0, null);
                             clearLeftMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + clearMessageExpiresAfter;
                             audioPlayer.removeImmediateClip(folderCarLeft);
                             audioPlayer.removeImmediateClip(folderStillThere);
                             audioPlayer.removeImmediateClip(folderCarRight);
                             audioPlayer.removeImmediateClip(folderInTheMiddle);
                             audioPlayer.removeImmediateClip(folderClearRight);
                             audioPlayer.removeImmediateClip(folderClearAllRound);
                             audioPlayer.playClipImmediately(clearLeftMessage, false);
                             if (wasInMiddle)
                             {
                                 nextMessageType = NextMessageType.carRight;
                                 nextMessageDue = now.Add(repeatHoldFrequency);
                             }
                             else
                             {
                                 nextMessageType = NextMessageType.none;
                             }
                         }
                     }
                     if (carsOnRightCount == 0)
                     {
                         audioPlayer.closeChannel();
                     }
                     reportedOverlapLeft = false;
                     break;
                 case NextMessageType.clearRight:
                     if (reportedOverlapRight)
                     {
                         if (carsOnLeftCount == 0 && wasInMiddle)
                         {
                             QueuedMessage clearAllRoundMessage = new QueuedMessage(folderClearAllRound, 0, null);
                             clearAllRoundMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + clearMessageExpiresAfter;
                             audioPlayer.removeImmediateClip(folderCarLeft);
                             audioPlayer.removeImmediateClip(folderStillThere);
                             audioPlayer.removeImmediateClip(folderCarRight);
                             audioPlayer.removeImmediateClip(folderInTheMiddle);
                             audioPlayer.removeImmediateClip(folderClearLeft);
                             audioPlayer.removeImmediateClip(folderClearRight);
                             audioPlayer.playClipImmediately(clearAllRoundMessage, false);
                             nextMessageType = NextMessageType.none;
                             audioPlayer.closeChannel();
                             reportedOverlapLeft = false;
                             wasInMiddle = false;
                         }
                         else
                         {
                             QueuedMessage clearRightMessage = new QueuedMessage(folderClearRight, 0, null);
                             clearRightMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + clearMessageExpiresAfter;
                             audioPlayer.removeImmediateClip(folderCarLeft);
                             audioPlayer.removeImmediateClip(folderStillThere);
                             audioPlayer.removeImmediateClip(folderCarRight);
                             audioPlayer.removeImmediateClip(folderInTheMiddle);
                             audioPlayer.removeImmediateClip(folderClearLeft);
                             audioPlayer.removeImmediateClip(folderClearAllRound);
                             audioPlayer.playClipImmediately(clearRightMessage, false);
                             if (wasInMiddle)
                             {
                                 nextMessageType = NextMessageType.carLeft;
                                 nextMessageDue = now.Add(repeatHoldFrequency);
                             }
                             else
                             {
                                 nextMessageType = NextMessageType.none;
                             }
                         }
                     }
                     if (carsOnLeftCount == 0)
                     {
                         audioPlayer.closeChannel();
                     }
                     reportedOverlapRight = false;
                     break;
                 case NextMessageType.stillThere:
                     if (reportedOverlapLeft || reportedOverlapRight)
                     {
                         QueuedMessage holdYourLineMessage = new QueuedMessage(folderStillThere, 0, null);
                         holdYourLineMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + holdMessageExpiresAfter;
                         audioPlayer.removeImmediateClip(folderClearRight);
                         audioPlayer.removeImmediateClip(folderClearLeft);
                         audioPlayer.removeImmediateClip(folderClearAllRound);
                         audioPlayer.playClipImmediately(holdYourLineMessage, true, false);
                         nextMessageType = NextMessageType.stillThere;
                         nextMessageDue = now.Add(repeatHoldFrequency);
                     }
                     break;
                 case NextMessageType.none:
                     break;
             }
         }
         else
         {
             audioPlayer.closeChannel();
             reportedOverlapLeft = false;
             reportedOverlapRight = false;
         }
     }
 }
示例#43
0
        protected override void triggerInternal(Shared lastState, Shared currentState)
        {
            DateTime now = DateTime.Now;

            float currentSpeed = currentState.CarSpeed;
            float previousSpeed = lastState.CarSpeed;
            if (enabled && CommonData.isRaceRunning &&
                currentState.Player.GameSimulationTime > timeAfterRaceStartToActivate &&
                currentState.ControlType == (int)Constant.Control.Player && currentSpeed > minSpeedForSpotterToOperate)
            {
                channelLeftOpenTimerStarted = false;
                timeWhenChannelShouldBeClosed = now.Add(timeToWaitBeforeClosingChannelLeftOpen);
                float currentDeltaFront = currentState.TimeDeltaFront;
                float currentDeltaBehind = currentState.TimeDeltaBehind;
                float previousDeltaFront = lastState.TimeDeltaFront;
                float previousDeltaBehind = lastState.TimeDeltaBehind;

                if (checkDelta(currentDeltaFront, currentSpeed) && checkDelta(currentDeltaBehind, currentSpeed) &&
                    checkDelta(previousDeltaFront, previousSpeed) && checkDelta(previousDeltaBehind, previousSpeed))
                {
                    lastSpotterDataIsUsable = true;
                    // if we think there's already a car along side, add a little to the car length so we're
                    // sure it's gone before calling clear
                    float carLengthToUse = carLength;
                    if (isCurrentlyOverlapping)
                    {
                        carLengthToUse += gapNeededForClear;
                    }
                    // the time deltas might be small negative numbers while the cars are along side. They might also be large
                    // negative numbers if the data are noisy - either way, use the absolute value to check for overlap
                    Boolean carAlongSideInFront = carLengthToUse / currentSpeed > Math.Abs(currentDeltaFront);
                    Boolean carAlongSideBehind = carLengthToUse / currentSpeed > Math.Abs(currentDeltaBehind);

                    if (!carAlongSideInFront && !carAlongSideBehind)
                    {
                        // we're clear here, so when we next detect we're overlapping we know this must be
                        // a new overlap. This may be valid or due to noise.
                        newlyOverlapping = true;
                        if (isCurrentlyOverlapping)
                        {
                            if (newlyClear)
                            {
                                // start the timer...
                                newlyClear = false;
                                timeWhenWeCanSayClear = now.Add(clearMessageDelay);
                            }
                            // only play "clear" if we've been clear for the specified time
                            if (now > timeWhenWeCanSayClear)
                            {
                                // don't play this message if the channel's closed
                                isCurrentlyOverlapping = false;
                                if (audioPlayer.isChannelOpen())
                                {
                                    Console.WriteLine("Clear - delta front = " + currentDeltaFront + " delta behind = " + currentDeltaBehind);
                                    QueuedMessage clearMessage = new QueuedMessage(0, this);
                                    clearMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + clearMessageExpiresAfter;
                                    audioPlayer.removeImmediateClip(folderStillThere);
                                    audioPlayer.playClipImmediately(folderClear, clearMessage);
                                    audioPlayer.closeChannel();
                                }
                                else
                                {
                                    Console.WriteLine("Not playing clear message - channel is already closed");
                                }
                            }
                        }
                    }
                    else
                    {
                        // we're overlapping here, so when we next detect we're 'clear' we know this must be
                        // a new clear. This may be valid or due to noise
                        newlyClear = true;
                        if (newlyOverlapping)
                        {
                            timeWhenWeCanSayHold = now.Add(overlapMessageDelay);
                            newlyOverlapping = false;
                        }
                        if (now > timeWhenWeCanSayHold)
                        {
                            if (isCurrentlyOverlapping)
                            {
                                // play "still there" if we've not played one for a while
                                if (now > timeOfNextHoldMessage)
                                {
                                    // channel's already open, still there
                                    Console.WriteLine("Still there - delta front = " + currentDeltaFront + " delta behind = " + currentDeltaBehind);
                                    timeOfNextHoldMessage = now.Add(repeatHoldFrequency);
                                    QueuedMessage stillThereMessage = new QueuedMessage(0, this);
                                    stillThereMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + holdMessageExpiresAfter;
                                    audioPlayer.playClipImmediately(folderStillThere, stillThereMessage);
                                }
                            }
                            else
                            {
                                // only say a car is overlapping if the closing speed isn't too high
                                float timeElapsed = (float)currentState.Player.GameSimulationTime - (float)lastState.Player.GameSimulationTime;
                                float closingSpeedInFront = (previousDeltaFront - currentDeltaFront) * currentSpeed / timeElapsed;
                                float closingSpeedBehind = (previousDeltaBehind - currentDeltaBehind) * currentSpeed / timeElapsed;

                                if ((carAlongSideInFront && Math.Abs(closingSpeedInFront) < maxClosingSpeed) ||
                                    (carAlongSideBehind && Math.Abs(closingSpeedBehind) < maxClosingSpeed))
                                {
                                    Boolean frontOverlapIsReducing = carAlongSideInFront && closingSpeedInFront > 0;
                                    Boolean rearOverlapIsReducing = carAlongSideBehind && closingSpeedBehind > 0;
                                    if (rearOverlapIsReducing || (frontOverlapIsReducing && !spotterOnlyWhenBeingPassed))
                                    {
                                        Console.WriteLine("New overlap");
                                        Console.WriteLine("delta front  = " + currentDeltaFront + " closing speed front  = " + closingSpeedInFront);
                                        Console.WriteLine("delta behind = " + currentDeltaBehind + " closing speed behind = " + closingSpeedBehind);
                                        timeOfNextHoldMessage = now.Add(repeatHoldFrequency);
                                        isCurrentlyOverlapping = true;
                                        audioPlayer.holdOpenChannel(true);
                                        QueuedMessage holdMessage = new QueuedMessage(0, this);
                                        holdMessage.expiryTime = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + holdMessageExpiresAfter;
                                        audioPlayer.playClipImmediately(folderHoldYourLine, holdMessage);
                                    }
                                }
                            }
                        }
                    }
                }
                else if (isCurrentlyOverlapping)
                {
                    if (lastSpotterDataIsUsable)
                    {
                        // this is the first chunk of unusable data
                        lastSpotterDataIsUsable = false;
                        timeWhenWeveHadEnoughUnusableData = now.Add(maxTimeToKeepChannelOpenWhileReceivingUnusableData);
                    }
                    if (now > timeWhenWeveHadEnoughUnusableData)
                    {
                        Console.WriteLine("Had " + maxTimeToKeepChannelOpenWhileReceivingUnusableData.Seconds + " seconds of unusable spotter data, closing channel");
                        isCurrentlyOverlapping = false;
                        audioPlayer.closeChannel();
                    }
                }
            }
            else if (isCurrentlyOverlapping)
            {
                if (!channelLeftOpenTimerStarted)
                {
                    timeWhenChannelShouldBeClosed = now.Add(timeToWaitBeforeClosingChannelLeftOpen);
                    channelLeftOpenTimerStarted = true;
                }
                if (now > timeWhenChannelShouldBeClosed)
                {
                    Console.WriteLine("Closing channel left open in spotter");
                    timeWhenChannelShouldBeClosed = DateTime.MaxValue;
                    isCurrentlyOverlapping = false;
                    audioPlayer.closeChannel();
                    channelLeftOpenTimerStarted = false;
                    isCurrentlyOverlapping = false;
                }
            }
        }