private static void addObjectToMessages(List <MessageFragment> messageFragments, Object o) { if (o == null) { messageFragments.Add(null); } else if (o.GetType() == typeof(String)) { messageFragments.Add(MessageFragment.Text((String)o)); } else if (o.GetType() == typeof(TimeSpan)) { messageFragments.Add(MessageFragment.Time(new TimeSpanWrapper((TimeSpan)o, preferHundredths ? Precision.HUNDREDTHS : Precision.TENTHS))); } else if (o.GetType() == typeof(TimeSpanWrapper)) { messageFragments.Add(MessageFragment.Time((TimeSpanWrapper)o)); } else if (o.GetType() == typeof(OpponentData)) { messageFragments.Add(MessageFragment.Opponent((OpponentData)o)); } else if (o.GetType() == typeof(int) || o.GetType() == typeof(double) || o.GetType() == typeof(float) || o.GetType() == typeof(short) || o.GetType() == typeof(long) || o.GetType() == typeof(decimal) || o.GetType() == typeof(uint)) { messageFragments.Add(MessageFragment.Integer(Convert.ToInt32(o))); } }
public void TryParse_should_not_move_offset_on_invalid_input() { var offset = 1; MessageFragment.TryParse(" %d", ref offset); offset.Should().Be(1); }
public void TryParse_should_move_offset_accordingly() { var offset = 1; MessageFragment.TryParse(" %m", ref offset); offset.Should().Be(3); }
/// <summary> /// Returns a Fragment back to its ObjectPool so it can be used again. /// </summary> /// <param name="fragment"></param> public void ReleaseFragment(MessageFragment fragment) { if (fragment is WritableMessageFragment wmf) { GenericPool <WritableMessageFragment> .Release(wmf); } else if (fragment is ReadOnlyMessageFragment romf) { GenericPool <ReadOnlyMessageFragment> .Release(romf); } }
/// <summary> /// Replaces the Fragments in <see cref="Fragments"/> and returns the previous fragment back to the ObjectPool so it can be reused. /// </summary> /// <param name="original">Fragment to replace.</param> /// <param name="repacement">Replacement Fragment.</param> public void ReplaceFragment(MessageFragment original, MessageFragment repacement) { var index = Fragments.IndexOf(original); if (index == -1) { throw new Exception($"Can not replace Fragment {original.ToString()} that is not part of the message."); } Fragments[index] = repacement; ReleaseFragment(original); }
public override void Build() { if (Chunk.Type > MessageType.SerializedObject) { SerializedObject = ViewContent.Session.GetCachedObject(Chunk.SequenceNumber, Chunk.GetSerializedObject); } Fragment fragment; double height; if (Chunk.Type == MessageType.ConnectionBanner && ViewContent.Session.ConnectionBanner != null) { // show connection info instead "Connecting to ..." fragment = new ConnectionFragment() { Model = ViewContent.Session.ConnectionBanner }; height = 76; } else if (Chunk.Type == MessageType.SslHandshake) { fragment = new SslHandshakeFragment() { Model = (SslHandshake)SerializedObject }; height = 45; } else { fragment = new MessageFragment(); height = 56; } ViewContent.MoveInsertionPointToLineBeginning(); fragment.Source = this; fragment.Bounds = new Rect(0, ViewContent.InsertionPoint.Y, ViewContent.Metrics.Viewport.Width, ViewContent.SnapToPixelsY(height)); fragment.ApproxFileOffset = Chunk.ActualOffset; fragment.ApproxFileLength = Chunk.ActualLength; ViewContent.TextLayer.Add(fragment); ViewContent.MoveInsertionPointToLineBeginning(); }
private void messageInterruptTest() { PlaybackModerator.SetTracing(true /*enabled*/); List <String> rawDriverNames = new List <string>(); List <MessageFragment> fragments = new List <MessageFragment>(); fragments.Add(MessageFragment.Text(Strategy.folderClearTrackOnPitExit)); fragments.Add(MessageFragment.Text(Strategy.folderWeShouldEmergeInPosition)); fragments.Add(MessageFragment.Integer(12)); fragments.Add(MessageFragment.Text(Strategy.folderBetween)); fragments.Add(MessageFragment.Opponent(makeTempDriver("bakus", rawDriverNames))); fragments.Add(MessageFragment.Text(Strategy.folderAnd)); fragments.Add(MessageFragment.Opponent(makeTempDriver("fillingham", rawDriverNames))); audioPlayer.playMessage(new QueuedMessage("check", 0, messageFragments: fragments, abstractEvent: this)); audioPlayer.wakeMonitorThreadForRegularMessages(DateTime.UtcNow); fragments = new List <MessageFragment>(); fragments.Add(MessageFragment.Text(Strategy.folderClearTrackOnPitExit)); fragments.Add(MessageFragment.Text(Strategy.folderWeShouldEmergeInPosition)); fragments.Add(MessageFragment.Integer(12)); fragments.Add(MessageFragment.Text(Strategy.folderBetween)); fragments.Add(MessageFragment.Opponent(makeTempDriver("bakus", rawDriverNames))); fragments.Add(MessageFragment.Text(Strategy.folderAnd)); fragments.Add(MessageFragment.Opponent(makeTempDriver("fillingham", rawDriverNames))); audioPlayer.playMessage(new QueuedMessage("check", 0, messageFragments: fragments, abstractEvent: this)); audioPlayer.wakeMonitorThreadForRegularMessages(DateTime.UtcNow); Thread.Sleep(2500); audioPlayer.playMessageImmediately(new QueuedMessage(NoisyCartesianCoordinateSpotter.folderEnableSpotter, 0)); QueuedMessage inTheMiddleMessage = new QueuedMessage("spotter/in_the_middle", 0); //inTheMiddleMessage.expiryTime = (DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond) + 2000; audioPlayer.playSpotterMessage(inTheMiddleMessage, true); }
private static void addObjectToMessages(List <MessageFragment> messageFragments, Object o) { if (o == null) { messageFragments.Add(null); } else if (o.GetType() == typeof(String)) { messageFragments.Add(MessageFragment.Text((String)o)); } else if (o.GetType() == typeof(TimeSpan)) { messageFragments.Add(MessageFragment.Time((TimeSpan)o)); } else if (o.GetType() == typeof(OpponentData)) { messageFragments.Add(MessageFragment.Opponent((OpponentData)o)); } else if (o.GetType() == typeof(int) || o.GetType() == typeof(double) || o.GetType() == typeof(float) || o.GetType() == typeof(short) || o.GetType() == typeof(long) || o.GetType() == typeof(decimal) || o.GetType() == typeof(uint)) { messageFragments.Add(MessageFragment.Integer(Convert.ToInt32(o))); } }
override protected void triggerInternal(GameStateData previousGameState, GameStateData currentGameState) { var cgs = currentGameState; var pgs = previousGameState; if (cgs.PitData.InPitlane || /*|| cgs.SessionData.SessionRunningTime < 10 */ GameStateData.onManualFormationLap || // We may want manual formation to phase of FrozenOrder. pgs == null) { return; // don't process if we're in the pits or just started a session } var cfod = cgs.FrozenOrderData; var pfod = pgs.FrozenOrderData; var cfodp = cgs.FrozenOrderData.Phase; if (cfodp == FrozenOrderPhase.None) { return; // Nothing to do. } var useAmericanTerms = GlobalBehaviourSettings.useAmericanTerms || GlobalBehaviourSettings.useOvalLogic; var useOvalLogic = GlobalBehaviourSettings.useOvalLogic; if (pfod.Phase == FrozenOrderPhase.None) { Console.WriteLine("Frozen Order: New Phase detected: " + cfod.Phase); int delay = Utilities.random.Next(0, 3); if (cfod.Phase == FrozenOrderPhase.Rolling) { audioPlayer.playMessage(new QueuedMessage(folderRollingStartReminder, delay + 4, secondsDelay: delay, abstractEvent: this, priority: 10)); } else if (cfod.Phase == FrozenOrderPhase.FormationStanding) { audioPlayer.playMessage(new QueuedMessage(folderStandingStartReminder, delay + 4, secondsDelay: delay, abstractEvent: this, priority: 10)); } // Clear previous state. this.clearState(); } // Because FO Action is distance dependent, it tends to fluctuate. // We need to detect when it stabilizes (values stay identical for ACTION_STABLE_THRESHOLD times). if (cfod.Action == pfod.Action && cfod.DriverToFollowRaw == pfod.DriverToFollowRaw && cfod.AssignedColumn == pfod.AssignedColumn) { ++this.numUpdatesActionSame; } else { this.newFrozenOrderAction = cfod.Action; this.newDriverToFollow = cfod.DriverToFollowRaw; this.newFrozenOrderColumn = cfod.AssignedColumn; this.numUpdatesActionSame = 0; } var isActionUpdateStable = this.numUpdatesActionSame >= FrozenOrderMonitor.ACTION_STABLE_THRESHOLD; // Detect if we should be following SC, as SC has no driver name. var shouldFollowSafetyCar = false; var driverToFollow = ""; if (cfodp == FrozenOrderPhase.Rolling || cfodp == FrozenOrderPhase.FullCourseYellow) { shouldFollowSafetyCar = (cfod.AssignedColumn == FrozenOrderColumn.None && cfod.AssignedPosition == 1) || // Single file order. (cfod.AssignedColumn != FrozenOrderColumn.None && cfod.AssignedPosition <= 2); // Double file (grid) order. driverToFollow = shouldFollowSafetyCar ? (useAmericanTerms ? folderThePaceCar : folderTheSafetyCar) : cfod.DriverToFollowRaw; } if (cfodp == FrozenOrderPhase.Rolling) { var prevDriverToFollow = this.currDriverToFollow; var prevFrozenOrderAction = this.currFrozenOrderAction; if (isActionUpdateStable && (this.currFrozenOrderAction != this.newFrozenOrderAction || this.currDriverToFollow != this.newDriverToFollow || this.currFrozenOrderColumn != this.newFrozenOrderColumn)) { this.currFrozenOrderAction = this.newFrozenOrderAction; this.currDriverToFollow = this.newDriverToFollow; this.currFrozenOrderColumn = this.newFrozenOrderColumn; // canReadDriverToFollow will be true if we're behind the safety car or we can read the driver's name: var canReadDriverToFollow = shouldFollowSafetyCar || AudioPlayer.canReadName(driverToFollow); var usableDriverNameToFollow = shouldFollowSafetyCar ? driverToFollow : DriverNameHelper.getUsableDriverName(driverToFollow); var validationData = new Dictionary <string, object>(); validationData.Add(FrozenOrderMonitor.validateMessageTypeKey, FrozenOrderMonitor.validateMessageTypeAction); validationData.Add(FrozenOrderMonitor.validationActionKey, cfod.Action); validationData.Add(FrozenOrderMonitor.validationAssignedPositionKey, cfod.AssignedPosition); validationData.Add(FrozenOrderMonitor.validationDriverToFollowKey, cfod.DriverToFollowRaw); if (this.newFrozenOrderAction == FrozenOrderAction.Follow && prevDriverToFollow != this.currDriverToFollow) // Don't announce Follow messages for the driver that we caught up to or allowed to pass. { if (canReadDriverToFollow) { // Follow messages are only meaningful if there's name to announce. int delay = Utilities.random.Next(3, 6); if (cfod.AssignedColumn == FrozenOrderColumn.None || Utilities.random.Next(1, 11) > 8) // Randomly, announce message without coulmn info. { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/follow_driver" : "frozen_order/follow_safety_car", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderFollow, usableDriverNameToFollow), abstractEvent: this, validationData: validationData, priority: 10)); } else { string columnName; if (useOvalLogic) { columnName = cfod.AssignedColumn == FrozenOrderColumn.Left ? folderInTheInsideColumn : folderInTheOutsideColumn; } else { columnName = cfod.AssignedColumn == FrozenOrderColumn.Left ? folderInTheLeftColumn : folderInTheRightColumn; } audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/follow_driver_in_col" : "frozen_order/follow_safecy_car_in_col", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderFollow, usableDriverNameToFollow, columnName), abstractEvent: this, validationData: validationData, priority: 10)); } } } else if (this.newFrozenOrderAction == FrozenOrderAction.AllowToPass) { // Follow messages are only meaningful if there's name to announce. int delay = Utilities.random.Next(1, 4); if (canReadDriverToFollow && Utilities.random.Next(1, 11) > 2) // Randomly, announce message without name. { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/allow_driver_to_pass" : "frozen_order/allow_safety_car_to_pass", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderAllow, usableDriverNameToFollow, folderToPass), abstractEvent: this, validationData: validationData, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage(folderYoureAheadOfAGuyYouShouldBeFollowing, delay + 6, secondsDelay: delay, abstractEvent: this, validationData: validationData, priority: 10)); } } else if (this.newFrozenOrderAction == FrozenOrderAction.CatchUp) { int delay = Utilities.random.Next(1, 4); if (canReadDriverToFollow && Utilities.random.Next(1, 11) > 2) // Randomly, announce message without name. { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/catch_up_to_driver" : "frozen_order/catch_up_to_safety_car", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderCatchUpTo, usableDriverNameToFollow), abstractEvent: this, validationData: validationData, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage(folderYouNeedToCatchUpToTheGuyAhead, delay + 6, secondsDelay: delay, abstractEvent: this, validationData: validationData, priority: 10)); } } else if (this.newFrozenOrderAction == FrozenOrderAction.StayInPole && prevFrozenOrderAction != FrozenOrderAction.MoveToPole) // No point in nagging user to stay in pole if we previously told them to move there. { int delay = Utilities.random.Next(0, 3); if (cfod.AssignedColumn == FrozenOrderColumn.None || Utilities.random.Next(1, 11) > 8) // Randomly, announce message without coulmn info. { audioPlayer.playMessage(new QueuedMessage("frozen_order/stay_in_pole", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderStayInPole), abstractEvent: this, validationData: validationData, priority: 10)); } else { string folderToPlay = null; if (useOvalLogic) { folderToPlay = cfod.AssignedColumn == FrozenOrderColumn.Left ? folderStayInPoleInInsideColumn : folderStayInPoleInOutsideColumn; } else { folderToPlay = cfod.AssignedColumn == FrozenOrderColumn.Left ? folderStayInPoleInLeftColumn : folderStayInPoleInRightColumn; } audioPlayer.playMessage(new QueuedMessage("frozen_order/stay_in_pole_in_column", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderToPlay), abstractEvent: this, validationData: validationData, priority: 10)); } } else if (this.newFrozenOrderAction == FrozenOrderAction.MoveToPole) { int delay = Utilities.random.Next(2, 5); if (cfod.AssignedColumn == FrozenOrderColumn.None) { audioPlayer.playMessage(new QueuedMessage("frozen_order/move_to_pole", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderMoveToPole), abstractEvent: this, validationData: validationData, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage("frozen_order/move_to_pole_row", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderMoveToPoleRow), abstractEvent: this, validationData: validationData, priority: 10)); } } } } else if (cfodp == FrozenOrderPhase.FullCourseYellow) { var prevDriverToFollow = this.currDriverToFollow; var prevFrozenOrderColumn = this.currFrozenOrderColumn; var announceSCRLastFCYLapLane = useAmericanTerms && currentGameState.StockCarRulesData.stockCarRulesEnabled && (currentGameState.FlagData.fcyPhase == FullCourseYellowPhase.LAST_LAP_NEXT || currentGameState.FlagData.fcyPhase == FullCourseYellowPhase.LAST_LAP_CURRENT); if (isActionUpdateStable && (this.currFrozenOrderAction != this.newFrozenOrderAction || this.currDriverToFollow != this.newDriverToFollow || this.currFrozenOrderColumn != this.newFrozenOrderColumn || announceSCRLastFCYLapLane && !this.scrLastFCYLapLaneAnnounced)) { this.currFrozenOrderAction = this.newFrozenOrderAction; this.currDriverToFollow = this.newDriverToFollow; this.currFrozenOrderColumn = this.newFrozenOrderColumn; this.scrLastFCYLapLaneAnnounced = announceSCRLastFCYLapLane; // canReadDriverToFollow will be true if we're behind the safety car or we can read the driver's name: var canReadDriverToFollow = shouldFollowSafetyCar || AudioPlayer.canReadName(driverToFollow); var usableDriverNameToFollow = shouldFollowSafetyCar ? driverToFollow : DriverNameHelper.getUsableDriverName(driverToFollow); var validationData = new Dictionary <string, object>(); validationData.Add(FrozenOrderMonitor.validateMessageTypeKey, FrozenOrderMonitor.validateMessageTypeAction); validationData.Add(FrozenOrderMonitor.validationActionKey, cfod.Action); validationData.Add(FrozenOrderMonitor.validationAssignedPositionKey, cfod.AssignedPosition); validationData.Add(FrozenOrderMonitor.validationDriverToFollowKey, cfod.DriverToFollowRaw); if (this.newFrozenOrderAction == FrozenOrderAction.Follow && ((prevDriverToFollow != this.currDriverToFollow) || // Don't announce Follow messages for the driver that we caught up to or allowed to pass. (prevFrozenOrderColumn != this.currFrozenOrderColumn && announceSCRLastFCYLapLane))) // But announce for SCR last FCY lap. { int delay = Utilities.random.Next(0, 3); if (canReadDriverToFollow) { if (announceSCRLastFCYLapLane && cfod.AssignedColumn == FrozenOrderColumn.Left) { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/follow_driver_in_left" : "frozen_order/follow_safety_car_in_left", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderFollow, usableDriverNameToFollow, useOvalLogic ? folderInTheInsideColumn : folderInTheLeftColumn), abstractEvent: this, validationData: validationData, priority: 10)); } else if (announceSCRLastFCYLapLane && cfod.AssignedColumn == FrozenOrderColumn.Right) { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/follow_driver_in_right" : "frozen_order/follow_safety_car_in_right", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderFollow, usableDriverNameToFollow, useOvalLogic ? folderInTheOutsideColumn : folderInTheRightColumn), abstractEvent: this, validationData: validationData, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/follow_driver" : "frozen_order/follow_safety_car", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderFollow, usableDriverNameToFollow), abstractEvent: this, validationData: validationData, priority: 10)); } } else if (announceSCRLastFCYLapLane && cfod.AssignedColumn == FrozenOrderColumn.Left) { audioPlayer.playMessage(new QueuedMessage(useOvalLogic ? folderLineUpInInsideColumn : folderLineUpInLeftColumn, delay + 6, secondsDelay: delay, abstractEvent: this, validationData: validationData, priority: 10)); } else if (announceSCRLastFCYLapLane && cfod.AssignedColumn == FrozenOrderColumn.Right) { audioPlayer.playMessage(new QueuedMessage(useOvalLogic ? folderLineUpInOutsideColumn : folderLineUpInRightColumn, delay + 6, secondsDelay: delay, abstractEvent: this, validationData: validationData, priority: 10)); } } else if (this.newFrozenOrderAction == FrozenOrderAction.AllowToPass) { int delay = Utilities.random.Next(1, 4); if (canReadDriverToFollow && Utilities.random.Next(1, 11) > 2) // Randomly, announce message without name. { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/allow_driver_to_pass" : "frozen_order/allow_safety_car_to_pass", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderAllow, usableDriverNameToFollow, folderToPass), abstractEvent: this, validationData: validationData, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage(folderYoureAheadOfAGuyYouShouldBeFollowing, delay + 6, secondsDelay: delay, abstractEvent: this, validationData: validationData, priority: 10)); } } else if (this.newFrozenOrderAction == FrozenOrderAction.CatchUp) { int delay = Utilities.random.Next(1, 4); if (canReadDriverToFollow && Utilities.random.Next(1, 11) > 2) // Randomly, announce message without name. { audioPlayer.playMessage(new QueuedMessage(!shouldFollowSafetyCar ? "frozen_order/catch_up_to_driver" : "frozen_order/catch_up_to_safety_car", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderCatchUpTo, usableDriverNameToFollow), abstractEvent: this, validationData: validationData, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage(folderYouNeedToCatchUpToTheGuyAhead, delay + 6, secondsDelay: delay, abstractEvent: this, validationData: validationData, priority: 10)); } } } } else if (cfodp == FrozenOrderPhase.FormationStanding) { string columnName = null; if (cfod.AssignedColumn != FrozenOrderColumn.None) { if (useOvalLogic) { columnName = cfod.AssignedColumn == FrozenOrderColumn.Left ? folderInTheInsideColumn : folderInTheOutsideColumn; } else { columnName = cfod.AssignedColumn == FrozenOrderColumn.Left ? folderInTheLeftColumn : folderInTheRightColumn; } } if (!this.formationStandingStartAnnounced && cgs.SessionData.SessionRunningTime > 10) { this.formationStandingStartAnnounced = true; var isStartingFromPole = cfod.AssignedPosition == 1; int delay = Utilities.random.Next(0, 3); if (isStartingFromPole) { if (columnName == null) { audioPlayer.playMessage(new QueuedMessage(folderWereStartingFromPole, 6, abstractEvent: this)); } else { audioPlayer.playMessage(new QueuedMessage("frozen_order/youre_starting_from_pole_in_column", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderWereStartingFromPole, columnName), abstractEvent: this, priority: 10)); } } else { if (columnName == null) { audioPlayer.playMessage(new QueuedMessage("frozen_order/youre_starting_from_pos", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderWeStartingFromPosition, cfod.AssignedPosition), abstractEvent: this, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage("frozen_order/youre_starting_from_pos_row_in_column", delay + 6, secondsDelay: delay, messageFragments: MessageContents(folderWeStartingFromPosition, cfod.AssignedPosition, folderRow, cfod.AssignedGridPosition, columnName), abstractEvent: this, priority: 10)); } } } if (!this.formationStandingPreStartReminderAnnounced && cgs.SessionData.SectorNumber == 3 && cgs.PositionAndMotionData.DistanceRoundTrack > (cgs.SessionData.TrackDefinition.trackLength - FrozenOrderMonitor.DIST_TO_START_TO_ANNOUNCE_POS_REMINDER)) { this.formationStandingPreStartReminderAnnounced = true; var isStartingFromPole = cfod.AssignedPosition == 1; int delay = Utilities.random.Next(0, 3); if (isStartingFromPole) { if (columnName == null) { audioPlayer.playMessage(new QueuedMessage("frozen_order/get_ready_starting_from_pole", delay + 6, secondsDelay: delay, messageFragments: MessageContents(LapCounter.folderGetReady, folderWereStartingFromPole), abstractEvent: this, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage("frozen_order/get_ready_starting_from_pole_in_column", delay + 6, secondsDelay: delay, messageFragments: MessageContents(LapCounter.folderGetReady, folderWereStartingFromPole, columnName), abstractEvent: this, priority: 10)); } } else { if (columnName == null) { audioPlayer.playMessage(new QueuedMessage("frozen_order/get_ready_youre_starting_from_pos", delay + 6, secondsDelay: delay, messageFragments: MessageContents(LapCounter.folderGetReady, folderWeStartingFromPosition, cfod.AssignedPosition), abstractEvent: this, priority: 10)); } else { audioPlayer.playMessage(new QueuedMessage("frozen_order/get_ready_youre_starting_from_pos_row_in_column", delay + 6, secondsDelay: delay, messageFragments: MessageContents(LapCounter.folderGetReady, folderWeStartingFromPosition, cfod.AssignedPosition, folderRow, cfod.AssignedGridPosition, columnName), abstractEvent: this, priority: 10)); } } } } // Announce SC speed. if (pfod.SafetyCarSpeed == -1.0f && cfod.SafetyCarSpeed != -1.0f) { // TODO: may also need to announce basic "SC in" message. var kmPerHour = cfod.SafetyCarSpeed * 3.6f; var messageFragments = new List <MessageFragment>(); if (useAmericanTerms) { messageFragments.Add(MessageFragment.Text(FrozenOrderMonitor.folderPaceCarSpeedIs)); var milesPerHour = kmPerHour * 0.621371f; messageFragments.Add(MessageFragment.Integer((int)Math.Round(milesPerHour), false)); messageFragments.Add(MessageFragment.Text(FrozenOrderMonitor.folderMilesPerHour)); } else { messageFragments.Add(MessageFragment.Text(FrozenOrderMonitor.folderSafetyCarSpeedIs)); messageFragments.Add(MessageFragment.Integer((int)Math.Round(kmPerHour), false)); messageFragments.Add(MessageFragment.Text(FrozenOrderMonitor.folderKilometresPerHour)); } int delay = Utilities.random.Next(10, 16); audioPlayer.playMessage(new QueuedMessage("frozen_order/pace_car_speed", delay + 6, secondsDelay: delay, messageFragments: messageFragments, abstractEvent: this, priority: 10)); } // Announce SC left. if (pfod.SafetyCarSpeed != -1.0f && cfod.SafetyCarSpeed == -1.0f) { if (useAmericanTerms) { audioPlayer.playMessage(new QueuedMessage(folderPaceCarJustLeft, 10, abstractEvent: this)); } else { audioPlayer.playMessage(new QueuedMessage(folderSafetyCarJustLeft, 10, abstractEvent: this)); } } // For fast rolling, do nothing for now. }
/// <summary> /// This function handles turning a bundle of messages (representing all messages accrued in a timeslice), /// into 1 or more packets, combining multiple messages into one packet or spliting large message across /// several packets as needed. /// </summary> /// <param name="bundle"></param> private void SendBundle(NetworkBundle bundle) { log.DebugFormat("[{0}] Sending Bundle", session.LoggingIdentifier); bool writeOptionalHeaders = true; List <MessageFragment> fragments = new List <MessageFragment>(); // Pull all messages out and create MessageFragment objects while (bundle.HasMoreMessages) { var message = bundle.Dequeue(); var fragment = new MessageFragment(message, ConnectionData.FragmentSequence++); fragments.Add(fragment); } log.DebugFormat("[{0}] Bundle Fragment Count: {1}", session.LoggingIdentifier, fragments.Count); // Loop through while we have fragements while (fragments.Count > 0 || writeOptionalHeaders) { ServerPacket packet = new ServerPacket(); PacketHeader packetHeader = packet.Header; if (fragments.Count > 0) { packetHeader.Flags |= PacketHeaderFlags.BlobFragments; } if (bundle.EncryptedChecksum) { packetHeader.Flags |= PacketHeaderFlags.EncryptedChecksum; } uint availableSpace = Packet.MaxPacketDataSize; // Pull first message and see if it is a large one var firstMessage = fragments.FirstOrDefault(); if (firstMessage != null) { // If a large message send only this one, filling the whole packet if (firstMessage.DataRemaining >= availableSpace) { log.DebugFormat("[{0}] Sending large fragment", session.LoggingIdentifier); ServerPacketFragment spf = firstMessage.GetNextFragment(); packet.Fragments.Add(spf); availableSpace -= (uint)spf.Length; if (firstMessage.DataRemaining <= 0) { fragments.Remove(firstMessage); } } // Otherwise we'll write any optional headers and process any small messages that will fit else { if (writeOptionalHeaders) { writeOptionalHeaders = false; WriteOptionalHeaders(bundle, packet); availableSpace -= (uint)packet.Data.Length; } // Create a list to remove completed messages after iterator List <MessageFragment> removeList = new List <MessageFragment>(); foreach (MessageFragment fragment in fragments) { // Is this a large fragment and does it have a tail that needs sending? if (!fragment.TailSent && availableSpace >= fragment.TailSize) { log.DebugFormat("[{0}] Sending tail fragment", session.LoggingIdentifier); ServerPacketFragment spf = fragment.GetTailFragment(); packet.Fragments.Add(spf); availableSpace -= (uint)spf.Length; } // Otherwise will this message fit in the remaining space? else if (availableSpace >= fragment.NextSize) { log.DebugFormat("[{0}] Sending small message", session.LoggingIdentifier); ServerPacketFragment spf = fragment.GetNextFragment(); packet.Fragments.Add(spf); availableSpace -= (uint)spf.Length; } // If message is out of data, set to remove it if (fragment.DataRemaining <= 0) { removeList.Add(fragment); } } // Remove all completed messages fragments.RemoveAll(x => removeList.Contains(x)); } } // If no messages, write optional headers else { log.DebugFormat("[{0}] No messages, just sending optional headers", session.LoggingIdentifier); if (writeOptionalHeaders) { writeOptionalHeaders = false; WriteOptionalHeaders(bundle, packet); availableSpace -= (uint)packet.Data.Length; } } EnqueueSend(packet); } }
public override void respond(String voiceMessage) { if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_ADD)) { int amount = 0; foreach (KeyValuePair <String[], int> entry in SpeechRecogniser.numberToNumber) { foreach (String numberStr in entry.Key) { if (voiceMessage.Contains(" " + numberStr + " ")) { amount = entry.Value; break; } } } if (amount == 0) { audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderDidntUnderstand, 0)); return; } if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.LITERS)) { AddFuel(amount); audioPlayer.playMessageImmediately(new QueuedMessage("iracing_add_fuel", 0, messageFragments: MessageContents(AudioPlayer.folderAcknowlegeOK, amount, amount == 1 ? Fuel.folderLitre : Fuel.folderLitres))); } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.GALLONS)) { AddFuel(convertGallonsToLitres(amount)); audioPlayer.playMessageImmediately(new QueuedMessage("iracing_add_fuel", 0, messageFragments: MessageContents(AudioPlayer.folderAcknowlegeOK, amount, amount == 1 ? Fuel.folderGallon : Fuel.folderGallons))); } else { Console.WriteLine("Got fuel request with no unit, assuming " + (Fuel.fuelReportsInGallon ? " gallons" : "litres")); if (!Fuel.fuelReportsInGallon) { AddFuel(amount); audioPlayer.playMessageImmediately(new QueuedMessage("iracing_add_fuel", 0, messageFragments: MessageContents(AudioPlayer.folderAcknowlegeOK, amount, amount == 1 ? Fuel.folderLitre : Fuel.folderLitres))); } else { AddFuel(convertGallonsToLitres(amount)); audioPlayer.playMessageImmediately(new QueuedMessage("iracing_add_fuel", 0, messageFragments: MessageContents(AudioPlayer.folderAcknowlegeOK, amount, amount == 1 ? Fuel.folderGallon : Fuel.folderGallons))); } } return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_FUEL_TO_THE_END)) { Fuel fuelEvent = (Fuel)CrewChief.getEvent("Fuel"); float litresNeeded = fuelEvent.getLitresToEndOfRace(true); if (litresNeeded == float.MaxValue) { audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderNoData, 0)); } else if (litresNeeded <= 0) { audioPlayer.playMessageImmediately(new QueuedMessage(Fuel.folderPlentyOfFuel, 0)); } else if (litresNeeded > 0) { int roundedLitresNeeded = (int)Math.Ceiling(litresNeeded); AddFuel(roundedLitresNeeded); if (roundedLitresNeeded > fuelCapacity - currentFuel) { // if we have a known fuel capacity and this is less than the calculated amount of fuel we need, warn about it. audioPlayer.playMessage(new QueuedMessage(Fuel.folderWillNeedToStopAgain, 0, secondsDelay: 4, abstractEvent: this)); } else { audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderFuelToEnd, 0)); } return; } } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_TEAROFF)) { Tearoff(); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_FAST_REPAIR)) { FastRepair(); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CLEAR_ALL)) { ClearAll(); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CLEAR_TYRES)) { ClearTires(); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CLEAR_WIND_SCREEN)) { ClearTearoff(); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CLEAR_FAST_REPAIR)) { ClearFastRepair(); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CLEAR_FUEL)) { ClearFuel(); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_TYRE_PRESSURE) || SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_FRONT_LEFT_TYRE_PRESSURE) || SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_FRONT_RIGHT_TYRE_PRESSURE) || SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_REAR_LEFT_TYRE_PRESSURE) || SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_REAR_RIGHT_TYRE_PRESSURE)) { int amount = 0; foreach (KeyValuePair <String[], int> entry in SpeechRecogniser.numberToNumber) { foreach (String numberStr in entry.Key) { if (voiceMessage.Contains(" " + numberStr)) { amount = entry.Value; break; } } } if (amount == 0) { audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderDidntUnderstand, 0)); return; } else { if (pressureUnit == PressureUnit.PSI) { amount = convertPSItoKPA(amount); } if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_TYRE_PRESSURE)) { ChangeTire(PitCommandModeTypes.LF, amount); ChangeTire(PitCommandModeTypes.RF, amount); ChangeTire(PitCommandModeTypes.LR, amount); ChangeTire(PitCommandModeTypes.RR, amount); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_FRONT_LEFT_TYRE_PRESSURE)) { ChangeTire(PitCommandModeTypes.LF, amount); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_FRONT_RIGHT_TYRE_PRESSURE)) { ChangeTire(PitCommandModeTypes.RF, amount); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_REAR_LEFT_TYRE_PRESSURE)) { ChangeTire(PitCommandModeTypes.LR, amount); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_REAR_RIGHT_TYRE_PRESSURE)) { ChangeTire(PitCommandModeTypes.RR, amount); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } } } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_ALL_TYRES)) { ChangeTire(PitCommandModeTypes.LF, lastColdFLPressure); ChangeTire(PitCommandModeTypes.RF, lastColdFRPressure); ChangeTire(PitCommandModeTypes.LR, lastColdRLPressure); ChangeTire(PitCommandModeTypes.RR, lastColdRRPressure); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_FRONT_LEFT_TYRE)) { ChangeTire(PitCommandModeTypes.LF, lastColdFLPressure); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_FRONT_RIGHT_TYRE)) { ChangeTire(PitCommandModeTypes.RF, lastColdFRPressure); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_REAR_LEFT_TYRE)) { ChangeTire(PitCommandModeTypes.LR, lastColdRLPressure); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_REAR_RIGHT_TYRE)) { ChangeTire(PitCommandModeTypes.RR, lastColdRRPressure); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_LEFT_SIDE_TYRES)) { ClearTires(); ChangeTire(PitCommandModeTypes.LF, lastColdFLPressure); ChangeTire(PitCommandModeTypes.LR, lastColdRLPressure); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.PIT_STOP_CHANGE_RIGHT_SIDE_TYRES)) { ClearTires(); ChangeTire(PitCommandModeTypes.RF, lastColdFRPressure); ChangeTire(PitCommandModeTypes.RR, lastColdRRPressure); audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderAcknowlegeOK, 0)); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.HOW_MANY_INCIDENT_POINTS)) { audioPlayer.playMessageImmediately(new QueuedMessage("Incidents/incidents", 0, messageFragments: MessageContents(folderYouHave, incidentsCount, folderincidents))); return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.WHATS_THE_INCIDENT_LIMIT)) { if (hasLimitedIncidents) { audioPlayer.playMessageImmediately(new QueuedMessage("Incidents/limit", 0, messageFragments: MessageContents(folderincidentlimit, maxIncidentCount))); } else { audioPlayer.playMessageImmediately(new QueuedMessage("Incidents/limit", 0, messageFragments: MessageContents(folderUnlimited))); } return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.WHATS_MY_IRATING)) { if (iRating != -1) { audioPlayer.playMessageImmediately(new QueuedMessage("license/irating", 0, messageFragments: MessageContents(iRating))); return; } else { audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderNoData, 0)); return; } } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.WHATS_MY_LICENSE_CLASS)) { if (licenseLevel.Item2 == -1) { audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderNoData, 0)); return; } if (licenseLevel.Item2 != -1) { Tuple <int, int> wholeandfractional = Utilities.WholeAndFractionalPart(licenseLevel.Item2, 2); List <MessageFragment> messageFragments = new List <MessageFragment>(); if (licenseLevel.Item1.ToLower() == "a") { messageFragments.Add(MessageFragment.Text(folderLicenseA)); } else if (licenseLevel.Item1.ToLower() == "b") { messageFragments.Add(MessageFragment.Text(folderLicenseB)); } else if (licenseLevel.Item1.ToLower() == "c") { messageFragments.Add(MessageFragment.Text(folderLicenseC)); } else if (licenseLevel.Item1.ToLower() == "d") { messageFragments.Add(MessageFragment.Text(folderLicenseD)); } else if (licenseLevel.Item1.ToLower() == "r") { messageFragments.Add(MessageFragment.Text(folderLicenseR)); } else if (licenseLevel.Item1.ToLower() == "wc") { messageFragments.Add(MessageFragment.Text(folderLicensePro)); } else { audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderNoData, 0)); return; } messageFragments.AddRange(MessageContents(wholeandfractional.Item1, NumberReader.folderPoint, wholeandfractional.Item2)); QueuedMessage licenceLevelMessage = new QueuedMessage("License/license", 0, messageFragments: messageFragments); audioPlayer.playDelayedImmediateMessage(licenceLevelMessage); } return; } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.WHATS_THE_SOF)) { if (strenghtOfField != -1) { audioPlayer.playMessageImmediately(new QueuedMessage("license/irating", 0, messageFragments: MessageContents(strenghtOfField))); return; } else { audioPlayer.playMessageImmediately(new QueuedMessage(AudioPlayer.folderNoData, 0)); return; } } }
public bool soundTestPlay(String[] foldersOrStuff, int messageNumber = 1) { List <String> rawDriverNames = new List <string>(); List <MessageFragment> fragments = new List <MessageFragment>(); if (foldersOrStuff.Length > 0 && File.Exists(foldersOrStuff[0])) { foldersOrStuff = File.ReadAllLines(foldersOrStuff[0]); } int iter = 0; String messageName = ""; foreach (String stuffToPlay in foldersOrStuff) { messageName = "sound_test_message_" + messageNumber.ToString(); iter++; int num; bool isNumeric = int.TryParse(stuffToPlay, out num); if (stuffToPlay.StartsWith("#") || stuffToPlay.Length < 1) { continue; } if (stuffToPlay.StartsWith("&")) { String [] nextNessage = new String [foldersOrStuff.Length - iter]; Array.Copy(foldersOrStuff, iter, nextNessage, 0, foldersOrStuff.Length - iter); audioPlayer.playMessageImmediately(new QueuedMessage(messageName, 0, messageFragments: fragments, abstractEvent: this, type: SoundType.IMPORTANT_MESSAGE, priority: 0)); messageNumber++; return(soundTestPlay(nextNessage, messageNumber)); } if (isNumeric) { fragments.Add(MessageFragment.Integer(num)); } else if (stuffToPlay.ToLower().StartsWith("pause")) { String pauseLength = stuffToPlay.Substring(6); isNumeric = int.TryParse(pauseLength, out num); if (isNumeric) { fragments.Add(MessageFragment.Text(Pause(num))); } } else if (stuffToPlay.ToLower().StartsWith("name")) { String nameToMake = stuffToPlay.Substring(5); fragments.Add(MessageFragment.Opponent(makeTempDriver(nameToMake, rawDriverNames))); } else if (stuffToPlay.ToLower().StartsWith("time")) { float time = 0; String timeToMake = ""; Precision precision = Precision.AUTO_LAPTIMES; timeToMake = stuffToPlay.Substring(9); isNumeric = float.TryParse(timeToMake, out time); if (isNumeric) { if (stuffToPlay.ToLower().Contains("lap")) { precision = Precision.AUTO_LAPTIMES; } else if (stuffToPlay.ToLower().Contains("gap")) { precision = Precision.AUTO_GAPS; } else if (stuffToPlay.ToLower().Contains("hun")) { precision = Precision.HUNDREDTHS; } else if (stuffToPlay.ToLower().Contains("sec")) { precision = Precision.SECONDS; } else if (stuffToPlay.ToLower().Contains("ten")) { precision = Precision.TENTHS; } fragments.Add(MessageFragment.Time(TimeSpanWrapper.FromSeconds(time, precision))); } } else { fragments.Add(MessageFragment.Text(stuffToPlay)); } } audioPlayer.playMessageImmediately(new QueuedMessage(messageName, 0, messageFragments: fragments, abstractEvent: this, type: SoundType.IMPORTANT_MESSAGE, priority: 0)); return(true); }
public void TryParse_should_parse_fragment() { var offset = 1; MessageFragment.TryParse(" %m", ref offset).Should().Be(new MessageFragment()); }
public void TryParse_should_be_case_insensitive() { var offset = 1; MessageFragment.TryParse(" %M", ref offset).Should().NotBeNull(); }
public void TryParse_should_return_null_on_invalid_input(string input) { var offset = 1; MessageFragment.TryParse(input, ref offset).Should().BeNull(); }
/// <summary> /// This function handles turning a bundle of messages (representing all messages accrued in a timeslice), /// into 1 or more packets, combining multiple messages into one packet or spliting large message across /// several packets as needed. /// /// 1 Create Packet /// 2 If first packet for this bundle, fill any optional headers /// 3 Append fragments that will fit /// 3.1 Check each fragment to see if it is a partial fit /// 4 If we have a partial message remaining or more messages, create additional packets. /// </summary> /// <param name="bundle"></param> private void SendBundle(NetworkBundle bundle) { bool firstPacket = true; MessageFragment carryOverMessage = null; while (firstPacket || carryOverMessage != null || bundle.Messages.Count > 0) { ServerPacket packet = new ServerPacket(); PacketHeader packetHeader = packet.Header; if (bundle.encryptedChecksum) { packetHeader.Flags |= PacketHeaderFlags.EncryptedChecksum; } uint availableSpace = Packet.MaxPacketDataSize; if (firstPacket) { firstPacket = false; if (bundle.SendAck) //0x4000 { packetHeader.Flags |= PacketHeaderFlags.AckSequence; packet.BodyWriter.Write(lastReceivedSequence); } if (bundle.TimeSync) //0x1000000 { packetHeader.Flags |= PacketHeaderFlags.TimeSynch; packet.BodyWriter.Write(ConnectionData.ServerTime); } if (bundle.ClientTime != -1f) //0x4000000 { packetHeader.Flags |= PacketHeaderFlags.EchoResponse; packet.BodyWriter.Write(bundle.ClientTime); packet.BodyWriter.Write((float)ConnectionData.ServerTime - bundle.ClientTime); } availableSpace -= (uint)packet.Data.Length; } if (carryOverMessage != null || bundle.Messages.Count > 0) { packetHeader.Flags |= PacketHeaderFlags.BlobFragments; while (carryOverMessage != null || bundle.Messages.Count > 0) { if (availableSpace <= PacketFragmentHeader.HeaderSize + 4) { break; } MessageFragment currentMessageFragment; if (carryOverMessage != null) { currentMessageFragment = carryOverMessage; carryOverMessage = null; currentMessageFragment.index++; } else { currentMessageFragment = new MessageFragment(bundle.Messages.Dequeue()); } var currentGameMessage = currentMessageFragment.message; ServerPacketFragment fragment = new ServerPacketFragment(); PacketFragmentHeader fragmentHeader = fragment.Header; availableSpace -= PacketFragmentHeader.HeaderSize; currentMessageFragment.sequence = currentMessageFragment.sequence == 0 ? ConnectionData.FragmentSequence++ : currentMessageFragment.sequence; uint dataToSend = (uint)currentGameMessage.Data.Length - currentMessageFragment.position; if (dataToSend > availableSpace) { dataToSend = availableSpace; carryOverMessage = currentMessageFragment; } if (currentMessageFragment.count == 0) { uint remainingData = (uint)currentGameMessage.Data.Length - dataToSend; currentMessageFragment.count = (ushort)(Math.Ceiling((double)remainingData / PacketFragment.MaxFragmentDataSize) + 1); } fragmentHeader.Sequence = currentMessageFragment.sequence; fragmentHeader.Id = 0x80000000; fragmentHeader.Count = currentMessageFragment.count; fragmentHeader.Index = currentMessageFragment.index; fragmentHeader.Group = (ushort)currentMessageFragment.message.Group; currentGameMessage.Data.Seek(currentMessageFragment.position, SeekOrigin.Begin); fragment.Content = new byte[dataToSend]; currentGameMessage.Data.Read(fragment.Content, 0, (int)dataToSend); currentMessageFragment.position = currentMessageFragment.position + dataToSend; availableSpace -= dataToSend; packet.AddFragment(fragment); //break; } } PacketQueue.Enqueue(packet); } }
/// <summary> /// This function handles turning a bundle of messages (representing all messages accrued in a timeslice), /// into 1 or more packets, combining multiple messages into one packet or spliting large message across /// several packets as needed. /// /// 1 Create Packet /// 2 If first packet for this bundle, fill any optional headers /// 3 Append messages that will fit /// 4 If we have more messages, create additional packets. /// 5 If any packet is greater than the max packet size, split it across two fragments /// </summary> /// <param name="bundle"></param> private void SendBundle(NetworkBundle bundle) { bool firstPacket = true; MessageFragment carryOverMessage = null; while (firstPacket || carryOverMessage != null || bundle.Messages.Count > 0) { ServerPacket packet = new ServerPacket(); PacketHeader packetHeader = packet.Header; if (bundle.EncryptedChecksum) { packetHeader.Flags |= PacketHeaderFlags.EncryptedChecksum; } uint availableSpace = Packet.MaxPacketDataSize; if (firstPacket) { firstPacket = false; if (bundle.SendAck) //0x4000 { packetHeader.Flags |= PacketHeaderFlags.AckSequence; packet.BodyWriter.Write(lastReceivedSequence); } if (bundle.TimeSync) //0x1000000 { packetHeader.Flags |= PacketHeaderFlags.TimeSynch; packet.BodyWriter.Write(ConnectionData.ServerTime); } if (bundle.ClientTime != -1f) //0x4000000 { packetHeader.Flags |= PacketHeaderFlags.EchoResponse; packet.BodyWriter.Write(bundle.ClientTime); packet.BodyWriter.Write((float)ConnectionData.ServerTime - bundle.ClientTime); } availableSpace -= (uint)packet.Data.Length; } if (carryOverMessage != null || bundle.Messages.Count > 0) { packetHeader.Flags |= PacketHeaderFlags.BlobFragments; int fragmentCount = 0; while (carryOverMessage != null || bundle.Messages.Count > 0) { MessageFragment currentMessageFragment; if (carryOverMessage != null) // If we have a carryOverMessage, use that { currentMessageFragment = carryOverMessage; carryOverMessage = null; } else // If we don't have a carryOverMessage, go ahead and dequeue next message from the bundle { currentMessageFragment = new MessageFragment(bundle.Messages.Dequeue()); } var currentGameMessage = currentMessageFragment.message; availableSpace -= PacketFragmentHeader.HeaderSize; // Account for fragment header // Compute amount of data to send based on the total length and current position uint dataToSend = (uint)currentGameMessage.Data.Length - currentMessageFragment.position; if (dataToSend > availableSpace) // Message is too large to fit in packet { carryOverMessage = currentMessageFragment; if (fragmentCount == 0) // If this is first message in packet, this is just a really large message, so proceed with splitting it { dataToSend = availableSpace; } else // Otherwise there are other messages already, so we'll break and come back and see if the message will fit { break; } } if (currentMessageFragment.count == 0) // Compute number of fragments if we have not already { uint remainingData = (uint)currentGameMessage.Data.Length - dataToSend; currentMessageFragment.count = (ushort)(Math.Ceiling((double)remainingData / PacketFragment.MaxFragmentDataSize) + 1); } // Set sequence, if new, pull next sequence from ConnectionData, if it is a carryOver, reuse that sequence currentMessageFragment.sequence = currentMessageFragment.sequence == 0 ? ConnectionData.FragmentSequence++ : currentMessageFragment.sequence; // Build ServerPacketFragment structure ServerPacketFragment fragment = new ServerPacketFragment(); PacketFragmentHeader fragmentHeader = fragment.Header; fragmentHeader.Sequence = currentMessageFragment.sequence; fragmentHeader.Id = 0x80000000; fragmentHeader.Count = currentMessageFragment.count; fragmentHeader.Index = currentMessageFragment.index; fragmentHeader.Group = (ushort)currentMessageFragment.message.Group; // Read data starting at current position reading dataToSend bytes currentGameMessage.Data.Seek(currentMessageFragment.position, SeekOrigin.Begin); fragment.Content = new byte[dataToSend]; currentGameMessage.Data.Read(fragment.Content, 0, (int)dataToSend); // Increment position and index currentMessageFragment.position = currentMessageFragment.position + dataToSend; currentMessageFragment.index++; // Add fragment to packet packet.AddFragment(fragment); fragmentCount++; // Deduct consumed space availableSpace -= dataToSend; // Smallest message I am aware of requires HeaderSize + 4 bytes, so if we have less space then that, go ahead and break if (availableSpace <= PacketFragmentHeader.HeaderSize + 4) { break; } } } PacketQueue.Enqueue(packet); } }
public override void respond(string voiceMessage) { if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.SESSION_STATUS) || SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.STATUS)) { if (hasOutstandingPenalty) { if (lapsCompleted - penaltyLap == 2) { audioPlayer.playMessageImmediately(new QueuedMessage("youHaveAPenaltyBoxThisLap", 0, messageFragments: MessageContents(folderYouHavePenalty, PitStops.folderMandatoryPitStopsPitThisLap))); } else { audioPlayer.playMessageImmediately(new QueuedMessage(folderYouHavePenalty, 0)); } } } else { if (!hasHadAPenalty) { audioPlayer.playMessageImmediately(new QueuedMessage(folderYouDontHaveAPenalty, 0)); return; } if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.DO_I_HAVE_A_PENALTY)) { if (hasOutstandingPenalty) { if (lapsCompleted - penaltyLap == 2) { audioPlayer.playMessageImmediately(new QueuedMessage("youHaveAPenaltyBoxThisLap", 0, messageFragments: MessageContents(folderYouHavePenalty, PitStops.folderMandatoryPitStopsPitThisLap))); } else { audioPlayer.playMessageImmediately(new QueuedMessage(folderYouHavePenalty, 0)); } } else { audioPlayer.playMessageImmediately(new QueuedMessage(folderYouDontHaveAPenalty, 0)); } } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.HAVE_I_SERVED_MY_PENALTY)) { if (hasOutstandingPenalty) { List <MessageFragment> messages = new List <MessageFragment>(); messages.Add(MessageFragment.Text(AudioPlayer.folderNo)); messages.Add(MessageFragment.Text(folderYouStillHavePenalty)); if (lapsCompleted - penaltyLap == 2) { messages.Add(MessageFragment.Text(PitStops.folderMandatoryPitStopsPitThisLap)); } audioPlayer.playMessageImmediately(new QueuedMessage("noYouStillHaveAPenalty", 0, messageFragments: messages)); } else { audioPlayer.playMessageImmediately(new QueuedMessage("yesYouServedYourPenalty", 0, messageFragments: MessageContents(AudioPlayer.folderYes, folderPenaltyServed))); } } else if (SpeechRecogniser.ResultContains(voiceMessage, SpeechRecogniser.DO_I_STILL_HAVE_A_PENALTY)) { if (hasOutstandingPenalty) { List <MessageFragment> messages = new List <MessageFragment>(); messages.Add(MessageFragment.Text(AudioPlayer.folderYes)); messages.Add(MessageFragment.Text(folderYouStillHavePenalty)); if (lapsCompleted - penaltyLap == 2) { messages.Add(MessageFragment.Text(PitStops.folderMandatoryPitStopsPitThisLap)); } audioPlayer.playMessageImmediately(new QueuedMessage("yesYouStillHaveAPenalty", 0, messageFragments: messages)); } else { audioPlayer.playMessageImmediately(new QueuedMessage("noYouServedYourPenalty", 0, messageFragments: MessageContents(AudioPlayer.folderNo, folderPenaltyServed))); } } } }