Example #1
0
        public static pCars2APIStruct MergeWithExistingState(pCars2APIStruct existingState, sRaceData raceData)
        {
            Boolean isTimedSession = (raceData.sLapsTimeInEvent >> 15) == 1;
            int     sessionLength  = raceData.sLapsTimeInEvent / 2; // need the bottom bits of this short here - is it valid to just halve it?

            if (isTimedSession)
            {
                existingState.mLapsInEvent = (uint)sessionLength;
                existingState.mSessionLengthTimeFromGame = 0;
            }
            else
            {
                existingState.mSessionLengthTimeFromGame = 300 * (uint)sessionLength;  // *300 because this is in 5 minutes blocks
                existingState.mLapsInEvent = 0;
            }
            existingState.mTrackLength = raceData.sTrackLength;

            existingState.mWorldFastestLapTime        = raceData.sWorldFastestLapTime;
            existingState.mWorldFastestSector1Time    = raceData.sWorldFastestSector1Time;
            existingState.mWorldFastestSector2Time    = raceData.sWorldFastestSector2Time;
            existingState.mWorldFastestSector3Time    = raceData.sWorldFastestSector3Time;
            existingState.mPersonalFastestLapTime     = raceData.sPersonalFastestLapTime;
            existingState.mPersonalFastestSector1Time = raceData.sPersonalFastestSector1Time;
            existingState.mPersonalFastestSector2Time = raceData.sPersonalFastestSector2Time;
            existingState.mPersonalFastestSector3Time = raceData.sPersonalFastestSector3Time;

            existingState.mTrackLocation            = raceData.sTrackLocation;
            existingState.mTrackVariation           = raceData.sTrackVariation;
            existingState.mTranslatedTrackLocation  = raceData.sTranslatedTrackLocation;
            existingState.mTranslatedTrackVariation = raceData.sTranslatedTrackVariation;

            existingState.mEnforcedPitStopLap = raceData.sEnforcedPitStopLap;
            return(existingState);
        }
 public override Object ReadGameData(Boolean forSpotter)
 {
     CrewChiefV4.PCars2.PCars2SharedMemoryReader.PCars2StructWrapper structWrapper = new CrewChiefV4.PCars2.PCars2SharedMemoryReader.PCars2StructWrapper();
     structWrapper.ticksWhenRead = DateTime.UtcNow.Ticks;
     lock (this)
     {
         if (!initialised)
         {
             if (!InitialiseInternal())
             {
                 throw new GameDataReadException("Failed to initialise UDP client");
             }
         }
         previousGameState = StructHelper.Clone(currentGameState);
         currentGameState  = StructHelper.Clone(workingGameState);
         if (forSpotter)
         {
             newSpotterData = false;
         }
     }
     structWrapper.data = currentGameState;
     if (!forSpotter && dumpToFile && dataToDump != null && currentGameState.mTrackLocation != null &&
         currentGameState.mTrackLocation.Length > 0)
     {
         dataToDump.Add(structWrapper);
     }
     return(structWrapper);
 }
Example #3
0
 public static String getCarClassName(pCars2APIStruct shared, int participantIndex)
 {
     if (shared.mCarClassNames == null)
     {
         return("");
     }
     return(getNameFromBytes(shared.mCarClassNames.Skip(participantIndex * 64).Take(64).ToArray()));
 }
Example #4
0
 public static pCars2APIStruct MergeWithExistingState(pCars2APIStruct existingState, sVehicleClassNamesData vehicleClassNamesData)
 {
     for (int i = 0; i < 60; i++)    // why 60 class names here? Who knows
     {
         // we only have 20 bytes of data per name here
         // TODO: understand this data and map it
     }
     return(existingState);
 }
Example #5
0
        protected override float[] getWorldPositionOfDriverAtPosition(Object currentStateObj, int position)
        {
            pCars2APIStruct latestRawData = (pCars2APIStruct)currentStateObj;

            foreach (pCars2APIParticipantStruct participant in latestRawData.mParticipantData)
            {
                if (participant.mRacePosition == position)
                {
                    return(new float[] { participant.mWorldPosition[0], participant.mWorldPosition[2] });
                }
            }
            return(new float[] { 0, 0 });
        }
