diff --git a/WpfApp1/DataHandle/DataAdapter.cs b/WpfApp1/DataHandle/DataAdapter.cs new file mode 100644 index 0000000..80711b6 --- /dev/null +++ b/WpfApp1/DataHandle/DataAdapter.cs @@ -0,0 +1,110 @@ +using System; + +namespace F1Tools +{ + internal static class DataAdapter + { + public static LocalData AsLocalData(this Codemasters.F1_2019.Packet packet) + { + if (packet == null) + return null; + + var result = new LocalData(); + if (packet.PacketType == Codemasters.F1_2019.PacketType.CarTelemetry) + { + var curPack = packet as Codemasters.F1_2019.TelemetryPacket; + var data = curPack.FieldTelemetryData[curPack.PlayerCarIndex]; + + result.Brake = data.Brake; + result.Throttle = data.Throttle; + result.SpeedKph = data.SpeedKph; + result.EngineRpm = data.EngineRpm; + result.Gear = data.Gear; + result.DrsActive = data.DrsActive; + } + else if (packet.PacketType == Codemasters.F1_2019.PacketType.CarStatus) + { + var curPack = packet as Codemasters.F1_2019.CarStatusPacket; + var data = curPack.FieldCarStatusData[0]; + + result.DrsAllowed = data.DrsAllowed; + } + return result; + } + + public static LocalData AsLocalData(this Codemasters.F1_2020.Packet packet) + { + if (packet == null) + return null; + + var result = new LocalData(); + if (packet.PacketType == Codemasters.F1_2020.PacketType.CarTelemetry) + { + var curPack = packet as Codemasters.F1_2020.TelemetryPacket; + var data = curPack.FieldTelemetryData[curPack.PlayerCarIndex]; + + result.Brake = data.Brake; + result.Throttle = data.Throttle; + result.SpeedKph = data.SpeedKph; + result.EngineRpm = data.EngineRpm; + result.Gear = data.Gear; + result.DrsActive = data.DrsActive; + } + else if (packet.PacketType == Codemasters.F1_2020.PacketType.CarStatus) + { + var curPack = packet as Codemasters.F1_2020.CarStatusPacket; + var data = curPack.FieldCarStatusData[0]; + + result.DrsAllowed = data.DrsAllowed; + result.DrsFailure = data.DrsFailure; + } + return result; + } + + public static LocalData AsLocalData(this Codemasters.F1_2021.Packet packet) + { + if (packet == null) + return null; + + var result = new LocalData(); + if (packet.PacketType == Codemasters.F1_2021.PacketType.CarTelemetry) + { + var curPack = packet as Codemasters.F1_2021.TelemetryPacket; + var data = curPack.FieldTelemetryData[curPack.PlayerCarIndex]; + + result.Brake = data.Brake; + result.Throttle = data.Throttle; + result.SpeedKph = data.SpeedKph; + result.EngineRpm = data.EngineRpm; + result.Gear = data.Gear; + result.DrsActive = data.DrsActive; + } + else if (packet.PacketType == Codemasters.F1_2021.PacketType.CarStatus) + { + var curPack = packet as Codemasters.F1_2021.CarStatusPacket; + var data = curPack.FieldCarStatusData[0]; + + result.DrsAllowed = data.DrsAllowed; + } + return result; + } + + public static LocalData AsLocalData(this float[] fh5Data) + { + var result = new LocalData + { + Throttle = fh5Data[80] / 255F, + Brake = fh5Data[81] / 255F, + Clutch = fh5Data[82] / 255F, + Gear = (int)fh5Data[84], + EngineRpm = fh5Data[4], + SpeedKph = fh5Data[64] * 3.6F, + }; + if (result.Gear == 0) + result.Gear = -1; + else if (result.Gear == 11) + result.Gear = 0; + return result; + } + } +} diff --git a/WpfApp1/DataHandle/DataReciver.cs b/WpfApp1/DataHandle/DataReciver.cs index c10a500..e5e59a7 100644 --- a/WpfApp1/DataHandle/DataReciver.cs +++ b/WpfApp1/DataHandle/DataReciver.cs @@ -1,4 +1,5 @@ -using System.Net; +using System; +using System.Net; using System.Net.Sockets; using static F1Tools.TypeFactory; @@ -28,10 +29,11 @@ private static void MicroTimer_OnRunningCallback(int id, int msg, int user, int var bytes = UDP.Receive(ref IP); if (bytes.Length > 0) { - var packet = GetPacket(bytes, _version, out _version); - if (_version == GameVersion.Unkonwn) + var data = GetData(bytes, _version, out _version); + if (_version == GameVersion.Unkonwn || data == null) return; - ReciveEvent?.Invoke(packet); + ReciveEvent?.Invoke(data); + //Console.WriteLine($"{data.Throttle} {data.Brake}"); } } @@ -56,7 +58,7 @@ public static void Dispose() UDP.Dispose(); } - public delegate void ReciverHandler(object packet); + public delegate void ReciverHandler(LocalData localData); public static event ReciverHandler ReciveEvent; } } diff --git a/WpfApp1/DataHandle/ShowDataHandle.cs b/WpfApp1/DataHandle/ShowDataHandle.cs index a6f73a4..f17eabd 100644 --- a/WpfApp1/DataHandle/ShowDataHandle.cs +++ b/WpfApp1/DataHandle/ShowDataHandle.cs @@ -1,98 +1,27 @@ -using static F1Tools.TypeFactory; - -namespace F1Tools +namespace F1Tools { public static class ShowDataHandle { - public static void F1Handle(F1Instrument f1, dynamic packet) + public static void F1Handle(F1Instrument f1, LocalData data) { - if (packet == null) + if (data == null) return; - - switch (DataReciver.Version) - { - case GameVersion.F1_2019: - Handle19(f1, packet); - break; - case GameVersion.F1_2020: - Handle20(f1, packet); - break; - case GameVersion.F1_2021: - Handle21(f1, packet); - break; - default: - break; - } - } - - private static void Handle19(F1Instrument f1, Codemasters.F1_2019.Packet packet) - { - if (packet.PacketType == Codemasters.F1_2019.PacketType.CarTelemetry) - { - var curPack = packet as Codemasters.F1_2019.TelemetryPacket; - var data = curPack.FieldTelemetryData[curPack.PlayerCarIndex]; - - f1.SetBrake(data.Brake); - f1.SetThrottle(data.Throttle); - f1.SetSpeed(data.SpeedKph); - f1.SetRPM(data.EngineRpm); - f1.SetGear(data.Gear); - f1.SetDRS(data.DrsActive); - } - else if (packet.PacketType == Codemasters.F1_2019.PacketType.CarStatus) - { - var curPack = packet as Codemasters.F1_2019.CarStatusPacket; - var data = curPack.FieldCarStatusData[0]; - - f1.DRSEnable(data.DrsAllowed); - } - } - - private static void Handle20(F1Instrument f1, Codemasters.F1_2020.Packet packet) - { - if (packet.PacketType == Codemasters.F1_2020.PacketType.CarTelemetry) - { - var curPack = packet as Codemasters.F1_2020.TelemetryPacket; - var data = curPack.FieldTelemetryData[curPack.PlayerCarIndex]; - - f1.SetBrake(data.Brake); - f1.SetThrottle(data.Throttle); - f1.SetSpeed(data.SpeedKph); - f1.SetRPM(data.EngineRpm); - f1.SetGear(data.Gear); - f1.SetDRS(data.DrsActive); - } - else if (packet.PacketType == Codemasters.F1_2020.PacketType.CarStatus) - { - var curPack = packet as Codemasters.F1_2020.CarStatusPacket; - var data = curPack.FieldCarStatusData[0]; - - f1.DRSEnable(data.DrsAllowed); - f1.DRSNegative(data.DrsFailure); - } - } - - private static void Handle21(F1Instrument f1, Codemasters.F1_2021.Packet packet) - { - if (packet.PacketType == Codemasters.F1_2021.PacketType.CarTelemetry) - { - var curPack = packet as Codemasters.F1_2021.TelemetryPacket; - var data = curPack.FieldTelemetryData[curPack.PlayerCarIndex]; - - f1.SetBrake(data.Brake); - f1.SetThrottle(data.Throttle); - f1.SetSpeed(data.SpeedKph); - f1.SetRPM(data.EngineRpm); - f1.SetGear(data.Gear); - f1.SetDRS(data.DrsActive); - } - else if (packet.PacketType == Codemasters.F1_2021.PacketType.CarStatus) - { - var curPack = packet as Codemasters.F1_2021.CarStatusPacket; - var data = curPack.FieldCarStatusData[0]; - - f1.DRSEnable(data.DrsAllowed); - } + if (data.Brake.HasValue) + f1.SetBrake(data.Brake.Value); + if (data.Throttle.HasValue) + f1.SetThrottle(data.Throttle.Value); + if (data.SpeedKph.HasValue) + f1.SetSpeed((int)data.SpeedKph.Value); + if (data.EngineRpm.HasValue) + f1.SetRPM((int)data.EngineRpm.Value); + if (data.Gear.HasValue) + f1.SetGear(data.Gear.Value); + if (data.DrsActive.HasValue) + f1.SetDRS(data.DrsActive.Value); + if (data.DrsAllowed.HasValue) + f1.DRSEnable(data.DrsAllowed.Value); + if (data.DrsFailure.HasValue) + f1.DRSNegative(data.DrsFailure.Value); } } } diff --git a/WpfApp1/DataHandle/TypeFactory.cs b/WpfApp1/DataHandle/TypeFactory.cs index ed20457..656a54c 100644 --- a/WpfApp1/DataHandle/TypeFactory.cs +++ b/WpfApp1/DataHandle/TypeFactory.cs @@ -4,21 +4,24 @@ namespace F1Tools { public class TypeFactory { - public static object GetPacket(byte[] bytes, GameVersion version, out GameVersion outVersion) + public static LocalData GetData(byte[] bytes, GameVersion version, out GameVersion outVersion) { if (version != GameVersion.Unkonwn) { switch (version) { case GameVersion.F1_2019: - outVersion = GetPacket2019(bytes, out Codemasters.F1_2019.Packet packet19) ? GameVersion.F1_2019 : GameVersion.Unkonwn; - return packet19; + outVersion = F1.GetPacket2019(bytes, out Codemasters.F1_2019.Packet packet19) ? GameVersion.F1_2019 : GameVersion.Unkonwn; + return packet19.AsLocalData(); case GameVersion.F1_2020: - outVersion = GetPacket2020(bytes, out Codemasters.F1_2020.Packet packet20) ? GameVersion.F1_2020 : GameVersion.Unkonwn; - return packet20; + outVersion = F1.GetPacket2020(bytes, out Codemasters.F1_2020.Packet packet20) ? GameVersion.F1_2020 : GameVersion.Unkonwn; + return packet20.AsLocalData(); case GameVersion.F1_2021: - outVersion = GetPacket2021(bytes, out Codemasters.F1_2021.Packet packet21) ? GameVersion.F1_2021 : GameVersion.Unkonwn; - return packet21; + outVersion = F1.GetPacket2021(bytes, out Codemasters.F1_2021.Packet packet21) ? GameVersion.F1_2021 : GameVersion.Unkonwn; + return packet21.AsLocalData(); + case GameVersion.Horizon5: + outVersion = FH5.GetFh5Data(bytes, out float[] data) ? GameVersion.Horizon5 : GameVersion.Unkonwn; + return data.AsLocalData(); default: outVersion = GameVersion.Unkonwn; return null; @@ -26,172 +29,9 @@ public static object GetPacket(byte[] bytes, GameVersion version, out GameVersio } else { - if (GetPacket2019(bytes, out Codemasters.F1_2019.Packet packet19)) - { - outVersion = GameVersion.F1_2019; - return packet19; - } - else if (GetPacket2020(bytes, out Codemasters.F1_2020.Packet packet20)) - { - outVersion = GameVersion.F1_2020; - return packet20; - } - else if (GetPacket2021(bytes, out Codemasters.F1_2021.Packet packet21)) - { - outVersion = GameVersion.F1_2021; - return packet21; - } - else - { - outVersion = GameVersion.Unkonwn; - return null; - } - } - } - - public static bool GetPacket2019(byte[] bytes, out Codemasters.F1_2019.Packet packet) - { - packet = null; - try - { - var type = Codemasters.F1_2019.CodemastersToolkit.GetPacketType(bytes); - - switch (type) - { - case Codemasters.F1_2019.PacketType.CarStatus: - packet = new Codemasters.F1_2019.CarStatusPacket(); - break; - case Codemasters.F1_2019.PacketType.CarTelemetry: - packet = new Codemasters.F1_2019.TelemetryPacket(); - break; - //case PacketType.FinalClassification: - // pack = new FinalClassificationPacket(); - // break; - //case PacketType.Lap: - // pack = new LapPacket(); - // break; - //case PacketType.LobbyInfo: - // pack = new LobbyInfoPacket(); - // break; - //case PacketType.Motion: - // pack = new MotionPacket(); - // break; - case Codemasters.F1_2019.PacketType.Participants: - packet = new Codemasters.F1_2019.ParticipantPacket(); - break; - //case Codemasters.F1_2019.PacketType.Session: - // pack = new SessionPacket(); - // break; - default: break; - } - - if (packet != null) - packet.LoadBytes(bytes); - - return true; - } - catch (Exception ex) - { - return false; - } - } - - public static bool GetPacket2020(byte[] bytes, out Codemasters.F1_2020.Packet packet) - { - packet = null; - try - { - var type = Codemasters.F1_2020.CodemastersToolkit.GetPacketType(bytes); - - switch (type) - { - case Codemasters.F1_2020.PacketType.CarStatus: - packet = new Codemasters.F1_2020.CarStatusPacket(); - break; - case Codemasters.F1_2020.PacketType.CarTelemetry: - packet = new Codemasters.F1_2020.TelemetryPacket(); - break; - //case PacketType.FinalClassification: - // pack = new FinalClassificationPacket(); - // break; - //case PacketType.Lap: - // pack = new LapPacket(); - // break; - //case PacketType.LobbyInfo: - // pack = new LobbyInfoPacket(); - // break; - //case PacketType.Motion: - // pack = new MotionPacket(); - // break; - case Codemasters.F1_2020.PacketType.Participants: - packet = new Codemasters.F1_2020.ParticipantPacket(); - break; - //case PacketType.Session: - // pack = new SessionPacket(); - // break; - default: break; - } - - if (packet != null) - packet.LoadBytes(bytes); - return true; + outVersion = Helper.GetGameVersion(bytes); + return null; } - catch (Exception ex) - { - return false; - } - } - - public static bool GetPacket2021(byte[] bytes, out Codemasters.F1_2021.Packet packet) - { - packet = null; - try - { - var type = Codemasters.F1_2021.CodemastersToolkit.GetPacketType(bytes); - - switch (type) - { - case Codemasters.F1_2021.PacketType.CarStatus: - packet = new Codemasters.F1_2021.CarStatusPacket(); - break; - case Codemasters.F1_2021.PacketType.CarTelemetry: - packet = new Codemasters.F1_2021.TelemetryPacket(); - break; - //case PacketType.FinalClassification: - // pack = new FinalClassificationPacket(); - // break; - //case PacketType.Lap: - // pack = new LapPacket(); - // break; - //case PacketType.LobbyInfo: - // pack = new LobbyInfoPacket(); - // break; - //case PacketType.Motion: - // pack = new MotionPacket(); - // break; - case Codemasters.F1_2021.PacketType.Participants: - packet = new Codemasters.F1_2021.ParticipantPacket(); - break; - //case PacketType.Session: - // pack = new SessionPacket(); - // break; - default: break; - } - - if (packet != null) - packet.LoadBytes(bytes); - - return true; - } - catch (Exception ex) - { - return false; - } - } - - public enum GameVersion - { - F1_2019, F1_2020, F1_2021, Unkonwn } } } diff --git a/WpfApp1/F1/F1.cs b/WpfApp1/F1/F1.cs new file mode 100644 index 0000000..0c9d67e --- /dev/null +++ b/WpfApp1/F1/F1.cs @@ -0,0 +1,149 @@ +using System; + +namespace F1Tools +{ + public static class F1 + { + + + public static bool GetPacket2019(byte[] bytes, out Codemasters.F1_2019.Packet packet) + { + packet = null; + try + { + var type = Codemasters.F1_2019.CodemastersToolkit.GetPacketType(bytes); + + switch (type) + { + case Codemasters.F1_2019.PacketType.CarStatus: + packet = new Codemasters.F1_2019.CarStatusPacket(); + break; + case Codemasters.F1_2019.PacketType.CarTelemetry: + packet = new Codemasters.F1_2019.TelemetryPacket(); + break; + //case PacketType.FinalClassification: + // pack = new FinalClassificationPacket(); + // break; + //case PacketType.Lap: + // pack = new LapPacket(); + // break; + //case PacketType.LobbyInfo: + // pack = new LobbyInfoPacket(); + // break; + //case PacketType.Motion: + // pack = new MotionPacket(); + // break; + //case Codemasters.F1_2019.PacketType.Participants: + // packet = new Codemasters.F1_2019.ParticipantPacket(); + // break; + //case Codemasters.F1_2019.PacketType.Session: + // pack = new SessionPacket(); + // break; + default: break; + } + + if (packet != null) + packet.LoadBytes(bytes); + + return true; + } + catch (Exception ex) + { + return false; + } + } + + public static bool GetPacket2020(byte[] bytes, out Codemasters.F1_2020.Packet packet) + { + packet = null; + try + { + var type = Codemasters.F1_2020.CodemastersToolkit.GetPacketType(bytes); + + switch (type) + { + case Codemasters.F1_2020.PacketType.CarStatus: + packet = new Codemasters.F1_2020.CarStatusPacket(); + break; + case Codemasters.F1_2020.PacketType.CarTelemetry: + packet = new Codemasters.F1_2020.TelemetryPacket(); + break; + //case PacketType.FinalClassification: + // pack = new FinalClassificationPacket(); + // break; + //case PacketType.Lap: + // pack = new LapPacket(); + // break; + //case PacketType.LobbyInfo: + // pack = new LobbyInfoPacket(); + // break; + //case PacketType.Motion: + // pack = new MotionPacket(); + // break; + //case Codemasters.F1_2020.PacketType.Participants: + // packet = new Codemasters.F1_2020.ParticipantPacket(); + // break; + //case PacketType.Session: + // pack = new SessionPacket(); + // break; + default: break; + } + + if (packet != null) + packet.LoadBytes(bytes); + return true; + } + catch (Exception ex) + { + return false; + } + } + + public static bool GetPacket2021(byte[] bytes, out Codemasters.F1_2021.Packet packet) + { + packet = null; + try + { + var type = Codemasters.F1_2021.CodemastersToolkit.GetPacketType(bytes); + + switch (type) + { + case Codemasters.F1_2021.PacketType.CarStatus: + packet = new Codemasters.F1_2021.CarStatusPacket(); + break; + case Codemasters.F1_2021.PacketType.CarTelemetry: + packet = new Codemasters.F1_2021.TelemetryPacket(); + break; + //case PacketType.FinalClassification: + // pack = new FinalClassificationPacket(); + // break; + //case PacketType.Lap: + // pack = new LapPacket(); + // break; + //case PacketType.LobbyInfo: + // pack = new LobbyInfoPacket(); + // break; + //case PacketType.Motion: + // pack = new MotionPacket(); + // break; + //case Codemasters.F1_2021.PacketType.Participants: + // packet = new Codemasters.F1_2021.ParticipantPacket(); + // break; + //case PacketType.Session: + // pack = new SessionPacket(); + // break; + default: break; + } + + if (packet != null) + packet.LoadBytes(bytes); + + return true; + } + catch (Exception ex) + { + return false; + } + } + } +} diff --git a/WpfApp1/F1Instrument.xaml.cs b/WpfApp1/F1Instrument.xaml.cs index 62fe629..82c6482 100644 --- a/WpfApp1/F1Instrument.xaml.cs +++ b/WpfApp1/F1Instrument.xaml.cs @@ -45,12 +45,12 @@ public partial class F1Instrument : UserControl private DoubleAnimation sizeBigAn = new DoubleAnimation { From = 50, - To = 90, + To = 80, Duration = TimeSpan.FromMilliseconds(300) }; private DoubleAnimation sizeSmln = new DoubleAnimation { - From = 90, + From = 80, To = 50, Duration = TimeSpan.FromMilliseconds(300) }; @@ -92,7 +92,7 @@ public F1Instrument() DRSNegative(false); lb_DRS.Foreground = new SolidColorBrush(Colors.White); - + lb_R.Foreground = new SolidColorBrush(Colors.Gray); lb_N.Foreground = new SolidColorBrush(Colors.Gray); lb_1.Foreground = new SolidColorBrush(Colors.Gray); @@ -111,11 +111,15 @@ public F1Instrument() public void SetThrottle(float thr) { + thr = thr < 0 ? 0 : thr; + thr = thr > 1 ? 1 : thr; arc_tr.EndAngle = 128 + ((307 - 128) * thr); } public void SetBrake(float bre) { + bre = bre < 0 ? 0 : bre; + bre = bre > 1 ? 1 : bre; arc_break.EndAngle = 410 - ((410 - 311) * bre); } @@ -123,8 +127,10 @@ public void SetSpeed(int sp) { if (SPEED != sp) { - arc_speed.EndAngle = ((421 - 120) * (sp / 360.0)) + 120; lb_speed.Content = sp.ToString(); + sp = sp > 360 ? 360 : sp; + arc_speed.EndAngle = ((421 - 120) * (sp / 360.0)) + 120; + SPEED = sp; } } @@ -154,7 +160,7 @@ public void DRSEnable(bool enable) { if (DRS_Ena != enable) { - if(enable) + if (enable) lb_DRS.Foreground.BeginAnimation(SolidColorBrush.ColorProperty, DRS_Enable_Ac); else lb_DRS.Foreground.BeginAnimation(SolidColorBrush.ColorProperty, DRS_Disable_Ac); diff --git a/WpfApp1/F1_2020_Tools.csproj b/WpfApp1/F1_2020_Tools.csproj index aa6729b..f5f62aa 100644 --- a/WpfApp1/F1_2020_Tools.csproj +++ b/WpfApp1/F1_2020_Tools.csproj @@ -231,10 +231,17 @@ MSBuild:Compile Designer + + + + + + + True diff --git a/WpfApp1/FH5/FH5.cs b/WpfApp1/FH5/FH5.cs new file mode 100644 index 0000000..6ad803d --- /dev/null +++ b/WpfApp1/FH5/FH5.cs @@ -0,0 +1,54 @@ +using F1Tools.Models; +using System; + +namespace F1Tools +{ + public class FH5 + { + public static bool GetFh5Data(byte[] bytes, out float[] data) + { + data = new float[100]; + + if (bytes.Length != 324) + return false; + try + { + int index = 0; + int arrayIndex = 0; + foreach (var item in FH5Format.FH5FormatData) + { + switch (item.Type) + { + case "Int32": + data[arrayIndex] = BitConverter.ToInt32(bytes, index); + index += item.Size; arrayIndex++; + break; + case "float": + data[arrayIndex] = BitConverter.ToSingle(bytes, index); + index += item.Size; arrayIndex++; + break; + case "bool": + data[arrayIndex] = BitConverter.ToInt32(bytes, index); + index += item.Size; arrayIndex++; + break; + case "UInt16": + data[arrayIndex] = BitConverter.ToUInt16(bytes, index); + index += item.Size; arrayIndex++; + break; + case "uint8": + data[arrayIndex] = bytes[index]; + index += item.Size; arrayIndex++; + break; + default: break; + } + } + } + catch (Exception ex) + { + return false; + } + + return true; + } + } +} diff --git a/WpfApp1/FH5/FH5Format.cs b/WpfApp1/FH5/FH5Format.cs new file mode 100644 index 0000000..e5ad75b --- /dev/null +++ b/WpfApp1/FH5/FH5Format.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; + +namespace F1Tools.Models +{ + public class FH5Unit + { + public int Size; + public string Type; + public string Name; + + public FH5Unit(int size, string type, string name) + { + Size = size; + Type = type; + Name = name; + } + } + + + public class FH5Format : List + { + + public static FH5Format FH5FormatData = new FH5Format + { + new FH5Unit(4,"Int32","IsRaceOn"),// = 1 when race is on. = 0 when in menus/race stopped + new FH5Unit(4,"Int32","TimestampMS"),//Can overflow to 0 eventually + new FH5Unit(4,"float","EngineMaxRpm"), + new FH5Unit(4,"float","EngineIdleRpm"), + new FH5Unit(4,"float","CurrentEngineRpm"), + new FH5Unit(4,"float","AccelerationX"),//In the car's local space; X = right, Y = up, Z = forward + new FH5Unit(4,"float","AccelerationY"), + new FH5Unit(4,"float","AccelerationZ"), + new FH5Unit(4,"float","VelocityX"), + new FH5Unit(4,"float","VelocityY"), + new FH5Unit(4,"float","VelocityZ"), + new FH5Unit(4,"float","AngularVelocityX"), + new FH5Unit(4,"float","AngularVelocityY"), + new FH5Unit(4,"float","AngularVelocityZ"), + new FH5Unit(4,"float","Yaw"), + new FH5Unit(4,"float","Pitch"), + new FH5Unit(4,"float","Roll"), + new FH5Unit(4,"float","NormalizedSuspensionTravelFrontLeft"),// Suspension travel normalized: 0.0f = max stretch; 1.0 = max compression + new FH5Unit(4,"float","NormalizedSuspensionTravelFrontRight"), + new FH5Unit(4,"float","NormalizedSuspensionTravelRearLeft"), + new FH5Unit(4,"float","NormalizedSuspensionTravelRearRight"), + new FH5Unit(4,"float","TireSlipRatioFrontLeft"),// Tire normalized slip ratio, = 0 means 100% grip and |ratio| > 1.0 means loss of grip. THis is longitudinal slip or just spin + new FH5Unit(4,"float","TireSlipRatioFrontRight"), + new FH5Unit(4,"float","TireSlipRatioRearLeft"), + new FH5Unit(4,"float","TireSlipRatioRearRight"), + new FH5Unit(4,"float","WheelRotationSpeedFrontLeft"),// Wheel rotation speed radians/sec. + new FH5Unit(4,"float","WheelRotationSpeedFrontRight"), + new FH5Unit(4,"float","WheelRotationSpeedRearLeft"), + new FH5Unit(4,"float","WheelRotationSpeedRearRight"), + new FH5Unit(4,"bool","WheelOnRumbleStripFrontLeft"),// = 1 when wheel is on rumble strip, = 0 when off. + new FH5Unit(4,"bool","WheelOnRumbleStripFrontRight"), + new FH5Unit(4,"bool","WheelOnRumbleStripRearLeft"), + new FH5Unit(4,"bool","WheelOnRumbleStripRearRight"), + new FH5Unit(4,"bool","WheelInPuddleDepthFrontLeft"),// = from 0 to 1, where 1 is the deepest puddle + new FH5Unit(4,"bool","WheelInPuddleDepthFrontRight"), + new FH5Unit(4,"bool","WheelInPuddleDepthRearLeft"), + new FH5Unit(4,"bool","WheelInPuddleDepthRearRight"), + new FH5Unit(4,"float","SurfaceRumbleFrontLeft"),// Non-dimensional surface rumble values passed to controller force feedback + new FH5Unit(4,"float","SurfaceRumbleFrontRight"), + new FH5Unit(4,"float","SurfaceRumbleRearLeft"), + new FH5Unit(4,"float","SurfaceRumbleRearRight"), + new FH5Unit(4,"float","TireSlipAngleFrontLeft"),// Tire normalized slip angle, = 0 means 100% grip and |angle| > 1.0 means loss of grip. This is lateral tire slip angle (not the same as wheel angle) + new FH5Unit(4,"float","TireSlipAngleFrontRight"), + new FH5Unit(4,"float","TireSlipAngleRearLeft"), + new FH5Unit(4,"float","TireSlipAngleRearRight"), + new FH5Unit(4,"float","TireCombinedSlipFrontLeft"),// Tire normalized combined slip, = 0 means 100% grip and |slip| > 1.0 means loss of grip. This is a combination of TireSlipRatioFrontLeft and TireSlipAngleFrontLeft. + new FH5Unit(4,"float","TireCombinedSlipFrontRight"), + new FH5Unit(4,"float","TireCombinedSlipRearLeft"), + new FH5Unit(4,"float","TireCombinedSlipRearRight"), + new FH5Unit(4,"float","SuspensionTravelMetersFrontLeft"),// Actual suspension travel in meters + new FH5Unit(4,"float","SuspensionTravelMetersFrontRight"), + new FH5Unit(4,"float","SuspensionTravelMetersRearLeft"), + new FH5Unit(4,"float","SuspensionTravelMetersRearRight"), + new FH5Unit(4,"Int32","CarOrdinal"),//Unique ID of the car make/model + new FH5Unit(4,"Int32","CarClass"),//Between 0 (D -- worst cars) and 7 (X class -- best cars) inclusive + new FH5Unit(4,"Int32","CarPerformanceIndex"),//Between 100 (slowest car) and 999 (fastest car) inclusive + new FH5Unit(4,"Int32","DrivetrainType"),//Corresponds to EDrivetrainType; 0 = FWD, 1 = RWD, 2 = AWD + new FH5Unit(4,"Int32","NumCylinders"),//Number of cylinders in the engine + new FH5Unit(4,"Int32","CarCategory"), + new FH5Unit(4,"Int32","unknown"),// > 0 when crashing into objects + new FH5Unit(4,"Int32","unknown"),// > 0 when crashing into objects + new FH5Unit(4,"float","PositionX"), + new FH5Unit(4,"float","PositionY"), + new FH5Unit(4,"float","PositionZ"), + new FH5Unit(4,"float","Speed"),// in meters per second + new FH5Unit(4,"float","Power"),// in watts + new FH5Unit(4,"float","Torque"),// newton meter + new FH5Unit(4,"float","TireTemperatureFrontLeft"),// °F + new FH5Unit(4,"float","TireTemperatureFrontRight"), + new FH5Unit(4,"float","TireTemperatureRearLeft"), + new FH5Unit(4,"float","TireTemperatureRearRight"), + new FH5Unit(4,"float","Boost"), + new FH5Unit(4,"float","Fuel"), + new FH5Unit(4,"float","DistanceTraveled"), + new FH5Unit(4,"float","BestLap"), + new FH5Unit(4,"float","LastLap"), + new FH5Unit(4,"float","CurrentLap"), + new FH5Unit(4,"float","CurrentRaceTime"), + new FH5Unit(2,"UInt16","LapNumber"), + new FH5Unit(1,"uint8","RacePosition"), + new FH5Unit(1,"uint8","Throttle"),// /255 + new FH5Unit(1,"uint8","Brake"),// /255 + new FH5Unit(1,"uint8","Clutch"),// /25// /2555 + new FH5Unit(1,"uint8","HandBrake"), + new FH5Unit(1,"uint8","Gear"), + new FH5Unit(1,"uint8","Steer"),// /255 + new FH5Unit(1,"uint8","NormalizedDrivingLine"), + new FH5Unit(1,"uint8","NormalizedAIBrakeDifference") + }; + } +} diff --git a/WpfApp1/Helper/ConsoleManager.cs b/WpfApp1/Helper/ConsoleManager.cs new file mode 100644 index 0000000..036e96d --- /dev/null +++ b/WpfApp1/Helper/ConsoleManager.cs @@ -0,0 +1,99 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; + +namespace F1Tools +{ + public static class ConsoleManager + { + private const string Kernel32_DllName = "kernel32.dll"; + + [DllImport(Kernel32_DllName)] + private static extern bool AllocConsole(); + + [DllImport(Kernel32_DllName)] + private static extern bool FreeConsole(); + + [DllImport(Kernel32_DllName)] + private static extern IntPtr GetConsoleWindow(); + + [DllImport(Kernel32_DllName)] + private static extern int GetConsoleOutputCP(); + + public static bool HasConsole + { + get { return GetConsoleWindow() != IntPtr.Zero; } + } + + /// + /// Creates a new console instance if the process is not attached to a console already. + /// + public static void Show() + { + //#if DEBUG + if (!HasConsole) + { + AllocConsole(); + InvalidateOutAndError(); + } + //#endif + } + + /// + /// If the process has a console attached to it, it will be detached and no longer visible. Writing to the System.Console is still possible, but no output will be shown. + /// + public static void Hide() + { + //#if DEBUG + if (HasConsole) + { + SetOutAndErrorNull(); + FreeConsole(); + } + //#endif + } + + public static void Toggle() + { + if (HasConsole) + { + Hide(); + } + else + { + Show(); + } + } + + static void InvalidateOutAndError() + { + Type type = typeof(System.Console); + + System.Reflection.FieldInfo _out = type.GetField("_out", + System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); + + System.Reflection.FieldInfo _error = type.GetField("_error", + System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); + + System.Reflection.MethodInfo _InitializeStdOutError = type.GetMethod("InitializeStdOutError", + System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); + + Debug.Assert(_out != null); + Debug.Assert(_error != null); + + Debug.Assert(_InitializeStdOutError != null); + + _out.SetValue(null, null); + _error.SetValue(null, null); + + _InitializeStdOutError.Invoke(null, new object[] { true }); + } + + static void SetOutAndErrorNull() + { + Console.SetOut(TextWriter.Null); + Console.SetError(TextWriter.Null); + } + } +} diff --git a/WpfApp1/Helper/Helper.cs b/WpfApp1/Helper/Helper.cs index d697017..20b571e 100644 --- a/WpfApp1/Helper/Helper.cs +++ b/WpfApp1/Helper/Helper.cs @@ -11,6 +11,66 @@ namespace F1Tools { public static class Helper { + + public static GameVersion GetGameVersion(byte[] bytes) + { + if (bytes.Length == 324) + return GameVersion.Horizon5; + + try + { + Codemasters.F1_2021.Packet packet = null; + var type = Codemasters.F1_2021.CodemastersToolkit.GetPacketType(bytes); + switch (type) + { + case Codemasters.F1_2021.PacketType.CarStatus: + packet = new Codemasters.F1_2021.CarStatusPacket(); + break; + case Codemasters.F1_2021.PacketType.CarTelemetry: + packet = new Codemasters.F1_2021.TelemetryPacket(); + break; + case Codemasters.F1_2021.PacketType.FinalClassification: + packet = new Codemasters.F1_2021.FinalClassificationPacket(); + break; + case Codemasters.F1_2021.PacketType.Lap: + packet = new Codemasters.F1_2021.LapPacket(); + break; + case Codemasters.F1_2021.PacketType.LobbyInfo: + packet = new Codemasters.F1_2021.LobbyInfoPacket(); + break; + case Codemasters.F1_2021.PacketType.Motion: + packet = new Codemasters.F1_2021.MotionPacket(); + break; + case Codemasters.F1_2021.PacketType.Participants: + packet = new Codemasters.F1_2021.ParticipantPacket(); + break; + case Codemasters.F1_2021.PacketType.Session: + packet = new Codemasters.F1_2021.SessionPacket(); + break; + default: break; + } + + if (packet != null) + packet.LoadBytes(bytes); + + switch (packet?.PacketFormat) + { + case 2019: + return GameVersion.F1_2019; + case 2020: + return GameVersion.F1_2020; + case 2021: + return GameVersion.F1_2021; + default: + return GameVersion.Unkonwn; + } + } + catch + { + return GameVersion.Unkonwn; + } + } + public static string GetIP() { string hostName = Dns.GetHostName();//本机名 diff --git a/WpfApp1/MainWindow.xaml.cs b/WpfApp1/MainWindow.xaml.cs index 004fee9..b7ef099 100644 --- a/WpfApp1/MainWindow.xaml.cs +++ b/WpfApp1/MainWindow.xaml.cs @@ -1,6 +1,7 @@ using Codemasters.F1_2019; using Codemasters.F1_2020; using Codemasters.F1_2021; +using System; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -23,6 +24,8 @@ public MainWindow() { InitializeComponent(); + //ConsoleManager.Show(); + DataReciver.ReciveEvent += DataReciver_ReciveEvent; var ip = Helper.GetLocalIP(); lb_ip.Content = $"当前IP:{ip}"; @@ -69,9 +72,9 @@ private void HideIP() } #region F1 Data Processor - private delegate void F1InstrumentDelegate(F1Instrument f1, object packet); + private delegate void F1InstrumentDelegate(F1Instrument f1, LocalData packet); - private void DataReciver_ReciveEvent(object packet) + private void DataReciver_ReciveEvent(LocalData packet) { f1.Dispatcher.Invoke(new F1InstrumentDelegate(ShowDataHandle.F1Handle), f1, packet); if (sp_ip.Visibility != Visibility.Hidden) diff --git a/WpfApp1/Models/GameVersion.cs b/WpfApp1/Models/GameVersion.cs new file mode 100644 index 0000000..d792ce4 --- /dev/null +++ b/WpfApp1/Models/GameVersion.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace F1Tools +{ + public enum GameVersion + { + F1_2019, F1_2020, F1_2021, Unkonwn, Horizon5 + } +} diff --git a/WpfApp1/Models/LocalData.cs b/WpfApp1/Models/LocalData.cs new file mode 100644 index 0000000..ad285eb --- /dev/null +++ b/WpfApp1/Models/LocalData.cs @@ -0,0 +1,17 @@ +namespace F1Tools +{ + public class LocalData + { + public bool? DrsFailure; + public bool? DrsAllowed; + public bool? DrsActive; + + public float? Throttle; + public float? Brake; + public float? Clutch; + public float? HandBrake; + public float? SpeedKph; + public float? EngineRpm; + public int? Gear; + } +} diff --git a/WpfApp1/Properties/AssemblyInfo.cs b/WpfApp1/Properties/AssemblyInfo.cs index 310204d..971cbf3 100644 --- a/WpfApp1/Properties/AssemblyInfo.cs +++ b/WpfApp1/Properties/AssemblyInfo.cs @@ -50,5 +50,5 @@ // //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 //通过使用 "*",如下所示: -[assembly: AssemblyVersion("2.4.3.0")] +[assembly: AssemblyVersion("2.5.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]