F1 2019 UDP解码

F1 2019 UDP decoding

我目前正在为 F1 方向盘开发自己的显示器。 F1 2019(by codemasters)通过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 年转换。

而且我不知道要使用哪个索引号来获取我想要的每个变量。

我希望有人能对这件事有所启发。在codemasters论坛上好像大家都知道如何从byte数组中获取数据

谨致问候。

好的,我发现(感谢 Jeremy)是我需要从字节数组中获取结构。我遵循了这些例子: Example1 Example2

所以 Codemasters(F1 2019 的制造商)正在发送一个字节数组,其中包含所有需要的信息。他们已将结构转换为字节数组。这些结构包含游戏发出的所有信息。所以需要做的是将字节数组转换回结构。请记住,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。通过对每个Packet的Header进行转换得到变量中对应的信息:stuff.

Here you can see the information of the PacketHeader while debugging

我将尝试解释代码的作用。我不确定我是否可以 100% 解释它,因为我自己并不完全理解它。

PacketHeader ByteArrayToPacketHeader(byte[] bytes)
{

}

首先我做了一个新方法。此方法会将结构从字节数组中拉出。 然后我将所需的变量添加到方法中:

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

我不太了解句柄,但如果它是我认为的那样,它会固定字节以便它们可以正确转换。

我还做了一个变量:stuff。在这个变量中,结构将是 "stored"。 在下一部分中,我添加了转换代码:

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

转换完成就是这段代码。 填写PacketHeader时,在代码中,会按照struct布局,填写变量。

需要完成的最后一部分是调用此方法。 我这样做是这样的:

PacketHeader packetheader = ByteArrayToPacketHeader(received);

在这里你可以看到我调用了PacketHeader方法并创建了一个名为packetheader的变量。在此变量中将存储所有信息。

重要! 在接收到的槽中填入你想要使用的字节数组。这样该方法将使用该字节数组。

如果我现在想从 PacketHeader 结构中调用一个变量,我只需这样写:

packetheader.m_packetFormat (example)

目前我能够从 PacketHeader 中获取正确的信息,但仍然不能从其他结构中获取。但我离完成我的项目又近了一步!

如果解释不完全正确,我很抱歉。 (我还在学习自己)。 如果您对此解释有任何提示或注意事项,请与我联系。我想了解更多关于这个主题的信息。

此致。