Example #6
0
 public static pCars2APIStruct MergeWithExistingState(pCars2APIStruct existingState, sGameStateData gameStateData)
 {
     existingState.mGameState          = (uint)gameStateData.mGameState & 7;
     existingState.mSessionState       = (uint)gameStateData.mGameState >> 4;
     existingState.mAmbientTemperature = gameStateData.sAmbientTemperature;
     existingState.mTrackTemperature   = gameStateData.sTrackTemperature;
     existingState.mRainDensity        = gameStateData.sRainDensity;
     existingState.mSnowDensity        = gameStateData.sSnowDensity;
     existingState.mWindSpeed          = gameStateData.sWindSpeed;
     existingState.mWindDirectionX     = gameStateData.sWindDirectionX;
     existingState.mWindDirectionY     = gameStateData.sWindDirectionY;
     return(existingState);
 }
 public override Object ReadGameData(Boolean forSpotter)
 {
     lock (this)
     {
         pCars2APIStruct _pcarsapistruct = new pCars2APIStruct();
         if (!initialised)
         {
             if (!InitialiseInternal())
             {
                 throw new GameDataReadException("Failed to initialise shared memory");
             }
         }
         try
         {
             int retries = -1;
             do
             {
                 retries++;
                 using (var sharedMemoryStreamView = memoryMappedFile.CreateViewStream())
                 {
                     BinaryReader _SharedMemoryStream = new BinaryReader(sharedMemoryStreamView);
                     sharedMemoryReadBuffer = _SharedMemoryStream.ReadBytes(sharedmemorysize);
                     GCHandle handle = GCHandle.Alloc(sharedMemoryReadBuffer, GCHandleType.Pinned);
                     try
                     {
                         _pcarsapistruct = (pCars2APIStruct)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(pCars2APIStruct));
                     }
                     finally
                     {
                         handle.Free();
                     }
                 }
             } while (_pcarsapistruct.mSequenceNumber % 2 != 0);
             tornFramesCount += retries;
             PCars2StructWrapper structWrapper = new PCars2StructWrapper();
             structWrapper.ticksWhenRead = DateTime.UtcNow.Ticks;
             structWrapper.data          = _pcarsapistruct;
             if (!forSpotter && dumpToFile && dataToDump != null && _pcarsapistruct.mTrackLocation != null &&
                 _pcarsapistruct.mTrackLocation.Length > 0)
             {
                 dataToDump.Add(structWrapper);
             }
             return(structWrapper);
         }
         catch (Exception ex)
         {
             throw new GameDataReadException(ex.Message, ex);
         }
     }
 }
Example #8
0
        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);
        }
Example #9
0
        // For double-file manual rolling starts. Will only work when the cars are all nicely settled on the grid - preferably
        // when the game thinks the race has just started
        public override Tuple <GridSide, Dictionary <int, GridSide> > getGridSide(Object currentStateObj)
        {
            CrewChiefV4.PCars2.PCars2SharedMemoryReader.PCars2StructWrapper currentWrapper = (CrewChiefV4.PCars2.PCars2SharedMemoryReader.PCars2StructWrapper)currentStateObj;
            pCars2APIStruct            latestRawData  = currentWrapper.data;
            int                        playerIndex    = PCars2GameStateMapper.getPlayerIndex(latestRawData);
            pCars2APIParticipantStruct playerData     = latestRawData.mParticipantData[playerIndex];
            float                      playerRotation = latestRawData.mOrientation[1];

            if (playerRotation < 0)
            {
                playerRotation = (float)(2 * Math.PI) + playerRotation;
            }
            playerRotation = (float)(2 * Math.PI) - playerRotation;
            float playerXPosition        = playerData.mWorldPosition[0];
            float playerZPosition        = playerData.mWorldPosition[2];
            int   playerStartingPosition = (int)playerData.mRacePosition;
            int   numCars = latestRawData.mNumParticipants;

            return(getGridSideInternal(latestRawData, playerRotation, playerXPosition, playerZPosition, playerStartingPosition, numCars));
        }
