public static pCarsAPIStruct MergeWithExistingState(pCarsAPIStruct existingState, sTelemetryData udpTelemetryData) { existingState.hasNewPositionData = false; existingState.mGameState = (uint)udpTelemetryData.sGameSessionState & 7; existingState.mSessionState = (uint)udpTelemetryData.sGameSessionState >> 4; existingState.mRaceState = (uint)udpTelemetryData.sRaceStateFlags & 7; // Participant Info existingState.mViewedParticipantIndex = udpTelemetryData.sViewedParticipantIndex; existingState.mNumParticipants = udpTelemetryData.sNumParticipants; // 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; existingState.mLapsInEvent = udpTelemetryData.sLapsInEvent; existingState.mTrackLength = udpTelemetryData.sTrackLength; // Timing & Scoring existingState.mLapInvalidated = (udpTelemetryData.sRaceStateFlags >> 3 & 1) == 1; existingState.mSessionFastestLapTime = udpTelemetryData.sBestLapTime; existingState.mLastLapTime = udpTelemetryData.sLastLapTime; existingState.mCurrentTime = udpTelemetryData.sCurrentTime; existingState.mSplitTimeAhead = udpTelemetryData.sSplitTimeAhead; existingState.mSplitTimeBehind = udpTelemetryData.sSplitTimeBehind; existingState.mSplitTime = udpTelemetryData.sSplitTime; existingState.mEventTimeRemaining = udpTelemetryData.sEventTimeRemaining; existingState.mPersonalFastestLapTime = udpTelemetryData.sPersonalFastestLapTime; existingState.mWorldFastestLapTime = udpTelemetryData.sWorldFastestLapTime; existingState.mCurrentSector1Time = udpTelemetryData.sCurrentSector1Time; existingState.mCurrentSector2Time = udpTelemetryData.sCurrentSector2Time; existingState.mCurrentSector3Time = udpTelemetryData.sCurrentSector3Time; existingState.mSessionFastestSector1Time = udpTelemetryData.sFastestSector1Time; existingState.mSessionFastestSector2Time = udpTelemetryData.sFastestSector2Time; existingState.mSessionFastestSector3Time = udpTelemetryData.sFastestSector3Time; existingState.mPersonalFastestSector1Time = udpTelemetryData.sPersonalFastestSector1Time; existingState.mPersonalFastestSector2Time = udpTelemetryData.sPersonalFastestSector2Time; existingState.mPersonalFastestSector3Time = udpTelemetryData.sPersonalFastestSector3Time; existingState.mWorldFastestSector1Time = udpTelemetryData.sWorldFastestSector1Time; existingState.mWorldFastestSector2Time = udpTelemetryData.sWorldFastestSector2Time; existingState.mWorldFastestSector3Time = udpTelemetryData.sWorldFastestSector3Time; // Flags existingState.mHighestFlagColour = (uint)udpTelemetryData.sHighestFlag & 7; existingState.mHighestFlagReason = (uint)udpTelemetryData.sHighestFlag >> 3 & 3; // Pit Info existingState.mPitMode = (uint)udpTelemetryData.sPitModeSchedule & 7; existingState.mPitSchedule = (uint)udpTelemetryData.sPitModeSchedule >> 3 & 3; // 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.mRPM = udpTelemetryData.sRpm; 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.mAntiLockActive = (udpTelemetryData.sRaceStateFlags >> 4 & 1) == 1; existingState.mBoostActive = (udpTelemetryData.sRaceStateFlags >> 5 & 1) == 1; 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.mTyreSlipSpeed = udpTelemetryData.sTyreSlipSpeed; existingState.mTyreTemp = toFloatArray(udpTelemetryData.sTyreTemp, 255); existingState.mTyreGrip = toFloatArray(udpTelemetryData.sTyreGrip, 255); existingState.mTyreHeightAboveGround = udpTelemetryData.sTyreHeightAboveGround; existingState.mTyreLateralStiffness = udpTelemetryData.sTyreLateralStiffness; existingState.mTyreWear = toFloatArray(udpTelemetryData.sTyreWear, 255); existingState.mBrakeDamage = toFloatArray(udpTelemetryData.sBrakeDamage, 255); existingState.mSuspensionDamage = toFloatArray(udpTelemetryData.sSuspensionDamage, 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); existingState.mWheelLocalPosition = udpTelemetryData.sWheelLocalPositionY; existingState.mRideHeight = udpTelemetryData.sRideHeight; existingState.mSuspensionTravel = udpTelemetryData.sSuspensionTravel; existingState.mSuspensionVelocity = udpTelemetryData.sSuspensionVelocity; existingState.mAirPressure = toFloatArray(udpTelemetryData.sAirPressure, 1); existingState.mEngineSpeed = udpTelemetryData.sEngineSpeed; existingState.mEngineTorque = udpTelemetryData.sEngineTorque; existingState.mEnforcedPitStopLap = (uint)udpTelemetryData.sEnforcedPitStopLap; // Car Damage existingState.mCrashState = udpTelemetryData.sCrashState; existingState.mAeroDamage = (float)udpTelemetryData.sAeroDamage / 255f; existingState.mEngineDamage = (float)udpTelemetryData.sEngineDamage / 255f; // Weather existingState.mAmbientTemperature = udpTelemetryData.sAmbientTemperature; existingState.mTrackTemperature = udpTelemetryData.sTrackTemperature; existingState.mRainDensity = (float)udpTelemetryData.sRainDensity / 255f; existingState.mWindSpeed = udpTelemetryData.sWindSpeed * 2; existingState.mWindDirectionX = (float)udpTelemetryData.sWindDirectionX / 127f; existingState.mWindDirectionY = (float)udpTelemetryData.sWindDirectionY / 127f; //existingState.mCloudBrightness = udpTelemetryData.sCloudBrightness / 255; if (existingState.mParticipantData == null) { existingState.mParticipantData = new pCarsAPIParticipantStruct[udpTelemetryData.sParticipantInfo.Count()]; } for (int i = 0; i < udpTelemetryData.sParticipantInfo.Count(); i++) { sParticipantInfo newPartInfo = udpTelemetryData.sParticipantInfo[i]; Boolean isActive = (newPartInfo.sRacePosition >> 7) == 1; pCarsAPIParticipantStruct existingPartInfo = existingState.mParticipantData[i]; existingPartInfo.mIsActive = isActive; if (isActive) { existingPartInfo.mCurrentLap = newPartInfo.sCurrentLap; existingPartInfo.mCurrentLapDistance = newPartInfo.sCurrentLapDistance; existingPartInfo.mLapsCompleted = (uint)newPartInfo.sLapsCompleted & 127; // TODO: there's a 'lapInvalidated' flag here but nowhere to put it in the existing struct Boolean lapInvalidated = (newPartInfo.sLapsCompleted >> 7) == 1; existingPartInfo.mRacePosition = (uint)newPartInfo.sRacePosition & 127; existingPartInfo.mCurrentSector = (uint)newPartInfo.sSector & 7; // and now the bit magic for the extra position precision... float[] newWorldPositions = toFloatArray(newPartInfo.sWorldPosition, 1); float xAdjustment = ((float)((uint)newPartInfo.sSector >> 3 & 3)) / 4f; float zAdjustment = ((float)((uint)newPartInfo.sSector >> 5 & 3)) / 4f; newWorldPositions[0] = newWorldPositions[0] + xAdjustment; newWorldPositions[2] = newWorldPositions[2] + zAdjustment; if (!existingState.hasNewPositionData && i != udpTelemetryData.sViewedParticipantIndex && (existingPartInfo.mWorldPosition == null || (newWorldPositions[0] != existingPartInfo.mWorldPosition[0] || newWorldPositions[2] != existingPartInfo.mWorldPosition[2]))) { existingState.hasNewPositionData = true; } existingPartInfo.mWorldPosition = newWorldPositions; // TODO: LastSectorTime is now in the UDP data, but there's no slot for this in the participants struct // existingPartInfo.mLastSectorTime = newPartInfo.sLastSectorTime; } else { existingPartInfo.mWorldPosition = new float[] { 0, 0, 0 }; } existingState.mParticipantData[i] = existingPartInfo; } // TODO: buttons return(existingState); }
private OpponentData createOpponentData(pCarsAPIParticipantStruct participantStruct, Boolean loadDriverName) { OpponentData opponentData = new OpponentData(); opponentData.DriverRawName = participantStruct.mName.Trim(); if (loadDriverName && CrewChief.enableDriverNames) { speechRecogniser.addNewOpponentName(opponentData.DriverRawName); } opponentData.Position = (int)participantStruct.mRacePosition; opponentData.UnFilteredPosition = opponentData.Position; opponentData.CompletedLaps = (int)participantStruct.mLapsCompleted; opponentData.CurrentSectorNumber = (int)participantStruct.mCurrentSector; opponentData.WorldPosition = new float[] { participantStruct.mWorldPosition[0], participantStruct.mWorldPosition[2] }; opponentData.DistanceRoundTrack = participantStruct.mCurrentLapDistance; return opponentData; }
public static pCarsAPIParticipantStruct getParticipantDataForName(pCarsAPIParticipantStruct[] pCarsAPIParticipantStructArray, String name, int index) { if (name != null && name.Length > 0) { foreach (pCarsAPIParticipantStruct data in pCarsAPIParticipantStructArray) { if (data.mName == name) { return data; } } } return pCarsAPIParticipantStructArray[index]; }
public static Tuple<int, pCarsAPIParticipantStruct> getPlayerDataStruct(pCarsAPIParticipantStruct[] pCarsAPIParticipantStructArray, int viewedParticipantIndex) { if (!getPlayerByName) { return new Tuple<int, pCarsAPIParticipantStruct>(viewedParticipantIndex, pCarsAPIParticipantStructArray[viewedParticipantIndex]); } else if (playerSteamId == null) { if (userSpecifiedSteamId == null || userSpecifiedSteamId.Length == 0) { // get the player ID from the first viewed participant the app 'sees' and use this for the remainder of the app's run time pCarsAPIParticipantStruct likelyParticipantData = pCarsAPIParticipantStructArray[viewedParticipantIndex]; playerSteamId = likelyParticipantData.mName; Console.WriteLine("Using player steam ID " + playerSteamId + " from the first reported viewed participant"); if (playerSteamId == null || playerSteamId.Length == 0) { getPlayerByName = false; Console.WriteLine("Player steam ID is not valid, falling back to viewedParticipantIndex"); } return new Tuple<int, pCarsAPIParticipantStruct>(viewedParticipantIndex, likelyParticipantData); } else { // use the steamID provided playerSteamId = userSpecifiedSteamId; } } for (int i=0; i<pCarsAPIParticipantStructArray.Length; i++) { if (pCarsAPIParticipantStructArray[i].mName == playerSteamId) { return new Tuple<int, pCarsAPIParticipantStruct> (i,pCarsAPIParticipantStructArray[i]); } } // no match in the block, so use the viewParticipantIndex getPlayerByName = false; return new Tuple<int, pCarsAPIParticipantStruct>(viewedParticipantIndex, pCarsAPIParticipantStructArray[viewedParticipantIndex]); }
private Boolean opponentIsRacing(float currentOpponentX, float currentOpponentY, float previousOpponentX, float previousOpponentY, pCarsAPIParticipantStruct playerData, pCarsAPIParticipantStruct previousPlayerData, float interval) { float deltaX = Math.Abs(currentOpponentX - playerData.mWorldPosition[0]); float deltaY = Math.Abs(currentOpponentY - playerData.mWorldPosition[2]); if (deltaX > trackWidth || deltaY > trackWidth) { return false; } float opponentVelocityX = Math.Abs(currentOpponentX - previousOpponentX) / interval; float opponentVelocityY = Math.Abs(currentOpponentY - previousOpponentY) / interval; // hard code this - if the opponent car is going < 4m/s on both axis we're not interested if (opponentVelocityX < 4 && opponentVelocityY < 4) { return false; } float playerVelocityX = Math.Abs(playerData.mWorldPosition[0] - previousPlayerData.mWorldPosition[0]) / interval; float playerVelocityY = Math.Abs(playerData.mWorldPosition[2] - previousPlayerData.mWorldPosition[2]) / interval; if (Math.Abs(playerVelocityX - opponentVelocityX) > maxClosingSpeed || Math.Abs(playerVelocityY - opponentVelocityY) > maxClosingSpeed) { // Console.WriteLine("high closing speed: x = " + (playerVelocityX - opponentVelocityX) + " y = " + (playerVelocityY - opponentVelocityY)); return false; } return true; }