Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions Examples/WarThunderExample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ public static async Task BasicStateRecording()
await using var session = new GameSession()
.AddSource(WarThunderSources.CreateStateSource())
.OnData<StateData>(data =>
Console.WriteLine($"Speed: {data.IndicatedAirspeed:F1} km/h, " +
$"Alt: {data.Altitude:F0}m, " +
$"Throttle: {data.Throttle * 100:F0}%"))
Console.WriteLine($"Speed: {data.IndicatedAirspeedKmh:F1} km/h, " +
$"Alt: {data.AltitudeMeters:F0}m, " +
$"Throttle: {data.Throttle1Percent:F0}%"))
.AutoOutput();

Console.WriteLine("Recording War Thunder /state endpoint at 60Hz...");
Expand All @@ -35,7 +35,7 @@ public static async Task MultiEndpointRecording()
.AddSource(WarThunderSources.CreateStateSource(hz: 60)) // 60Hz
.AddSource(WarThunderSources.CreateIndicatorsSource(hz: 10)) // 10Hz
.OnData<StateData>(data =>
Console.WriteLine($"[State] Speed: {data.IndicatedAirspeed:F1} km/h, Alt: {data.Altitude:F0}m"))
Console.WriteLine($"[State] Speed: {data.IndicatedAirspeedKmh:F1} km/h, Alt: {data.AltitudeMeters:F0}m"))
.OnData<IndicatorsData>(data =>
Console.WriteLine($"[Indicators] Oil: {data.OilTemp:F1}°C, Water: {data.WaterTemp:F1}°C"));

Expand All @@ -55,15 +55,15 @@ public static async Task RealtimeOnlyMonitoring()
{
Console.Clear();
Console.WriteLine("=== War Thunder Telemetry ===");
Console.WriteLine($"Speed (IAS): {data.IndicatedAirspeed:F1} km/h");
Console.WriteLine($"Speed (TAS): {data.TrueAirspeed:F1} km/h");
Console.WriteLine($"Altitude: {data.Altitude:F0} m");
Console.WriteLine($"Speed (IAS): {data.IndicatedAirspeedKmh:F1} km/h");
Console.WriteLine($"Speed (TAS): {data.TrueAirspeedKmh:F1} km/h");
Console.WriteLine($"Altitude: {data.AltitudeMeters:F0} m");
Console.WriteLine($"Mach: {data.Mach:F2}");
Console.WriteLine($"AoA: {data.AngleOfAttack:F1}°");
Console.WriteLine($"Throttle: {data.Throttle * 100:F0}%");
Console.WriteLine($"RPM: {data.RPM:F0}");
Console.WriteLine($"AoA: {data.AngleOfAttackDeg:F1}°");
Console.WriteLine($"Throttle: {data.Throttle1Percent:F0}%");
Console.WriteLine($"RPM: {data.Rpm1:F0}");
Console.WriteLine($"G-Force: {data.Ny:F2}g");
Console.WriteLine($"Fuel: {data.Fuel:F1} kg");
Console.WriteLine($"Fuel: {data.FuelMassKg:F1} kg");
});

Console.WriteLine("Starting realtime War Thunder monitoring...");
Expand All @@ -88,7 +88,7 @@ public static async Task CustomConfiguration()
await using var session = new GameSession()
.AddSource(new StateSource(options))
.OnData<StateData>(data =>
Console.WriteLine($"Custom config: Speed={data.IndicatedAirspeed:F1} km/h"));
Console.WriteLine($"Custom config: Speed={data.IndicatedAirspeedKmh:F1} km/h"));