Example #10
0
        public static pCars2APIStruct MergeWithExistingState(pCars2APIStruct existingState, sParticipantVehicleNamesData participantVehicleNamesData)
        {
            int offset = (participantVehicleNamesData.mPartialPacketIndex - 1) * 16;

            if (existingState.mCarNames == null)
            {
                existingState.mCarNames = new byte[64 * 64];
            }
            for (int i = 0; i < 16; i++)
            {
                ushort index       = participantVehicleNamesData.sVehicles[i].sIndex;
                uint   classIndex  = participantVehicleNamesData.sVehicles[i].sClass;
                byte[] name        = participantVehicleNamesData.sVehicles[i].sName;
                int    start       = (offset + i) * 64;
                int    end         = start + 64;
                int    sourceIndex = 0;
                for (int j = start; j < end; j++)
                {
                    existingState.mCarNames[j] = name[sourceIndex];
                    sourceIndex++;
                }
            }
            return(existingState);
        }
Example #11
0
 public static pCars2APIStruct MergeWithExistingState(pCars2APIStruct existingState, sTimeStatsData timeStatsData)
 {
     float[] lastSectorTimes = new float[32];
     if (existingState.mFastestLapTimes == null)
     {
         existingState.mFastestLapTimes = new float[32];
     }
     if (existingState.mFastestSector1Times == null)
     {
         existingState.mFastestSector1Times = new float[32];
     }
     if (existingState.mFastestSector2Times == null)
     {
         existingState.mFastestSector2Times = new float[32];
     }
     if (existingState.mFastestSector3Times == null)
     {
         existingState.mFastestSector3Times = new float[32];
     }
     for (int i = 0; i < 32; i++)
     {
         sParticipantStatsInfo participantInfo = timeStatsData.sStats.sParticipants[i];
         existingState.mFastestLapTimes[i]     = participantInfo.sFastestLapTime;
         existingState.mFastestSector1Times[i] = participantInfo.sFastestSector1Time;
         existingState.mFastestSector2Times[i] = participantInfo.sFastestSector2Time;
         existingState.mFastestSector3Times[i] = participantInfo.sFastestSector3Time;
         existingState.mLastLapTime            = participantInfo.sLastLapTime;
         lastSectorTimes[i] = participantInfo.sLastSectorTime;
         if (i == existingState.mViewedParticipantIndex)
         {
             existingState.mLastLapTime = participantInfo.sLastLapTime;
         }
     }
     existingState.lastSectorTimes = lastSectorTimes;
     return(existingState);
 }
        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);
        }
