From a7615dd644585c46b67b330461b15911ed47855f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:00:27 +0000 Subject: [PATCH 1/5] Initial plan From ec33e4e986a9b15a2e5f723ef367aaaa4998cb2f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:04:24 +0000 Subject: [PATCH 2/5] Fix unsafe fixed buffer pointer handling and UTF-8 marshaling - Fix F1TelemetryFrameExtensions to use Unsafe.Read and direct pointer access for fixed buffers - Change F12025 Participant m_name from ByValTStr to byte array for proper UTF-8 marshaling - UdpSourceBase Dispose() implementation already correct (from previous PR) Co-authored-by: codegefluester <203914+codegefluester@users.noreply.github.com> --- .../Telemetry/Sources/Formula1/F12025/Participant.cs | 4 ++-- .../Sources/Formula1/F1TelemetryFrameExtensions.cs | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/GamesDat/Telemetry/Sources/Formula1/F12025/Participant.cs b/GamesDat/Telemetry/Sources/Formula1/F12025/Participant.cs index 441d97d..a7ccbf0 100644 --- a/GamesDat/Telemetry/Sources/Formula1/F12025/Participant.cs +++ b/GamesDat/Telemetry/Sources/Formula1/F12025/Participant.cs @@ -14,8 +14,8 @@ public struct Participant public byte m_raceNumber; // Race number of the car public byte m_nationality; // Nationality of the driver - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] - public string m_name; // Name of participant in UTF-8 format – null terminated + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] m_name; // Name of participant in UTF-8 format – null terminated // Will be truncated with ... (U+2026) if too long public byte m_yourTelemetry; // The player's UDP setting, 0 = restricted, 1 = public public byte m_showOnlineNames; // The player's show online names setting, 0 = off, 1 = on diff --git a/GamesDat/Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs b/GamesDat/Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs index cdf640b..eb72a30 100644 --- a/GamesDat/Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs +++ b/GamesDat/Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace GamesDat.Core.Telemetry.Sources.Formula1 @@ -31,7 +32,7 @@ public static unsafe T GetPacket(this F1TelemetryFrame frame) where T : struc $"Packet data too small. Expected {expectedSize} bytes for {packetType.Name}, got {frame.DataLength}"); } - return Marshal.PtrToStructure((IntPtr)frame.RawData); + return Unsafe.Read(frame.RawData); } /// @@ -49,7 +50,8 @@ public static unsafe T GetPacket(this F1TelemetryFrame frame) where T : struc throw new InvalidOperationException($"Packet data too small. Expected {expectedSize} bytes for {packetType.Name}, got {frame.DataLength}"); } - var result = Marshal.PtrToStructure((IntPtr)frame.RawData, packetType); + byte* ptr = frame.RawData; + var result = Marshal.PtrToStructure((IntPtr)ptr, packetType); return result; } @@ -59,7 +61,8 @@ public static unsafe T GetPacket(this F1TelemetryFrame frame) where T : struc public static unsafe byte[] GetRawData(this F1TelemetryFrame frame) { var data = new byte[frame.DataLength]; - Marshal.Copy((IntPtr)frame.RawData, data, 0, frame.DataLength); + byte* ptr = frame.RawData; + Marshal.Copy((IntPtr)ptr, data, 0, frame.DataLength); return data; } } From fc6d5f5790ad4c8c179da3e30c7d6bc9825f9785 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:05:09 +0000 Subject: [PATCH 3/5] Add Name property helper for UTF-8 decoded participant name Co-authored-by: codegefluester <203914+codegefluester@users.noreply.github.com> --- .../Sources/Formula1/F12025/Participant.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/GamesDat/Telemetry/Sources/Formula1/F12025/Participant.cs b/GamesDat/Telemetry/Sources/Formula1/F12025/Participant.cs index a7ccbf0..ff5d482 100644 --- a/GamesDat/Telemetry/Sources/Formula1/F12025/Participant.cs +++ b/GamesDat/Telemetry/Sources/Formula1/F12025/Participant.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using System.Text; namespace GamesDat.Core.Telemetry.Sources.Formula1.F12025 { @@ -26,5 +27,18 @@ public struct Participant [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public LiveryColour[] m_liveryColours; // Colours for the car + /// + /// Gets the participant name as a decoded UTF-8 string + /// + public readonly string Name + { + get + { + if (m_name == null) return string.Empty; + int length = Array.IndexOf(m_name, (byte)0); + if (length < 0) length = m_name.Length; + return Encoding.UTF8.GetString(m_name, 0, length); + } + } } } From c4bac6948590df7d74015b87ac4e46324fa502e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 09:55:34 +0000 Subject: [PATCH 4/5] Fix AccessViolationException in GetPacket by using Unsafe.AsPointer Use Unsafe.AsPointer(ref frame.RawData[0]) instead of Unsafe.Read to properly get a pointer to the fixed buffer. This resolves both the CS0213 compilation error and the runtime AccessViolationException. Co-authored-by: codegefluester <203914+codegefluester@users.noreply.github.com> --- .../Sources/Formula1/F1TelemetryFrameExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GamesDat/Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs b/GamesDat/Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs index eb72a30..2031f50 100644 --- a/GamesDat/Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs +++ b/GamesDat/Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs @@ -32,7 +32,7 @@ public static unsafe T GetPacket(this F1TelemetryFrame frame) where T : struc $"Packet data too small. Expected {expectedSize} bytes for {packetType.Name}, got {frame.DataLength}"); } - return Unsafe.Read(frame.RawData); + return Unsafe.ReadUnaligned(Unsafe.AsPointer(ref frame.RawData[0])); } /// @@ -50,7 +50,7 @@ public static unsafe T GetPacket(this F1TelemetryFrame frame) where T : struc throw new InvalidOperationException($"Packet data too small. Expected {expectedSize} bytes for {packetType.Name}, got {frame.DataLength}"); } - byte* ptr = frame.RawData; + void* ptr = Unsafe.AsPointer(ref frame.RawData[0]); var result = Marshal.PtrToStructure((IntPtr)ptr, packetType); return result; } @@ -61,7 +61,7 @@ public static unsafe T GetPacket(this F1TelemetryFrame frame) where T : struc public static unsafe byte[] GetRawData(this F1TelemetryFrame frame) { var data = new byte[frame.DataLength]; - byte* ptr = frame.RawData; + void* ptr = Unsafe.AsPointer(ref frame.RawData[0]); Marshal.Copy((IntPtr)ptr, data, 0, frame.DataLength); return data; } From b24d1c3d0cb5ad6ef20492b6b261cad1314d559d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Kaiser?= Date: Wed, 11 Feb 2026 11:37:30 +0100 Subject: [PATCH 5/5] Fix frame extension and test --- GamesDat.Demo/Program.cs | 2 +- .../Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/GamesDat.Demo/Program.cs b/GamesDat.Demo/Program.cs index fc8f443..8fda38e 100644 --- a/GamesDat.Demo/Program.cs +++ b/GamesDat.Demo/Program.cs @@ -12,7 +12,7 @@ internal class Program { static async Task Main(string[] args) { - //await CaptureF1SessionAsync(); + await CaptureF1SessionAsync(); //await ReadF1Session("./sessions/f1_20260210_220103.bin"); } diff --git a/GamesDat/Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs b/GamesDat/Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs index 2031f50..706fe00 100644 --- a/GamesDat/Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs +++ b/GamesDat/Telemetry/Sources/Formula1/F1TelemetryFrameExtensions.cs @@ -32,7 +32,8 @@ public static unsafe T GetPacket(this F1TelemetryFrame frame) where T : struc $"Packet data too small. Expected {expectedSize} bytes for {packetType.Name}, got {frame.DataLength}"); } - return Unsafe.ReadUnaligned(Unsafe.AsPointer(ref frame.RawData[0])); + void* ptr = Unsafe.AsPointer(ref frame.RawData[0]); + return Marshal.PtrToStructure((IntPtr)ptr); } ///