public getOpponentKeyBehind ( System.Boolean useUnfilteredPosition ) : Object | ||
useUnfilteredPosition | System.Boolean | |
return | Object |
public GameStateData mapToGameStateData(Object memoryMappedFileStruct, GameStateData previousGameState) { pCarsAPIStruct shared = ((CrewChiefV3.PCars.PCarsSharedMemoryReader.PCarsStructWrapper)memoryMappedFileStruct).data; long ticks = ((CrewChiefV3.PCars.PCarsSharedMemoryReader.PCarsStructWrapper)memoryMappedFileStruct).ticksWhenRead; // game state is 3 for paused, 5 for replay. No idea what 4 is... if (shared.mGameState == (uint)eGameState.GAME_FRONT_END || (shared.mGameState == (uint)eGameState.GAME_INGAME_PAUSED && !System.Diagnostics.Debugger.IsAttached) || (shared.mGameState == (uint)eGameState.GAME_INGAME_PAUSED) || shared.mGameState == (uint)eGameState.GAME_VIEWING_REPLAY || shared.mGameState == (uint)eGameState.GAME_EXITED) { // don't ignore the paused game updates if we're in debug mode return previousGameState; } GameStateData currentGameState = new GameStateData(ticks); if (shared.mNumParticipants < 1 || shared.mTrackLength <= 0) { // Unusable data in the block // TODO: is this check sufficient? return null; } Tuple<int, pCarsAPIParticipantStruct> playerData = getPlayerDataStruct(shared.mParticipantData, shared.mViewedParticipantIndex); if (getPlayerByName && playerSteamId != shared.mParticipantData[shared.mViewedParticipantIndex].mName) { return null; } int playerDataIndex = playerData.Item1; pCarsAPIParticipantStruct viewedParticipant = playerData.Item2; NameValidator.validateName(viewedParticipant.mName); currentGameState.SessionData.CompletedLaps = (int)viewedParticipant.mLapsCompleted; currentGameState.SessionData.SectorNumber = (int)viewedParticipant.mCurrentSector; currentGameState.SessionData.Position = (int)viewedParticipant.mRacePosition; currentGameState.SessionData.UnFilteredPosition = (int)viewedParticipant.mRacePosition; currentGameState.SessionData.IsNewSector = previousGameState == null || viewedParticipant.mCurrentSector != previousGameState.SessionData.SectorNumber; // When in the pit lane, mCurrentLapDistance gets set to 0 when crossing the start line and *remains at 0* until some distance into the lap (about 300 metres) currentGameState.PositionAndMotionData.DistanceRoundTrack = viewedParticipant.mCurrentLapDistance; // previous session data to check if we've started an new session SessionPhase lastSessionPhase = SessionPhase.Unavailable; SessionType lastSessionType = SessionType.Unavailable; float lastSessionRunningTime = 0; int lastSessionLapsCompleted = 0; TrackDefinition lastSessionTrack = null; Boolean lastSessionHasFixedTime = false; int lastSessionNumberOfLaps = 0; float lastSessionRunTime = 0; float lastSessionTimeRemaining = 0; if (previousGameState != null) { lastSessionPhase = previousGameState.SessionData.SessionPhase; lastSessionType = previousGameState.SessionData.SessionType; lastSessionRunningTime = previousGameState.SessionData.SessionRunningTime; lastSessionHasFixedTime = previousGameState.SessionData.SessionHasFixedTime; lastSessionTrack = previousGameState.SessionData.TrackDefinition; lastSessionLapsCompleted = previousGameState.SessionData.CompletedLaps; lastSessionNumberOfLaps = previousGameState.SessionData.SessionNumberOfLaps; lastSessionRunTime = previousGameState.SessionData.SessionRunTime; lastSessionTimeRemaining = previousGameState.SessionData.SessionTimeRemaining; currentGameState.carClass = previousGameState.carClass; } if (currentGameState.carClass.carClassEnum == CarData.CarClassEnum.UNKNOWN_RACE) { CarData.CarClass newClass = CarData.getCarClassForPCarsClassName(shared.mCarClassName); if (newClass.carClassEnum != currentGameState.carClass.carClassEnum) { currentGameState.carClass = newClass; Console.WriteLine("Player is using car class " + currentGameState.carClass.carClassEnum + " (class name " + shared.mCarClassName + ")"); brakeTempThresholdsForPlayersCar = CarData.getBrakeTempThresholds(currentGameState.carClass, shared.mCarName); // no tyre data in the block so get the default tyre types for this car defaultTyreTypeForPlayersCar = CarData.getDefaultTyreType(currentGameState.carClass, shared.mCarName); } } // current session data currentGameState.SessionData.SessionType = mapToSessionType(shared); Boolean leaderHasFinished = previousGameState != null && previousGameState.SessionData.LeaderHasFinishedRace; currentGameState.SessionData.LeaderHasFinishedRace = leaderHasFinished; currentGameState.SessionData.IsDisqualified = shared.mRaceState == (int)eRaceState.RACESTATE_DISQUALIFIED; currentGameState.SessionData.SessionPhase = mapToSessionPhase(currentGameState.SessionData.SessionType, shared.mSessionState, shared.mRaceState, shared.mNumParticipants, leaderHasFinished, lastSessionPhase, lastSessionTimeRemaining, lastSessionRunTime); float sessionTimeRemaining = -1; int numberOfLapsInSession = (int)shared.mLapsInEvent; if (shared.mEventTimeRemaining > 0) { currentGameState.SessionData.SessionHasFixedTime = true; sessionTimeRemaining = shared.mEventTimeRemaining; } currentGameState.SessionData.TrackDefinition = TrackData.getTrackDefinition(shared.mTrackLocation + ":" + shared.mTrackVariation, shared.mTrackLength); // Console.WriteLine(lastSessionPhase + ", " + currentGameState.SessionData.SessionPhase + "; " + lastSessionType + ", " + currentGameState.SessionData.SessionType); // now check if this is a new session... Boolean raceRestarted = currentGameState.SessionData.SessionType == SessionType.Race && lastSessionPhase == SessionPhase.Green && currentGameState.SessionData.SessionPhase == SessionPhase.Countdown; if (raceRestarted || (currentGameState.SessionData.SessionType != SessionType.Unavailable && (lastSessionType != currentGameState.SessionData.SessionType || lastSessionHasFixedTime != currentGameState.SessionData.SessionHasFixedTime || lastSessionTrack == null || lastSessionTrack.name != currentGameState.SessionData.TrackDefinition.name || lastSessionLapsCompleted > currentGameState.SessionData.CompletedLaps || (numberOfLapsInSession > 0 && lastSessionNumberOfLaps > 0 && lastSessionNumberOfLaps != numberOfLapsInSession) || (sessionTimeRemaining > 0 && sessionTimeRemaining > lastSessionRunTime)))) { Console.WriteLine("New session, trigger..."); if (raceRestarted) { Console.WriteLine("Race restarted (green -> countdown)"); } if (lastSessionType != currentGameState.SessionData.SessionType) { Console.WriteLine("lastSessionType = " + lastSessionType + " currentGameState.SessionData.SessionType = " + currentGameState.SessionData.SessionType); } else if (lastSessionHasFixedTime != currentGameState.SessionData.SessionHasFixedTime) { Console.WriteLine("lastSessionHasFixedTime = " + lastSessionHasFixedTime + " currentGameState.SessionData.SessionHasFixedTime = " + currentGameState.SessionData.SessionHasFixedTime); } else if (lastSessionTrack != currentGameState.SessionData.TrackDefinition) { String lastTrackName = lastSessionTrack == null ? "unknown" : lastSessionTrack.name; String currentTrackName = currentGameState.SessionData.TrackDefinition == null ? "unknown" : currentGameState.SessionData.TrackDefinition.name; Console.WriteLine("lastSessionTrack = " + lastTrackName + " currentGameState.SessionData.Track = " + currentTrackName); } else if (lastSessionLapsCompleted > currentGameState.SessionData.CompletedLaps) { Console.WriteLine("lastSessionLapsCompleted = " + lastSessionLapsCompleted + " currentGameState.SessionData.CompletedLaps = " + currentGameState.SessionData.CompletedLaps); } else if (lastSessionNumberOfLaps != numberOfLapsInSession) { Console.WriteLine("lastSessionNumberOfLaps = " + lastSessionNumberOfLaps + " numberOfLapsInSession = "+ numberOfLapsInSession); } else if (sessionTimeRemaining > 0 && sessionTimeRemaining > lastSessionRunTime) { Console.WriteLine("sessionTimeRemaining = " + sessionTimeRemaining + " lastSessionRunTime = " + lastSessionRunTime); } currentGameState.SessionData.IsNewSession = true; currentGameState.SessionData.SessionNumberOfLaps = numberOfLapsInSession; currentGameState.SessionData.LeaderHasFinishedRace = false; currentGameState.SessionData.SessionStartTime = currentGameState.Now; currentGameState.SessionData.SessionStartPosition = (int)viewedParticipant.mRacePosition; if (currentGameState.SessionData.SessionHasFixedTime) { currentGameState.SessionData.SessionRunTime = sessionTimeRemaining; currentGameState.SessionData.SessionTimeRemaining = sessionTimeRemaining; if (currentGameState.SessionData.SessionRunTime == 0) { Console.WriteLine("Setting session run time to 0"); } Console.WriteLine("Time in this new session = " + sessionTimeRemaining); } currentGameState.SessionData.DriverRawName = viewedParticipant.mName; currentGameState.PitData.IsRefuellingAllowed = true; for (int i=0; i < shared.mParticipantData.Length; i++) { pCarsAPIParticipantStruct participantStruct = shared.mParticipantData[i]; if (i != playerDataIndex && participantStruct.mIsActive && participantStruct.mName != null && participantStruct.mName.Length > 0) { if (!currentGameState.OpponentData.ContainsKey(participantStruct.mName)) { currentGameState.OpponentData.Add(participantStruct.mName, createOpponentData(participantStruct, false)); } } } currentGameState.carClass = CarData.getCarClassForPCarsClassName(shared.mCarClassName); Console.WriteLine("Player is using car class " + currentGameState.carClass.carClassEnum + " (class name " + shared.mCarClassName + ")"); brakeTempThresholdsForPlayersCar = CarData.getBrakeTempThresholds(currentGameState.carClass, shared.mCarName); // no tyre data in the block so get the default tyre types for this car defaultTyreTypeForPlayersCar = CarData.getDefaultTyreType(currentGameState.carClass, shared.mCarName); } else { Boolean justGoneGreen = false; if (lastSessionPhase != currentGameState.SessionData.SessionPhase) { if (currentGameState.SessionData.SessionPhase == SessionPhase.Green) { justGoneGreen = true; // just gone green, so get the session data if (currentGameState.SessionData.SessionType == SessionType.Race) { if (currentGameState.SessionData.SessionHasFixedTime) { currentGameState.SessionData.SessionRunTime = sessionTimeRemaining; currentGameState.SessionData.SessionTimeRemaining = sessionTimeRemaining; if (currentGameState.SessionData.SessionRunTime == 0) { Console.WriteLine("Setting session run time to 0"); } } currentGameState.SessionData.SessionStartTime = currentGameState.Now; currentGameState.SessionData.SessionNumberOfLaps = numberOfLapsInSession; currentGameState.SessionData.SessionStartPosition = (int)viewedParticipant.mRacePosition; } currentGameState.SessionData.LeaderHasFinishedRace = false; currentGameState.SessionData.NumCarsAtStartOfSession = shared.mNumParticipants; currentGameState.SessionData.TrackDefinition = TrackData.getTrackDefinition(shared.mTrackLocation + ":" + shared.mTrackVariation, shared.mTrackLength); currentGameState.carClass = CarData.getCarClassForPCarsClassName(shared.mCarClassName); Console.WriteLine("Player is using car class " + currentGameState.carClass.carClassEnum + " (class name " + shared.mCarClassName + ")"); brakeTempThresholdsForPlayersCar = CarData.getBrakeTempThresholds(currentGameState.carClass, shared.mCarName); // no tyre data in the block so get the default tyre types for this car defaultTyreTypeForPlayersCar = CarData.getDefaultTyreType(currentGameState.carClass, shared.mCarName); if (previousGameState != null) { currentGameState.OpponentData = previousGameState.OpponentData; currentGameState.PitData.IsRefuellingAllowed = previousGameState.PitData.IsRefuellingAllowed; if (currentGameState.SessionData.SessionType != SessionType.Race) { currentGameState.SessionData.SessionStartTime = previousGameState.SessionData.SessionStartTime; currentGameState.SessionData.SessionRunTime = previousGameState.SessionData.SessionRunTime; currentGameState.SessionData.SessionTimeRemaining = previousGameState.SessionData.SessionTimeRemaining; currentGameState.SessionData.SessionNumberOfLaps = previousGameState.SessionData.SessionNumberOfLaps; } } Console.WriteLine("Just gone green, session details..."); Console.WriteLine("SessionType " + currentGameState.SessionData.SessionType); Console.WriteLine("SessionPhase " + currentGameState.SessionData.SessionPhase); if (previousGameState != null) { Console.WriteLine("previous SessionPhase " + previousGameState.SessionData.SessionPhase); } Console.WriteLine("EventIndex " + currentGameState.SessionData.EventIndex); Console.WriteLine("SessionIteration " + currentGameState.SessionData.SessionIteration); Console.WriteLine("HasMandatoryPitStop " + currentGameState.PitData.HasMandatoryPitStop); Console.WriteLine("PitWindowStart " + currentGameState.PitData.PitWindowStart); Console.WriteLine("PitWindowEnd " + currentGameState.PitData.PitWindowEnd); Console.WriteLine("NumCarsAtStartOfSession " + currentGameState.SessionData.NumCarsAtStartOfSession); Console.WriteLine("SessionNumberOfLaps " + currentGameState.SessionData.SessionNumberOfLaps); Console.WriteLine("SessionRunTime " + currentGameState.SessionData.SessionRunTime); Console.WriteLine("SessionStartPosition " + currentGameState.SessionData.SessionStartPosition); Console.WriteLine("SessionStartTime " + currentGameState.SessionData.SessionStartTime); String trackName = currentGameState.SessionData.TrackDefinition == null ? "unknown" : currentGameState.SessionData.TrackDefinition.name; Console.WriteLine("TrackName " + trackName); } } // copy persistent data from the previous game state // if (!justGoneGreen && previousGameState != null) { currentGameState.SessionData.SessionStartTime = previousGameState.SessionData.SessionStartTime; currentGameState.SessionData.SessionRunTime = previousGameState.SessionData.SessionRunTime; currentGameState.SessionData.SessionNumberOfLaps = previousGameState.SessionData.SessionNumberOfLaps; currentGameState.SessionData.SessionStartPosition = previousGameState.SessionData.SessionStartPosition; currentGameState.SessionData.NumCarsAtStartOfSession = previousGameState.SessionData.NumCarsAtStartOfSession; currentGameState.SessionData.TrackDefinition = previousGameState.SessionData.TrackDefinition; currentGameState.SessionData.EventIndex = previousGameState.SessionData.EventIndex; currentGameState.SessionData.SessionIteration = previousGameState.SessionData.SessionIteration; currentGameState.OpponentData = previousGameState.OpponentData; currentGameState.PitData.PitWindowStart = previousGameState.PitData.PitWindowStart; currentGameState.PitData.PitWindowEnd = previousGameState.PitData.PitWindowEnd; currentGameState.PitData.HasMandatoryPitStop = previousGameState.PitData.HasMandatoryPitStop; currentGameState.PitData.HasMandatoryDriverChange = previousGameState.PitData.HasMandatoryDriverChange; currentGameState.PitData.HasMandatoryTyreChange = previousGameState.PitData.HasMandatoryTyreChange; currentGameState.PitData.MandatoryTyreChangeRequiredTyreType = previousGameState.PitData.MandatoryTyreChangeRequiredTyreType; currentGameState.PitData.IsRefuellingAllowed = previousGameState.PitData.IsRefuellingAllowed; currentGameState.PitData.MaxPermittedDistanceOnCurrentTyre = previousGameState.PitData.MaxPermittedDistanceOnCurrentTyre; currentGameState.PitData.MinPermittedDistanceOnCurrentTyre = previousGameState.PitData.MinPermittedDistanceOnCurrentTyre; currentGameState.PitData.OnInLap = previousGameState.PitData.OnInLap; currentGameState.PitData.OnOutLap = previousGameState.PitData.OnOutLap; // the other properties of PitData are updated each tick, and shouldn't be copied over here. Nasty... currentGameState.SessionData.SessionTimesAtEndOfSectors = previousGameState.SessionData.SessionTimesAtEndOfSectors; currentGameState.PenaltiesData.CutTrackWarnings = previousGameState.PenaltiesData.CutTrackWarnings; currentGameState.SessionData.formattedPlayerLapTimes = previousGameState.SessionData.formattedPlayerLapTimes; currentGameState.SessionData.PlayerLapTimeSessionBest = previousGameState.SessionData.PlayerLapTimeSessionBest; currentGameState.SessionData.OpponentsLapTimeSessionBestOverall = previousGameState.SessionData.OpponentsLapTimeSessionBestOverall; currentGameState.SessionData.OpponentsLapTimeSessionBestPlayerClass = previousGameState.SessionData.OpponentsLapTimeSessionBestPlayerClass; currentGameState.SessionData.OverallSessionBestLapTime = previousGameState.SessionData.OverallSessionBestLapTime; currentGameState.SessionData.PlayerClassSessionBestLapTime = previousGameState.SessionData.PlayerClassSessionBestLapTime; currentGameState.SessionData.GameTimeAtLastPositionFrontChange = previousGameState.SessionData.GameTimeAtLastPositionFrontChange; currentGameState.SessionData.GameTimeAtLastPositionBehindChange = previousGameState.SessionData.GameTimeAtLastPositionBehindChange; currentGameState.SessionData.LastSector1Time = previousGameState.SessionData.LastSector1Time; currentGameState.SessionData.LastSector2Time = previousGameState.SessionData.LastSector2Time; currentGameState.SessionData.LastSector3Time = previousGameState.SessionData.LastSector3Time; currentGameState.SessionData.PlayerBestSector1Time = previousGameState.SessionData.PlayerBestSector1Time; currentGameState.SessionData.PlayerBestSector2Time = previousGameState.SessionData.PlayerBestSector2Time; currentGameState.SessionData.PlayerBestSector3Time = previousGameState.SessionData.PlayerBestSector3Time; currentGameState.SessionData.PlayerBestLapSector1Time = previousGameState.SessionData.PlayerBestLapSector1Time; currentGameState.SessionData.PlayerBestLapSector2Time = previousGameState.SessionData.PlayerBestLapSector2Time; currentGameState.SessionData.PlayerBestLapSector3Time = previousGameState.SessionData.PlayerBestLapSector3Time; currentGameState.Conditions = previousGameState.Conditions; } } //------------------- Variable session data --------------------------- if (currentGameState.SessionData.SessionHasFixedTime) { currentGameState.SessionData.SessionRunningTime = currentGameState.SessionData.SessionRunTime - shared.mEventTimeRemaining; currentGameState.SessionData.SessionTimeRemaining = shared.mEventTimeRemaining; } else { currentGameState.SessionData.SessionRunningTime = (float)(currentGameState.Now - currentGameState.SessionData.SessionStartTime).TotalSeconds; } if (currentGameState.SessionData.IsNewSector) { if (currentGameState.SessionData.SectorNumber == 1) { currentGameState.SessionData.LapTimePreviousEstimateForInvalidLap = currentGameState.SessionData.SessionRunningTime - currentGameState.SessionData.SessionTimesAtEndOfSectors[3]; currentGameState.SessionData.SessionTimesAtEndOfSectors[3] = currentGameState.SessionData.SessionRunningTime; currentGameState.SessionData.LastSector3Time = shared.mCurrentSector3Time; if (currentGameState.SessionData.LastSector3Time > 0 && (currentGameState.SessionData.PlayerBestSector3Time == -1 || currentGameState.SessionData.LastSector3Time < currentGameState.SessionData.PlayerBestSector3Time)) { currentGameState.SessionData.PlayerBestSector3Time = currentGameState.SessionData.LastSector3Time; } if (shared.mLastLapTime > 0 && (currentGameState.SessionData.PlayerLapTimeSessionBest == -1 || shared.mLastLapTime <= currentGameState.SessionData.PlayerLapTimeSessionBest)) { currentGameState.SessionData.PlayerBestLapSector1Time = currentGameState.SessionData.LastSector1Time; currentGameState.SessionData.PlayerBestLapSector2Time = currentGameState.SessionData.LastSector2Time; currentGameState.SessionData.PlayerBestLapSector3Time = currentGameState.SessionData.LastSector3Time; } } else if (currentGameState.SessionData.SectorNumber == 2) { currentGameState.SessionData.SessionTimesAtEndOfSectors[1] = currentGameState.SessionData.SessionRunningTime; currentGameState.SessionData.LastSector1Time = shared.mCurrentSector1Time; if (currentGameState.SessionData.LastSector1Time > 0 && (currentGameState.SessionData.PlayerBestSector1Time == -1 || currentGameState.SessionData.LastSector1Time < currentGameState.SessionData.PlayerBestSector1Time)) { currentGameState.SessionData.PlayerBestSector1Time = currentGameState.SessionData.LastSector1Time; } } if (currentGameState.SessionData.SectorNumber == 3) { currentGameState.SessionData.SessionTimesAtEndOfSectors[2] = currentGameState.SessionData.SessionRunningTime; currentGameState.SessionData.LastSector2Time = shared.mCurrentSector2Time; if (currentGameState.SessionData.LastSector2Time > 0 && (currentGameState.SessionData.PlayerBestSector2Time == -1 || currentGameState.SessionData.LastSector2Time < currentGameState.SessionData.PlayerBestSector2Time)) { currentGameState.SessionData.PlayerBestSector2Time = currentGameState.SessionData.LastSector2Time; } } } currentGameState.SessionData.Flag = mapToFlagEnum(shared.mHighestFlagColour); currentGameState.SessionData.NumCars = shared.mNumParticipants; currentGameState.SessionData.CurrentLapIsValid = !shared.mLapInvalidated; currentGameState.SessionData.IsNewLap = previousGameState == null || currentGameState.SessionData.CompletedLaps == previousGameState.SessionData.CompletedLaps + 1 || ((shared.mSessionState == (int)eSessionState.SESSION_PRACTICE || shared.mSessionState == (int)eSessionState.SESSION_QUALIFY || shared.mSessionState == (int)eSessionState.SESSION_TEST || shared.mSessionState == (int)eSessionState.SESSION_TIME_ATTACK) && previousGameState.SessionData.LapTimeCurrent == -1 && shared.mCurrentTime > 0); currentGameState.SessionData.IsRacingSameCarBehind = previousGameState != null && previousGameState.getOpponentKeyBehind(false) == currentGameState.getOpponentKeyBehind(false); currentGameState.SessionData.IsRacingSameCarInFront = previousGameState != null && previousGameState.getOpponentKeyInFront(false) == currentGameState.getOpponentKeyInFront(false); if (!currentGameState.SessionData.IsRacingSameCarInFront) { currentGameState.SessionData.GameTimeAtLastPositionFrontChange = currentGameState.SessionData.SessionRunningTime; } if (!currentGameState.SessionData.IsRacingSameCarBehind) { currentGameState.SessionData.GameTimeAtLastPositionBehindChange = currentGameState.SessionData.SessionRunningTime; } currentGameState.SessionData.LapTimeCurrent = shared.mCurrentTime; currentGameState.SessionData.TimeDeltaBehind = shared.mSplitTimeBehind; currentGameState.SessionData.TimeDeltaFront = shared.mSplitTimeAhead; // NOTE: the shared.mSessionFastestLapTime is JUST FOR THE PLAYER so the code below is not going to work: // currentGameState.SessionData.SessionFastestLapTimeFromGame = shared.mSessionFastestLapTime; // currentGameState.SessionData.SessionFastestLapTimeFromGamePlayerClass = shared.mSessionFastestLapTime; for (int i = 0; i < shared.mParticipantData.Length; i++) { if (i != playerDataIndex) { pCarsAPIParticipantStruct participantStruct = shared.mParticipantData[i]; if (participantStruct.mName != null && currentGameState.OpponentData.ContainsKey(participantStruct.mName)) { OpponentData currentOpponentData = currentGameState.OpponentData[participantStruct.mName]; if (currentOpponentData.IsActive && participantStruct.mIsActive) { if (previousGameState != null) { int previousOpponentSectorNumber = 1; int previousOpponentCompletedLaps = 0; int previousOpponentPosition = 0; Boolean previousOpponentIsEnteringPits = false; Boolean previousOpponentIsExitingPits = false; float[] previousOpponentWorldPosition = new float[] { 0, 0, 0 }; float previousOpponentSpeed = 0; OpponentData previousOpponentData = null; if (previousGameState.OpponentData.ContainsKey(participantStruct.mName)) { previousOpponentData = previousGameState.OpponentData[participantStruct.mName]; previousOpponentSectorNumber = previousOpponentData.CurrentSectorNumber; previousOpponentCompletedLaps = previousOpponentData.CompletedLaps; previousOpponentPosition = previousOpponentData.Position; previousOpponentIsEnteringPits = previousOpponentData.isEnteringPits(); previousOpponentIsExitingPits = previousOpponentData.isExitingPits(); previousOpponentWorldPosition = previousOpponentData.WorldPosition; previousOpponentSpeed = previousOpponentData.Speed; } int currentOpponentRacePosition = (int)participantStruct.mRacePosition; int currentOpponentLapsCompleted = (int)participantStruct.mLapsCompleted; int currentOpponentSector = (int)participantStruct.mCurrentSector; if (currentOpponentSector == 0) { currentOpponentSector = previousOpponentSectorNumber; } float currentOpponentLapDistance = participantStruct.mCurrentLapDistance; if (currentOpponentRacePosition == 1 && (currentGameState.SessionData.SessionNumberOfLaps > 0 && currentGameState.SessionData.SessionNumberOfLaps == currentOpponentLapsCompleted) || (currentGameState.SessionData.SessionRunTime > 0 && currentGameState.SessionData.SessionTimeRemaining < 1 && previousOpponentCompletedLaps < currentOpponentLapsCompleted)) { currentGameState.SessionData.LeaderHasFinishedRace = true; } if (currentOpponentRacePosition == 1 && previousOpponentPosition > 1) { currentGameState.SessionData.HasLeadChanged = true; } int opponentPositionAtSector3 = previousOpponentPosition; Boolean isEnteringPits = false; Boolean isLeavingPits = false; if (attemptPitDetection) { if (previousOpponentData != null && currentGameState.SessionData.SessionRunningTime > 30) { if (currentOpponentSector == 3) { if (previousOpponentSectorNumber == 2) { opponentPositionAtSector3 = currentOpponentRacePosition; } else if (!previousOpponentIsEnteringPits) { isEnteringPits = currentGameState.SessionData.TrackDefinition != null && currentGameState.SessionData.TrackDefinition.isAtPitEntry(participantStruct.mWorldPosition[0], participantStruct.mWorldPosition[2]); } else { isEnteringPits = previousOpponentIsEnteringPits; } } else if (currentOpponentSector == 1 && !previousOpponentIsExitingPits) { isLeavingPits = currentGameState.SessionData.TrackDefinition != null && currentGameState.SessionData.TrackDefinition.isAtPitExit(participantStruct.mWorldPosition[0], participantStruct.mWorldPosition[2]); } } if (isEnteringPits && !previousOpponentIsEnteringPits) { if (opponentPositionAtSector3 == 1) { Console.WriteLine("leader pitting, pos at sector 3 = " + opponentPositionAtSector3 + " current pos = " + currentOpponentRacePosition); currentGameState.PitData.LeaderIsPitting = true; currentGameState.PitData.OpponentForLeaderPitting = currentOpponentData; } if (currentGameState.SessionData.Position > 2 && opponentPositionAtSector3 == currentGameState.SessionData.Position - 1) { Console.WriteLine("car in front pitting, pos at sector 3 = " + opponentPositionAtSector3 + " current pos = " + currentOpponentRacePosition); currentGameState.PitData.CarInFrontIsPitting = true; currentGameState.PitData.OpponentForCarAheadPitting = currentOpponentData; } if (!currentGameState.isLast() && opponentPositionAtSector3 == currentGameState.SessionData.Position + 1) { Console.WriteLine("car behind pitting, pos at sector 3 = " + opponentPositionAtSector3 + " current pos = " + currentOpponentRacePosition); currentGameState.PitData.CarBehindIsPitting = true; currentGameState.PitData.OpponentForCarBehindPitting = currentOpponentData; } } } float secondsSinceLastUpdate = (float)new TimeSpan(currentGameState.Ticks - previousGameState.Ticks).TotalSeconds; upateOpponentData(currentOpponentData, currentOpponentRacePosition, currentOpponentLapsCompleted, currentOpponentSector, isEnteringPits || isLeavingPits, currentGameState.SessionData.SessionRunningTime, secondsSinceLastUpdate, new float[] { participantStruct.mWorldPosition[0], participantStruct.mWorldPosition[2] }, previousOpponentWorldPosition, previousOpponentSpeed, shared.mWorldFastestLapTime, participantStruct.mCurrentLapDistance, shared.mRainDensity == 1, shared.mAmbientTemperature, shared.mTrackTemperature); if (currentOpponentData.IsNewLap && currentOpponentData.CurrentBestLapTime > 0) { // the car class is always Unknown for PCars - it's not in the opponent data if (currentGameState.SessionData.OpponentsLapTimeSessionBestOverall == -1 || currentOpponentData.CurrentBestLapTime < currentGameState.SessionData.OpponentsLapTimeSessionBestOverall) { currentGameState.SessionData.OpponentsLapTimeSessionBestOverall = currentOpponentData.CurrentBestLapTime; currentGameState.SessionData.OpponentsLapTimeSessionBestPlayerClass = currentOpponentData.CurrentBestLapTime; if (currentGameState.SessionData.OverallSessionBestLapTime == -1 || currentGameState.SessionData.OverallSessionBestLapTime > currentOpponentData.CurrentBestLapTime) { currentGameState.SessionData.OverallSessionBestLapTime = currentOpponentData.CurrentBestLapTime; currentGameState.SessionData.PlayerClassSessionBestLapTime = currentOpponentData.CurrentBestLapTime; } } } } } else { currentOpponentData.IsActive = false; } } else { if (participantStruct.mIsActive && participantStruct.mName != null && participantStruct.mName.Length > 0) { Console.WriteLine("Creating opponent for name " + participantStruct.mName); currentGameState.OpponentData.Add(participantStruct.mName, createOpponentData(participantStruct, true)); } } } } currentGameState.SessionData.LapTimePrevious = shared.mLastLapTime; if (currentGameState.SessionData.IsNewLap) { currentGameState.SessionData.PreviousLapWasValid = previousGameState != null && previousGameState.SessionData.CurrentLapIsValid; currentGameState.SessionData.formattedPlayerLapTimes.Add(TimeSpan.FromSeconds(shared.mLastLapTime).ToString(@"mm\:ss\.fff")); } else if (previousGameState != null) { currentGameState.SessionData.PreviousLapWasValid = previousGameState.SessionData.PreviousLapWasValid; } if (currentGameState.SessionData.IsNewLap && currentGameState.SessionData.PreviousLapWasValid && currentGameState.SessionData.LapTimePrevious > 0) { if (currentGameState.SessionData.PlayerLapTimeSessionBest == -1 || currentGameState.SessionData.LapTimePrevious < currentGameState.SessionData.PlayerLapTimeSessionBest) { currentGameState.SessionData.PlayerLapTimeSessionBest = currentGameState.SessionData.LapTimePrevious; if (currentGameState.SessionData.OverallSessionBestLapTime == -1 || currentGameState.SessionData.LapTimePrevious < currentGameState.SessionData.OverallSessionBestLapTime) { currentGameState.SessionData.OverallSessionBestLapTime = currentGameState.SessionData.LapTimePrevious; } if (currentGameState.SessionData.PlayerClassSessionBestLapTime == -1 || currentGameState.SessionData.LapTimePrevious < currentGameState.SessionData.PlayerClassSessionBestLapTime) { currentGameState.SessionData.PlayerClassSessionBestLapTime = currentGameState.SessionData.LapTimePrevious; } } } currentGameState.PitData.InPitlane = shared.mPitMode == (int)ePitMode.PIT_MODE_DRIVING_INTO_PITS || shared.mPitMode == (int)ePitMode.PIT_MODE_IN_PIT || shared.mPitMode == (int)ePitMode.PIT_MODE_DRIVING_OUT_OF_PITS || shared.mPitMode == (int)ePitMode.PIT_MODE_IN_GARAGE; if (currentGameState.PitData.InPitlane) { // should we just use the sector number to check this? if (shared.mPitMode == (int)ePitMode.PIT_MODE_DRIVING_INTO_PITS) { currentGameState.PitData.OnInLap = true; currentGameState.PitData.OnOutLap = false; } else if (shared.mPitMode == (int)ePitMode.PIT_MODE_DRIVING_OUT_OF_PITS || shared.mPitMode == (int)ePitMode.PIT_MODE_IN_GARAGE) { currentGameState.PitData.OnInLap = false; currentGameState.PitData.OnOutLap = true; } } else if (currentGameState.SessionData.IsNewLap) { currentGameState.PitData.OnInLap = false; currentGameState.PitData.OnOutLap = false; } currentGameState.PitData.IsAtPitExit = previousGameState != null && currentGameState.PitData.OnOutLap && previousGameState.PitData.InPitlane && !currentGameState.PitData.InPitlane; currentGameState.PitData.HasRequestedPitStop = shared.mPitSchedule == (int)ePitSchedule.PIT_SCHEDULE_STANDARD; if (previousGameState != null && previousGameState.PitData.HasRequestedPitStop) { Console.WriteLine("Has requested pitstop"); } if (currentGameState.SessionData.SessionType == SessionType.Race && shared.mEnforcedPitStopLap > 0) { currentGameState.PitData.HasMandatoryPitStop = true; currentGameState.PitData.PitWindowStart = (int) shared.mEnforcedPitStopLap; currentGameState.PitData.PitWindow = mapToPitWindow(currentGameState, shared.mPitSchedule, shared.mPitMode); currentGameState.PitData.IsMakingMandatoryPitStop = (currentGameState.PitData.PitWindow == PitWindow.Open || currentGameState.PitData.PitWindow == PitWindow.StopInProgress) && (currentGameState.PitData.OnInLap || currentGameState.PitData.OnOutLap); } currentGameState.CarDamageData.DamageEnabled = true; // no way to tell if it's disabled from the shared memory currentGameState.CarDamageData.OverallAeroDamage = mapToAeroDamageLevel(shared.mAeroDamage); currentGameState.CarDamageData.OverallEngineDamage = mapToEngineDamageLevel(shared.mEngineDamage); currentGameState.CarDamageData.OverallTransmissionDamage = DamageLevel.NONE; currentGameState.CarDamageData.SuspensionDamageStatus = CornerData.getCornerData(suspensionDamageThresholds, shared.mSuspensionDamage[0], shared.mSuspensionDamage[1], shared.mSuspensionDamage[2], shared.mSuspensionDamage[3]); currentGameState.CarDamageData.BrakeDamageStatus = CornerData.getCornerData(brakeDamageThresholds, shared.mBrakeDamage[0], shared.mBrakeDamage[1], shared.mBrakeDamage[2], shared.mBrakeDamage[3]); currentGameState.EngineData.EngineOilPressure = shared.mOilPressureKPa; // todo: units conversion currentGameState.EngineData.EngineOilTemp = shared.mOilTempCelsius; currentGameState.EngineData.EngineWaterTemp = shared.mWaterTempCelsius; currentGameState.EngineData.EngineRpm = shared.mRPM; currentGameState.EngineData.MaxEngineRpm = shared.mMaxRPM; currentGameState.EngineData.MinutesIntoSessionBeforeMonitoring = 2; currentGameState.FuelData.FuelCapacity = shared.mFuelCapacity; currentGameState.FuelData.FuelLeft = currentGameState.FuelData.FuelCapacity * shared.mFuelLevel; currentGameState.FuelData.FuelPressure = shared.mFuelPressureKPa; currentGameState.FuelData.FuelUseActive = true; // no way to tell if it's disabled currentGameState.PenaltiesData.HasDriveThrough = shared.mPitSchedule == (int)ePitSchedule.PIT_SCHEDULE_DRIVE_THROUGH; currentGameState.PenaltiesData.HasStopAndGo = shared.mPitSchedule == (int)ePitSchedule.PIT_SCHEDULE_STOP_GO; currentGameState.PositionAndMotionData.CarSpeed = shared.mSpeed; //------------------------ Tyre data ----------------------- currentGameState.TyreData.HasMatchedTyreTypes = true; currentGameState.TyreData.TireWearActive = true; currentGameState.TyreData.LeftFrontAttached = (shared.mTyreFlags[0] & 1) == 1; currentGameState.TyreData.RightFrontAttached = (shared.mTyreFlags[1] & 1) == 1; currentGameState.TyreData.LeftRearAttached = (shared.mTyreFlags[2] & 1) == 1; currentGameState.TyreData.RightRearAttached = (shared.mTyreFlags[3] & 1) == 1; currentGameState.TyreData.FrontLeft_CenterTemp = shared.mTyreTreadTemp[0] - 273; currentGameState.TyreData.FrontLeft_LeftTemp = shared.mTyreTreadTemp[0] - 273; currentGameState.TyreData.FrontLeft_RightTemp = shared.mTyreTreadTemp[0] - 273; currentGameState.TyreData.FrontLeftTyreType = defaultTyreTypeForPlayersCar; currentGameState.TyreData.FrontLeftPressure = -1; // not in the block currentGameState.TyreData.FrontLeftPercentWear = Math.Min(100, shared.mTyreWear[0] * 100 / wornOutTyreWearLevel); if (currentGameState.SessionData.IsNewLap) { currentGameState.TyreData.PeakFrontLeftTemperatureForLap = currentGameState.TyreData.FrontLeft_CenterTemp; } else if (previousGameState == null || currentGameState.TyreData.FrontLeft_CenterTemp > previousGameState.TyreData.PeakFrontLeftTemperatureForLap) { currentGameState.TyreData.PeakFrontLeftTemperatureForLap = currentGameState.TyreData.FrontLeft_CenterTemp; } currentGameState.TyreData.FrontRight_CenterTemp = shared.mTyreTreadTemp[1] - 273; currentGameState.TyreData.FrontRight_LeftTemp = shared.mTyreTreadTemp[1] - 273; currentGameState.TyreData.FrontRight_RightTemp = shared.mTyreTreadTemp[1] - 273; currentGameState.TyreData.FrontRightTyreType = defaultTyreTypeForPlayersCar; currentGameState.TyreData.FrontRightPressure = -1; // not in the block currentGameState.TyreData.FrontRightPercentWear = Math.Min(100, shared.mTyreWear[1] * 100 / wornOutTyreWearLevel); if (currentGameState.SessionData.IsNewLap) { currentGameState.TyreData.PeakFrontRightTemperatureForLap = currentGameState.TyreData.FrontRight_CenterTemp; } else if (previousGameState == null || currentGameState.TyreData.FrontRight_CenterTemp > previousGameState.TyreData.PeakFrontRightTemperatureForLap) { currentGameState.TyreData.PeakFrontRightTemperatureForLap = currentGameState.TyreData.FrontRight_CenterTemp; } currentGameState.TyreData.RearLeft_CenterTemp = shared.mTyreTreadTemp[2] - 273; currentGameState.TyreData.RearLeft_LeftTemp = shared.mTyreTreadTemp[2] - 273; currentGameState.TyreData.RearLeft_RightTemp = shared.mTyreTreadTemp[2] - 273; currentGameState.TyreData.RearLeftTyreType = defaultTyreTypeForPlayersCar; currentGameState.TyreData.RearLeftPressure = -1; // not in the block currentGameState.TyreData.RearLeftPercentWear = Math.Min(100, shared.mTyreWear[2] * 100 / wornOutTyreWearLevel); if (currentGameState.SessionData.IsNewLap) { currentGameState.TyreData.PeakRearLeftTemperatureForLap = currentGameState.TyreData.RearLeft_CenterTemp; } else if (previousGameState == null || currentGameState.TyreData.RearLeft_CenterTemp > previousGameState.TyreData.PeakRearLeftTemperatureForLap) { currentGameState.TyreData.PeakRearLeftTemperatureForLap = currentGameState.TyreData.RearLeft_CenterTemp; } currentGameState.TyreData.RearRight_CenterTemp = shared.mTyreTreadTemp[3] - 273; currentGameState.TyreData.RearRight_LeftTemp = shared.mTyreTreadTemp[3] - 273; currentGameState.TyreData.RearRight_RightTemp = shared.mTyreTreadTemp[3] - 273; currentGameState.TyreData.RearRightTyreType = defaultTyreTypeForPlayersCar; currentGameState.TyreData.RearRightPressure = -1; // not in the block currentGameState.TyreData.RearRightPercentWear = Math.Min(100, shared.mTyreWear[3] * 100 / wornOutTyreWearLevel); if (currentGameState.SessionData.IsNewLap) { currentGameState.TyreData.PeakRearRightTemperatureForLap = currentGameState.TyreData.RearRight_CenterTemp; } else if (previousGameState == null || currentGameState.TyreData.RearRight_CenterTemp > previousGameState.TyreData.PeakRearRightTemperatureForLap) { currentGameState.TyreData.PeakRearRightTemperatureForLap = currentGameState.TyreData.RearRight_CenterTemp; } currentGameState.TyreData.TyreConditionStatus = CornerData.getCornerData(tyreWearThresholds, currentGameState.TyreData.FrontLeftPercentWear, currentGameState.TyreData.FrontRightPercentWear, currentGameState.TyreData.RearLeftPercentWear, currentGameState.TyreData.RearRightPercentWear); currentGameState.TyreData.TyreTempStatus = CornerData.getCornerData(CarData.tyreTempThresholds[defaultTyreTypeForPlayersCar], currentGameState.TyreData.PeakFrontLeftTemperatureForLap, currentGameState.TyreData.PeakFrontRightTemperatureForLap, currentGameState.TyreData.PeakRearLeftTemperatureForLap, currentGameState.TyreData.PeakRearRightTemperatureForLap); currentGameState.TyreData.BrakeTempStatus = CornerData.getCornerData(brakeTempThresholdsForPlayersCar, shared.mBrakeTempCelsius[0], shared.mBrakeTempCelsius[1], shared.mBrakeTempCelsius[2], shared.mBrakeTempCelsius[3]); currentGameState.TyreData.LeftFrontBrakeTemp = shared.mBrakeTempCelsius[0]; currentGameState.TyreData.RightFrontBrakeTemp = shared.mBrakeTempCelsius[1]; currentGameState.TyreData.LeftRearBrakeTemp = shared.mBrakeTempCelsius[2]; currentGameState.TyreData.RightRearBrakeTemp = shared.mBrakeTempCelsius[0]; // improvised cut track warnings... if (incrementCutTrackCountWhenLeavingRacingSurface) { currentGameState.PenaltiesData.IsOffRacingSurface = !racingSurfaces.Contains(shared.mTerrain[0]) && !racingSurfaces.Contains(shared.mTerrain[1]) && !racingSurfaces.Contains(shared.mTerrain[2]) && !racingSurfaces.Contains(shared.mTerrain[3]); if (previousGameState != null && previousGameState.PenaltiesData.IsOffRacingSurface && currentGameState.PenaltiesData.IsOffRacingSurface) { currentGameState.PenaltiesData.CutTrackWarnings = previousGameState.PenaltiesData.CutTrackWarnings + 1; } } if (!currentGameState.PitData.OnOutLap && previousGameState != null && previousGameState.SessionData.CurrentLapIsValid && !currentGameState.SessionData.CurrentLapIsValid && !(shared.mSessionState == (int)eSessionState.SESSION_RACE && shared.mRaceState == (int)eRaceState.RACESTATE_NOT_STARTED)) { currentGameState.PenaltiesData.CutTrackWarnings = previousGameState.PenaltiesData.CutTrackWarnings + 1; } // Tyre slip speed seems to peak at about 30 with big lock or wheelspin (in Sauber Merc). It's noisy as hell and is frequently bouncing around // in single figures, with the noise varying between cars. // tyreRPS is much cleaner but we don't know the diameter of the tyre so can't compare it (accurately) to the car's speed if (shared.mSpeed > 7) { float minRotatingSpeed = 2 * (float)Math.PI * shared.mSpeed / currentGameState.carClass.maxTyreCircumference; // I think the tyreRPS is actually radians per second... currentGameState.TyreData.LeftFrontIsLocked = Math.Abs(shared.mTyreRPS[0]) < minRotatingSpeed; currentGameState.TyreData.RightFrontIsLocked = Math.Abs(shared.mTyreRPS[1]) < minRotatingSpeed; currentGameState.TyreData.LeftRearIsLocked = Math.Abs(shared.mTyreRPS[2]) < minRotatingSpeed; currentGameState.TyreData.RightRearIsLocked = Math.Abs(shared.mTyreRPS[3]) < minRotatingSpeed; float maxRotatingSpeed = 2 * (float)Math.PI * shared.mSpeed / currentGameState.carClass.minTyreCircumference; currentGameState.TyreData.LeftFrontIsSpinning = Math.Abs(shared.mTyreRPS[0]) > maxRotatingSpeed; currentGameState.TyreData.RightFrontIsSpinning = Math.Abs(shared.mTyreRPS[1]) > maxRotatingSpeed; currentGameState.TyreData.LeftRearIsSpinning = Math.Abs(shared.mTyreRPS[2]) > maxRotatingSpeed; currentGameState.TyreData.RightRearIsSpinning = Math.Abs(shared.mTyreRPS[3]) > maxRotatingSpeed; } if (currentGameState.Conditions.timeOfMostRecentSample.Add(ConditionsMonitor.ConditionsSampleFrequency) < currentGameState.Now) { currentGameState.Conditions.addSample(currentGameState.Now, currentGameState.SessionData.CompletedLaps, currentGameState.SessionData.SectorNumber, shared.mAmbientTemperature, shared.mTrackTemperature, shared.mRainDensity, shared.mWindSpeed, shared.mWindDirectionX, shared.mWindDirectionY, shared.mCloudBrightness); } return currentGameState; }
public GameStateData mapToGameStateData(Object memoryMappedFileStruct, GameStateData previousGameState) { CrewChiefV3.RaceRoom.R3ESharedMemoryReader.R3EStructWrapper wrapper = (CrewChiefV3.RaceRoom.R3ESharedMemoryReader.R3EStructWrapper)memoryMappedFileStruct; GameStateData currentGameState = new GameStateData(wrapper.ticksWhenRead); RaceRoomData.RaceRoomShared shared = wrapper.data; if (shared.Player.GameSimulationTime <= 0 || shared.slot_id < 0 || shared.ControlType == (int)RaceRoomConstant.Control.Remote || shared.ControlType == (int)RaceRoomConstant.Control.Replay) { return null; } Boolean isCarRunning = CheckIsCarRunning(shared); SessionPhase lastSessionPhase = SessionPhase.Unavailable; float lastSessionRunningTime = 0; if (previousGameState != null) { lastSessionPhase = previousGameState.SessionData.SessionPhase; lastSessionRunningTime = previousGameState.SessionData.SessionRunningTime; } currentGameState.SessionData.SessionType = mapToSessionType(shared); currentGameState.SessionData.SessionRunningTime = (float)shared.Player.GameSimulationTime; currentGameState.ControlData.ControlType = mapToControlType(shared.ControlType); // TODO: the rest of the control data currentGameState.SessionData.NumCarsAtStartOfSession = shared.NumCars; int previousLapsCompleted = previousGameState == null ? 0 : previousGameState.SessionData.CompletedLaps; currentGameState.SessionData.SessionPhase = mapToSessionPhase(lastSessionPhase, currentGameState.SessionData.SessionType, lastSessionRunningTime, currentGameState.SessionData.SessionRunningTime, shared.SessionPhase, currentGameState.ControlData.ControlType, previousLapsCompleted, shared.CompletedLaps, isCarRunning); List<String> opponentDriverNamesProcessedThisUpdate = new List<String>(); if ((lastSessionPhase != currentGameState.SessionData.SessionPhase && (lastSessionPhase == SessionPhase.Unavailable || lastSessionPhase == SessionPhase.Finished)) || ((lastSessionPhase == SessionPhase.Checkered || lastSessionPhase == SessionPhase.Finished || lastSessionPhase == SessionPhase.Green) && currentGameState.SessionData.SessionPhase == SessionPhase.Countdown) || lastSessionRunningTime > currentGameState.SessionData.SessionRunningTime) { currentGameState.SessionData.IsNewSession = true; Console.WriteLine("New session, trigger data:"); Console.WriteLine("lastSessionPhase = " + lastSessionPhase); Console.WriteLine("lastSessionRunningTime = " + lastSessionRunningTime); Console.WriteLine("currentSessionPhase = " + currentGameState.SessionData.SessionPhase); Console.WriteLine("rawSessionPhase = " + shared.SessionPhase); Console.WriteLine("currentSessionRunningTime = " + currentGameState.SessionData.SessionRunningTime); currentGameState.SessionData.EventIndex = shared.EventIndex; currentGameState.SessionData.SessionIteration = shared.SessionIteration; currentGameState.SessionData.SessionStartTime = currentGameState.Now; currentGameState.OpponentData.Clear(); currentGameState.SessionData.TrackDefinition = TrackData.getTrackDefinition(null, shared.track_info.length); currentGameState.PitData.IsRefuellingAllowed = true; // reset the engine temp monitor stuff gotBaselineEngineData = false; baselineEngineDataSamples = 0; baselineEngineDataOilTemp = 0; baselineEngineDataWaterTemp = 0; for (int i = 0; i < shared.all_drivers_data.Length; i++) { DriverData participantStruct = shared.all_drivers_data[i]; String driverName = getNameFromBytes(participantStruct.driver_info.nameByteArray); if (participantStruct.driver_info.slot_id == shared.slot_id) { currentGameState.SessionData.IsNewSector = previousGameState == null || participantStruct.track_sector != previousGameState.SessionData.SectorNumber; currentGameState.SessionData.SectorNumber = participantStruct.track_sector; currentGameState.SessionData.DriverRawName = driverName; if (playerName == null) { NameValidator.validateName(driverName); playerName = driverName; } currentGameState.PitData.InPitlane = participantStruct.in_pitlane == 1; currentGameState.PositionAndMotionData.DistanceRoundTrack = participantStruct.lap_distance; currentGameState.carClass = CarData.getCarClassForRaceRoomId(participantStruct.driver_info.class_id); Console.WriteLine("Player is using car class " + currentGameState.carClass.carClassEnum + " (class ID " + participantStruct.driver_info.class_id + ")"); brakeTempThresholdsForPlayersCar = CarData.getBrakeTempThresholds(currentGameState.carClass, null); } else { if (driverName.Length > 0 && currentGameState.SessionData.DriverRawName != driverName) { if (opponentDriverNamesProcessedThisUpdate.Contains(driverName)) { // would be nice to warn here, but this happens a lot :( } else { opponentDriverNamesProcessedThisUpdate.Add(driverName); currentGameState.OpponentData.Add(driverName, createOpponentData(participantStruct, driverName, false)); } } } } } else { Boolean justGoneGreen = false; if (lastSessionPhase != currentGameState.SessionData.SessionPhase) { Console.WriteLine("New session phase, was " + lastSessionPhase + " now " + currentGameState.SessionData.SessionPhase); if (currentGameState.SessionData.SessionPhase == SessionPhase.Green) { justGoneGreen = true; // just gone green, so get the session data if (shared.NumberOfLaps > 0) { currentGameState.SessionData.SessionNumberOfLaps = shared.NumberOfLaps; currentGameState.SessionData.SessionHasFixedTime = false; } if (shared.SessionTimeRemaining > 0) { currentGameState.SessionData.SessionRunTime = shared.SessionTimeRemaining; currentGameState.SessionData.SessionHasFixedTime = true; } currentGameState.SessionData.SessionStartPosition = shared.Position; currentGameState.SessionData.NumCarsAtStartOfSession = shared.NumCars; currentGameState.SessionData.SessionStartTime = currentGameState.Now; currentGameState.carClass = CarData.getCarClassForRaceRoomId(shared.all_drivers_data[shared.slot_id].driver_info.class_id); Console.WriteLine("Player is using car class " + currentGameState.carClass.carClassEnum); brakeTempThresholdsForPlayersCar = CarData.getBrakeTempThresholds(currentGameState.carClass, null); if (previousGameState != null) { currentGameState.PitData.IsRefuellingAllowed = previousGameState.PitData.IsRefuellingAllowed; currentGameState.OpponentData = previousGameState.OpponentData; currentGameState.SessionData.TrackDefinition = previousGameState.SessionData.TrackDefinition; currentGameState.SessionData.DriverRawName = previousGameState.SessionData.DriverRawName; } currentGameState.PitData.PitWindowStart = shared.PitWindowStart; currentGameState.PitData.PitWindowEnd = shared.PitWindowEnd; currentGameState.PitData.HasMandatoryPitStop = currentGameState.PitData.PitWindowStart > 0 && currentGameState.PitData.PitWindowEnd > 0; if (currentGameState.PitData.HasMandatoryPitStop) { if (currentGameState.carClass.carClassEnum == CarData.CarClassEnum.DTM_2014 || currentGameState.carClass.carClassEnum == CarData.CarClassEnum.DTM_2015) { // iteration 1 of the DTM 2015 doesn't have a mandatory tyre change, but this means the pit window stuff won't be set, so we're (kind of) OK here... currentGameState.PitData.HasMandatoryTyreChange = true; } else if (currentGameState.carClass.carClassEnum == CarData.CarClassEnum.ADAC_GTM_2014) { currentGameState.PitData.HasMandatoryDriverChange = true; } if (currentGameState.PitData.HasMandatoryTyreChange && currentGameState.PitData.MandatoryTyreChangeRequiredTyreType == TyreType.Unknown_Race) { if (currentGameState.carClass.carClassEnum == CarData.CarClassEnum.DTM_2014) { double halfRaceDistance = currentGameState.SessionData.SessionNumberOfLaps / 2d; if (mapToTyreType(shared.TireType) == TyreType.Option) { currentGameState.PitData.MandatoryTyreChangeRequiredTyreType = TyreType.Prime; // TODO: this might be a lap early... currentGameState.PitData.MaxPermittedDistanceOnCurrentTyre = ((int)Math.Floor(halfRaceDistance)) - 1; } else { currentGameState.PitData.MandatoryTyreChangeRequiredTyreType = TyreType.Option; currentGameState.PitData.MinPermittedDistanceOnCurrentTyre = (int)Math.Ceiling(halfRaceDistance); } } else if (currentGameState.carClass.carClassEnum == CarData.CarClassEnum.DTM_2015) { currentGameState.PitData.MandatoryTyreChangeRequiredTyreType = TyreType.Prime; // the mandatory change must be completed by the end of the pit window currentGameState.PitData.MaxPermittedDistanceOnCurrentTyre = currentGameState.PitData.PitWindowEnd; } } } Console.WriteLine("Just gone green, session details..."); // reset the engine temp monitor stuff gotBaselineEngineData = false; baselineEngineDataSamples = 0; baselineEngineDataOilTemp = 0; baselineEngineDataWaterTemp = 0; Console.WriteLine("SessionType " + currentGameState.SessionData.SessionType); Console.WriteLine("SessionPhase " + currentGameState.SessionData.SessionPhase); Console.WriteLine("EventIndex " + currentGameState.SessionData.EventIndex); Console.WriteLine("SessionIteration " + currentGameState.SessionData.SessionIteration); Console.WriteLine("HasMandatoryPitStop " + currentGameState.PitData.HasMandatoryPitStop); Console.WriteLine("PitWindowStart " + currentGameState.PitData.PitWindowStart); Console.WriteLine("PitWindowEnd " + currentGameState.PitData.PitWindowEnd); Console.WriteLine("NumCarsAtStartOfSession " + currentGameState.SessionData.NumCarsAtStartOfSession); Console.WriteLine("SessionNumberOfLaps " + currentGameState.SessionData.SessionNumberOfLaps); Console.WriteLine("SessionRunTime " + currentGameState.SessionData.SessionRunTime); Console.WriteLine("SessionStartPosition " + currentGameState.SessionData.SessionStartPosition); Console.WriteLine("SessionStartTime " + currentGameState.SessionData.SessionStartTime); String trackName = currentGameState.SessionData.TrackDefinition == null ? "unknown" : currentGameState.SessionData.TrackDefinition.name; Console.WriteLine("TrackName " + trackName); } } if (!justGoneGreen && previousGameState != null) { currentGameState.SessionData.SessionStartTime = previousGameState.SessionData.SessionStartTime; currentGameState.SessionData.SessionRunTime = previousGameState.SessionData.SessionRunTime; currentGameState.SessionData.SessionNumberOfLaps = previousGameState.SessionData.SessionNumberOfLaps; currentGameState.SessionData.SessionStartPosition = previousGameState.SessionData.SessionStartPosition; currentGameState.SessionData.NumCarsAtStartOfSession = previousGameState.SessionData.NumCarsAtStartOfSession; currentGameState.SessionData.EventIndex = previousGameState.SessionData.EventIndex; currentGameState.SessionData.SessionIteration = previousGameState.SessionData.SessionIteration; currentGameState.PitData.PitWindowStart = previousGameState.PitData.PitWindowStart; currentGameState.PitData.PitWindowEnd = previousGameState.PitData.PitWindowEnd; currentGameState.PitData.HasMandatoryPitStop = previousGameState.PitData.HasMandatoryPitStop; currentGameState.PitData.HasMandatoryDriverChange = previousGameState.PitData.HasMandatoryDriverChange; currentGameState.PitData.HasMandatoryTyreChange = previousGameState.PitData.HasMandatoryTyreChange; currentGameState.PitData.MandatoryTyreChangeRequiredTyreType = previousGameState.PitData.MandatoryTyreChangeRequiredTyreType; currentGameState.PitData.IsRefuellingAllowed = previousGameState.PitData.IsRefuellingAllowed; currentGameState.PitData.MaxPermittedDistanceOnCurrentTyre = previousGameState.PitData.MaxPermittedDistanceOnCurrentTyre; currentGameState.PitData.MinPermittedDistanceOnCurrentTyre = previousGameState.PitData.MinPermittedDistanceOnCurrentTyre; currentGameState.PitData.OnInLap = previousGameState.PitData.OnInLap; currentGameState.PitData.OnOutLap = previousGameState.PitData.OnOutLap; currentGameState.SessionData.TrackDefinition = previousGameState.SessionData.TrackDefinition; currentGameState.SessionData.formattedPlayerLapTimes = previousGameState.SessionData.formattedPlayerLapTimes; currentGameState.SessionData.PlayerLapTimeSessionBest = previousGameState.SessionData.PlayerLapTimeSessionBest; currentGameState.SessionData.OpponentsLapTimeSessionBestOverall = previousGameState.SessionData.OpponentsLapTimeSessionBestOverall; currentGameState.SessionData.OpponentsLapTimeSessionBestPlayerClass = previousGameState.SessionData.OpponentsLapTimeSessionBestPlayerClass; currentGameState.carClass = previousGameState.carClass; currentGameState.SessionData.DriverRawName = previousGameState.SessionData.DriverRawName; currentGameState.SessionData.SessionTimesAtEndOfSectors = previousGameState.SessionData.SessionTimesAtEndOfSectors; currentGameState.SessionData.LapTimePreviousEstimateForInvalidLap = previousGameState.SessionData.LapTimePreviousEstimateForInvalidLap; currentGameState.SessionData.OverallSessionBestLapTime = previousGameState.SessionData.OverallSessionBestLapTime; currentGameState.SessionData.PlayerClassSessionBestLapTime = previousGameState.SessionData.PlayerClassSessionBestLapTime; currentGameState.SessionData.GameTimeAtLastPositionFrontChange = previousGameState.SessionData.GameTimeAtLastPositionFrontChange; currentGameState.SessionData.GameTimeAtLastPositionBehindChange = previousGameState.SessionData.GameTimeAtLastPositionBehindChange; currentGameState.SessionData.LastSector1Time = previousGameState.SessionData.LastSector1Time; currentGameState.SessionData.LastSector2Time = previousGameState.SessionData.LastSector2Time; currentGameState.SessionData.LastSector3Time = previousGameState.SessionData.LastSector3Time; currentGameState.SessionData.PlayerBestSector1Time = previousGameState.SessionData.PlayerBestSector1Time; currentGameState.SessionData.PlayerBestSector2Time = previousGameState.SessionData.PlayerBestSector2Time; currentGameState.SessionData.PlayerBestSector3Time = previousGameState.SessionData.PlayerBestSector3Time; currentGameState.SessionData.PlayerBestLapSector1Time = previousGameState.SessionData.PlayerBestLapSector1Time; currentGameState.SessionData.PlayerBestLapSector2Time = previousGameState.SessionData.PlayerBestLapSector2Time; currentGameState.SessionData.PlayerBestLapSector3Time = previousGameState.SessionData.PlayerBestLapSector3Time; } } //------------------------ Session data ----------------------- currentGameState.SessionData.Flag = FlagEnum.UNKNOWN; currentGameState.SessionData.SessionTimeRemaining = shared.SessionTimeRemaining; currentGameState.SessionData.CompletedLaps = shared.CompletedLaps; currentGameState.SessionData.LapTimeCurrent = shared.LapTimeCurrent; currentGameState.SessionData.CurrentLapIsValid = currentGameState.SessionData.LapTimeCurrent != -1; currentGameState.SessionData.LapTimePrevious = shared.LapTimePrevious; currentGameState.SessionData.PreviousLapWasValid = shared.LapTimePrevious > 0; currentGameState.SessionData.NumCars = shared.NumCars; currentGameState.SessionData.Position = getRacePosition(currentGameState.SessionData.DriverRawName, currentGameState.SessionData.Position, shared.Position, currentGameState.Now); // currentGameState.SessionData.Position = shared.Position; currentGameState.SessionData.UnFilteredPosition = shared.Position; currentGameState.SessionData.TimeDeltaBehind = shared.TimeDeltaBehind; currentGameState.SessionData.TimeDeltaFront = shared.TimeDeltaFront; currentGameState.SessionData.SessionFastestLapTimeFromGame = shared.LapTimeBestLeader; currentGameState.SessionData.SessionFastestLapTimeFromGamePlayerClass = shared.LapTimeBestLeaderClass; if (currentGameState.SessionData.OverallSessionBestLapTime == -1 || currentGameState.SessionData.OverallSessionBestLapTime > shared.LapTimeBestLeader) { currentGameState.SessionData.OverallSessionBestLapTime = shared.LapTimeBestLeader; } if (currentGameState.SessionData.PlayerClassSessionBestLapTime == -1 || currentGameState.SessionData.PlayerClassSessionBestLapTime > shared.LapTimeBestLeaderClass) { currentGameState.SessionData.PlayerClassSessionBestLapTime = shared.LapTimeBestLeaderClass; } // TODO: calculate the actual session best sector times from the bollocks in the block (cumulative deltas between the last player sector time and the session best) currentGameState.SessionData.IsNewLap = previousGameState != null && previousGameState.SessionData.IsNewLap == false && (shared.CompletedLaps == previousGameState.SessionData.CompletedLaps + 1 || ((lastSessionPhase == SessionPhase.Countdown || lastSessionPhase == SessionPhase.Formation || lastSessionPhase == SessionPhase.Garage) && currentGameState.SessionData.SessionPhase == SessionPhase.Green)); if (currentGameState.SessionData.IsNewLap) { currentGameState.SessionData.formattedPlayerLapTimes.Add(TimeSpan.FromSeconds(shared.LapTimePrevious).ToString(@"mm\:ss\.fff")); } if (previousGameState != null && !currentGameState.SessionData.IsNewSession) { currentGameState.OpponentData = previousGameState.OpponentData; currentGameState.SessionData.SectorNumber = previousGameState.SessionData.SectorNumber; } foreach (DriverData participantStruct in shared.all_drivers_data) { if (participantStruct.driver_info.slot_id == shared.slot_id) { if (currentGameState.carClass.carClassEnum == CarData.CarClassEnum.UNKNOWN_RACE) { CarData.CarClass newClass = CarData.getCarClassForRaceRoomId(participantStruct.driver_info.class_id); if (newClass.carClassEnum != currentGameState.carClass.carClassEnum) { currentGameState.carClass = newClass; Console.WriteLine("Player is using car class " + currentGameState.carClass.carClassEnum + " (class ID " + participantStruct.driver_info.class_id + ")"); brakeTempThresholdsForPlayersCar = CarData.getBrakeTempThresholds(currentGameState.carClass, null); } } currentGameState.SessionData.IsNewSector = participantStruct.track_sector != 0 && currentGameState.SessionData.SectorNumber != participantStruct.track_sector; if (currentGameState.SessionData.IsNewSector) { if (participantStruct.track_sector == 1) { if (currentGameState.SessionData.SessionTimesAtEndOfSectors[3] != -1) { currentGameState.SessionData.LapTimePreviousEstimateForInvalidLap = currentGameState.SessionData.SessionRunningTime - currentGameState.SessionData.SessionTimesAtEndOfSectors[3]; } currentGameState.SessionData.SessionTimesAtEndOfSectors[3] = currentGameState.SessionData.SessionRunningTime; if (participantStruct.sector_time_previous_self.Sector3 > 0 && participantStruct.sector_time_current_self.Sector2 > 0) { float sectorTime = participantStruct.sector_time_previous_self.Sector3 - participantStruct.sector_time_current_self.Sector2; currentGameState.SessionData.LastSector3Time = sectorTime; if (currentGameState.SessionData.PlayerBestSector3Time == -1 || currentGameState.SessionData.LastSector3Time < currentGameState.SessionData.PlayerBestSector3Time) { currentGameState.SessionData.PlayerBestSector3Time = currentGameState.SessionData.LastSector3Time; } if (currentGameState.SessionData.LapTimePrevious > 0 && (currentGameState.SessionData.PlayerLapTimeSessionBest == -1 || currentGameState.SessionData.LapTimePrevious <= currentGameState.SessionData.PlayerLapTimeSessionBest)) { currentGameState.SessionData.PlayerBestLapSector1Time = currentGameState.SessionData.LastSector1Time; currentGameState.SessionData.PlayerBestLapSector2Time = currentGameState.SessionData.LastSector2Time; currentGameState.SessionData.PlayerBestLapSector3Time = currentGameState.SessionData.LastSector3Time; } } } else if (participantStruct.track_sector == 2) { currentGameState.SessionData.SessionTimesAtEndOfSectors[1] = currentGameState.SessionData.SessionRunningTime; if (participantStruct.sector_time_current_self.Sector1 > 0) { currentGameState.SessionData.LastSector1Time = participantStruct.sector_time_current_self.Sector1; if (currentGameState.SessionData.PlayerBestSector1Time == -1 || currentGameState.SessionData.LastSector1Time < currentGameState.SessionData.PlayerBestSector1Time) { currentGameState.SessionData.PlayerBestSector1Time = currentGameState.SessionData.LastSector1Time; } } } else if (participantStruct.track_sector == 3) { currentGameState.SessionData.SessionTimesAtEndOfSectors[2] = currentGameState.SessionData.SessionRunningTime; if (participantStruct.sector_time_current_self.Sector2 > 0 && participantStruct.sector_time_current_self.Sector1 > 0) { float sectorTime = participantStruct.sector_time_current_self.Sector2 - participantStruct.sector_time_current_self.Sector1; currentGameState.SessionData.LastSector2Time = sectorTime; if (currentGameState.SessionData.PlayerBestSector2Time == -1 || currentGameState.SessionData.LastSector2Time < currentGameState.SessionData.PlayerBestSector2Time) { currentGameState.SessionData.PlayerBestSector2Time = currentGameState.SessionData.LastSector2Time; } } } } currentGameState.SessionData.SectorNumber = participantStruct.track_sector; currentGameState.PitData.InPitlane = participantStruct.in_pitlane == 1; currentGameState.PositionAndMotionData.DistanceRoundTrack = participantStruct.lap_distance; if (currentGameState.PitData.InPitlane) { if (participantStruct.track_sector == 3) { currentGameState.PitData.OnInLap = true; currentGameState.PitData.OnOutLap = false; } else if (participantStruct.track_sector == 1) { currentGameState.PitData.OnInLap = false; currentGameState.PitData.OnOutLap = true; } } else if (currentGameState.SessionData.IsNewLap) { // starting a new lap while not in the pitlane so clear the in / out lap flags currentGameState.PitData.OnInLap = false; currentGameState.PitData.OnOutLap = false; } if (previousGameState != null && currentGameState.PitData.OnOutLap && previousGameState.PitData.InPitlane && !currentGameState.PitData.InPitlane) { currentGameState.PitData.IsAtPitExit = true; } break; } } foreach (DriverData participantStruct in shared.all_drivers_data) { if (participantStruct.driver_info.slot_id != -1 && participantStruct.driver_info.slot_id != shared.slot_id) { String driverName = getNameFromBytes(participantStruct.driver_info.nameByteArray); if (driverName.Length == 0 || driverName == currentGameState.SessionData.DriverRawName || opponentDriverNamesProcessedThisUpdate.Contains(driverName) || participantStruct.place < 1) { continue; } if (currentGameState.OpponentData.ContainsKey(driverName)) { opponentDriverNamesProcessedThisUpdate.Add(driverName); if (previousGameState != null) { OpponentData previousOpponentData = null; Boolean newOpponentLap = false; int previousOpponentSectorNumber = 1; int previousOpponentCompletedLaps = 0; int previousOpponentPosition = 0; Boolean previousOpponentIsEnteringPits = false; Boolean previousOpponentIsExitingPits = false; float[] previousOpponentWorldPosition = new float[] { 0, 0, 0 }; float previousOpponentSpeed = 0; if (previousGameState.OpponentData.ContainsKey(driverName)) { previousOpponentData = previousGameState.OpponentData[driverName]; previousOpponentSectorNumber = previousOpponentData.CurrentSectorNumber; previousOpponentCompletedLaps = previousOpponentData.CompletedLaps; previousOpponentPosition = previousOpponentData.Position; previousOpponentIsEnteringPits = previousOpponentData.isEnteringPits(); previousOpponentIsExitingPits = previousOpponentData.isExitingPits(); previousOpponentWorldPosition = previousOpponentData.WorldPosition; previousOpponentSpeed = previousOpponentData.Speed; newOpponentLap = previousOpponentData.CurrentSectorNumber == 3 && participantStruct.track_sector == 1; } OpponentData currentOpponentData = currentGameState.OpponentData[driverName]; float sectorTime = -1; if (participantStruct.track_sector == 1) { sectorTime = participantStruct.sector_time_current_self.Sector3; } else if (participantStruct.track_sector == 2) { sectorTime = participantStruct.sector_time_current_self.Sector1; } else if (participantStruct.track_sector == 3) { sectorTime = participantStruct.sector_time_current_self.Sector2; } int currentOpponentRacePosition = getRacePosition(driverName, previousOpponentPosition, participantStruct.place, currentGameState.Now); //int currentOpponentRacePosition = participantStruct.place; int currentOpponentLapsCompleted = participantStruct.completed_laps; int currentOpponentSector = participantStruct.track_sector; if (currentOpponentSector == 0) { currentOpponentSector = previousOpponentSectorNumber; } float currentOpponentLapDistance = participantStruct.lap_distance; Boolean finishedAllottedRaceLaps = currentGameState.SessionData.SessionNumberOfLaps > 0 && currentGameState.SessionData.SessionNumberOfLaps == currentOpponentLapsCompleted; Boolean finishedAllottedRaceTime = false; if (currentGameState.carClass.carClassEnum == CarData.CarClassEnum.DTM_2015 && currentGameState.SessionData.SessionType == SessionType.Race) { if (currentGameState.SessionData.SessionRunTime > 0 && currentGameState.SessionData.SessionTimeRemaining <= 0 && previousOpponentCompletedLaps < currentOpponentLapsCompleted) { if (!currentOpponentData.HasStartedExtraLap) { currentOpponentData.HasStartedExtraLap = true; } else { finishedAllottedRaceTime = true; } } } else if (currentGameState.SessionData.SessionRunTime > 0 && currentGameState.SessionData.SessionTimeRemaining <= 0 && previousOpponentCompletedLaps < currentOpponentLapsCompleted) { finishedAllottedRaceTime = true; } if (currentOpponentRacePosition == 1 && (finishedAllottedRaceTime || finishedAllottedRaceLaps)) { currentGameState.SessionData.LeaderHasFinishedRace = true; } if (currentOpponentRacePosition == 1 && previousOpponentPosition > 1) { currentGameState.SessionData.HasLeadChanged = true; } Boolean isEnteringPits = participantStruct.in_pitlane == 1 && currentOpponentSector == 3; Boolean isLeavingPits = participantStruct.in_pitlane == 1 && currentOpponentSector == 1; if (isEnteringPits && !previousOpponentIsEnteringPits) { int opponentPositionAtSector3 = currentOpponentData.Position; LapData currentLapData = currentOpponentData.getCurrentLapData(); if (currentLapData != null && currentLapData.SectorPositions.Count > 2) { opponentPositionAtSector3 = currentLapData.SectorPositions[2]; } if (opponentPositionAtSector3 == 1) { currentGameState.PitData.LeaderIsPitting = true; currentGameState.PitData.OpponentForLeaderPitting = currentOpponentData; } if (currentGameState.SessionData.Position > 2 && opponentPositionAtSector3 == currentGameState.SessionData.Position - 1) { currentGameState.PitData.CarInFrontIsPitting = true; currentGameState.PitData.OpponentForCarAheadPitting = currentOpponentData; } if (!currentGameState.isLast() && opponentPositionAtSector3 == currentGameState.SessionData.Position + 1) { currentGameState.PitData.CarBehindIsPitting = true; currentGameState.PitData.OpponentForCarBehindPitting = currentOpponentData; } } float secondsSinceLastUpdate = (float)new TimeSpan(currentGameState.Ticks - previousGameState.Ticks).TotalSeconds; upateOpponentData(currentOpponentData, currentOpponentRacePosition, participantStruct.place, currentOpponentLapsCompleted, currentOpponentSector, sectorTime, participantStruct.sector_time_previous_self.Sector3, isEnteringPits || isLeavingPits, participantStruct.current_lap_valid == 1, currentGameState.SessionData.SessionRunningTime, secondsSinceLastUpdate, new float[] { participantStruct.position.X, participantStruct.position.Z }, previousOpponentWorldPosition, participantStruct.lap_distance, participantStruct.tire_type); if (newOpponentLap) { if (currentOpponentData.CurrentBestLapTime > 0) { if (currentGameState.SessionData.OpponentsLapTimeSessionBestOverall == -1 || currentOpponentData.CurrentBestLapTime < currentGameState.SessionData.OpponentsLapTimeSessionBestOverall) { currentGameState.SessionData.OpponentsLapTimeSessionBestOverall = currentOpponentData.CurrentBestLapTime; if (currentGameState.SessionData.OverallSessionBestLapTime == -1 || currentGameState.SessionData.OverallSessionBestLapTime > currentOpponentData.CurrentBestLapTime) { currentGameState.SessionData.OverallSessionBestLapTime = currentOpponentData.CurrentBestLapTime; } } if (currentOpponentData.CarClass.carClassEnum == CarData.CarClassEnum.UNKNOWN_RACE || currentGameState.carClass.carClassEnum == CarData.CarClassEnum.UNKNOWN_RACE || currentOpponentData.CarClass.carClassEnum == currentGameState.carClass.carClassEnum) { if (currentGameState.SessionData.OpponentsLapTimeSessionBestPlayerClass == -1 || currentOpponentData.CurrentBestLapTime < currentGameState.SessionData.OpponentsLapTimeSessionBestPlayerClass) { currentGameState.SessionData.OpponentsLapTimeSessionBestPlayerClass = currentOpponentData.CurrentBestLapTime; if (currentGameState.SessionData.PlayerClassSessionBestLapTime == -1 || currentGameState.SessionData.PlayerClassSessionBestLapTime > currentOpponentData.CurrentBestLapTime) { currentGameState.SessionData.PlayerClassSessionBestLapTime = currentOpponentData.CurrentBestLapTime; } } } } } // TODO: fix this properly - hack to work around issue with lagging position updates - // only allow a blue flag if the 'settled' position and the latest position agree Boolean isInSector1OnOutlap = currentOpponentData.CurrentSectorNumber == 1 && (currentOpponentData.getCurrentLapData() != null && currentOpponentData.getCurrentLapData().OutLap); if (currentGameState.SessionData.SessionType == SessionType.Race && currentOpponentData.Position == participantStruct.place && !isEnteringPits && !isLeavingPits && currentGameState.PositionAndMotionData.DistanceRoundTrack != 0 && currentOpponentData.Position + 1 < shared.Position && !isInSector1OnOutlap && isBehindWithinDistance(shared.track_info.length, 8, 80, currentGameState.PositionAndMotionData.DistanceRoundTrack, participantStruct.lap_distance)) { currentGameState.SessionData.Flag = FlagEnum.BLUE; } } } else { opponentDriverNamesProcessedThisUpdate.Add(driverName); currentGameState.OpponentData.Add(driverName, createOpponentData(participantStruct, driverName, true)); } } } if (currentGameState.SessionData.IsNewLap && currentGameState.SessionData.PreviousLapWasValid && currentGameState.SessionData.LapTimePrevious > 0) { if ((currentGameState.SessionData.PlayerLapTimeSessionBest == -1 || currentGameState.SessionData.LapTimePrevious < currentGameState.SessionData.PlayerLapTimeSessionBest)) { currentGameState.SessionData.PlayerLapTimeSessionBest = currentGameState.SessionData.LapTimePrevious; if (currentGameState.SessionData.OverallSessionBestLapTime == -1 || currentGameState.SessionData.OverallSessionBestLapTime > currentGameState.SessionData.PlayerLapTimeSessionBest) { currentGameState.SessionData.OverallSessionBestLapTime = currentGameState.SessionData.PlayerLapTimeSessionBest; } if (currentGameState.SessionData.PlayerClassSessionBestLapTime == -1 || currentGameState.SessionData.PlayerClassSessionBestLapTime > currentGameState.SessionData.PlayerLapTimeSessionBest) { currentGameState.SessionData.PlayerClassSessionBestLapTime = currentGameState.SessionData.PlayerLapTimeSessionBest; } } } // TODO: lap time previous for invalid laps (is this still needed?) if (shared.SessionType == (int)RaceRoomConstant.Session.Race && shared.SessionPhase == (int)RaceRoomConstant.SessionPhase.Checkered && previousGameState != null && previousGameState.SessionData.SessionPhase == SessionPhase.Green) { Console.WriteLine("Leader has finished race, player has done "+ shared.CompletedLaps + " laps, session time = " + shared.Player.GameSimulationTime); currentGameState.SessionData.LeaderHasFinishedRace = true; } currentGameState.SessionData.IsRacingSameCarBehind = previousGameState != null && previousGameState.getOpponentKeyBehind(false) == currentGameState.getOpponentKeyBehind(false); currentGameState.SessionData.IsRacingSameCarInFront = previousGameState != null && previousGameState.getOpponentKeyInFront(false) == currentGameState.getOpponentKeyInFront(false); if (!currentGameState.SessionData.IsRacingSameCarInFront) { currentGameState.SessionData.GameTimeAtLastPositionFrontChange = currentGameState.SessionData.SessionRunningTime; } if (!currentGameState.SessionData.IsRacingSameCarBehind) { currentGameState.SessionData.GameTimeAtLastPositionBehindChange = currentGameState.SessionData.SessionRunningTime; } //------------------------ Car damage data ----------------------- currentGameState.CarDamageData.DamageEnabled = shared.CarDamage.Aerodynamics != -1 && shared.CarDamage.Transmission != -1 && shared.CarDamage.Engine != -1; if (currentGameState.CarDamageData.DamageEnabled) { if (shared.CarDamage.Aerodynamics < destroyedAeroThreshold) { currentGameState.CarDamageData.OverallAeroDamage = DamageLevel.DESTROYED; } else if (shared.CarDamage.Aerodynamics < severeAeroDamageThreshold) { currentGameState.CarDamageData.OverallAeroDamage = DamageLevel.MAJOR; } else if (shared.CarDamage.Aerodynamics < minorAeroDamageThreshold) { currentGameState.CarDamageData.OverallAeroDamage = DamageLevel.MINOR; } else if (shared.CarDamage.Aerodynamics < trivialAeroDamageThreshold) { currentGameState.CarDamageData.OverallAeroDamage = DamageLevel.TRIVIAL; } else { currentGameState.CarDamageData.OverallAeroDamage = DamageLevel.NONE; } if (shared.CarDamage.Engine < destroyedEngineThreshold) { currentGameState.CarDamageData.OverallEngineDamage = DamageLevel.DESTROYED; } else if (shared.CarDamage.Engine < severeEngineDamageThreshold) { currentGameState.CarDamageData.OverallEngineDamage = DamageLevel.MAJOR; } else if (shared.CarDamage.Engine < minorEngineDamageThreshold) { currentGameState.CarDamageData.OverallEngineDamage = DamageLevel.MINOR; } else if (shared.CarDamage.Engine < trivialEngineDamageThreshold) { currentGameState.CarDamageData.OverallEngineDamage = DamageLevel.TRIVIAL; } else { currentGameState.CarDamageData.OverallEngineDamage = DamageLevel.NONE; } if (shared.CarDamage.Transmission < destroyedTransmissionThreshold) { currentGameState.CarDamageData.OverallTransmissionDamage = DamageLevel.DESTROYED; } else if (shared.CarDamage.Transmission < severeTransmissionDamageThreshold) { currentGameState.CarDamageData.OverallTransmissionDamage = DamageLevel.MAJOR; } else if (shared.CarDamage.Transmission < minorTransmissionDamageThreshold) { currentGameState.CarDamageData.OverallTransmissionDamage = DamageLevel.MINOR; } else if (shared.CarDamage.Transmission < trivialTransmissionDamageThreshold) { currentGameState.CarDamageData.OverallTransmissionDamage = DamageLevel.TRIVIAL; } else { currentGameState.CarDamageData.OverallTransmissionDamage = DamageLevel.NONE; } } //------------------------ Engine data ----------------------- currentGameState.EngineData.EngineOilPressure = shared.EngineOilPressure; currentGameState.EngineData.EngineRpm = Utilities.RpsToRpm(shared.EngineRps); currentGameState.EngineData.MaxEngineRpm = Utilities.RpsToRpm(shared.MaxEngineRps); currentGameState.EngineData.MinutesIntoSessionBeforeMonitoring = 5; if (!gotBaselineEngineData) { if (currentGameState.SessionData.SessionRunningTime > baselineEngineDataStartSeconds && currentGameState.SessionData.SessionRunningTime < baselineEngineDataFinishSeconds && isCarRunning) { baselineEngineDataSamples++; baselineEngineDataWaterTemp += shared.EngineWaterTemp; baselineEngineDataOilTemp += shared.EngineOilTemp; } else if (currentGameState.SessionData.SessionRunningTime >= baselineEngineDataFinishSeconds && baselineEngineDataSamples > 0) { gotBaselineEngineData = true; baselineEngineDataOilTemp = baselineEngineDataOilTemp / baselineEngineDataSamples; baselineEngineDataWaterTemp = baselineEngineDataWaterTemp / baselineEngineDataSamples; Console.WriteLine("Got baseline engine temps, water = " + baselineEngineDataWaterTemp + ", oil = " + baselineEngineDataOilTemp); } } else { currentGameState.EngineData.EngineOilTemp = shared.EngineOilTemp * targetEngineOilTemp / baselineEngineDataOilTemp; currentGameState.EngineData.EngineWaterTemp = shared.EngineWaterTemp * targetEngineWaterTemp / baselineEngineDataWaterTemp; } //------------------------ Fuel data ----------------------- currentGameState.FuelData.FuelUseActive = shared.FuelUseActive == 1; currentGameState.FuelData.FuelPressure = shared.FuelPressure; currentGameState.FuelData.FuelCapacity = shared.FuelCapacity; currentGameState.FuelData.FuelLeft = shared.FuelLeft; //------------------------ Penalties data ----------------------- currentGameState.PenaltiesData.CutTrackWarnings = shared.CutTrackWarnings; currentGameState.PenaltiesData.HasDriveThrough = shared.Penalties.DriveThrough > 0; currentGameState.PenaltiesData.HasSlowDown = shared.Penalties.SlowDown > 0; currentGameState.PenaltiesData.HasPitStop = shared.Penalties.PitStop > 0; currentGameState.PenaltiesData.HasStopAndGo = shared.Penalties.StopAndGo > 0; currentGameState.PenaltiesData.HasTimeDeduction = shared.Penalties.TimeDeduction > 0; ; currentGameState.PenaltiesData.NumPenalties = shared.NumPenalties; //------------------------ Pit stop data ----------------------- currentGameState.PitData.PitWindow = mapToPitWindow(shared.PitWindowStatus); currentGameState.PitData.IsMakingMandatoryPitStop = (currentGameState.PitData.PitWindow == PitWindow.Open || currentGameState.PitData.PitWindow == PitWindow.StopInProgress) && (currentGameState.PitData.OnInLap || currentGameState.PitData.OnOutLap); //------------------------ Car position / motion data ----------------------- currentGameState.PositionAndMotionData.CarSpeed = shared.CarSpeed; //------------------------ Transmission data ----------------------- currentGameState.TransmissionData.Gear = shared.Gear; //------------------------ Tyre data ----------------------- // no way to have unmatched tyre types in R3E currentGameState.TyreData.HasMatchedTyreTypes = true; currentGameState.TyreData.TireWearActive = shared.TireWearActive == 1; TyreType tyreType = mapToTyreType(shared.TireType); currentGameState.TyreData.FrontLeft_CenterTemp = shared.TireTemp.FrontLeft_Center; currentGameState.TyreData.FrontLeft_LeftTemp = shared.TireTemp.FrontLeft_Left; currentGameState.TyreData.FrontLeft_RightTemp = shared.TireTemp.FrontLeft_Right; float frontLeftTemp = (currentGameState.TyreData.FrontLeft_CenterTemp + currentGameState.TyreData.FrontLeft_LeftTemp + currentGameState.TyreData.FrontLeft_RightTemp) / 3; currentGameState.TyreData.FrontLeftTyreType = tyreType; currentGameState.TyreData.FrontLeftPressure = shared.TirePressure.FrontLeft; currentGameState.TyreData.FrontLeftPercentWear = getTyreWearPercentage(shared.CarDamage.TireFrontLeft); if (currentGameState.SessionData.IsNewLap) { currentGameState.TyreData.PeakFrontLeftTemperatureForLap = frontLeftTemp; } else if (previousGameState == null || frontLeftTemp > previousGameState.TyreData.PeakFrontLeftTemperatureForLap) { currentGameState.TyreData.PeakFrontLeftTemperatureForLap = frontLeftTemp; } currentGameState.TyreData.FrontRight_CenterTemp = shared.TireTemp.FrontRight_Center; currentGameState.TyreData.FrontRight_LeftTemp = shared.TireTemp.FrontRight_Left; currentGameState.TyreData.FrontRight_RightTemp = shared.TireTemp.FrontRight_Right; float frontRightTemp = (currentGameState.TyreData.FrontRight_CenterTemp + currentGameState.TyreData.FrontRight_LeftTemp + currentGameState.TyreData.FrontRight_RightTemp) / 3; currentGameState.TyreData.FrontRightTyreType = tyreType; currentGameState.TyreData.FrontRightPressure = shared.TirePressure.FrontRight; currentGameState.TyreData.FrontRightPercentWear = getTyreWearPercentage(shared.CarDamage.TireFrontRight); if (currentGameState.SessionData.IsNewLap) { currentGameState.TyreData.PeakFrontRightTemperatureForLap = frontRightTemp; } else if (previousGameState == null || frontRightTemp > previousGameState.TyreData.PeakFrontRightTemperatureForLap) { currentGameState.TyreData.PeakFrontRightTemperatureForLap = frontRightTemp; } currentGameState.TyreData.RearLeft_CenterTemp = shared.TireTemp.RearLeft_Center; currentGameState.TyreData.RearLeft_LeftTemp = shared.TireTemp.RearLeft_Left; currentGameState.TyreData.RearLeft_RightTemp = shared.TireTemp.RearLeft_Right; float rearLeftTemp = (currentGameState.TyreData.RearLeft_CenterTemp + currentGameState.TyreData.RearLeft_LeftTemp + currentGameState.TyreData.RearLeft_RightTemp) / 3; currentGameState.TyreData.RearLeftTyreType = tyreType; currentGameState.TyreData.RearLeftPressure = shared.TirePressure.RearLeft; currentGameState.TyreData.RearLeftPercentWear = getTyreWearPercentage(shared.CarDamage.TireRearLeft); if (currentGameState.SessionData.IsNewLap) { currentGameState.TyreData.PeakRearLeftTemperatureForLap = rearLeftTemp; } else if (previousGameState == null || rearLeftTemp > previousGameState.TyreData.PeakRearLeftTemperatureForLap) { currentGameState.TyreData.PeakRearLeftTemperatureForLap = rearLeftTemp; } currentGameState.TyreData.RearRight_CenterTemp = shared.TireTemp.RearRight_Center; currentGameState.TyreData.RearRight_LeftTemp = shared.TireTemp.RearRight_Left; currentGameState.TyreData.RearRight_RightTemp = shared.TireTemp.RearRight_Right; float rearRightTemp = (currentGameState.TyreData.RearRight_CenterTemp + currentGameState.TyreData.RearRight_LeftTemp + currentGameState.TyreData.RearRight_RightTemp) / 3; currentGameState.TyreData.RearRightTyreType = tyreType; currentGameState.TyreData.RearRightPressure = shared.TirePressure.RearRight; currentGameState.TyreData.RearRightPercentWear = getTyreWearPercentage(shared.CarDamage.TireRearRight); if (currentGameState.SessionData.IsNewLap) { currentGameState.TyreData.PeakRearRightTemperatureForLap = rearRightTemp; } else if (previousGameState == null || rearRightTemp > previousGameState.TyreData.PeakRearRightTemperatureForLap) { currentGameState.TyreData.PeakRearRightTemperatureForLap = rearRightTemp; } currentGameState.TyreData.TyreConditionStatus = CornerData.getCornerData(tyreWearThresholds, currentGameState.TyreData.FrontLeftPercentWear, currentGameState.TyreData.FrontRightPercentWear, currentGameState.TyreData.RearLeftPercentWear, currentGameState.TyreData.RearRightPercentWear); currentGameState.TyreData.TyreTempStatus = CornerData.getCornerData(CarData.tyreTempThresholds[tyreType], currentGameState.TyreData.PeakFrontLeftTemperatureForLap, currentGameState.TyreData.PeakFrontRightTemperatureForLap, currentGameState.TyreData.PeakRearLeftTemperatureForLap, currentGameState.TyreData.PeakRearRightTemperatureForLap); if (brakeTempThresholdsForPlayersCar != null) { currentGameState.TyreData.BrakeTempStatus = CornerData.getCornerData(brakeTempThresholdsForPlayersCar, shared.BrakeTemperatures.FrontLeft, shared.BrakeTemperatures.FrontRight, shared.BrakeTemperatures.RearLeft, shared.BrakeTemperatures.RearRight); } currentGameState.TyreData.LeftFrontBrakeTemp = shared.BrakeTemperatures.FrontLeft; currentGameState.TyreData.RightFrontBrakeTemp = shared.BrakeTemperatures.FrontRight; currentGameState.TyreData.LeftRearBrakeTemp = shared.BrakeTemperatures.RearLeft; currentGameState.TyreData.RightRearBrakeTemp = shared.BrakeTemperatures.RearRight; // some simple locking / spinning checks if (shared.CarSpeed > 7) { float minRotatingSpeed = 2 * (float)Math.PI * shared.CarSpeed / currentGameState.carClass.maxTyreCircumference; // I think the tyreRPS is actually radians per second... currentGameState.TyreData.LeftFrontIsLocked = Math.Abs(shared.wheel_speed.front_left) < minRotatingSpeed; currentGameState.TyreData.RightFrontIsLocked = Math.Abs(shared.wheel_speed.front_right) < minRotatingSpeed; currentGameState.TyreData.LeftRearIsLocked = Math.Abs(shared.wheel_speed.rear_left) < minRotatingSpeed; currentGameState.TyreData.RightRearIsLocked = Math.Abs(shared.wheel_speed.rear_right) < minRotatingSpeed; float maxRotatingSpeed = 2 * (float)Math.PI * shared.CarSpeed / currentGameState.carClass.minTyreCircumference; currentGameState.TyreData.LeftFrontIsSpinning = Math.Abs(shared.wheel_speed.front_left) > maxRotatingSpeed; currentGameState.TyreData.RightFrontIsSpinning = Math.Abs(shared.wheel_speed.front_right) > maxRotatingSpeed; currentGameState.TyreData.LeftRearIsSpinning = Math.Abs(shared.wheel_speed.rear_left) > maxRotatingSpeed; currentGameState.TyreData.RightRearIsSpinning = Math.Abs(shared.wheel_speed.rear_right) > maxRotatingSpeed; } currentGameState.OvertakingAids = getOvertakingAids(shared, currentGameState.carClass.carClassEnum, currentGameState.SessionData.CompletedLaps, currentGameState.SessionData.SessionType); return currentGameState; }