Example #13
0
        public override void trigger(Object lastStateObj, Object currentStateObj, GameStateData currentGameState)
        {
            if (paused)
            {
                return;
            }
            CrewChiefV4.PCars2.PCars2SharedMemoryReader.PCars2StructWrapper currentWrapper = (CrewChiefV4.PCars2.PCars2SharedMemoryReader.PCars2StructWrapper)currentStateObj;
            pCars2APIStruct currentState = currentWrapper.data;
            ePitMode        pitMode      = (ePitMode)currentState.mPitMode;
            eGameState      gameState    = (eGameState)currentState.mGameState;

            // game state is 3 for paused, 5 for replay. No idea what 4 is...
            if (pitMode != ePitMode.PIT_MODE_NONE ||
                gameState == eGameState.GAME_FRONT_END ||
                (gameState == eGameState.GAME_INGAME_PAUSED && !CrewChief.Debugging) ||
                gameState == eGameState.GAME_INGAME_REPLAY || gameState == eGameState.GAME_FRONT_END_REPLAY ||
                gameState == eGameState.GAME_EXITED)
            {
                // don't ignore the paused game updates if we're in debug mode
                return;
            }
            CrewChiefV4.PCars2.PCars2SharedMemoryReader.PCars2StructWrapper previousWrapper = (CrewChiefV4.PCars2.PCars2SharedMemoryReader.PCars2StructWrapper)lastStateObj;
            pCars2APIStruct lastState = previousWrapper.data;

            DateTime now      = new DateTime(currentWrapper.ticksWhenRead);
            float    interval = (float)(((double)currentWrapper.ticksWhenRead - (double)previousWrapper.ticksWhenRead) / (double)TimeSpan.TicksPerSecond);

            if (currentState.mRaceState == (int)eRaceState.RACESTATE_RACING &&
                lastState.mRaceState != (int)eRaceState.RACESTATE_RACING)
            {
                timeToStartSpotting = now.Add(TimeSpan.FromSeconds(timeAfterRaceStartToActivate));
            }
            // this check looks a bit funky... whe we start a practice session, the raceState is not_started
            // until we cross the line for the first time. Which is retarded really.
            if (currentState.mRaceState == (int)eRaceState.RACESTATE_INVALID || now < timeToStartSpotting ||
                (currentState.mSessionState == (int)eSessionState.SESSION_RACE && currentState.mRaceState == (int)eRaceState.RACESTATE_NOT_STARTED))
            {
                return;
            }

            if (enabled && currentState.mNumParticipants > 1 &&
                (enableSpotterInTimetrial || currentState.mSessionState != (uint)eSessionState.SESSION_TIME_ATTACK))
            {
                int playerIndex = PCars2GameStateMapper.getPlayerIndex(currentState);
                if (playerIndex != currentState.mViewedParticipantIndex)
                {
                    return;
                }
                pCars2APIParticipantStruct playerData = currentState.mParticipantData[playerIndex];
                if (currentGameState != null && currentGameState.Now > nextCarClassCheckDue)
                {
                    var carClass = currentGameState.carClass;
                    if (carClass != null && !String.Equals(currentPlayerCarClassID, carClass.getClassIdentifier()))
                    {
                        // Retrieve and use user overridable spotter car length/width.
                        this.internalSpotter.setCarDimensions(GlobalBehaviourSettings.spotterVehicleLength, GlobalBehaviourSettings.spotterVehicleWidth);
                        this.currentPlayerCarClassID = carClass.getClassIdentifier();
                    }
                    nextCarClassCheckDue = currentGameState.Now.AddSeconds(5);
                }
                float[] currentPlayerPosition = new float[] { playerData.mWorldPosition[0], playerData.mWorldPosition[2] };

                List <float[]> currentOpponentPositions = new List <float[]>();
                float[]        playerVelocityData       = new float[3];
                playerVelocityData[0] = currentState.mSpeed;
                playerVelocityData[1] = currentState.mWorldVelocity[0];
                playerVelocityData[2] = currentState.mWorldVelocity[2];

                positionsFilledForThisTick.Clear();
                positionsFilledForThisTick.Add(playerData.mRacePosition);
                for (int i = 0; i < currentState.mParticipantData.Count(); i++)
                {
                    if (i == playerIndex)
                    {
                        continue;
                    }
                    pCars2APIParticipantStruct opponentData = currentState.mParticipantData[i];
                    if (opponentData.mIsActive && !positionsFilledForThisTick.Contains(opponentData.mRacePosition))
                    {
                        float[] currentPositions = new float[] { opponentData.mWorldPosition[0], opponentData.mWorldPosition[2] };
                        currentOpponentPositions.Add(currentPositions);
                        positionsFilledForThisTick.Add(opponentData.mRacePosition);
                    }
                }
                if (currentOpponentPositions.Count() > 0)
                {
                    float playerRotation = currentState.mOrientation[1];
                    if (playerRotation < 0)
                    {
                        playerRotation = playerRotation * -1;
                    }
                    else
                    {
                        playerRotation = twoPi - playerRotation;
                    }
                    internalSpotter.triggerInternal(playerRotation, currentPlayerPosition, playerVelocityData, currentOpponentPositions);
                }
            }
        }
