B4J Question UDP Packet Data (Bytearray) to "struct"?

DonManfred

Expert
Licensed User
Longtime User
Here i started a thread asking on how to Capture Broadcast UDP Packets.
I´m not able to test it as yet but i´m sure it will work when erel says it will.

So. Imagine it will work, then i am supposed to get different UDP Packets with different contents.

One packet for example is the ParticipantInfoStrings struct

struct sParticipantInfoStrings
{
static const u32 sPacketSize = 1347;
u16 sBuildVersionNumber; // 0
u8 sPacketType; // 2
char sCarName[64]; // 3
char sCarClassName[64]; // 131
char sTrackLocation[64]; // 195
char sTrackVariation[64]; // 259
char sName[16][64]; // 323
// 1347
};

From my investigations with delphi on win32 i can say that i got two kind of packets so far.
ONE with a size of 1347 and a lot other with the size of 1367 bytes.
The last one are the truct sTelemetryData

How would i need to use the bytearray i have to get the sBuildVersionNumber, sPacketType, sCarName and so on into B4J variables?

I need to understand how to interpret for example
u16 sBuildVersionNumber; // 0

How do i get a B4J variable from the first two bytes of the bytearray?

There are different types in the structs i have to rebuild.

u16, u32, u8, s8, s16, f32, char....

The structs for the telemetrydata is more complex

struct sTelemetryData
{
static const u32 sPacketSize = 1367;
u16 sBuildVersionNumber; // 0
u8 sPacketType; // 2

// Game states
u8 sGameSessionState; // 3

// Participant info
s8 sViewedParticipantIndex; // 4
s8 sNumParticipants; // 5

// Unfiltered input
u8 sUnfilteredThrottle; // 6
u8 sUnfilteredBrake; // 7
s8 sUnfilteredSteering; // 8
u8 sUnfilteredClutch; // 9
u8 sRaceStateFlags; // 10

// Event information
u8 sLapsInEvent; // 11

// Timings
f32 sBestLapTime; // 12
f32 sLastLapTime; // 16
f32 sCurrentTime; // 20
f32 sSplitTimeAhead; // 24
f32 sSplitTimeBehind; // 28
f32 sSplitTime; // 32
f32 sEventTimeRemaining; // 36
f32 sPersonalFastestLapTime; // 40
f32 sWorldFastestLapTime; // 44
f32 sCurrentSector1Time; // 48
f32 sCurrentSector2Time; // 52
f32 sCurrentSector3Time; // 56
f32 sFastestSector1Time; // 60
f32 sFastestSector2Time; // 64
f32 sFastestSector3Time; // 68
f32 sPersonalFastestSector1Time; // 72
f32 sPersonalFastestSector2Time; // 76
f32 sPersonalFastestSector3Time; // 80
f32 sWorldFastestSector1Time; // 84
f32 sWorldFastestSector2Time; // 88
f32 sWorldFastestSector3Time; // 92

u16 sJoyPad; // 96

// Flags
u8 sHighestFlag; // 98

// Pit info
u8 sPitModeSchedule; // 99

// Car state
s16 sOilTempCelsius; // 100
u16 sOilPressureKPa; // 102
s16 sWaterTempCelsius; // 104
u16 sWaterPressureKpa; // 106
u16 sFuelPressureKpa; // 108
u8 sCarFlags; // 110
u8 sFuelCapacity; // 111
u8 sBrake; // 112
u8 sThrottle; // 113
u8 sClutch; // 114
s8 sSteering; // 115
f32 sFuelLevel; // 116
f32 sSpeed; // 120
u16 sRpm; // 124
u16 sMaxRpm; // 126
u8 sGearNumGears; // 128
u8 sBoostAmount; // 129
s8 sEnforcedPitStopLap; // 130
u8 sCrashState; // 131

f32 sOdometerKM; // 132
f32 sOrientation[3]; // 136
f32 sLocalVelocity[3]; // 148
f32 sWorldVelocity[3]; // 160
f32 sAngularVelocity[3]; // 172
f32 sLocalAcceleration[3]; // 184
f32 sWorldAcceleration[3]; // 196
f32 sExtentsCentre[3]; // 208

// Wheels / Tyres
u8 sTyreFlags[4]; // 220
u8 sTerrain[4]; // 224
f32 sTyreY[4]; // 228
f32 sTyreRPS[4]; // 244
f32 sTyreSlipSpeed[4]; // 260
u8 sTyreTemp[4]; // 276
u8 sTyreGrip[4]; // 280
f32 sTyreHeightAboveGround[4]; // 284
f32 sTyreLateralStiffness[4]; // 300
u8 sTyreWear[4]; // 316
u8 sBrakeDamage[4]; // 320
u8 sSuspensionDamage[4]; // 324
s16 sBrakeTempCelsius[4]; // 328
u16 sTyreTreadTemp[4]; // 336
u16 sTyreLayerTemp[4]; // 344
u16 sTyreCarcassTemp[4]; // 352
u16 sTyreRimTemp[4]; // 360
u16 sTyreInternalAirTemp[4]; // 368
f32 sWheelLocalPositionY[4]; // 376
f32 sRideHeight[4]; // 392
f32 sSuspensionTravel[4]; // 408
f32 sSuspensionVelocity[4]; // 424
u16 sAirPressure[4]; // 440

// Extras
f32 sEngineSpeed; // 448
f32 sEngineTorque; // 452

// Car damage
u8 sAeroDamage; // 456
u8 sEngineDamage; // 457

// Weather
s8 sAmbientTemperature; // 458
s8 sTrackTemperature; // 459
u8 sRainDensity; // 460
s8 sWindSpeed; // 461
s8 sWindDirectionX; // 462
s8 sWindDirectionY; // 463

sParticipantInfo sParticipantInfo[56]; // 464
// 56*16=896
f32 sTrackLength; // 1360
u8 sWings[2]; // 1364
u8 sDPad; // 1366
// 1368 struct is padded to
};

