UDP-декодирование F1 2019 - PullRequest
       4

UDP-декодирование F1 2019

0 голосов
/ 14 февраля 2020

В настоящее время я работаю над собственным дисплеем для рулевого колеса F1. F1 2019 (по мастерам кодирования) отправляет данные через UDP. Эти данные хранятся в байтовом массиве.

У меня проблемы с декодированием возвращаемого массива. Проблема в том, что я получаю много информации обратно, но я не знаю, что с ней делать. Я проведу вас через то, что я пробовал.

Я подключаюсь к игре через порт 20777 (стандартный порт для игры):

using System.Net;
using System.Net.Sockets;

var Client = new UdpClient(20777); //Connectionport

В этом следующем фрагменте кода я получить информацию из игры:

var RemoteIP = new IPEndPoint(IPAddress.Any, 60240);

byte[] received = Client.EndReceive(res, ref RemoteIP);

Как вы видите, данные из игры в настоящее время хранятся в байтовом массиве.

Здесь идет сложная часть (для меня).

Данные, отправляемые F1 2019, упакованы в структуры (из того, что я понимаю с их сайта). Но я понятия не имею, как я получаю информацию из массива байтов и в правильные переменные (например, какова текущая скорость или какова передача автомобиля).

Информация о пакетах на сайте от codemasters:

https://forums.codemasters.com/topic/44592-f1-2019-udp-specification/

Теперь актуальный вопрос:

Когда я набираю эту строку кода:

short game_version = BitConverter.ToInt16(received, 0);

И я отображаю его в текстовом поле, переменная game_version теперь 2019.

Я не понимаю, почему при indexnumber 0 байты преобразуются в 2019.

И я не знаю, какие номера индексов использовать для получения каждой необходимой мне переменной.

Я надеюсь, что кто-то может пролить свет на этот вопрос. На форуме разработчиков кода все, похоже, знают, как получить данные из байтового массива.

С уважением.

1 Ответ

1 голос
/ 16 февраля 2020

Хорошо, я обнаружил (спасибо Джереми), что мне нужно получить структуру из массива байтов. Я следовал этим примерам: Example1 Example2

Таким образом, Codemasters (создатели F1 2019) отправляют байтовый массив со всей необходимой информацией. Они преобразовали структуры в массив байтов. Эти структуры содержат всю информацию, которую посылает игра. Таким образом, вещь, которая должна произойти, это преобразование байтового массива обратно в структуры. Имейте в виду, что structlayout от Codemasters должен оставаться прежним, иначе вы не получите правильную информацию в правильной переменной.

PacketHeader packetheader = ByteArrayToPacketHeader(received);

PacketHeader ByteArrayToPacketHeader(byte[] bytes)
{
   GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
   PacketHeader stuff;
   try
   {
     stuff = (PacketHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(PacketHeader));
   }
   finally
   {
   handle.Free();
   }
   return stuff;
   }

В настоящее время код выше преобразует входящий байтовый массив (полученный) в структура PacketHeader. Структура выглядит следующим образом:

public struct PacketHeader
    {
        public ushort m_packetFormat;         // 2019
        public byte m_gameMajorVersion;     // Game major version - "X.00"
        public byte m_gameMinorVersion;     // Game minor version - "1.XX"
        public byte m_packetVersion;        // Version of this packet type, all start from 1
        public byte m_packetId;             // Identifier for the packet type, see below
        public ulong m_sessionUID;           // Unique identifier for the session
        public float m_sessionTime;          // Session timestamp
        public uint m_frameIdentifier;      // Identifier for the frame the data was retrieved on
        public byte m_playerCarIndex;       // Index of player's car in the array
    };

Каждый пакет (структура) с информацией имеет PacketHeader. Преобразовав Заголовок каждого Пакета, вы получите соответствующую информацию в переменной: stuff.

Здесь вы можете увидеть информацию PacketHeader при отладке

Я буду попытайтесь объяснить, что делает код. Я не уверен, что могу объяснить это на 100%, потому что сам не понимаю этого полностью.

PacketHeader ByteArrayToPacketHeader(byte[] bytes)
{

}

Сначала я создал новый метод. Этот метод извлекает структуру из байтового массива. Затем я добавил необходимые переменные в метод:

GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
PacketHeader stuff;

Я действительно не понимаю дескриптор, но если это то, что я думаю, он записывает байты, чтобы их можно было правильно преобразовать.

Я также сделал переменную: вещи. В этой переменной структура будет «сохранена». В следующей части я добавил код преобразования:

try
{
  stuff = (PacketHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(PacketHeader));
}
finally
{
   handle.Free();
}
return stuff;

Преобразование выполнено с помощью этого кода. Когда PacketHeader заполнен, в коде будет следовать структура структуры и переменные будут заполнены.

Последняя часть, которая должна быть сделана, - это вызов этого метода. Я сделал это так:

PacketHeader packetheader = ByteArrayToPacketHeader(received);

Здесь вы можете видеть, что я вызвал метод PacketHeader и создал переменную с именем packetheader. В этой переменной будет храниться вся информация.

Внимание! Заполните байтовый массив, который вы хотите использовать в полученном слоте. Таким образом, метод будет использовать этот байтовый массив.

Если я теперь хочу вызвать переменную из структуры PacketHeader, я просто напишу это:

packetheader.m_packetFormat (example)

В настоящее время я могу получить правильная информация из PacketHeader, но все же не из других структур. Но я на шаг ближе к завершению моего проекта!

Извините, если объяснение не совсем верно. (Я все еще учусь сам). Пожалуйста, свяжитесь со мной, если у вас есть какие-либо советы или замечания по поводу этого объяснения. Я хотел бы узнать больше об этом предмете.

С уважением.

...