private int readRawData(byte[] rawData) { // unpack the packet header manually before attempting to load into a struct uint packetNumber = BitConverter.ToUInt32(rawData, 0); uint categoryPacketNumber = BitConverter.ToUInt32(rawData, 4); int partialPacketIndexBytes = rawData[8]; int partialPacketNumber = rawData[9]; EUDPStreamerPacketHandlerType packetType = (EUDPStreamerPacketHandlerType)rawData[10]; int packetVersion = rawData[11]; int frameLength = 0; switch (packetType) { case EUDPStreamerPacketHandlerType.eCarPhysics: telemPacketCount++; if (telemPacketCount > packetCountAtStartOfNextRateCheck) { lastPacketRateEstimate = (int)((float)TimeSpan.TicksPerSecond * (float)(telemPacketCount - packetCountAtStartOfCurrentRateCheck) / (float)(DateTime.UtcNow.Ticks - ticksAtStartOfCurrentPacketRateCheck)); Console.WriteLine("Packet rate = " + lastPacketRateEstimate + "Hz, totals:" + "\rtelem = " + telemPacketCount + "\rraceDefinition = " + raceDefinitionPacketCount + "\rparticipants = " + participantsPacketCount + "\rtimings = " + timingsPacketCount + "\rgameState = " + gameStatePacketCount + "\rweather = " + weatherStatePacketCount + "\rvehicleNames = " + vehicleNamesPacketCount + "\rtimeStats = " + timeStatsPacketCount + "\rparticipantVehicleNames = " + participantVehicleNamesPacketCount + "\rin sequence = " + inSequenceTelemCount + " oos accepted = " + acceptedOutOfSequenceTelemCount + " oos rejected = " + discardedTelemCount); packetCountAtStartOfCurrentRateCheck = telemPacketCount; packetCountAtStartOfNextRateCheck = packetCountAtStartOfCurrentRateCheck + packetRateCheckInterval; ticksAtStartOfCurrentPacketRateCheck = DateTime.UtcNow.Ticks; } frameLength = UDPPacketSizes.telemetryPacketSize; Boolean sequenceCheckOK = isNextInSequence(packetNumber); if (sequenceCheckOK) { inSequenceTelemCount++; } if (strictPacketOrdering && !sequenceCheckOK) { discardedTelemCount++; } else { GCHandle telemHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sTelemetryData telem = (sTelemetryData)Marshal.PtrToStructure(telemHandle.AddrOfPinnedObject(), typeof(sTelemetryData)); if (sequenceCheckOK || !telemIsOutOfSequence(telem)) { buttonsState = ConvertBytesToBoolArray(telem.sDPad, telem.sJoyPad1, telem.sJoyPad2); lastSequenceNumberForTelemPacket = (int)packetNumber; workingGameState = StructHelper.MergeWithExistingState(workingGameState, telem); newSpotterData = true; } } finally { telemHandle.Free(); } } break; case EUDPStreamerPacketHandlerType.eRaceDefinition: raceDefinitionPacketCount++; frameLength = UDPPacketSizes.raceDataPacketSize; GCHandle raceDefHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sRaceData raceDefinition = (sRaceData)Marshal.PtrToStructure(raceDefHandle.AddrOfPinnedObject(), typeof(sRaceData)); workingGameState = StructHelper.MergeWithExistingState(workingGameState, raceDefinition); } finally { raceDefHandle.Free(); } break; case EUDPStreamerPacketHandlerType.eParticipants: participantsPacketCount++; frameLength = UDPPacketSizes.participantsDataPacketSize; GCHandle participantsHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sParticipantsData participants = (sParticipantsData)Marshal.PtrToStructure(participantsHandle.AddrOfPinnedObject(), typeof(sParticipantsData)); workingGameState = StructHelper.MergeWithExistingState(workingGameState, participants); } finally { participantsHandle.Free(); } break; case EUDPStreamerPacketHandlerType.eTimings: timingsPacketCount++; frameLength = UDPPacketSizes.timingsDataPacketSize; GCHandle timingsHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sTimingsData timings = (sTimingsData)Marshal.PtrToStructure(timingsHandle.AddrOfPinnedObject(), typeof(sTimingsData)); workingGameState = StructHelper.MergeWithExistingState(workingGameState, timings); } finally { timingsHandle.Free(); } break; case EUDPStreamerPacketHandlerType.eGameState: gameStatePacketCount++; frameLength = UDPPacketSizes.gameStateDataPacketSize; GCHandle gameStateHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sGameStateData gameState = (sGameStateData)Marshal.PtrToStructure(gameStateHandle.AddrOfPinnedObject(), typeof(sGameStateData)); workingGameState = StructHelper.MergeWithExistingState(workingGameState, gameState); } finally { gameStateHandle.Free(); } break; case EUDPStreamerPacketHandlerType.eWeatherState: weatherStatePacketCount++; Console.WriteLine("Got an undocumented and unsupported weather packet"); break; case EUDPStreamerPacketHandlerType.eVehicleNames: weatherStatePacketCount++; Console.WriteLine("Got an undocumented and unsupported vehicle names packet"); break; case EUDPStreamerPacketHandlerType.eTimeStats: participantsPacketCount++; frameLength = UDPPacketSizes.timeStatsPacketSize; GCHandle timeStatsHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sTimeStatsData timeStatsData = (sTimeStatsData)Marshal.PtrToStructure(timeStatsHandle.AddrOfPinnedObject(), typeof(sTimeStatsData)); workingGameState = StructHelper.MergeWithExistingState(workingGameState, timeStatsData); } finally { timeStatsHandle.Free(); } break; case EUDPStreamerPacketHandlerType.eParticipantVehicleNames: participantsPacketCount++; frameLength = UDPPacketSizes.participantVehicleNamesPacketSize; GCHandle vehNamesHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sParticipantVehicleNamesData participantVehicleNames = (sParticipantVehicleNamesData)Marshal.PtrToStructure(vehNamesHandle.AddrOfPinnedObject(), typeof(sParticipantVehicleNamesData)); workingGameState = StructHelper.MergeWithExistingState(workingGameState, participantVehicleNames); } finally { vehNamesHandle.Free(); } break; } return(frameLength); }
public static pCars2APIStruct MergeWithExistingState(pCars2APIStruct existingState, sParticipantsData participantsData) { if (existingState.mParticipantData == null) { existingState.mParticipantData = new pCars2APIParticipantStruct[32]; } int offset = (participantsData.mPartialPacketIndex - 1) * 16; // existingState is a struct, so any changes we make as we iterate this array will be done to a copy, not a reference for (int i = offset; i < offset + 16 && i < existingState.mParticipantData.Length; i++) { pCars2APIParticipantStruct existingParticipant = existingState.mParticipantData[i]; existingParticipant.mName = participantsData.sName[i - offset].nameByteArray; existingState.mParticipantData[i] = existingParticipant; } return(existingState); }