Any help/tips/hints are welcome ;-)
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You should post a full hex message. Without it is difficult to get it right.
Something like:
B4X:
'process globals
Type PIS (BuildVersionNumber As Short, PacketType As Byte, CarName As String, _
     TrackLocation As String, TrackVariation As String, Name(16) As String)


Sub ParseMessage(data() As Byte) As PIS
   Dim p As PIS
   p.Initialize
   Dim raf As RandomAccessFile
   raf.Initialize3(data, True) 'change the endianess if the version number is incorrect
   p.BuildVersionNumber = raf.ReadShort(0)
   p.PacketType = raf.ReadSignedByte(raf.CurrentPosition)
   Dim buffer(64) As Byte
   p.CarName = ReadString(raf, buffer)
   p.TrackLocation = ReadString(raf, buffer)
   p.TrackVariation = ReadString(raf, buffer)
   For i = 0 To p.Name.Length
     p.Name(i) = ReadString(raf, buffer)
   Next
   Return p
End Sub

Private Sub ReadString(raf As RandomAccessFile, buffer() As Byte) As String
   raf.ReadBytes(buffer, 0, buffer.Length, raf.CurrentPosition)
   Return BytesToString(buffer, 0, buffer.Length, "utf8")
End Sub
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
Erel wins dodgy acronym of the day award for

Type PIS (BuildVersionNumber.......

On a serious note , you could use JNA Structure to get the data too
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
You should post a full hex message. Without it is difficult to get it right

It starts with this... Seems the b4j log cut the output
740401424D57204D33204533302047726F757020410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047726F757020410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004272616E6473204861746368006B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000496E6479002050726978000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...

Something like

Thank you very much for the sample!!! It was a really help to get this working

I´m working on defining the desired ParseMethod for the telemetry packet right now :)

I´ll keep you informed
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
On a serious note , you could use JNA Structure to get the data too
Can you explain or even give a link to more information about this? (but i´ll try to do a search for it too)

I gues you are talking about the \jna-master\src\com\sun\jna\Structure.java?

Do you have an example on how to use this from B4J?
 
Last edited:
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
I must agree with Erel as there are so few packet types, you would end up writing far more code than using pure B4J.

If RandomAccessFile is an nio.ByteBuffer, then that is probably the cleanest solution to use.
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Just if you are interested... It´s not finished though but it is a working start :)

