F1 2019 UDP解码

2024-05-03

我目前正在为 F1 方向盘开发自己的显示器。 F1 2019(由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/ https://forums.codemasters.com/topic/44592-f1-2019-udp-specification/

现在真正的问题是:

当我输入这行代码时:

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

我将它显示在文本框中,变量game_version现在已经是2019年了。

我不明白为什么,随着indexnumber0,字节在2019年转换。

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

我希望有人能够对这个问题有所启发。在codemasters论坛上似乎每个人都知道如何从字节数组中获取数据。

亲切的问候。


好吧,我发现(感谢 Jeremy)是我需要从字节数组中获取一个结构。我遵循了这些例子:Example1 https://stackoverflow.com/questions/5076302/how-do-i-load-a-byte-array-into-a-structure-in-c/5076491#5076491 Example2 https://stackoverflow.com/questions/2871/reading-a-c-c-data-structure-in-c-sharp-from-a-byte-array

因此,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;
   }

目前,上面的代码将传入的字节数组(接收到)转换为 struct 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
    };

每个带有信息的数据包(结构体)都有一个数据包头。通过转换每个数据包的标头,您可以在变量:stuff 中获得相应的信息。

这里可以在调试时看到PacketHeader的信息 https://i.stack.imgur.com/HKoJr.png

我将尝试解释该代码的作用。我不确定我能100%解释它,因为我自己也不完全理解它。

PacketHeader ByteArrayToPacketHeader(byte[] bytes)
{

}

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

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

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

我还做了一个变量: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 中获取正确的信息,但仍然无法从其他结构中获取。但我离完成我的项目又近了一步!

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

亲切的问候。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

F1 2019 UDP解码 的相关文章

随机推荐