Console.WriteLine("Recording with custom configuration...");
await session.StartAsync();
Expand Down
148 changes: 121 additions & 27 deletions GamesDat.Demo/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ static async Task Main(string[] args)
#region War Thunder
static async Task CaptureWarThunderSession()
{
Console.WriteLine("═══════════════════════════════════════════════════════");
Console.WriteLine(" WAR THUNDER REAL-TIME TELEMETRY MONITOR");
Console.WriteLine("═══════════════════════════════════════════════════════");
Console.WriteLine();
Console.WriteLine("Waiting for War Thunder match to start...");
Console.WriteLine("(Launch War Thunder and enter a battle)");
Console.WriteLine();
Console.WriteLine("Press Ctrl+C to stop");
Console.WriteLine("═══════════════════════════════════════════════════════");
Console.WriteLine();

var cts = new CancellationTokenSource();
ConsoleCancelEventHandler handler = (s, e) =>
{
Expand All @@ -28,36 +39,119 @@ static async Task CaptureWarThunderSession()
};
Console.CancelKeyPress += handler;

try
{
var session = new GameSession()
.AddSource(
WarThunderSources.CreateStateSource()
.UseWriter(new BinarySessionWriter())
.OutputTo($"./sessions/warthunder_{DateTime.UtcNow:yyyyMMdd_HHmmss}.bin"))
.OnData<StateData>(data =>
var lastValidData = false;
var frameCount = 0;

var session = new GameSession()
.AddSource(
WarThunderSources.CreateStateSource(hz: 60) // 10Hz for readable console output
.UseWriter(new BinarySessionWriter())
.OutputTo($"./sessions/warthunder_{DateTime.UtcNow:yyyyMMdd_HHmmss}.bin"))
.OnData<StateData>(data =>
{
frameCount++;

// Detect match state changes
if (data.Valid && !lastValidData)
{
Console.WriteLine($"Altitude: {data.Altitude} | Speed {data.TrueAirspeed} | Throttle {data.Throttle}");
});
Console.Clear();
Console.WriteLine("═══════════════════════════════════════════════════════");
Console.WriteLine(" ✈️ MATCH STARTED - LIVE TELEMETRY");
Console.WriteLine("═══════════════════════════════════════════════════════");
Console.WriteLine();
}
else if (!data.Valid && lastValidData)
{
Console.Clear();
Console.WriteLine("═══════════════════════════════════════════════════════");
Console.WriteLine(" MATCH ENDED - Waiting for next battle...");
Console.WriteLine("═══════════════════════════════════════════════════════");
Console.WriteLine();
}

await session.StartAsync(cts.Token);
lastValidData = data.Valid;

// Session is now running, wait for cancellation
await Task.Delay(Timeout.Infinite, cts.Token);
}
catch (FileNotFoundException)
{
Console.WriteLine("\nError: War Thunder is not running. Start War Thunder and try again.");
}
catch (OperationCanceledException)
{
Console.WriteLine("\nCapture stopped by user.");
}
finally
{
Console.CancelKeyPress -= handler;
cts.Dispose();
}
if (data.Valid && frameCount % 1 == 0) // Update every frame (10Hz)
{
// Clear and redraw dashboard every frame
Console.SetCursorPosition(0, 4);
DrawDashboard(data);
}
});

await session.StartAsync(cts.Token);
await Task.Delay(Timeout.Infinite, cts.Token);
}

