I am receiving data packets over UDP that I parse into structs and in a specific situation my data gets all messed up and I can't figure out what the problem might be. Let me give you an overview of what I am doing.
In this example the data is send from the Formula 1 2020 game and the curious thing is that the first entry in the m_carTelemetryData
array (see below) is always fine, and the data is all sound. However, every entry of the 22 after the first one is totally messed up with either 0 values, null values or completely outlandish values for all the different fields in the struct.
I tried several things already to pinpoint the issue, but I have now reached the end of my knowledge about the things I am dealing with here. My best guess is that something is going wrong when converting the data into a struct or something else is going on that causes a misalignment (?) of the data.
What I tried so far
BinaryReader
- no luckBitConverter.ToFoo(bytes, offset)
- no luckPack
attribute assuming that's where I got wrong - no luckMy questions:
Here is the code for reference (if anything helpful is missing, please let me know):
Packet Header
[StructLayout(LayoutKind.Sequential), Pack = 1]
struct PacketHeader2020 {
public ushort m_packetFormat;
public byte m_gameMajorVersion;
public byte m_gameMinorVersion;
public byte m_packetVersion;
public byte m_packetId;
public ulong m_sessionUUID;
public float m_sessionTime;
public uint m_frameIdentifier;
public byte m_playerCarIndex;
public byte m_secondaryPlayerCarIndex;
}
Packet
public struct CarTelemetryPacket2020
{
public PacketHeader2020 m_header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)]
public CarTelemetryData2020[] m_carTelemetryData;
public ButtonFlag m_buttonStatus;
public byte m_mfdPanelIndex;
public byte m_mfdPanelIndexSecondaryPlayer;
public byte m_suggestedGear;
};
CarTelemetryData2020
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CarTelemetryData2020
{
public ushort m_speed;
public float m_throttle;
public float m_steer;
public float m_brake;
public byte m_clutch;
public sbyte m_gear;
public ushort m_engineRPM;
public byte m_drs;
public byte m_revLightsPercent;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public ushort[] m_brakesTemperature;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public ushort[] m_tyresSurfaceTemperature;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public ushort[] m_tyresInnerTemperature;
public ushort m_engineTemperature;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public float[] m_tyresPressure;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public SurfaceType[] m_surfaceType;
}
byte[] -> struct
public static T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
}
finally
{
handle.Free();
}
}
I just pasted your code into LINQPad and found a few problems. The CarTelemetryPacket2020
structure needed a pack clause. Also m_tyresSurfaceTemperature
and m_tyresInnerTemperature
should have been a byte. The following returns a size of 1307 as per the protocol specification. You're right that the sizes should have matched up and I don't see any other obvious problems with your code.
void Main()
{
System.Runtime.InteropServices.Marshal.SizeOf(typeof(CarTelemetryPacket2020)).Dump();
}
[StructLayout(LayoutKind.Sequential, Pack = 1) ]
public struct PacketHeader2020
{
public ushort m_packetFormat;
public byte m_gameMajorVersion;
public byte m_gameMinorVersion;
public byte m_packetVersion;
public byte m_packetId;
public ulong m_sessionUUID;
public float m_sessionTime;
public uint m_frameIdentifier;
public byte m_playerCarIndex;
public byte m_secondaryPlayerCarIndex;
}
// Added pack = 1
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CarTelemetryPacket2020
{
public PacketHeader2020 m_header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)]
public CarTelemetryData2020[] m_carTelemetryData;
public UInt32 m_buttonStatus;
public byte m_mfdPanelIndex;
public byte m_mfdPanelIndexSecondaryPlayer;
public byte m_suggestedGear;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CarTelemetryData2020
{
public ushort m_speed;
public float m_throttle;
public float m_steer;
public float m_brake;
public byte m_clutch;
public sbyte m_gear;
public ushort m_engineRPM;
public byte m_drs;
public byte m_revLightsPercent;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public ushort[] m_brakesTemperature;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
// Changed following to byte
public byte[] m_tyresSurfaceTemperature;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
// Changed following to byte
public byte[] m_tyresInnerTemperature;
public ushort m_engineTemperature;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public float[] m_tyresPressure;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] m_surfaceType;
}