Example #14
0
        public static pCars2APIStruct MergeWithExistingState(pCars2APIStruct existingState, sTelemetryData udpTelemetryData)
        {
            // Participant Info
            existingState.mViewedParticipantIndex = udpTelemetryData.sViewedParticipantIndex;

            // Unfiltered Input
            existingState.mUnfilteredThrottle = (float)udpTelemetryData.sUnfilteredThrottle / 255f;
            existingState.mUnfilteredBrake    = (float)udpTelemetryData.sUnfilteredBrake / 255f;
            existingState.mUnfilteredSteering = (float)udpTelemetryData.sUnfilteredSteering / 127f;
            existingState.mUnfilteredClutch   = (float)udpTelemetryData.sUnfilteredClutch / 255f;

            // Car State
            existingState.mCarFlags         = udpTelemetryData.sCarFlags;
            existingState.mOilTempCelsius   = udpTelemetryData.sOilTempCelsius;
            existingState.mOilPressureKPa   = udpTelemetryData.sOilPressureKPa;
            existingState.mWaterTempCelsius = udpTelemetryData.sWaterTempCelsius;
            existingState.mWaterPressureKPa = udpTelemetryData.sWaterPressureKpa;
            existingState.mFuelPressureKPa  = udpTelemetryData.sFuelPressureKpa;
            existingState.mFuelLevel        = udpTelemetryData.sFuelLevel;
            existingState.mFuelCapacity     = udpTelemetryData.sFuelCapacity;
            existingState.mSpeed            = udpTelemetryData.sSpeed;
            existingState.mMaxRPM           = udpTelemetryData.sMaxRpm;
            existingState.mBrake            = (float)udpTelemetryData.sBrake / 255f;
            existingState.mThrottle         = (float)udpTelemetryData.sThrottle / 255f;
            existingState.mClutch           = (float)udpTelemetryData.sClutch / 255f;
            existingState.mSteering         = (float)udpTelemetryData.sSteering / 127f;
            existingState.mGear             = udpTelemetryData.sGearNumGears & 15;
            existingState.mNumGears         = udpTelemetryData.sGearNumGears >> 4;
            existingState.mOdometerKM       = udpTelemetryData.sOdometerKM;
            existingState.mBoostAmount      = udpTelemetryData.sBoostAmount;

            // Motion & Device Related
            existingState.mOrientation       = udpTelemetryData.sOrientation;
            existingState.mLocalVelocity     = udpTelemetryData.sLocalVelocity;
            existingState.mWorldVelocity     = udpTelemetryData.sWorldVelocity;
            existingState.mAngularVelocity   = udpTelemetryData.sAngularVelocity;
            existingState.mLocalAcceleration = udpTelemetryData.sLocalAcceleration;
            existingState.mWorldAcceleration = udpTelemetryData.sWorldAcceleration;
            existingState.mExtentsCentre     = udpTelemetryData.sExtentsCentre;


            existingState.mTyreFlags             = toUIntArray(udpTelemetryData.sTyreFlags);
            existingState.mTerrain               = toUIntArray(udpTelemetryData.sTerrain);
            existingState.mTyreY                 = udpTelemetryData.sTyreY;
            existingState.mTyreRPS               = udpTelemetryData.sTyreRPS;
            existingState.mTyreTemp              = toFloatArray(udpTelemetryData.sTyreTemp, 255);
            existingState.mTyreHeightAboveGround = udpTelemetryData.sTyreHeightAboveGround;
            existingState.mTyreWear              = toFloatArray(udpTelemetryData.sTyreWear, 255);
            existingState.mBrakeTempCelsius      = toFloatArray(udpTelemetryData.sBrakeTempCelsius, 1);
            existingState.mTyreTreadTemp         = toFloatArray(udpTelemetryData.sTyreTreadTemp, 1);
            existingState.mTyreLayerTemp         = toFloatArray(udpTelemetryData.sTyreLayerTemp, 1);
            existingState.mTyreCarcassTemp       = toFloatArray(udpTelemetryData.sTyreCarcassTemp, 1);
            existingState.mTyreRimTemp           = toFloatArray(udpTelemetryData.sTyreRimTemp, 1);
            existingState.mTyreInternalAirTemp   = toFloatArray(udpTelemetryData.sTyreInternalAirTemp, 1);
            // IMO tyre temps aren't mapped here - they're in UDP but not MMF
            existingState.mWheelLocalPositionY  = udpTelemetryData.sWheelLocalPositionY;
            existingState.mRideHeight           = udpTelemetryData.sRideHeight;
            existingState.mSuspensionTravel     = udpTelemetryData.sSuspensionTravel;
            existingState.mSuspensionRideHeight = toFloatArray(udpTelemetryData.sSuspensionRideHeight, 1);
            existingState.mSuspensionVelocity   = udpTelemetryData.sSuspensionVelocity;
            existingState.mAirPressure          = toFloatArray(udpTelemetryData.sAirPressure, 1);

            existingState.mEngineSpeed  = udpTelemetryData.sEngineSpeed;
            existingState.mEngineTorque = udpTelemetryData.sEngineTorque;

            // Car Damage
            existingState.mCrashState       = udpTelemetryData.sCrashState;
            existingState.mAeroDamage       = (float)udpTelemetryData.sAeroDamage / 255f;
            existingState.mEngineDamage     = (float)udpTelemetryData.sEngineDamage / 255f;
            existingState.mBrakeDamage      = toFloatArray(udpTelemetryData.sBrakeDamage, 255);
            existingState.mSuspensionDamage = toFloatArray(udpTelemetryData.sSuspensionDamage, 255);

            existingState.mWings = toFloatArray(udpTelemetryData.sWings, 1);

            existingState.mJoyPad1 = udpTelemetryData.sJoyPad1;
            existingState.mJoyPad2 = udpTelemetryData.sJoyPad2;
            existingState.mDPad    = udpTelemetryData.sDPad;

            // tyres
            existingState.mLFTyreCompoundName = udpTelemetryData.lfTyreCompound;
            existingState.mRFTyreCompoundName = udpTelemetryData.rfTyreCompound;
            existingState.mLRTyreCompoundName = udpTelemetryData.lrTyreCompound;
            existingState.mRRTyreCompoundName = udpTelemetryData.rrTyreCompound;

            return(existingState);
        }