B4X:
    Type Participant (BuildVersionNumber As Short, PacketType As Byte, CarName As String, _
     CarClassName As String, TrackLocation As String, TrackVariation As String, Name(16) As String)

    Type ParticipantInfo (WorldPosition(3) As Short, CurrentLapDistance As Short, RacePosition As Byte, _
    LapsCompleted As Byte, CurrentLap As Byte, Sector As Byte, LastSectorTime As Float)
  
    Type Telemetry (BuildVersionNumber As Short, PacketType As Byte, GameSessionstate As Byte, _
    ViewedParticipantIndex As Byte, NumParticipants As Byte, UnfilteredThrottle As Byte, _
    UnfilteredBrake As Byte, UnfilteredSteering As Byte, UnfilteredClutch As Byte, RaceStateFlags As Byte, _
    LapsInEvent As Byte, BestLapTime As Float, LastLapTime As Float, CurrentTime As Float, _
    SplitTimeAhead As Float, SplitTimeBehind As Float, SplitTime As Float, EventTimeRemaining As Float, _
    PersonalFastestLapTime As Float, WorldFastestLapTime As Float, CurrentSector1Time As Float, _
    CurrentSector2Time As Float, CurrentSector3Time As Float, FastestSector1Time As Float, FastestSector2Time As Float, _
    FastestSector3Time As Float, PersonalFastestSector1Time As Float, PersonalFastestSector2Time As Float, _
    PersonalFastestSector3Time As Float, _
    WorldFastestSector1Time As Float, WorldFastestSector2Time As Float, _
    WorldFastestSector3Time As Float, JoyPad As Short, HighestFlag As Byte, PitModeSchedule As Byte, _
    OilTempCelsius As Short, OilPressureKPa As Short, WaterTempCelsius As Short, WaterPressureKpa As Short, _
    FuelPressureKpa As Short, CarFlags As Byte, FuelCapacity As Byte, Brake As Byte, Throttle As Byte, _
    Clutch As Byte, Steering As Byte, FuelLevel As Float, Speed As Float, RPM As Short, MaxRPM As Short, _
    GearNumGears As Byte, BoostAmount As Byte, EnforcedPitstopLap As Byte, CrashState As Byte, _
    OdometerKM As Float, Orientation(3) As Float, LocalVelocity(3) As Float, WorldVelocity(3) As Float, _
    AngularVelocity(3) As Float, LocalAcceleration(3) As Float, WorldAcceleration(3) As Float, _
    ExtentsCentre(3) As Float, TyreFlags(4) As Byte, Terrain(4) As Byte, TyreY(4) As Float, TyreRPS(4) As Float, _
    TyreSlipSpeed(4) As Float, TyreTemp(4) As Byte, TyreGrip(4) As Byte, _
    TyreHeightAboveGround(4) As Float, TyreLateralStiffness(4) As Float, TyreWear(4) As Byte, BrakeDamage(4) As Byte, _
    SuspensionDamage(4) As Byte, BrakeTempCelsius(4) As Short, TyreTreadTemp(4) As Short, TyreLayerTemp(4) As Short, _
    TyreCarcassTemp(4) As Short, TyreRimTemp(4) As Short, TyreInternalAirTemp(4) As Short, _
    WheelLocalPositionY(4) As Float, RideHeight(4) As Float, SuspensionTravel(4) As Float, SuspensionVelocity(4) As Float, _
    AirPressure(4) As Short, EngineSpeed As Float, EngineTorque As Float, _
    AeroDamage As Byte, EngineDamage As Byte, AmbientTemperature As Byte, TrackTemperature As Byte, _
    RainDensity As Byte, WindSpeed As Byte, WindDirectionX As Byte, WindDirectionY As Byte, _
    Driver(56) As ParticipantInfo, TrackLength As Float, Wings(2) As Byte, DPad As Byte)

B4X:
Sub UDP_PacketArrived (Packet As UDPPacket)
    Dim msg As String
    msg = BytesToString(Packet.Data, Packet.Offset, Packet.Length, "UTF8")
    Log("> NEW PACKET")
    Log("Host: "&Packet.Host)
    Log("Adress: "&Packet.HostAddress)
    Log("Port: "&Packet.Port)
    Log("Len: "&Packet.Length)
    Log("ToString: "&Packet.toString)
    'Log("HEX: "&bconv.HexFromBytes(Packet.Data))
  
    If Packet.Length = 1347 Then
        Dim drivers As Participant = ParseMessage(Packet.Data)
        Log(drivers.BuildVersionNumber)

        Log(drivers.CarName)
        Log(drivers.CarClassName)
        Log(drivers.TrackLocation)
        Log(drivers.TrackVariation)
        For i = 0 To 15
            Log(i&": "&drivers.Name(i))      
        Next
    End If
    If Packet.Length = 1367 Then
        Dim t As Telemetry =    ParseTelemetry(Packet.Data)
        Log("Speed: "&t.Speed)      
        Log("Drivers: "&t.Driver.Length)
        ' All other Values of Telemetry are available too    
    End If

    memo.Text = memo.Text &CRLF&bconv.HexFromBytes(Packet.Data)
    'Msgbox.show("Message received: " & msg, "")
    Log(msg)
