diff --git a/DoTelemetry.cpp b/DoTelemetry.cpp index 400bf96..ff51b98 100644 --- a/DoTelemetry.cpp +++ b/DoTelemetry.cpp @@ -4,11 +4,17 @@ #include "dotelemetry.h" #include "tmtelemetry.h" +// Forward declarations +BOOL IsRaceBeforeStart(STelemetryData* pTelemetry); +BOOL IsRaceRunning(STelemetryData* pTelemetry); +BOOL IsRaceFinished(STelemetryData* pTelemetry); + // Processing of the telemetry data void DoTelemetry(STelemetryData* pTelemetry) { TCHAR szText[MAX_CONTROLTEXT]; static int nRaceNumber = 0; // Number of attempts + static Nat32 uLapCount = 0; // Current lap static BOOL bAddFinalColumns = FALSE; // Append some stats after the end of each race // Static variables for storing values for the statistics: @@ -95,9 +101,38 @@ void DoTelemetry(STelemetryData* pTelemetry) // Race state if (pTelemetry->Current.Race.State != pTelemetry->Previous.Race.State) { - // Handle the start of a race (race state changes from "BeforeState" to "Running") - if (pTelemetry->Previous.Race.State == STelemetry::ERaceState_BeforeState && - pTelemetry->Current.Race.State == STelemetry::ERaceState_Running) + switch (pTelemetry->Current.Race.State) + { + case STelemetry::ERaceState_BeforeState: + StatusBar_SetText(hwndStatusBar, SBP_RACESTATE, szRaceBeforeStart); + break; + + case STelemetry::ERaceState_Running: + StatusBar_SetText(hwndStatusBar, SBP_RACESTATE, szRaceRunning); + break; + + case STelemetry::ERaceState_Finished: + StatusBar_SetText(hwndStatusBar, SBP_RACESTATE, szRaceFinished); + break; + + //case STelemetry::ERaceState_Eliminated: + // StatusBar_SetText(hwndStatusBar, SBP_RACESTATE, szRaceEliminated); + // break; + + default: + StatusBar_SetText(hwndStatusBar, SBP_RACESTATE, TEXT("")); + } + + // Handle the countdown + if (IsRaceBeforeStart(pTelemetry)) + { + // Reset the lap counter + uLapCount = 0; + StatusBar_SetLapCount(hwndStatusBar, SBP_LAPS, uLapCount, pTelemetry->Current.Race.NbLaps); + } + + // Handle the start of a race + if (IsRaceRunning(pTelemetry)) { uTopSpeed = 0; nNbGearchanges = 0; @@ -116,6 +151,10 @@ void DoTelemetry(STelemetryData* pTelemetry) bIsSlipping = pTelemetry->Current.Vehicle.WheelsIsSliping[0] || pTelemetry->Current.Vehicle.WheelsIsSliping[1] || pTelemetry->Current.Vehicle.WheelsIsSliping[2] || pTelemetry->Current.Vehicle.WheelsIsSliping[3]; + // Set the lap counter to 1 + uLapCount = 1; + StatusBar_SetLapCount(hwndStatusBar, SBP_LAPS, uLapCount, pTelemetry->Current.Race.NbLaps); + // Add a new race to the list-view control and increment the number of attempts if (ListView_AddRace(hwndListView, nRaceNumber + 1, COLUMN_AUTOFIT) != -1) nRaceNumber++; @@ -158,10 +197,8 @@ void DoTelemetry(STelemetryData* pTelemetry) } } - // Handle the end of a race (race state changes from "Running" to "Finished" or "BeforeStart") - if (pTelemetry->Previous.Race.State == STelemetry::ERaceState_Running && - (pTelemetry->Current.Race.State == STelemetry::ERaceState_Finished || - pTelemetry->Current.Race.State == STelemetry::ERaceState_BeforeState)) + // Handle the end of a race + if (IsRaceFinished(pTelemetry)) { // Test if the checkpoint count has increased to differ between finished and restart if (pTelemetry->Current.Race.NbCheckpoints > pTelemetry->Previous.Race.NbCheckpoints) @@ -178,29 +215,59 @@ void DoTelemetry(STelemetryData* pTelemetry) nRaceNumber--; } - switch (pTelemetry->Current.Race.State) + pTelemetry->Previous.Race.State = pTelemetry->Current.Race.State; + } + + // Number of checkpoints + if (pTelemetry->Current.Race.NbCheckpoints != pTelemetry->Previous.Race.NbCheckpoints) + { + // Add the new checkpoint time to the list-view control + Nat32 uCurrentNbCheckpoints = pTelemetry->Current.Race.NbCheckpoints; + if (uCurrentNbCheckpoints > 0 && uCurrentNbCheckpoints <= _countof(pTelemetry->Current.Race.CheckpointTimes) && + uCurrentNbCheckpoints > uMaxNbCheckpoints) { - case STelemetry::ERaceState_BeforeState: - StatusBar_SetText(hwndStatusBar, SBP_RACESTATE, szRaceBeforeStart); - break; + if (dwColumns & COL_SECTORTIMES) + ListView_AddSectorTime(hwndListView, nRaceNumber, COLUMN_AUTOFIT, uCurrentNbCheckpoints, + pTelemetry->Current.Race.CheckpointTimes[uCurrentNbCheckpoints - 1], + uCurrentNbCheckpoints >= 2 ? pTelemetry->Current.Race.CheckpointTimes[uCurrentNbCheckpoints - 2] : 0); - case STelemetry::ERaceState_Running: - StatusBar_SetText(hwndStatusBar, SBP_RACESTATE, szRaceRunning); - break; + if (dwColumns & COL_CHECKPOINTS) + ListView_AddCheckpointTime(hwndListView, nRaceNumber, COLUMN_AUTOFIT, uCurrentNbCheckpoints, + pTelemetry->Current.Race.CheckpointTimes[uCurrentNbCheckpoints - 1]); + } - case STelemetry::ERaceState_Finished: - StatusBar_SetText(hwndStatusBar, SBP_RACESTATE, szRaceFinished); - break; + // Update the lap counter after crossing the start/finish line + Nat32 uCurrentLap = uLapCount; + Nat32 uNumberOfLaps = pTelemetry->Current.Race.NbLaps; // Could be zero + Nat32 uCheckpointsPerLap = pTelemetry->Current.Race.NbCheckpointsPerLap; // Always 0 with Trackmania Turbo + + if (uCheckpointsPerLap != 0) + { + uCurrentLap = uCurrentNbCheckpoints / uCheckpointsPerLap; + // Correct the lap counter by one, except on restart and when crossing the finish line + if (uCurrentNbCheckpoints != 0 && (uCurrentLap < uNumberOfLaps || uNumberOfLaps == 0)) + uCurrentLap++; + // Keep the number of laps driven after the race is over + if (uCurrentLap < uLapCount) + uCurrentLap = uLapCount; + } + + if (uCurrentLap != uLapCount) + { + uLapCount = uCurrentLap; + StatusBar_SetLapCount(hwndStatusBar, SBP_LAPS, uLapCount, uNumberOfLaps); + } - //case STelemetry::ERaceState_Eliminated: - // StatusBar_SetText(hwndStatusBar, SBP_RACESTATE, szRaceEliminated); - // break; + // Update the checkpoint counter + _sntprintf(szText, _countof(szText), szNbCheckpoints, uCurrentNbCheckpoints); + StatusBar_SetText(hwndStatusBar, SBP_CHECKPOINTS, szText, TRUE); - default: - StatusBar_SetText(hwndStatusBar, SBP_RACESTATE, TEXT("")); - } + // Here we have to store the highest number of checkpoints per game client so that + // the list is not flooded with data when Maniaplanet and Turbo run simultaneously + if (uCurrentNbCheckpoints > pTelemetry->Previous.Race.NbCheckpoints) + uMaxNbCheckpoints = uCurrentNbCheckpoints; - pTelemetry->Previous.Race.State = pTelemetry->Current.Race.State; + pTelemetry->Previous.Race.NbCheckpoints = uCurrentNbCheckpoints; } // Map name @@ -237,45 +304,6 @@ void DoTelemetry(STelemetryData* pTelemetry) pTelemetry->Previous.Race.Time = pTelemetry->Current.Race.Time; } - // Number of respawns - if (pTelemetry->Current.Race.NbRespawns != pTelemetry->Previous.Race.NbRespawns) - { - _sntprintf(szText, _countof(szText), szNbRespawns, pTelemetry->Current.Race.NbRespawns); - StatusBar_SetText(hwndStatusBar, SBP_RESPAWNS, szText, TRUE); - - pTelemetry->Previous.Race.NbRespawns = pTelemetry->Current.Race.NbRespawns; - } - - // Number of checkpoints - if (pTelemetry->Current.Race.NbCheckpoints != pTelemetry->Previous.Race.NbCheckpoints) - { - // Add the new checkpoint time to the list-view control - Nat32 uCurrentNbCheckpoints = pTelemetry->Current.Race.NbCheckpoints; - if (uCurrentNbCheckpoints > 0 && uCurrentNbCheckpoints <= _countof(pTelemetry->Current.Race.CheckpointTimes) && - uCurrentNbCheckpoints > uMaxNbCheckpoints) - { - // BUGBUG: It looks like we can't be sure that the checkpoint time was also already updated! - if (dwColumns & COL_SECTORTIMES) - ListView_AddSectorTime(hwndListView, nRaceNumber, COLUMN_AUTOFIT, uCurrentNbCheckpoints, - pTelemetry->Current.Race.CheckpointTimes[uCurrentNbCheckpoints - 1], - uCurrentNbCheckpoints >= 2 ? pTelemetry->Current.Race.CheckpointTimes[uCurrentNbCheckpoints - 2] : 0); - - if (dwColumns & COL_CHECKPOINTS) - ListView_AddCheckpointTime(hwndListView, nRaceNumber, COLUMN_AUTOFIT, uCurrentNbCheckpoints, - pTelemetry->Current.Race.CheckpointTimes[uCurrentNbCheckpoints - 1]); - } - - // Here we have to store the highest number of checkpoints per game client so that - // the list is not flooded with data when Maniaplanet and Turbo run simultaneously - if (uCurrentNbCheckpoints > pTelemetry->Previous.Race.NbCheckpoints) - uMaxNbCheckpoints = uCurrentNbCheckpoints; - - _sntprintf(szText, _countof(szText), szNbCheckpoints, uCurrentNbCheckpoints); - StatusBar_SetText(hwndStatusBar, SBP_CHECKPOINTS, szText, TRUE); - - pTelemetry->Previous.Race.NbCheckpoints = uCurrentNbCheckpoints; - } - // Speed if (pTelemetry->Current.Vehicle.SpeedMeter != pTelemetry->Previous.Vehicle.SpeedMeter) { @@ -445,11 +473,17 @@ void DoTelemetry(STelemetryData* pTelemetry) // Map UID if (strcmp(pTelemetry->Current.Game.MapId, pTelemetry->Previous.Game.MapId) != 0) { - // Clear all races after map change if (strcmp(pTelemetry->Current.Game.MapId, "Unassigned") != 0) + { + // Clear all races after map change if (ListView_DeleteAllRaces(hwndListView)) nRaceNumber = 0; + // Reset the lap counter + uLapCount = 0; + StatusBar_SetLapCount(hwndStatusBar, SBP_LAPS, uLapCount, pTelemetry->Current.Race.NbLaps); + } + lstrcpynA(pTelemetry->Previous.Game.MapId, pTelemetry->Current.Game.MapId, _countof(pTelemetry->Previous.Game.MapId)); } @@ -512,6 +546,8 @@ void InitTelemetryData(STelemetryData* pTelemetry) pTelemetry->Previous.Race.Time = (Nat32)-2; // -1 is a regular value pTelemetry->Previous.Race.NbRespawns = (Nat32)-2; // -1 is a regular value pTelemetry->Previous.Race.NbCheckpoints = (Nat32)-1; + pTelemetry->Previous.Race.NbCheckpointsPerLap = (Nat32)-1; + pTelemetry->Previous.Race.NbLaps = (Nat32)-1; pTelemetry->Previous.Vehicle.InputSteer = -2.0f; // -1.0 is a regular value pTelemetry->Previous.Vehicle.InputGasPedal = -1.0f; @@ -525,3 +561,26 @@ void InitTelemetryData(STelemetryData* pTelemetry) pTelemetry->Previous.Vehicle.RumbleIntensity = -1.0f; pTelemetry->Previous.Vehicle.SpeedMeter = (Nat32)-1; } + +// Checks if the countdown has just started (race state changes from "Finished" or "Running" to "BeforeStart") +__inline BOOL IsRaceBeforeStart(STelemetryData* pTelemetry) +{ + return ((pTelemetry->Previous.Race.State == STelemetry::ERaceState_Finished || + pTelemetry->Previous.Race.State == STelemetry::ERaceState_Running) && + pTelemetry->Current.Race.State == STelemetry::ERaceState_BeforeState); +} + +// Checks if the race has just started (race state changes from "BeforeStart" to "Running") +__inline BOOL IsRaceRunning(STelemetryData* pTelemetry) +{ + return (pTelemetry->Previous.Race.State == STelemetry::ERaceState_BeforeState && + pTelemetry->Current.Race.State == STelemetry::ERaceState_Running); +} + +// Checks if the race has just finished (race state changes from "Running" to "Finished" or "BeforeStart") +__inline BOOL IsRaceFinished(STelemetryData* pTelemetry) +{ + return (pTelemetry->Previous.Race.State == STelemetry::ERaceState_Running && + (pTelemetry->Current.Race.State == STelemetry::ERaceState_Finished || + pTelemetry->Current.Race.State == STelemetry::ERaceState_BeforeState)); +} diff --git a/Helper.cpp b/Helper.cpp index 53ebd1d..01d94bc 100644 --- a/Helper.cpp +++ b/Helper.cpp @@ -139,6 +139,21 @@ BOOL StatusBar_SetText(HWND hwndCtl, UINT uIndexType, LPCTSTR lpszText, BOOL bCe } } +BOOL StatusBar_SetLapCount(HWND hwndCtl, UINT uIndexType, UINT uCurrentLap, UINT uNumberOfLaps, BOOL bCenter) +{ + TCHAR szText[MAX_CONTROLTEXT]; + + if (hwndCtl == NULL) + return FALSE; + + if (uNumberOfLaps == 0) + _sntprintf(szText, _countof(szText), szCurLap, uCurrentLap); + else + _sntprintf(szText, _countof(szText), szNbLaps, uCurrentLap, uNumberOfLaps); + + return StatusBar_SetText(hwndCtl, uIndexType, szText, bCenter); +} + void ListView_SelectAll(HWND hwndCtl) { diff --git a/Helper.h b/Helper.h index 37d3f19..9aa1b6a 100644 --- a/Helper.h +++ b/Helper.h @@ -24,7 +24,8 @@ const TCHAR szRaceBeforeStart[] = TEXT("Race: BeforeStart"); const TCHAR szRaceRunning[] = TEXT("Race: Running"); const TCHAR szRaceFinished[] = TEXT("Race: Finished"); const TCHAR szRaceEliminated[] = TEXT("Race: Eliminated"); -const TCHAR szNbRespawns[] = TEXT("RSP: %d"); +const TCHAR szCurLap[] = TEXT("Lap: %d"); +const TCHAR szNbLaps[] = TEXT("Lap: %d/%d"); const TCHAR szNbCheckpoints[] = TEXT("CP: %d"); const TCHAR szSpeedKmh[] = TEXT("%d km/h"); const TCHAR szSpeedMph[] = TEXT("%d mph"); @@ -59,6 +60,7 @@ BOOL GetFileName(HWND hDlg, LPTSTR lpszFileName, SIZE_T cchStringLen, LPDWORD lp // Status bar functions BOOL StatusBar_SetText(HWND hwndCtl, UINT uIndexType, LPCTSTR lpszText, BOOL bCenter = FALSE); +BOOL StatusBar_SetLapCount(HWND hwndCtl, UINT uIndexType, UINT uCurrentLap, UINT uNumberOfLaps, BOOL bCenter = TRUE); // List-view functions void ListView_SelectAll(HWND hwndCtl); diff --git a/TMTelemetry.cpp b/TMTelemetry.cpp index 77c2b59..d9e2e10 100644 --- a/TMTelemetry.cpp +++ b/TMTelemetry.cpp @@ -428,7 +428,7 @@ BOOL WndProc_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) SetWindowFont(hwndStatusBar, GetStockFont(DEFAULT_GUI_FONT), FALSE); // Set the number of parts and the coordinate of the right edge of each part - int aStatusBarParts[15] = { 125, 235, 385, 480, 555, 605, 650, 715, 790, 850, 940, 1030, 1120, 1180, -1 }; + int aStatusBarParts[15] = { 125, 235, 385, 480, 555, 620, 665, 730, 805, 865, 955, 1045, 1135, 1195, -1 }; SIZE_T uParts = _countof(aStatusBarParts); for (SIZE_T i = 0; i < (uParts - 1); i++) aStatusBarParts[i] = MulDiv(aStatusBarParts[i], nDpi, USER_DEFAULT_SCREEN_DPI); diff --git a/TMTelemetry.h b/TMTelemetry.h index fed74b6..91ebe4e 100644 --- a/TMTelemetry.h +++ b/TMTelemetry.h @@ -31,7 +31,7 @@ typedef enum _STATUSBAR_PART SBP_MAPNAME, SBP_PLAYERMODEL, SBP_RACETIME, - SBP_RESPAWNS, + SBP_LAPS, SBP_CHECKPOINTS, SBP_SPEEDMETER, SBP_ENGINERPM, diff --git a/maniaplanet_telemetry.h b/maniaplanet_telemetry.h index d645150..4fc36cf 100644 --- a/maniaplanet_telemetry.h +++ b/maniaplanet_telemetry.h @@ -38,7 +38,7 @@ struct STelemetry { }; struct SGameState { EGameState State; - char GameplayVariant[64]; // environment name 'stadium' 'canyon', .... + char GameplayVariant[64]; // player model 'StadiumCar', 'CanyonCar', .... char MapId[64]; char MapName[256]; char __future__[128]; @@ -49,14 +49,16 @@ struct STelemetry { Nat32 NbRespawns; Nat32 NbCheckpoints; Nat32 CheckpointTimes[125]; - char __future__[32]; + Nat32 NbCheckpointsPerLap; // new since Maniaplanet update 2019-10-10; not supported by Trackmania Turbo. + Nat32 NbLaps; // new since Maniaplanet update 2019-10-10; not supported by Trackmania Turbo. + char __future__[24]; }; struct SObjectState { Nat32 Timestamp; Nat32 DiscontinuityCount; // the number changes everytime the object is moved not continuously (== teleported). Quat Rotation; - Vec3 Translation; // +x is "left", +y is "up", +z is "front" - Vec3 Velocity; // (world velocity) + Vec3 Translation; // +x is "left", +y is "up", +z is "front" + Vec3 Velocity; // (world velocity) Nat32 LatestStableGroundContactTime; char __future__[32]; };