In my project I am trying to get data from a byte array. I am using structures to store the data. I am now doing the following:
byte[] received = Client.EndReceive(res, ref RemoteIP);
I am getting a byte array through UDP. This byte array has a certain struct layout found here: https://forums.codemasters.com/topic/50942-f1-2020-udp-specification/
This is an example of the byte array send through udp:
E4-07-01-10-01-06-D2-60-7A-29-BA-53-CE-8C-73-0F-96-42-85-0E-00-00-00-FF-00-00-80-00-00-3F-C0-60-A8-3C-80-00-00-3F-32-02-98-12-00-00-20-00-20-00-20-00-20-00-64-64-64-64-64-64-64-64-5A-00-28-87-AF-41-28-87-AF-41-2B-C6-BB-41-2B-C6-BB-41-07-07-07-07-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-CC-10-00-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-CC-10-00-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-CC-10-01-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-CC-10-00-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-AB-0D-00-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-D7-0E-00-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-D7-0E-00-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-AB-0D-00-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-CC-10-00-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-CC-10-00-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-CC-10-00-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-CC-10-00-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-80-00-00-00-00-00-00-CC-10-00-00-20-00-20-00-20-00-20-00-55-55-5A-5A-55-55-5A-5A-5A-00-00-00-AC-41-00-00-AC-41-00-00-B8-41-00-00-B8-41-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-FF-00
I've setup the structs, and I get the correct packet header information. But when I try to get information from a packet itself, I get an exception.
To first get the packet header I do the following:
ReadOnlySpan<byte> remaining = received;
var header = MemoryMarshal.Cast<byte, PacketHeader>(remaining)[0];
remaining = remaining.Slice(Unsafe.SizeOf<PacketHeader>());
Now under "header" the correct packet headers are stored according to the byte array. I also get the right game version and all the other information stored in the packet header.
To get the following information out of the packet "CarTelemetry" I do the following:
switch (header.m_packetId)
{
case PacketType.CarTelemetry:
int index = 0;
foreach (var telemetry in MemoryMarshal.Cast<byte, CarTelemetryData>(remaining).Slice(0, 21))
{
if(header.m_playerCarIndex == index)
{
Console.WriteLine($"speed: {telemetry.m_speed}, throttle: {telemetry.m_throttle}\n");
var temps = telemetry.m_tyresInnerTemperature;
Console.WriteLine($"type temps: {temps.A}/{temps.B}/{temps.C}/{temps.D}\n");
}
index++;
}
remaining = remaining.Slice(21 * Unsafe.SizeOf<CarTelemetryData>());
var buttons = MemoryMarshal.Cast<byte, uint>(remaining)[0];
Console.WriteLine($"Buttons: {buttons}\n");
remaining = remaining.Slice(sizeof(uint));
Console.WriteLine($"Unaccounted for: {remaining.Length}\n");
break;
}
More on this here: Byte Array to Struct UDP Packet
But with this code now I get the following exception: "System.ArgumentOutOfRangeException" The exception tells me that the parameter start is out of range of valid values, Parameter name: start.
I don't know what is going wrong and how to fix it.
Edit: As requested, I get the exception at the following line:
foreach (var telemetry in MemoryMarshal.Cast<byte, CarTelemetryData>(remaining).Slice(0, 20))
My structs look like this:
public enum PacketType : byte
{
Motion = 0, // Contains all motion data for player’s car – only sent while player is in control
Session = 1,// Data about the session – track, time left
LapData = 2,// Data about all the lap times of cars in the session
Event = 3, // Various notable events that happen during a session
Participants = 4, // List of participants in the session, mostly relevant for multiplayer
CarSetups = 5, // Packet detailing car setups for cars in the race
CarTelemetry = 6, // Telemetry data for all cars
CarStatus = 7 // Status data for all cars such as damage
}
[StructLayout(LayoutKind.Explicit, Pack = 0, Size = 8)]
public struct UshortQuad
{
[FieldOffset(0)]
public ushort A;
[FieldOffset(2)]
public ushort B;
[FieldOffset(4)]
public ushort C;
[FieldOffset(6)]
public ushort D;
}
[StructLayout(LayoutKind.Explicit, Pack = 0, Size = 16)]
public struct FloatQuad
{
[FieldOffset(0)]
public float A;
[FieldOffset(4)]
public float B;
[FieldOffset(8)]
public float C;
[FieldOffset(12)]
public float D;
}
[StructLayout(LayoutKind.Explicit, Pack = 0, Size = 4)]
public struct ByteQuad
{
[FieldOffset(0)]
public byte A;
[FieldOffset(1)]
public byte B;
[FieldOffset(2)]
public byte C;
[FieldOffset(3)]
public byte D;
}
[StructLayout(LayoutKind.Explicit, Pack = 0, Size = 24)]
public struct PacketHeader
{
[FieldOffset(0)]
public ushort m_packetFormat; // 2020
[FieldOffset(2)]
public byte m_gameMajorVersion; // Game major version - "X.00"
[FieldOffset(3)]
public byte m_gameMinorVersion; // Game minor version - "1.XX"
[FieldOffset(4)]
public byte m_packetVersion; // Version of this packet type, all start from 1
[FieldOffset(5)]
public PacketType m_packetId; // Identifier for the packet type, see below
[FieldOffset(6)]
public ulong m_sessionUID; // Unique identifier for the session
[FieldOffset(14)]
public float m_sessionTime; // Session timestamp
[FieldOffset(18)]
public uint m_frameIdentifier; // Identifier for the frame the data was retrieved on
[FieldOffset(22)]
public byte m_playerCarIndex; // Index of player's car in the array
[FieldOffset(23)]
byte m_secondaryPlayerCarIndex; // Index of secondary player's car in the array (splitscreen)
// 255 if no second player
};
[StructLayout(LayoutKind.Explicit, Pack = 0, Size = 60)]
public struct CarTelemetryData
{
[FieldOffset(0)]
public ushort m_speed; // Speed of car in kilometres per hour
[FieldOffset(2)]
public float m_throttle; // Amount of throttle applied (0.0 to 1.0)
[FieldOffset(6)]
public float m_steer; // Steering (-1.0 (full lock left) to 1.0 (full lock right))
[FieldOffset(10)]
public float m_brake; // Amount of brake applied (0.0 to 1.0)
[FieldOffset(14)]
public byte m_clutch; // Amount of clutch applied (0 to 100)
[FieldOffset(15)]
public sbyte m_gear; // Gear selected (1-8, N=0, R=-1)
[FieldOffset(16)]
public ushort m_engineRPM; // Engine RPM
[FieldOffset(18)]
public byte m_drs; // 0 = off, 1 = on
[FieldOffset(19)]
public byte m_revLightsPercent; // Rev lights indicator (percentage)
[FieldOffset(20)]
public UshortQuad m_brakesTemperature; // Brakes temperature (celsius)
[FieldOffset(28)]
public ByteQuad m_tyresSurfaceTemperature; // Tyres surface temperature (celsius)
[FieldOffset(32)]
public ByteQuad m_tyresInnerTemperature; // Tyres inner temperature (celsius)
[FieldOffset(36)]
public ushort m_engineTemperature; // Engine temperature (celsius)
[FieldOffset(40)]
public FloatQuad tyresPressure; // Tyres pressure (PSI)
[FieldOffset(56)]
public ByteQuad m_surfaceType; // Driving surface, see appendice
};