End Sub

B4X:
Sub ParseMessage(data() As Byte) As Participant
   Log("ParseMessage("&data.Length&")")
     Dim p As Participant
   p.Initialize
   Dim raf As RandomAccessFile
   raf.Initialize3(data, True) 'change the endianess if the version number is incorrect
   p.BuildVersionNumber = raf.ReadShort(0)
   p.PacketType = raf.ReadSignedByte(2)
   Dim buffer(64) As Byte
   p.CarName = ReadString(raf, buffer).Replace(Chr(0),Chr(32))
   p.CarClassName = ReadString(raf, buffer).Replace(Chr(0),Chr(32))
   p.TrackLocation = ReadString(raf, buffer).Replace(Chr(0),Chr(32))
   p.TrackVariation = ReadString(raf, buffer).Replace(Chr(0),Chr(32))
   For i = 0 To p.Name.Length-1
     p.Name(i) = ReadString(raf, buffer).Replace(Chr(0),Chr(32))
   Next
   Return p
End Sub
Sub ParseTelemetry(data() As Byte) As Telemetry
  Log("ParseTelemetry("&data.Length&")")
    Dim t As Telemetry
  t.Initialize
  Dim raf As RandomAccessFile
  raf.Initialize3(data, False) 'change the endianess if the version number is incorrect
    'struct sTelemetryData
  t.BuildVersionNumber = raf.ReadShort(0)
  t.PacketType = raf.ReadUnsignedByte(2)
    t.GameSessionstate = raf.ReadUnsignedByte(3)
    '  // Participant info
    t.ViewedParticipantIndex = raf.ReadSignedByte(4)
    '  s8    sNumParticipants;             // 5
    t.NumParticipants = raf.ReadSignedByte(5)
    '  // Unfiltered input
    '  u8    sUnfilteredThrottle;          // 6
    t.UnfilteredThrottle = raf.ReadUnsignedByte(6)
    '  u8    sUnfilteredBrake;             // 7
    t.UnfilteredBrake = raf.ReadUnsignedByte(7)
    '  s8    sUnfilteredSteering;          // 8
    t.UnfilteredSteering = raf.ReadUnsignedByte(8)
    '  u8    sUnfilteredClutch;            // 9
    t.UnfilteredClutch = raf.ReadUnsignedByte(9)
    '  u8    sRaceStateFlags;              // 10
    t.RaceStateFlags = raf.ReadUnsignedByte(10)
    '
    '  // Event information
    '  u8    sLapsInEvent;                 // 11
    t.LapsInEvent =  raf.ReadUnsignedByte(11)
    '
    '  // Timings
    '  f32   sBestLapTime;                 // 12
    t.BestLapTime = raf.ReadFloat(12)
    '  f32   sLastLapTime;                 // 16
    t.LastLapTime = raf.ReadFloat(16)
    '  f32   sCurrentTime;                 // 20
    t.CurrentTime = raf.ReadFloat(20)
    '  f32   sSplitTimeAhead;              // 24
    t.SplitTimeAhead = raf.ReadFloat(24)
    '  f32   sSplitTimeBehind;             // 28
    t.SplitTimeBehind = raf.ReadFloat(28)
    '  f32   sSplitTime;                   // 32
    t.SplitTime = raf.ReadFloat(32)
    '  f32   sEventTimeRemaining;          // 36
    t.EventTimeRemaining = raf.ReadFloat(36)
    '  f32   sPersonalFastestLapTime;      // 40
    t.PersonalFastestLapTime = raf.ReadFloat(40)
    '  f32   sWorldFastestLapTime;         // 44
    t.WorldFastestLapTime = raf.ReadFloat(44)
    '  f32   sCurrentSector1Time;          // 48
    t.CurrentSector1Time = raf.ReadFloat(48)
    '  f32   sCurrentSector2Time;          // 52
    t.CurrentSector2Time = raf.ReadFloat(52)
    '  f32   sCurrentSector3Time;          // 56
    t.CurrentSector3Time = raf.ReadFloat(56)
    '  f32   sFastestSector1Time;          // 60
    t.FastestSector1Time = raf.ReadFloat(60)
    '  f32   sFastestSector2Time;          // 64
    t.FastestSector2Time = raf.ReadFloat(64)
    '  f32   sFastestSector3Time;          // 68
    t.FastestSector3Time = raf.ReadFloat(68)
    '  f32   sPersonalFastestSector1Time;  // 72
    t.PersonalFastestSector1Time = raf.ReadFloat(72)
    '  f32   sPersonalFastestSector2Time;  // 76
    t.PersonalFastestSector2Time = raf.ReadFloat(76)
    '  f32   sPersonalFastestSector3Time;  // 80
    t.PersonalFastestSector3Time = raf.ReadFloat(80)
    '  f32   sWorldFastestSector1Time;     // 84
    t.WorldFastestSector1Time = raf.ReadFloat(84)
    '  f32   sWorldFastestSector2Time;     // 88
    t.WorldFastestSector2Time = raf.ReadFloat(88)
    '  f32   sWorldFastestSector3Time;     // 92
    t.WorldFastestSector3Time = raf.ReadFloat(92)
    '
    '  u16   sJoyPad;                      // 96
    t.JoyPad = raf.ReadShort(96)
    '
    '  // Flags
    '  u8    sHighestFlag;                 // 98
    t.HighestFlag = raf.ReadUnsignedByte(98)
    '
    '  // Pit info
    '  u8    sPitModeSchedule;             // 99
    t.PitModeSchedule = raf.ReadUnsignedByte(99)
    '
    '  // Car state
    '  s16   sOilTempCelsius;              // 100
    t.OilTempCelsius = raf.ReadShort(100)
    '  u16   sOilPressureKPa;              // 102
    t.OilPressureKPa = raf.ReadShort(102)
    '  s16   sWaterTempCelsius;            // 104
    t.WaterTempCelsius = raf.ReadShort(104)
    '  u16   sWaterPressureKpa;            // 106
    t.WaterPressureKpa = raf.ReadShort(106)
    '  u16   sFuelPressureKpa;             // 108
    t.FuelPressureKpa = raf.ReadShort(108)
    '  u8    sCarFlags;                    // 110
    t.CarFlags = raf.ReadUnsignedByte(110)
    '  u8    sFuelCapacity;                // 111
    t.FuelCapacity = raf.ReadUnsignedByte(111)
    '  u8    sBrake;                       // 112
    t.Brake = raf.ReadUnsignedByte(112)
    '  u8    sThrottle;                    // 113
    t.Throttle = raf.ReadUnsignedByte(113)
    '  u8    sClutch;                      // 114
    t.Clutch = raf.ReadUnsignedByte(114)
    '  s8    sSteering;                    // 115
    t.Steering = raf.ReadUnsignedByte(115)
    '  f32   sFuelLevel;                   // 116
    t.FuelLevel = raf.ReadFloat(116)
    '  f32   sSpeed;                       // 120
    t.Speed = raf.ReadFloat(120)
    '  u16   sRpm;                         // 124
    t.RPM = raf.ReadShort(124)
    '  u16   sMaxRpm;                      // 126
    t.MaxRPM = raf.ReadShort(126)
    '  u8    sGearNumGears;                // 128
    t.GearNumGears = raf.ReadUnsignedByte(128)
    '  u8    sBoostAmount;                 // 129
    t.BoostAmount = raf.ReadUnsignedByte(129)
    '  s8    sEnforcedPitStopLap;          // 130
    t.EnforcedPitstopLap = raf.ReadSignedByte(130)
    '  u8    sCrashState;                  // 131
    t.CrashState = raf.ReadUnsignedByte(131)
    '
    '  f32   sOdometerKM;                  // 132
    t.OdometerKM = raf.ReadFloat(132)
    '  f32   sOrientation[3];              // 136
    t.Orientation(0) = raf.ReadFloat(136)
    t.Orientation(1) = raf.ReadFloat(140)
    t.Orientation(2) = raf.ReadFloat(144)
    '  f32   sLocalVelocity[3];            // 148
    t.LocalVelocity(0) = raf.ReadFloat(148)
    t.LocalVelocity(1) = raf.ReadFloat(152)
    t.LocalVelocity(2) = raf.ReadFloat(156)
    '  f32   sWorldVelocity[3];            // 160
    t.WorldVelocity(0) = raf.ReadFloat(160)
    t.WorldVelocity(1) = raf.ReadFloat(164)
    t.WorldVelocity(2) = raf.ReadFloat(168)
    '  f32   sAngularVelocity[3];          // 172
    t.AngularVelocity(0) = raf.ReadFloat(172)
    t.AngularVelocity(1) = raf.ReadFloat(176)
    t.AngularVelocity(2) = raf.ReadFloat(180)
    '  f32   sLocalAcceleration[3];        // 184
    t.LocalAcceleration(0) = raf.ReadFloat(184)
    t.LocalAcceleration(1) = raf.ReadFloat(188)
    t.LocalAcceleration(2) = raf.ReadFloat(192)
    '  f32   sWorldAcceleration[3];        // 196
    t.WorldAcceleration(0) = raf.ReadFloat(196)
    t.WorldAcceleration(1) = raf.ReadFloat(200)
    t.WorldAcceleration(2) = raf.ReadFloat(204)
    '  f32   sExtentsCentre[3];            // 208
    t.ExtentsCentre(0) = raf.ReadFloat(208)
    t.ExtentsCentre(1) = raf.ReadFloat(212)
    t.ExtentsCentre(2) = raf.ReadFloat(216)
    '
    '  // Wheels / Tyres
    '  u8    sTyreFlags[4];                // 220
    t.TyreFlags(0) = raf.ReadUnsignedByte(220)
    t.TyreFlags(1) = raf.ReadUnsignedByte(221)
    t.TyreFlags(2) = raf.ReadUnsignedByte(222)
    t.TyreFlags(3) = raf.ReadUnsignedByte(223)
    '  u8    sTerrain[4];                  // 224
    t.Terrain(0) = raf.ReadUnsignedByte(224)
    t.Terrain(1) = raf.ReadUnsignedByte(225)
    t.Terrain(2) = raf.ReadUnsignedByte(226)
    t.Terrain(3) = raf.ReadUnsignedByte(227)
    '  f32   sTyreY[4];                    // 228
    t.TyreY(0) = raf.ReadFloat(228)
    t.TyreY(1) = raf.ReadFloat(232)
    t.TyreY(2) = raf.ReadFloat(236)
    t.TyreY(3) = raf.ReadFloat(240)

    '  f32   sTyreRPS[4];                  // 244
    t.TyreRPS(0) = raf.ReadFloat(244)
    t.TyreRPS(1) = raf.ReadFloat(248)
    t.TyreRPS(2) = raf.ReadFloat(252)
    t.TyreRPS(3) = raf.ReadFloat(256)
    '  f32   sTyreSlipSpeed[4];            // 260
    t.TyreSlipSpeed(0) = raf.ReadFloat(260)
    t.TyreSlipSpeed(1) = raf.ReadFloat(264)
    t.TyreSlipSpeed(2) = raf.ReadFloat(268)
    t.TyreSlipSpeed(3) = raf.ReadFloat(272)
    '  u8    sTyreTemp[4];                 // 276
    t.TyreTemp(0) = raf.ReadUnsignedByte(276)
    t.TyreTemp(1) = raf.ReadUnsignedByte(277)
    t.TyreTemp(2) = raf.ReadUnsignedByte(278)
    t.TyreTemp(3) = raf.ReadUnsignedByte(279)
    '  u8    sTyreGrip[4];                 // 280
    t.TyreGrip(0) = raf.ReadUnsignedByte(280)
    t.TyreGrip(1) = raf.ReadUnsignedByte(281)
    t.TyreGrip(2) = raf.ReadUnsignedByte(282)
    t.TyreGrip(3) = raf.ReadUnsignedByte(283)
    '  f32   sTyreHeightAboveGround[4];    // 284
    t.TyreHeightAboveGround(0) = raf.ReadFloat(284)
    t.TyreHeightAboveGround(1) = raf.ReadFloat(288)
    t.TyreHeightAboveGround(2) = raf.ReadFloat(292)
    t.TyreHeightAboveGround(3) = raf.ReadFloat(296)
    '  f32   sTyreLateralStiffness[4];     // 300
    t.TyreLateralStiffness(0) = raf.ReadFloat(300)
    t.TyreLateralStiffness(1) = raf.ReadFloat(304)
    t.TyreLateralStiffness(2) = raf.ReadFloat(308)
    t.TyreLateralStiffness(3) = raf.ReadFloat(312)
    '  u8    sTyreWear[4];                 // 316
    t.TyreWear(0) = raf.ReadUnsignedByte(316)
    t.TyreWear(1) = raf.ReadUnsignedByte(317)
    t.TyreWear(2) = raf.ReadUnsignedByte(318)
    t.TyreWear(3) = raf.ReadUnsignedByte(319)
    '  u8    sBrakeDamage[4];              // 320
    t.BrakeDamage(0) = raf.ReadUnsignedByte(320)
    t.BrakeDamage(1) = raf.ReadUnsignedByte(321)
    t.BrakeDamage(2) = raf.ReadUnsignedByte(322)
    t.BrakeDamage(3) = raf.ReadUnsignedByte(323)
    '  u8    sSuspensionDamage[4];         // 324
    t.SuspensionDamage(0) = raf.ReadUnsignedByte(324)
    t.SuspensionDamage(1) = raf.ReadUnsignedByte(325)
    t.SuspensionDamage(2) = raf.ReadUnsignedByte(326)
    t.SuspensionDamage(3) = raf.ReadUnsignedByte(327)
    '  s16   sBrakeTempCelsius[4];         // 328
    t.BrakeTempCelsius(0) = raf.ReadShort(328)
    t.BrakeTempCelsius(1) = raf.ReadShort(330)
    t.BrakeTempCelsius(2) = raf.ReadShort(332)
    t.BrakeTempCelsius(3) = raf.ReadShort(334)
    '  u16   sTyreTreadTemp[4];            // 336
    t.TyreTreadTemp(0) = raf.ReadShort(336)
    t.TyreTreadTemp(1) = raf.ReadShort(338)
    t.TyreTreadTemp(2) = raf.ReadShort(340)
    t.TyreTreadTemp(3) = raf.ReadShort(342)
    '  u16   sTyreLayerTemp[4];            // 344
    t.TyreLayerTemp(0) = raf.ReadShort(344)
    t.TyreLayerTemp(1) = raf.ReadShort(346)
    t.TyreLayerTemp(2) = raf.ReadShort(348)
    t.TyreLayerTemp(3) = raf.ReadShort(350)
    '  u16   sTyreCarcassTemp[4];          // 352
    t.TyreCarCassTemp(0) = raf.ReadShort(352)
    t.TyreCarCassTemp(1) = raf.ReadShort(354)
    t.TyreCarCassTemp(2) = raf.ReadShort(356)
    t.TyreCarCassTemp(3) = raf.ReadShort(358)
    '  u16   sTyreRimTemp[4];              // 360
    t.TyreRimTemp(0) = raf.ReadShort(360)
    t.TyreRimTemp(1) = raf.ReadShort(362)
    t.TyreRimTemp(2) = raf.ReadShort(364)
    t.TyreRimTemp(3) = raf.ReadShort(366)
    '  u16   sTyreInternalAirTemp[4];      // 368
    t.TyreInternalAirTemp(0) = raf.ReadShort(368)
    t.TyreInternalAirTemp(1) = raf.ReadShort(370)
    t.TyreInternalAirTemp(2) = raf.ReadShort(372)
    t.TyreInternalAirTemp(3) = raf.ReadShort(374)
    '  f32   sWheelLocalPositionY[4];      // 376
    't.WheelLocalPositionY(0) = raf.ReadFloat(376)
    't.WheelLocalPositionY(1) = raf.ReadFloat(380)
    't.WheelLocalPositionY(2) = raf.ReadFloat(384)
    't.WheelLocalPositionY(3) = raf.ReadFloat(388)
    '  f32   sRideHeight[4];               // 392
    t.RideHeight(0) = raf.ReadFloat(392)
    t.RideHeight(1) = raf.ReadFloat(396)
    t.RideHeight(2) = raf.ReadFloat(400)
    t.RideHeight(3) = raf.ReadFloat(404)
    '  f32   sSuspensionTravel[4];         // 408
    t.SuspensionTravel(0) = raf.ReadFloat(408)
    t.SuspensionTravel(1) = raf.ReadFloat(412)
    t.SuspensionTravel(2) = raf.ReadFloat(416)
    t.SuspensionTravel(3) = raf.ReadFloat(420)
    '  f32   sSuspensionVelocity[4];       // 424
    t.SuspensionVelocity(0) = raf.ReadFloat(424)
    t.SuspensionVelocity(1) = raf.ReadFloat(428)
    t.SuspensionVelocity(2) = raf.ReadFloat(432)
    t.SuspensionVelocity(3) = raf.ReadFloat(436)
    '  u16   sAirPressure[4];              // 440
    t.AirPressure(0) = raf.ReadShort(440)
    t.AirPressure(1) = raf.ReadShort(442)
    t.AirPressure(2) = raf.ReadShort(444)
    t.AirPressure(3) = raf.ReadShort(446)
    '
    '  // Extras
    '  f32   sEngineSpeed;                 // 448
    t.EngineSpeed = raf.ReadFloat(448)
    '  f32   sEngineTorque;                // 452
    t.EngineTorque = raf.ReadFloat(452)
    '
    '  // Car damage
    '  u8    sAeroDamage;                  // 456
    t.AeroDamage = raf.ReadUnsignedByte(456)
    '  u8    sEngineDamage;                // 457
    t.EngineDamage = raf.ReadUnsignedByte(457)
    '
    '  // Weather
    '  s8    sAmbientTemperature;          // 458
    t.AmbientTemperature = raf.ReadSignedByte(458)
    '  s8    sTrackTemperature;            // 459
    t.TrackTemperature = raf.ReadSignedByte(459)
    '  u8    sRainDensity;                 // 460
    t.RainDensity = raf.ReadUnSignedByte(460)
    '  s8    sWindSpeed;                   // 461
    t.WindSpeed = raf.ReadSignedByte(461)
    '  s8    sWindDirectionX;              // 462
    t.WindDirectionX = raf.ReadSignedByte(462)
    '  s8    sWindDirectionY;              // 463
    t.WindDirectionY = raf.ReadSignedByte(463)
    '
    Dim driverpos(56) As ParticipantInfo
    For i = 0 To 55
        'Log("pos "&(464+(i*16)))
        'Log(raf.ReadsignedByte(464))
        'If  raf.ReadsignedByte(464) <> 0 Then
            Dim driver As ParticipantInfo
            driver.Initialize
            driver.WorldPosition(0) = raf.ReadShort(464+(i*16))
            driver.WorldPosition(1) = raf.ReadShort(466+(i*16))
            driver.WorldPosition(2) = raf.ReadShort(468+(i*16))
            driver.CurrentLapDistance = raf.ReadShort(470+(i*16))
            driver.RacePosition = raf.ReadUnsignedByte(472+(i*16))
            driver.LapsCompleted = raf.ReadUnsignedByte(473+(i*16))
            driver.CurrentLap = raf.ReadUnsignedByte(474+(i*16))
            driver.Sector = raf.ReadUnsignedByte(475+(i*16))
            driver.LastSectorTime = raf.ReadFloat(476+(i*16))
            driverpos(i) = driver       
        'End If
    Next
    t.Driver = driverpos
    '  sParticipantInfo sParticipantInfo[56];  // 464
    '                                      // 56*16=896
    '  f32   sTrackLength;                 // 1360
    t.TrackLength = raf.ReadFloat(1360)
    '  u8    sWings[2];                    // 1364
    t.Wings(0) = raf.ReadUnsignedByte(1364)
    t.Wings(1) = raf.ReadUnsignedByte(1365)
    '  u8    sDPad;                        // 1366               
    t.DPad = raf.ReadUnsignedByte(1366)
    '                                      // 1368    struct Is padded To
    '};

   


   Return t
End Sub
Private Sub ReadString(raf As RandomAccessFile, buffer() As Byte) As String
   raf.ReadBytes(buffer, 0, buffer.Length, raf.CurrentPosition)
   Return BytesToString(buffer, 0, buffer.Length, "utf8")
End Sub
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
Nice work, have you noticed more effort goes into games related programming than 'normal' applications lol.
 
Upvote 0
Top