diff --git a/OpenSky.Agent.SimConnectMSFS/SimConnect.cs b/OpenSky.Agent.SimConnectMSFS/SimConnect.cs
index aab1042..5c285ee 100644
--- a/OpenSky.Agent.SimConnectMSFS/SimConnect.cs
+++ b/OpenSky.Agent.SimConnectMSFS/SimConnect.cs
@@ -24,19 +24,19 @@ namespace OpenSky.Agent.SimConnectMSFS
using OpenSkyApi;
- using AircraftIdentity = OpenSky.Agent.SimConnectMSFS.Structs.AircraftIdentity;
- using FuelTanks = OpenSky.Agent.SimConnectMSFS.Structs.FuelTanks;
- using LandingAnalysis = OpenSky.Agent.SimConnectMSFS.Structs.LandingAnalysis;
- using PayloadStations = OpenSky.Agent.SimConnectMSFS.Structs.PayloadStations;
- using PrimaryTracking = OpenSky.Agent.SimConnectMSFS.Structs.PrimaryTracking;
- using SecondaryTracking = OpenSky.Agent.SimConnectMSFS.Structs.SecondaryTracking;
- using Simulator = OpenSky.Agent.Simulator.Simulator;
- using SlewAircraftIntoPosition = OpenSky.Agent.SimConnectMSFS.Structs.SlewAircraftIntoPosition;
- using WeightAndBalance = OpenSky.Agent.SimConnectMSFS.Structs.WeightAndBalance;
+ using AircraftIdentity = Structs.AircraftIdentity;
+ using FuelTanks = Structs.FuelTanks;
+ using LandingAnalysis = Structs.LandingAnalysis;
+ using PayloadStations = Structs.PayloadStations;
+ using PrimaryTracking = Structs.PrimaryTracking;
+ using SecondaryTracking = Structs.SecondaryTracking;
+ using Simulator = Simulator.Simulator;
+ using SlewAircraftIntoPosition = Structs.SlewAircraftIntoPosition;
+ using WeightAndBalance = Structs.WeightAndBalance;
/// -------------------------------------------------------------------------------------------------
///
- /// Simconnect client.
+ /// Simconnect client for Microsoft Flight Simulator 2020.
///
///
/// sushi.at, 13/03/2021.
@@ -174,7 +174,7 @@ public override void SetAircraftRegistry(string registry)
if (this.fsConnect.Connected)
{
var planeRegistry = new PlaneRegistry { AtcID = registry };
- this.fsConnect.UpdateData(Requests.PlaneRegistry, planeRegistry);
+ this.fsConnect.UpdateData(Requests.AircraftRegistry, planeRegistry);
}
else
{
@@ -527,10 +527,10 @@ private void FsDataReceived(object sender, FsDataReceivedEventArgs e)
this.LastReceivedTimes[Requests.PayloadStations] = DateTime.UtcNow;
}
- if (simConnectObject is AircraftIdentity isPlaneIdentity)
+ if (simConnectObject is AircraftIdentity isAircraftIdentity)
{
- this.AircraftIdentity = isPlaneIdentity.Convert();
- this.LastReceivedTimes[Requests.PlaneIdentity] = DateTime.UtcNow;
+ this.AircraftIdentity = isAircraftIdentity.Convert();
+ this.LastReceivedTimes[Requests.AircraftIdentity] = DateTime.UtcNow;
new Thread(this.ProcessAircraftIdentity) { Name = "OpenSky.ProcessAircraftIdentity" }.Start();
}
@@ -591,11 +591,11 @@ private void ReadFromSimconnect()
this.fsConnect.RegisterDataDefinition(Requests.Secondary, SecondaryTrackingDefinition.Definition);
this.fsConnect.RegisterDataDefinition(Requests.FuelTanks, FuelTanksDefinition.Definition);
this.fsConnect.RegisterDataDefinition(Requests.PayloadStations, PayloadStationsDefinition.Definition);
- this.fsConnect.RegisterDataDefinition(Requests.PlaneIdentity, AircraftIdentityDefinition.Definition);
+ this.fsConnect.RegisterDataDefinition(Requests.AircraftIdentity, AircraftIdentityDefinition.Definition);
this.fsConnect.RegisterDataDefinition(Requests.WeightAndBalance, WeightAndBalanceDefinition.Definition);
this.fsConnect.RegisterDataDefinition(Requests.LandingAnalysis, LandingAnalysisDefinition.Definition);
this.fsConnect.RegisterDataDefinition(Requests.SlewPlaneIntoPosition, SlewAircraftIntoPositionDefinition.Definition);
- this.fsConnect.RegisterDataDefinition(Requests.PlaneRegistry, PlaneRegistryDefinition.Definition);
+ this.fsConnect.RegisterDataDefinition(Requests.AircraftRegistry, PlaneRegistryDefinition.Definition);
// Register client events
this.fsConnect.MapClientEventToSimEvent(ClientEvents.SetTime, ClientEvents.SetZuluYears, "ZULU_YEAR_SET");
diff --git a/OpenSky.Agent.SimConnectMSFS/Structs/PayloadStations.cs b/OpenSky.Agent.SimConnectMSFS/Structs/PayloadStations.cs
index 875f7f7..d18453f 100644
--- a/OpenSky.Agent.SimConnectMSFS/Structs/PayloadStations.cs
+++ b/OpenSky.Agent.SimConnectMSFS/Structs/PayloadStations.cs
@@ -402,7 +402,7 @@ public static Simulator.Models.PayloadStations Convert(this PayloadStations stat
Weight17 = stations.Weight17,
Weight18 = stations.Weight18,
Weight19 = stations.Weight19,
- Weight20 = stations.Weight20,
+ Weight20 = stations.Weight20
};
}
@@ -464,7 +464,7 @@ public static PayloadStations ConvertBack(this Simulator.Models.PayloadStations
Weight17 = stations.Weight17,
Weight18 = stations.Weight18,
Weight19 = stations.Weight19,
- Weight20 = stations.Weight20,
+ Weight20 = stations.Weight20
};
}
}
diff --git a/OpenSky.Agent.SimConnectMSFS/Structs/SlewAircraftIntoPosition.cs b/OpenSky.Agent.SimConnectMSFS/Structs/SlewAircraftIntoPosition.cs
index 7bfdf34..c94a866 100644
--- a/OpenSky.Agent.SimConnectMSFS/Structs/SlewAircraftIntoPosition.cs
+++ b/OpenSky.Agent.SimConnectMSFS/Structs/SlewAircraftIntoPosition.cs
@@ -38,6 +38,13 @@ public struct SlewAircraftIntoPosition
/// -------------------------------------------------------------------------------------------------
public double Longitude { get; set; }
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// The altitude in feet.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public double Altitude { get; set; }
+
/// -------------------------------------------------------------------------------------------------
///
/// The radio height in feet.
@@ -118,6 +125,7 @@ public static Agent.Simulator.Models.SlewAircraftIntoPosition Convert(this SlewA
{
Latitude = position.Latitude,
Longitude = position.Longitude,
+ Altitude = position.Altitude,
RadioHeight = position.RadioHeight,
Heading = position.Heading,
AirspeedTrue = position.AirspeedTrue,
@@ -148,6 +156,7 @@ public static SlewAircraftIntoPosition ConvertBack(this Agent.Simulator.Models.S
{
Latitude = position.Latitude,
Longitude = position.Longitude,
+ Altitude = position.Altitude,
RadioHeight = position.RadioHeight,
Heading = position.Heading,
AirspeedTrue = position.AirspeedTrue,
@@ -179,6 +188,7 @@ public static class SlewAircraftIntoPositionDefinition
{
new SimVar("PLANE LATITUDE", "Degrees", SIMCONNECT_DATATYPE.FLOAT64),
new SimVar("PLANE LONGITUDE", "Degrees", SIMCONNECT_DATATYPE.FLOAT64),
+ new SimVar("PLANE ALTITUDE", "Feet", SIMCONNECT_DATATYPE.FLOAT64),
new SimVar("PLANE ALT ABOVE GROUND", "Feet", SIMCONNECT_DATATYPE.FLOAT64),
new SimVar("PLANE HEADING DEGREES MAGNETIC", "Degrees", SIMCONNECT_DATATYPE.FLOAT64),
new SimVar("AIRSPEED TRUE", "Knots", SIMCONNECT_DATATYPE.FLOAT64),
diff --git a/OpenSky.Agent.Simulator/Enums/Requests.cs b/OpenSky.Agent.Simulator/Enums/Requests.cs
index ed82159..25cfc19 100644
--- a/OpenSky.Agent.Simulator/Enums/Requests.cs
+++ b/OpenSky.Agent.Simulator/Enums/Requests.cs
@@ -40,9 +40,9 @@ public enum Requests : uint
PayloadStations = 3,
///
- /// Plane identity request
+ /// Aircraft identity request
///
- PlaneIdentity = 4,
+ AircraftIdentity = 4,
///
/// Weight and balance request
@@ -60,8 +60,8 @@ public enum Requests : uint
SlewPlaneIntoPosition = 7,
///
- /// Plane registry request
+ /// Aircraft registry request
///
- PlaneRegistry = 8
+ AircraftRegistry = 8
}
}
\ No newline at end of file
diff --git a/OpenSky.Agent.Simulator/Models/FuelTanks.cs b/OpenSky.Agent.Simulator/Models/FuelTanks.cs
index 2b75fde..7875edb 100644
--- a/OpenSky.Agent.Simulator/Models/FuelTanks.cs
+++ b/OpenSky.Agent.Simulator/Models/FuelTanks.cs
@@ -235,6 +235,32 @@ public double TotalQuantity
}
}
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Updates the capacities from a modified dictionary.
+ ///
+ ///
+ /// sushi.at, 10/02/2022.
+ ///
+ ///
+ /// The modified dictionary containing the new capacity values.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public void UpdateCapactiesFromDictionary(Dictionary modifiedDictionary)
+ {
+ this.FuelTankCenterCapacity = modifiedDictionary[FuelTank.Center];
+ this.FuelTankCenter2Capacity = modifiedDictionary[FuelTank.Center2];
+ this.FuelTankCenter3Capacity = modifiedDictionary[FuelTank.Center3];
+ this.FuelTankLeftMainCapacity = modifiedDictionary[FuelTank.LeftMain];
+ this.FuelTankLeftAuxCapacity = modifiedDictionary[FuelTank.LeftAux];
+ this.FuelTankLeftTipCapacity = modifiedDictionary[FuelTank.LeftTip];
+ this.FuelTankRightMainCapacity = modifiedDictionary[FuelTank.RightMain];
+ this.FuelTankRightAuxCapacity = modifiedDictionary[FuelTank.RightAux];
+ this.FuelTankRightTipCapacity = modifiedDictionary[FuelTank.RightTip];
+ this.FuelTankExternal1Capacity = modifiedDictionary[FuelTank.External1];
+ this.FuelTankExternal2Capacity = modifiedDictionary[FuelTank.External2];
+ }
+
/// -------------------------------------------------------------------------------------------------
///
/// Updates the quantities from a modified dictionary.
diff --git a/OpenSky.Agent.Simulator/Models/SlewAircraftIntoPosition.cs b/OpenSky.Agent.Simulator/Models/SlewAircraftIntoPosition.cs
index 961be38..a6fcd83 100644
--- a/OpenSky.Agent.Simulator/Models/SlewAircraftIntoPosition.cs
+++ b/OpenSky.Agent.Simulator/Models/SlewAircraftIntoPosition.cs
@@ -25,6 +25,13 @@ public class SlewAircraftIntoPosition
/// -------------------------------------------------------------------------------------------------
public double AirspeedTrue { get; set; }
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Gets or sets the altitude.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public double Altitude { get; set; }
+
/// -------------------------------------------------------------------------------------------------
///
/// The bank angle in degrees.
@@ -109,6 +116,7 @@ public static SlewAircraftIntoPosition FromPrimaryTracking(PrimaryTracking prima
Latitude = primary.Latitude,
Longitude = primary.Longitude,
RadioHeight = primary.RadioHeight,
+ Altitude = primary.Altitude,
Heading = primary.Heading,
AirspeedTrue = primary.AirspeedTrue,
PitchAngle = primary.PitchAngle,
diff --git a/OpenSky.Agent.Simulator/OpenSky.Agent.Simulator.csproj b/OpenSky.Agent.Simulator/OpenSky.Agent.Simulator.csproj
index c3dc59c..57579ef 100644
--- a/OpenSky.Agent.Simulator/OpenSky.Agent.Simulator.csproj
+++ b/OpenSky.Agent.Simulator/OpenSky.Agent.Simulator.csproj
@@ -128,6 +128,7 @@
+
diff --git a/OpenSky.Agent.Simulator/Simulator.Flight.cs b/OpenSky.Agent.Simulator/Simulator.Flight.cs
index ce15ac9..2b0cae7 100644
--- a/OpenSky.Agent.Simulator/Simulator.Flight.cs
+++ b/OpenSky.Agent.Simulator/Simulator.Flight.cs
@@ -28,7 +28,7 @@ namespace OpenSky.Agent.Simulator
using OpenSkyApi;
using PositionReport = OpenSkyApi.PositionReport;
- using TrackingEventMarker = OpenSky.Agent.Simulator.Models.TrackingEventMarker;
+ using TrackingEventMarker = Models.TrackingEventMarker;
/// -------------------------------------------------------------------------------------------------
///
@@ -261,13 +261,13 @@ public Flight Flight
}
};
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Fuel].Expected =
+ this.TrackingConditions[(int)Models.TrackingConditions.Fuel].Expected =
$"{value.FuelGallons:F1} gal, {value.FuelGallons * 3.78541:F1} liters ▶ {value.FuelGallons * value.Aircraft.Type.FuelWeightPerGallon:F1} lbs, {value.FuelGallons * value.Aircraft.Type.FuelWeightPerGallon * 0.453592:F1} kg";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Payload].Expected = $"{value.PayloadPounds:F1} lbs, {value.PayloadPounds * 0.453592:F1} kg";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.PlaneModel].Expected = $"{value.Aircraft.Type.Name} (v{value.Aircraft.Type.VersionNumber})";
+ this.TrackingConditions[(int)Models.TrackingConditions.Payload].Expected = $"{value.PayloadPounds:F1} lbs, {value.PayloadPounds * 0.453592:F1} kg";
+ this.TrackingConditions[(int)Models.TrackingConditions.PlaneModel].Expected = $"{value.Aircraft.Type.Name} (v{value.Aircraft.Type.VersionNumber})";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Fuel].AutoSet = !value.Aircraft.Type.RequiresManualFuelling;
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Payload].AutoSet = !value.Aircraft.Type.RequiresManualLoading;
+ this.TrackingConditions[(int)Models.TrackingConditions.Fuel].AutoSet = !value.Aircraft.Type.RequiresManualFuelling;
+ this.TrackingConditions[(int)Models.TrackingConditions.Payload].AutoSet = !value.Aircraft.Type.RequiresManualLoading;
if (!value.Resume)
{
@@ -332,12 +332,13 @@ public Flight Flight
PitchAngle = value.PitchAngle,
OnGround = value.OnGround,
AirspeedTrue = value.AirspeedTrue ?? 0,
+ Altitude = value.Altitude ?? 0,
RadioHeight = value.RadioHeight ?? 0,
VerticalSpeedSeconds = value.VerticalSpeedSeconds
}
};
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Fuel].Expected =
+ this.TrackingConditions[(int)Models.TrackingConditions.Fuel].Expected =
$"{this.flightLoadingTempModels.FuelTanks.TotalQuantity:F1} gal, {this.flightLoadingTempModels.FuelTanks.TotalQuantity * 3.78541:F1} liters ▶ {this.flightLoadingTempModels.FuelTanks.TotalQuantity * value.Aircraft.Type.FuelWeightPerGallon:F1} lbs, {this.flightLoadingTempModels.FuelTanks.TotalQuantity * value.Aircraft.Type.FuelWeightPerGallon * 0.453592:F1} kg";
}
}
@@ -531,7 +532,7 @@ public void StopTracking(bool resumeLater)
this.TrackingConditions[(int)condition].Reset();
}
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.RealismSettings].Expected = "No slew, No unlimited fuel,\r\nCrash detection, SimRate=1";
+ this.TrackingConditions[(int)Models.TrackingConditions.RealismSettings].Expected = "No slew, No unlimited fuel,\r\nCrash detection, SimRate=0 or 1";
}
if (!resumeLater)
diff --git a/OpenSky.Agent.Simulator/Simulator.Process.FlightPhases.cs b/OpenSky.Agent.Simulator/Simulator.Process.FlightPhases.cs
index cee0c20..c01ba76 100644
--- a/OpenSky.Agent.Simulator/Simulator.Process.FlightPhases.cs
+++ b/OpenSky.Agent.Simulator/Simulator.Process.FlightPhases.cs
@@ -202,7 +202,7 @@ private void TransitionFlightPhase()
var player = new SoundPlayer(assembly.GetManifestResourceStream("OpenSky.Agent.Resources.OSnegative.wav"));
player.Play();
SpeechSoundPacks.Instance.PlaySpeechEvent(SpeechEvent.AbortedSimMainMenu);
- this.StopTracking(false);
+ this.StopTracking(true);
}
}
diff --git a/OpenSky.Agent.Simulator/Simulator.Process.Systems.cs b/OpenSky.Agent.Simulator/Simulator.Process.Systems.cs
index fef07b6..9b9b5ea 100644
--- a/OpenSky.Agent.Simulator/Simulator.Process.Systems.cs
+++ b/OpenSky.Agent.Simulator/Simulator.Process.Systems.cs
@@ -103,7 +103,7 @@ private void MonitorPrimarySystems(ProcessPrimaryTracking ppt)
var player = new SoundPlayer(assembly.GetManifestResourceStream("OpenSky.Agent.Resources.OSnegative.wav"));
player.Play();
SpeechSoundPacks.Instance.PlaySpeechEvent(SpeechEvent.AbortedSlew);
- this.StopTracking(false);
+ this.StopTracking(true);
}
// Teleport to another position?
@@ -119,7 +119,7 @@ private void MonitorPrimarySystems(ProcessPrimaryTracking ppt)
var player = new SoundPlayer(assembly.GetManifestResourceStream("OpenSky.Agent.Resources.OSnegative.wav"));
player.Play();
SpeechSoundPacks.Instance.PlaySpeechEvent(SpeechEvent.AbortedTeleport);
- this.StopTracking(false);
+ this.StopTracking(true);
}
}
}
@@ -154,7 +154,7 @@ private void MonitorSecondarySystems(ProcessSecondaryTracking pst)
var player = new SoundPlayer(assembly.GetManifestResourceStream("OpenSky.Agent.Resources.OSnegative.wav"));
player.PlaySync();
SpeechSoundPacks.Instance.PlaySpeechEvent(SpeechEvent.AbortedEnginesGroundHandling);
- this.StopTracking(false);
+ this.StopTracking(true);
}
// Was the beacon light off when the engine was started?
@@ -231,7 +231,7 @@ private void MonitorSecondarySystems(ProcessSecondaryTracking pst)
var player = new SoundPlayer(assembly.GetManifestResourceStream("OpenSky.Agent.Resources.OSnegative.wav"));
player.PlaySync();
SpeechSoundPacks.Instance.PlaySpeechEvent(SpeechEvent.AbortedPushbackGroundHandling);
- this.StopTracking(false);
+ this.StopTracking(true);
}
// Pushback start?
@@ -345,7 +345,7 @@ private void MonitorSecondarySystems(ProcessSecondaryTracking pst)
var player = new SoundPlayer(assembly.GetManifestResourceStream("OpenSky.Agent.Resources.OSnegative.wav"));
player.PlaySync();
SpeechSoundPacks.Instance.PlaySpeechEvent(SpeechEvent.AbortedTimeBackwards);
- this.StopTracking(false);
+ this.StopTracking(true);
}
if (timeDelta.TotalSeconds > 30)
@@ -355,7 +355,7 @@ private void MonitorSecondarySystems(ProcessSecondaryTracking pst)
var player = new SoundPlayer(assembly.GetManifestResourceStream("OpenSky.Agent.Resources.OSnegative.wav"));
player.PlaySync();
SpeechSoundPacks.Instance.PlaySpeechEvent(SpeechEvent.AbortedTimeChanged);
- this.StopTracking(false);
+ this.StopTracking(true);
}
}
}
diff --git a/OpenSky.Agent.Simulator/Simulator.Process.cs b/OpenSky.Agent.Simulator/Simulator.Process.cs
index c7b6264..17693be 100644
--- a/OpenSky.Agent.Simulator/Simulator.Process.cs
+++ b/OpenSky.Agent.Simulator/Simulator.Process.cs
@@ -118,36 +118,36 @@ protected void MonitorTrackingStartConditions(SecondaryTracking secondary)
{
if (this.Flight != null && this.TrackingStatus == TrackingStatus.Preparing || this.TrackingStatus == TrackingStatus.Resuming)
{
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.DateTime].Expected = $"{DateTime.UtcNow.AddHours(this.Flight?.UtcOffset ?? 0):HH:mm dd.MM.yyyy}";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.DateTime].Current = $"{secondary.UtcDateTime:HH:mm dd.MM.yyyy}";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.PlaneModel].Current = this.AircraftIdentity.Type;
+ this.TrackingConditions[(int)Models.TrackingConditions.DateTime].Expected = $"{DateTime.UtcNow.AddHours(this.Flight?.UtcOffset ?? 0):HH:mm dd.MM.yyyy}";
+ this.TrackingConditions[(int)Models.TrackingConditions.DateTime].Current = $"{secondary.UtcDateTime:HH:mm dd.MM.yyyy}";
+ this.TrackingConditions[(int)Models.TrackingConditions.PlaneModel].Current = this.AircraftIdentity.Type;
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.DateTime].ConditionMet =
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.DateTime].AutoSet || Math.Abs((DateTime.UtcNow.AddHours(this.Flight?.UtcOffset ?? 0) - secondary.UtcDateTime).TotalMinutes) < 1;
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.PlaneModel].ConditionMet = this.Flight?.Aircraft.Type.MatchesAircraftInSimulator() ?? false;
+ this.TrackingConditions[(int)Models.TrackingConditions.DateTime].ConditionMet =
+ this.TrackingConditions[(int)Models.TrackingConditions.DateTime].AutoSet || Math.Abs((DateTime.UtcNow.AddHours(this.Flight?.UtcOffset ?? 0) - secondary.UtcDateTime).TotalMinutes) < 1;
+ this.TrackingConditions[(int)Models.TrackingConditions.PlaneModel].ConditionMet = this.Flight?.Aircraft.Type.MatchesAircraftInSimulator() ?? false;
if (this.TrackingStatus == TrackingStatus.Preparing)
{
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Fuel].Enabled = true;
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Payload].Enabled = true;
+ this.TrackingConditions[(int)Models.TrackingConditions.Fuel].Enabled = true;
+ this.TrackingConditions[(int)Models.TrackingConditions.Payload].Enabled = true;
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Fuel].Current =
+ this.TrackingConditions[(int)Models.TrackingConditions.Fuel].Current =
$"{this.WeightAndBalance.FuelTotalQuantity:F1} gal, {this.WeightAndBalance.FuelTotalQuantity * 3.78541:F1} liters ▶ {this.WeightAndBalance.FuelTotalQuantity * this.Flight?.Aircraft.Type.FuelWeightPerGallon:F1} lbs, {this.WeightAndBalance.FuelTotalQuantity * this.Flight?.Aircraft.Type.FuelWeightPerGallon * 0.453592:F1} kg";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Payload].Current = $"{this.PayloadStations.TotalWeight:F1} lbs, {this.PayloadStations.TotalWeight * 0.453592:F1} kg";
+ this.TrackingConditions[(int)Models.TrackingConditions.Payload].Current = $"{this.PayloadStations.TotalWeight:F1} lbs, {this.PayloadStations.TotalWeight * 0.453592:F1} kg";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Fuel].ConditionMet =
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Fuel].AutoSet || Math.Abs((int)(this.WeightAndBalance.FuelTotalQuantity - this.Flight?.FuelGallons ?? 0)) < 0.27; // Allow roughly 1 liter of margin
+ this.TrackingConditions[(int)Models.TrackingConditions.Fuel].ConditionMet =
+ this.TrackingConditions[(int)Models.TrackingConditions.Fuel].AutoSet || Math.Abs((int)(this.WeightAndBalance.FuelTotalQuantity - this.Flight?.FuelGallons ?? 0)) < 0.27; // Allow roughly 1 liter of margin
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Payload].ConditionMet =
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Payload].AutoSet || Math.Abs((int)(this.PayloadStations.TotalWeight - this.Flight?.PayloadPounds ?? 0)) < 2.2; // Allow 1 kg of margin
+ this.TrackingConditions[(int)Models.TrackingConditions.Payload].ConditionMet =
+ this.TrackingConditions[(int)Models.TrackingConditions.Payload].AutoSet || Math.Abs((int)(this.PayloadStations.TotalWeight - this.Flight?.PayloadPounds ?? 0)) < 2.2; // Allow 1 kg of margin
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.RealismSettings].Expected = "No slew, No unlimited fuel,\r\nCrash detection, SimRate=1";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.RealismSettings].ConditionMet =
- !this.PrimaryTracking.SlewActive && !secondary.UnlimitedFuel && secondary.CrashDetection && Math.Abs((int)(this.PrimaryTracking.SimulationRate - 1)) == 0;
+ this.TrackingConditions[(int)Models.TrackingConditions.RealismSettings].Expected = "No slew, No unlimited fuel,\r\nCrash detection, SimRate=0 or 1";
+ this.TrackingConditions[(int)Models.TrackingConditions.RealismSettings].ConditionMet =
+ !this.PrimaryTracking.SlewActive && !secondary.UnlimitedFuel && secondary.CrashDetection && ((int)this.PrimaryTracking.SimulationRate == 0 || (int)this.PrimaryTracking.SimulationRate == 1);
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Location].Current =
+ this.TrackingConditions[(int)Models.TrackingConditions.Location].Current =
$"{this.PrimaryTracking.GeoCoordinate.GetDistanceTo(new GeoCoordinate(this.Flight?.Origin.Latitude ?? 0, this.Flight?.Origin.Longitude ?? 0)) / 1000:F2} km from starting location - {(this.PrimaryTracking.OnGround ? "On ground" : "Airborne")}";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Location].ConditionMet =
+ this.TrackingConditions[(int)Models.TrackingConditions.Location].ConditionMet =
this.PrimaryTracking.GeoCoordinate.GetDistanceTo(new GeoCoordinate(this.Flight?.Origin.Latitude ?? 0, this.Flight?.Origin.Longitude ?? 0)) < 5000;
}
@@ -155,28 +155,28 @@ protected void MonitorTrackingStartConditions(SecondaryTracking secondary)
{
if (this.Flight?.Aircraft.Type.RequiresManualFuelling != true)
{
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Fuel].Enabled = false;
+ this.TrackingConditions[(int)Models.TrackingConditions.Fuel].Enabled = false;
}
else
{
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Fuel].Enabled = true;
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Fuel].Current =
+ this.TrackingConditions[(int)Models.TrackingConditions.Fuel].Enabled = true;
+ this.TrackingConditions[(int)Models.TrackingConditions.Fuel].Current =
$"{this.WeightAndBalance.FuelTotalQuantity:F1} gal, {this.WeightAndBalance.FuelTotalQuantity * 3.78541:F1} liters ▶ {this.WeightAndBalance.FuelTotalQuantity * this.Flight?.Aircraft.Type.FuelWeightPerGallon:F1} lbs, {this.WeightAndBalance.FuelTotalQuantity * this.Flight?.Aircraft.Type.FuelWeightPerGallon * 0.453592:F1} kg";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Fuel].ConditionMet =
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Fuel].AutoSet ||
+ this.TrackingConditions[(int)Models.TrackingConditions.Fuel].ConditionMet =
+ this.TrackingConditions[(int)Models.TrackingConditions.Fuel].AutoSet ||
Math.Abs(this.WeightAndBalance.FuelTotalQuantity - this.flightLoadingTempModels.FuelTanks.TotalQuantity) < 0.81; // Allow roughly 3 liters of margin, as it can be very hard to get this right otherwise
}
if (this.Flight?.Aircraft.Type.RequiresManualLoading != true)
{
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Payload].Enabled = false;
+ this.TrackingConditions[(int)Models.TrackingConditions.Payload].Enabled = false;
}
else
{
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Payload].Enabled = true;
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Payload].Current = $"{this.PayloadStations.TotalWeight:F1} lbs, {this.PayloadStations.TotalWeight * 0.453592:F1} kg";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Payload].ConditionMet =
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Payload].AutoSet || Math.Abs((double)(this.PayloadStations.TotalWeight - this.Flight?.PayloadPounds)) < 2.2; // Allow 1 kg of margin
+ this.TrackingConditions[(int)Models.TrackingConditions.Payload].Enabled = true;
+ this.TrackingConditions[(int)Models.TrackingConditions.Payload].Current = $"{this.PayloadStations.TotalWeight:F1} lbs, {this.PayloadStations.TotalWeight * 0.453592:F1} kg";
+ this.TrackingConditions[(int)Models.TrackingConditions.Payload].ConditionMet =
+ this.TrackingConditions[(int)Models.TrackingConditions.Payload].AutoSet || Math.Abs((double)(this.PayloadStations.TotalWeight - this.Flight?.PayloadPounds)) < 2.2; // Allow 1 kg of margin
}
var currentLocation = $"{this.PrimaryTracking.GeoCoordinate.GetDistanceTo(this.flightLoadingTempModels?.SlewAircraftIntoPosition.GeoCoordinate ?? new GeoCoordinate(0, 0, 0)) / 1000:F2} km from resume location";
@@ -184,11 +184,11 @@ protected void MonitorTrackingStartConditions(SecondaryTracking secondary)
currentLocation += $"\r\nLongitude: {this.flightLoadingTempModels?.SlewAircraftIntoPosition.Longitude:F4}";
currentLocation += $"\r\nAltitude (AGL): {this.flightLoadingTempModels?.SlewAircraftIntoPosition.RadioHeight:F0}";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.RealismSettings].Expected = "No unlimited fuel,\r\nCrash detection, SimRate=1";
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.RealismSettings].ConditionMet = !secondary.UnlimitedFuel && secondary.CrashDetection && Math.Abs((int)(this.PrimaryTracking.SimulationRate - 1)) == 0;
+ this.TrackingConditions[(int)Models.TrackingConditions.RealismSettings].Expected = "No unlimited fuel,\r\nCrash detection, SimRate=0 or 1";
+ this.TrackingConditions[(int)Models.TrackingConditions.RealismSettings].ConditionMet = !secondary.UnlimitedFuel && secondary.CrashDetection && ((int)this.PrimaryTracking.SimulationRate == 0 || (int)this.PrimaryTracking.SimulationRate == 1);
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Location].Current = currentLocation;
- this.TrackingConditions[(int)Agent.Simulator.Models.TrackingConditions.Location].ConditionMet =
+ this.TrackingConditions[(int)Models.TrackingConditions.Location].Current = currentLocation;
+ this.TrackingConditions[(int)Models.TrackingConditions.Location].ConditionMet =
(this.PrimaryTracking.GeoCoordinate.GetDistanceTo(this.flightLoadingTempModels?.SlewAircraftIntoPosition.GeoCoordinate ?? new GeoCoordinate(0, 0, 0)) < 100) &&
Math.Abs((int)(this.PrimaryTracking.RadioHeight - this.flightLoadingTempModels?.SlewAircraftIntoPosition.RadioHeight ?? -1000)) < 50;
}
@@ -253,7 +253,7 @@ protected void ProcessPayloadStations(PayloadStations older, PayloadStations new
var player = new SoundPlayer(assembly.GetManifestResourceStream("OpenSky.Agent.Resources.OSnegative.wav"));
player.PlaySync();
SpeechSoundPacks.Instance.PlaySpeechEvent(SpeechEvent.AbortedPayloadChange);
- this.StopTracking(false);
+ this.StopTracking(true);
}
}
}
@@ -370,6 +370,12 @@ private void ProcessPrimaryTracking()
// Are we close to landing?
this.SampleRates[Requests.LandingAnalysis] = this.WasAirborne && ppt.New.RadioHeight < 500 ? 25 : 500;
this.OnPropertyChanged(nameof(this.SampleRates));
+
+ // Was the sim paused/un-paused?
+ if (Math.Abs(ppt.Old.SimulationRate - ppt.New.SimulationRate) > 0.1)
+ {
+ this.OnPropertyChanged(nameof(this.IsPaused));
+ }
}
else
{
diff --git a/OpenSky.Agent.Simulator/Simulator.cs b/OpenSky.Agent.Simulator/Simulator.cs
index e72442b..793a2fc 100644
--- a/OpenSky.Agent.Simulator/Simulator.cs
+++ b/OpenSky.Agent.Simulator/Simulator.cs
@@ -115,7 +115,7 @@ protected Simulator(OpenSkyService openSkyServiceInstance)
{ Requests.Secondary, 500 },
{ Requests.FuelTanks, 15000 },
{ Requests.PayloadStations, 15000 },
- { Requests.PlaneIdentity, 15000 },
+ { Requests.AircraftIdentity, 15000 },
{ Requests.WeightAndBalance, 15000 },
{ Requests.LandingAnalysis, 500 }
};
@@ -128,12 +128,12 @@ protected Simulator(OpenSkyService openSkyServiceInstance)
this.TrackingConditions = new Dictionary
{
- { (int)Agent.Simulator.Models.TrackingConditions.DateTime, new TrackingCondition { AutoSet = true } },
- { (int)Agent.Simulator.Models.TrackingConditions.Fuel, new TrackingCondition { AutoSet = true } },
- { (int)Agent.Simulator.Models.TrackingConditions.Payload, new TrackingCondition { AutoSet = true } },
- { (int)Agent.Simulator.Models.TrackingConditions.PlaneModel, new TrackingCondition() },
- { (int)Agent.Simulator.Models.TrackingConditions.RealismSettings, new TrackingCondition { Expected = "No slew, No unlimited fuel,\r\nCrash detection, SimRate=1" } },
- { (int)Agent.Simulator.Models.TrackingConditions.Location, new TrackingCondition() }
+ { (int)Models.TrackingConditions.DateTime, new TrackingCondition { AutoSet = true } },
+ { (int)Models.TrackingConditions.Fuel, new TrackingCondition { AutoSet = true } },
+ { (int)Models.TrackingConditions.Payload, new TrackingCondition { AutoSet = true } },
+ { (int)Models.TrackingConditions.PlaneModel, new TrackingCondition() },
+ { (int)Models.TrackingConditions.RealismSettings, new TrackingCondition { Expected = "No slew, No unlimited fuel,\r\nCrash detection, SimRate=0 or 1" } },
+ { (int)Models.TrackingConditions.Location, new TrackingCondition() }
};
// Start our worker threads
diff --git a/OpenSky.Agent.Simulator/Tools/AircraftRegistryExtensions.cs b/OpenSky.Agent.Simulator/Tools/AircraftRegistryExtensions.cs
new file mode 100644
index 0000000..a268225
--- /dev/null
+++ b/OpenSky.Agent.Simulator/Tools/AircraftRegistryExtensions.cs
@@ -0,0 +1,43 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// OpenSky project 2021-2022
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace OpenSky.Agent.Simulator.Tools
+{
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Extension methods for removing simulator prefixes from aircraft registries.
+ ///
+ ///
+ /// sushi.at, 09/02/2022.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public static class AircraftRegistryExtensions
+ {
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// A string extension method that removes the simulation prefix from an aircraft registry.
+ ///
+ ///
+ /// sushi.at, 09/02/2022.
+ ///
+ ///
+ /// The registry to act on.
+ ///
+ ///
+ /// The registry without the prefix.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public static string RemoveSimPrefix(this string registry)
+ {
+ if (registry is { Length: >= 3 } && registry[1] == '.')
+ {
+ return registry.Substring(2);
+ }
+
+ return registry;
+ }
+ }
+}
diff --git a/OpenSky.Agent.UdpXPlane11/Models/AircraftIdentityDataRef.cs b/OpenSky.Agent.UdpXPlane11/Models/AircraftIdentityDataRef.cs
new file mode 100644
index 0000000..23a00f1
--- /dev/null
+++ b/OpenSky.Agent.UdpXPlane11/Models/AircraftIdentityDataRef.cs
@@ -0,0 +1,186 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// OpenSky project 2021-2022
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace OpenSky.Agent.UdpXPlane11.Models
+{
+ using OpenSkyApi;
+
+ using XPlaneConnector;
+ using XPlaneConnector.DataRefs;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// XPlane 11 dataref enabled version of aircraft identity model.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public class AircraftIdentityDataRef : Agent.Simulator.Models.AircraftIdentity
+ {
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// (Immutable) The aircraft ICAO character array.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private readonly char[] acfICAO = new char[40];
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// (Immutable) The aircraft description character array.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private readonly char[] acfDescription = new char[50];
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public AircraftIdentityDataRef()
+ {
+ // todo Not sure how to determine otherwise
+ this.FlapsAvailable = true;
+ this.AtcType = "n/a";
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Makes a copy of this object.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// A copy of this object.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public Agent.Simulator.Models.AircraftIdentity Clone()
+ {
+ return new Agent.Simulator.Models.AircraftIdentity
+ {
+ Type = this.Type,
+ EngineType = this.EngineType,
+ EngineCount = this.EngineCount,
+ AtcType = this.AtcType,
+ AtcModel = this.AtcModel,
+ FlapsAvailable = this.FlapsAvailable,
+ GearRetractable = this.GearRetractable
+ };
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Register with Xplane connector.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// The Xplane connector.
+ ///
+ ///
+ /// The configured sample rate.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public void RegisterWithConnector(XPlaneConnector connector, int sampleRate)
+ {
+ for (var i = 0; i < 40; i++)
+ {
+ var icao = DataRefs.AircraftViewAcfICAO;
+ icao.DataRef += $"[{i}]";
+ connector.Subscribe(icao, 1000 / sampleRate, this.DataRefUpdated);
+ }
+
+ for (var i = 0; i < 50; i++)
+ {
+ var description = DataRefs.AircraftViewAcfDescrip;
+ description.DataRef += $"[{i}]";
+ connector.Subscribe(description, 1000 / sampleRate, this.DataRefUpdated);
+ }
+
+ connector.Subscribe(DataRefs.AircraftEngineAcfNumEngines, 1000 / sampleRate, this.DataRefUpdated);
+ var engineType = DataRefs.AircraftPropAcfEnType;
+ engineType.DataRef += "[0]";
+ connector.Subscribe(engineType, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.AircraftGearAcfGearRetract, 1000 / sampleRate, this.DataRefUpdated);
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Dataref subscription updated.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// The element.
+ ///
+ ///
+ /// The value.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private void DataRefUpdated(DataRefElement element, float value)
+ {
+ if (element.DataRef.StartsWith(DataRefs.AircraftViewAcfICAO.DataRef))
+ {
+ if (element.DataRef.Contains("[") && element.DataRef.EndsWith("]"))
+ {
+ var indexString = element.DataRef.Split('[')[1].Replace("]", string.Empty);
+ if (int.TryParse(indexString, out var index) && index is >= 0 and < 40)
+ {
+ this.acfICAO[index] = (char)value;
+ this.AtcModel = new string(this.acfICAO).Replace("\0", string.Empty);
+ }
+ }
+ }
+
+ if (element.DataRef.StartsWith(DataRefs.AircraftViewAcfDescrip.DataRef))
+ {
+ if (element.DataRef.Contains("[") && element.DataRef.EndsWith("]"))
+ {
+ var indexString = element.DataRef.Split('[')[1].Replace("]", string.Empty);
+ if (int.TryParse(indexString, out var index) && index is >= 0 and < 50)
+ {
+ this.acfDescription[index] = (char)value;
+ this.Type = new string(this.acfDescription).Replace("\0", string.Empty);
+ }
+ }
+ }
+
+ if (element.DataRef == DataRefs.AircraftEngineAcfNumEngines.DataRef)
+ {
+ this.EngineCount = (int)value;
+ }
+
+ if (element.DataRef.StartsWith(DataRefs.AircraftPropAcfEnType.DataRef))
+ {
+ this.EngineType = (int)value switch
+ {
+ 0 => EngineType.Piston,
+ 1 => EngineType.Piston,
+ 2 => EngineType.Turboprop,
+ 3 => EngineType.Unsupported, // Electric engine
+ 4 => EngineType.Jet,
+ 5 => EngineType.Jet,
+ 6 => EngineType.Unsupported, // Rocket
+ 7 => EngineType.Unsupported, // Tip rockets
+ 8 => EngineType.Turboprop,
+ _ => EngineType.None
+ };
+ }
+
+ if (element.DataRef == DataRefs.AircraftGearAcfGearRetract.DataRef)
+ {
+ this.GearRetractable = (int)value == 1;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSky.Agent.UdpXPlane11/Models/FuelTanksDataRef.cs b/OpenSky.Agent.UdpXPlane11/Models/FuelTanksDataRef.cs
new file mode 100644
index 0000000..2c03cee
--- /dev/null
+++ b/OpenSky.Agent.UdpXPlane11/Models/FuelTanksDataRef.cs
@@ -0,0 +1,399 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// OpenSky project 2021-2022
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace OpenSky.Agent.UdpXPlane11.Models
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ using OpenSky.Agent.Simulator.Enums;
+
+ using XPlaneConnector;
+ using XPlaneConnector.DataRefs;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// XPlane 11 dataref enabled version of fuel tanks model.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public class FuelTanksDataRef : Agent.Simulator.Models.FuelTanks
+ {
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// The tank indices.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ internal Dictionary tankIndices = new();
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// (Immutable) The current fuel weight for each tank.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private readonly float[] tankFuelWeight = new float[9];
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// (Immutable) The fuel tank rations.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private readonly float[] tankRatios = { -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, };
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// (Immutable) the fuel tank X-axis coordinates.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private readonly float[] tankX = { -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999 };
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// The fuel maximum weight.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private float fuelMaxWeight;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// The fuel weight lbs/gal.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private double fuelWeight;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Makes a copy of this object.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// A copy of this object.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public Simulator.Models.FuelTanks Clone()
+ {
+ return new Simulator.Models.FuelTanks
+ {
+ // Omitted external tanks since XPlane only supports 9 tanks
+ FuelTankCenterCapacity = this.FuelTankCenterCapacity,
+ FuelTankCenter2Capacity = this.FuelTankCenter2Capacity,
+ FuelTankCenter3Capacity = this.FuelTankCenter3Capacity,
+ FuelTankLeftMainCapacity = this.FuelTankLeftMainCapacity,
+ FuelTankLeftAuxCapacity = this.FuelTankLeftAuxCapacity,
+ FuelTankLeftTipCapacity = this.FuelTankLeftTipCapacity,
+ FuelTankRightMainCapacity = this.FuelTankRightMainCapacity,
+ FuelTankRightAuxCapacity = this.FuelTankRightAuxCapacity,
+ FuelTankRightTipCapacity = this.FuelTankRightTipCapacity,
+
+ FuelTankCenterQuantity = this.FuelTankCenterQuantity,
+ FuelTankCenter2Quantity = this.FuelTankCenter2Quantity,
+ FuelTankCenter3Quantity = this.FuelTankCenter3Quantity,
+ FuelTankLeftMainQuantity = this.FuelTankLeftMainQuantity,
+ FuelTankLeftAuxQuantity = this.FuelTankLeftAuxQuantity,
+ FuelTankLeftTipQuantity = this.FuelTankLeftTipQuantity,
+ FuelTankRightMainQuantity = this.FuelTankRightMainQuantity,
+ FuelTankRightAuxQuantity = this.FuelTankRightAuxQuantity,
+ FuelTankRightTipQuantity = this.FuelTankRightTipQuantity,
+ };
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Register with Xplane connector.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// The Xplane connector.
+ ///
+ ///
+ /// The configured sample rate.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public void RegisterWithConnector(XPlaneConnector connector, int sampleRate)
+ {
+ for (var i = 0; i < 9; i++)
+ {
+ var tankRatio = DataRefs.AircraftOverflowAcfTankRat;
+ tankRatio.DataRef += $"[{i}]";
+ connector.Subscribe(tankRatio, 1000 / sampleRate, this.DataRefUpdated);
+
+ var tankWeight = DataRefs.FlightmodelWeightMFuel;
+ tankWeight.DataRef += $"[{i}]";
+ connector.Subscribe(tankWeight, 1000 / sampleRate, this.DataRefUpdated);
+
+ var tankXRef = DataRefs.AircraftOverflowAcfTankX;
+ tankXRef.DataRef += $"[{i}]";
+ connector.Subscribe(tankXRef, 1000 / sampleRate, this.DataRefUpdated);
+ }
+
+ connector.Subscribe(DataRefs.AircraftWeightAcfMFuelTot, 1000 / sampleRate, this.DataRefUpdated);
+ var engineType = DataRefs.AircraftPropAcfEnType;
+ engineType.DataRef += "[0]";
+ connector.Subscribe(engineType, 1000 / sampleRate, this.DataRefUpdated);
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Dataref subscription updated.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// The element.
+ ///
+ ///
+ /// The value.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private void DataRefUpdated(DataRefElement element, float value)
+ {
+ var updateCapacities = false;
+ var updateQuantities = false;
+ var updateIndices = false;
+ if (element.DataRef.StartsWith(DataRefs.AircraftOverflowAcfTankRat.DataRef))
+ {
+ if (element.DataRef.Contains("[") && element.DataRef.EndsWith("]"))
+ {
+ var indexString = element.DataRef.Split('[')[1].Replace("]", string.Empty);
+ if (int.TryParse(indexString, out var index) && index is >= 0 and < 9)
+ {
+ this.tankRatios[index] = value;
+ updateCapacities = true;
+ }
+ }
+ }
+
+ if (element.DataRef.StartsWith(DataRefs.FlightmodelWeightMFuel.DataRef))
+ {
+ if (element.DataRef.Contains("[") && element.DataRef.EndsWith("]"))
+ {
+ var indexString = element.DataRef.Split('[')[1].Replace("]", string.Empty);
+ if (int.TryParse(indexString, out var index) && index is >= 0 and < 9)
+ {
+ this.tankFuelWeight[index] = value;
+ updateQuantities = true;
+ }
+ }
+ }
+
+ if (element.DataRef.StartsWith(DataRefs.AircraftOverflowAcfTankX.DataRef))
+ {
+ if (element.DataRef.Contains("[") && element.DataRef.EndsWith("]"))
+ {
+ var indexString = element.DataRef.Split('[')[1].Replace("]", string.Empty);
+ if (int.TryParse(indexString, out var index) && index is >= 0 and < 9)
+ {
+ this.tankX[index] = value;
+ updateIndices = true;
+ }
+ }
+ }
+
+ if (element.DataRef == DataRefs.AircraftWeightAcfMFuelTot.DataRef)
+ {
+ this.fuelMaxWeight = value;
+ updateCapacities = true;
+ }
+
+ if (element.DataRef.StartsWith(DataRefs.AircraftPropAcfEnType.DataRef))
+ {
+ this.fuelWeight = (int)value switch
+ {
+ 0 => 6,
+ 1 => 6,
+ 2 => 6.7,
+ 3 => 0, // Electric engine
+ 4 => 6.7,
+ 5 => 6.7,
+ 6 => 0, // Rocket
+ 7 => 0, // Tip rockets
+ 8 => 6.7,
+ _ => 0
+ };
+ updateCapacities = true;
+ updateQuantities = true;
+ }
+
+ // ReSharper disable CompareOfFloatsByEqualityOperator
+ if ((updateIndices || updateCapacities) && this.tankX.All(t => t != -9999) && this.tankRatios.All(t => t != -9999))
+ {
+ this.tankIndices.Clear();
+ var leftTanks = new List();
+ var rightTanks = new List();
+ for (var i = 0; i < 9; i++)
+ {
+ // Is the tank used?
+ if (this.tankRatios[i] == 0)
+ {
+ continue;
+ }
+
+ // A center tank
+ if (this.tankX[i] < 0.5 && this.tankX[i] > -0.5)
+ {
+ if (!this.tankIndices.ContainsKey(FuelTank.Center))
+ {
+ this.tankIndices.Add(FuelTank.Center, i);
+ continue;
+ }
+
+ if (!this.tankIndices.ContainsKey(FuelTank.Center2))
+ {
+ this.tankIndices.Add(FuelTank.Center2, i);
+ continue;
+ }
+
+ if (!this.tankIndices.ContainsKey(FuelTank.Center3))
+ {
+ this.tankIndices.Add(FuelTank.Center3, i);
+ continue;
+ }
+
+ throw new Exception("Can't support more than 3 center tanks!");
+ }
+
+ // A right side tank
+ if (this.tankX[i] >= 0.5)
+ {
+ rightTanks.Add(new TankIndexWithRatio { Index = i, Ratio = this.tankRatios[i] });
+ continue;
+ }
+
+ // A left side tank
+ {
+ leftTanks.Add(new TankIndexWithRatio { Index = i, Ratio = this.tankRatios[i] });
+ }
+ }
+
+ // Add left and right tanks in order of their size
+ foreach (var tankIndexWithRatio in leftTanks.OrderByDescending(t => t.Ratio))
+ {
+ if (!this.tankIndices.ContainsKey(FuelTank.LeftMain))
+ {
+ this.tankIndices.Add(FuelTank.LeftMain, tankIndexWithRatio.Index);
+ continue;
+ }
+
+ if (!this.tankIndices.ContainsKey(FuelTank.LeftTip))
+ {
+ this.tankIndices.Add(FuelTank.LeftTip, tankIndexWithRatio.Index);
+ continue;
+ }
+
+ if (!this.tankIndices.ContainsKey(FuelTank.LeftAux))
+ {
+ this.tankIndices.Add(FuelTank.LeftAux, tankIndexWithRatio.Index);
+ continue;
+ }
+
+ if (!this.tankIndices.ContainsKey(FuelTank.External1))
+ {
+ this.tankIndices.Add(FuelTank.External1, tankIndexWithRatio.Index);
+ continue;
+ }
+
+ throw new Exception("Can't support more than 4 left side tanks!");
+ }
+
+ foreach (var tankIndexWithRatio in rightTanks.OrderByDescending(t => t.Ratio))
+ {
+ if (!this.tankIndices.ContainsKey(FuelTank.RightMain))
+ {
+ this.tankIndices.Add(FuelTank.RightMain, tankIndexWithRatio.Index);
+ continue;
+ }
+
+ if (!this.tankIndices.ContainsKey(FuelTank.RightTip))
+ {
+ this.tankIndices.Add(FuelTank.RightTip, tankIndexWithRatio.Index);
+ continue;
+ }
+
+ if (!this.tankIndices.ContainsKey(FuelTank.RightAux))
+ {
+ this.tankIndices.Add(FuelTank.RightAux, tankIndexWithRatio.Index);
+ continue;
+ }
+
+ if (!this.tankIndices.ContainsKey(FuelTank.External2))
+ {
+ this.tankIndices.Add(FuelTank.External2, tankIndexWithRatio.Index);
+ continue;
+ }
+
+ throw new Exception("Can't support more than 4 right side tanks!");
+ }
+ }
+
+ if (updateCapacities)
+ {
+ var capacities = new Dictionary();
+ foreach (FuelTank tank in Enum.GetValues(typeof(FuelTank)))
+ {
+ capacities.Add(tank, 0);
+ }
+
+ var totalCapacityGallons = (this.fuelMaxWeight * 2.205) / this.fuelWeight;
+ foreach (var tankIndex in this.tankIndices)
+ {
+ capacities[tankIndex.Key] = this.tankRatios[tankIndex.Value] * totalCapacityGallons;
+ }
+
+ this.UpdateCapactiesFromDictionary(capacities);
+ }
+
+ if (updateQuantities)
+ {
+ var quantities = new Dictionary();
+ foreach (FuelTank tank in Enum.GetValues(typeof(FuelTank)))
+ {
+ quantities.Add(tank, 0);
+ }
+
+ foreach (var tankIndex in this.tankIndices)
+ {
+ quantities[tankIndex.Key] = this.tankFuelWeight[tankIndex.Value] * 2.205 / this.fuelWeight;
+ }
+
+ this.UpdateQuantitiesFromDictionary(quantities);
+ }
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// A tank index with ratio (for sorting).
+ ///
+ ///
+ /// sushi.at, 11/02/2022.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private class TankIndexWithRatio
+ {
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Gets or sets the zero-based index of the fuel tank.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public int Index { get; set; }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Gets or sets the ratio.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public float Ratio { get; set; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSky.Agent.UdpXPlane11/Models/LandingAnalysisDataRef.cs b/OpenSky.Agent.UdpXPlane11/Models/LandingAnalysisDataRef.cs
new file mode 100644
index 0000000..cd3a759
--- /dev/null
+++ b/OpenSky.Agent.UdpXPlane11/Models/LandingAnalysisDataRef.cs
@@ -0,0 +1,203 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// OpenSky project 2021-2022
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace OpenSky.Agent.UdpXPlane11.Models
+{
+ using System;
+
+ using XPlaneConnector;
+ using XPlaneConnector.DataRefs;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// XPlane 11 dataref enabled version of landing analysis model.
+ ///
+ ///
+ /// sushi.at, 07/02/2022.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public class LandingAnalysisDataRef : Simulator.Models.LandingAnalysis
+ {
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// The heading.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private float heading;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// The wind degrees.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private float windDegrees;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// The wind speed.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private float windSpeed;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// sushi.at, 10/02/2022.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public LandingAnalysisDataRef()
+ {
+ // Todo figure out how to calculate that correctly in XP11
+ this.SpeedLat = 0;
+ this.SpeedLong = 1;
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Makes a copy of this object.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// A copy of this object.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public Simulator.Models.LandingAnalysis Clone()
+ {
+ return new Simulator.Models.LandingAnalysis
+ {
+ Latitude = this.Latitude,
+ Longitude = this.Longitude,
+ Altitude = this.Altitude,
+ OnGround = this.OnGround,
+ WindLat = this.WindLat,
+ WindLong = this.WindLong,
+ AirspeedTrue = this.AirspeedTrue,
+ GroundSpeed = this.GroundSpeed,
+ SpeedLat = this.SpeedLat,
+ SpeedLong = this.SpeedLong,
+ Gforce = this.Gforce,
+ LandingRateSeconds = this.LandingRateSeconds,
+ BankAngle = this.BankAngle
+ };
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Register with Xplane connector.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// The Xplane connector.
+ ///
+ ///
+ /// The configured sample rate.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public void RegisterWithConnector(XPlaneConnector connector, int sampleRate)
+ {
+ connector.Subscribe(DataRefs.FlightmodelPositionLatitude, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionLongitude, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionElevation, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionYAgl, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionMagPsi, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.WeatherWindDirectionDegt, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.WeatherWindSpeedKt, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionTrueAirspeed, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionGroundspeed, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.Flightmodel2MiscGforceNormal, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionVhInd, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionTruePhi, 1000 / sampleRate, this.DataRefUpdated);
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Dataref subscription updated.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// The element.
+ ///
+ ///
+ /// The value.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private void DataRefUpdated(DataRefElement element, float value)
+ {
+ if (element.DataRef == DataRefs.FlightmodelPositionLatitude.DataRef)
+ {
+ this.Latitude = value;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionLongitude.DataRef)
+ {
+ this.Longitude = value;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionElevation.DataRef)
+ {
+ this.Altitude = value * 3.281;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionYAgl.DataRef)
+ {
+ this.OnGround = value < 1; // todo there has to be a better way
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionTrueAirspeed.DataRef)
+ {
+ this.AirspeedTrue = value * 1.944;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionGroundspeed.DataRef)
+ {
+ this.GroundSpeed = value * 1.944;
+ }
+
+ if (element.DataRef == DataRefs.Flightmodel2MiscGforceNormal.DataRef)
+ {
+ this.Gforce = value;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionVhInd.DataRef)
+ {
+ this.LandingRateSeconds = value * 3.281;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionTruePhi.DataRef)
+ {
+ this.BankAngle = value;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionMagPsi.DataRef)
+ {
+ this.heading = value;
+ }
+
+ if (element.DataRef == DataRefs.WeatherWindDirectionDegt.DataRef)
+ {
+ this.windDegrees = value;
+ }
+
+ if (element.DataRef == DataRefs.WeatherWindSpeedKt.DataRef)
+ {
+ this.windSpeed = value * 1.944f;
+ }
+
+ var windDelta = Math.Abs(this.heading - this.windDegrees);
+ this.WindLat = Math.Sin((Math.PI / 180) * windDelta) * this.windSpeed;
+ this.WindLong = Math.Cos((Math.PI / 180) * windDelta) * this.windSpeed;
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSky.Agent.UdpXPlane11/Models/PayloadStationsDataRef.cs b/OpenSky.Agent.UdpXPlane11/Models/PayloadStationsDataRef.cs
new file mode 100644
index 0000000..e7ea8ae
--- /dev/null
+++ b/OpenSky.Agent.UdpXPlane11/Models/PayloadStationsDataRef.cs
@@ -0,0 +1,100 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// OpenSky project 2021-2022
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace OpenSky.Agent.UdpXPlane11.Models
+{
+ using XPlaneConnector;
+ using XPlaneConnector.DataRefs;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// XPlane 11 dataref enabled version of payload stations model.
+ ///
+ ///
+ /// sushi.at, 07/02/2022.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public class PayloadStationsDataRef : Simulator.Models.PayloadStations
+ {
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// sushi.at, 07/02/2022.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public PayloadStationsDataRef()
+ {
+ this.Count = 1;
+ this.Name1 = "Payload";
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Makes a copy of this object.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// A copy of this object.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public Simulator.Models.PayloadStations Clone()
+ {
+ return new Simulator.Models.PayloadStations
+ {
+ // Omitted the other 19 stations as they will never be populated
+ Count = this.Count,
+ Name1 = this.Name1,
+ Weight1 = this.Weight1
+ };
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Register with Xplane connector.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// The Xplane connector.
+ ///
+ ///
+ /// The configured sample rate.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public void RegisterWithConnector(XPlaneConnector connector, int sampleRate)
+ {
+ connector.Subscribe(DataRefs.FlightmodelWeightMFixed, 1000 / sampleRate, this.DataRefUpdated);
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Dataref subscription updated.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// The element.
+ ///
+ ///
+ /// The value.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private void DataRefUpdated(DataRefElement element, float value)
+ {
+ if (element.DataRef == DataRefs.FlightmodelWeightMFixed.DataRef)
+ {
+ this.Weight1 = value * 2.205;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSky.Agent.UdpXPlane11/Models/PrimaryTrackingDataRef.cs b/OpenSky.Agent.UdpXPlane11/Models/PrimaryTrackingDataRef.cs
new file mode 100644
index 0000000..c160f84
--- /dev/null
+++ b/OpenSky.Agent.UdpXPlane11/Models/PrimaryTrackingDataRef.cs
@@ -0,0 +1,196 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// OpenSky project 2021-2022
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace OpenSky.Agent.UdpXPlane11.Models
+{
+ using XPlaneConnector;
+ using XPlaneConnector.DataRefs;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// XPlane 11 dataref enabled version of primary tracking model.
+ ///
+ ///
+ /// sushi.at, 02/02/2022.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public class PrimaryTrackingDataRef : Simulator.Models.PrimaryTracking
+ {
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Makes a copy of this object.
+ ///
+ ///
+ /// sushi.at, 03/02/2022.
+ ///
+ ///
+ /// A copy of this object.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public Simulator.Models.PrimaryTracking Clone()
+ {
+ return new Simulator.Models.PrimaryTracking
+ {
+ Latitude = this.Latitude,
+ Longitude = this.Longitude,
+ Altitude = this.Altitude,
+ RadioHeight = this.RadioHeight,
+ IndicatedAltitude = this.IndicatedAltitude,
+ OnGround = this.OnGround,
+ Heading = this.Heading,
+ AirspeedTrue = this.AirspeedTrue,
+ GroundSpeed = this.GroundSpeed,
+ AirspeedIndicated = this.AirspeedIndicated,
+ PitchAngle = this.PitchAngle,
+ BankAngle = this.BankAngle,
+ VerticalSpeedSeconds = this.VerticalSpeedSeconds,
+ StallWarning = this.StallWarning,
+ OverspeedWarning = this.OverspeedWarning,
+ GForce = this.GForce,
+ SimulationRate = this.SimulationRate,
+ SlewActive = this.SlewActive,
+ Crash = this.Crash
+ };
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Register with Xplane connector.
+ ///
+ ///
+ /// sushi.at, 03/02/2022.
+ ///
+ ///
+ /// The Xplane connector.
+ ///
+ ///
+ /// The configured sample rate.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public void RegisterWithConnector(XPlaneConnector connector, int sampleRate)
+ {
+ connector.Subscribe(DataRefs.FlightmodelPositionLatitude, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionLongitude, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionElevation, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionYAgl, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelMiscHInd2, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionMagPsi, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionTrueAirspeed, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionGroundspeed, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionIndicatedAirspeed, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionTrueTheta, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionTruePhi, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelPositionVhInd, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.Cockpit2AnnunciatorsStallWarning, 1000 / sampleRate, this.DataRefUpdated);
+
+ // todo detect overspeed possible?
+ connector.Subscribe(DataRefs.Flightmodel2MiscGforceNormal, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.TimeSimSpeed, 1000 / sampleRate, this.DataRefUpdated);
+
+ // no slew mode really
+ connector.Subscribe(DataRefs.Flightmodel2MiscHasCrashed, 1000 / sampleRate, this.DataRefUpdated);
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Dataref subscription updated.
+ ///
+ ///
+ /// sushi.at, 03/02/2022.
+ ///
+ ///
+ /// The element.
+ ///
+ ///
+ /// The value.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private void DataRefUpdated(DataRefElement element, float value)
+ {
+ if (element.DataRef == DataRefs.FlightmodelPositionLatitude.DataRef)
+ {
+ this.Latitude = value;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionLongitude.DataRef)
+ {
+ this.Longitude = value;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionElevation.DataRef)
+ {
+ this.Altitude = value * 3.281;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionYAgl.DataRef)
+ {
+ this.RadioHeight = value * 3.281;
+ this.OnGround = value < 1; // todo there has to be a better way
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelMiscHInd2.DataRef)
+ {
+ this.IndicatedAltitude = value;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionMagPsi.DataRef)
+ {
+ this.Heading = value;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionTrueAirspeed.DataRef)
+ {
+ this.AirspeedTrue = value * 1.944;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionGroundspeed.DataRef)
+ {
+ this.GroundSpeed = value * 1.944;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionIndicatedAirspeed.DataRef)
+ {
+ this.AirspeedIndicated = value * 1.944;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionTrueTheta.DataRef)
+ {
+ this.PitchAngle = value;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionTruePhi.DataRef)
+ {
+ this.BankAngle = value;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelPositionVhInd.DataRef)
+ {
+ this.VerticalSpeedSeconds = value * 3.281;
+ }
+
+ if (element.DataRef == DataRefs.Cockpit2AnnunciatorsStallWarning.DataRef)
+ {
+ this.StallWarning = (int)value == 1;
+ }
+
+ if (element.DataRef == DataRefs.Flightmodel2MiscGforceNormal.DataRef)
+ {
+ this.GForce = value;
+ }
+
+ if (element.DataRef == DataRefs.TimeSimSpeed.DataRef)
+ {
+ this.SimulationRate = value;
+ }
+
+ if (element.DataRef == DataRefs.Flightmodel2MiscHasCrashed.DataRef)
+ {
+ this.Crash = (int)value == 1;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSky.Agent.UdpXPlane11/Models/SecondaryTrackingDataRef.cs b/OpenSky.Agent.UdpXPlane11/Models/SecondaryTrackingDataRef.cs
new file mode 100644
index 0000000..3ced2da
--- /dev/null
+++ b/OpenSky.Agent.UdpXPlane11/Models/SecondaryTrackingDataRef.cs
@@ -0,0 +1,340 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// OpenSky project 2021-2022
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace OpenSky.Agent.UdpXPlane11.Models
+{
+ using System;
+ using System.Diagnostics;
+
+ using OpenSky.Agent.Simulator.Enums;
+ using OpenSky.FlightLogXML;
+
+ using XPlaneConnector;
+ using XPlaneConnector.DataRefs;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// XPlane 11 dataref enabled version of secondary tracking model.
+ ///
+ ///
+ /// sushi.at, 03/02/2022.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public class SecondaryTrackingDataRef : Simulator.Models.SecondaryTracking
+ {
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Number of engines.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private int numberOfEngines;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// sushi.at, 03/02/2022.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public SecondaryTrackingDataRef()
+ {
+ // These can't be changed in XPlane
+ this.CrashDetection = true;
+ this.UnlimitedFuel = false;
+
+ this.UtcYear = DateTime.UtcNow.Year; // Doesn't seem to exist in xplane
+ this.TimeOfDay = TimeOfDay.Unknown; // todo check if we can determine this somehow
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Makes a copy of this object.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// A copy of this object.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public Simulator.Models.SecondaryTracking Clone()
+ {
+ return new Simulator.Models.SecondaryTracking
+ {
+ UtcTime = this.UtcTime,
+ UtcDay = this.UtcDay,
+ UtcMonth = this.UtcMonth,
+ UtcYear = this.UtcYear,
+ TimeOfDay = this.TimeOfDay,
+ CrashDetection = this.CrashDetection,
+ UnlimitedFuel = this.UnlimitedFuel,
+ ElectricalMasterBattery = this.ElectricalMasterBattery,
+ EngineCombustion1 = this.EngineCombustion1,
+ EngineCombustion2 = this.EngineCombustion2,
+ EngineCombustion3 = this.EngineCombustion3,
+ EngineCombustion4 = this.EngineCombustion4,
+ Pushback = this.Pushback,
+ ApuGenerator = this.ApuGenerator,
+ LightBeacon = this.LightBeacon,
+ LightNav = this.LightNav,
+ LightStrobe = this.LightStrobe,
+ LightTaxi = this.LightTaxi,
+ LightLanding = this.LightLanding,
+ FlapsHandle = this.FlapsHandle,
+ FlapsPercentage = this.FlapsPercentage,
+ GearHandle = this.GearHandle,
+ GearPercentage = this.GearPercentage,
+ AutoPilot = this.AutoPilot,
+ ParkingBrake = this.ParkingBrake,
+ SpoilersArmed = this.SpoilersArmed,
+ SeatBeltSign = this.SeatBeltSign,
+ NoSmokingSign = this.NoSmokingSign
+ };
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Register with Xplane connector.
+ ///
+ ///
+ /// sushi.at, 03/02/2022.
+ ///
+ ///
+ /// The Xplane connector.
+ ///
+ ///
+ /// The configured sample rate.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public void RegisterWithConnector(XPlaneConnector connector, int sampleRate)
+ {
+ connector.Subscribe(DataRefs.TimeZuluTimeSec, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.Cockpit2ClockTimerCurrentDay, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.Cockpit2ClockTimerCurrentMonth, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.CockpitElectricalBatteryOn, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.AircraftEngineAcfNumEngines, 1000 / sampleRate, this.DataRefUpdated);
+ var engine1Running = DataRefs.FlightmodelEngineENGNRunning;
+ engine1Running.DataRef += "[0]";
+ connector.Subscribe(engine1Running, 1000 / sampleRate, this.DataRefUpdated);
+ var engine2Running = DataRefs.FlightmodelEngineENGNRunning;
+ engine2Running.DataRef += "[1]";
+ connector.Subscribe(engine2Running, 1000 / sampleRate, this.DataRefUpdated);
+ var engine3Running = DataRefs.FlightmodelEngineENGNRunning;
+ engine3Running.DataRef += "[2]";
+ connector.Subscribe(engine3Running, 1000 / sampleRate, this.DataRefUpdated);
+ var engine4Running = DataRefs.FlightmodelEngineENGNRunning;
+ engine4Running.DataRef += "[3]";
+ connector.Subscribe(engine4Running, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.GraphicsAnimationGroundTrafficTowbarHeadingDeg, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.Cockpit2ElectricalAPURunning, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.CockpitElectricalBeaconLightsOn, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.CockpitElectricalNavLightsOn, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.CockpitElectricalStrobeLightsOn, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.CockpitElectricalTaxiLightOn, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.CockpitElectricalLandingLightsOn, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelControlsFlaprqst, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelControlsFlaprat, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.CockpitSwitchesGearHandleStatus, 1000 / sampleRate, this.DataRefUpdated);
+ var gearDeploy = DataRefs.Flightmodel2GearDeployRatio;
+ gearDeploy.DataRef += "[0]";
+ connector.Subscribe(gearDeploy, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.CockpitAutopilotAutopilotMode, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelControlsParkbrake, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelControlsSbrkrqst, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.CockpitSwitchesFastenSeatBelts, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.CockpitSwitchesNoSmoking, 1000 / sampleRate, this.DataRefUpdated);
+
+ for (var i = 0; i < 40; i++)
+ {
+ var tailNum = DataRefs.AircraftViewAcfTailnum;
+ tailNum.DataRef += $"[{i}]";
+ connector.Subscribe(tailNum, 1000 / sampleRate, this.DataRefUpdated);
+ }
+ }
+
+ private readonly char[] tailNumber = new char[40];
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Dataref subscription updated.
+ ///
+ ///
+ /// sushi.at, 03/02/2022.
+ ///
+ ///
+ /// The element.
+ ///
+ ///
+ /// The value.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private void DataRefUpdated(DataRefElement element, float value)
+ {
+ if (element.DataRef.StartsWith(DataRefs.AircraftViewAcfTailnum.DataRef))
+ {
+ if (element.DataRef.Contains("[") && element.DataRef.EndsWith("]"))
+ {
+ var indexString = element.DataRef.Split('[')[1].Replace("]", string.Empty);
+ if (int.TryParse(indexString, out var index) && index is >= 0 and < 40)
+ {
+ this.tailNumber[index] = (char)value;
+ var tailString = new string(this.tailNumber).Replace("\0", string.Empty);
+ Debug.WriteLine($"Registry: {tailString}");
+ }
+ }
+ }
+
+ if (element.DataRef == DataRefs.TimeZuluTimeSec.DataRef)
+ {
+ this.UtcTime = value;
+ }
+
+ if (element.DataRef == DataRefs.Cockpit2ClockTimerCurrentDay.DataRef)
+ {
+ this.UtcDay = (int)value;
+ }
+
+ if (element.DataRef == DataRefs.Cockpit2ClockTimerCurrentMonth.DataRef)
+ {
+ this.UtcMonth = (int)value;
+ }
+
+ if (element.DataRef == DataRefs.CockpitElectricalBatteryOn.DataRef)
+ {
+ this.ElectricalMasterBattery = (int)value == 1;
+ }
+
+ if (element.DataRef == DataRefs.AircraftEngineAcfNumEngines.DataRef)
+ {
+ this.numberOfEngines = (int)value;
+ if (this.numberOfEngines < 1)
+ {
+ this.EngineCombustion1 = false;
+ }
+
+ if (this.numberOfEngines < 2)
+ {
+ this.EngineCombustion2 = false;
+ }
+
+ if (this.numberOfEngines < 3)
+ {
+ this.EngineCombustion3 = false;
+ }
+
+ if (this.numberOfEngines < 4)
+ {
+ this.EngineCombustion4 = false;
+ }
+ }
+
+ if (element.DataRef.StartsWith(DataRefs.FlightmodelEngineENGNRunning.DataRef))
+ {
+ if (element.DataRef.EndsWith("[0]"))
+ {
+ this.EngineCombustion1 = (int)value == 1 && this.numberOfEngines >= 1;
+ }
+
+ if (element.DataRef.EndsWith("[1]"))
+ {
+ this.EngineCombustion2 = (int)value == 1 && this.numberOfEngines >= 2;
+ }
+
+ if (element.DataRef.EndsWith("[2]"))
+ {
+ this.EngineCombustion3 = (int)value == 1 && this.numberOfEngines >= 3;
+ }
+
+ if (element.DataRef.EndsWith("[3]"))
+ {
+ this.EngineCombustion4 = (int)value == 1 && this.numberOfEngines >= 4;
+ }
+ }
+
+ if (element.DataRef == DataRefs.GraphicsAnimationGroundTrafficTowbarHeadingDeg.DataRef)
+ {
+ this.Pushback = value != 0 ? Pushback.Straight : Pushback.NoPushback; // todo check
+ }
+
+ if (element.DataRef == DataRefs.Cockpit2ElectricalAPURunning.DataRef)
+ {
+ this.ApuGenerator = (int)value == 1;
+ }
+
+ if (element.DataRef == DataRefs.CockpitElectricalBeaconLightsOn.DataRef)
+ {
+ this.LightBeacon = (int)value == 1;
+ }
+
+ if (element.DataRef == DataRefs.CockpitElectricalNavLightsOn.DataRef)
+ {
+ this.LightNav = (int)value == 1;
+ }
+
+ if (element.DataRef == DataRefs.CockpitElectricalStrobeLightsOn.DataRef)
+ {
+ this.LightStrobe = (int)value == 1;
+ }
+
+ if (element.DataRef == DataRefs.CockpitElectricalTaxiLightOn.DataRef)
+ {
+ this.LightTaxi = (int)value == 1;
+ }
+
+ if (element.DataRef == DataRefs.CockpitElectricalLandingLightsOn.DataRef)
+ {
+ this.LightLanding = (int)value == 1;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelControlsFlaprqst.DataRef)
+ {
+ this.FlapsHandle = value * 100;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelControlsFlaprat.DataRef)
+ {
+ this.FlapsPercentage = value * 100;
+ }
+
+ if (element.DataRef == DataRefs.CockpitSwitchesGearHandleStatus.DataRef)
+ {
+ this.GearHandle = (int)value == 1;
+ }
+
+ if (element.DataRef.StartsWith(DataRefs.Flightmodel2GearDeployRatio.DataRef))
+ {
+ this.GearPercentage = value;
+ }
+
+ if (element.DataRef == DataRefs.CockpitAutopilotAutopilotMode.DataRef)
+ {
+ this.AutoPilot = (int)value == 2;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelControlsParkbrake.DataRef)
+ {
+ this.ParkingBrake = value > 0.1;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelControlsSbrkrqst.DataRef)
+ {
+ this.SpoilersArmed = value < 0;
+ }
+
+ if (element.DataRef == DataRefs.CockpitSwitchesFastenSeatBelts.DataRef)
+ {
+ this.SeatBeltSign = (int)value == 1;
+ }
+
+ if (element.DataRef == DataRefs.CockpitSwitchesNoSmoking.DataRef)
+ {
+ this.NoSmokingSign = (int)value == 1;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSky.Agent.UdpXPlane11/Models/WeightAndBalanceDataRef.cs b/OpenSky.Agent.UdpXPlane11/Models/WeightAndBalanceDataRef.cs
new file mode 100644
index 0000000..d4f40a2
--- /dev/null
+++ b/OpenSky.Agent.UdpXPlane11/Models/WeightAndBalanceDataRef.cs
@@ -0,0 +1,188 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// OpenSky project 2021-2022
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace OpenSky.Agent.UdpXPlane11.Models
+{
+ using XPlaneConnector;
+ using XPlaneConnector.DataRefs;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// XPlane 11 dataref enabled version of weight and balance model.
+ ///
+ ///
+ /// sushi.at, 07/02/2022.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public class WeightAndBalanceDataRef : Simulator.Models.WeightAndBalance
+ {
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// The fuel maximum weight.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private float fuelMaxWeight;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// The fuel weight.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private float fuelWeight;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// sushi.at, 07/02/2022.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public WeightAndBalanceDataRef()
+ {
+ // XPlane doesn't have a variables for the current CG
+ this.CgPercentLateral = 0;
+ this.CgPercent = 0;
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Makes a copy of this object.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// A copy of this object.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public Simulator.Models.WeightAndBalance Clone()
+ {
+ return new Simulator.Models.WeightAndBalance
+ {
+ EmptyWeight = this.EmptyWeight,
+ TotalWeight = this.TotalWeight,
+ MaxGrossWeight = this.MaxGrossWeight,
+ FuelTotalCapacity = this.FuelTotalCapacity,
+ FuelTotalQuantity = this.FuelTotalQuantity,
+ FuelWeightPerGallon = this.FuelWeightPerGallon,
+ CgAftLimit = this.CgAftLimit,
+ CgFwdLimit = this.CgFwdLimit,
+ CgPercent = this.CgPercent,
+ CgPercentLateral = this.CgPercentLateral
+ };
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Register with Xplane connector.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// The Xplane connector.
+ ///
+ ///
+ /// The configured sample rate.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public void RegisterWithConnector(XPlaneConnector connector, int sampleRate)
+ {
+ connector.Subscribe(DataRefs.AircraftWeightAcfMEmpty, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelWeightMTotal, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.AircraftWeightAcfMMax, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.AircraftWeightAcfMFuelTot, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.FlightmodelWeightMFuelTotal, 1000 / sampleRate, this.DataRefUpdated);
+ var engineType = DataRefs.AircraftPropAcfEnType;
+ engineType.DataRef += "[0]";
+ connector.Subscribe(engineType, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.AircraftOverflowAcfCgzAft, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.AircraftOverflowAcfCgzFwd, 1000 / sampleRate, this.DataRefUpdated);
+ connector.Subscribe(DataRefs.Cockpit2GaugesIndicatorsCGIndicator, 1000 / sampleRate, this.DataRefUpdated);
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Dataref subscription updated.
+ ///
+ ///
+ /// sushi.at, 06/02/2022.
+ ///
+ ///
+ /// The element.
+ ///
+ ///
+ /// The value.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private void DataRefUpdated(DataRefElement element, float value)
+ {
+ var updateFuelValues = false;
+ if (element.DataRef == DataRefs.AircraftWeightAcfMEmpty.DataRef)
+ {
+ this.EmptyWeight = value * 2.205;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelWeightMTotal.DataRef)
+ {
+ this.TotalWeight = value * 2.205;
+ }
+
+ if (element.DataRef == DataRefs.AircraftWeightAcfMMax.DataRef)
+ {
+ this.MaxGrossWeight = value * 2.205;
+ }
+
+ if (element.DataRef == DataRefs.AircraftWeightAcfMFuelTot.DataRef)
+ {
+ this.fuelMaxWeight = value;
+ updateFuelValues = true;
+ }
+
+ if (element.DataRef == DataRefs.FlightmodelWeightMFuelTotal.DataRef)
+ {
+ this.fuelWeight = value;
+ updateFuelValues = true;
+ }
+
+ if (element.DataRef.StartsWith(DataRefs.AircraftPropAcfEnType.DataRef))
+ {
+ this.FuelWeightPerGallon = (int)value switch
+ {
+ 0 => 6,
+ 1 => 6,
+ 2 => 6.7,
+ 3 => 0, // Electric engine
+ 4 => 6.7,
+ 5 => 6.7,
+ 6 => 0, // Rocket
+ 7 => 0, // Tip rockets
+ 8 => 6.7,
+ _ => 0
+ };
+ updateFuelValues = true;
+ }
+
+ if (element.DataRef == DataRefs.AircraftOverflowAcfCgzAft.DataRef)
+ {
+ this.CgAftLimit = value;
+ }
+
+ if (element.DataRef == DataRefs.AircraftOverflowAcfCgzFwd.DataRef)
+ {
+ this.CgFwdLimit = value;
+ }
+
+ if (updateFuelValues)
+ {
+ this.FuelTotalCapacity = (this.fuelMaxWeight * 2.205) / this.FuelWeightPerGallon;
+ this.FuelTotalQuantity = (this.fuelWeight * 2.205) / this.FuelWeightPerGallon;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSky.Agent.UdpXPlane11/OpenSky.Agent.UdpXPlane11.csproj b/OpenSky.Agent.UdpXPlane11/OpenSky.Agent.UdpXPlane11.csproj
new file mode 100644
index 0000000..3e571da
--- /dev/null
+++ b/OpenSky.Agent.UdpXPlane11/OpenSky.Agent.UdpXPlane11.csproj
@@ -0,0 +1,86 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {DFBDA2B8-5775-4766-BE86-D729FCF20DE1}
+ Library
+ Properties
+ OpenSky.Agent.UdpXPlane11
+ OpenSky.Agent.UdpXPlane11
+ v4.8
+ 512
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ x64
+ latest
+ bin\Debug\OpenSky.Agent.UdpXPlane11.xml
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ x64
+ latest
+ bin\Release\OpenSky.Agent.UdpXPlane11.xml
+
+
+
+ ..\packages\JetBrains.Annotations.2021.3.0\lib\net20\JetBrains.Annotations.dll
+
+
+ ..\packages\OpenSky.FlightLogXML.0.1.5\lib\net48\OpenSky.FlightLogXML.dll
+
+
+ ..\packages\MSFT.ParallelExtensionsExtras.1.2.0\lib\ParallelExtensionsExtras.dll
+
+
+
+
+
+
+
+
+
+
+ ..\packages\XPlaneConnector.1.3.0\lib\netstandard2.0\XPlaneConnector.dll
+
+
+ ..\packages\XPlaneConnector.DataRefs.11.51.0\lib\netstandard2.0\XPlaneConnector.DataRefs.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {30c467e8-2eee-41e5-be01-0142a61ba171}
+ OpenSky.Agent.Simulator
+
+
+
+
+
\ No newline at end of file
diff --git a/OpenSky.Agent.UdpXPlane11/Properties/AssemblyInfo.cs b/OpenSky.Agent.UdpXPlane11/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d429d0e
--- /dev/null
+++ b/OpenSky.Agent.UdpXPlane11/Properties/AssemblyInfo.cs
@@ -0,0 +1,21 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// OpenSky project 2021-2022
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("OpenSky.Agent.UdpXP11")]
+[assembly: AssemblyDescription("OpenSky Agent UDP library for X-Plane 11")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("OpenSky")]
+[assembly: AssemblyProduct("OpenSky")]
+[assembly: AssemblyCopyright("OpenSky project 2021-2022")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: Guid("dfbda2b8-5775-4766-be86-d729fcf20de1")]
+[assembly: AssemblyVersion("0.4.0")]
+[assembly: AssemblyFileVersion("0.4.0")]
\ No newline at end of file
diff --git a/OpenSky.Agent.UdpXPlane11/UdpXPlane11.cs b/OpenSky.Agent.UdpXPlane11/UdpXPlane11.cs
new file mode 100644
index 0000000..5c4e7e8
--- /dev/null
+++ b/OpenSky.Agent.UdpXPlane11/UdpXPlane11.cs
@@ -0,0 +1,540 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// OpenSky project 2021-2022
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace OpenSky.Agent.UdpXPlane11
+{
+ using System;
+ using System.Diagnostics;
+ using System.Linq;
+ using System.Net.Sockets;
+ using System.Threading;
+
+ using OpenSky.Agent.Simulator.Enums;
+ using OpenSky.Agent.Simulator.Models;
+ using OpenSky.Agent.Simulator.Tools;
+ using OpenSky.Agent.UdpXPlane11.Models;
+
+ using OpenSkyApi;
+
+ using XPlaneConnector;
+ using XPlaneConnector.DataRefs;
+
+ using Simulator = Simulator.Simulator;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// UDP client for X-Plane 11.
+ ///
+ ///
+ /// sushi.at, 02/02/2022.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public class UdpXPlane11 : Simulator
+ {
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// (Immutable) the simulator IP address.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private readonly string simulatorIPAddress;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// (Immutable) the simulator port.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private readonly uint simulatorPort;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// The UDP xplane connector.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private XPlaneConnector connector;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// sushi.at, 02/02/2022.
+ ///
+ ///
+ /// Name of the simulator IP address.
+ ///
+ ///
+ /// The simulator port.
+ ///
+ ///
+ /// The OpenSky service instance.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public UdpXPlane11(string simulatorIPAddress, uint simulatorPort, OpenSkyService openSkyServiceInstance) : base(openSkyServiceInstance)
+ {
+ this.simulatorIPAddress = simulatorIPAddress;
+ this.simulatorPort = simulatorPort;
+
+ // Initialize empty data structures, to prevent NullReferenceExceptions
+ this.PrimaryTracking = new PrimaryTracking();
+ this.SecondaryTracking = new SecondaryTracking();
+ this.FuelTanks = new FuelTanks();
+ this.PayloadStations = new PayloadStations();
+ this.AircraftIdentity = new AircraftIdentity();
+ this.WeightAndBalance = new WeightAndBalance();
+
+ // Start our worker thread
+ new Thread(this.ReadFromXPlane) { Name = "UdpXPlane11.ReadFromXPlane" }.Start();
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Gets the name of the simulator interface.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public static string SimulatorInterfaceName => "UdpXPlane11";
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Gets a value indicating whether the sim is paused (proper pause, not ESC menu and definitely
+ /// not active pause).
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public override bool IsPaused => this.PrimaryTracking?.SimulationRate == 0;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Gets the type of the simulator.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public override OpenSkyApi.Simulator SimulatorType => OpenSkyApi.Simulator.XPlane11;
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Pauses the simulator, in XPlane 11 that means setting the simrate to 0.
+ ///
+ ///
+ /// sushi.at, 31/01/2022.
+ ///
+ ///
+ /// True to pause, false to un-pause.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public override void Pause(bool pause)
+ {
+ this.connector?.SetDataRefValue(DataRefs.TimeSimSpeed, pause ? 0 : 1);
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Sets the aircraft registration in the simulator.
+ ///
+ ///
+ /// sushi.at, 31/01/2022.
+ ///
+ ///
+ /// The registry to set.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public override void SetAircraftRegistry(string registry)
+ {
+ // Doesn't work in XP11 (comes from livery, the dataref is write-able but has no effect)
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Sets fuel and payload to values restored from a save file.
+ ///
+ ///
+ /// sushi.at, 31/01/2022.
+ ///
+ ///
+ /// Thrown when an exception error condition occurs.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public override void SetFuelAndPayloadFromSave()
+ {
+ if (this.Connected)
+ {
+ if (this.flightLoadingTempModels == null)
+ {
+ throw new Exception("No restored fuel and payload station values found.");
+ }
+
+ Debug.WriteLine("UdpXplane11 setting fuel and payload stations from temp structs restored from save");
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[0]", (float)this.flightLoadingTempModels.FuelTanks.FuelTankLeftMainQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[1]", (float)this.flightLoadingTempModels.FuelTanks.FuelTankRightMainQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[2]", (float)this.flightLoadingTempModels.FuelTanks.FuelTankLeftTipQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[3]", (float)this.flightLoadingTempModels.FuelTanks.FuelTankRightTipQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[4]", (float)this.flightLoadingTempModels.FuelTanks.FuelTankLeftAuxQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[5]", (float)this.flightLoadingTempModels.FuelTanks.FuelTankRightAuxQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[6]", (float)this.flightLoadingTempModels.FuelTanks.FuelTankCenterQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[7]", (float)this.flightLoadingTempModels.FuelTanks.FuelTankCenter2Quantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[8]", (float)this.flightLoadingTempModels.FuelTanks.FuelTankCenter3Quantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFixed, (float)this.flightLoadingTempModels.PayloadStations.Weight1 / 2.205f);
+
+ this.RefreshModelNow(Requests.FuelTanks);
+ this.RefreshModelNow(Requests.PayloadStations);
+ }
+ else
+ {
+ throw new Exception("Not connected to sim!");
+ }
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Sets the fuel tanks quantities in the simulator.
+ ///
+ ///
+ /// sushi.at, 31/01/2022.
+ ///
+ ///
+ /// The new fuel tank quantities to set.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public override void SetFuelTanks(FuelTanks newFuelTanks)
+ {
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[0]", (float)newFuelTanks.FuelTankLeftMainQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[1]", (float)newFuelTanks.FuelTankRightMainQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[2]", (float)newFuelTanks.FuelTankLeftTipQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[3]", (float)newFuelTanks.FuelTankRightTipQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[4]", (float)newFuelTanks.FuelTankLeftAuxQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[5]", (float)newFuelTanks.FuelTankRightAuxQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[6]", (float)newFuelTanks.FuelTankCenterQuantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[7]", (float)newFuelTanks.FuelTankCenter2Quantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFuel.DataRef + "[8]", (float)newFuelTanks.FuelTankCenter3Quantity / 2.205f * (float)this.WeightAndBalance.FuelWeightPerGallon);
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Sets the payload station weights in the simulator.
+ ///
+ ///
+ /// sushi.at, 31/01/2022.
+ ///
+ ///
+ /// The new payload station weights to set.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public override void SetPayloadStations(PayloadStations newPayloadStations)
+ {
+ this.connector?.SetDataRefValue(DataRefs.FlightmodelWeightMFixed, (float)newPayloadStations.Weight1 / 2.205f);
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Sets slew to on or off.
+ ///
+ ///
+ /// sushi.at, 31/01/2022.
+ ///
+ ///
+ /// True to enable, false to disable.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public override void SetSlew(bool enable)
+ {
+ // Slew does not exist in XPlane11, so we are going to use pause instead
+ this.connector?.SetDataRefValue(DataRefs.TimeSimSpeed, enable ? 0 : 1);
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Sets the UTC time in the sim.
+ ///
+ ///
+ /// sushi.at, 31/01/2022.
+ ///
+ ///
+ /// The new UTC time.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public override void SetTime(DateTime time)
+ {
+ this.connector?.SetDataRefValue(DataRefs.Cockpit2ClockTimerCurrentDay, time.Day);
+ this.connector?.SetDataRefValue(DataRefs.Cockpit2ClockTimerCurrentMonth, time.Month);
+ this.connector?.SetDataRefValue(DataRefs.TimeZuluTimeSec, time.Hour * 60 * 60 + time.Minute * 60 + time.Second);
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Slew plane to flight position - flight object determines where, either moves plane to
+ /// starting position or to last reported flight position.
+ ///
+ ///
+ /// sushi.at, 31/01/2022.
+ ///
+ ///
+ /// Thrown when an exception error condition occurs.
+ ///
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public override void SlewPlaneToFlightPosition()
+ {
+ if (this.Connected)
+ {
+ if (this.Flight == null)
+ {
+ throw new Exception("Not currently tracking a flight!");
+ }
+
+ // Slew into starting position at origin airport?
+ if (!this.Flight.Resume)
+ {
+ throw new Exception("Slew to Origin is currently not supported for X-Plane 11. Please use the map in the simulator.");
+
+ //if (!this.PrimaryTracking.OnGround || this.PrimaryTracking.GroundSpeed > 1)
+ //{
+ // throw new Exception("Plane needs to be stationary on the ground for this!");
+ //}
+
+ //if (!this.PrimaryTracking.SlewActive)
+ //{
+ // this.SetSlew(true);
+ //}
+
+ //var dg = new XPDatagram();
+ //dg.Add("POSI");
+ //dg.Bytes.Add(0); // aircraft index, 0 is the player's
+
+ //// Long, Lat and Alt are doubles
+ //{
+ // var doubleBytes = BitConverter.GetBytes(this.Flight?.Origin.Latitude ?? 0);
+ // dg.Bytes.AddRange(BitConverter.IsLittleEndian ? doubleBytes : doubleBytes.Reverse());
+ //}
+ //{
+ // var doubleBytes = BitConverter.GetBytes(this.Flight?.Origin.Longitude ?? 0);
+ // dg.Bytes.AddRange(BitConverter.IsLittleEndian ? doubleBytes : doubleBytes.Reverse());
+ //}
+ //{
+ // var doubleBytes = BitConverter.GetBytes(-998d); // TODO what would you put there without knowing the ground elevation at the target coordinates?
+ // dg.Bytes.AddRange(BitConverter.IsLittleEndian ? doubleBytes : doubleBytes.Reverse());
+ //}
+
+ ////dg.Add((float)(this.Flight?.Origin.Latitude ?? 0));
+ ////dg.Add((float)(this.Flight?.Origin.Longitude ?? 0));
+ ////dg.Add(-998f);
+
+ //dg.Add(-998f);
+ //dg.Add(-998f);
+ //dg.Add(-998f);
+ //dg.Add(-998f);
+ ////dg.FillTo(509);
+
+ //var client = new UdpClient();
+ //client.Connect(this.simulatorIPAddress, 49009);
+ //client.Send(dg.Get(), dg.Len);
+ }
+ else
+ {
+ if (this.flightLoadingTempModels == null)
+ {
+ throw new Exception("No resume position available.");
+ }
+
+ if (!this.PrimaryTracking.SlewActive)
+ {
+ this.SetSlew(true);
+ }
+
+ var dg = new XPDatagram();
+ dg.Add("POSI");
+ dg.Bytes.Add(0); // aircraft index, 0 is the player's
+
+ // Long, Lat and Alt are doubles
+ {
+ var doubleBytes = BitConverter.GetBytes(this.flightLoadingTempModels.SlewAircraftIntoPosition.Latitude);
+ dg.Bytes.AddRange(BitConverter.IsLittleEndian ? doubleBytes : doubleBytes.Reverse());
+ }
+ {
+ var doubleBytes = BitConverter.GetBytes(this.flightLoadingTempModels.SlewAircraftIntoPosition.Longitude);
+ dg.Bytes.AddRange(BitConverter.IsLittleEndian ? doubleBytes : doubleBytes.Reverse());
+ }
+ {
+ var doubleBytes = BitConverter.GetBytes(this.flightLoadingTempModels.SlewAircraftIntoPosition.Altitude / 3.281);
+ dg.Bytes.AddRange(BitConverter.IsLittleEndian ? doubleBytes : doubleBytes.Reverse());
+ }
+
+ dg.Add((float)this.flightLoadingTempModels.SlewAircraftIntoPosition.PitchAngle);
+ dg.Add((float)this.flightLoadingTempModels.SlewAircraftIntoPosition.BankAngle);
+ dg.Add((float)this.flightLoadingTempModels.SlewAircraftIntoPosition.Heading);
+ dg.Add(-998f); // Don't change gear
+
+ var client = new UdpClient();
+ client.Connect(this.simulatorIPAddress, 49009);
+ client.Send(dg.Get(), dg.Len);
+ }
+ }
+ else
+ {
+ throw new Exception("Not connected to sim!");
+ }
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Read from X-Plane 11 UDP connector on background thread.
+ ///
+ ///
+ /// sushi.at, 02/02/2022.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private void ReadFromXPlane()
+ {
+ try
+ {
+ // Create dataref handlers
+ var primaryTracking = new PrimaryTrackingDataRef();
+ var secondaryTracking = new SecondaryTrackingDataRef();
+ var aircraftIdentity = new AircraftIdentityDataRef();
+ var fuelTanks = new FuelTanksDataRef();
+ var payloadStations = new PayloadStationsDataRef();
+ var weightAndBalance = new WeightAndBalanceDataRef();
+ var landingAnalysis = new LandingAnalysisDataRef();
+
+ while (!this.close)
+ {
+ try
+ {
+ if ((DateTime.Now - (this.connector?.LastReceive ?? DateTime.MinValue)) > TimeSpan.FromSeconds(10))
+ {
+ this.Connected = false;
+ try
+ {
+ this.connector?.Stop();
+ }
+ catch
+ {
+ // Ignore
+ }
+
+ this.connector = new XPlaneConnector(this.simulatorIPAddress, (int)this.simulatorPort);
+ primaryTracking.RegisterWithConnector(this.connector, this.SampleRates[Requests.Primary]);
+ secondaryTracking.RegisterWithConnector(this.connector, this.SampleRates[Requests.Secondary]);
+ aircraftIdentity.RegisterWithConnector(this.connector, this.SampleRates[Requests.AircraftIdentity]);
+ fuelTanks.RegisterWithConnector(this.connector, this.SampleRates[Requests.FuelTanks]);
+ payloadStations.RegisterWithConnector(this.connector, this.SampleRates[Requests.PayloadStations]);
+ weightAndBalance.RegisterWithConnector(this.connector, this.SampleRates[Requests.WeightAndBalance]);
+ landingAnalysis.RegisterWithConnector(this.connector, this.SampleRates[Requests.LandingAnalysis]);
+ this.connector.Start();
+ }
+ else if ((DateTime.Now - this.connector.LastReceive) < TimeSpan.FromSeconds(3))
+ {
+ this.Connected = true;
+ }
+
+ if (this.Connected)
+ {
+ // Primary tracking
+ {
+ var clone = primaryTracking.Clone();
+ this.primaryTrackingProcessingQueue.Enqueue(new ProcessPrimaryTracking { Old = this.PrimaryTracking, New = clone });
+ this.OnPropertyChanged(nameof(this.PrimaryTrackingProcessingQueueLength));
+
+ this.PrimaryTracking = clone;
+ this.LastReceivedTimes[Requests.Primary] = DateTime.UtcNow;
+ }
+ foreach (Requests request in Enum.GetValues(typeof(Requests)))
+ {
+ if (this.SampleRates.ContainsKey(request))
+ {
+ var lastTime = this.LastReceivedTimes[request];
+ if (request != Requests.Primary && (!lastTime.HasValue || (DateTime.UtcNow - lastTime.Value).TotalMilliseconds > this.SampleRates[request]))
+ {
+ if (request == Requests.Secondary)
+ {
+ var clone = secondaryTracking.Clone();
+ this.secondaryTrackingProcessingQueue.Enqueue(new ProcessSecondaryTracking { Old = this.SecondaryTracking, New = clone });
+ this.OnPropertyChanged(nameof(this.SecondaryTrackingProcessingQueueLength));
+
+ this.SecondaryTracking = clone;
+ this.LastReceivedTimes[Requests.Secondary] = DateTime.UtcNow;
+ }
+
+ if (request == Requests.AircraftIdentity)
+ {
+ this.AircraftIdentity = aircraftIdentity.Clone();
+ this.LastReceivedTimes[Requests.AircraftIdentity] = DateTime.UtcNow;
+ new Thread(this.ProcessAircraftIdentity) { Name = "OpenSky.ProcessAircraftIdentity" }.Start();
+ }
+
+ if (request == Requests.FuelTanks)
+ {
+ this.FuelTanks = fuelTanks.Clone();
+ this.LastReceivedTimes[Requests.FuelTanks] = DateTime.UtcNow;
+ }
+
+ if (request == Requests.PayloadStations)
+ {
+ new Thread(
+ () =>
+ {
+ var clone = payloadStations.Clone();
+ this.ProcessPayloadStations(this.PayloadStations, clone);
+ this.PayloadStations = clone;
+ })
+ { Name = "OpenSky.ProcessPayloadStations" }.Start();
+ this.LastReceivedTimes[Requests.PayloadStations] = DateTime.UtcNow;
+ }
+
+ if (request == Requests.WeightAndBalance)
+ {
+ new Thread(
+ () =>
+ {
+ var clone = weightAndBalance.Clone();
+ this.ProcessWeightAndBalance(this.WeightAndBalance, clone);
+ this.WeightAndBalance = clone;
+ })
+ { Name = "OpenSky.ProcessWeightAndBalance" }.Start();
+ this.LastReceivedTimes[Requests.WeightAndBalance] = DateTime.UtcNow;
+ }
+
+ if (request == Requests.LandingAnalysis)
+ {
+ var clone = landingAnalysis.Clone();
+ this.landingAnalysisProcessingQueue.Enqueue(new ProcessLandingAnalysis { Old = this.LandingAnalysis, New = clone });
+ this.OnPropertyChanged(nameof(this.LandingAnalysisProcessingQueueLength));
+
+ this.LandingAnalysis = clone;
+ this.LastReceivedTimes[Requests.LandingAnalysis] = DateTime.UtcNow;
+ }
+ }
+ }
+ }
+
+ Thread.Sleep(Math.Min(this.SampleRates[Requests.Primary], this.SampleRates[Requests.LandingAnalysis]));
+ }
+ else
+ {
+ SleepScheduler.SleepFor(TimeSpan.FromSeconds(10));
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex);
+ SleepScheduler.SleepFor(TimeSpan.FromSeconds(this.Flight == null ? 30 : 5));
+ }
+ }
+
+ this.connector.Stop();
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine("Error managing XPlane connector: " + ex);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSky.Agent.UdpXPlane11/packages.config b/OpenSky.Agent.UdpXPlane11/packages.config
new file mode 100644
index 0000000..945aec4
--- /dev/null
+++ b/OpenSky.Agent.UdpXPlane11/packages.config
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OpenSky.Agent.sln b/OpenSky.Agent.sln
index b5297e4..6c9c735 100644
--- a/OpenSky.Agent.sln
+++ b/OpenSky.Agent.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.31025.194
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSky.Agent", "OpenSky.Agent\OpenSky.Agent.csproj", "{26FAA45D-B4A3-4228-8AF3-E5811BCFC765}"
EndProject
@@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSky.Agent.SimConnectMSF
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSky.Agent.Simulator", "OpenSky.Agent.Simulator\OpenSky.Agent.Simulator.csproj", "{30C467E8-2EEE-41E5-BE01-0142A61BA171}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSky.Agent.UdpXPlane11", "OpenSky.Agent.UdpXPlane11\OpenSky.Agent.UdpXPlane11.csproj", "{DFBDA2B8-5775-4766-BE86-D729FCF20DE1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -55,6 +57,14 @@ Global
{30C467E8-2EEE-41E5-BE01-0142A61BA171}.Release|Any CPU.Build.0 = Release|Any CPU
{30C467E8-2EEE-41E5-BE01-0142A61BA171}.Release|x86.ActiveCfg = Release|Any CPU
{30C467E8-2EEE-41E5-BE01-0142A61BA171}.Release|x86.Build.0 = Release|Any CPU
+ {DFBDA2B8-5775-4766-BE86-D729FCF20DE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DFBDA2B8-5775-4766-BE86-D729FCF20DE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DFBDA2B8-5775-4766-BE86-D729FCF20DE1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {DFBDA2B8-5775-4766-BE86-D729FCF20DE1}.Debug|x86.Build.0 = Debug|Any CPU
+ {DFBDA2B8-5775-4766-BE86-D729FCF20DE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DFBDA2B8-5775-4766-BE86-D729FCF20DE1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DFBDA2B8-5775-4766-BE86-D729FCF20DE1}.Release|x86.ActiveCfg = Release|Any CPU
+ {DFBDA2B8-5775-4766-BE86-D729FCF20DE1}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/OpenSky.Agent.sln.DotSettings b/OpenSky.Agent.sln.DotSettings
index fee4d16..34f700b 100644
--- a/OpenSky.Agent.sln.DotSettings
+++ b/OpenSky.Agent.sln.DotSettings
@@ -527,6 +527,7 @@ OpenSky project $CURRENT_YEAR$
WB
WCF
XML
+ XP
XY
ZIP
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
@@ -586,14 +587,18 @@ OpenSky project $CURRENT_YEAR$
True
True
True
+ True
+ True
True
True
True
True
True
True
+ True
True
True
True
True
- True
\ No newline at end of file
+ True
+ True
\ No newline at end of file
diff --git a/OpenSky.Agent/App.xaml.cs b/OpenSky.Agent/App.xaml.cs
index 4687568..64b7a0a 100644
--- a/OpenSky.Agent/App.xaml.cs
+++ b/OpenSky.Agent/App.xaml.cs
@@ -251,6 +251,11 @@ protected override void OnStartup([NotNull] StartupEventArgs e)
Simulator.Simulator.SetSimulatorInstance(new SimConnect(Settings.Default.SimConnectHostName, Settings.Default.SimConnectPort, AgentOpenSkyService.Instance));
}
+ if (UdpXPlane11.UdpXPlane11.SimulatorInterfaceName.Equals(simulatorInterface, StringComparison.InvariantCultureIgnoreCase))
+ {
+ Simulator.Simulator.SetSimulatorInstance(new UdpXPlane11.UdpXPlane11(Settings.Default.XPlaneIPAddress, Settings.Default.XPlanePort, AgentOpenSkyService.Instance));
+ }
+
if (Simulator.Simulator.Instance != null)
{
Simulator.Simulator.Instance.LandingReported += (_, landingReportNotification) =>
@@ -324,7 +329,7 @@ private static void AppDispatcherUnhandledException(
private void PerformShutdown()
{
// Check if we are currently tracking a flight
- if (Agent.Simulator.Simulator.Instance.TrackingStatus is TrackingStatus.GroundOperations or TrackingStatus.Tracking)
+ if (Simulator.Simulator.Instance.TrackingStatus is TrackingStatus.GroundOperations or TrackingStatus.Tracking)
{
Debug.WriteLine("User requested shutdown, but flight tracking is still in progress...");
MessageBoxResult? answer = MessageBoxResult.None;
diff --git a/OpenSky.Agent/OpenSky.Agent.csproj b/OpenSky.Agent/OpenSky.Agent.csproj
index 8c987f3..a085d37 100644
--- a/OpenSky.Agent/OpenSky.Agent.csproj
+++ b/OpenSky.Agent/OpenSky.Agent.csproj
@@ -392,13 +392,13 @@
0.1.5
- 19.4.0.48
+ 19.4.0.50
- 19.4.0.48
+ 19.4.0.50
- 19.4.0.48
+ 19.4.0.50
2.7.4
@@ -444,10 +444,12 @@
{30c467e8-2eee-41e5-be01-0142a61ba171}
OpenSky.Agent.Simulator
+
+ {dfbda2b8-5775-4766-be86-d729fcf20de1}
+ OpenSky.Agent.UdpXPlane11
+
-
-
-
+
call "$(ProjectDir)pre-build.bat" "$(ProjectDir)" "$(ConfigurationName)"
diff --git a/OpenSky.Agent/Properties/Settings.Designer.cs b/OpenSky.Agent/Properties/Settings.Designer.cs
index 512fdf9..7901847 100644
--- a/OpenSky.Agent/Properties/Settings.Designer.cs
+++ b/OpenSky.Agent/Properties/Settings.Designer.cs
@@ -203,25 +203,25 @@ public string SimulatorInterface {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("localhost")]
- public string SimulatorHostName {
+ [global::System.Configuration.DefaultSettingValueAttribute("127.0.0.1")]
+ public string XPlaneIPAddress {
get {
- return ((string)(this["SimulatorHostName"]));
+ return ((string)(this["XPlaneIPAddress"]));
}
set {
- this["SimulatorHostName"] = value;
+ this["XPlaneIPAddress"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("500")]
- public string SimulatorPort {
+ [global::System.Configuration.DefaultSettingValueAttribute("49000")]
+ public uint XPlanePort {
get {
- return ((string)(this["SimulatorPort"]));
+ return ((uint)(this["XPlanePort"]));
}
set {
- this["SimulatorPort"] = value;
+ this["XPlanePort"] = value;
}
}
}
diff --git a/OpenSky.Agent/Properties/Settings.settings b/OpenSky.Agent/Properties/Settings.settings
index 1935d6b..deb8066 100644
--- a/OpenSky.Agent/Properties/Settings.settings
+++ b/OpenSky.Agent/Properties/Settings.settings
@@ -50,11 +50,11 @@
SimConnectMSFS
-
- localhost
+
+ 127.0.0.1
-
- 500
+
+ 49000
\ No newline at end of file
diff --git a/OpenSky.Agent/Views/Models/AircraftTypesViewModel.cs b/OpenSky.Agent/Views/Models/AircraftTypesViewModel.cs
index 0043387..b2f5153 100644
--- a/OpenSky.Agent/Views/Models/AircraftTypesViewModel.cs
+++ b/OpenSky.Agent/Views/Models/AircraftTypesViewModel.cs
@@ -996,7 +996,8 @@ private void AddAircraftType()
MinPrice = this.MinimumPrice,
MaxPrice = this.MaximumPrice,
MaxPayloadDeltaAllowed = this.MaxPayloadDeltaAllowed,
- Comments = this.Comments
+ Comments = this.Comments,
+ Simulator = this.Simulator.SimulatorType
};
this.LoadingText = "Adding new aircraft type";
diff --git a/OpenSky.Agent/Views/Models/FlightTrackingViewModel.cs b/OpenSky.Agent/Views/Models/FlightTrackingViewModel.cs
index 97af1a6..9e52f3c 100644
--- a/OpenSky.Agent/Views/Models/FlightTrackingViewModel.cs
+++ b/OpenSky.Agent/Views/Models/FlightTrackingViewModel.cs
@@ -898,7 +898,7 @@ private void StartTracking()
}
// Set the plane registration
- this.Simulator.SetAircraftRegistry(this.Simulator.Flight?.Aircraft.Registry);
+ this.Simulator.SetAircraftRegistry(this.Simulator.Flight?.Aircraft.Registry.RemoveSimPrefix());
// Wait a bit to make sure all structs have updated, especially time in sim
Thread.Sleep(this.Simulator.SampleRates[Requests.Secondary] + 1000);
@@ -1093,7 +1093,7 @@ private void StartTracking()
this.Simulator.SetFuelAndPayloadFromSave();
// Set the plane registration
- this.Simulator.SetAircraftRegistry(this.Simulator.Flight?.Aircraft.Registry);
+ this.Simulator.SetAircraftRegistry(this.Simulator.Flight?.Aircraft.Registry.RemoveSimPrefix());
// Start five second countdown?
if (this.Simulator.PrimaryTracking.SlewActive)
diff --git a/OpenSky.Agent/Views/Models/SettingsViewModel.cs b/OpenSky.Agent/Views/Models/SettingsViewModel.cs
index e43f5dc..14f8f7a 100644
--- a/OpenSky.Agent/Views/Models/SettingsViewModel.cs
+++ b/OpenSky.Agent/Views/Models/SettingsViewModel.cs
@@ -29,10 +29,11 @@ namespace OpenSky.Agent.Views.Models
using OpenSky.Agent.Simulator.Models;
using OpenSky.Agent.Simulator.Tools;
using OpenSky.Agent.Tools;
+ using OpenSky.Agent.UdpXPlane11;
using OpenSkyApi;
- using Simulator = Simulator.Simulator;
+ using Simulator = OpenSky.Agent.Simulator.Simulator;
/// -------------------------------------------------------------------------------------------------
///
@@ -103,45 +104,45 @@ public class SettingsViewModel : ViewModel
/// -------------------------------------------------------------------------------------------------
///
- /// The simulator host name.
+ /// The simconnect simulator host name.
///
/// -------------------------------------------------------------------------------------------------
- private string simulatorHostName;
+ private string simConnectHostName;
/// -------------------------------------------------------------------------------------------------
///
- /// The simulator port.
+ /// True if simConnect MSFS is checked.
///
/// -------------------------------------------------------------------------------------------------
- private uint simulatorPort;
+ private bool simConnectMSFSChecked;
/// -------------------------------------------------------------------------------------------------
///
- /// True if simConnect MSFS is checked.
+ /// The simconnect simulator port.
///
/// -------------------------------------------------------------------------------------------------
- private bool simConnectMSFSChecked;
+ private uint simConnectPort;
/// -------------------------------------------------------------------------------------------------
///
- /// Gets or sets a value indicating whether simConnect MSFS is checked.
+ /// True if UDP X-Plane 11 is checked.
///
/// -------------------------------------------------------------------------------------------------
- public bool SimConnectMSFSChecked
- {
- get => this.simConnectMSFSChecked;
+ private bool udpXplaneChecked;
- set
- {
- if (Equals(this.simConnectMSFSChecked, value))
- {
- return;
- }
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Name of the X-Plane 11 IP address.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private string xplaneIPAddress;
- this.simConnectMSFSChecked=value;
- this.NotifyPropertyChanged();
- }
- }
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// The X-Plane 11 UDP port.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ private uint xplanePort;
/// -------------------------------------------------------------------------------------------------
///
@@ -177,8 +178,10 @@ public SettingsViewModel()
// Load settings
Settings.Default.Reload();
- this.SimulatorHostName = Settings.Default.SimConnectHostName;
- this.SimulatorPort = Settings.Default.SimConnectPort;
+ this.SimConnectHostName = Settings.Default.SimConnectHostName;
+ this.SimConnectPort = Settings.Default.SimConnectPort;
+ this.XplaneIPAddress = Settings.Default.XPlaneIPAddress;
+ this.XplanePort = Settings.Default.XPlanePort;
this.BingMapsKey = UserSessionService.Instance.LinkedAccounts?.BingMapsKey;
this.SimBriefUsername = UserSessionService.Instance.LinkedAccounts?.SimbriefUsername;
this.SelectedLandingReportNotification = LandingReportNotification.Parse(Settings.Default.LandingReportNotification);
@@ -198,6 +201,11 @@ public SettingsViewModel()
this.SimConnectMSFSChecked = true;
}
+ if (UdpXPlane11.SimulatorInterfaceName.Equals(simulatorInterface, StringComparison.InvariantCultureIgnoreCase))
+ {
+ this.UdpXplaneChecked = true;
+ }
+
// Load profile image
if (UserSessionService.Instance.AccountOverview?.ProfileImage?.Length > 0)
{
@@ -454,21 +462,43 @@ public string SimBriefUsername
/// -------------------------------------------------------------------------------------------------
///
- /// Gets or sets the simulator host name.
+ /// Gets or sets the simconnect simulator host name.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public string SimConnectHostName
+ {
+ get => this.simConnectHostName;
+
+ set
+ {
+ if (Equals(this.simConnectHostName, value))
+ {
+ return;
+ }
+
+ this.simConnectHostName = value;
+ this.NotifyPropertyChanged();
+ this.IsDirty = true;
+ }
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Gets or sets a value indicating whether simConnect MSFS is checked.
///
/// -------------------------------------------------------------------------------------------------
- public string SimulatorHostName
+ public bool SimConnectMSFSChecked
{
- get => this.simulatorHostName;
+ get => this.simConnectMSFSChecked;
set
{
- if (Equals(this.simulatorHostName, value))
+ if (Equals(this.simConnectMSFSChecked, value))
{
return;
}
- this.simulatorHostName = value;
+ this.simConnectMSFSChecked = value;
this.NotifyPropertyChanged();
this.IsDirty = true;
}
@@ -476,21 +506,21 @@ public string SimulatorHostName
/// -------------------------------------------------------------------------------------------------
///
- /// Gets or sets the simulator port.
+ /// Gets or sets the simconnect simulator port.
///
/// -------------------------------------------------------------------------------------------------
- public uint SimulatorPort
+ public uint SimConnectPort
{
- get => this.simulatorPort;
+ get => this.simConnectPort;
set
{
- if (Equals(this.simulatorPort, value))
+ if (Equals(this.simConnectPort, value))
{
return;
}
- this.simulatorPort = value;
+ this.simConnectPort = value;
this.NotifyPropertyChanged();
this.IsDirty = true;
}
@@ -517,6 +547,27 @@ public uint SimulatorPort
/// -------------------------------------------------------------------------------------------------
public List TextToSpeechVoices { get; }
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Gets or sets a value indicating whether UDP X-Plane 11 is checked.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public bool UdpXplaneChecked
+ {
+ get => this.udpXplaneChecked;
+ set
+ {
+ if (Equals(this.udpXplaneChecked, value))
+ {
+ return;
+ }
+
+ this.udpXplaneChecked = value;
+ this.NotifyPropertyChanged();
+ this.IsDirty = true;
+ }
+ }
+
/// -------------------------------------------------------------------------------------------------
///
/// Gets the update profile image command.
@@ -531,6 +582,48 @@ public uint SimulatorPort
/// -------------------------------------------------------------------------------------------------
public UserSessionService UserSession => UserSessionService.Instance;
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Gets or sets the IP address of the X-Plane 11 host.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public string XplaneIPAddress
+ {
+ get => this.xplaneIPAddress;
+ set
+ {
+ if (Equals(this.xplaneIPAddress, value))
+ {
+ return;
+ }
+
+ this.xplaneIPAddress = value;
+ this.NotifyPropertyChanged();
+ this.IsDirty = true;
+ }
+ }
+
+ /// -------------------------------------------------------------------------------------------------
+ ///
+ /// Gets or sets the X-Plane 11 port.
+ ///
+ /// -------------------------------------------------------------------------------------------------
+ public uint XplanePort
+ {
+ get => this.xplanePort;
+ set
+ {
+ if (Equals(this.xplanePort, value))
+ {
+ return;
+ }
+
+ this.xplanePort = value;
+ this.NotifyPropertyChanged();
+ this.IsDirty = true;
+ }
+ }
+
/// -------------------------------------------------------------------------------------------------
///
/// Change password (opens page in browser).
@@ -639,8 +732,8 @@ private void RestoreDefaults()
if (messageBox.Result == ExtendedMessageBoxResult.Yes)
{
Debug.WriteLine("Resetting settings to defaults...");
- this.SimulatorHostName = "localhost";
- this.SimulatorPort = 500;
+ this.SimConnectHostName = "localhost";
+ this.SimConnectPort = 500;
}
};
this.ViewReference.ShowMessageBox(messageBox);
@@ -666,9 +759,19 @@ private void SaveSettings()
if (this.SimConnectMSFSChecked)
{
Settings.Default.SimulatorInterface = SimConnect.SimulatorInterfaceName;
- if (Simulator.Instance == null || Simulator.Instance.GetType() != typeof(SimConnect))
+ if (Simulator.Instance == null || Simulator.Instance.GetType() != typeof(SimConnect) || !Equals(Settings.Default.SimConnectHostName, this.SimConnectHostName) || Settings.Default.SimConnectPort != this.SimConnectPort)
+ {
+ Simulator.SetSimulatorInstance(new SimConnect(this.SimConnectHostName, this.SimConnectPort, AgentOpenSkyService.Instance));
+ simulatorWasChanged = true;
+ }
+ }
+
+ if (this.UdpXplaneChecked)
+ {
+ Settings.Default.SimulatorInterface = UdpXPlane11.SimulatorInterfaceName;
+ if (Simulator.Instance == null || Simulator.Instance.GetType() != typeof(UdpXPlane11) || !Equals(Settings.Default.XPlaneIPAddress, this.XplaneIPAddress) || Settings.Default.XPlanePort != this.XplanePort)
{
- Simulator.SetSimulatorInstance(new SimConnect(this.SimulatorHostName, this.SimulatorPort, AgentOpenSkyService.Instance));
+ Simulator.SetSimulatorInstance(new UdpXPlane11(this.XplaneIPAddress, this.XplanePort, AgentOpenSkyService.Instance));
simulatorWasChanged = true;
}
}
@@ -685,8 +788,10 @@ private void SaveSettings()
};
}
- Settings.Default.SimConnectHostName = this.SimulatorHostName;
- Settings.Default.SimConnectPort = this.SimulatorPort;
+ Settings.Default.SimConnectHostName = this.SimConnectHostName;
+ Settings.Default.SimConnectPort = this.SimConnectPort;
+ Settings.Default.XPlaneIPAddress = this.XplaneIPAddress;
+ Settings.Default.XPlanePort = this.XplanePort;
Settings.Default.LandingReportNotification = this.SelectedLandingReportNotification?.NotificationID ?? 1;
Settings.Default.SoundPack = this.SelectedSoundPack;
SpeechSoundPacks.Instance.SelectedSoundPack = this.SelectedSoundPack;
diff --git a/OpenSky.Agent/Views/Models/StartupViewModel.cs b/OpenSky.Agent/Views/Models/StartupViewModel.cs
index 4cce746..be31e97 100644
--- a/OpenSky.Agent/Views/Models/StartupViewModel.cs
+++ b/OpenSky.Agent/Views/Models/StartupViewModel.cs
@@ -367,7 +367,7 @@ private void SimConnectPropertyChanged(object sender, PropertyChangedEventArgs e
this.NotificationIcon = this.greyIcon;
this.NotificationStatusString = "OpenSky is trying to connect to the simulator...";
- this.DiscordRpcClient.SetPresence(new RichPresence
+ this.DiscordRpcClient?.SetPresence(new RichPresence
{
State = "Not Connected",
Details = "Trying to connect to simulator",
@@ -388,7 +388,7 @@ private void SimConnectPropertyChanged(object sender, PropertyChangedEventArgs e
this.NotificationIcon = this.openSkyIcon;
this.NotificationStatusString = "OpenSky is connected to the sim but not tracking a flight";
- this.DiscordRpcClient.SetPresence(new RichPresence
+ this.DiscordRpcClient?.SetPresence(new RichPresence
{
State = "Idle",
Details = "Waiting for a flight",
@@ -405,7 +405,7 @@ private void SimConnectPropertyChanged(object sender, PropertyChangedEventArgs e
this.NotificationIcon = this.openSkyIcon;
this.NotificationStatusString = $"OpenSky is preparing to track flight {Agent.Simulator.Simulator.Instance.Flight?.FullFlightNumber}";
- this.DiscordRpcClient.SetPresence(new RichPresence
+ this.DiscordRpcClient?.SetPresence(new RichPresence
{
State = Agent.Simulator.Simulator.Instance.TrackingStatus.ToString(),
Details = $"Preparing flight {Agent.Simulator.Simulator.Instance.Flight?.FullFlightNumber}",
@@ -423,7 +423,7 @@ private void SimConnectPropertyChanged(object sender, PropertyChangedEventArgs e
this.NotificationIcon = this.pauseIcon;
this.NotificationStatusString = $"OpenSky tracking and your flight {Agent.Simulator.Simulator.Instance.Flight?.FullFlightNumber} are paused";
- this.DiscordRpcClient.SetPresence(new RichPresence
+ this.DiscordRpcClient?.SetPresence(new RichPresence
{
State = $"Paused, {Agent.Simulator.Simulator.Instance.FlightPhase}",
Details = $"Tracking flight {Agent.Simulator.Simulator.Instance.Flight?.FullFlightNumber}",
@@ -442,7 +442,7 @@ private void SimConnectPropertyChanged(object sender, PropertyChangedEventArgs e
this.redFlashing = true;
this.NotificationStatusString = $"OpenSky is tracking your flight {Agent.Simulator.Simulator.Instance.Flight?.FullFlightNumber}";
- this.DiscordRpcClient.SetPresence(new RichPresence
+ this.DiscordRpcClient?.SetPresence(new RichPresence
{
State = $"Recording, {Agent.Simulator.Simulator.Instance.FlightPhase}",
Details = $"Tracking flight {Agent.Simulator.Simulator.Instance.Flight?.FullFlightNumber}",
diff --git a/OpenSky.Agent/Views/Settings.xaml b/OpenSky.Agent/Views/Settings.xaml
index 3f9a495..7bc8685 100644
--- a/OpenSky.Agent/Views/Settings.xaml
+++ b/OpenSky.Agent/Views/Settings.xaml
@@ -121,27 +121,54 @@
-
-
- Microsoft Flight Simulator (SimConnect)
-
-
-
-
-
-
-
-
-
-
-
- Use these settings if you are running the OpenSky Agent on a different computer than your simulator. If you both are running on the same computer leave these settings unchanged.
- Simulator host name
- Simulator network port
-
-
-
-
+
+
+
+
+
+
+
+ Microsoft Flight Simulator (SimConnect)
+
+
+
+
+
+
+
+
+
+
+
+ Use these settings if you are running the OpenSky Agent on a different computer than your simulator. If you both are running on the same computer leave these settings unchanged.
+ Simulator host name
+ Simulator network port
+
+
+
+
+
+
+ X-Plane 11 (UDP)
+
+
+
+
+
+
+
+
+
+
+
+ Use these settings if you are running the OpenSky Agent on a different computer than your simulator. If you both are running on the same computer leave these settings unchanged.
+ Simulator IP address
+ Simulator network port
+
+
+
+
+
Notifications
diff --git a/changelog.txt b/changelog.txt
index 851b94e..3ac1604 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -7,6 +7,7 @@ Version 0.4.0 (ALPHA4)
--------------------------------------------------------------------------------------
- Common simulator interface code extracted and separated from SimConnect code
- Minor bug fixes and improvements
+- Experimental X-Plane 11 support
--------------------------------------------------------------------------------------
Version 0.3.7 (ALPHA3)