diff --git a/.gitignore b/.gitignore index bd50d9e..5a01e8b 100644 --- a/.gitignore +++ b/.gitignore @@ -92,7 +92,7 @@ typings/ out/ *storybook.log -test-data/*.png +test-data/**/*.png test-data/unused src/**/tracks/*.svg asset-data diff --git a/src/app/bridge/iracingSdk/dumpTelemetry.ts b/src/app/bridge/iracingSdk/dumpTelemetry.ts index f0d1875..4a56dc4 100644 --- a/src/app/bridge/iracingSdk/dumpTelemetry.ts +++ b/src/app/bridge/iracingSdk/dumpTelemetry.ts @@ -24,8 +24,11 @@ export async function dumpCurrentTelemetry() { await writeFile(`${dirPath}/session.json`, session, 'utf-8'), ]); console.log(`Saved to: ${dirPath}`); + return { dirPath }; } else { console.warn('No telemetry data received'); } } + + return { dirPath: null }; } diff --git a/src/app/setupTaskbar.ts b/src/app/setupTaskbar.ts index 8883d3c..e47df18 100644 --- a/src/app/setupTaskbar.ts +++ b/src/app/setupTaskbar.ts @@ -1,6 +1,8 @@ -import { nativeImage, Tray, Menu, app, globalShortcut } from 'electron'; +import { nativeImage, Tray, Menu, app, globalShortcut, desktopCapturer } from 'electron'; import { TelemetrySink } from './bridge/iracingSdk/telemetrySink'; import { OverlayManager } from './overlayManager'; +import { writeFile } from 'node:fs/promises'; +import path from 'node:path'; class Taskbar { private tray: Tray; @@ -65,11 +67,34 @@ class Taskbar { this.overlayManager.toggleLockOverlays(); } - private saveTelemetry(): void { - if (process.platform === 'darwin') return; - import('./bridge/iracingSdk/dumpTelemetry').then( - async ({ dumpCurrentTelemetry }) => await dumpCurrentTelemetry() - ); + private async saveTelemetry(): Promise { + try { + // First, import and call dumpTelemetry to get the directory path + const { dumpCurrentTelemetry } = await import('./bridge/iracingSdk/dumpTelemetry'); + const telemetryResult = await dumpCurrentTelemetry(); + + // Check if dirPath exists and is not null + const dirPath = telemetryResult && 'dirPath' in telemetryResult ? telemetryResult.dirPath : null; + if (dirPath) { + // Capture all screens + const sources = await desktopCapturer.getSources({ + types: ['screen'], + thumbnailSize: { width: 1920, height: 1080 } // Use a standard resolution + }); + + // Save each screen as a separate file + await Promise.all(sources.map(async (source, index) => { + if (source.thumbnail) { + const screenshotPath = path.join(dirPath, `screenshot_${index + 1}.png`); + const pngData = source.thumbnail.toPNG(); + await writeFile(screenshotPath, pngData); + console.log(`Screenshot ${index + 1} saved to: ${screenshotPath}`); + } + })); + } + } catch (error) { + console.error('Error capturing screenshots:', error); + } } private registerShortcuts(): void { diff --git a/src/frontend/components/Standings/hooks/useDriverRelatives.tsx b/src/frontend/components/Standings/hooks/useDriverRelatives.tsx index 7089898..963b8ec 100644 --- a/src/frontend/components/Standings/hooks/useDriverRelatives.tsx +++ b/src/frontend/components/Standings/hooks/useDriverRelatives.tsx @@ -1,50 +1,56 @@ import { useMemo } from 'react'; import { useDriverCarIdx, + useSessionStore, useTelemetryValues, } from '@irdashies/context'; import { useDriverStandings } from './useDriverPositions'; export const useDriverRelatives = ({ buffer }: { buffer: number }) => { - const carIdxEstTime = useTelemetryValues('CarIdxEstTime'); const drivers = useDriverStandings(); const carIdxLapDistPct = useTelemetryValues('CarIdxLapDistPct'); + const carIdxLap = useTelemetryValues('CarIdxLap'); + const playerIndex = useDriverCarIdx(); + const driverCarEstLapTime = useSessionStore( + (s) => s.session?.DriverInfo?.DriverCarEstLapTime ?? 0 + ); const standings = useMemo(() => { - const player = drivers.find((d) => d.carIdx === playerIndex); - if (!player) { - return []; - } + const calculateDelta = (otherCarIdx: number) => { + const playerCarIdx = playerIndex ?? 0; - const driverEstLapTime = player.carClass.estLapTime ?? 0; + const playerLapNum = carIdxLap?.[playerCarIdx]; + const playerDistPct = carIdxLapDistPct?.[playerCarIdx]; - const calculateDelta = (carIdx: number, isAhead: boolean) => { - const playerEstTime = carIdxEstTime?.[playerIndex ?? 0]; - const oppositionEstTime = carIdxEstTime?.[carIdx]; - const opposition = drivers.find((d) => d.carIdx === carIdx); + const otherLapNum = carIdxLap?.[otherCarIdx]; + const otherDistPct = carIdxLapDistPct?.[otherCarIdx]; - if (!opposition) { - return 0; + if ( + playerLapNum === undefined || playerLapNum < 0 || + playerDistPct === undefined || playerDistPct < 0 || playerDistPct > 1 || + otherLapNum === undefined || otherLapNum < 0 || + otherDistPct === undefined || otherDistPct < 0 || otherDistPct > 1 || + driverCarEstLapTime <= 0 + ) { + return NaN; } - let delta = (oppositionEstTime - playerEstTime); + let distPctDifference = otherDistPct - playerDistPct; - if (isAhead) { - // For cars ahead, use their lap time since they determine the full lap duration - while (delta < 0) delta += driverEstLapTime; - while (delta > 0.5 * driverEstLapTime) delta -= driverEstLapTime; - } else { - // For cars behind, use player's lap time since we're measuring against our lap - while (delta > 0) delta -= driverEstLapTime; - while (delta < -0.5 * driverEstLapTime) delta += driverEstLapTime; + if (distPctDifference > 0.5) { + distPctDifference -= 1.0; + } else if (distPctDifference < -0.5) { + distPctDifference += 1.0; } + + const timeDelta = distPctDifference * driverCarEstLapTime; - return delta; + return timeDelta; }; const isHalfLapDifference = (car1: number, car2: number) => { - const diff = (car1 - car2 + 1) % 1; // Normalize the difference to [0, 1) + const diff = (car1 - car2 + 1) % 1; return diff <= 0.5; }; @@ -60,7 +66,7 @@ export const useDriverRelatives = ({ buffer }: { buffer: number }) => { }) .map((result) => ({ ...result, - delta: calculateDelta(result.carIdx, isAhead), + delta: calculateDelta(result.carIdx), })) .filter((result) => (isAhead ? result.delta > 0 : result.delta < 0)) .sort((a, b) => (isAhead ? a.delta - b.delta : b.delta - a.delta)) @@ -69,14 +75,24 @@ export const useDriverRelatives = ({ buffer }: { buffer: number }) => { }; const carsAhead = filterAndMapDrivers(true); + const player = drivers.find((result) => result.carIdx === playerIndex); const carsBehind = filterAndMapDrivers(false); - const relatives = [...carsAhead, { ...player, delta: 0 }, ...carsBehind]; + if (!player) { + return []; + } - // TODO: remove pace car if not under caution or pacing + const relatives = [...carsAhead, { ...player, delta: 0 }, ...carsBehind]; return relatives; - }, [drivers, buffer, carIdxEstTime, playerIndex, carIdxLapDistPct]); + }, [ + drivers, + buffer, + playerIndex, + driverCarEstLapTime, + carIdxLapDistPct, + carIdxLap, + ]); return standings; }; diff --git a/src/frontend/components/TrackMap/hooks/useTrackId.tsx b/src/frontend/components/TrackMap/hooks/useTrackId.tsx index b68531e..a73b823 100644 --- a/src/frontend/components/TrackMap/hooks/useTrackId.tsx +++ b/src/frontend/components/TrackMap/hooks/useTrackId.tsx @@ -2,7 +2,7 @@ import { useSessionStore } from '@irdashies/context'; export const useTrackId = () => { const trackId = useSessionStore( - (state) => state.session?.WeekendInfo.TrackID + (state) => state.session?.WeekendInfo?.TrackID ); return trackId; };