Example #15
0
        public static pCars2APIStruct MergeWithExistingState(pCars2APIStruct existingState, sTimingsData timingsData)
        {
            existingState.mNumParticipants    = timingsData.sNumParticipants;
            existingState.mEventTimeRemaining = timingsData.sEventTimeRemaining;// time remaining, -1 for invalid time,  -1 - laps remaining in lap based races  --
            existingState.mSplitTimeAhead     = timingsData.sSplitTimeAhead;
            existingState.mSplitTimeBehind    = timingsData.sSplitTimeBehind;
            existingState.mSplitTime          = timingsData.sSplitTime; // what's this?
            if (existingState.mParticipantData == null)
            {
                existingState.mParticipantData = new pCars2APIParticipantStruct[32];
            }
            if (existingState.mRaceStates == null)
            {
                existingState.mRaceStates = new uint[32];
            }
            if (existingState.mLapsInvalidated == null)
            {
                existingState.mLapsInvalidated = new byte[32];
            }
            if (existingState.mPitModes == null)
            {
                existingState.mPitModes = new uint[32];
            }
            if (existingState.mCurrentSector1Times == null)
            {
                existingState.mCurrentSector1Times = new float[32];
            }
            if (existingState.mCurrentSector2Times == null)
            {
                existingState.mCurrentSector2Times = new float[32];
            }
            if (existingState.mCurrentSector3Times == null)
            {
                existingState.mCurrentSector3Times = new float[32];
            }
            for (int i = 0; i < existingState.mParticipantData.Length; i++)
            {
                sParticipantInfo newParticipantInfo = timingsData.sParticipants[i];
                Boolean          isHuman            = (newParticipantInfo.sCarIndex >> 7) == 1;
                uint             carIndex           = (uint)newParticipantInfo.sCarIndex & 127;

                Boolean isActive = (newParticipantInfo.sRacePosition >> 7) == 1;
                pCars2APIParticipantStruct existingPartInfo = existingState.mParticipantData[i];

                if (isActive)
                {
                    existingPartInfo.mIsActive = i < existingState.mNumParticipants;

                    existingPartInfo.mCurrentLap = newParticipantInfo.sCurrentLap;
                    // is this safe?:
                    existingPartInfo.mLapsCompleted      = existingPartInfo.mCurrentLap - 1;
                    existingPartInfo.mCurrentLapDistance = newParticipantInfo.sCurrentLapDistance;
                    existingPartInfo.mRacePosition       = (uint)newParticipantInfo.sRacePosition & 127;
                    existingPartInfo.mCurrentSector      = newParticipantInfo.sSector & 7;

                    // err... laps completed is missing?
                    // existingPartInfo.mLapsCompleted = (uint)newParticipantInfo.sLapsCompleted & 127;
                    byte lapInvalidated = (byte)(newParticipantInfo.sRaceState >> 7);
                    existingState.mRaceStates[i] = (uint)newParticipantInfo.sRaceState & 127;
                    if (i == existingState.mViewedParticipantIndex)
                    {
                        existingState.mRaceState = existingState.mRaceStates[i];
                    }
                    existingState.mLapsInvalidated[i]    = lapInvalidated;
                    existingState.mPitModes[i]           = (uint)newParticipantInfo.sPitModeSchedule & 28;
                    existingState.mPitSchedules[i]       = (uint)newParticipantInfo.sPitModeSchedule & 3;
                    existingState.mHighestFlagColours[i] = (uint)newParticipantInfo.sHighestFlag & 28;
                    existingState.mHighestFlagReasons[i] = (uint)newParticipantInfo.sHighestFlag & 3;
                    // no obvious slot in MMF for currentTime - do we need it if we have currentsectortime for S3?
                    if (existingPartInfo.mCurrentSector == 1)
                    {
                        existingState.mCurrentSector1Times[i] = newParticipantInfo.sCurrentSectorTime;
                    }
                    if (existingPartInfo.mCurrentSector == 2)
                    {
                        existingState.mCurrentSector2Times[i] = newParticipantInfo.sCurrentSectorTime;
                    }
                    if (existingPartInfo.mCurrentSector == 3)
                    {
                        existingState.mCurrentSector3Times[i] = newParticipantInfo.sCurrentSectorTime;
                    }

                    // and now the bit magic for the extra position precision...
                    float[] newWorldPositions = toFloatArray(newParticipantInfo.sWorldPosition, 1);
                    float   xAdjustment       = ((float)((uint)newParticipantInfo.sSector >> 6 & 3)) / 4f;
                    float   zAdjustment       = ((float)((uint)newParticipantInfo.sSector >> 4 & 3)) / 4f;

                    newWorldPositions[0]            = newWorldPositions[0] + xAdjustment;
                    newWorldPositions[2]            = newWorldPositions[2] + zAdjustment;
                    existingPartInfo.mWorldPosition = newWorldPositions;

                    if (i == existingState.mViewedParticipantIndex)
                    {
                        existingState.mLapInvalidated    = lapInvalidated == 1;
                        existingState.mHighestFlagColour = existingState.mHighestFlagColours[i];
                        existingState.mHighestFlagReason = existingState.mHighestFlagReasons[i];
                        existingState.mPitMode           = existingState.mPitModes[i];
                        existingState.mPitSchedule       = existingState.mPitSchedules[i];
                    }
                }
                else
                {
                    existingPartInfo.mWorldPosition = new float[] { 0, 0, 0 };
                    existingPartInfo.mIsActive      = false;
                }
                existingState.mParticipantData[i] = existingPartInfo;
            }
            return(existingState);
        }