public override void OnNext(ForzaDataStruct value) { UpdateUI(value); }
protected virtual void UpdateUI(ForzaDataStruct data) { ForzaSledDataStruct sd = data.Sled; lock (SyncRoot) { // line 1 ConsoleWriteAt(5, 0, GetRaceIsOneValue(sd.IsRaceOn), 3, GetRaceIsOneValueColor(sd.IsRaceOn)); ConsoleWriteAt(13, 0, $"{sd.CarOrdinal,11:##0}", 11); ConsoleWriteAt(31, 0, "DCBASRPX"[sd.CarClass].ToString(), 1); ConsoleWriteAt(39, 0, $"{sd.CarPerformanceIndex,3:##0}", 3); ConsoleWriteAt(54, 0, GetDriveTrainValue(sd.DrivetrainType), 3); ConsoleWriteAt(68, 0, string.Format("{0:#0}", sd.NumCylinders), 2); // engine ConsoleWriteAt(8, 3, $"{sd.CurrentEngineRpm,5:####0}", 5, GetCurrentEngineRpmValueColor(sd.CurrentEngineRpm, sd.EngineIdleRpm, sd.EngineMaxRpm)); ConsoleWriteAt(8, 4, $"{sd.EngineIdleRpm,5:####0}", 5); ConsoleWriteAt(8, 5, $"{sd.EngineMaxRpm,5:####0}", 5); // acceleration ConsoleWriteAt(13, 8, $"{sd.AccelerationX,11:###0.000000}", 11); ConsoleWriteAt(25, 8, $"{sd.AccelerationY,11:###0.000000}", 11); ConsoleWriteAt(37, 8, $"{sd.AccelerationZ,11:###0.000000}", 11); // velocity ConsoleWriteAt(13, 9, $"{sd.VelocityX,11:###0.000000}", 11); ConsoleWriteAt(25, 9, $"{sd.VelocityY,11:###0.000000}", 11); ConsoleWriteAt(37, 9, $"{sd.VelocityZ,11:###0.000000}", 11); // angle ConsoleWriteAt(13, 12, $"{sd.Yaw,11:###0.000000}", 11); ConsoleWriteAt(25, 12, $"{sd.Pitch,11:###0.000000}", 11); ConsoleWriteAt(37, 12, $"{sd.Roll,11:###0.000000}", 11); // angular velocity ConsoleWriteAt(13, 13, $"{sd.AngularVelocityX,11:###0.000000}", 11); ConsoleWriteAt(25, 13, $"{sd.AngularVelocityY,11:###0.000000}", 11); ConsoleWriteAt(37, 13, $"{sd.AngularVelocityZ,11:###0.000000}", 11); ForzaCarDashDataStruct cdd = data.CarDash; // line 2 ConsoleWriteAt(4, 1, $"{cdd.LapNumber + 1}", 3); ConsoleWriteAt(17, 1, $"{cdd.RacePosition}", 2); ConsoleWriteAt(25, 1, $"{cdd.Fuel * 100f,5:##0.0}", 5); ConsoleWriteAt(42, 1, $"{cdd.DistanceTraveled / 1000f,5:##0.0}", 5); ConsoleWriteAt(56, 1, GetRaceTimeValue(cdd.CurrentRaceTime), 14); // speed, power, torque ConsoleWriteAt(27, 3, $"{cdd.Speed * 3.6f,7:####0.0}", 7); ConsoleWriteAt(27, 4, $"{cdd.Power / 1000f,7:####0.0}", 7); ConsoleWriteAt(27, 5, $"{cdd.Torque,7:####0.0}", 7); // laps ConsoleWriteAt(50, 3, GetRaceTimeValue(cdd.CurrentLap), 14); ConsoleWriteAt(50, 4, GetRaceTimeValue(cdd.LastLap), 14); ConsoleWriteAt(50, 5, GetRaceTimeValue(cdd.BestLap), 14); // controls ConsoleWriteAt(63, 7, $"{cdd.Accel / 2.55f,3:##0}", 3); ConsoleWriteAt(63, 8, $"{cdd.Brake / 2.55f,3:##0}", 3); ConsoleWriteAt(63, 9, $"{cdd.Clutch / 2.55f,3:##0}", 3); ConsoleWriteAt(63, 10, $"{cdd.HandBrake / 2.55f,3:##0}", 3); ConsoleWriteAt(63, 11, $"{cdd.Gear,3:##0}", 3); ConsoleWriteAt(62, 12, $"{cdd.Steer / 1.27f,3:+0;-0;0}", 4); } }
static void Main(string[] args) { try { _args = PowArgs.Parser <Arguments> .Parse(args); } catch (Exception ex) { Console.Error.WriteLine(ex.Message); ShowHelp(); Exit(ExitCodes.ArgsError); return; } if (_args.Help) { ShowHelp(); Exit(ExitCodes.Help); return; } else if (_args.UseTimestamp == _args.UseStaticFrequency) { Console.Error.WriteLine("You must specify which fix to use: timestamp OR frequency"); ShowHelp(); Exit(ExitCodes.ArgsError); return; } var inputFile = new FileInfo(_args.Input); var outputFile = new FileInfo(_args.Output); string typeOfFix = _args.UseTimestamp ? "timestamp" : _args.UseStaticFrequency ? "fixed frequency" : "unknown"; // input file existence if (!inputFile.Exists) { Console.Error.WriteLine($"Input file {inputFile.Name} is not found or its access is denied"); Exit(ExitCodes.InputError); return; } // output directory creation if (!outputFile.Directory.Exists) { outputFile.Directory.Create(); } Console.Out.WriteLine($"Input: {inputFile.Name}"); Console.Out.WriteLine($"Output: {outputFile.Name}"); Console.Out.WriteLine($"Fix: {typeOfFix}"); // input read using (FileStream input = new FileStream(inputFile.FullName, FileMode.Open, FileAccess.Read)) using (FileStream output = new FileStream(outputFile.FullName, FileMode.Create, FileAccess.Write)) using (SampleReader reader = new SampleReader(input)) using (SampleWriter writer = new SampleWriter(output)) { ForzaDataReader dataReader = new ForzaDataReader(); ForzaDataStruct?firstForzaData = null; ForzaDataStruct?prevForzaData = null; int chunkIndex; // iterate every chunk for (chunkIndex = 0; reader.TryRead(out SampleStruct chunk); chunkIndex++) { // decode forza data structure ForzaDataStruct forzaData = dataReader.Read(chunk.Data); if (!firstForzaData.HasValue) { firstForzaData = forzaData; } // if timestamps are used, validate them if (_args.UseTimestamp) { // non increasing timestamps if (prevForzaData?.Sled.TimestampMS > forzaData.Sled.TimestampMS) { if (_args.IgnoreInvalidChunks) { Console.Out.WriteLine($"Ignoring chunk #{chunkIndex}, {chunk.Length} bytes (non increasing timestamp)"); continue; } else { Console.Error.WriteLine($"Non increasing timestamp at chunk #{chunkIndex}, {chunk.Length} bytes"); Exit(ExitCodes.NonIncreasingTimestamps); break; } } // fixing elapsed ticks from previous chunk timestamp diff uint elapsedMilliseconds = forzaData.Sled.TimestampMS - firstForzaData.Value.Sled.TimestampMS; chunk.Elapsed = TimeSpan.FromMilliseconds(elapsedMilliseconds).Ticks; } else if (_args.UseStaticFrequency) { // fixing elapsed ticks with static chunk time uint elapsedMilliseconds = (uint)Math.Round( chunkIndex * ChunkTime, MidpointRounding.AwayFromZero ); chunk.Elapsed = TimeSpan.FromMilliseconds(elapsedMilliseconds).Ticks; } // fixed chunk written to output writer.Write(chunk); prevForzaData = forzaData; } // warning if not on end of stream if (!reader.EndOfStream) { Console.Error.WriteLine($"Can't decode more chunks, the rest of the source is ignored"); } writer.Flush(); outputFile.Refresh(); // final result Console.Out.WriteLine($"Chunks: {reader.Reads} read, {writer.Writes} written (diff: {writer.Writes - reader.Reads})"); Console.Out.WriteLine($"Size: {inputFile.Length} bytes on input, {outputFile.Length} bytes on output, (diff: {outputFile.Length - inputFile.Length})"); } Exit(ExitCodes.OK); }