static void DrawDashboard(StateData data)
{
var engineCount = GetActiveEngineCount(data);

Console.WriteLine("╔═══════════════════════════════════════════════════════╗");
Console.WriteLine("║ FLIGHT PARAMETERS ║");
Console.WriteLine("╠═══════════════════════════════════════════════════════╣");
Console.WriteLine($"║ Altitude: {data.AltitudeMeters,8:F0} m ║");
Console.WriteLine($"║ IAS: {data.IndicatedAirspeedKmh,8:F0} km/h ║");
Console.WriteLine($"║ TAS: {data.TrueAirspeedKmh,8:F0} km/h ║");
Console.WriteLine($"║ Mach: {data.Mach,8:F2} ║");
Console.WriteLine($"║ Vertical Speed: {data.VyMs,8:F1} m/s ║");
Console.WriteLine($"║ ║");
Console.WriteLine($"║ AoA (Attack): {data.AngleOfAttackDeg,8:F1}° ║");
Console.WriteLine($"║ AoS (Slip): {data.AngleOfSlipDeg,8:F1}° ║");
Console.WriteLine($"║ G-Force: {data.Ny,8:F2} g ║");
Console.WriteLine($"║ Roll Rate: {data.WxDegPerSec,8:F0}°/s ║");
Console.WriteLine("╠═══════════════════════════════════════════════════════╣");
Console.WriteLine("║ CONTROL SURFACES ║");
Console.WriteLine("╠═══════════════════════════════════════════════════════╣");
Console.WriteLine($"║ Aileron: {data.AileronPercent,8:F1}% {GetBar(data.AileronPercent, 100)}");
Console.WriteLine($"║ Elevator: {data.ElevatorPercent,8:F1}% {GetBar(data.ElevatorPercent, 100)}");
Console.WriteLine($"║ Rudder: {data.RudderPercent,8:F1}% {GetBar(data.RudderPercent, 100)}");
Console.WriteLine($"║ Flaps: {data.FlapsPercent,8:F1}% {GetBar(data.FlapsPercent, 100)}");
Console.WriteLine($"║ Gear: {data.GearPercent,8:F1}% {(data.GearPercent > 0 ? "DOWN ✓" : "UP")} ║");
Console.WriteLine($"║ Airbrake: {data.AirbrakePercent,8:F1}% {(data.AirbrakePercent > 0 ? "DEPLOYED" : "RETRACTED")} ║");
Console.WriteLine("╠═══════════════════════════════════════════════════════╣");
Console.WriteLine($"║ ENGINE {(engineCount > 1 ? $"(1 of {engineCount})" : "STATUS")} ║");
Console.WriteLine("╠═══════════════════════════════════════════════════════╣");
Console.WriteLine($"║ Throttle: {data.Throttle1Percent,8:F1}% {GetBar(data.Throttle1Percent, 100)}");
Console.WriteLine($"║ RPM: {data.Rpm1,8:F0} ║");
Console.WriteLine($"║ Power: {data.Power1Hp,8:F1} hp ║");
Console.WriteLine($"║ Manifold Press: {data.ManifoldPressure1Atm,8:F2} atm ║");
Console.WriteLine($"║ Mixture: {data.Mixture1Percent,8:F1}% ║");
Console.WriteLine($"║ Radiator: {data.Radiator1Percent,8:F1}% ║");
Console.WriteLine($"║ Water Temp: {data.WaterTemp1C,8:F0}°C ║");
Console.WriteLine($"║ Oil Temp: {data.OilTemp1C,8:F0}°C ║");
Console.WriteLine($"║ Thrust: {data.Thrust1Kgs,8:F0} kgf ║");
Console.WriteLine($"║ Prop Pitch: {data.Pitch1Deg,8:F1}° ║");
Console.WriteLine($"║ Efficiency: {data.Efficiency1Percent,8:F1}% ║");
Console.WriteLine("╠═══════════════════════════════════════════════════════╣");
Console.WriteLine("║ FUEL STATUS ║");
Console.WriteLine("╠═══════════════════════════════════════════════════════╣");
var fuelPercent = data.FuelMassInitialKg > 0 ? (data.FuelMassKg / data.FuelMassInitialKg * 100) : 0;
Console.WriteLine($"║ Current Fuel: {data.FuelMassKg,8:F1} kg ({fuelPercent,5:F1}%) ║");
Console.WriteLine($"║ Initial Fuel: {data.FuelMassInitialKg,8:F1} kg ║");
Console.WriteLine($"║ Fuel Used: {(data.FuelMassInitialKg - data.FuelMassKg),8:F1} kg ║");
Console.WriteLine("╚═══════════════════════════════════════════════════════╝");
Console.WriteLine();
Console.WriteLine($" Recording to file... | Press Ctrl+C to stop");
Console.Write(" "); // Clear any extra characters
}

static int GetActiveEngineCount(StateData data)
{
var count = 0;
if (data.Rpm1 > 0 || data.Throttle1Percent > 0) count = 1;
if (data.Rpm2 > 0 || data.Throttle2Percent > 0) count = 2;
if (data.Rpm3 > 0 || data.Throttle3Percent > 0) count = 3;
if (data.Rpm4 > 0 || data.Throttle4Percent > 0) count = 4;
return count > 0 ? count : 1; // Default to 1
}

static string GetBar(float value, float max, int width = 15)
{
var percent = Math.Abs(value) / max;
var filled = (int)(percent * width);
var bar = new string('█', Math.Min(filled, width)) + new string('░', Math.Max(width - filled, 0));
return $"[{bar}]║";
}
#endregion

Expand Down
15 changes: 13 additions & 2 deletions GamesDat/GameSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ private async Task RunAsync(CancellationToken ct)
{
Console.WriteLine($"[{SourceTypeName}] Starting source...");
int frameCount = 0;

await foreach (var data in _source.ReadContinuousAsync(ct))
{
frameCount++;
Expand Down Expand Up @@ -185,7 +185,18 @@ private async Task RunAsync(CancellationToken ct)
}
catch (OperationCanceledException)
{
// Normal cancellation
// Check if this was expected cancellation
if (ct.IsCancellationRequested)
{
// Normal cancellation from user (Ctrl+C)
Console.WriteLine($"[{SourceTypeName}] Stopped by user");
}
else
{
// Unexpected cancellation - this shouldn't happen
Console.WriteLine($"[{SourceTypeName}] WARNING: Unexpected cancellation (not from user request)");
Console.WriteLine($"[{SourceTypeName}] This may indicate a premature termination issue");
}
}
catch (Exception ex)
{
Expand Down
Loading
Loading