diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34ac3bd..7fd0c36 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,14 +41,7 @@ jobs: - name: Install dependencies if: steps.cache-deps.outputs.cache-hit != 'true' - run: | - npm ci --ignore-scripts - npm run prepare - npm rebuild - - - name: Apply patches and rebuild - if: steps.cache-deps.outputs.cache-hit == 'true' - run: npm run prepare + run: npm ci - name: Run linting run: npm run lint diff --git a/.gitignore b/.gitignore index 795f565..bd50d9e 100644 --- a/.gitignore +++ b/.gitignore @@ -99,3 +99,7 @@ asset-data # should be generated with script src/**/tracks/tracks.json + +# native build +build/ +bin/ \ No newline at end of file diff --git a/README.md b/README.md index ca7b269..651a23b 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This project is still in the early stages of development, so there may be bugs a ## Introduction -This project is built with React and Electron and uses ths iRacing SDK via [irsdk-node](https://github.com/bengsfort/irsdk-node) library to retrieve data from the iRacing live telemetry memory-map. +This project is built with React and Electron and uses the iRacing SDK to retrieve data from the iRacing live telemetry memory-map. ## Installation @@ -87,6 +87,7 @@ irdashies/ ``` - `src/app/` contains the main Electron application code. +- `src/app/irsdk/` contains the iRacing SDK code including the native C++ bindings. - `src/frontend/` contains the React components for the overlays. - `src/types/` contains TypeScript type definitions shared between the frontend and backend (e.g. telemetry types). diff --git a/binding.gyp b/binding.gyp new file mode 100644 index 0000000..f7e3e4f --- /dev/null +++ b/binding.gyp @@ -0,0 +1,27 @@ +{ + "targets": [ + { + "target_name": "irsdk_node", + "sources": [], + "defines": [ + "NAPI_DISABLE_CPP_EXCEPTIONS", + ], + "include_dirs": [ + "=18" - } - }, - "node_modules/@irsdk-node/types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@irsdk-node/types/-/types-3.0.0.tgz", - "integrity": "sha512-A+3u0mPRNxYaJqKamA0c8hLkiR3cIkwANX190oXgLTxMw2AnF2QQJ5jTqoxSZXxysOr/iZFaVyxNciCPOyqWzw==", - "engines": { - "node": ">=16" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -2453,45 +2428,6 @@ "node": ">= 8" } }, - "node_modules/@npmcli/agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", - "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", - "license": "ISC", - "optional": true, - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/agent/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC", - "optional": true - }, - "node_modules/@npmcli/agent/node_modules/socks-proxy-agent": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", - "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", - "license": "MIT", - "optional": true, - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/@npmcli/fs": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", @@ -4456,6 +4392,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/js-yaml": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/jsdom": { "version": "21.1.7", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", @@ -5050,13 +4993,6 @@ "node": ">=10.0.0" } }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true, - "license": "BSD-2-Clause" - }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -5118,7 +5054,7 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 14" @@ -5141,7 +5077,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", @@ -5188,7 +5124,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5198,7 +5134,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -5564,7 +5500,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/base32-encode": { @@ -5637,16 +5573,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -6115,7 +6041,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "devOptional": true, + "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -6155,27 +6081,11 @@ "node": ">=6.0" } }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -6332,7 +6242,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -6345,7 +6255,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/colorette": { @@ -6460,7 +6370,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -7005,7 +6915,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -7302,7 +7212,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/ee-first": { @@ -7945,7 +7855,7 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/encode-utf8": { @@ -7970,6 +7880,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -8017,7 +7928,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -8027,7 +7938,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/error-ex": { @@ -8743,7 +8654,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz", "integrity": "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==", - "devOptional": true, + "dev": true, "license": "Apache-2.0" }, "node_modules/express": { @@ -8933,13 +8844,6 @@ "node": ">=16.0.0" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT", - "optional": true - }, "node_modules/filename-reserved-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", @@ -9044,16 +8948,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-yarn-workspace-root": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", - "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "micromatch": "^4.0.2" - } - }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -9141,7 +9035,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -9158,7 +9052,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "devOptional": true, + "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -9236,7 +9130,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -9673,7 +9567,7 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/graphemer": { @@ -9808,7 +9702,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause" }, "node_modules/http-cookie-agent": { @@ -9857,7 +9751,7 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -9885,7 +9779,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -9994,7 +9888,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -10004,7 +9898,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10084,7 +9978,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "jsbn": "1.1.0", @@ -10104,22 +9998,6 @@ "node": ">= 0.10" } }, - "node_modules/irsdk-node": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/irsdk-node/-/irsdk-node-4.0.1.tgz", - "integrity": "sha512-RYiVwRZCg16/SCsqZRdcrvCiW9eiU9nqAXvjkyvDM/88M4D+mlQXo07L2RZMqzmEGPE+YE5M8M/Vy1AzE4jCIQ==", - "dependencies": { - "@irsdk-node/types": "^3.0.0", - "js-yaml": "^4.1.0", - "module-alias": "^2.2.2" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@irsdk-node/native": "^4.0.0" - } - }, "node_modules/is-arguments": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", @@ -10380,7 +10258,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/is-map": { @@ -10682,7 +10560,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { @@ -10761,7 +10639,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "devOptional": true, + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -10806,7 +10684,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/jsdoc-type-pratt-parser": { @@ -10909,26 +10787,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-stable-stringify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.2.1.tgz", - "integrity": "sha512-Lp6HbbBgosLmJbjx0pBLbgvx68FaFU1sdkmBuckmhhJ88kL13OA51CDtR2yJB50eCNMH9wRqtQNNiAqQH4YXnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "isarray": "^2.0.5", - "jsonify": "^0.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -10970,16 +10828,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsonify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", - "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", - "dev": true, - "license": "Public Domain", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/jsonpointer": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", @@ -11027,16 +10875,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/klaw-sync": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", - "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.11" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -11818,7 +11656,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -11862,7 +11700,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -11875,7 +11713,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -11888,7 +11726,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -11901,14 +11739,14 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "minipass": "^3.0.0", @@ -11922,14 +11760,14 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" @@ -11938,12 +11776,6 @@ "node": ">=10" } }, - "node_modules/module-alias": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz", - "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==", - "license": "MIT" - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -12001,7 +11833,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -12031,8 +11863,8 @@ "version": "8.3.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz", "integrity": "sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==", + "dev": true, "license": "MIT", - "optional": true, "engines": { "node": "^18 || ^20 || >= 21" } @@ -12093,345 +11925,50 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/node-gyp": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.3.1.tgz", - "integrity": "sha512-Pp3nFHBThHzVtNY7U6JfPjvT/DTE8+o/4xKsLQtBoU+j2HLsGlhcfzflAoUreaJbNmYnX+LlLi0qjV8kpyO6xQ==", - "license": "MIT", - "optional": true, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "license": "ISC", "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^13.0.0", - "nopt": "^7.0.0", - "proc-log": "^4.1.0", - "semver": "^7.3.5", - "tar": "^6.2.1", - "which": "^4.0.0" + "abbrev": "^1.0.0" }, "bin": { - "node-gyp": "bin/node-gyp.js" + "nopt": "bin/nopt.js" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/node-gyp/node_modules/@npmcli/fs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", - "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", - "license": "ISC", - "optional": true, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, - "node_modules/node-gyp/node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, "license": "ISC", - "optional": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "optional": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/node-gyp/node_modules/cacache": { - "version": "18.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", - "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "license": "ISC", - "optional": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "license": "ISC", - "optional": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/node-gyp/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC", - "optional": true - }, - "node_modules/node-gyp/node_modules/make-fetch-happen": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", - "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", - "license": "ISC", - "optional": true, - "dependencies": { - "@npmcli/agent": "^2.0.0", - "cacache": "^18.0.0", - "http-cache-semantics": "^4.1.1", - "is-lambda": "^1.0.1", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "proc-log": "^4.2.0", - "promise-retry": "^2.0.1", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", - "optional": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "optional": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/node-gyp/node_modules/minipass-collect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/node-gyp/node_modules/minipass-fetch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", - "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", - "license": "MIT", - "optional": true, - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/node-gyp/node_modules/nopt": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", - "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", - "license": "ISC", - "optional": true, - "dependencies": { - "abbrev": "^2.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/proc-log": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", - "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", - "license": "ISC", - "optional": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/ssri": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", - "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "license": "ISC", - "optional": true, - "dependencies": { - "unique-slug": "^4.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "license": "ISC", - "optional": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "dev": true, - "license": "MIT" - }, - "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "dev": true, - "license": "ISC", - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" + "bin": { + "semver": "bin/semver" } }, "node_modules/normalize-range": { @@ -12634,23 +12171,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -12733,16 +12253,6 @@ "node": ">=8" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/own-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", @@ -12837,7 +12347,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" @@ -12863,7 +12373,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "devOptional": true, + "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { @@ -12946,67 +12456,6 @@ "node": ">= 0.8" } }, - "node_modules/patch-package": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz", - "integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@yarnpkg/lockfile": "^1.1.0", - "chalk": "^4.1.2", - "ci-info": "^3.7.0", - "cross-spawn": "^7.0.3", - "find-yarn-workspace-root": "^2.0.0", - "fs-extra": "^9.0.0", - "json-stable-stringify": "^1.0.2", - "klaw-sync": "^6.0.0", - "minimist": "^1.2.6", - "open": "^7.4.2", - "rimraf": "^2.6.3", - "semver": "^7.5.3", - "slash": "^2.0.0", - "tmp": "^0.0.33", - "yaml": "^2.2.2" - }, - "bin": { - "patch-package": "index.js" - }, - "engines": { - "node": ">=14", - "npm": ">5" - } - }, - "node_modules/patch-package/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/patch-package/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -13031,7 +12480,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13048,7 +12497,7 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "devOptional": true, + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -13065,14 +12514,14 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/path-scurry/node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "devOptional": true, + "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -13362,7 +12811,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "err-code": "^2.0.2", @@ -14007,7 +13456,7 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -14255,7 +13704,7 @@ "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "devOptional": true, + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -14437,7 +13886,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -14450,7 +13899,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14546,16 +13995,6 @@ "dev": true, "license": "ISC" }, - "node_modules/slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/slice-ansi": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", @@ -14590,7 +14029,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 6.0.0", @@ -14601,7 +14040,7 @@ "version": "2.8.4", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ip-address": "^9.0.5", @@ -14711,7 +14150,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause" }, "node_modules/ssri": { @@ -14818,7 +14257,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -14837,7 +14276,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -14852,14 +14291,14 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14869,7 +14308,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -14980,7 +14419,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -14997,7 +14436,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -15010,7 +14449,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -15173,7 +14612,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "chownr": "^2.0.0", @@ -15191,7 +14630,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "devOptional": true, + "dev": true, "license": "ISC", "engines": { "node": ">=8" @@ -15201,7 +14640,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/temp": { @@ -15442,19 +14881,6 @@ "dev": true, "license": "MIT" }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/tmp-promise": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", @@ -16422,7 +15848,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -16554,7 +15980,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -16573,7 +15999,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -16591,14 +16017,14 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -16608,7 +16034,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -16623,7 +16049,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -16636,7 +16062,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -16765,6 +16191,8 @@ "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", "dev": true, "license": "ISC", + "optional": true, + "peer": true, "bin": { "yaml": "bin.mjs" }, diff --git a/package.json b/package.json index 6c3e5f0..71d3c02 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,7 @@ "lint": "eslint --ext .ts,.tsx .", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", - "test": "vitest --coverage", - "prepare": "patch-package" + "test": "vitest --coverage" }, "devDependencies": { "@chromatic-com/storybook": "^3.2.2", @@ -46,6 +45,7 @@ "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.2.0", "@types/d3": "^7.4.3", + "@types/js-yaml": "^4.0.9", "@types/jsdom": "^21.1.7", "@types/react": "^19.0.12", "@types/react-dom": "^19.0.4", @@ -61,7 +61,7 @@ "eslint-plugin-storybook": "^0.12.0", "globals": "^16.0.0", "jsdom": "^26.0.0", - "patch-package": "^8.0.0", + "node-addon-api": "^8.3.1", "postcss": "^8.5.3", "prettier": "^3.5.3", "storybook": "^8.4.7", @@ -85,7 +85,7 @@ "@phosphor-icons/react": "^2.1.7", "d3": "^7.9.0", "electron-squirrel-startup": "^1.0.1", - "irsdk-node": "^4.0.1", + "js-yaml": "^4.1.0", "react": "^19.1.0", "react-dom": "^19.1.0", "react-router-dom": "^7.4.1", diff --git a/patches/@irsdk-node+native+4.0.1.patch b/patches/@irsdk-node+native+4.0.1.patch deleted file mode 100644 index d0b0fc3..0000000 --- a/patches/@irsdk-node+native+4.0.1.patch +++ /dev/null @@ -1,36 +0,0 @@ -diff --git a/node_modules/@irsdk-node/native/lib/irsdk_utils.cpp b/node_modules/@irsdk-node/native/lib/irsdk_utils.cpp -index ef91e3b..f807651 100644 ---- a/node_modules/@irsdk-node/native/lib/irsdk_utils.cpp -+++ b/node_modules/@irsdk-node/native/lib/irsdk_utils.cpp -@@ -338,7 +338,7 @@ unsigned int irsdk_getBroadcastMsgID() - - void irsdk_broadcastMsg(irsdk_BroadcastMsg msg, int var1, int var2, int var3) - { -- irsdk_broadcastMsg(msg, var1, MAKELONG(var2, var3)); -+ irsdk_broadcastMsg(msg, var1, static_castMAKELONG(var2, var3)); - } - - void irsdk_broadcastMsg(irsdk_BroadcastMsg msg, int var1, float var2) -diff --git a/node_modules/@irsdk-node/native/src/irsdk_node.h b/node_modules/@irsdk-node/native/src/irsdk_node.h -index bc39c64..6567d3b 100644 ---- a/node_modules/@irsdk-node/native/src/irsdk_node.h -+++ b/node_modules/@irsdk-node/native/src/irsdk_node.h -@@ -32,12 +32,12 @@ private: - Napi::Value __GetTelemetryTypes(const Napi::CallbackInfo &info); - Napi::Value GetTelemetryVar(const Napi::CallbackInfo &info); - -- bool iRacingSdkNode::GetTelemetryBool(int entry, int index); -- int iRacingSdkNode::GetTelemetryInt(int entry, int index); -- float iRacingSdkNode::GetTelemetryFloat(int entry, int index); -- double iRacingSdkNode::GetTelemetryDouble(int entry, int index); -- Napi::Object iRacingSdkNode::GetTelemetryVarByIndex(const Napi::Env env, int index); -- Napi::Object iRacingSdkNode::GetTelemetryVar(const Napi::Env env, const char *varName); -+ bool GetTelemetryBool(int entry, int index); -+ int GetTelemetryInt(int entry, int index); -+ float GetTelemetryFloat(int entry, int index); -+ double GetTelemetryDouble(int entry, int index); -+ Napi::Object GetTelemetryVarByIndex(const Napi::Env env, int index); -+ Napi::Object GetTelemetryVar(const Napi::Env env, const char *varName); - - bool _loggingEnabled; - char* _data; diff --git a/src/app/bridge/iracingSdk/dumpTelemetry.ts b/src/app/bridge/iracingSdk/dumpTelemetry.ts index 41fd16b..f0d1875 100644 --- a/src/app/bridge/iracingSdk/dumpTelemetry.ts +++ b/src/app/bridge/iracingSdk/dumpTelemetry.ts @@ -1,7 +1,7 @@ import path from 'node:path'; import { writeFile, mkdir } from 'node:fs/promises'; import { app } from 'electron'; -import { IRacingSDK } from 'irsdk-node'; +import { IRacingSDK } from '../../irsdk'; export async function dumpCurrentTelemetry() { console.log('Starting...'); diff --git a/src/app/bridge/iracingSdk/iracingSdkBridge.ts b/src/app/bridge/iracingSdk/iracingSdkBridge.ts index fe2d050..a8b1862 100644 --- a/src/app/bridge/iracingSdk/iracingSdkBridge.ts +++ b/src/app/bridge/iracingSdk/iracingSdkBridge.ts @@ -1,6 +1,6 @@ -import { IRacingSDK } from 'irsdk-node'; +import { IRacingSDK } from '../../irsdk'; import { TelemetrySink } from './telemetrySink'; -import { OverlayManager } from 'src/app/overlayManager'; +import { OverlayManager } from '../../overlayManager'; import type { IrSdkBridge, Session, Telemetry } from '@irdashies/types'; const TIMEOUT = 1000; diff --git a/src/app/bridge/iracingSdk/setup.ts b/src/app/bridge/iracingSdk/setup.ts index 44dccb6..701a20d 100644 --- a/src/app/bridge/iracingSdk/setup.ts +++ b/src/app/bridge/iracingSdk/setup.ts @@ -37,7 +37,7 @@ async function setupBridge( } const module = - isDemoMode || process.platform === 'darwin' + isDemoMode || process.platform !== 'win32' ? await import('./mock-data/mockSdkBridge') : await import('./iracingSdkBridge'); diff --git a/src/app/irsdk/index.ts b/src/app/irsdk/index.ts new file mode 100644 index 0000000..251081a --- /dev/null +++ b/src/app/irsdk/index.ts @@ -0,0 +1 @@ +export * from './node'; \ No newline at end of file diff --git a/src/app/irsdk/native/binding.gyp b/src/app/irsdk/native/binding.gyp new file mode 100644 index 0000000..14bc2ed --- /dev/null +++ b/src/app/irsdk/native/binding.gyp @@ -0,0 +1,19 @@ +{ + "targets": [ + { + "target_name": "irsdk_node", + "sources": [ + "src/irsdk_node.cc", + "lib/irsdk_utils.cpp", + "lib/yaml_parser.cpp", + "lib/irsdk_defines.h" + ], + "defines": [ + "NAPI_DISABLE_CPP_EXCEPTIONS", + ], + "include_dirs": [ + "; + +export interface INativeSDK { + readonly currDataVersion: number; + enableLogging: boolean; + + // Main API + // Control + startSDK(): boolean; + stopSDK(): void; + + // State + isRunning(): boolean; + waitForData(timeout?: number): boolean; + getSessionData(): string; // full yaml + getTelemetryData(): TelemetryVarList; + + getTelemetryVariable(index: number): TelemetryVariable; + // eslint-disable-next-line @typescript-eslint/unified-signatures + getTelemetryVariable(name: string): TelemetryVariable; + + // Broadcast command overloads + // This is handled in the cpp side so no need to mess with it in js + broadcast(message: BroadcastMessages.CameraSwitchPos, pos: number, group: number, camera: number): void; + // eslint-disable-next-line @typescript-eslint/unified-signatures + broadcast(message: BroadcastMessages.CameraSwitchNum, driver: number, group: number, camera: number): void; + broadcast(message: BroadcastMessages.CameraSetState, state: CameraState): void; + broadcast(message: BroadcastMessages.ReplaySetPlaySpeed, speed: number, slowMotion: number): void; + broadcast(message: BroadcastMessages.ReplaySetPlayPosition, pos: ReplayPositionCommand, frame: number): void; + broadcast(message: BroadcastMessages.ReplaySearch, mode: ReplaySearchCommand): void; + broadcast(message: BroadcastMessages.ReplaySetState, state: ReplayStateCommand): void; + broadcast(message: BroadcastMessages.ReloadTextures, command: ReloadTexturesCommand, carIndex?: number): void; + broadcast(message: BroadcastMessages.ChatCommand, command: ChatCommand, macro?: number): void; + broadcast(message: BroadcastMessages.PitCommand, command: PitCommand, param?: number): void; + broadcast(message: BroadcastMessages.TelemCommand, command: TelemetryCommand): void; + broadcast(message: BroadcastMessages.FFBCommand, command: FFBCommand, value: number): void; + // eslint-disable-next-line @typescript-eslint/unified-signatures + broadcast(message: BroadcastMessages.ReplaySearchSessionTime, session: number, time: number): void; + broadcast(message: BroadcastMessages.VideoCapture, command: VideoCaptureCommand): void; +} + +export class NativeSDK implements INativeSDK { + public readonly currDataVersion: number; + + public enableLogging: boolean; + + constructor(); + + // Main API + // Control + public startSDK(): boolean; + + public stopSDK(): void; + + // State + public isRunning(): boolean; + + public waitForData(timeout?: number): boolean; + + public getSessionData(): string; // full yaml + + public getTelemetryData(): TelemetryVarList; + + public getTelemetryVariable(index: number): TelemetryVariable; + + // eslint-disable-next-line @typescript-eslint/unified-signatures + public getTelemetryVariable(name: string): TelemetryVariable; + + // Private helpers + public __getTelemetryTypes(): TelemetryTypesDict; + + // Broadcast command overloads + // This is handled in the cpp side so no need to mess with it in js + public broadcast(message: BroadcastMessages.CameraSwitchPos, pos: number, group: number, camera: number): void; + + // eslint-disable-next-line @typescript-eslint/unified-signatures + public broadcast(message: BroadcastMessages.CameraSwitchNum, driver: number, group: number, camera: number): void; + + public broadcast(message: BroadcastMessages.CameraSetState, state: CameraState): void; + + public broadcast(message: BroadcastMessages.ReplaySetPlaySpeed, speed: number, slowMotion: number): void; + + public broadcast(message: BroadcastMessages.ReplaySetPlayPosition, pos: ReplayPositionCommand, frame: number): void; + + public broadcast(message: BroadcastMessages.ReplaySearch, mode: ReplaySearchCommand): void; + + public broadcast(message: BroadcastMessages.ReplaySetState, state: ReplayStateCommand): void; + + public broadcast(message: BroadcastMessages.ReloadTextures, command: ReloadTexturesCommand, carIndex?: number): void; + + public broadcast(message: BroadcastMessages.ChatCommand, command: ChatCommand, macro?: number): void; + + public broadcast(message: BroadcastMessages.PitCommand, command: PitCommand, param?: number): void; + + public broadcast(message: BroadcastMessages.TelemCommand, command: TelemetryCommand): void; + + public broadcast(message: BroadcastMessages.FFBCommand, command: FFBCommand, value: number): void; + + // eslint-disable-next-line @typescript-eslint/unified-signatures + public broadcast(message: BroadcastMessages.ReplaySearchSessionTime, session: number, time: number): void; + + public broadcast(message: BroadcastMessages.VideoCapture, command: VideoCaptureCommand): void; +} + +// export const DebugSDK: typeof NativeSDK; diff --git a/src/app/irsdk/native/index.js b/src/app/irsdk/native/index.js new file mode 100644 index 0000000..3685412 --- /dev/null +++ b/src/app/irsdk/native/index.js @@ -0,0 +1,7 @@ +// Import from JS so that we can type the API in a nicer way (without aliases) +// The alternative would be to somehow get types generated, or use aliases to +// fake a module and then define that module... but those are gross, so no thanks +// eslint-disable-next-line @typescript-eslint/no-require-imports +export const NativeSDK = require('../build/Release/irsdk_node.node').iRacingSdkNode; +// @todo For some reason this is not being built when being downloaded. It runs via prepack, but not in the built version. +// export const DebugSDK = require("../build/Debug/irsdk_node.node").iRacingSdkNode; diff --git a/src/app/irsdk/native/irsdk_node.cc b/src/app/irsdk/native/irsdk_node.cc new file mode 100644 index 0000000..c1b15c5 --- /dev/null +++ b/src/app/irsdk/native/irsdk_node.cc @@ -0,0 +1,523 @@ +#include "./irsdk_node.h" +#include "./lib/yaml_parser.h" + +/* +Nan::SetPrototypeMethod(tmpl, "getSessionData", GetSessionData); +Nan::SetPrototypeMethod(tmpl, "getSessionVersionNum", GetSessionVersionNum); +Nan::SetPrototypeMethod(tmpl, "getTelemetryData", GetTelemetryData); +Nan::SetPrototypeMethod(tmpl, "broadcast", BroadcastMessage); +Nan::SetPrototypeMethod(tmpl, "__getTelemetryTypes", __GetTelemetryTypes); +*/ + +// --------------------------- +// Constructors +// --------------------------- +Napi::Object iRacingSdkNode::Init(Napi::Env env, Napi::Object exports) +{ + Napi::Function func = DefineClass(env, "iRacingSdkNode", { + // Properties + InstanceAccessor<&iRacingSdkNode::GetCurrSessionDataVersion>("currDataVersion"), + InstanceAccessor<&iRacingSdkNode::GetEnableLogging, &iRacingSdkNode::SetEnableLogging>("enableLogging"), + // Methods + //Control + InstanceMethod<&iRacingSdkNode::StartSdk>("startSDK"), + InstanceMethod("stopSDK", &iRacingSdkNode::StopSdk), + InstanceMethod("waitForData", &iRacingSdkNode::WaitForData), + InstanceMethod("broadcast", &iRacingSdkNode::BroadcastMessage), + // Getters + InstanceMethod("isRunning", &iRacingSdkNode::IsRunning), + InstanceMethod("getSessionVersionNum", &iRacingSdkNode::GetSessionVersionNum), + InstanceMethod("getSessionData", &iRacingSdkNode::GetSessionData), + InstanceMethod("getTelemetryData", &iRacingSdkNode::GetTelemetryData), + InstanceMethod("getTelemetryVariable", &iRacingSdkNode::GetTelemetryVar), + // Helpers + InstanceMethod("__getTelemetryTypes", &iRacingSdkNode::__GetTelemetryTypes) + }); + + Napi::FunctionReference* constructor = new Napi::FunctionReference(); + *constructor = Napi::Persistent(func); + env.SetInstanceData(constructor); + + exports.Set("iRacingSdkNode", func); + return exports; +} + +iRacingSdkNode::iRacingSdkNode(const Napi::CallbackInfo &info) + : Napi::ObjectWrap(info) + , _data(NULL) + , _bufLineLen(0) + , _sessionStatusID(0) + , _lastSessionCt(-1) + , _sessionData(NULL) + , _loggingEnabled(false) +{ + printf("Initializing cpp class instance...\n"); +} + +// --------------------------- +// Property implementations +// --------------------------- +Napi::Value iRacingSdkNode::GetCurrSessionDataVersion(const Napi::CallbackInfo &info) +{ + int ver = this->_lastSessionCt; + return Napi::Number::New(info.Env(), ver); +} + +Napi::Value iRacingSdkNode::GetEnableLogging(const Napi::CallbackInfo &info) +{ + bool enabled = this->_loggingEnabled; + return Napi::Boolean::New(info.Env(), enabled); +} + +void iRacingSdkNode::SetEnableLogging(const Napi::CallbackInfo &info, const Napi::Value &value) +{ + Napi::Boolean enable; + if (info.Length() <= 0 || !info[0].IsBoolean()) { + enable = Napi::Boolean::New(info.Env(), false); + } else { + enable = info[0].As(); + } + printf("Setting logging enabled: %i\n", info[0]); + this->_loggingEnabled = enable; +} + +// --------------------------- +// Instance implementations +// --------------------------- +// SDK Control +Napi::Value iRacingSdkNode::StartSdk(const Napi::CallbackInfo &info) +{ + printf("Starting SDK...\n"); + if (!irsdk_isConnected()) { + bool result = irsdk_startup(); + printf("Connected at least! %i\n", result); + return Napi::Boolean::New(info.Env(), result); + } + return Napi::Boolean::New(info.Env(), true); +} + +Napi::Value iRacingSdkNode::StopSdk(const Napi::CallbackInfo &info) +{ + irsdk_shutdown(); + return Napi::Boolean::New(info.Env(), true); +} + +Napi::Value iRacingSdkNode::WaitForData(const Napi::CallbackInfo &info) +{ + // Figure out the time to wait + // This will default to the timeout set on the class + Napi::Number timeout; + if (info.Length() <= 0 || !info[0].IsNumber()) { + timeout = Napi::Number::New(info.Env(), 16); + } else { + timeout = info[0].As(); + } + + if (!irsdk_isConnected() && !irsdk_startup()) { + return Napi::Boolean::New(info.Env(), false); + } + + // @todo: try to do this async instead + const irsdk_header* header = irsdk_getHeader(); + + // @todo: This isn't the best way of doing this. Need to improve, but this works for now + if (!this->_data) { + this->_data = new char[header->bufLen]; + } + + // wait for start of sesh or new data + bool dataReady = irsdk_waitForDataReady(timeout, this->_data); + if (dataReady && header) + { + if (this->_loggingEnabled) ("Session started or we have new data.\n"); + + // New connection or data changed length + if (this->_bufLineLen != header->bufLen) { + if (this->_loggingEnabled) printf("Connection started / data changed length.\n"); + + this->_bufLineLen = header->bufLen; + + // Increment connection + this->_sessionStatusID++; + + // Reset info str status + this->_lastSessionCt = -1; + return Napi::Boolean::New(info.Env(), true); + } else if (this->_data) { + if (this->_loggingEnabled) printf("Data initialized and ready to process.\n"); + // already initialized and ready to process + return Napi::Boolean::New(info.Env(), true); + } + } + else if (!(this->_data != NULL && irsdk_isConnected())) + { + printf("Session ended. Cleaning up.\n"); + // Session ended + if (this->_data) delete[] this->_data; + this->_data = NULL; + + // Reset Info str + this->_lastSessionCt = -1; + } + printf("Session ended or something went wrong. Not successful.\n"); + return Napi::Boolean::New(info.Env(), false); +} + +Napi::Value iRacingSdkNode::BroadcastMessage(const Napi::CallbackInfo &info) +{ + auto env = info.Env(); + + // Determine message type + if (info.Length() <= 2 || !info[0].IsNumber()) { + return Napi::Boolean::New(env, false); + } + + if (info.Length() == 4 && !info[2].IsNumber()) { + return Napi::Boolean::New(env, false); + } + + int msgEnumIndex = info[0].As(); + irsdk_BroadcastMsg msgType = static_cast(msgEnumIndex); + + // Args + int arg1 = info[1].As(); + auto arg2 = info[2].As(); + auto arg3 = info[3].As(); + + // these defs are in irsdk_defines.cpp + switch (msgType) + { + // irsdk_BroadcastMsg msg, int arg1, int arg2, int var3 + case irsdk_BroadcastCamSwitchPos: // @todo we need to use irsdk_padCarNum for arg1 + case irsdk_BroadcastCamSwitchNum: + printf("BroadcastMessage(msgType: %d, arg1: %d, arg2: %d, arg3: %d)\n", msgType, arg1, arg2.Int32Value(), arg3.Int32Value()); + irsdk_broadcastMsg(msgType, arg1, arg2, arg3); + break; + + // irsdk_BroadcastMsg msg, int arg1, int unused, int unused + case irsdk_BroadcastReplaySearch: // arg1 == irsdk_RpySrchMode + case irsdk_BroadcastReplaySetState: // arg1 == irsdk_RpyStateMode + case irsdk_BroadcastCamSetState: // arg1 == irsdk_CameraState + case irsdk_BroadcastTelemCommand: // arg1 == irsdk_TelemCommandMode + case irsdk_BroadcastVideoCapture: // arg1 == irsdk_VideoCaptureMode + printf("BroadcastMessage(msgType: %d, arg1: %d, arg2: -1, arg3: -1)\n", msgType, arg1); + irsdk_broadcastMsg(msgType, arg1, -1, -1); + break; + + // irsdk_BroadcastMsg msg, int arg1, int arg2, int unused + case irsdk_BroadcastReloadTextures: // arg1 == irsdk_ReloadTexturesMode + case irsdk_BroadcastChatComand: // arg1 == irsdk_ChatCommandMode + case irsdk_BroadcastReplaySetPlaySpeed: + printf("BroadcastMessage(msgType: %d, arg1: %d, arg2: %d, arg3: -1)\n", msgType, arg1, arg2.Int32Value()); + irsdk_broadcastMsg(msgType, arg1, arg2, -1); + break; + + // irsdk_BroadcastMsg msg, int arg1, float arg2 + case irsdk_BroadcastPitCommand: // arg1 == irsdk_PitCommandMode + case irsdk_BroadcastFFBCommand: // arg1 == irsdk_FFBCommandMode + case irsdk_BroadcastReplaySearchSessionTime: + case irskd_BroadcastReplaySetPlayPosition: + printf("BroadcastMessage(msgType: %d, arg1: %d, arg2: %f)\n", msgType, arg1, (float)arg2.FloatValue()); + irsdk_broadcastMsg(msgType, arg1, (float)arg2.FloatValue()); + break; + + default: + printf("Attempted to broadcast an unsupported message."); + return Napi::Boolean::New(env, false); + } + + return Napi::Boolean::New(env, true); +} + +// SDK State Getters +Napi::Value iRacingSdkNode::IsRunning(const Napi::CallbackInfo &info) +{ + bool result = irsdk_isConnected(); + return Napi::Boolean::New(info.Env(), result); +} + +Napi::Value iRacingSdkNode::GetSessionVersionNum(const Napi::CallbackInfo &info) +{ + int sessVer = irsdk_getSessionInfoStrUpdate(); + return Napi::Number::New(info.Env(), sessVer); +} + +// Helper function to convert Windows-1252 to UTF-8 +std::string ConvertToUTF8(const char* input) { + if (!input) return ""; + + std::string result; + result.reserve(strlen(input) * 2); // Reserve space for potential UTF-8 expansion + + for (const char* p = input; *p; ++p) { + unsigned char c = *p; + if (c < 0x80) { + // ASCII character + result += c; + } else { + // Windows-1252 to UTF-8 conversion + switch (c) { + case 0x80: result += "\xE2\x82\xAC"; break; // € + case 0x82: result += "\xE2\x80\x9A"; break; // ‚ + case 0x83: result += "\xC6\x92"; break; // ƒ + case 0x84: result += "\xE2\x80\x9E"; break; // „ + case 0x85: result += "\xE2\x80\xA6"; break; // … + case 0x86: result += "\xE2\x80\xA0"; break; // † + case 0x87: result += "\xE2\x80\xA1"; break; // ‡ + case 0x88: result += "\xCB\x86"; break; // ˆ + case 0x89: result += "\xE2\x80\xB0"; break; // ‰ + case 0x8A: result += "\xC5\xA0"; break; // Š + case 0x8B: result += "\xE2\x80\xB9"; break; // ‹ + case 0x8C: result += "\xC5\x92"; break; // Œ + case 0x8E: result += "\xC5\xBD"; break; // Ž + case 0x91: result += "\xE2\x80\x98"; break; // ' + case 0x92: result += "\xE2\x80\x99"; break; // ' + case 0x93: result += "\xE2\x80\x9C"; break; // " + case 0x94: result += "\xE2\x80\x9D"; break; // " + case 0x95: result += "\xE2\x80\xA2"; break; // • + case 0x96: result += "\xE2\x80\x93"; break; // – + case 0x97: result += "\xE2\x80\x94"; break; // — + case 0x98: result += "\xCB\x9C"; break; // ˜ + case 0x99: result += "\xE2\x84\xA2"; break; // ™ + case 0x9A: result += "\xC5\xA1"; break; // š + case 0x9B: result += "\xE2\x80\xBA"; break; // › + case 0x9C: result += "\xC5\x93"; break; // œ + case 0x9E: result += "\xC5\xBE"; break; // ž + case 0x9F: result += "\xC5\xB8"; break; // Ÿ + case 0xA0: result += "\xC2\xA0"; break; //   + case 0xA1: result += "\xC2\xA1"; break; // ¡ + case 0xA2: result += "\xC2\xA2"; break; // ¢ + case 0xA3: result += "\xC2\xA3"; break; // £ + case 0xA4: result += "\xC2\xA4"; break; // ¤ + case 0xA5: result += "\xC2\xA5"; break; // ¥ + case 0xA6: result += "\xC2\xA6"; break; // ¦ + case 0xA7: result += "\xC2\xA7"; break; // § + case 0xA8: result += "\xC2\xA8"; break; // ¨ + case 0xA9: result += "\xC2\xA9"; break; // © + case 0xAA: result += "\xC2\xAA"; break; // ª + case 0xAB: result += "\xC2\xAB"; break; // « + case 0xAC: result += "\xC2\xAC"; break; // ¬ + case 0xAD: result += "\xC2\xAD"; break; // ­ + case 0xAE: result += "\xC2\xAE"; break; // ® + case 0xAF: result += "\xC2\xAF"; break; // ¯ + case 0xB0: result += "\xC2\xB0"; break; // ° + case 0xB1: result += "\xC2\xB1"; break; // ± + case 0xB2: result += "\xC2\xB2"; break; // ² + case 0xB3: result += "\xC2\xB3"; break; // ³ + case 0xB4: result += "\xC2\xB4"; break; // ´ + case 0xB5: result += "\xC2\xB5"; break; // µ + case 0xB6: result += "\xC2\xB6"; break; // ¶ + case 0xB7: result += "\xC2\xB7"; break; // · + case 0xB8: result += "\xC2\xB8"; break; // ¸ + case 0xB9: result += "\xC2\xB9"; break; // ¹ + case 0xBA: result += "\xC2\xBA"; break; // º + case 0xBB: result += "\xC2\xBB"; break; // » + case 0xBC: result += "\xC2\xBC"; break; // ¼ + case 0xBD: result += "\xC2\xBD"; break; // ½ + case 0xBE: result += "\xC2\xBE"; break; // ¾ + case 0xBF: result += "\xC2\xBF"; break; // ¿ + case 0xC0: result += "\xC3\x80"; break; // À + case 0xC1: result += "\xC3\x81"; break; // Á + case 0xC2: result += "\xC3\x82"; break; //  + case 0xC3: result += "\xC3\x83"; break; // à + case 0xC4: result += "\xC3\x84"; break; // Ä + case 0xC5: result += "\xC3\x85"; break; // Å + case 0xC6: result += "\xC3\x86"; break; // Æ + case 0xC7: result += "\xC3\x87"; break; // Ç + case 0xC8: result += "\xC3\x88"; break; // È + case 0xC9: result += "\xC3\x89"; break; // É + case 0xCA: result += "\xC3\x8A"; break; // Ê + case 0xCB: result += "\xC3\x8B"; break; // Ë + case 0xCC: result += "\xC3\x8C"; break; // Ì + case 0xCD: result += "\xC3\x8D"; break; // Í + case 0xCE: result += "\xC3\x8E"; break; // Î + case 0xCF: result += "\xC3\x8F"; break; // Ï + case 0xD0: result += "\xC3\x90"; break; // Ð + case 0xD1: result += "\xC3\x91"; break; // Ñ + case 0xD2: result += "\xC3\x92"; break; // Ò + case 0xD3: result += "\xC3\x93"; break; // Ó + case 0xD4: result += "\xC3\x94"; break; // Ô + case 0xD5: result += "\xC3\x95"; break; // Õ + case 0xD6: result += "\xC3\x96"; break; // Ö + case 0xD7: result += "\xC3\x97"; break; // × + case 0xD8: result += "\xC3\x98"; break; // Ø + case 0xD9: result += "\xC3\x99"; break; // Ù + case 0xDA: result += "\xC3\x9A"; break; // Ú + case 0xDB: result += "\xC3\x9B"; break; // Û + case 0xDC: result += "\xC3\x9C"; break; // Ü + case 0xDD: result += "\xC3\x9D"; break; // Ý + case 0xDE: result += "\xC3\x9E"; break; // Þ + case 0xDF: result += "\xC3\x9F"; break; // ß + case 0xE0: result += "\xC3\xA0"; break; // à + case 0xE1: result += "\xC3\xA1"; break; // á + case 0xE2: result += "\xC3\xA2"; break; // â + case 0xE3: result += "\xC3\xA3"; break; // ã + case 0xE4: result += "\xC3\xA4"; break; // ä + case 0xE5: result += "\xC3\xA5"; break; // å + case 0xE6: result += "\xC3\xA6"; break; // æ + case 0xE7: result += "\xC3\xA7"; break; // ç + case 0xE8: result += "\xC3\xA8"; break; // è + case 0xE9: result += "\xC3\xA9"; break; // é + case 0xEA: result += "\xC3\xAA"; break; // ê + case 0xEB: result += "\xC3\xAB"; break; // ë + case 0xEC: result += "\xC3\xAC"; break; // ì + case 0xED: result += "\xC3\xAD"; break; // í + case 0xEE: result += "\xC3\xAE"; break; // î + case 0xEF: result += "\xC3\xAF"; break; // ï + case 0xF0: result += "\xC3\xB0"; break; // ð + case 0xF1: result += "\xC3\xB1"; break; // ñ + case 0xF2: result += "\xC3\xB2"; break; // ò + case 0xF3: result += "\xC3\xB3"; break; // ó + case 0xF4: result += "\xC3\xB4"; break; // ô + case 0xF5: result += "\xC3\xB5"; break; // õ + case 0xF6: result += "\xC3\xB6"; break; // ö + case 0xF7: result += "\xC3\xB7"; break; // ÷ + case 0xF8: result += "\xC3\xB8"; break; // ø + case 0xF9: result += "\xC3\xB9"; break; // ù + case 0xFA: result += "\xC3\xBA"; break; // ú + case 0xFB: result += "\xC3\xBB"; break; // û + case 0xFC: result += "\xC3\xBC"; break; // ü + case 0xFD: result += "\xC3\xBD"; break; // ý + case 0xFE: result += "\xC3\xBE"; break; // þ + case 0xFF: result += "\xC3\xBF"; break; // ÿ + default: result += c; break; + } + } + } + return result; +} + +Napi::Value iRacingSdkNode::GetSessionData(const Napi::CallbackInfo &info) +{ + int latestUpdate = irsdk_getSessionInfoStrUpdate(); + if (this->_lastSessionCt != latestUpdate) { + printf("Session data has been updated (prev: %d, new: %d)\n", this->_lastSessionCt, latestUpdate); + this->_lastSessionCt = latestUpdate; + this->_sessionData = irsdk_getSessionInfoStr(); + } + const char *session = this->_sessionData; + if (session == NULL) { + return Napi::String::New(info.Env(), ""); + } + + // Convert Windows-1252 to UTF-8 + std::string utf8Session = ConvertToUTF8(session); + return Napi::String::New(info.Env(), utf8Session.c_str()); +} + +Napi::Value iRacingSdkNode::GetTelemetryVar(const Napi::CallbackInfo &info) +{ + Napi::Env env = info.Env(); + + int varIndex; + if (info.Length() <= 0) { + varIndex = 0; + } else if (!info[0].IsNumber()) { + if (info[0].IsString()) { + const char *name = info[0].As().Utf8Value().c_str(); + return this->GetTelemetryVar(env, name); + } + varIndex = 0; + } + + return this->GetTelemetryVarByIndex(env, varIndex); +} + +Napi::Value iRacingSdkNode::GetTelemetryData(const Napi::CallbackInfo &info) +{ + const irsdk_header* header = irsdk_getHeader(); + auto env = info.Env(); + auto telemVars = Napi::Object::New(env); + + int count = header->numVars; + for (int i = 0; i < count; i++) { + auto telemVariable = this->GetTelemetryVarByIndex(env, i); + if (telemVariable.IsObject() && telemVariable.Has("name")) { + telemVars.Set(telemVariable.Get("name"), telemVariable); + } + } + + return telemVars; +} + +// Helpers +Napi::Value iRacingSdkNode::__GetTelemetryTypes(const Napi::CallbackInfo &info) +{ + auto env = info.Env(); + auto result = Napi::Object::New(env); + + const int count = irsdk_getHeader()->numVars; + const irsdk_varHeader *varHeader; + for (int i = 0; i < count; i++) { + varHeader = irsdk_getVarHeaderEntry(i); + result.Set(varHeader->name, Napi::Number::New(env, varHeader->type)); + } + + return result; +} + + +// --------------------------- +// Helper functions +// --------------------------- +bool iRacingSdkNode::GetTelemetryBool(int entry, int index) +{ + const irsdk_varHeader *headerVar = irsdk_getVarHeaderEntry(entry); + return *(reinterpret_cast(_data + headerVar->offset) + index); +} + +int iRacingSdkNode::GetTelemetryInt(int entry, int index) +{ + // Each int is 4 bytes + const irsdk_varHeader *headerVar = irsdk_getVarHeaderEntry(entry); + return *(reinterpret_cast(_data + headerVar->offset) + index * 4); +} + +float iRacingSdkNode::GetTelemetryFloat(int entry, int index) +{ + // Each float is 4 bytes + const irsdk_varHeader *headerVar = irsdk_getVarHeaderEntry(entry); + return *(reinterpret_cast(_data + headerVar->offset) + index * 4); +} + +double iRacingSdkNode::GetTelemetryDouble(int entry, int index) +{ + // Each double is 8 bytes + const irsdk_varHeader *headerVar = irsdk_getVarHeaderEntry(entry); + return *(reinterpret_cast(_data + headerVar->offset) + index * 8); +} + +Napi::Object iRacingSdkNode::GetTelemetryVarByIndex(const Napi::Env env, int index) +{ + auto headerVar = irsdk_getVarHeaderEntry(index); + auto telemVar = Napi::Object::New(env); + + // Create entry object + telemVar.Set("countAsTime", headerVar->countAsTime); + telemVar.Set("length", headerVar->count); + telemVar.Set("name", headerVar->name); + telemVar.Set("description", headerVar->desc); + telemVar.Set("unit", headerVar->unit); + telemVar.Set("varType", headerVar->type); + + int dataSize = headerVar->count * irsdk_VarTypeBytes[headerVar->type]; + auto entryVal = Napi::ArrayBuffer::New(env, dataSize); + memcpy(entryVal.Data(), this->_data + headerVar->offset, dataSize); + + telemVar.Set("value", entryVal); + return telemVar; +} + +Napi::Object iRacingSdkNode::GetTelemetryVar(const Napi::Env env, const char *varName) +{ + int varIndex = irsdk_varNameToIndex(varName); + return this->GetTelemetryVarByIndex(env, varIndex); +} + +Napi::Object InitAll(Napi::Env env, Napi::Object exports) +{ + iRacingSdkNode::Init(env, exports); + return exports; +} + +NODE_API_MODULE(NODE_GYP_MODULE_NAME, InitAll); diff --git a/src/app/irsdk/native/irsdk_node.h b/src/app/irsdk/native/irsdk_node.h new file mode 100644 index 0000000..e3f8bf7 --- /dev/null +++ b/src/app/irsdk/native/irsdk_node.h @@ -0,0 +1,50 @@ +#ifndef IRSDK_NODE_H +#define IRSDK_NODE_H + +#include +#include "./lib/irsdk_defines.h" +#include "./lib/irsdk_client.h" + +class iRacingSdkNode : public Napi::ObjectWrap +{ +public: + static Napi::Object Init(Napi::Env env, Napi::Object exports); + iRacingSdkNode(const Napi::CallbackInfo& info); + +private: + // Properties + Napi::Value GetCurrSessionDataVersion(const Napi::CallbackInfo &info); + Napi::Value GetEnableLogging(const Napi::CallbackInfo &info); + void SetEnableLogging(const Napi::CallbackInfo &info, const Napi::Value &value); + + // Methods + // Control + Napi::Value StartSdk(const Napi::CallbackInfo &info); + Napi::Value StopSdk(const Napi::CallbackInfo &info); + Napi::Value WaitForData(const Napi::CallbackInfo &info); + Napi::Value BroadcastMessage(const Napi::CallbackInfo &info); + // Getters + Napi::Value IsRunning(const Napi::CallbackInfo &info); + Napi::Value GetSessionVersionNum(const Napi::CallbackInfo &info); + Napi::Value GetSessionData(const Napi::CallbackInfo &info); + Napi::Value GetTelemetryData(const Napi::CallbackInfo &info); + // Helpers + Napi::Value __GetTelemetryTypes(const Napi::CallbackInfo &info); + Napi::Value GetTelemetryVar(const Napi::CallbackInfo &info); + + bool GetTelemetryBool(int entry, int index); + int GetTelemetryInt(int entry, int index); + float GetTelemetryFloat(int entry, int index); + double GetTelemetryDouble(int entry, int index); + Napi::Object GetTelemetryVarByIndex(const Napi::Env env, int index); + Napi::Object GetTelemetryVar(const Napi::Env env, const char *varName); + + bool _loggingEnabled; + char* _data; + int _bufLineLen; + int _sessionStatusID; + int _lastSessionCt; + const char* _sessionData; +}; + +#endif diff --git a/src/app/irsdk/native/lib/irsdk_client.cpp b/src/app/irsdk/native/lib/irsdk_client.cpp new file mode 100644 index 0000000..97277e1 --- /dev/null +++ b/src/app/irsdk/native/lib/irsdk_client.cpp @@ -0,0 +1,495 @@ +/* +Copyright (c) 2013, iRacing.com Motorsport Simulations, LLC. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of iRacing.com Motorsport Simulations nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include +#include "irsdk_defines.h" +#include "yaml_parser.h" +#include "irsdk_client.h" + +#pragma warning(disable:4996) + +irsdkClient& irsdkClient::instance() +{ + static irsdkClient INSTANCE; + return INSTANCE; +} + +bool irsdkClient::waitForData(int timeoutMS) +{ + // wait for start of session or new data + if(irsdk_waitForDataReady(timeoutMS, m_data) && irsdk_getHeader()) + { + // if new connection, or data changed lenght then init + if(!m_data || m_nData != irsdk_getHeader()->bufLen) + { + // allocate memory to hold incoming data from sim + if(m_data) delete [] m_data; + m_nData = irsdk_getHeader()->bufLen; + m_data = new char[m_nData]; + + // indicate a new connection + m_statusID++; + + // reset session info str status + m_lastSessionCt = -1; + + // and try to fill in the data + if(irsdk_getNewData(m_data)) + return true; + } + else if(m_data) + { + // else we are allready initialized, and data is ready for processing + return true; + } + } + else if(!isConnected()) + { + // else session ended + if(m_data) + delete[] m_data; + m_data = NULL; + + // reset session info str status + m_lastSessionCt = -1; + } + + return false; +} + +void irsdkClient::shutdown() +{ + irsdk_shutdown(); + if(m_data) + delete[] m_data; + m_data = NULL; + + // reset session info str status + m_lastSessionCt = -1; +} + +bool irsdkClient::isConnected() +{ + return m_data != NULL && irsdk_isConnected(); +} + +int irsdkClient::getVarIdx(const char*name) +{ + if(isConnected()) + { + return irsdk_varNameToIndex(name); + } + + return -1; +} + +int /*irsdk_VarType*/ irsdkClient::getVarType(int idx) +{ + if(isConnected()) + { + const irsdk_varHeader *vh = irsdk_getVarHeaderEntry(idx); + if(vh) + { + return vh->type; + } + else + { + //invalid variable index + assert(false); + } + } + + return irsdk_char; +} + +int irsdkClient::getVarCount(int idx) +{ + if(isConnected()) + { + const irsdk_varHeader *vh = irsdk_getVarHeaderEntry(idx); + if(vh) + { + return vh->count; + } + else + { + //invalid variable index + assert(false); + } + } + + return 0; +} + +bool irsdkClient::getVarBool(int idx, int entry) +{ + if(isConnected()) + { + const irsdk_varHeader *vh = irsdk_getVarHeaderEntry(idx); + if(vh) + { + if(entry >= 0 && entry < vh->count) + { + const char * data = m_data + vh->offset; + switch(vh->type) + { + // 1 byte + case irsdk_char: + case irsdk_bool: + return (((const char*)data)[entry]) != 0; + break; + + // 4 bytes + case irsdk_int: + case irsdk_bitField: + return (((const int*)data)[entry]) != 0; + break; + + // test float/double for greater than 1.0 so that + // we have a chance of this being usefull + // technically there is no right conversion... + case irsdk_float: + return (((const float*)data)[entry]) >= 1.0f; + break; + + // 8 bytes + case irsdk_double: + return (((const double*)data)[entry]) >= 1.0; + break; + } + } + else + { + // invalid offset + assert(false); + } + } + else + { + //invalid variable index + assert(false); + } + } + + return false; +} + +int irsdkClient::getVarInt(int idx, int entry) +{ + if(isConnected()) + { + const irsdk_varHeader *vh = irsdk_getVarHeaderEntry(idx); + if(vh) + { + if(entry >= 0 && entry < vh->count) + { + const char * data = m_data + vh->offset; + switch(vh->type) + { + // 1 byte + case irsdk_char: + case irsdk_bool: + return (int)(((const char*)data)[entry]); + break; + + // 4 bytes + case irsdk_int: + case irsdk_bitField: + return (int)(((const int*)data)[entry]); + break; + + case irsdk_float: + return (int)(((const float*)data)[entry]); + break; + + // 8 bytes + case irsdk_double: + return (int)(((const double*)data)[entry]); + break; + } + } + else + { + // invalid offset + assert(false); + } + } + else + { + //invalid variable index + assert(false); + } + } + + return 0; +} + +float irsdkClient::getVarFloat(int idx, int entry) +{ + if(isConnected()) + { + const irsdk_varHeader *vh = irsdk_getVarHeaderEntry(idx); + if(vh) + { + if(entry >= 0 && entry < vh->count) + { + const char * data = m_data + vh->offset; + switch(vh->type) + { + // 1 byte + case irsdk_char: + case irsdk_bool: + return (float)(((const char*)data)[entry]); + break; + + // 4 bytes + case irsdk_int: + case irsdk_bitField: + return (float)(((const int*)data)[entry]); + break; + + case irsdk_float: + return (float)(((const float*)data)[entry]); + break; + + // 8 bytes + case irsdk_double: + return (float)(((const double*)data)[entry]); + break; + } + } + else + { + // invalid offset + assert(false); + } + } + else + { + //invalid variable index + assert(false); + } + } + + return 0.0f; +} + +double irsdkClient::getVarDouble(int idx, int entry) +{ + if(isConnected()) + { + const irsdk_varHeader *vh = irsdk_getVarHeaderEntry(idx); + if(vh) + { + if(entry >= 0 && entry < vh->count) + { + const char * data = m_data + vh->offset; + switch(vh->type) + { + // 1 byte + case irsdk_char: + case irsdk_bool: + return (double)(((const char*)data)[entry]); + break; + + // 4 bytes + case irsdk_int: + case irsdk_bitField: + return (double)(((const int*)data)[entry]); + break; + + case irsdk_float: + return (double)(((const float*)data)[entry]); + break; + + // 8 bytes + case irsdk_double: + return (double)(((const double*)data)[entry]); + break; + } + } + else + { + // invalid offset + assert(false); + } + } + else + { + //invalid variable index + assert(false); + } + } + + return 0.0; +} + +//path is in the form of "DriverInfo:Drivers:CarIdx:{%d}UserName:" +int irsdkClient::getSessionStrVal(const char *path, char *val, int valLen) +{ + if(isConnected() && path && val && valLen > 0) + { + // track changes in string + m_lastSessionCt = getSessionCt(); + + const char *tVal = NULL; + int tValLen = 0; + if(parseYaml(irsdk_getSessionInfoStr(), path, &tVal, &tValLen)) + { + // dont overflow out buffer + int len = tValLen; + if(len > valLen) + len = valLen; + + // copy what we can, even if buffer too small + memcpy(val, tVal, len); + val[len] = '\0'; // origional string has no null termination... + + // if buffer was big enough, return success + if(valLen >= tValLen) + return 1; + else // return size of buffer needed + return -tValLen; + } + } + + return 0; +} + +// get the whole string +const char* irsdkClient::getSessionStr() +{ + if(isConnected()) + { + m_lastSessionCt = getSessionCt(); + return irsdk_getSessionInfoStr(); + } + + return NULL; +} + + +//---------------------------------- + +irsdkCVar::irsdkCVar() + : m_idx(-1) + , m_statusID(-1) +{ + m_name[0] = '\0'; +} + +irsdkCVar::irsdkCVar(const char *name) +{ + m_name[0] = '\0'; + setVarName(name); +} + +void irsdkCVar::setVarName(const char *name) +{ + if(!name || 0 != strncmp(name, m_name, sizeof(m_name))) + { + m_idx = -1; + m_statusID = -1; + + if(name) + { + strncpy(m_name, name, max_string); + m_name[max_string-1] = '\0'; + } + else + m_name[0] = '\0'; + } +} + +bool irsdkCVar::checkIdx() +{ + if(irsdkClient::instance().isConnected()) + { + if(m_statusID != irsdkClient::instance().getStatusID()) + { + m_statusID = irsdkClient::instance().getStatusID(); + m_idx = irsdkClient::instance().getVarIdx(m_name); + } + + return true; + } + + return false; +} + +int /*irsdk_VarType*/ irsdkCVar::getType() +{ + if(checkIdx()) + return irsdkClient::instance().getVarType(m_idx); + return 0; +} + +int irsdkCVar::getCount() +{ + if(checkIdx()) + return irsdkClient::instance().getVarCount(m_idx); + return 0; +} + +bool irsdkCVar::isValid() +{ + checkIdx(); + return (m_idx > -1); +} + + +bool irsdkCVar::getBool(int entry) +{ + if(checkIdx()) + return irsdkClient::instance().getVarBool(m_idx, entry); + return false; +} + +int irsdkCVar::getInt(int entry) +{ + if(checkIdx()) + return irsdkClient::instance().getVarInt(m_idx, entry); + return 0; +} + +float irsdkCVar::getFloat(int entry) +{ + if(checkIdx()) + return irsdkClient::instance().getVarFloat(m_idx, entry); + return 0.0f; +} + +double irsdkCVar::getDouble(int entry) +{ + if(checkIdx()) + return irsdkClient::instance().getVarDouble(m_idx, entry); + return 0.0; +} + diff --git a/src/app/irsdk/native/lib/irsdk_client.h b/src/app/irsdk/native/lib/irsdk_client.h new file mode 100644 index 0000000..2969e29 --- /dev/null +++ b/src/app/irsdk/native/lib/irsdk_client.h @@ -0,0 +1,139 @@ +/* +Copyright (c) 2013, iRacing.com Motorsport Simulations, LLC. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of iRacing.com Motorsport Simulations nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef IRSDKCLIENT_H +#define IRSDKCLIENT_H + +// A C++ wrapper around the irsdk calls that takes care of the details of maintaining a connection. +// reads out the data into a cache so you don't have to worry about timming +class irsdkClient +{ +public: + // singleton + static irsdkClient& instance(); + + // wait for live data, or if a .ibt file is open + // then read the next line from the file. + bool waitForData(int timeoutMS = 16); + + bool isConnected(); + int getStatusID() { return m_statusID; } + + int getVarIdx(const char*name); + + // what is the base type of the data + // returns irsdk_VarType as int so we don't depend on irsdk_defines.h + int getVarType(int idx); + int getVarType(const char *name) { return getVarType(getVarIdx(name)); } + + // how many elements in array, or 1 if not an array + int getVarCount(int idx); + int getVarCount(const char *name) { return getVarCount(getVarIdx(name)); } + + // idx is the variables index, entry is the array offset, or 0 if not an array element + // will convert data to requested type + bool getVarBool(int idx, int entry = 0); + bool getVarBool(const char *name, int entry = 0) { return getVarBool(getVarIdx(name), entry); } + + int getVarInt(int idx, int entry = 0); + int getVarInt(const char *name, int entry = 0) { return getVarInt(getVarIdx(name), entry); } + + float getVarFloat(int idx, int entry = 0); + float getVarFloat(const char *name, int entry = 0) { return getVarFloat(getVarIdx(name), entry); } + + double getVarDouble(int idx, int entry = 0); + double getVarDouble(const char *name, int entry = 0) { return getVarDouble(getVarIdx(name), entry); } + + //--- + + // value that increments with each update to string + int getSessionCt() { return irsdk_getSessionInfoStrUpdate(); } + + // has string changed since we last read any values from it + bool wasSessionStrUpdated() { return m_lastSessionCt != getSessionCt(); } + + // pars string for individual value, 1 success, 0 failure, -n minimum buffer size + //****Note, this is a linear parser, so it is slow! + int getSessionStrVal(const char *path, char *val, int valLen); + + // get the whole string + const char *getSessionStr(); + +protected: + + irsdkClient() + : m_data(NULL) + , m_nData(0) + , m_statusID(0) + , m_lastSessionCt(-1) + { } + + ~irsdkClient() { shutdown(); } + + void shutdown(); + + char *m_data; + int m_nData; + int m_statusID; + + int m_lastSessionCt; + + static irsdkClient *m_instance; +}; + + +// helper class to keep track of our variables index +// Create a global instance of this and it will take care of the details for you. +class irsdkCVar +{ +public: + irsdkCVar(); + irsdkCVar(const char *name); + + void setVarName(const char *name); + + // returns irsdk_VarType as int so we don't depend on irsdk_defines.h + int getType(); + int getCount(); + bool isValid(); + + // entry is the array offset, or 0 if not an array element + bool getBool(int entry = 0); + int getInt(int entry = 0); + float getFloat(int entry = 0); + double getDouble(int entry = 0); + +protected: + bool checkIdx(); + + static const int max_string = 32; //IRSDK_MAX_STRING + char m_name[max_string]; + int m_idx; + int m_statusID; +}; + +#endif // IRSDKCLIENT_H diff --git a/src/app/irsdk/native/lib/irsdk_defines.h b/src/app/irsdk/native/lib/irsdk_defines.h new file mode 100644 index 0000000..55f0d2c --- /dev/null +++ b/src/app/irsdk/native/lib/irsdk_defines.h @@ -0,0 +1,528 @@ +/* +Copyright (c) 2013, iRacing.com Motorsport Simulations, LLC. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of iRacing.com Motorsport Simulations nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef IRSDK_DEFINES_H +#define IRSDK_DEFINES_H + +/* + The IRSDK is a simple api that lets clients access telemetry data from the + iRacing simulator. It is broken down into several parts: + + - Live data + Live data is output from the sim into a shared memory mapped file. Any + application can open this memory mapped file and read the telemetry data + out. The format of this data was laid out in such a way that it should be + possible to access from any language that can open a windows memory mapped + file, without needing an external api. + + There are two different types of data that the telemetry outputs, + sessionInfo and variables: + + Session info is for data that only needs to be updated every once in a + while. This data is output as a YAML formatted string. + + Variables, on the other hand, are output at a rate of 60 times a second. + The varHeader struct defines each variable that the sim will output, while + the varData struct gives details about the current line buffer that the vars + are being written into. Each variable is packed into a binary array with + an offset and length stored in the varHeader. The number of variables + available can change depending on the car or session loaded. But once the + sim is running the variable list is locked down and will not change during a + session. + + The sim writes a new line of variables every 16 ms, and then signals any + listeners in order to wake them up to read the data. Because the sim has no + way of knowing when a listener is done reading the data, we triple buffer + it in order to give all the clients enough time to read the data out. This + gives you a minimum of 16 ms to read the data out and process it. So it is + best to copy the data out before processing it. You can use the function + irsdk_waitForDataReady() to both wait for new data and copy the data to a + local buffer. + + - Logged data + Detailed information about the local drivers car can be logged to disk in + the form of an ibt binary file. This logging is enabled in the sim by + typing alt-L at any time. The ibt file format directly mirrors the format + of the live data. + + It is stored as an irsdk_header followed immediately by an irsdk_diskSubHeader. + After that the offsets in the irsdk_header point to the sessionInfo string, + the varHeader, and the varBuffer. + + - Remote Conrol + You can control the camera selections and playback of a replay tape, from + any external application by sending a windows message with the + irsdk_broadcastMsg() function. +*/ + +// Constant Definitions + +#include + +static const _TCHAR IRSDK_DATAVALIDEVENTNAME[] = _T("Local\\IRSDKDataValidEvent"); +static const _TCHAR IRSDK_MEMMAPFILENAME[] = _T("Local\\IRSDKMemMapFileName"); +static const _TCHAR IRSDK_BROADCASTMSGNAME[] = _T("IRSDK_BROADCASTMSG"); + +static const int IRSDK_MAX_BUFS = 4; +static const int IRSDK_MAX_STRING = 32; +// descriptions can be longer than max_string! +static const int IRSDK_MAX_DESC = 64; + +// define markers for unlimited session lap and time +static const int IRSDK_UNLIMITED_LAPS = 32767; +static const float IRSDK_UNLIMITED_TIME = 604800.0f; + +// latest version of our telemetry headers +static const int IRSDK_VER = 2; + +enum irsdk_StatusField +{ + irsdk_stConnected = 1 +}; + +enum irsdk_VarType +{ + // 1 byte + irsdk_char = 0, + irsdk_bool, + + // 4 bytes + irsdk_int, + irsdk_bitField, + irsdk_float, + + // 8 bytes + irsdk_double, + + //index, don't use + irsdk_ETCount +}; + +static const int irsdk_VarTypeBytes[irsdk_ETCount] = +{ + 1, // irsdk_char + 1, // irsdk_bool + + 4, // irsdk_int + 4, // irsdk_bitField + 4, // irsdk_float + + 8 // irsdk_double +}; + +// bit fields +enum irsdk_EngineWarnings +{ + irsdk_waterTempWarning = 0x01, + irsdk_fuelPressureWarning = 0x02, + irsdk_oilPressureWarning = 0x04, + irsdk_engineStalled = 0x08, + irsdk_pitSpeedLimiter = 0x10, + irsdk_revLimiterActive = 0x20, + irsdk_oilTempWarning = 0x40, +}; + +// global flags +enum irsdk_Flags +{ + // global flags + irsdk_checkered = 0x00000001, + irsdk_white = 0x00000002, + irsdk_green = 0x00000004, + irsdk_yellow = 0x00000008, + irsdk_red = 0x00000010, + irsdk_blue = 0x00000020, + irsdk_debris = 0x00000040, + irsdk_crossed = 0x00000080, + irsdk_yellowWaving = 0x00000100, + irsdk_oneLapToGreen = 0x00000200, + irsdk_greenHeld = 0x00000400, + irsdk_tenToGo = 0x00000800, + irsdk_fiveToGo = 0x00001000, + irsdk_randomWaving = 0x00002000, + irsdk_caution = 0x00004000, + irsdk_cautionWaving = 0x00008000, + + // drivers black flags + irsdk_black = 0x00010000, + irsdk_disqualify = 0x00020000, + irsdk_servicible = 0x00040000, // car is allowed service (not a flag) + irsdk_furled = 0x00080000, + irsdk_repair = 0x00100000, + + // start lights + irsdk_startHidden = 0x10000000, + irsdk_startReady = 0x20000000, + irsdk_startSet = 0x40000000, + irsdk_startGo = 0x80000000, +}; + + +// status +enum irsdk_TrkLoc +{ + irsdk_NotInWorld = -1, + irsdk_OffTrack, + irsdk_InPitStall, + irsdk_AproachingPits, + irsdk_OnTrack +}; + +enum irsdk_TrkSurf +{ + irsdk_SurfaceNotInWorld = -1, + irsdk_UndefinedMaterial = 0, + + irsdk_Asphalt1Material, + irsdk_Asphalt2Material, + irsdk_Asphalt3Material, + irsdk_Asphalt4Material, + irsdk_Concrete1Material, + irsdk_Concrete2Material, + irsdk_RacingDirt1Material, + irsdk_RacingDirt2Material, + irsdk_Paint1Material, + irsdk_Paint2Material, + irsdk_Rumble1Material, + irsdk_Rumble2Material, + irsdk_Rumble3Material, + irsdk_Rumble4Material, + + irsdk_Grass1Material, + irsdk_Grass2Material, + irsdk_Grass3Material, + irsdk_Grass4Material, + irsdk_Dirt1Material, + irsdk_Dirt2Material, + irsdk_Dirt3Material, + irsdk_Dirt4Material, + irsdk_SandMaterial, + irsdk_Gravel1Material, + irsdk_Gravel2Material, + irsdk_GrasscreteMaterial, + irsdk_AstroturfMaterial, +}; + +enum irsdk_SessionState +{ + irsdk_StateInvalid, + irsdk_StateGetInCar, + irsdk_StateWarmup, + irsdk_StateParadeLaps, + irsdk_StateRacing, + irsdk_StateCheckered, + irsdk_StateCoolDown +}; + +enum irsdk_CarLeftRight +{ + irsdk_LROff, + irsdk_LRClear, // no cars around us. + irsdk_LRCarLeft, // there is a car to our left. + irsdk_LRCarRight, // there is a car to our right. + irsdk_LRCarLeftRight, // there are cars on each side. + irsdk_LR2CarsLeft, // there are two cars to our left. + irsdk_LR2CarsRight // there are two cars to our right. +}; + +enum irsdk_CameraState +{ + irsdk_IsSessionScreen = 0x0001, // the camera tool can only be activated if viewing the session screen (out of car) + irsdk_IsScenicActive = 0x0002, // the scenic camera is active (no focus car) + + //these can be changed with a broadcast message + irsdk_CamToolActive = 0x0004, + irsdk_UIHidden = 0x0008, + irsdk_UseAutoShotSelection = 0x0010, + irsdk_UseTemporaryEdits = 0x0020, + irsdk_UseKeyAcceleration = 0x0040, + irsdk_UseKey10xAcceleration = 0x0080, + irsdk_UseMouseAimMode = 0x0100 +}; + +enum irsdk_PitSvFlags +{ + irsdk_LFTireChange = 0x0001, + irsdk_RFTireChange = 0x0002, + irsdk_LRTireChange = 0x0004, + irsdk_RRTireChange = 0x0008, + + irsdk_FuelFill = 0x0010, + irsdk_WindshieldTearoff = 0x0020, + irsdk_FastRepair = 0x0040 +}; + +enum irsdk_PitSvStatus +{ + // status + irsdk_PitSvNone = 0, + irsdk_PitSvInProgress, + irsdk_PitSvComplete, + + // errors + irsdk_PitSvTooFarLeft = 100, + irsdk_PitSvTooFarRight, + irsdk_PitSvTooFarForward, + irsdk_PitSvTooFarBack, + irsdk_PitSvBadAngle, + irsdk_PitSvCantFixThat, +}; + +enum irsdk_PaceMode +{ + irsdk_PaceModeSingleFileStart = 0, + irsdk_PaceModeDoubleFileStart, + irsdk_PaceModeSingleFileRestart, + irsdk_PaceModeDoubleFileRestart, + irsdk_PaceModeNotPacing, +}; + +enum irsdk_PaceFlags +{ + irsdk_PaceFlagsEndOfLine = 0x01, + irsdk_PaceFlagsFreePass = 0x02, + irsdk_PaceFlagsWavedAround = 0x04, +}; + +//---- +// + +struct irsdk_varHeader +{ + int type; // irsdk_VarType + int offset; // offset fron start of buffer row + int count; // number of entrys (array) + // so length in bytes would be irsdk_VarTypeBytes[type] * count + bool countAsTime; + char pad[3]; // (16 byte align) + + char name[IRSDK_MAX_STRING]; + char desc[IRSDK_MAX_DESC]; + char unit[IRSDK_MAX_STRING]; // something like "kg/m^2" + + void clear() + { + type = 0; + offset = 0; + count = 0; + countAsTime = false; + memset(name, 0, sizeof(name)); + memset(desc, 0, sizeof(name)); + memset(unit, 0, sizeof(name)); + } +}; + +struct irsdk_varBuf +{ + int tickCount; // used to detect changes in data + int bufOffset; // offset from header + int pad[2]; // (16 byte align) +}; + +struct irsdk_header +{ + int ver; // this api header version, see IRSDK_VER + int status; // bitfield using irsdk_StatusField + int tickRate; // ticks per second (60 or 360 etc) + + // session information, updated periodicaly + int sessionInfoUpdate; // Incremented when session info changes + int sessionInfoLen; // Length in bytes of session info string + int sessionInfoOffset; // Session info, encoded in YAML format + + // State data, output at tickRate + + int numVars; // length of arra pointed to by varHeaderOffset + int varHeaderOffset; // offset to irsdk_varHeader[numVars] array, Describes the variables received in varBuf + + int numBuf; // <= IRSDK_MAX_BUFS (3 for now) + int bufLen; // length in bytes for one line + int pad1[2]; // (16 byte align) + irsdk_varBuf varBuf[IRSDK_MAX_BUFS]; // buffers of data being written to +}; + +// sub header used when writing telemetry to disk +struct irsdk_diskSubHeader +{ + time_t sessionStartDate; + double sessionStartTime; + double sessionEndTime; + int sessionLapCount; + int sessionRecordCount; +}; + +//---- +// Client function definitions + +bool irsdk_startup(); +void irsdk_shutdown(); + +bool irsdk_getNewData(char *data); +bool irsdk_waitForDataReady(int timeOut, char *data); +bool irsdk_isConnected(); + +const irsdk_header *irsdk_getHeader(); +const char *irsdk_getData(int index); +const char *irsdk_getSessionInfoStr(); +int irsdk_getSessionInfoStrUpdate(); // incrementing index that indicates new session info string + +const irsdk_varHeader *irsdk_getVarHeaderPtr(); +const irsdk_varHeader *irsdk_getVarHeaderEntry(int index); + +int irsdk_varNameToIndex(const char *name); +int irsdk_varNameToOffset(const char *name); + +//---- +// Remote controll the sim by sending these windows messages +// camera and replay commands only work when you are out of your car, +// pit commands only work when in your car +enum irsdk_BroadcastMsg +{ + irsdk_BroadcastCamSwitchPos = 0, // car position, group, camera + irsdk_BroadcastCamSwitchNum, // driver #, group, camera + irsdk_BroadcastCamSetState, // irsdk_CameraState, unused, unused + irsdk_BroadcastReplaySetPlaySpeed, // speed, slowMotion, unused + irskd_BroadcastReplaySetPlayPosition, // irsdk_RpyPosMode, Frame Number (high, low) + irsdk_BroadcastReplaySearch, // irsdk_RpySrchMode, unused, unused + irsdk_BroadcastReplaySetState, // irsdk_RpyStateMode, unused, unused + irsdk_BroadcastReloadTextures, // irsdk_ReloadTexturesMode, carIdx, unused + irsdk_BroadcastChatComand, // irsdk_ChatCommandMode, subCommand, unused + irsdk_BroadcastPitCommand, // irsdk_PitCommandMode, parameter + irsdk_BroadcastTelemCommand, // irsdk_TelemCommandMode, unused, unused + irsdk_BroadcastFFBCommand, // irsdk_FFBCommandMode, value (float, high, low) + irsdk_BroadcastReplaySearchSessionTime, // sessionNum, sessionTimeMS (high, low) + irsdk_BroadcastVideoCapture, // irsdk_VideoCaptureMode, unused, unused + irsdk_BroadcastLast // unused placeholder +}; + +enum irsdk_ChatCommandMode +{ + irsdk_ChatCommand_Macro = 0, // pass in a number from 1-15 representing the chat macro to launch + irsdk_ChatCommand_BeginChat, // Open up a new chat window + irsdk_ChatCommand_Reply, // Reply to last private chat + irsdk_ChatCommand_Cancel // Close chat window +}; + +enum irsdk_PitCommandMode // this only works when the driver is in the car +{ + irsdk_PitCommand_Clear = 0, // Clear all pit checkboxes + irsdk_PitCommand_WS, // Clean the winshield, using one tear off + irsdk_PitCommand_Fuel, // Add fuel, optionally specify the amount to add in liters or pass '0' to use existing amount + irsdk_PitCommand_LF, // Change the left front tire, optionally specifying the pressure in KPa or pass '0' to use existing pressure + irsdk_PitCommand_RF, // right front + irsdk_PitCommand_LR, // left rear + irsdk_PitCommand_RR, // right rear + irsdk_PitCommand_ClearTires, // Clear tire pit checkboxes + irsdk_PitCommand_FR, // Request a fast repair + irsdk_PitCommand_ClearWS, // Uncheck Clean the winshield checkbox + irsdk_PitCommand_ClearFR, // Uncheck request a fast repair + irsdk_PitCommand_ClearFuel, // Uncheck add fuel +}; + +enum irsdk_TelemCommandMode // You can call this any time, but telemtry only records when driver is in there car +{ + irsdk_TelemCommand_Stop = 0, // Turn telemetry recording off + irsdk_TelemCommand_Start, // Turn telemetry recording on + irsdk_TelemCommand_Restart, // Write current file to disk and start a new one +}; + +enum irsdk_RpyStateMode +{ + irsdk_RpyState_EraseTape = 0, // clear any data in the replay tape + irsdk_RpyState_Last // unused place holder +}; + +enum irsdk_ReloadTexturesMode +{ + irsdk_ReloadTextures_All = 0, // reload all textuers + irsdk_ReloadTextures_CarIdx // reload only textures for the specific carIdx +}; + +// Search replay tape for events +enum irsdk_RpySrchMode +{ + irsdk_RpySrch_ToStart = 0, + irsdk_RpySrch_ToEnd, + irsdk_RpySrch_PrevSession, + irsdk_RpySrch_NextSession, + irsdk_RpySrch_PrevLap, + irsdk_RpySrch_NextLap, + irsdk_RpySrch_PrevFrame, + irsdk_RpySrch_NextFrame, + irsdk_RpySrch_PrevIncident, + irsdk_RpySrch_NextIncident, + irsdk_RpySrch_Last // unused placeholder +}; + +enum irsdk_RpyPosMode +{ + irsdk_RpyPos_Begin = 0, + irsdk_RpyPos_Current, + irsdk_RpyPos_End, + irsdk_RpyPos_Last // unused placeholder +}; + +enum irsdk_FFBCommandMode // You can call this any time +{ + irsdk_FFBCommand_MaxForce = 0, // Set the maximum force when mapping steering torque force to direct input units (float in Nm) + irsdk_FFBCommand_Last // unused placeholder +}; + +// irsdk_BroadcastCamSwitchPos or irsdk_BroadcastCamSwitchNum camera focus defines +// pass these in for the first parameter to select the 'focus at' types in the camera system. +enum irsdk_csMode +{ + irsdk_csFocusAtIncident = -3, + irsdk_csFocusAtLeader = -2, + irsdk_csFocusAtExiting = -1, + // ctFocusAtDriver + car number... + irsdk_csFocusAtDriver = 0 +}; + +enum irsdk_VideoCaptureMode +{ + irsdk_VideoCapture_TriggerScreenShot = 0, // save a screenshot to disk + irsdk_VideoCaptuer_StartVideoCapture, // start capturing video + irsdk_VideoCaptuer_EndVideoCapture, // stop capturing video + irsdk_VideoCaptuer_ToggleVideoCapture, // toggle video capture on/off + irsdk_VideoCaptuer_ShowVideoTimer, // show video timer in upper left corner of display + irsdk_VideoCaptuer_HideVideoTimer, // hide video timer +}; + +//send a remote controll message to the sim +// var1, var2, and var3 are all 16 bits signed +void irsdk_broadcastMsg(irsdk_BroadcastMsg msg, int var1, int var2, int var3); +// var2 can be a full 32 bits +void irsdk_broadcastMsg(irsdk_BroadcastMsg msg, int var1, int var2); +// var2 can be a full 32 bit float +void irsdk_broadcastMsg(irsdk_BroadcastMsg msg, int var1, float var2); + +// add a leading zero (or zeros) to a car number +// to encode car #001 call padCarNum(1,2) +int irsdk_padCarNum(int num, int zero); + +#endif //IRSDK_DEFINES_H diff --git a/src/app/irsdk/native/lib/irsdk_utils.cpp b/src/app/irsdk/native/lib/irsdk_utils.cpp new file mode 100644 index 0000000..f807651 --- /dev/null +++ b/src/app/irsdk/native/lib/irsdk_utils.cpp @@ -0,0 +1,377 @@ +/* +Copyright (c) 2013, iRacing.com Motorsport Simulations, LLC. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of iRacing.com Motorsport Simulations nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define MIN_WIN_VER 0x0501 + +#ifndef WINVER +# define WINVER MIN_WIN_VER +#endif + +#ifndef _WIN32_WINNT +# define _WIN32_WINNT MIN_WIN_VER +#endif + +#include +#include +#include +#include + +#ifdef _MSC_VER +#include +#endif + +#include "irsdk_defines.h" + +// for timeBeginPeriod() +#pragma comment(lib, "Winmm") +// for RegisterWindowMessage() and SendMessage() +#pragma comment(lib, "User32") + +// Local memory + +static HANDLE hDataValidEvent = NULL; +static HANDLE hMemMapFile = NULL; + +static const char *pSharedMem = NULL; +static const irsdk_header *pHeader = NULL; + +static int lastTickCount = INT_MAX; +static bool isInitialized = false; + +static const double timeout = 30.0; // timeout after 30 seconds with no communication +static time_t lastValidTime = 0; + +// Function Implementations + +bool irsdk_startup() +{ + if(!hMemMapFile) + { + hMemMapFile = OpenFileMapping( FILE_MAP_READ, FALSE, IRSDK_MEMMAPFILENAME); + lastTickCount = INT_MAX; + } + + if(hMemMapFile) + { + if(!pSharedMem) + { + pSharedMem = (const char *)MapViewOfFile(hMemMapFile, FILE_MAP_READ, 0, 0, 0); + pHeader = (irsdk_header *)pSharedMem; + lastTickCount = INT_MAX; + } + + if(pSharedMem) + { + if(!hDataValidEvent) + { + hDataValidEvent = OpenEvent(SYNCHRONIZE, false, IRSDK_DATAVALIDEVENTNAME); + lastTickCount = INT_MAX; + } + + if(hDataValidEvent) + { + isInitialized = true; + return isInitialized; + } + //else printf("Error opening event: %d\n", GetLastError()); + } + //else printf("Error mapping file: %d\n", GetLastError()); + } + //else printf("Error opening file: %d\n", GetLastError()); + + isInitialized = false; + return isInitialized; +} + +void irsdk_shutdown() +{ + if(hDataValidEvent) + CloseHandle(hDataValidEvent); + + if(pSharedMem) + UnmapViewOfFile(pSharedMem); + + if(hMemMapFile) + CloseHandle(hMemMapFile); + + hDataValidEvent = NULL; + pSharedMem = NULL; + pHeader = NULL; + hMemMapFile = NULL; + + isInitialized = false; + lastTickCount = INT_MAX; +} + +bool irsdk_getNewData(char *data) +{ + if(isInitialized || irsdk_startup()) + { +#ifdef _MSC_VER + _ASSERTE(NULL != pHeader); +#endif + + // if sim is not active, then no new data + if(!(pHeader->status & irsdk_stConnected)) + { + lastTickCount = INT_MAX; + return false; + } + + int latest = 0; + for(int i=1; inumBuf; i++) + if(pHeader->varBuf[latest].tickCount < pHeader->varBuf[i].tickCount) + latest = i; + + // if newer than last recieved, than report new data + if(lastTickCount < pHeader->varBuf[latest].tickCount) + { + // if asked to retrieve the data + if(data) + { + // try twice to get the data out + for(int count = 0; count < 2; count++) + { + int curTickCount = pHeader->varBuf[latest].tickCount; + memcpy(data, pSharedMem + pHeader->varBuf[latest].bufOffset, pHeader->bufLen); + if(curTickCount == pHeader->varBuf[latest].tickCount) + { + lastTickCount = curTickCount; + lastValidTime = time(NULL); + return true; + } + } + // if here, the data changed out from under us. + return false; + } + else + { + lastTickCount = pHeader->varBuf[latest].tickCount; + lastValidTime = time(NULL); + return true; + } + } + // if older than last recieved, than reset, we probably disconnected + else if(lastTickCount > pHeader->varBuf[latest].tickCount) + { + lastTickCount = pHeader->varBuf[latest].tickCount; + return false; + } + // else the same, and nothing changed this tick + } + + return false; +} + + +bool irsdk_waitForDataReady(int timeOut, char *data) +{ +#ifdef _MSC_VER + _ASSERTE(timeOut >= 0); +#endif + + if(isInitialized || irsdk_startup()) + { + // just to be sure, check before we sleep + if(irsdk_getNewData(data)) + return true; + + // sleep till signaled + WaitForSingleObject(hDataValidEvent, timeOut); + + // we woke up, so check for data + if(irsdk_getNewData(data)) + return true; + else + return false; + } + + // sleep if error + if(timeOut > 0) + Sleep(timeOut); + + return false; +} + +bool irsdk_isConnected() +{ + if(isInitialized) + { + int elapsed = (int)difftime(time(NULL), lastValidTime); + return (pHeader->status & irsdk_stConnected) > 0 && elapsed < timeout; + } + + return false; +} + +const irsdk_header *irsdk_getHeader() +{ + if(isInitialized) + { + return pHeader; + } + + return NULL; +} + +// direct access to the data buffer +// Warnign! This buffer is volitile so read it out fast! +// Use the cached copy from irsdk_waitForDataReady() or irsdk_getNewData() instead +const char *irsdk_getData(int index) +{ + if(isInitialized) + { + return pSharedMem + pHeader->varBuf[index].bufOffset; + } + + return NULL; +} + +const char *irsdk_getSessionInfoStr() +{ + if(isInitialized) + { + return pSharedMem + pHeader->sessionInfoOffset; + } + return NULL; +} + +int irsdk_getSessionInfoStrUpdate() +{ + if(isInitialized) + { + return pHeader->sessionInfoUpdate; + } + return -1; +} + +const irsdk_varHeader *irsdk_getVarHeaderPtr() +{ + if(isInitialized) + { + return ((irsdk_varHeader*)(pSharedMem + pHeader->varHeaderOffset)); + } + return NULL; +} + +const irsdk_varHeader *irsdk_getVarHeaderEntry(int index) +{ + if(isInitialized) + { + if(index >= 0 && index < pHeader->numVars) + { + return &((irsdk_varHeader*)(pSharedMem + pHeader->varHeaderOffset))[index]; + } + } + return NULL; +} + +// Note: this is a linear search, so cache the results +int irsdk_varNameToIndex(const char *name) +{ + const irsdk_varHeader *pVar; + + if(name) + { + for(int index=0; indexnumVars; index++) + { + pVar = irsdk_getVarHeaderEntry(index); + if(pVar && 0 == strncmp(name, pVar->name, IRSDK_MAX_STRING)) + { + return index; + } + } + } + + return -1; +} + +int irsdk_varNameToOffset(const char *name) +{ + const irsdk_varHeader *pVar; + + if(name) + { + for(int index=0; indexnumVars; index++) + { + pVar = irsdk_getVarHeaderEntry(index); + if(pVar && 0 == strncmp(name, pVar->name, IRSDK_MAX_STRING)) + { + return pVar->offset; + } + } + } + + return -1; +} + +unsigned int irsdk_getBroadcastMsgID() +{ + static unsigned int msgId = RegisterWindowMessage(IRSDK_BROADCASTMSGNAME); + + return msgId; +} + +void irsdk_broadcastMsg(irsdk_BroadcastMsg msg, int var1, int var2, int var3) +{ + irsdk_broadcastMsg(msg, var1, static_castMAKELONG(var2, var3)); +} + +void irsdk_broadcastMsg(irsdk_BroadcastMsg msg, int var1, float var2) +{ + // multiply by 2^16-1 to move fractional part to the integer part + int real = (int)(var2 * 65536.0f); + + irsdk_broadcastMsg(msg, var1, real); +} + +void irsdk_broadcastMsg(irsdk_BroadcastMsg msg, int var1, int var2) +{ + static unsigned int msgId = irsdk_getBroadcastMsgID(); + + if(msgId && msg >= 0 && msg < irsdk_BroadcastLast) + { + SendNotifyMessage(HWND_BROADCAST, msgId, MAKELONG(msg, var1), var2); + } +} + +int irsdk_padCarNum(int num, int zero) +{ + int retVal = num; + int numPlace = 1; + if(num > 99) + numPlace = 3; + else if(num > 9) + numPlace = 2; + if(zero) + { + numPlace += zero; + retVal = num + 1000*numPlace; + } + + return retVal; +} diff --git a/src/app/irsdk/native/lib/yaml_parser.cpp b/src/app/irsdk/native/lib/yaml_parser.cpp new file mode 100644 index 0000000..5d66ba9 --- /dev/null +++ b/src/app/irsdk/native/lib/yaml_parser.cpp @@ -0,0 +1,176 @@ +/* +Copyright (c) 2013, iRacing.com Motorsport Simulations, LLC. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of iRacing.com Motorsport Simulations nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +enum yaml_state { + space, + key, + keysep, + value, + newline +}; + +// super simple YAML parser +bool parseYaml(const char *data, const char* path, const char **val, int *len) +{ + if(data && path && val && len) + { + // make sure we set this to something + *val = NULL; + *len = 0; + + int depth = 0; + yaml_state state = space; + + const char *keystr = NULL; + int keylen = 0; + + const char *valuestr = NULL; + int valuelen = 0; + + const char *pathptr = path; + int pathdepth = 0; + + while(*data) + { + switch(*data) + { + case ' ': + if(state == newline) + state = space; + if(state == space) + depth++; + else if(state == key) + keylen++; + else if(state == value) + valuelen++; + break; + case '-': + if(state == newline) + state = space; + if(state == space) + depth++; + else if(state == key) + keylen++; + else if(state == value) + valuelen++; + else if(state == keysep) + { + state = value; + valuestr = data; + valuelen = 1; + } + break; + case ':': + if(state == key) + { + state = keysep; + keylen++; + } + else if(state == keysep) + { + state = value; + valuestr = data; + } + else if(state == value) + valuelen++; + break; + case '\n': + case '\r': + if(state != newline) + { + if(depth < pathdepth) + { + return false; + } + else if(keylen && 0 == strncmp(keystr, pathptr, keylen)) + { + bool found = true; + //do we need to test the value? + if(*(pathptr+keylen) == '{') + { + //search for closing brace + int pathvaluelen = keylen + 1; + while(*(pathptr+pathvaluelen) && *(pathptr+pathvaluelen) != '}') + pathvaluelen++; + + if(valuelen == pathvaluelen - (keylen+1) && 0 == strncmp(valuestr, (pathptr+keylen+1), valuelen)) + pathptr += valuelen + 2; + else + found = false; + } + + if(found) + { + pathptr += keylen; + pathdepth = depth; + + if(*pathptr == '\0') + { + *val = valuestr; + *len = valuelen; + return true; + } + } + } + + depth = 0; + keylen = 0; + valuelen = 0; + } + state = newline; + break; + default: + if(state == space || state == newline) + { + state = key; + keystr = data; + keylen = 0; //redundant? + } + else if(state == keysep) + { + state = value; + valuestr = data; + valuelen = 0; //redundant? + } + if(state == key) + keylen++; + if(state == value) + valuelen++; + break; + } + + // important, increment our pointer + data++; + } + + } + return false; +} + diff --git a/src/app/irsdk/native/lib/yaml_parser.h b/src/app/irsdk/native/lib/yaml_parser.h new file mode 100644 index 0000000..6abcf78 --- /dev/null +++ b/src/app/irsdk/native/lib/yaml_parser.h @@ -0,0 +1,34 @@ +/* +Copyright (c) 2013, iRacing.com Motorsport Simulations, LLC. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of iRacing.com Motorsport Simulations nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef YAML_PARSER_H +#define YAML_PARSER_H + +// super simple YAML parser +bool parseYaml(const char *data, const char* path, const char **val, int *len); + +#endif //YAML_PARSER_H diff --git a/src/app/irsdk/native/scripts/generate-var-types.js b/src/app/irsdk/native/scripts/generate-var-types.js new file mode 100644 index 0000000..72dc26f --- /dev/null +++ b/src/app/irsdk/native/scripts/generate-var-types.js @@ -0,0 +1,72 @@ +/* eslint-disable @typescript-eslint/no-require-imports */ +const NativeSDK = require("../build/Debug/irsdk_node.node").iRacingSdkNode; +const path = require("path"); +const fs = require("fs"); + +const TARGET_FILE = "_GENERATED_telemetry.ts"; +const OUT_PATH = path.resolve(process.cwd(), "../types/", TARGET_FILE); + +console.log("Generating iRacing telemetry variable types."); +console.log("Make sure the sim is running!"); + +const sdk = new NativeSDK(); +sdk.startSDK(); + +// Telemetry command, Start Recording +sdk.broadcast(10, 1); +// Wait a max of 5s +if (!sdk.waitForData(5000)) { + process.stderr.write("No data. Make sure the sim is running and try again."); + process.exit(1); +} + +const varTypes = [ + "string", + "boolean", + "number", + "number", + "number", + "number", +]; + +// Get all the types +const types = sdk.__getTelemetryTypes(); +const out = ` +// ! THIS FILE IS AUTO-GENERATED, EDITS WILL BE OVERRIDDEN ! +// ! Make changes to the generate-var-types in @irsk-node/native ! + +/** + * A variable included in the telemetry. + */ +export interface TelemetryVariable { + /** The name of the variable. */ + name: string; + /** The description. */ + description: string; + /** The unit of the value (ex. "kg/m^2") */ + unit: string; + /** Should it be treated as a time? */ + countAsTime: boolean; + /** The number of values provided. */ + length: number; + /** The native variable type */ + varType: number; + /** The current value of this variable. */ + value: VarType; +} + +export interface TelemetryVarList { +${Object.keys(types).map((varName) => + ` ${varName}: TelemetryVariable<${varTypes[types[varName]]}[]>` +).join(";\n")}; +} +`; + +fs.writeFile(OUT_PATH, out, "utf-8", (err) => { + if (err) { + console.error("There was an error creating the file:", err); + return; + } + console.log("Successfully generated types!"); + process.exit(0); +}); diff --git a/src/app/irsdk/node/constants.ts b/src/app/irsdk/node/constants.ts new file mode 100644 index 0000000..b2154de --- /dev/null +++ b/src/app/irsdk/node/constants.ts @@ -0,0 +1 @@ +export const SIM_STATUS_URI = 'http://127.0.0.1:32034/get_sim_status?object=simStatus'; diff --git a/src/app/irsdk/node/get-sdk.ts b/src/app/irsdk/node/get-sdk.ts new file mode 100644 index 0000000..c31efbb --- /dev/null +++ b/src/app/irsdk/node/get-sdk.ts @@ -0,0 +1,13 @@ +import { platform } from 'os'; + +import type { INativeSDK } from '../native'; + +import { MockSDK } from './utils/mock-sdk'; + +export async function getSdkOrMock(): Promise { + if (platform() === 'win32') { + const Sdk = (await import('../native')).NativeSDK; + return new Sdk(); + } + return new MockSDK(); +} diff --git a/src/app/irsdk/node/index.ts b/src/app/irsdk/node/index.ts new file mode 100644 index 0000000..aadfc1f --- /dev/null +++ b/src/app/irsdk/node/index.ts @@ -0,0 +1 @@ +export * from './irsdk-node'; diff --git a/src/app/irsdk/node/irsdk-node.ts b/src/app/irsdk/node/irsdk-node.ts new file mode 100644 index 0000000..305e014 --- /dev/null +++ b/src/app/irsdk/node/irsdk-node.ts @@ -0,0 +1,379 @@ +import yaml from 'js-yaml'; +import { + BroadcastMessages, + CameraState, + ChatCommand, + FFBCommand, + PitCommand, + ReloadTexturesCommand, + ReplayPositionCommand, + ReplaySearchCommand, + ReplayStateCommand, + TelemetryCommand, + VideoCaptureCommand, + TelemetryVariable, + TelemetryVarList, + CameraInfo, + CarSetupInfo, + DriverInfo, + RadioInfo, + SessionList, + SplitTimeInfo, + WeekendInfo, + SessionData, +} from '../types'; +import type { INativeSDK } from '../native'; + +import { getSimStatus } from './utils'; +import { getSdkOrMock } from './get-sdk'; + +function copyTelemData< +K extends keyof TelemetryVarList = keyof TelemetryVarList, +T extends TelemetryVarList[K] = TelemetryVarList[K] +>(src: T, key: K, dest: TelemetryVarList): void { + dest[key] = { ...src }; + // bool + if (src.varType === 1) { + dest[key].value = []; + const arr = new Int8Array(src.value as number[]); + arr.forEach((val, i) => { + dest[key].value[i] = !!val; + }); + return; + } + // numbers + if (src.varType === 2 || src.varType === 3) { // int + dest[key].value = [...new Int32Array(src.value as number[])]; + } else if (src.varType === 4) { // float + dest[key].value = [...new Float32Array(src.value as number[])]; + } else if (src.varType === 5) { // double + dest[key].value = [...new Float64Array(src.value as number[])]; + } +} + +export class IRacingSDK { + // Public + /** + * Enable attempting to auto-start telemetry when starting the SDK (if it is not running). + * @default false + */ + public autoEnableTelemetry = false; + + // Private + private _dataVer = -1; + + private _sessionData: SessionData | null = null; + + private _sdk?: INativeSDK; + + private _sdkReq: Promise; + + constructor() { + this._sdkReq = this._loadSDK(); + void IRacingSDK.IsSimRunning(); + } + + private async _loadSDK(): Promise { + const sdk = await getSdkOrMock(); + this._sdk = sdk; + this._sdk.startSDK(); + } + + public async ready(): Promise { + await this._sdkReq; + return true; + } + + /** + * The current version number of the session data. Increments internally every time data changes. + * @property {number} + * @readonly + */ + public get currDataVersion(): number { + return this._sdk?.currDataVersion ?? -1; + } + + /** Whether or not to enable verbose logging in the SDK. + * @property {boolean} + */ + public get enableLogging(): boolean { + return this._sdk?.enableLogging ?? false; + } + + public set enableLogging(value: boolean) { + if (this._sdk) this._sdk.enableLogging = value; + } + + // @todo: add getter for current session string version + + /** + * Checks whether the simulation service is running. + * @returns {boolean} True if the service is running. + */ + public static async IsSimRunning(): Promise { + try { + const result = await getSimStatus(); + return result; + } catch (e) { + console.error('Could not successfully determine sim status:', e); + } + return false; + } + + public get sessionStatusOK(): boolean { + return this._sdk?.isRunning() ?? false; + } + + /** + * Starts the native iRacing SDK and begins subscribing for data. + * @returns {boolean} If the SDK started successfully. + */ + public startSDK(): boolean { + if (!this._sdk?.isRunning()) { + const successful = this._sdk?.startSDK() ?? false; + if (this.autoEnableTelemetry) { + this.enableTelemetry(true); + } + return successful; + } + return true; + } + + /** + * Stops the SDK from running and resets the data version. + */ + public stopSDK(): void { + this._sdk?.stopSDK(); + this._dataVer = -1; + } + + /** + * Wait for new data from the sdk. + * @param {number} timeout Timeout (in ms). Max is 60fps (1/60) + */ + public waitForData(timeout?: number): boolean { + return this._sdk?.waitForData(timeout) ?? false; + } + + /** + * Gets the current session data (from yaml format). + * @returns {SessionData} + */ + public getSessionData(): SessionData | null { + if (this._sessionData && this._dataVer === this.currDataVersion) return this._sessionData; + if (!this._sdk) return null; + + try { + const seshString = this._sdk?.getSessionData(); + this._sessionData = yaml.load(seshString) as SessionData; + return this._sessionData; + } catch (err) { + console.error('There was an error getting session data:', err); + } + + return null; + } + + /** + * Gets the current weekend info from the session data + * @returns {WeekendInfo} + */ + public getWeekendInfo(): WeekendInfo | null { + const session = this.getSessionData(); + return session?.WeekendInfo ?? null; + } + + /** + * Gets the current session info from the session data. + * @returns {SessionInfo} + */ + public getSessionInfo(): SessionList | null { + const session = this.getSessionData(); + return session?.SessionInfo ?? null; + } + + /** + * Gets the current camera info from the session data. + * @returns {CameraInfo} + */ + public getCameraInfo(): CameraInfo | null { + const session = this.getSessionData(); + return session?.CameraInfo ?? null; + } + + /** + * Gets the current radio info from the session data. + * @returns {RadioInfo} + */ + public getRadioInfo(): RadioInfo | null { + const session = this.getSessionData(); + return session?.RadioInfo ?? null; + } + + /** + * Gets the current driver info from the session data. + * @returns {DriverInfo} + */ + public getDriverInfo(): DriverInfo | null { + const session = this.getSessionData(); + return session?.DriverInfo ?? null; + } + + /** + * Gets the current split time info from the session data. + * @returns {SplitTimeInfo} + */ + public getSplitInfo(): SplitTimeInfo | null { + const session = this.getSessionData(); + return session?.SplitTimeInfo ?? null; + } + + /** + * Gets the current session info from the session data. + * @returns {CarSetupInfo} + */ + public getCarSetupInfo(): CarSetupInfo | null { + const session = this.getSessionData(); + return session?.CarSetup ?? null; + } + + /** + * Get the current value of the telemetry variables. + */ + public getTelemetry(): TelemetryVarList { + const rawData = this._sdk?.getTelemetryData(); + const data: Partial = {}; + + if (rawData) { + Object.keys(rawData).forEach((dataKey) => { + copyTelemData( + rawData[dataKey as keyof TelemetryVarList], + dataKey as keyof TelemetryVarList, + data as TelemetryVarList, + ); + }); + } + + return data as TelemetryVarList; + } + + /** + * Request the value of the given telemetry variable. + * @param index The number index of the variable. Only use if you know what you are doing! + */ + public getTelemetryVariable(index: number): TelemetryVariable | null; + + /** + * Request the value of the given telemetry variable. + * @param varName The name of the variable to retrieve. + */ + // eslint-disable-next-line @typescript-eslint/unified-signatures + public getTelemetryVariable(varName: keyof TelemetryVarList): TelemetryVariable | null; + + public getTelemetryVariable(telemVar: number | keyof TelemetryVarList): TelemetryVariable | null { + if (!this._sdk) return null; + + // @todo Need to fix this type. + const rawData = this._sdk?.getTelemetryVariable(telemVar as string); + const parsed: Partial = {}; + + // @todo good grief these types need to be fixed asap + copyTelemData( + rawData as TelemetryVariable, // eslint-disable-line + rawData.name as keyof TelemetryVarList, + parsed as TelemetryVarList, + ); + + return parsed[rawData.name as keyof TelemetryVarList] as TelemetryVariable; + } + + // Broadcast commands + public enableTelemetry(enabled: boolean): void { + const command = enabled ? TelemetryCommand.Start : TelemetryCommand.Stop; + this._sdk?.broadcast(BroadcastMessages.TelemCommand, command); + } + + public restartTelemetry(): void { + this._sdk?.broadcast(BroadcastMessages.TelemCommand, TelemetryCommand.Restart); + } + + public changeCameraPosition(position: number, group: number, camera: number): void { + this._sdk?.broadcast(BroadcastMessages.CameraSwitchPos, position, group, camera); + } + + // @todo: needs to be padded + public changeCameraNumber(driver: number, group: number, camera: number): void { + this._sdk?.broadcast(BroadcastMessages.CameraSwitchNum, driver, group, camera); + } + + public changeCameraState(state: CameraState): void { + this._sdk?.broadcast(BroadcastMessages.CameraSetState, state); + } + + public changeReplaySpeed(speed: number, slowMotion: boolean): void { + this._sdk?.broadcast(BroadcastMessages.ReplaySetPlaySpeed, speed, slowMotion ? 1 : 0); + } + + public changeReplayPosition(position: ReplayPositionCommand, frame: number): void { + this._sdk?.broadcast(BroadcastMessages.ReplaySetPlayPosition, position, frame); + } + + public searchReplay(command: ReplaySearchCommand): void { + this._sdk?.broadcast(BroadcastMessages.ReplaySearch, command); + } + + public changeReplayState(state: ReplayStateCommand): void { + this._sdk?.broadcast(BroadcastMessages.ReplaySetState, state); + } + + public triggerReplaySessionSearch(session: number, time: number): void { + this._sdk?.broadcast(BroadcastMessages.ReplaySearchSessionTime, session, time); + } + + public reloadAllTextures(): void { + this._sdk?.broadcast(BroadcastMessages.ReloadTextures, ReloadTexturesCommand.All, 0); + } + + public reloadCarTextures(car: number): void { + this._sdk?.broadcast(BroadcastMessages.ReloadTextures, ReloadTexturesCommand.CarIndex, car); + } + + public triggerChatState(state: ChatCommand.BeginChat | ChatCommand.Cancel | ChatCommand.Reply): void { + this._sdk?.broadcast(BroadcastMessages.ChatCommand, state, 1); + } + + /** + * @param {number} macro Between 1 - 15 + */ + public triggerChatMacro(macro: number): void { + const clamped = Math.min(15, Math.max(1, macro)); + this._sdk?.broadcast(BroadcastMessages.ChatCommand, ChatCommand.Macro, clamped); + } + + public triggerPitClearCommand( + command: PitCommand.Clear | PitCommand.ClearTires | PitCommand.ClearWS | PitCommand.ClearFR | PitCommand.ClearFuel, + ): void { + this._sdk?.broadcast(BroadcastMessages.PitCommand, command); + } + + public triggerPitCommand( + command: PitCommand.WS | PitCommand.FR, + ): void { + this._sdk?.broadcast(BroadcastMessages.PitCommand, command); + } + + public triggerPitChange( + command: PitCommand.Fuel | PitCommand.LF | PitCommand.RF | PitCommand.LR | PitCommand.RR, + amount: number, + ): void { + this._sdk?.broadcast(BroadcastMessages.PitCommand, command, amount); + } + + public changeFFB(mode: FFBCommand, amount: number): void { + this._sdk?.broadcast(BroadcastMessages.FFBCommand, mode, amount); + } + + public triggerVideoCapture(command: VideoCaptureCommand): void { + this._sdk?.broadcast(BroadcastMessages.VideoCapture, command); + } +} diff --git a/src/app/irsdk/node/utils/index.ts b/src/app/irsdk/node/utils/index.ts new file mode 100644 index 0000000..2fbffa1 --- /dev/null +++ b/src/app/irsdk/node/utils/index.ts @@ -0,0 +1 @@ +export * from './sim-status'; diff --git a/src/app/irsdk/node/utils/mock-data/loader.ts b/src/app/irsdk/node/utils/mock-data/loader.ts new file mode 100644 index 0000000..90f6ac7 --- /dev/null +++ b/src/app/irsdk/node/utils/mock-data/loader.ts @@ -0,0 +1,12 @@ +import { TelemetryVarList } from '../../../types'; +import yaml from 'js-yaml'; + +export const loadMockSessionData = async (): Promise => { + const json = await import('./session.json'); + return yaml.dump(json.default); +}; + +export const loadMockTelemetry = async (): Promise => { + const json = await import('./telemetry.json'); + return json.default as unknown as TelemetryVarList; +}; diff --git a/src/app/irsdk/node/utils/mock-data/session.json b/src/app/irsdk/node/utils/mock-data/session.json new file mode 100644 index 0000000..615512c --- /dev/null +++ b/src/app/irsdk/node/utils/mock-data/session.json @@ -0,0 +1,5334 @@ +{ + "WeekendInfo": { + "TrackName": "virginia 2022 full", + "TrackID": 465, + "TrackLength": "5.22 km", + "TrackLengthOfficial": "5.26 km", + "TrackDisplayName": "Virginia International Raceway", + "TrackDisplayShortName": "VIR", + "TrackConfigName": "Full Course", + "TrackCity": "Alton", + "TrackCountry": "USA", + "TrackAltitude": "166.18 m", + "TrackLatitude": "36.568814 m", + "TrackLongitude": "-79.206660 m", + "TrackNorthOffset": "4.2700 rad", + "TrackNumTurns": 20, + "TrackPitSpeedLimit": "60.00 kph", + "TrackType": "road course", + "TrackDirection": "neutral", + "TrackWeatherType": "Realistic", + "TrackSkies": "Dynamic", + "TrackSurfaceTemp": "22.80 C", + "TrackAirTemp": "19.80 C", + "TrackAirPressure": "29.52 Hg", + "TrackWindVel": "1.39 m/s", + "TrackWindDir": "3.08 rad", + "TrackRelativeHumidity": "33 %", + "TrackFogLevel": "0 %", + "TrackPrecipitation": "0 %", + "TrackCleanup": 1, + "TrackDynamicTrack": 1, + "TrackVersion": "2024.08.22.02", + "SeriesID": 112, + "SeasonID": 5033, + "SessionID": 258042302, + "SubSessionID": 73100610, + "LeagueID": 0, + "Official": 1, + "RaceWeek": 11, + "EventType": "Race", + "Category": "SportsCar", + "SimMode": "full", + "TeamRacing": 0, + "MinDrivers": 0, + "MaxDrivers": 1, + "DCRuleSet": "None", + "QualifierMustStartRace": 0, + "NumCarClasses": 4, + "NumCarTypes": 5, + "HeatRacing": 0, + "BuildType": "Release", + "BuildTarget": "Members", + "BuildVersion": "2024.10.09.01", + "RaceFarm": "US-East-OH", + "WeekendOptions": { + "NumStarters": 40, + "StartingGrid": "2x2 inline pole on left", + "QualifyScoring": "best lap", + "CourseCautions": "local", + "StandingStart": 0, + "ShortParadeLap": 0, + "Restarts": "double file lapped cars behind", + "WeatherType": "Realistic", + "Skies": "Dynamic", + "WindDirection": "N", + "WindSpeed": "3.22 km/h", + "WeatherTemp": "25.56 C", + "RelativeHumidity": "45 %", + "FogLevel": "0 %", + "TimeOfDay": "3:25 pm", + "Date": "2024-11-30T00:00:00.000Z", + "EarthRotationSpeedupFactor": 1, + "Unofficial": 0, + "CommercialMode": "consumer", + "NightMode": "variable", + "IsFixedSetup": 0, + "StrictLapsChecking": "default", + "HasOpenRegistration": 0, + "HardcoreLevel": 1, + "NumJokerLaps": 0, + "IncidentLimit": 17, + "FastRepairsLimit": 1, + "GreenWhiteCheckeredLimit": 0 + }, + "TelemetryOptions": { + "TelemetryDiskFile": "" + } + }, + "SessionInfo": { + "Sessions": [ + { + "SessionNum": 0, + "SessionLaps": "unlimited", + "SessionTime": "180.0000 sec", + "SessionNumLapsToAvg": 0, + "SessionType": "Practice", + "SessionTrackRubberState": "moderate usage", + "SessionName": "PRACTICE", + "SessionSubType": null, + "SessionSkipped": 0, + "SessionRunGroupsUsed": 0, + "SessionEnforceTireCompoundChange": 0, + "ResultsPositions": [ + { + "Position": 1, + "ClassPosition": 0, + "CarIdx": 28, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.041, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 2, + "ClassPosition": 1, + "CarIdx": 29, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 3, + "ClassPosition": 2, + "CarIdx": 30, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.563, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 4, + "ClassPosition": 0, + "CarIdx": 12, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 5, + "ClassPosition": 1, + "CarIdx": 13, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.381, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 6, + "ClassPosition": 3, + "CarIdx": 31, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 1, + "JokerLapsComplete": 0, + "LapsDriven": 0.364, + "Incidents": 2, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 7, + "ClassPosition": 4, + "CarIdx": 32, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 8, + "ClassPosition": 2, + "CarIdx": 14, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.736, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 9, + "ClassPosition": 5, + "CarIdx": 33, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 10, + "ClassPosition": 3, + "CarIdx": 15, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 11, + "ClassPosition": 6, + "CarIdx": 34, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 12, + "ClassPosition": 7, + "CarIdx": 35, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 1, + "JokerLapsComplete": 0, + "LapsDriven": 0.275, + "Incidents": 4, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 13, + "ClassPosition": 4, + "CarIdx": 16, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.604, + "Incidents": 3, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 14, + "ClassPosition": 5, + "CarIdx": 17, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.548, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 15, + "ClassPosition": 0, + "CarIdx": 1, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 16, + "ClassPosition": 8, + "CarIdx": 36, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 17, + "ClassPosition": 6, + "CarIdx": 18, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 18, + "ClassPosition": 7, + "CarIdx": 19, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 19, + "ClassPosition": 8, + "CarIdx": 20, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.287, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 20, + "ClassPosition": 1, + "CarIdx": 2, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.541, + "Incidents": 6, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 21, + "ClassPosition": 9, + "CarIdx": 21, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.274, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 22, + "ClassPosition": 10, + "CarIdx": 22, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.362, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 23, + "ClassPosition": 11, + "CarIdx": 23, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 24, + "ClassPosition": 12, + "CarIdx": 24, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.273, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 25, + "ClassPosition": 13, + "CarIdx": 25, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 26, + "ClassPosition": 2, + "CarIdx": 3, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 27, + "ClassPosition": 9, + "CarIdx": 37, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 28, + "ClassPosition": 10, + "CarIdx": 38, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 29, + "ClassPosition": 11, + "CarIdx": 39, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 30, + "ClassPosition": 12, + "CarIdx": 40, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 31, + "ClassPosition": 14, + "CarIdx": 26, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 32, + "ClassPosition": 15, + "CarIdx": 27, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 33, + "ClassPosition": 3, + "CarIdx": 4, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.56, + "Incidents": 4, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 34, + "ClassPosition": 4, + "CarIdx": 5, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 35, + "ClassPosition": 5, + "CarIdx": 6, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 1, + "JokerLapsComplete": 0, + "LapsDriven": 0.107, + "Incidents": 4, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 36, + "ClassPosition": 6, + "CarIdx": 7, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.786, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 37, + "ClassPosition": 7, + "CarIdx": 8, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.747, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 38, + "ClassPosition": 8, + "CarIdx": 9, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 39, + "ClassPosition": 9, + "CarIdx": 10, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 40, + "ClassPosition": 10, + "CarIdx": 11, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + } + ], + "ResultsFastestLap": [ + { + "CarIdx": 255, + "FastestLap": 0, + "FastestTime": -1 + } + ], + "ResultsAverageLapTime": -1, + "ResultsNumCautionFlags": 0, + "ResultsNumCautionLaps": 0, + "ResultsNumLeadChanges": 0, + "ResultsLapsComplete": -1, + "ResultsOfficial": 1 + }, + { + "SessionNum": 1, + "SessionLaps": 2, + "SessionTime": "480.0000 sec", + "SessionNumLapsToAvg": 0, + "SessionType": "Lone Qualify", + "SessionTrackRubberState": "carry over", + "SessionName": "QUALIFY", + "SessionSubType": null, + "SessionSkipped": 0, + "SessionRunGroupsUsed": 0, + "SessionEnforceTireCompoundChange": 0, + "ResultsPositions": [ + { + "Position": 1, + "ClassPosition": 0, + "CarIdx": 11, + "Lap": 2, + "Time": 115.2256, + "FastestLap": 2, + "FastestTime": 115.2256, + "LastTime": 115.2256, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.108, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 2, + "ClassPosition": 1, + "CarIdx": 5, + "Lap": 2, + "Time": 115.2539, + "FastestLap": 2, + "FastestTime": 115.2539, + "LastTime": 115.2539, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.484, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 3, + "ClassPosition": 2, + "CarIdx": 4, + "Lap": 1, + "Time": 115.7144, + "FastestLap": 1, + "FastestTime": 115.7144, + "LastTime": 115.876, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.047, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 4, + "ClassPosition": 3, + "CarIdx": 8, + "Lap": 2, + "Time": 115.7666, + "FastestLap": 2, + "FastestTime": 115.7666, + "LastTime": 115.7666, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.046, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 5, + "ClassPosition": 4, + "CarIdx": 7, + "Lap": 1, + "Time": 116.0211, + "FastestLap": 1, + "FastestTime": 116.0211, + "LastTime": 116.2048, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.071, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 6, + "ClassPosition": 5, + "CarIdx": 1, + "Lap": 1, + "Time": 117.6368, + "FastestLap": 1, + "FastestTime": 117.6368, + "LastTime": 117.6368, + "LapsLed": 0, + "LapsComplete": 1, + "JokerLapsComplete": 0, + "LapsDriven": 2.072, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 7, + "ClassPosition": 6, + "CarIdx": 9, + "Lap": 2, + "Time": 120.6603, + "FastestLap": 2, + "FastestTime": 120.6603, + "LastTime": 120.6603, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.14, + "Incidents": 3, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 8, + "ClassPosition": 0, + "CarIdx": 33, + "Lap": 2, + "Time": 128.1767, + "FastestLap": 2, + "FastestTime": 128.1767, + "LastTime": 128.1767, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.046, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 9, + "ClassPosition": 0, + "CarIdx": 18, + "Lap": 1, + "Time": 128.2224, + "FastestLap": 1, + "FastestTime": 128.2224, + "LastTime": 128.2224, + "LapsLed": 0, + "LapsComplete": 1, + "JokerLapsComplete": 0, + "LapsDriven": 2.043, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 10, + "ClassPosition": 1, + "CarIdx": 19, + "Lap": 1, + "Time": 128.2992, + "FastestLap": 1, + "FastestTime": 128.2992, + "LastTime": 128.2992, + "LapsLed": 0, + "LapsComplete": 1, + "JokerLapsComplete": 0, + "LapsDriven": 2.066, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 11, + "ClassPosition": 2, + "CarIdx": 24, + "Lap": 2, + "Time": 128.3399, + "FastestLap": 2, + "FastestTime": 128.3399, + "LastTime": 128.3399, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.416, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 12, + "ClassPosition": 3, + "CarIdx": 15, + "Lap": 1, + "Time": 128.412, + "FastestLap": 1, + "FastestTime": 128.412, + "LastTime": 128.4784, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.041, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 13, + "ClassPosition": 1, + "CarIdx": 36, + "Lap": 1, + "Time": 128.6368, + "FastestLap": 1, + "FastestTime": 128.6368, + "LastTime": 128.6368, + "LapsLed": 0, + "LapsComplete": 1, + "JokerLapsComplete": 0, + "LapsDriven": 2.892, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 14, + "ClassPosition": 2, + "CarIdx": 34, + "Lap": 2, + "Time": 128.7679, + "FastestLap": 2, + "FastestTime": 128.7679, + "LastTime": 128.7679, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.063, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 15, + "ClassPosition": 3, + "CarIdx": 30, + "Lap": 2, + "Time": 128.9203, + "FastestLap": 2, + "FastestTime": 128.9203, + "LastTime": 128.9203, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.237, + "Incidents": 5, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 16, + "ClassPosition": 4, + "CarIdx": 13, + "Lap": 1, + "Time": 129.4624, + "FastestLap": 1, + "FastestTime": 129.4624, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.542, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 17, + "ClassPosition": 4, + "CarIdx": 35, + "Lap": 1, + "Time": 129.6274, + "FastestLap": 1, + "FastestTime": 129.6274, + "LastTime": 129.8665, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.076, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 18, + "ClassPosition": 5, + "CarIdx": 39, + "Lap": 1, + "Time": 129.6396, + "FastestLap": 1, + "FastestTime": 129.6396, + "LastTime": 129.6396, + "LapsLed": 0, + "LapsComplete": 1, + "JokerLapsComplete": 0, + "LapsDriven": 3.265, + "Incidents": 2, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 19, + "ClassPosition": 6, + "CarIdx": 37, + "Lap": 2, + "Time": 129.7209, + "FastestLap": 2, + "FastestTime": 129.7209, + "LastTime": 129.7209, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.048, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 20, + "ClassPosition": 7, + "CarIdx": 38, + "Lap": 1, + "Time": 129.799, + "FastestLap": 1, + "FastestTime": 129.799, + "LastTime": 129.799, + "LapsLed": 0, + "LapsComplete": 1, + "JokerLapsComplete": 0, + "LapsDriven": 2.044, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 21, + "ClassPosition": 5, + "CarIdx": 27, + "Lap": 1, + "Time": 130.6752, + "FastestLap": 1, + "FastestTime": 130.6752, + "LastTime": 131.9421, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.101, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 22, + "ClassPosition": 8, + "CarIdx": 31, + "Lap": 2, + "Time": 130.9186, + "FastestLap": 2, + "FastestTime": 130.9186, + "LastTime": 130.9186, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.069, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 23, + "ClassPosition": 6, + "CarIdx": 16, + "Lap": 2, + "Time": 130.9347, + "FastestLap": 2, + "FastestTime": 130.9347, + "LastTime": 130.9347, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.04, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 24, + "ClassPosition": 7, + "CarIdx": 23, + "Lap": 2, + "Time": 131.008, + "FastestLap": 2, + "FastestTime": 131.008, + "LastTime": 131.008, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.082, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 25, + "ClassPosition": 8, + "CarIdx": 22, + "Lap": 2, + "Time": 134.5112, + "FastestLap": 2, + "FastestTime": 134.5112, + "LastTime": 134.5112, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.073, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 26, + "ClassPosition": 9, + "CarIdx": 14, + "Lap": 2, + "Time": 135.813, + "FastestLap": 2, + "FastestTime": 135.813, + "LastTime": 135.813, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.298, + "Incidents": 2, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 27, + "ClassPosition": 10, + "CarIdx": 20, + "Lap": 1, + "Time": 139.9101, + "FastestLap": 1, + "FastestTime": 139.9101, + "LastTime": 144.5411, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.313, + "Incidents": 2, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 28, + "ClassPosition": 9, + "CarIdx": 28, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.183, + "Incidents": 3, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 29, + "ClassPosition": 10, + "CarIdx": 29, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 30, + "ClassPosition": 11, + "CarIdx": 12, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.091, + "Incidents": 7, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 31, + "ClassPosition": 11, + "CarIdx": 32, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 1, + "JokerLapsComplete": 0, + "LapsDriven": 2.905, + "Incidents": 1, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 32, + "ClassPosition": 12, + "CarIdx": 17, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 2, + "JokerLapsComplete": 0, + "LapsDriven": 3.158, + "Incidents": 5, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 33, + "ClassPosition": 7, + "CarIdx": 2, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 34, + "ClassPosition": 13, + "CarIdx": 21, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 1, + "JokerLapsComplete": 0, + "LapsDriven": 2.536, + "Incidents": 2, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 35, + "ClassPosition": 14, + "CarIdx": 25, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 36, + "ClassPosition": 8, + "CarIdx": 3, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 37, + "ClassPosition": 12, + "CarIdx": 40, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 1, + "JokerLapsComplete": 0, + "LapsDriven": 2.616, + "Incidents": 8, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 38, + "ClassPosition": 15, + "CarIdx": 26, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 1.168, + "Incidents": 2, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 39, + "ClassPosition": 9, + "CarIdx": 6, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 0.076, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 40, + "ClassPosition": 10, + "CarIdx": 10, + "Lap": 0, + "Time": -1, + "FastestLap": -1, + "FastestTime": -1, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 0, + "JokerLapsComplete": 0, + "LapsDriven": 1.86, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + } + ], + "ResultsFastestLap": [ + { + "CarIdx": 11, + "FastestLap": 2, + "FastestTime": 115.2256 + } + ], + "ResultsAverageLapTime": -1, + "ResultsNumCautionFlags": 0, + "ResultsNumCautionLaps": 0, + "ResultsNumLeadChanges": 0, + "ResultsLapsComplete": -1, + "ResultsOfficial": 1 + }, + { + "SessionNum": 2, + "SessionLaps": "unlimited", + "SessionTime": "1500.0000 sec", + "SessionNumLapsToAvg": 0, + "SessionType": "Race", + "SessionTrackRubberState": "carry over", + "SessionName": "RACE", + "SessionSubType": null, + "SessionSkipped": 0, + "SessionRunGroupsUsed": 0, + "SessionEnforceTireCompoundChange": 0, + "ResultsPositions": [ + { + "Position": 1, + "ClassPosition": 0, + "CarIdx": 5, + "Lap": 0, + "Time": 0, + "FastestLap": 5, + "FastestTime": 114.2999, + "LastTime": 115.4786, + "LapsLed": 13, + "LapsComplete": 13, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 2, + "ClassPosition": 1, + "CarIdx": 3, + "Lap": 0, + "Time": 10.5272, + "FastestLap": 12, + "FastestTime": 114.4506, + "LastTime": 115.7261, + "LapsLed": 0, + "LapsComplete": 13, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 3, + "ClassPosition": 2, + "CarIdx": 11, + "Lap": 0, + "Time": 12.0505, + "FastestLap": 5, + "FastestTime": 114.3903, + "LastTime": 115.4036, + "LapsLed": 0, + "LapsComplete": 13, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 4, + "ClassPosition": 3, + "CarIdx": 4, + "Lap": 0, + "Time": 27.7656, + "FastestLap": 13, + "FastestTime": 114.8725, + "LastTime": 114.8725, + "LapsLed": 0, + "LapsComplete": 13, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 5, + "ClassPosition": 4, + "CarIdx": 7, + "Lap": 0, + "Time": 33.9592, + "FastestLap": 5, + "FastestTime": 115.9967, + "LastTime": 116.7067, + "LapsLed": 0, + "LapsComplete": 13, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 6, + "ClassPosition": 5, + "CarIdx": 8, + "Lap": 0, + "Time": 44.1095, + "FastestLap": 3, + "FastestTime": 116.5011, + "LastTime": 116.8522, + "LapsLed": 0, + "LapsComplete": 13, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 7, + "ClassPosition": 6, + "CarIdx": 10, + "Lap": 0, + "Time": 53.973, + "FastestLap": 3, + "FastestTime": 116.5278, + "LastTime": 119.6625, + "LapsLed": 0, + "LapsComplete": 13, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 8, + "ClassPosition": 7, + "CarIdx": 9, + "Lap": 0, + "Time": 62.4008, + "FastestLap": 2, + "FastestTime": 118.1125, + "LastTime": 118.7605, + "LapsLed": 0, + "LapsComplete": 12, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 9, + "ClassPosition": 8, + "CarIdx": 2, + "Lap": 0, + "Time": 75.6564, + "FastestLap": 8, + "FastestTime": 113.3759, + "LastTime": 122.9271, + "LapsLed": 0, + "LapsComplete": 12, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 10, + "ClassPosition": 9, + "CarIdx": 1, + "Lap": 1, + "Time": 125.7391, + "FastestLap": 12, + "FastestTime": 116.4422, + "LastTime": 116.4422, + "LapsLed": 0, + "LapsComplete": 12, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 11, + "ClassPosition": 0, + "CarIdx": 19, + "Lap": 1, + "Time": 167.7512, + "FastestLap": 5, + "FastestTime": 127.5759, + "LastTime": 128.2227, + "LapsLed": 0, + "LapsComplete": 12, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 12, + "ClassPosition": 1, + "CarIdx": 18, + "Lap": 1, + "Time": 172.2404, + "FastestLap": 5, + "FastestTime": 127.2168, + "LastTime": 128.2992, + "LapsLed": 0, + "LapsComplete": 12, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 13, + "ClassPosition": 2, + "CarIdx": 15, + "Lap": 1, + "Time": 163.6042, + "FastestLap": 3, + "FastestTime": 127.479, + "LastTime": 129.0626, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 14, + "ClassPosition": 3, + "CarIdx": 16, + "Lap": 1, + "Time": 167.4271, + "FastestLap": 11, + "FastestTime": 128.2986, + "LastTime": 128.2986, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 15, + "ClassPosition": 4, + "CarIdx": 24, + "Lap": 1, + "Time": 168.3933, + "FastestLap": 4, + "FastestTime": 127.8124, + "LastTime": 129.0925, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 16, + "ClassPosition": 5, + "CarIdx": 23, + "Lap": 1, + "Time": 174.8789, + "FastestLap": 7, + "FastestTime": 129.6642, + "LastTime": 131.5315, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 17, + "ClassPosition": 6, + "CarIdx": 27, + "Lap": 1, + "Time": 175.4728, + "FastestLap": 5, + "FastestTime": 129.4931, + "LastTime": 131.9713, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 18, + "ClassPosition": 0, + "CarIdx": 40, + "Lap": 1, + "Time": 176.2407, + "FastestLap": 2, + "FastestTime": 128.2977, + "LastTime": 128.8188, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 19, + "ClassPosition": 7, + "CarIdx": 25, + "Lap": 1, + "Time": 177.0842, + "FastestLap": 11, + "FastestTime": 128.803, + "LastTime": 128.803, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 20, + "ClassPosition": 1, + "CarIdx": 37, + "Lap": 1, + "Time": 188.1462, + "FastestLap": 6, + "FastestTime": 129.1821, + "LastTime": 134.1921, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 21, + "ClassPosition": 8, + "CarIdx": 13, + "Lap": 1, + "Time": 190.6592, + "FastestLap": 5, + "FastestTime": 127.6152, + "LastTime": 127.9048, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 22, + "ClassPosition": 9, + "CarIdx": 26, + "Lap": 1, + "Time": 193.9109, + "FastestLap": 8, + "FastestTime": 131.0692, + "LastTime": 132.685, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 23, + "ClassPosition": 2, + "CarIdx": 39, + "Lap": 1, + "Time": 196.5412, + "FastestLap": 9, + "FastestTime": 129.394, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 24, + "ClassPosition": 3, + "CarIdx": 35, + "Lap": 1, + "Time": 199.7525, + "FastestLap": 10, + "FastestTime": 130.2199, + "LastTime": 130.6221, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 25, + "ClassPosition": 4, + "CarIdx": 31, + "Lap": 1, + "Time": 200.1376, + "FastestLap": 4, + "FastestTime": 129.4173, + "LastTime": 138.302, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 26, + "ClassPosition": 5, + "CarIdx": 33, + "Lap": 1, + "Time": 200.9678, + "FastestLap": 6, + "FastestTime": 128.8251, + "LastTime": 131.5932, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 27, + "ClassPosition": 6, + "CarIdx": 29, + "Lap": 1, + "Time": 203.8258, + "FastestLap": 5, + "FastestTime": 127.6818, + "LastTime": 128.6354, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 28, + "ClassPosition": 10, + "CarIdx": 20, + "Lap": 1, + "Time": 211.0058, + "FastestLap": 5, + "FastestTime": 128.8921, + "LastTime": 128.9882, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 29, + "ClassPosition": 7, + "CarIdx": 32, + "Lap": 1, + "Time": 220.9026, + "FastestLap": 3, + "FastestTime": 129.7248, + "LastTime": 130.5236, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 30, + "ClassPosition": 11, + "CarIdx": 22, + "Lap": 1, + "Time": 225.2371, + "FastestLap": 10, + "FastestTime": 130.9325, + "LastTime": 131.3549, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 31, + "ClassPosition": 8, + "CarIdx": 28, + "Lap": 2, + "Time": 235.8864, + "FastestLap": 4, + "FastestTime": 132.9339, + "LastTime": 137.6917, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 32, + "ClassPosition": 12, + "CarIdx": 14, + "Lap": 2, + "Time": 249.5873, + "FastestLap": 5, + "FastestTime": 126.8659, + "LastTime": 129.8773, + "LapsLed": 0, + "LapsComplete": 11, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 33, + "ClassPosition": 13, + "CarIdx": 21, + "Lap": 2, + "Time": 176.7707, + "FastestLap": 4, + "FastestTime": 129.0495, + "LastTime": 129.473, + "LapsLed": 0, + "LapsComplete": 10, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 34, + "ClassPosition": 9, + "CarIdx": 30, + "Lap": 2, + "Time": 281.0014, + "FastestLap": 6, + "FastestTime": 127.6515, + "LastTime": 133.1761, + "LapsLed": 0, + "LapsComplete": 10, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 35, + "ClassPosition": 10, + "CarIdx": 36, + "Lap": 2, + "Time": 286.8481, + "FastestLap": 7, + "FastestTime": 129.4943, + "LastTime": -1, + "LapsLed": 0, + "LapsComplete": 10, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 36, + "ClassPosition": 11, + "CarIdx": 38, + "Lap": 3, + "Time": 153.5302, + "FastestLap": 2, + "FastestTime": 128.4891, + "LastTime": 130.8928, + "LapsLed": 0, + "LapsComplete": 9, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 37, + "ClassPosition": 12, + "CarIdx": 34, + "Lap": 4, + "Time": 143.7634, + "FastestLap": 2, + "FastestTime": 128.777, + "LastTime": 130.4988, + "LapsLed": 0, + "LapsComplete": 8, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + }, + { + "Position": 38, + "ClassPosition": 14, + "CarIdx": 17, + "Lap": 7, + "Time": 135.2831, + "FastestLap": 2, + "FastestTime": 131.5269, + "LastTime": 146.7832, + "LapsLed": 0, + "LapsComplete": 5, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 29, + "ReasonOutStr": "DQ" + }, + { + "Position": 39, + "ClassPosition": 15, + "CarIdx": 12, + "Lap": 9, + "Time": 131.0618, + "FastestLap": 2, + "FastestTime": 130.1302, + "LastTime": 207.7839, + "LapsLed": 0, + "LapsComplete": 3, + "JokerLapsComplete": 0, + "LapsDriven": 0, + "Incidents": 0, + "ReasonOutId": 0, + "ReasonOutStr": "Running" + } + ], + "ResultsFastestLap": [ + { + "CarIdx": 2, + "FastestLap": 8, + "FastestTime": 113.3759 + } + ], + "ResultsAverageLapTime": 115.5696, + "ResultsNumCautionFlags": 0, + "ResultsNumCautionLaps": 0, + "ResultsNumLeadChanges": 0, + "ResultsLapsComplete": 13, + "ResultsOfficial": 0 + } + ] + }, + "QualifyResultsInfo": { + "Results": [ + { + "Position": 0, + "ClassPosition": 0, + "CarIdx": 11, + "FastestLap": 2, + "FastestTime": 115.2256 + }, + { + "Position": 1, + "ClassPosition": 1, + "CarIdx": 5, + "FastestLap": 2, + "FastestTime": 115.2539 + }, + { + "Position": 2, + "ClassPosition": 2, + "CarIdx": 4, + "FastestLap": 1, + "FastestTime": 115.7144 + }, + { + "Position": 3, + "ClassPosition": 3, + "CarIdx": 8, + "FastestLap": 2, + "FastestTime": 115.7666 + }, + { + "Position": 4, + "ClassPosition": 4, + "CarIdx": 7, + "FastestLap": 1, + "FastestTime": 116.0211 + }, + { + "Position": 5, + "ClassPosition": 5, + "CarIdx": 1, + "FastestLap": 1, + "FastestTime": 117.6368 + }, + { + "Position": 6, + "ClassPosition": 6, + "CarIdx": 9, + "FastestLap": 2, + "FastestTime": 120.6603 + }, + { + "Position": 7, + "ClassPosition": 7, + "CarIdx": 2, + "FastestLap": 0, + "FastestTime": -1 + }, + { + "Position": 8, + "ClassPosition": 8, + "CarIdx": 3, + "FastestLap": 0, + "FastestTime": -1 + }, + { + "Position": 9, + "ClassPosition": 9, + "CarIdx": 10, + "FastestLap": 0, + "FastestTime": -1 + }, + { + "Position": 10, + "ClassPosition": 10, + "CarIdx": 6, + "FastestLap": 0, + "FastestTime": -1 + }, + { + "Position": 11, + "ClassPosition": 0, + "CarIdx": 18, + "FastestLap": 1, + "FastestTime": 128.2224 + }, + { + "Position": 12, + "ClassPosition": 1, + "CarIdx": 19, + "FastestLap": 1, + "FastestTime": 128.2992 + }, + { + "Position": 13, + "ClassPosition": 2, + "CarIdx": 24, + "FastestLap": 2, + "FastestTime": 128.3399 + }, + { + "Position": 14, + "ClassPosition": 3, + "CarIdx": 15, + "FastestLap": 1, + "FastestTime": 128.412 + }, + { + "Position": 15, + "ClassPosition": 4, + "CarIdx": 13, + "FastestLap": 1, + "FastestTime": 129.4624 + }, + { + "Position": 16, + "ClassPosition": 5, + "CarIdx": 27, + "FastestLap": 1, + "FastestTime": 130.6752 + }, + { + "Position": 17, + "ClassPosition": 6, + "CarIdx": 16, + "FastestLap": 2, + "FastestTime": 130.9347 + }, + { + "Position": 18, + "ClassPosition": 7, + "CarIdx": 23, + "FastestLap": 2, + "FastestTime": 131.008 + }, + { + "Position": 19, + "ClassPosition": 8, + "CarIdx": 22, + "FastestLap": 2, + "FastestTime": 134.5112 + }, + { + "Position": 20, + "ClassPosition": 9, + "CarIdx": 14, + "FastestLap": 2, + "FastestTime": 135.813 + }, + { + "Position": 21, + "ClassPosition": 10, + "CarIdx": 20, + "FastestLap": 1, + "FastestTime": 139.9101 + }, + { + "Position": 22, + "ClassPosition": 11, + "CarIdx": 12, + "FastestLap": 0, + "FastestTime": -1 + }, + { + "Position": 23, + "ClassPosition": 12, + "CarIdx": 17, + "FastestLap": 0, + "FastestTime": -1 + }, + { + "Position": 24, + "ClassPosition": 13, + "CarIdx": 21, + "FastestLap": 0, + "FastestTime": -1 + }, + { + "Position": 25, + "ClassPosition": 14, + "CarIdx": 25, + "FastestLap": 0, + "FastestTime": -1 + }, + { + "Position": 26, + "ClassPosition": 15, + "CarIdx": 26, + "FastestLap": 0, + "FastestTime": -1 + }, + { + "Position": 27, + "ClassPosition": 0, + "CarIdx": 33, + "FastestLap": 2, + "FastestTime": 128.1767 + }, + { + "Position": 28, + "ClassPosition": 1, + "CarIdx": 36, + "FastestLap": 1, + "FastestTime": 128.6368 + }, + { + "Position": 29, + "ClassPosition": 2, + "CarIdx": 34, + "FastestLap": 2, + "FastestTime": 128.7679 + }, + { + "Position": 30, + "ClassPosition": 3, + "CarIdx": 30, + "FastestLap": 2, + "FastestTime": 128.9203 + }, + { + "Position": 31, + "ClassPosition": 4, + "CarIdx": 35, + "FastestLap": 1, + "FastestTime": 129.6274 + }, + { + "Position": 32, + "ClassPosition": 5, + "CarIdx": 39, + "FastestLap": 1, + "FastestTime": 129.6396 + }, + { + "Position": 33, + "ClassPosition": 6, + "CarIdx": 37, + "FastestLap": 2, + "FastestTime": 129.7209 + }, + { + "Position": 34, + "ClassPosition": 7, + "CarIdx": 38, + "FastestLap": 1, + "FastestTime": 129.799 + }, + { + "Position": 35, + "ClassPosition": 8, + "CarIdx": 31, + "FastestLap": 2, + "FastestTime": 130.9186 + }, + { + "Position": 36, + "ClassPosition": 9, + "CarIdx": 28, + "FastestLap": 0, + "FastestTime": -1 + }, + { + "Position": 37, + "ClassPosition": 10, + "CarIdx": 29, + "FastestLap": 0, + "FastestTime": -1 + }, + { + "Position": 38, + "ClassPosition": 11, + "CarIdx": 32, + "FastestLap": 0, + "FastestTime": -1 + }, + { + "Position": 39, + "ClassPosition": 12, + "CarIdx": 40, + "FastestLap": 0, + "FastestTime": -1 + } + ] + }, + "CameraInfo": { + "Groups": [ + { + "GroupNum": 1, + "GroupName": "Nose", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamNose" + } + ] + }, + { + "GroupNum": 2, + "GroupName": "Gearbox", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamGearbox" + } + ] + }, + { + "GroupNum": 3, + "GroupName": "Roll Bar", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamRoll Bar" + } + ] + }, + { + "GroupNum": 4, + "GroupName": "LF Susp", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamLF Susp" + } + ] + }, + { + "GroupNum": 5, + "GroupName": "LR Susp", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamLR Susp" + } + ] + }, + { + "GroupNum": 6, + "GroupName": "Gyro", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamGyro" + } + ] + }, + { + "GroupNum": 7, + "GroupName": "RF Susp", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamRF Susp" + } + ] + }, + { + "GroupNum": 8, + "GroupName": "RR Susp", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamRR Susp" + } + ] + }, + { + "GroupNum": 9, + "GroupName": "Cockpit", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamCockpit" + } + ] + }, + { + "GroupNum": 10, + "GroupName": "Scenic", + "IsScenic": true, + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "Scenic_07" + }, + { + "CameraNum": 2, + "CameraName": "Scenic_08" + }, + { + "CameraNum": 3, + "CameraName": "Scenic_09" + }, + { + "CameraNum": 4, + "CameraName": "Scenic_10" + }, + { + "CameraNum": 5, + "CameraName": "Scenic_02" + }, + { + "CameraNum": 6, + "CameraName": "Scenic_03" + }, + { + "CameraNum": 7, + "CameraName": "Scenic_05" + }, + { + "CameraNum": 8, + "CameraName": "Scenic_04" + }, + { + "CameraNum": 9, + "CameraName": "Scenic_06" + }, + { + "CameraNum": 10, + "CameraName": "Scenic_01" + } + ] + }, + { + "GroupNum": 11, + "GroupName": "TV1", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamTV1_00" + }, + { + "CameraNum": 2, + "CameraName": "CamTV1_01" + }, + { + "CameraNum": 3, + "CameraName": "CamTV1_02" + }, + { + "CameraNum": 4, + "CameraName": "CamTV1_03" + }, + { + "CameraNum": 5, + "CameraName": "CamTV1_05" + }, + { + "CameraNum": 6, + "CameraName": "CamTV1_04" + }, + { + "CameraNum": 7, + "CameraName": "CamTV1_06" + }, + { + "CameraNum": 8, + "CameraName": "CamTV1_07" + }, + { + "CameraNum": 9, + "CameraName": "CamTV1_08" + }, + { + "CameraNum": 10, + "CameraName": "CamTV1_09" + } + ] + }, + { + "GroupNum": 12, + "GroupName": "TV2", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamTV2_04" + }, + { + "CameraNum": 2, + "CameraName": "CamTV2_01" + }, + { + "CameraNum": 3, + "CameraName": "CamTV2_02" + }, + { + "CameraNum": 4, + "CameraName": "CamTV2_03" + }, + { + "CameraNum": 5, + "CameraName": "CamTV2_05" + }, + { + "CameraNum": 6, + "CameraName": "CamTV2_07" + }, + { + "CameraNum": 7, + "CameraName": "CamTV2_08" + }, + { + "CameraNum": 8, + "CameraName": "CamTV2_09" + }, + { + "CameraNum": 9, + "CameraName": "CamTV2_10" + }, + { + "CameraNum": 10, + "CameraName": "CamTV2_15" + }, + { + "CameraNum": 11, + "CameraName": "CamTV2_12" + }, + { + "CameraNum": 12, + "CameraName": "CamTV2_13" + }, + { + "CameraNum": 13, + "CameraName": "CamTV2_14" + }, + { + "CameraNum": 14, + "CameraName": "CamTV2_11" + }, + { + "CameraNum": 15, + "CameraName": "CamTV2_00" + } + ] + }, + { + "GroupNum": 13, + "GroupName": "TV3", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamTV3_03" + }, + { + "CameraNum": 2, + "CameraName": "CamTV3_01" + }, + { + "CameraNum": 3, + "CameraName": "CamTV3_02" + }, + { + "CameraNum": 4, + "CameraName": "CamTV3_04" + }, + { + "CameraNum": 5, + "CameraName": "CamTV3_05" + }, + { + "CameraNum": 6, + "CameraName": "CamTV3_06" + }, + { + "CameraNum": 7, + "CameraName": "CamTV3_07" + }, + { + "CameraNum": 8, + "CameraName": "CamTV3_08" + }, + { + "CameraNum": 9, + "CameraName": "CamTV3_09" + }, + { + "CameraNum": 10, + "CameraName": "CamTV3_10" + } + ] + }, + { + "GroupNum": 14, + "GroupName": "TV Static", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamTV4_00" + }, + { + "CameraNum": 2, + "CameraName": "CamTV4_01" + }, + { + "CameraNum": 3, + "CameraName": "CamTV4_02" + }, + { + "CameraNum": 4, + "CameraName": "CamTV4_03" + }, + { + "CameraNum": 5, + "CameraName": "CamTV4_04" + }, + { + "CameraNum": 6, + "CameraName": "CamTV4_05" + }, + { + "CameraNum": 7, + "CameraName": "CamTV4_06" + }, + { + "CameraNum": 8, + "CameraName": "CamTV4_08" + }, + { + "CameraNum": 9, + "CameraName": "CamTV4_07" + }, + { + "CameraNum": 10, + "CameraName": "CamTV4_10" + }, + { + "CameraNum": 11, + "CameraName": "CamTV4_09" + }, + { + "CameraNum": 12, + "CameraName": "CamTV4_11" + }, + { + "CameraNum": 13, + "CameraName": "CamTV4_12" + }, + { + "CameraNum": 14, + "CameraName": "CamTV4_13" + }, + { + "CameraNum": 15, + "CameraName": "CamTV4_14" + }, + { + "CameraNum": 16, + "CameraName": "CamTV4_15" + }, + { + "CameraNum": 17, + "CameraName": "CamTV4_16" + }, + { + "CameraNum": 18, + "CameraName": "CamTV4_17" + } + ] + }, + { + "GroupNum": 15, + "GroupName": "TV Mixed", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamTV3_09b" + }, + { + "CameraNum": 2, + "CameraName": "CamTV1_00" + }, + { + "CameraNum": 3, + "CameraName": "CamTV1_01" + }, + { + "CameraNum": 4, + "CameraName": "CamTV1_02" + }, + { + "CameraNum": 5, + "CameraName": "CamTV1_04" + }, + { + "CameraNum": 6, + "CameraName": "CamTV1_05" + }, + { + "CameraNum": 7, + "CameraName": "CamTV1_06" + }, + { + "CameraNum": 8, + "CameraName": "CamTV1_07" + }, + { + "CameraNum": 9, + "CameraName": "CamTV1_09" + }, + { + "CameraNum": 10, + "CameraName": "CamTV2_00" + }, + { + "CameraNum": 11, + "CameraName": "CamTV2_01" + }, + { + "CameraNum": 12, + "CameraName": "CamTV2_02" + }, + { + "CameraNum": 13, + "CameraName": "CamTV2_03" + }, + { + "CameraNum": 14, + "CameraName": "CamTV2_04" + }, + { + "CameraNum": 15, + "CameraName": "CamTV2_05" + }, + { + "CameraNum": 16, + "CameraName": "CamTV2_06" + }, + { + "CameraNum": 17, + "CameraName": "CamTV2_07" + }, + { + "CameraNum": 18, + "CameraName": "CamTV2_08" + }, + { + "CameraNum": 19, + "CameraName": "CamTV2_09" + }, + { + "CameraNum": 20, + "CameraName": "CamTV2_10" + }, + { + "CameraNum": 21, + "CameraName": "CamTV2_11" + }, + { + "CameraNum": 22, + "CameraName": "CamTV2_12" + }, + { + "CameraNum": 23, + "CameraName": "CamTV2_14" + }, + { + "CameraNum": 24, + "CameraName": "CamTV2_15" + }, + { + "CameraNum": 25, + "CameraName": "CamTV3_01" + }, + { + "CameraNum": 26, + "CameraName": "CamTV3_02" + }, + { + "CameraNum": 27, + "CameraName": "CamTV3_03" + }, + { + "CameraNum": 28, + "CameraName": "CamTV3_04" + }, + { + "CameraNum": 29, + "CameraName": "CamTV3_05" + }, + { + "CameraNum": 30, + "CameraName": "CamTV3_05b" + }, + { + "CameraNum": 31, + "CameraName": "CamTV3_06" + }, + { + "CameraNum": 32, + "CameraName": "CamTV3_07" + }, + { + "CameraNum": 33, + "CameraName": "CamTV3_07b" + }, + { + "CameraNum": 34, + "CameraName": "CamTV3_08" + }, + { + "CameraNum": 35, + "CameraName": "CamTV3_09" + }, + { + "CameraNum": 36, + "CameraName": "CamTV3_10" + }, + { + "CameraNum": 37, + "CameraName": "CamTV4_00" + } + ] + }, + { + "GroupNum": 16, + "GroupName": "Pit Lane", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamPit Lane" + } + ] + }, + { + "GroupNum": 17, + "GroupName": "Pit Lane 2", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamPit Lane 2" + } + ] + }, + { + "GroupNum": 18, + "GroupName": "Blimp", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamBlimp" + } + ] + }, + { + "GroupNum": 19, + "GroupName": "Chopper", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamChopper" + } + ] + }, + { + "GroupNum": 20, + "GroupName": "Chase", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamChase" + } + ] + }, + { + "GroupNum": 21, + "GroupName": "Far Chase", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamFar Chase" + } + ] + }, + { + "GroupNum": 22, + "GroupName": "Rear Chase", + "Cameras": [ + { + "CameraNum": 1, + "CameraName": "CamRear Chase" + } + ] + } + ] + }, + "RadioInfo": { + "SelectedRadioNum": 0, + "Radios": [ + { + "RadioNum": 0, + "HopCount": 2, + "NumFrequencies": 6, + "TunedToFrequencyNum": 0, + "ScanningIsOn": 1, + "Frequencies": [ + { + "FrequencyNum": 0, + "FrequencyName": "@ALLTEAMS", + "Priority": 12, + "CarIdx": -1, + "EntryIdx": -1, + "ClubID": 0, + "CanScan": 1, + "CanSquawk": 1, + "Muted": 0, + "IsMutable": 1, + "IsDeletable": 0 + }, + { + "FrequencyNum": 1, + "FrequencyName": "@DRIVERS", + "Priority": 15, + "CarIdx": -1, + "EntryIdx": -1, + "ClubID": 0, + "CanScan": 1, + "CanSquawk": 0, + "Muted": 0, + "IsMutable": 1, + "IsDeletable": 0 + }, + { + "FrequencyNum": 2, + "FrequencyName": "@TEAM", + "Priority": 60, + "CarIdx": 4, + "EntryIdx": -1, + "ClubID": 0, + "CanScan": 1, + "CanSquawk": 1, + "Muted": 0, + "IsMutable": 0, + "IsDeletable": 0 + }, + { + "FrequencyNum": 3, + "FrequencyName": "@CLUB", + "Priority": 20, + "CarIdx": -1, + "EntryIdx": -1, + "ClubID": 34, + "CanScan": 1, + "CanSquawk": 1, + "Muted": 0, + "IsMutable": 1, + "IsDeletable": 0 + }, + { + "FrequencyNum": 4, + "FrequencyName": "@RACECONTROL", + "Priority": 80, + "CarIdx": -1, + "EntryIdx": -1, + "ClubID": 0, + "CanScan": 1, + "CanSquawk": 0, + "Muted": 0, + "IsMutable": 0, + "IsDeletable": 0 + }, + { + "FrequencyNum": 5, + "FrequencyName": "@PRIVATE", + "Priority": 70, + "CarIdx": -1, + "EntryIdx": 4, + "ClubID": 0, + "CanScan": 1, + "CanSquawk": 1, + "Muted": 0, + "IsMutable": 0, + "IsDeletable": 0 + } + ] + } + ] + }, + "DriverInfo": { + "DriverCarIdx": 4, + "DriverUserID": 968989, + "PaceCarIdx": 0, + "DriverHeadPosX": -0.276, + "DriverHeadPosY": 0.355, + "DriverHeadPosZ": 0.722, + "DriverCarIsElectric": 0, + "DriverCarIdleRPM": 960, + "DriverCarRedLine": 7500, + "DriverCarEngCylinderCount": 6, + "DriverCarFuelKgPerLtr": 0.75, + "DriverCarFuelMaxLtr": 104, + "DriverCarMaxFuelPct": 1, + "DriverCarGearNumForward": 7, + "DriverCarGearNeutral": 1, + "DriverCarGearReverse": 1, + "DriverCarSLFirstRPM": 6400, + "DriverCarSLShiftRPM": 7400, + "DriverCarSLLastRPM": 7400, + "DriverCarSLBlinkRPM": 7425, + "DriverCarVersion": "2024.10.09.01", + "DriverPitTrkPct": 0.987025, + "DriverCarEstLapTime": 113.6302, + "DriverSetupName": "sprint_open.sto", + "DriverSetupIsModified": 1, + "DriverSetupLoadTypeName": "user", + "DriverSetupPassedTech": 1, + "DriverIncidentCount": 4, + "Drivers": [ + { + "CarIdx": 0, + "UserName": "Pace Car", + "AbbrevName": null, + "Initials": null, + "UserID": -1, + "TeamID": 0, + "TeamName": "Pace Car", + "CarNumber": "0", + "CarNumberRaw": 0, + "CarPath": "safety pcporsche911cup", + "CarClassID": 11, + "CarID": 108, + "CarIsPaceCar": 1, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "safety pcporsche911cup", + "CarScreenNameShort": "safety pcporsche911cup", + "CarClassShortName": null, + "CarClassRelSpeed": 0, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 0, + "CarClassEstLapTime": 108.6151, + "IRating": 0, + "LicLevel": 1, + "LicSubLevel": 0, + "LicString": "R 0.00", + "LicColor": 16777215, + "IsSpectator": 0, + "CarDesignStr": "0,ffffff,ffffff,ffffff", + "HelmetDesignStr": "0,ffffff,ffffff,ffffff", + "SuitDesignStr": "0,ffffff,ffffff,ffffff", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,ffffff,ffffff", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "-none-", + "ClubID": 0, + "DivisionName": "Division 1", + "DivisionID": 0, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 1, + "UserName": "Oliver Linke2", + "AbbrevName": "Linke2, O", + "Initials": "OL", + "UserID": 1036770, + "TeamID": 0, + "TeamName": "Oliver Linke2", + "CarNumber": "15", + "CarNumberRaw": 15, + "CarPath": "bmwm4gt4", + "CarClassID": 2264, + "CarID": 122, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "BMW M4 GT4", + "CarScreenNameShort": "BMW M4 GT4", + "CarClassShortName": "BMW M4 GT4", + "CarClassRelSpeed": 49, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16767577, + "CarClassEstLapTime": 113.6302, + "IRating": 1448, + "LicLevel": 14, + "LicSubLevel": 235, + "LicString": "B 2.35", + "LicColor": 50946, + "IsSpectator": 0, + "CarDesignStr": "2,ff0000,00ff00,0000ff.959292", + "HelmetDesignStr": "28,111111,3e2e37,979a8b", + "SuitDesignStr": "33,111111,d5d5d5,783a3a", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "DE-AT-CH", + "ClubID": 42, + "DivisionName": "Division 4", + "DivisionID": 3, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 2, + "UserName": "Felipe Lopes", + "AbbrevName": "Lopes, F", + "Initials": "FL", + "UserID": 673917, + "TeamID": 0, + "TeamName": "Felipe Lopes", + "CarNumber": "20", + "CarNumberRaw": 20, + "CarPath": "bmwm4gt4", + "CarClassID": 2264, + "CarID": 122, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "BMW M4 GT4", + "CarScreenNameShort": "BMW M4 GT4", + "CarClassShortName": "BMW M4 GT4", + "CarClassRelSpeed": 49, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16767577, + "CarClassEstLapTime": 113.6302, + "IRating": 1429, + "LicLevel": 15, + "LicSubLevel": 316, + "LicString": "B 3.16", + "LicColor": 50946, + "IsSpectator": 0, + "CarDesignStr": "9,ff0008,00086b,ccff00;000000", + "HelmetDesignStr": "14,ff0008,00086b,ccff00", + "SuitDesignStr": "11,d3d3d3,6dd801,111111", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,f7ecec,7b7a7a,020202", + "CarSponsor_1": 0, + "CarSponsor_2": 241, + "ClubName": "New England", + "ClubID": 12, + "DivisionName": "Division 4", + "DivisionID": 3, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 3, + "UserName": "Michael Wiese", + "AbbrevName": "Wiese, M", + "Initials": "MW", + "UserID": 1060407, + "TeamID": 0, + "TeamName": "Michael Wiese", + "CarNumber": "26", + "CarNumberRaw": 26, + "CarPath": "bmwm4gt4", + "CarClassID": 2264, + "CarID": 122, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "BMW M4 GT4", + "CarScreenNameShort": "BMW M4 GT4", + "CarClassShortName": "BMW M4 GT4", + "CarClassRelSpeed": 49, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16767577, + "CarClassEstLapTime": 113.6302, + "IRating": 1411, + "LicLevel": 11, + "LicSubLevel": 332, + "LicString": "C 3.32", + "LicColor": 16706564, + "IsSpectator": 0, + "CarDesignStr": "14,e33232,ffffff,ffffff,e33232", + "HelmetDesignStr": "1,111111,5481fc,ffffff", + "SuitDesignStr": "1,111111,5481fc,ffffff", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,000000,777777,000000", + "CarSponsor_1": 132, + "CarSponsor_2": 106, + "ClubName": "Northwest", + "ClubID": 33, + "DivisionName": "Division 7", + "DivisionID": 6, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 4, + "UserName": "Tarik Alani", + "AbbrevName": "Alani, T", + "Initials": "TA", + "UserID": 968989, + "TeamID": 0, + "TeamName": "Tarik Alani", + "CarNumber": "33", + "CarNumberRaw": 33, + "CarPath": "bmwm4gt4", + "CarClassID": 2264, + "CarID": 122, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "BMW M4 GT4", + "CarScreenNameShort": "BMW M4 GT4", + "CarClassShortName": "BMW M4 GT4", + "CarClassRelSpeed": 49, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16767577, + "CarClassEstLapTime": 113.6302, + "IRating": 1367, + "LicLevel": 15, + "LicSubLevel": 375, + "LicString": "B 3.75", + "LicColor": 50946, + "IsSpectator": 0, + "CarDesignStr": "6,000000,ffffff,00107c", + "HelmetDesignStr": "7,000000,ffffff,00107c", + "SuitDesignStr": "30,000000,ffffff,00015d", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Australia/NZ", + "ClubID": 34, + "DivisionName": "Division 5", + "DivisionID": 4, + "CurDriverIncidentCount": 4, + "TeamIncidentCount": 4 + }, + { + "CarIdx": 5, + "UserName": "Harrison Zgorliski", + "AbbrevName": "Zgorliski, H", + "Initials": "HZ", + "UserID": 390344, + "TeamID": 0, + "TeamName": "Harrison Zgorliski", + "CarNumber": "34", + "CarNumberRaw": 34, + "CarPath": "bmwm4gt4", + "CarClassID": 2264, + "CarID": 122, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "BMW M4 GT4", + "CarScreenNameShort": "BMW M4 GT4", + "CarClassShortName": "BMW M4 GT4", + "CarClassRelSpeed": 49, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16767577, + "CarClassEstLapTime": 113.6302, + "IRating": 1244, + "LicLevel": 11, + "LicSubLevel": 374, + "LicString": "C 3.74", + "LicColor": 16706564, + "IsSpectator": 0, + "CarDesignStr": "14,000000,00c1ff,ffffff;000000", + "HelmetDesignStr": "35,000000,ffffff,868686", + "SuitDesignStr": "21,a9a9a9,ffffff,000000", + "BodyType": 0, + "FaceType": 4, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,5c5c5c,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Pennsylvania", + "ClubID": 16, + "DivisionName": "Division 5", + "DivisionID": 4, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 6, + "UserName": "Gustavo Guedes3", + "AbbrevName": "Guedes3, G", + "Initials": "GG", + "UserID": 1054794, + "TeamID": 0, + "TeamName": "Gustavo Guedes3", + "CarNumber": "35", + "CarNumberRaw": 35, + "CarPath": "bmwm4gt4", + "CarClassID": 2264, + "CarID": 122, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "BMW M4 GT4", + "CarScreenNameShort": "BMW M4 GT4", + "CarClassShortName": "BMW M4 GT4", + "CarClassRelSpeed": 49, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16767577, + "CarClassEstLapTime": 113.6302, + "IRating": 1225, + "LicLevel": 11, + "LicSubLevel": 318, + "LicString": "C 3.18", + "LicColor": 16706564, + "IsSpectator": 0, + "CarDesignStr": "23,8a0089,000000,52ec8f", + "HelmetDesignStr": "14,0002f0,4da300,ffde01", + "SuitDesignStr": "13,ff0000,ff0000,ffffff", + "BodyType": 0, + "FaceType": 6, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "California", + "ClubID": 6, + "DivisionName": "Division 9", + "DivisionID": 8, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 7, + "UserName": "Ted Gambill", + "AbbrevName": "Gambill, T", + "Initials": "TG", + "UserID": 15379, + "TeamID": 0, + "TeamName": "Ted Gambill", + "CarNumber": "36", + "CarNumberRaw": 36, + "CarPath": "bmwm4gt4", + "CarClassID": 2264, + "CarID": 122, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "BMW M4 GT4", + "CarScreenNameShort": "BMW M4 GT4", + "CarClassShortName": "BMW M4 GT4", + "CarClassRelSpeed": 49, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16767577, + "CarClassEstLapTime": 113.6302, + "IRating": 1195, + "LicLevel": 14, + "LicSubLevel": 261, + "LicString": "B 2.61", + "LicColor": 50946, + "IsSpectator": 0, + "CarDesignStr": "19,ffffff,07489e,61b738.0e8c43", + "HelmetDesignStr": "13,ffffff,07489e,000000", + "SuitDesignStr": "1,fafafa,47cc26,000000", + "BodyType": 1, + "FaceType": 6, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Carolina", + "ClubID": 25, + "DivisionName": "Division 5", + "DivisionID": 4, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 8, + "UserName": "Hirotaka Yamada", + "AbbrevName": "Yamada, H", + "Initials": "HY", + "UserID": 964782, + "TeamID": 0, + "TeamName": "Hirotaka Yamada", + "CarNumber": "37", + "CarNumberRaw": 37, + "CarPath": "bmwm4gt4", + "CarClassID": 2264, + "CarID": 122, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "BMW M4 GT4", + "CarScreenNameShort": "BMW M4 GT4", + "CarClassShortName": "BMW M4 GT4", + "CarClassRelSpeed": 49, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16767577, + "CarClassEstLapTime": 113.6302, + "IRating": 1192, + "LicLevel": 15, + "LicSubLevel": 327, + "LicString": "B 3.27", + "LicColor": 50946, + "IsSpectator": 0, + "CarDesignStr": "1,ff0000,00ff00,0000ff", + "HelmetDesignStr": "32,0003ff,00f7ff,000000", + "SuitDesignStr": "33,0500fa,000000,00f7ff", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Japan", + "ClubID": 48, + "DivisionName": "Division 5", + "DivisionID": 4, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 9, + "UserName": "Austin Cox3", + "AbbrevName": "Cox3, A", + "Initials": "AC", + "UserID": 1057693, + "TeamID": 0, + "TeamName": "Austin Cox3", + "CarNumber": "38", + "CarNumberRaw": 38, + "CarPath": "bmwm4gt4", + "CarClassID": 2264, + "CarID": 122, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "BMW M4 GT4", + "CarScreenNameShort": "BMW M4 GT4", + "CarClassShortName": "BMW M4 GT4", + "CarClassRelSpeed": 49, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16767577, + "CarClassEstLapTime": 113.6302, + "IRating": 1181, + "LicLevel": 6, + "LicSubLevel": 259, + "LicString": "D 2.59", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "17,000000,faff00,ff0000", + "HelmetDesignStr": "19,ffffff,ff00f5,370d38", + "SuitDesignStr": "10,ffffff,000000,ff0000", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 98, + "CarSponsor_2": 197, + "ClubName": "Ohio", + "ClubID": 20, + "DivisionName": "Division 5", + "DivisionID": 4, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 10, + "UserName": "Joshua Daynard", + "AbbrevName": "Daynard, J", + "Initials": "JD", + "UserID": 1033194, + "TeamID": 0, + "TeamName": "Joshua Daynard", + "CarNumber": "39", + "CarNumberRaw": 39, + "CarPath": "bmwm4gt4", + "CarClassID": 2264, + "CarID": 122, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "BMW M4 GT4", + "CarScreenNameShort": "BMW M4 GT4", + "CarClassShortName": "BMW M4 GT4", + "CarClassRelSpeed": 49, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16767577, + "CarClassEstLapTime": 113.6302, + "IRating": 1172, + "LicLevel": 10, + "LicSubLevel": 234, + "LicString": "C 2.34", + "LicColor": 16706564, + "IsSpectator": 0, + "CarDesignStr": "12,111111,cccccc,ed1c24", + "HelmetDesignStr": "5,111111,cccccc,ed1c24", + "SuitDesignStr": "1,111111,cccccc,ed1c24", + "BodyType": 0, + "FaceType": 10, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "California", + "ClubID": 6, + "DivisionName": "Division 8", + "DivisionID": 7, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 11, + "UserName": "Daniel Golding3", + "AbbrevName": "Golding3, D", + "Initials": "DG", + "UserID": 930125, + "TeamID": 0, + "TeamName": "Daniel Golding3", + "CarNumber": "40", + "CarNumberRaw": 40, + "CarPath": "bmwm4gt4", + "CarClassID": 2264, + "CarID": 122, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "BMW M4 GT4", + "CarScreenNameShort": "BMW M4 GT4", + "CarClassShortName": "BMW M4 GT4", + "CarClassRelSpeed": 49, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16767577, + "CarClassEstLapTime": 113.6302, + "IRating": 1159, + "LicLevel": 10, + "LicSubLevel": 222, + "LicString": "C 2.22", + "LicColor": 16706564, + "IsSpectator": 0, + "CarDesignStr": "1,ff0000,00ff00,0000ff", + "HelmetDesignStr": "34,85bede,111111,85bede", + "SuitDesignStr": "33,85bede,111111,7c7c7c", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "West", + "ClubID": 32, + "DivisionName": "Division 6", + "DivisionID": 5, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 12, + "UserName": "Fernando Back2", + "AbbrevName": "Back2, F", + "Initials": "FB", + "UserID": 1103400, + "TeamID": 0, + "TeamName": "Fernando Back2", + "CarNumber": "4", + "CarNumberRaw": 4, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1535, + "LicLevel": 6, + "LicSubLevel": 296, + "LicString": "D 2.96", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "23,0414f4,565656,ffffff.000000", + "HelmetDesignStr": "68,15d62e,efd600,0019ff", + "SuitDesignStr": "24,00f702,efd600,0500ff", + "BodyType": 0, + "FaceType": 4, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 1, + "CarSponsor_2": 49, + "ClubName": "Brazil", + "ClubID": 45, + "DivisionName": "Division 6", + "DivisionID": 5, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 13, + "UserName": "M�rio Ribeiro", + "AbbrevName": "Ribeiro, M", + "Initials": "MR", + "UserID": 348360, + "TeamID": 0, + "TeamName": "M�rio Ribeiro", + "CarNumber": "5", + "CarNumberRaw": 5, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1516, + "LicLevel": 11, + "LicSubLevel": 355, + "LicString": "C 3.55", + "LicColor": 16706564, + "IsSpectator": 0, + "CarDesignStr": "6,5e5e5e,ffffff,ffffff,000000", + "HelmetDesignStr": "17,ff0000,ffed00,53a321", + "SuitDesignStr": "5,000000,111111,ffffff", + "BodyType": 0, + "FaceType": 4, + "HelmetType": 0, + "CarNumberDesignStr": "16,2,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "UK and I", + "ClubID": 36, + "DivisionName": "Division 6", + "DivisionID": 5, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 14, + "UserName": "Curtis J Matthews", + "AbbrevName": "Matthews, C", + "Initials": "CM", + "UserID": 1095164, + "TeamID": 0, + "TeamName": "Curtis J Matthews", + "CarNumber": "8", + "CarNumberRaw": 8, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1510, + "LicLevel": 10, + "LicSubLevel": 270, + "LicString": "C 2.70", + "LicColor": 16706564, + "IsSpectator": 0, + "CarDesignStr": "4,ffffff,ff0008,8f8b8b,ffffff", + "HelmetDesignStr": "20,0030ff,ffed00,0030ff", + "SuitDesignStr": "22,0012ff,ffd706,ffd600", + "BodyType": 0, + "FaceType": 8, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Florida", + "ClubID": 22, + "DivisionName": "Division 6", + "DivisionID": 5, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 15, + "UserName": "Leonid Poplianski", + "AbbrevName": "Poplianski, L", + "Initials": "LP", + "UserID": 1141601, + "TeamID": 0, + "TeamName": "Leonid Poplianski", + "CarNumber": "10", + "CarNumberRaw": 10, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1507, + "LicLevel": 7, + "LicSubLevel": 343, + "LicString": "D 3.43", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "1,ff0000,00ff00,0000ff", + "HelmetDesignStr": "66,000000,ffffff,ffffff", + "SuitDesignStr": "1,000000,ffffff,ffffff", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Canada", + "ClubID": 15, + "DivisionName": "Division 4", + "DivisionID": 3, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 16, + "UserName": "Danoush Paborji", + "AbbrevName": "Paborji, D", + "Initials": "DP", + "UserID": 1116626, + "TeamID": 0, + "TeamName": "Danoush Paborji", + "CarNumber": "13", + "CarNumberRaw": 13, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1478, + "LicLevel": 6, + "LicSubLevel": 265, + "LicString": "D 2.65", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "1,ff0000,00ff00,0000ff", + "HelmetDesignStr": "60,ff8a00,111111,f6f6f6", + "SuitDesignStr": "4,000000,93ffae,000000", + "BodyType": 1, + "FaceType": 6, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Plains", + "ClubID": 31, + "DivisionName": "Division 4", + "DivisionID": 3, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 17, + "UserName": "Alex Thang", + "AbbrevName": "Thang, A", + "Initials": "AT", + "UserID": 1143845, + "TeamID": 0, + "TeamName": "Alex Thang", + "CarNumber": "14", + "CarNumberRaw": 14, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1464, + "LicLevel": 6, + "LicSubLevel": 249, + "LicString": "D 2.49", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "1,ff0000,00ff00,0000ff,000000", + "HelmetDesignStr": "12,0021f9,ffffff,ffffff", + "SuitDesignStr": "5,0a23ff,ffffff,ffffff", + "BodyType": 1, + "FaceType": 8, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,000000,ffffff", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "West", + "ClubID": 32, + "DivisionName": "Division 4", + "DivisionID": 3, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 18, + "UserName": "Danny Supa", + "AbbrevName": "Supa, D", + "Initials": "DS", + "UserID": 1031610, + "TeamID": 0, + "TeamName": "Danny Supa", + "CarNumber": "17", + "CarNumberRaw": 17, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1438, + "LicLevel": 11, + "LicSubLevel": 361, + "LicString": "C 3.61", + "LicColor": 16706564, + "IsSpectator": 0, + "CarDesignStr": "10,027911,ed2129,ffffff", + "HelmetDesignStr": "22,ffffff,075c00,ff0000", + "SuitDesignStr": "24,ff0000,00830d,ffffff", + "BodyType": 0, + "FaceType": 4, + "HelmetType": 0, + "CarNumberDesignStr": "37,0,087202,ff0000,ffffff", + "CarSponsor_1": 221, + "CarSponsor_2": 116, + "ClubName": "California", + "ClubID": 6, + "DivisionName": "Division 3", + "DivisionID": 2, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 19, + "UserName": "Nick Miraldi", + "AbbrevName": "Miraldi, N", + "Initials": "NM", + "UserID": 972247, + "TeamID": 0, + "TeamName": "Nick Miraldi", + "CarNumber": "18", + "CarNumberRaw": 18, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1438, + "LicLevel": 11, + "LicSubLevel": 347, + "LicString": "C 3.47", + "LicColor": 16706564, + "IsSpectator": 0, + "CarDesignStr": "2,000000,ffffff,ed2129.ff2020", + "HelmetDesignStr": "62,000000,ffffff,ff0808", + "SuitDesignStr": "30,000000,ffffff,ff1f1f", + "BodyType": 1, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,4,ffffff,000000,ffffff", + "CarSponsor_1": 130, + "CarSponsor_2": 189, + "ClubName": "West", + "ClubID": 32, + "DivisionName": "Division 6", + "DivisionID": 5, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 20, + "UserName": "Patrizio Torregiani", + "AbbrevName": "Torregiani, P", + "Initials": "PT", + "UserID": 112950, + "TeamID": 0, + "TeamName": "Patrizio Torregiani", + "CarNumber": "19", + "CarNumberRaw": 19, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1434, + "LicLevel": 18, + "LicSubLevel": 229, + "LicString": "A 2.29", + "LicColor": 87003, + "IsSpectator": 0, + "CarDesignStr": "5,a30100,ecfdf7,ecfdf7", + "HelmetDesignStr": "5,a30100,006501,ecfdf7", + "SuitDesignStr": "26,c40100,1f6827,d90d26", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "New England", + "ClubID": 12, + "DivisionName": "Division 7", + "DivisionID": 6, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 21, + "UserName": "Kaiser Knapp", + "AbbrevName": "Knapp, K", + "Initials": "KK", + "UserID": 925493, + "TeamID": 0, + "TeamName": "Kaiser Knapp", + "CarNumber": "21", + "CarNumberRaw": 21, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1426, + "LicLevel": 15, + "LicSubLevel": 337, + "LicString": "B 3.37", + "LicColor": 50946, + "IsSpectator": 0, + "CarDesignStr": "1,ff0000,00ff00,0000ff", + "HelmetDesignStr": "24,ffa32a,ffffff,7b0707", + "SuitDesignStr": "7,efb32b,f9f9f9,790a0a", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "California", + "ClubID": 6, + "DivisionName": "Division 7", + "DivisionID": 6, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 22, + "UserName": "Liam Hallen", + "AbbrevName": "Hallen, L", + "Initials": "LH", + "UserID": 1057743, + "TeamID": 0, + "TeamName": "Liam Hallen", + "CarNumber": "22", + "CarNumberRaw": 22, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1420, + "LicLevel": 6, + "LicSubLevel": 246, + "LicString": "D 2.46", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "1,ff0000,00ff00,0000ff", + "HelmetDesignStr": "11,ffffff,f390ff,000000", + "SuitDesignStr": "1,f7a3f6,ffffff,ffffff", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Ohio", + "ClubID": 20, + "DivisionName": "Rookie", + "DivisionID": 10, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 23, + "UserName": "Bob Bergman", + "AbbrevName": "Bergman, B", + "Initials": "BB", + "UserID": 1107119, + "TeamID": 0, + "TeamName": "Bob Bergman", + "CarNumber": "23", + "CarNumberRaw": 23, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1419, + "LicLevel": 15, + "LicSubLevel": 369, + "LicString": "B 3.69", + "LicColor": 50946, + "IsSpectator": 0, + "CarDesignStr": "2,fcfdff,ff0008,ffffff", + "HelmetDesignStr": "64,111111,ffffff,fc5353", + "SuitDesignStr": "1,111111,ffffff,5481fc", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 49, + "CarSponsor_2": 223, + "ClubName": "Canada", + "ClubID": 15, + "DivisionName": "Rookie", + "DivisionID": 10, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 24, + "UserName": "Hugo Belisles", + "AbbrevName": "Belisles, H", + "Initials": "HB", + "UserID": 1110164, + "TeamID": 0, + "TeamName": "Hugo Belisles", + "CarNumber": "24", + "CarNumberRaw": 24, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1419, + "LicLevel": 7, + "LicSubLevel": 364, + "LicString": "D 3.64", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "11,ed2129,ffffff,2a3795", + "HelmetDesignStr": "28,ed2229,eeeeee,2a3795", + "SuitDesignStr": "1,eeeeee,2a3795,ed2229", + "BodyType": 0, + "FaceType": 4, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Canada", + "ClubID": 15, + "DivisionName": "Rookie", + "DivisionID": 10, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 25, + "UserName": "Eduardo Gonzalez12", + "AbbrevName": "Gonzalez12, E", + "Initials": "EG", + "UserID": 1099066, + "TeamID": 0, + "TeamName": "Eduardo Gonzalez12", + "CarNumber": "25", + "CarNumberRaw": 25, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1418, + "LicLevel": 15, + "LicSubLevel": 347, + "LicString": "B 3.47", + "LicColor": 50946, + "IsSpectator": 0, + "CarDesignStr": "1,ff0000,00ff00,0000ff", + "HelmetDesignStr": "35,000000,447ac0,ee3442", + "SuitDesignStr": "35,000000,447ac0,ee3442", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Florida", + "ClubID": 22, + "DivisionName": "Division 9", + "DivisionID": 8, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 26, + "UserName": "Devon Strauch", + "AbbrevName": "Strauch, D", + "Initials": "DS", + "UserID": 1042916, + "TeamID": 0, + "TeamName": "Devon Strauch", + "CarNumber": "31", + "CarNumberRaw": 31, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1386, + "LicLevel": 19, + "LicSubLevel": 316, + "LicString": "A 3.16", + "LicColor": 87003, + "IsSpectator": 0, + "CarDesignStr": "3,ffffff,ed2129,deca12", + "HelmetDesignStr": "27,c922f2,0a0a0a,9b9b9b", + "SuitDesignStr": "1,0a0a0a,e5e5e5,9e00ff", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 221, + "CarSponsor_2": 7, + "ClubName": "New York", + "ClubID": 14, + "DivisionName": "Division 6", + "DivisionID": 5, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 27, + "UserName": "Joe Wallace3", + "AbbrevName": "Wallace3, J", + "Initials": "JW", + "UserID": 1134461, + "TeamID": 0, + "TeamName": "Joe Wallace3", + "CarNumber": "32", + "CarNumberRaw": 32, + "CarPath": "toyotagr86", + "CarClassID": 4012, + "CarID": 160, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Toyota GR86", + "CarScreenNameShort": "Toyota GR86", + "CarClassShortName": "Toyota GR86", + "CarClassRelSpeed": 36, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 16734344, + "CarClassEstLapTime": 126.9374, + "IRating": 1384, + "LicLevel": 6, + "LicSubLevel": 254, + "LicString": "D 2.54", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "15,f7f7f7,253792,dba764.a86e44", + "HelmetDesignStr": "45,000000,8a8142,d8a746", + "SuitDesignStr": "7,252523,ca955d,a8955c", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "43,1,ff0000,777777,000000", + "CarSponsor_1": 132, + "CarSponsor_2": 56, + "ClubName": "Australia/NZ", + "ClubID": 34, + "DivisionName": "Division 4", + "DivisionID": 3, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 28, + "UserName": "James Um", + "AbbrevName": "Um, J", + "Initials": "JU", + "UserID": 1002193, + "TeamID": 0, + "TeamName": "James Um", + "CarNumber": "1", + "CarNumberRaw": 1, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1547, + "LicLevel": 17, + "LicSubLevel": 169, + "LicString": "A 1.69", + "LicColor": 87003, + "IsSpectator": 0, + "CarDesignStr": "7,000000,c7c7c7,2dcd8f,565656", + "HelmetDesignStr": "36,ff0000,000000,ffffff", + "SuitDesignStr": "13,ffffff,0a0a0a,00aeef", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 217, + "CarSponsor_2": 72, + "ClubName": "Northwest", + "ClubID": 33, + "DivisionName": "Division 3", + "DivisionID": 2, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 29, + "UserName": "Chris Ferris", + "AbbrevName": "Ferris, C", + "Initials": "CF", + "UserID": 804684, + "TeamID": 0, + "TeamName": "Chris Ferris", + "CarNumber": "2", + "CarNumberRaw": 2, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1544, + "LicLevel": 18, + "LicSubLevel": 258, + "LicString": "A 2.58", + "LicColor": 87003, + "IsSpectator": 0, + "CarDesignStr": "9,eeeeee,000000,3cff00,000000", + "HelmetDesignStr": "36,000000,ff0000,ffffff", + "SuitDesignStr": "7,000000,ffffff,000000", + "BodyType": 1, + "FaceType": 8, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,70b4fd,eeeeee,0f00b4", + "CarSponsor_1": 0, + "CarSponsor_2": 97, + "ClubName": "Australia/NZ", + "ClubID": 34, + "DivisionName": "Division 3", + "DivisionID": 2, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 30, + "UserName": "Chris Harrison7", + "AbbrevName": "Harrison7, C", + "Initials": "CH", + "UserID": 1079682, + "TeamID": 0, + "TeamName": "Chris Harrison7", + "CarNumber": "3", + "CarNumberRaw": 3, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1536, + "LicLevel": 6, + "LicSubLevel": 268, + "LicString": "D 2.68", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "18,c1c9ff,ffd9ee,111111,c1c9ff", + "HelmetDesignStr": "1,ffffff,111111,0ada00", + "SuitDesignStr": "13,dcffaf,dd5e5e,46e0a8", + "BodyType": 0, + "FaceType": 10, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,c1c9ff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "California", + "ClubID": 6, + "DivisionName": "Division 4", + "DivisionID": 3, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 31, + "UserName": "Alain Kusters2", + "AbbrevName": "Kusters2, A", + "Initials": "AK", + "UserID": 1145208, + "TeamID": 0, + "TeamName": "Alain Kusters2", + "CarNumber": "6", + "CarNumberRaw": 6, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1516, + "LicLevel": 7, + "LicSubLevel": 393, + "LicString": "D 3.93", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "1,ed1c24,cccccc,111111", + "HelmetDesignStr": "1,ed1c24,cccccc,111111", + "SuitDesignStr": "1,ed1c24,cccccc,111111", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Canada", + "ClubID": 15, + "DivisionName": "Division 4", + "DivisionID": 3, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 32, + "UserName": "Nahuel Gallego", + "AbbrevName": "Gallego, N", + "Initials": "NG", + "UserID": 1108558, + "TeamID": 0, + "TeamName": "Nahuel Gallego", + "CarNumber": "7", + "CarNumberRaw": 7, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1512, + "LicLevel": 7, + "LicSubLevel": 362, + "LicString": "D 3.62", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "15,ffffff,ffffff,ffffff", + "HelmetDesignStr": "0,ffffff,ffffff,ffffff", + "SuitDesignStr": "0,ffffff,ffffff,ffffff", + "BodyType": 1, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,fa0a6f,000000,fdfdfd", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Hispanoam�rica", + "ClubID": 24, + "DivisionName": "Division 5", + "DivisionID": 4, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 33, + "UserName": "Julien Boutiot2", + "AbbrevName": "Boutiot2, J", + "Initials": "JB", + "UserID": 1143037, + "TeamID": 0, + "TeamName": "Julien Boutiot2", + "CarNumber": "9", + "CarNumberRaw": 9, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1508, + "LicLevel": 11, + "LicSubLevel": 371, + "LicString": "C 3.71", + "LicColor": 16706564, + "IsSpectator": 0, + "CarDesignStr": "7,1f2892,ffffff,7de54c", + "HelmetDesignStr": "1,1f2892,ffffff,7de54c", + "SuitDesignStr": "1,1f2892,ffffff,7de54c", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "France", + "ClubID": 39, + "DivisionName": "Division 5", + "DivisionID": 4, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 34, + "UserName": "Nathan Henrickson", + "AbbrevName": "Henrickson, N", + "Initials": "NH", + "UserID": 926308, + "TeamID": 0, + "TeamName": "Nathan Henrickson", + "CarNumber": "11", + "CarNumberRaw": 11, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1501, + "LicLevel": 6, + "LicSubLevel": 242, + "LicString": "D 2.42", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "12,fffefe,ff0000,000000", + "HelmetDesignStr": "2,cccccc,121212,1c2bed", + "SuitDesignStr": "1,cccccc,111111,ed1c24", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Illinois", + "ClubID": 26, + "DivisionName": "Division 5", + "DivisionID": 4, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 35, + "UserName": "John Bacho", + "AbbrevName": "Bacho, J", + "Initials": "JB", + "UserID": 29130, + "TeamID": 0, + "TeamName": "John Bacho", + "CarNumber": "12", + "CarNumberRaw": 12, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1497, + "LicLevel": 19, + "LicSubLevel": 310, + "LicString": "A 3.10", + "LicColor": 87003, + "IsSpectator": 0, + "CarDesignStr": "4,ae1d22,ae1d22,ffff00", + "HelmetDesignStr": "45,feec04,ffffff,e20100", + "SuitDesignStr": "3,feec04,ffffff,e20100", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,000000,777777", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Northwest", + "ClubID": 33, + "DivisionName": "Division 4", + "DivisionID": 3, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 36, + "UserName": "Altay Kececi", + "AbbrevName": "Kececi, A", + "Initials": "AK", + "UserID": 728884, + "TeamID": 0, + "TeamName": "Altay Kececi", + "CarNumber": "16", + "CarNumberRaw": 16, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1446, + "LicLevel": 14, + "LicSubLevel": 221, + "LicString": "B 2.21", + "LicColor": 50946, + "IsSpectator": 0, + "CarDesignStr": "8,111111,ffffff,e64c4c", + "HelmetDesignStr": "14,ae9200,ffffff,7b0000", + "SuitDesignStr": "5,000000,000000,000000", + "BodyType": 0, + "FaceType": 8, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,625757,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "International", + "ClubID": 1, + "DivisionName": "Division 5", + "DivisionID": 4, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 37, + "UserName": "Joe Stetson", + "AbbrevName": "Stetson, J", + "Initials": "JS", + "UserID": 230658, + "TeamID": 0, + "TeamName": "Joe Stetson", + "CarNumber": "27", + "CarNumberRaw": 27, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1408, + "LicLevel": 10, + "LicSubLevel": 272, + "LicString": "C 2.72", + "LicColor": 16706564, + "IsSpectator": 0, + "CarDesignStr": "3,1f2892,7de54c,ffffff", + "HelmetDesignStr": "1,1f2892,7de54c,ffffff", + "SuitDesignStr": "4,1f2892,7de54c,ffffff", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 50, + "CarSponsor_2": 2, + "ClubName": "Florida", + "ClubID": 22, + "DivisionName": "Division 4", + "DivisionID": 3, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 38, + "UserName": "Grant Wood2", + "AbbrevName": "Wood2, G", + "Initials": "GW", + "UserID": 1061826, + "TeamID": 0, + "TeamName": "Grant Wood2", + "CarNumber": "28", + "CarNumberRaw": 28, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1406, + "LicLevel": 11, + "LicSubLevel": 360, + "LicString": "C 3.60", + "LicColor": 16706564, + "IsSpectator": 0, + "CarDesignStr": "23,b9afa0,020065,006004;000000", + "HelmetDesignStr": "8,00ffff,3f4597,7e1a1a", + "SuitDesignStr": "21,000000,707070,7e1a1a", + "BodyType": 0, + "FaceType": 4, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 45, + "CarSponsor_2": 209, + "ClubName": "Georgia", + "ClubID": 21, + "DivisionName": "Division 7", + "DivisionID": 6, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 39, + "UserName": "Christopher Lee24", + "AbbrevName": "Lee24, C", + "Initials": "CL", + "UserID": 1136412, + "TeamID": 0, + "TeamName": "Christopher Lee24", + "CarNumber": "29", + "CarNumberRaw": 29, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1397, + "LicLevel": 7, + "LicSubLevel": 377, + "LicString": "D 3.77", + "LicColor": 16550439, + "IsSpectator": 0, + "CarDesignStr": "16,ffffff,911d1d,000000", + "HelmetDesignStr": "48,000000,ffffff,000000", + "SuitDesignStr": "13,fdfdfd,000000,000000", + "BodyType": 0, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,f9f9f9,06ff10,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Virginias", + "ClubID": 17, + "DivisionName": "Division 7", + "DivisionID": 6, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + }, + { + "CarIdx": 40, + "UserName": "Tiago Arce", + "AbbrevName": "Arce, T", + "Initials": "TA", + "UserID": 55760, + "TeamID": 0, + "TeamName": "Tiago Arce", + "CarNumber": "30", + "CarNumberRaw": 30, + "CarPath": "mx5 mx52016", + "CarClassID": 74, + "CarID": 67, + "CarIsPaceCar": 0, + "CarIsAI": 0, + "CarIsElectric": 0, + "CarScreenName": "Mazda MX-5 Cup", + "CarScreenNameShort": "MX-5 Cup", + "CarClassShortName": "MX5 Cup 2016", + "CarClassRelSpeed": 35, + "CarClassLicenseLevel": 0, + "CarClassMaxFuelPct": "1.000 %", + "CarClassWeightPenalty": "0.000 kg", + "CarClassPowerAdjust": "0.000 %", + "CarClassDryTireSetLimit": "0 %", + "CarClassColor": 11430911, + "CarClassEstLapTime": 126.2284, + "IRating": 1387, + "LicLevel": 17, + "LicSubLevel": 122, + "LicString": "A 1.22", + "LicColor": 87003, + "IsSpectator": 0, + "CarDesignStr": "0,e0b157,e0b157,e0b157", + "HelmetDesignStr": "45,040047,00ccf5,ffffff", + "SuitDesignStr": "6,000000,f50000,ffd600", + "BodyType": 1, + "FaceType": 0, + "HelmetType": 0, + "CarNumberDesignStr": "0,0,ffffff,777777,000000", + "CarSponsor_1": 0, + "CarSponsor_2": 0, + "ClubName": "Brazil", + "ClubID": 45, + "DivisionName": "Division 4", + "DivisionID": 3, + "CurDriverIncidentCount": -1, + "TeamIncidentCount": -1 + } + ] + }, + "SplitTimeInfo": { + "Sectors": [ + { + "SectorNum": 0, + "SectorStartPct": 0 + }, + { + "SectorNum": 1, + "SectorStartPct": 0.184456 + }, + { + "SectorNum": 2, + "SectorStartPct": 0.337214 + }, + { + "SectorNum": 3, + "SectorStartPct": 0.504637 + }, + { + "SectorNum": 4, + "SectorStartPct": 0.734279 + }, + { + "SectorNum": 5, + "SectorStartPct": 0.829332 + } + ] + }, + "CarSetup": { + "UpdateCount": 5, + "Tires": { + "TireType": { + "TireType": "Dry" + }, + "LeftFront": { + "StartingPressure": "159 kPa", + "LastHotPressure": "159 kPa", + "LastTempsOMI": "47C, 47C, 47C", + "TreadRemaining": "100%, 100%, 100%" + }, + "LeftRear": { + "StartingPressure": "165 kPa", + "LastHotPressure": "165 kPa", + "LastTempsOMI": "47C, 47C, 47C", + "TreadRemaining": "100%, 100%, 100%" + }, + "RightFront": { + "StartingPressure": "159 kPa", + "LastHotPressure": "159 kPa", + "LastTempsIMO": "47C, 47C, 47C", + "TreadRemaining": "100%, 100%, 100%" + }, + "RightRear": { + "StartingPressure": "165 kPa", + "LastHotPressure": "165 kPa", + "LastTempsIMO": "47C, 47C, 47C", + "TreadRemaining": "100%, 100%, 100%" + } + }, + "Chassis": { + "Front": { + "ArbSetting": 1, + "ToeIn": "-2.8 mm", + "CrossWeight": "50.0%" + }, + "LeftFront": { + "CornerWeight": "3835 N", + "RideHeight": "124.4 mm", + "SpringRate": "180 N/mm", + "SpringPerchOffset": "90.0 mm", + "BumpStiffness": "+10 clicks", + "ReboundStiffness": "+10 clicks", + "Camber": "-3.5 deg" + }, + "LeftRear": { + "CornerWeight": "3742 N", + "RideHeight": "137.9 mm", + "SpringRate": "150 N/mm", + "SpringPerchOffset": "98.0 mm", + "BumpStiffness": "+10 clicks", + "ReboundStiffness": "+10 clicks", + "Camber": "-2.5 deg", + "ToeIn": "+0.1 mm" + }, + "InCarDials": { + "BrakePressureBias": "57.8%", + "BrakePads": "Medium friction", + "DscSetting": "MDM", + "FdsSetting": 1 + }, + "RightFront": { + "CornerWeight": "3835 N", + "RideHeight": "124.4 mm", + "SpringRate": "180 N/mm", + "SpringPerchOffset": "90.0 mm", + "BumpStiffness": "+10 clicks", + "ReboundStiffness": "+10 clicks", + "Camber": "-3.5 deg" + }, + "RightRear": { + "CornerWeight": "3742 N", + "RideHeight": "137.9 mm", + "SpringRate": "150 N/mm", + "SpringPerchOffset": "98.0 mm", + "BumpStiffness": "+10 clicks", + "ReboundStiffness": "+10 clicks", + "Camber": "-2.5 deg", + "ToeIn": "+0.1 mm" + }, + "Rear": { + "FuelLevel": "50.0 L", + "ArbSetting": 2, + "WingSetting": 3 + } + } + } +} \ No newline at end of file diff --git a/src/app/irsdk/node/utils/mock-data/telemetry.json b/src/app/irsdk/node/utils/mock-data/telemetry.json new file mode 100644 index 0000000..04e4f53 --- /dev/null +++ b/src/app/irsdk/node/utils/mock-data/telemetry.json @@ -0,0 +1,5368 @@ +{ + "SessionTime": { + "countAsTime": false, + "length": 1, + "name": "SessionTime", + "description": "Seconds since session start", + "unit": "s", + "varType": 5, + "value": [ + 1909.900000004552 + ] + }, + "SessionTick": { + "countAsTime": false, + "length": 1, + "name": "SessionTick", + "description": "Current update number", + "unit": "", + "varType": 2, + "value": [ + 210919 + ] + }, + "SessionNum": { + "countAsTime": false, + "length": 1, + "name": "SessionNum", + "description": "Session number", + "unit": "", + "varType": 2, + "value": [ + 2 + ] + }, + "SessionState": { + "countAsTime": false, + "length": 1, + "name": "SessionState", + "description": "Session state", + "unit": "irsdk_SessionState", + "varType": 2, + "value": [ + 5 + ] + }, + "SessionUniqueID": { + "countAsTime": false, + "length": 1, + "name": "SessionUniqueID", + "description": "Session ID", + "unit": "", + "varType": 2, + "value": [ + 3 + ] + }, + "SessionFlags": { + "countAsTime": false, + "length": 1, + "name": "SessionFlags", + "description": "Session flags", + "unit": "irsdk_Flags", + "varType": 3, + "value": [ + 268697601 + ] + }, + "SessionTimeRemain": { + "countAsTime": false, + "length": 1, + "name": "SessionTimeRemain", + "description": "Seconds left till session ends", + "unit": "s", + "varType": 5, + "value": [ + 113.30286666211464 + ] + }, + "SessionLapsRemain": { + "countAsTime": false, + "length": 1, + "name": "SessionLapsRemain", + "description": "Old laps left till session ends use SessionLapsRemainEx", + "unit": "", + "varType": 2, + "value": [ + 32767 + ] + }, + "SessionLapsRemainEx": { + "countAsTime": false, + "length": 1, + "name": "SessionLapsRemainEx", + "description": "New improved laps left till session ends", + "unit": "", + "varType": 2, + "value": [ + 32767 + ] + }, + "SessionTimeTotal": { + "countAsTime": false, + "length": 1, + "name": "SessionTimeTotal", + "description": "Total number of seconds in session", + "unit": "s", + "varType": 5, + "value": [ + 1500 + ] + }, + "SessionLapsTotal": { + "countAsTime": false, + "length": 1, + "name": "SessionLapsTotal", + "description": "Total number of laps in session", + "unit": "", + "varType": 2, + "value": [ + 32767 + ] + }, + "SessionJokerLapsRemain": { + "countAsTime": false, + "length": 1, + "name": "SessionJokerLapsRemain", + "description": "Joker laps remaining to be taken", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "SessionOnJokerLap": { + "countAsTime": false, + "length": 1, + "name": "SessionOnJokerLap", + "description": "Player is currently completing a joker lap", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "SessionTimeOfDay": { + "countAsTime": false, + "length": 1, + "name": "SessionTimeOfDay", + "description": "Time of day in seconds", + "unit": "s", + "varType": 4, + "value": [ + 58909 + ] + }, + "RadioTransmitCarIdx": { + "countAsTime": false, + "length": 1, + "name": "RadioTransmitCarIdx", + "description": "The car index of the current person speaking on the radio", + "unit": "", + "varType": 2, + "value": [ + 19 + ] + }, + "RadioTransmitRadioIdx": { + "countAsTime": false, + "length": 1, + "name": "RadioTransmitRadioIdx", + "description": "The radio index of the current person speaking on the radio", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "RadioTransmitFrequencyIdx": { + "countAsTime": false, + "length": 1, + "name": "RadioTransmitFrequencyIdx", + "description": "The frequency index of the current person speaking on the radio", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "DisplayUnits": { + "countAsTime": false, + "length": 1, + "name": "DisplayUnits", + "description": "Default units for the user interface 0 = english 1 = metric", + "unit": "", + "varType": 2, + "value": [ + 1 + ] + }, + "DriverMarker": { + "countAsTime": false, + "length": 1, + "name": "DriverMarker", + "description": "Driver activated flag", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "PushToTalk": { + "countAsTime": false, + "length": 1, + "name": "PushToTalk", + "description": "Push to talk button state", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "PushToPass": { + "countAsTime": false, + "length": 1, + "name": "PushToPass", + "description": "Push to pass button state", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "ManualBoost": { + "countAsTime": false, + "length": 1, + "name": "ManualBoost", + "description": "Hybrid manual boost state", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "ManualNoBoost": { + "countAsTime": false, + "length": 1, + "name": "ManualNoBoost", + "description": "Hybrid manual no boost state", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "IsOnTrack": { + "countAsTime": false, + "length": 1, + "name": "IsOnTrack", + "description": "1=Car on track physics running with player in car", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "IsReplayPlaying": { + "countAsTime": false, + "length": 1, + "name": "IsReplayPlaying", + "description": "0=replay not playing 1=replay playing", + "unit": "", + "varType": 1, + "value": [ + true + ] + }, + "ReplayFrameNum": { + "countAsTime": false, + "length": 1, + "name": "ReplayFrameNum", + "description": "Integer replay frame number (60 per second)", + "unit": "", + "varType": 2, + "value": [ + 148864 + ] + }, + "ReplayFrameNumEnd": { + "countAsTime": false, + "length": 1, + "name": "ReplayFrameNumEnd", + "description": "Integer replay frame number from end of tape", + "unit": "", + "varType": 2, + "value": [ + 1201 + ] + }, + "IsDiskLoggingEnabled": { + "countAsTime": false, + "length": 1, + "name": "IsDiskLoggingEnabled", + "description": "0=disk based telemetry turned off 1=turned on", + "unit": "", + "varType": 1, + "value": [ + true + ] + }, + "IsDiskLoggingActive": { + "countAsTime": false, + "length": 1, + "name": "IsDiskLoggingActive", + "description": "0=disk based telemetry file not being written 1=being written", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "FrameRate": { + "countAsTime": false, + "length": 1, + "name": "FrameRate", + "description": "Average frames per second", + "unit": "fps", + "varType": 4, + "value": [ + 45.73246383666992 + ] + }, + "CpuUsageFG": { + "countAsTime": false, + "length": 1, + "name": "CpuUsageFG", + "description": "Percent of available tim fg thread took with a 1 sec avg", + "unit": "%", + "varType": 4, + "value": [ + 0.4905990660190582 + ] + }, + "GpuUsage": { + "countAsTime": false, + "length": 1, + "name": "GpuUsage", + "description": "Percent of available tim gpu took with a 1 sec avg", + "unit": "%", + "varType": 4, + "value": [ + 1.1253997087478638 + ] + }, + "ChanAvgLatency": { + "countAsTime": false, + "length": 1, + "name": "ChanAvgLatency", + "description": "Communications average latency", + "unit": "s", + "varType": 4, + "value": [ + 0.20068992674350739 + ] + }, + "ChanLatency": { + "countAsTime": false, + "length": 1, + "name": "ChanLatency", + "description": "Communications latency", + "unit": "s", + "varType": 4, + "value": [ + 0.20000000298023224 + ] + }, + "ChanQuality": { + "countAsTime": false, + "length": 1, + "name": "ChanQuality", + "description": "Communications quality", + "unit": "%", + "varType": 4, + "value": [ + 0.99757319688797 + ] + }, + "ChanPartnerQuality": { + "countAsTime": false, + "length": 1, + "name": "ChanPartnerQuality", + "description": "Partner communications quality", + "unit": "%", + "varType": 4, + "value": [ + 1 + ] + }, + "CpuUsageBG": { + "countAsTime": false, + "length": 1, + "name": "CpuUsageBG", + "description": "Percent of available tim bg thread took with a 1 sec avg", + "unit": "%", + "varType": 4, + "value": [ + 0.37499961256980896 + ] + }, + "ChanClockSkew": { + "countAsTime": false, + "length": 1, + "name": "ChanClockSkew", + "description": "Communications server clock skew", + "unit": "s", + "varType": 4, + "value": [ + 0 + ] + }, + "MemPageFaultSec": { + "countAsTime": false, + "length": 1, + "name": "MemPageFaultSec", + "description": "Memory page faults per second", + "unit": "", + "varType": 4, + "value": [ + 1 + ] + }, + "MemSoftPageFaultSec": { + "countAsTime": false, + "length": 1, + "name": "MemSoftPageFaultSec", + "description": "Memory soft page faults per second", + "unit": "", + "varType": 4, + "value": [ + 38186 + ] + }, + "PlayerCarPosition": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarPosition", + "description": "Players position in race", + "unit": "", + "varType": 2, + "value": [ + 4 + ] + }, + "PlayerCarClassPosition": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarClassPosition", + "description": "Players class position in race", + "unit": "", + "varType": 2, + "value": [ + 4 + ] + }, + "PlayerCarClass": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarClass", + "description": "Player car class id", + "unit": "", + "varType": 2, + "value": [ + 2264 + ] + }, + "PlayerTrackSurface": { + "countAsTime": false, + "length": 1, + "name": "PlayerTrackSurface", + "description": "Players car track surface type", + "unit": "irsdk_TrkLoc", + "varType": 2, + "value": [ + -1 + ] + }, + "PlayerTrackSurfaceMaterial": { + "countAsTime": false, + "length": 1, + "name": "PlayerTrackSurfaceMaterial", + "description": "Players car track surface material type", + "unit": "irsdk_TrkSurf", + "varType": 2, + "value": [ + -1 + ] + }, + "PlayerCarIdx": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarIdx", + "description": "Players carIdx", + "unit": "", + "varType": 2, + "value": [ + 4 + ] + }, + "PlayerCarTeamIncidentCount": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarTeamIncidentCount", + "description": "Players team incident count for this session", + "unit": "", + "varType": 2, + "value": [ + 4 + ] + }, + "PlayerCarMyIncidentCount": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarMyIncidentCount", + "description": "Players own incident count for this session", + "unit": "", + "varType": 2, + "value": [ + 4 + ] + }, + "PlayerCarDriverIncidentCount": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarDriverIncidentCount", + "description": "Teams current drivers incident count for this session", + "unit": "", + "varType": 2, + "value": [ + 4 + ] + }, + "PlayerCarWeightPenalty": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarWeightPenalty", + "description": "Players weight penalty", + "unit": "kg", + "varType": 4, + "value": [ + 0 + ] + }, + "PlayerCarPowerAdjust": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarPowerAdjust", + "description": "Players power adjust", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "PlayerCarDryTireSetLimit": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarDryTireSetLimit", + "description": "Players dry tire set limit", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "PlayerCarTowTime": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarTowTime", + "description": "Players car is being towed if time is greater than zero", + "unit": "s", + "varType": 4, + "value": [ + 0 + ] + }, + "PlayerCarInPitStall": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarInPitStall", + "description": "Players car is properly in their pitstall", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "PlayerCarPitSvStatus": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarPitSvStatus", + "description": "Players car pit service status bits", + "unit": "irsdk_PitSvStatus", + "varType": 2, + "value": [ + 0 + ] + }, + "PlayerTireCompound": { + "countAsTime": false, + "length": 1, + "name": "PlayerTireCompound", + "description": "Players car current tire compound", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "PlayerFastRepairsUsed": { + "countAsTime": false, + "length": 1, + "name": "PlayerFastRepairsUsed", + "description": "Players car number of fast repairs used", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "CarIdxLap": { + "countAsTime": false, + "length": 64, + "name": "CarIdxLap", + "description": "Laps started by car index", + "unit": "", + "varType": 2, + "value": [ + -1, + -1, + 13, + -1, + -1, + -1, + -1, + -1, + -1, + 13, + 14, + -1, + -1, + 12, + -1, + 12, + 12, + -1, + 13, + 13, + 12, + -1, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 11, + 12, + 12, + 12, + -1, + 12, + 11, + 12, + -1, + 12, + 12, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxLapCompleted": { + "countAsTime": false, + "length": 64, + "name": "CarIdxLapCompleted", + "description": "Laps completed by car index", + "unit": "", + "varType": 2, + "value": [ + -2, + -1, + 12, + -1, + -1, + -1, + -1, + -1, + -1, + 12, + 13, + -1, + -1, + 11, + -1, + 11, + 11, + -1, + 12, + 12, + 11, + -1, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 10, + 11, + 11, + 11, + -1, + 11, + 10, + 11, + -1, + 11, + 11, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxLapDistPct": { + "countAsTime": false, + "length": 64, + "name": "CarIdxLapDistPct", + "description": "Percentage distance around lap by car index", + "unit": "%", + "varType": 4, + "value": [ + 0.9942072629928589, + -1, + 0.841148853302002, + -1, + -1, + -1, + -1, + -1, + -1, + 0.936923086643219, + 0.06046311929821968, + -1, + -1, + 0.7775947451591492, + -1, + 0.9761711955070496, + 0.9293166399002075, + -1, + 0.02848833240568638, + 0.05448886379599571, + 0.5834031105041504, + -1, + 0.48615148663520813, + 0.8612086772918701, + 0.9262315034866333, + 0.8546850681304932, + 0.7217929363250732, + 0.8576954007148743, + 0.37332478165626526, + 0.6421698927879333, + 0.9219207167625427, + 0.6734675765037537, + 0.525010883808136, + 0.6666178107261658, + -1, + 0.675060510635376, + 0.8526926636695862, + 0.7811623811721802, + -1, + 0.7012394070625305, + 0.8447133302688599, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxTrackSurface": { + "countAsTime": false, + "length": 64, + "name": "CarIdxTrackSurface", + "description": "Track surface type by car index", + "unit": "irsdk_TrkLoc", + "varType": 2, + "value": [ + 2, + -1, + 3, + -1, + -1, + -1, + -1, + -1, + -1, + 3, + 3, + -1, + -1, + 3, + -1, + 3, + 3, + -1, + 3, + 3, + 3, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + -1, + 3, + 3, + 3, + -1, + 3, + 3, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxTrackSurfaceMaterial": { + "countAsTime": false, + "length": 64, + "name": "CarIdxTrackSurfaceMaterial", + "description": "Track surface material type by car index", + "unit": "irsdk_TrkSurf", + "varType": 2, + "value": [ + 1, + -1, + 1, + -1, + -1, + -1, + -1, + -1, + -1, + 1, + 1, + -1, + -1, + 1, + -1, + 1, + 1, + -1, + 1, + 1, + 1, + -1, + 1, + 13, + 1, + 1, + 1, + 13, + 1, + 1, + 1, + 1, + 1, + 1, + -1, + 1, + 1, + 1, + -1, + 1, + 1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxOnPitRoad": { + "countAsTime": false, + "length": 64, + "name": "CarIdxOnPitRoad", + "description": "On pit road between the cones by car index", + "unit": "", + "varType": 1, + "value": [ + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + }, + "CarIdxPosition": { + "countAsTime": false, + "length": 64, + "name": "CarIdxPosition", + "description": "Cars position in race by car index", + "unit": "", + "varType": 2, + "value": [ + 0, + 10, + 9, + 2, + 4, + 1, + 0, + 5, + 6, + 8, + 7, + 3, + 39, + 21, + 32, + 13, + 14, + 38, + 12, + 11, + 28, + 33, + 30, + 16, + 15, + 19, + 22, + 17, + 31, + 27, + 34, + 25, + 29, + 26, + 37, + 24, + 35, + 20, + 36, + 23, + 18, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "CarIdxClassPosition": { + "countAsTime": false, + "length": 64, + "name": "CarIdxClassPosition", + "description": "Cars class position in race by car index", + "unit": "", + "varType": 2, + "value": [ + 0, + 10, + 9, + 2, + 4, + 1, + 0, + 5, + 6, + 8, + 7, + 3, + 16, + 9, + 13, + 3, + 4, + 15, + 2, + 1, + 11, + 14, + 12, + 6, + 5, + 8, + 10, + 7, + 9, + 7, + 10, + 5, + 8, + 6, + 13, + 4, + 11, + 2, + 12, + 3, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "CarIdxClass": { + "countAsTime": false, + "length": 64, + "name": "CarIdxClass", + "description": "Cars class id by car index", + "unit": "", + "varType": 2, + "value": [ + 11, + 2264, + 2264, + 2264, + 2264, + 2264, + 2264, + 2264, + 2264, + 2264, + 2264, + 2264, + 4012, + 4012, + 4012, + 4012, + 4012, + 4012, + 4012, + 4012, + 4012, + 4012, + 4012, + 4012, + 4012, + 4012, + 4012, + 4012, + 74, + 74, + 74, + 74, + 74, + 74, + 74, + 74, + 74, + 74, + 74, + 74, + 74, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + 2264 + ] + }, + "CarIdxF2Time": { + "countAsTime": false, + "length": 64, + "name": "CarIdxF2Time", + "description": "Race time behind leader or fastest lap time otherwise", + "unit": "s", + "varType": 4, + "value": [ + 0, + 125.73909759521484, + 75.65640258789062, + 10.527199745178223, + 27.765600204467773, + 0, + 0, + 33.95920181274414, + 44.109500885009766, + 62.40079879760742, + 53.972999572753906, + 12.05049991607666, + 131.06179809570312, + 190.65919494628906, + 249.58729553222656, + 163.6042022705078, + 167.42709350585938, + 135.28309631347656, + 172.2404022216797, + 167.75120544433594, + 211.00579833984375, + 176.7707061767578, + 225.2371063232422, + 174.87890625, + 168.39329528808594, + 177.08419799804688, + 193.91090393066406, + 175.47279357910156, + 235.8863983154297, + 203.8258056640625, + 281.00140380859375, + 200.13760375976562, + 220.90260314941406, + 200.96780395507812, + 143.76339721679688, + 199.75250244140625, + 286.8481140136719, + 188.1461944580078, + 153.5301971435547, + 196.54119873046875, + 176.24070739746094, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "CarIdxEstTime": { + "countAsTime": false, + "length": 64, + "name": "CarIdxEstTime", + "description": "Estimated time to reach current location on track", + "unit": "s", + "varType": 4, + "value": [ + 108.16171264648438, + 0, + 96.89006042480469, + 0, + 0, + 0, + 0, + 0, + 0, + 107.96913146972656, + 5.171639442443848, + 0, + 0, + 98.13075256347656, + 0, + 124.49742126464844, + 119.42278289794922, + 0, + 2.827049493789673, + 5.343958854675293, + 77.45430755615234, + 0, + 62.60463333129883, + 110.67277526855469, + 119.0706787109375, + 109.69510650634766, + 92.41349792480469, + 110.12801361083984, + 50.2624397277832, + 83.64350128173828, + 117.88771057128906, + 86.93889617919922, + 67.26636505126953, + 86.2257080078125, + 0, + 87.1042709350586, + 108.81385040283203, + 98.14337921142578, + 0, + 89.79824829101562, + 107.85681915283203, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "CarIdxLastLapTime": { + "countAsTime": false, + "length": 64, + "name": "CarIdxLastLapTime", + "description": "Cars last lap time", + "unit": "s", + "varType": 4, + "value": [ + -1, + -1, + 122.9271011352539, + -1, + -1, + -1, + -1, + -1, + -1, + 118.760498046875, + 119.6624984741211, + -1, + -1, + 127.90480041503906, + -1, + 129.06260681152344, + 128.29859924316406, + -1, + 128.2991943359375, + 128.2227020263672, + 128.9882049560547, + -1, + 131.3549041748047, + 131.531494140625, + 129.09249877929688, + 128.80299377441406, + 132.68499755859375, + 131.97129821777344, + 137.6916961669922, + 128.63540649414062, + 133.1761016845703, + 138.302001953125, + 130.5236053466797, + 131.59320068359375, + -1, + 130.62210083007812, + -1, + 134.1920928955078, + -1, + -1, + 128.8188018798828, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxBestLapTime": { + "countAsTime": false, + "length": 64, + "name": "CarIdxBestLapTime", + "description": "Cars best lap time", + "unit": "s", + "varType": 4, + "value": [ + -1, + -1, + 113.37590026855469, + -1, + -1, + -1, + -1, + -1, + -1, + 118.11250305175781, + 116.52780151367188, + -1, + -1, + 127.61519622802734, + -1, + 127.47899627685547, + 128.29859924316406, + -1, + 127.216796875, + 127.57589721679688, + 128.89210510253906, + -1, + 130.9324951171875, + 129.66419982910156, + 127.8124008178711, + 128.80299377441406, + 131.06919860839844, + 129.49310302734375, + 132.93389892578125, + 127.68180084228516, + 127.65149688720703, + 129.41729736328125, + 129.72479248046875, + 128.82510375976562, + -1, + 130.2198944091797, + 129.49429321289062, + 129.18209838867188, + -1, + 129.3939971923828, + 128.29769897460938, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxBestLapNum": { + "countAsTime": false, + "length": 64, + "name": "CarIdxBestLapNum", + "description": "Cars best lap number", + "unit": "", + "varType": 2, + "value": [ + -1, + -1, + 8, + -1, + -1, + -1, + -1, + -1, + -1, + 2, + 3, + -1, + -1, + 5, + -1, + 3, + 11, + -1, + 5, + 5, + 5, + -1, + 10, + 7, + 4, + 11, + 8, + 5, + 4, + 5, + 6, + 4, + 3, + 6, + -1, + 10, + 7, + 6, + -1, + 9, + 2, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxTireCompound": { + "countAsTime": false, + "length": 64, + "name": "CarIdxTireCompound", + "description": "Cars current tire compound", + "unit": "", + "varType": 2, + "value": [ + -1, + -1, + 0, + -1, + -1, + -1, + -1, + -1, + -1, + 0, + 0, + -1, + -1, + 0, + -1, + 0, + 0, + -1, + 0, + 0, + 0, + -1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + -1, + 0, + 0, + 0, + -1, + 0, + 0, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxQualTireCompound": { + "countAsTime": false, + "length": 64, + "name": "CarIdxQualTireCompound", + "description": "Cars Qual tire compound", + "unit": "", + "varType": 2, + "value": [ + -1, + 0, + -1, + -1, + 0, + 0, + -1, + 0, + 0, + 0, + -1, + 0, + -1, + 0, + 0, + 0, + 0, + -1, + 0, + 0, + 0, + -1, + 0, + 0, + 0, + -1, + -1, + 0, + -1, + -1, + 0, + 0, + -1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxQualTireCompoundLocked": { + "countAsTime": false, + "length": 64, + "name": "CarIdxQualTireCompoundLocked", + "description": "Cars Qual tire compound is locked-in", + "unit": "", + "varType": 1, + "value": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + }, + "CarIdxFastRepairsUsed": { + "countAsTime": false, + "length": 64, + "name": "CarIdxFastRepairsUsed", + "description": "How many fast repairs each car has used", + "unit": "", + "varType": 2, + "value": [ + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "CarIdxSessionFlags": { + "countAsTime": false, + "length": 64, + "name": "CarIdxSessionFlags", + "description": "Session flags for each player", + "unit": "irsdk_Flags", + "varType": 3, + "value": [ + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 0, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 262144, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "PaceMode": { + "countAsTime": false, + "length": 1, + "name": "PaceMode", + "description": "Are we pacing or not", + "unit": "irsdk_PaceMode", + "varType": 2, + "value": [ + 1 + ] + }, + "CarIdxPaceLine": { + "countAsTime": false, + "length": 64, + "name": "CarIdxPaceLine", + "description": "What line cars are pacing in or -1 if not pacing", + "unit": "", + "varType": 2, + "value": [ + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxPaceRow": { + "countAsTime": false, + "length": 64, + "name": "CarIdxPaceRow", + "description": "What row cars are pacing in or -1 if not pacing", + "unit": "", + "varType": 2, + "value": [ + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxPaceFlags": { + "countAsTime": false, + "length": 64, + "name": "CarIdxPaceFlags", + "description": "Pacing status flags for each car", + "unit": "irsdk_PaceFlags", + "varType": 3, + "value": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "OnPitRoad": { + "countAsTime": false, + "length": 1, + "name": "OnPitRoad", + "description": "Is the player car on pit road between the cones", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "CarIdxSteer": { + "countAsTime": false, + "length": 64, + "name": "CarIdxSteer", + "description": "Steering wheel angle by car index", + "unit": "rad", + "varType": 4, + "value": [ + 3.4662186315648214e-11, + 0, + 0.3160237669944763, + 0, + 0, + 0, + 0, + 0, + 0, + -0.034656625241041183, + 0.0593019500374794, + 0, + 0, + -0.5755974054336548, + 0, + -0.12814277410507202, + -0.02699762023985386, + 0, + -0.18577665090560913, + -0.08335816115140915, + -0.021373825147747993, + 0, + -0.144452765583992, + -0.0006998949684202671, + 0.13654862344264984, + -0.9180959463119507, + 0.07310225814580917, + -0.5655624866485596, + -0.7315067648887634, + -0.04665734991431236, + 0.1220453530550003, + -0.15204386413097382, + -0.4145624339580536, + -0.06077919155359268, + 0, + 0.04472941905260086, + -1.5560194253921509, + -0.42265233397483826, + 0, + 0.041806917637586594, + 0.5071610808372498, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "CarIdxRPM": { + "countAsTime": false, + "length": 64, + "name": "CarIdxRPM", + "description": "Engine rpm by car index", + "unit": "revs/min", + "varType": 4, + "value": [ + 2000, + -1, + 5383.2998046875, + -1, + -1, + -1, + -1, + -1, + -1, + 6683.388671875, + 6167.03369140625, + -1, + -1, + 5730.9267578125, + -1, + 6317.42431640625, + 6749.64404296875, + -1, + 6453.357421875, + 4587.083984375, + 7219.27392578125, + -1, + 6604.56298828125, + 6121.6005859375, + 6776.2919921875, + 6019.22314453125, + 6613.2861328125, + 5938.18212890625, + 6915.33447265625, + 6613.2861328125, + 6204.3857421875, + 7033.7529296875, + 6154.619140625, + 6928.9130859375, + -1, + 6892.75244140625, + 7525, + 5547.69921875, + -1, + 7098.21875, + 6630.75732421875, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "CarIdxGear": { + "countAsTime": false, + "length": 64, + "name": "CarIdxGear", + "description": "-1=reverse 0=neutral 1..n=current gear by car index", + "unit": "", + "varType": 2, + "value": [ + 1, + -1, + 4, + -1, + -1, + -1, + -1, + -1, + -1, + 4, + 4, + -1, + -1, + 3, + -1, + 5, + 4, + -1, + 5, + 0, + 3, + -1, + 4, + 3, + 4, + 3, + 5, + 3, + 4, + 4, + 4, + 4, + 2, + 4, + -1, + 4, + 2, + 2, + -1, + 4, + 3, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "SteeringWheelAngle": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelAngle", + "description": "Steering wheel angle", + "unit": "rad", + "varType": 4, + "value": [ + -0.004920117557048798 + ] + }, + "Throttle": { + "countAsTime": false, + "length": 1, + "name": "Throttle", + "description": "0=off throttle to 1=full throttle", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "Brake": { + "countAsTime": false, + "length": 1, + "name": "Brake", + "description": "0=brake released to 1=max pedal force", + "unit": "%", + "varType": 4, + "value": [ + 0.6594855785369873 + ] + }, + "Clutch": { + "countAsTime": false, + "length": 1, + "name": "Clutch", + "description": "0=disengaged to 1=fully engaged", + "unit": "%", + "varType": 4, + "value": [ + 1 + ] + }, + "Gear": { + "countAsTime": false, + "length": 1, + "name": "Gear", + "description": "-1=reverse 0=neutral 1..n=current gear", + "unit": "", + "varType": 2, + "value": [ + 1 + ] + }, + "RPM": { + "countAsTime": false, + "length": 1, + "name": "RPM", + "description": "Engine rpm", + "unit": "revs/min", + "varType": 4, + "value": [ + 962.057373046875 + ] + }, + "PlayerCarSLFirstRPM": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarSLFirstRPM", + "description": "Shift light first light rpm", + "unit": "revs/min", + "varType": 4, + "value": [ + 6400 + ] + }, + "PlayerCarSLShiftRPM": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarSLShiftRPM", + "description": "Shift light shift rpm", + "unit": "revs/min", + "varType": 4, + "value": [ + 7400 + ] + }, + "PlayerCarSLLastRPM": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarSLLastRPM", + "description": "Shift light last light rpm", + "unit": "revs/min", + "varType": 4, + "value": [ + 7400 + ] + }, + "PlayerCarSLBlinkRPM": { + "countAsTime": false, + "length": 1, + "name": "PlayerCarSLBlinkRPM", + "description": "Shift light blink rpm", + "unit": "revs/min", + "varType": 4, + "value": [ + 7425 + ] + }, + "Lap": { + "countAsTime": false, + "length": 1, + "name": "Lap", + "description": "Laps started count", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "LapCompleted": { + "countAsTime": false, + "length": 1, + "name": "LapCompleted", + "description": "Laps completed count", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "LapDist": { + "countAsTime": false, + "length": 1, + "name": "LapDist", + "description": "Meters traveled from S/F this lap", + "unit": "m", + "varType": 4, + "value": [ + 0 + ] + }, + "LapDistPct": { + "countAsTime": false, + "length": 1, + "name": "LapDistPct", + "description": "Percentage distance around lap", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "RaceLaps": { + "countAsTime": false, + "length": 1, + "name": "RaceLaps", + "description": "Laps completed in race", + "unit": "", + "varType": 2, + "value": [ + 14 + ] + }, + "CarDistAhead": { + "countAsTime": false, + "length": 1, + "name": "CarDistAhead", + "description": "Distance to first car in front of player in meters", + "unit": "m", + "varType": 4, + "value": [ + 790.8822021484375 + ] + }, + "CarDistBehind": { + "countAsTime": false, + "length": 1, + "name": "CarDistBehind", + "description": "Distance to first car behind player in meters", + "unit": "m", + "varType": 4, + "value": [ + 21.216827392578125 + ] + }, + "LapBestLap": { + "countAsTime": false, + "length": 1, + "name": "LapBestLap", + "description": "Players best lap number", + "unit": "", + "varType": 2, + "value": [ + 13 + ] + }, + "LapBestLapTime": { + "countAsTime": false, + "length": 1, + "name": "LapBestLapTime", + "description": "Players best lap time", + "unit": "s", + "varType": 4, + "value": [ + 114.87249755859375 + ] + }, + "LapLastLapTime": { + "countAsTime": false, + "length": 1, + "name": "LapLastLapTime", + "description": "Players last lap time", + "unit": "s", + "varType": 4, + "value": [ + 114.87249755859375 + ] + }, + "LapCurrentLapTime": { + "countAsTime": false, + "length": 1, + "name": "LapCurrentLapTime", + "description": "Estimate of players current lap time as shown in F3 box", + "unit": "s", + "varType": 4, + "value": [ + 31.861799240112305 + ] + }, + "LapLasNLapSeq": { + "countAsTime": false, + "length": 1, + "name": "LapLasNLapSeq", + "description": "Player num consecutive clean laps completed for N average", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "LapLastNLapTime": { + "countAsTime": false, + "length": 1, + "name": "LapLastNLapTime", + "description": "Player last N average lap time", + "unit": "s", + "varType": 4, + "value": [ + 0 + ] + }, + "LapBestNLapLap": { + "countAsTime": false, + "length": 1, + "name": "LapBestNLapLap", + "description": "Player last lap in best N average lap time", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "LapBestNLapTime": { + "countAsTime": false, + "length": 1, + "name": "LapBestNLapTime", + "description": "Player best N average lap time", + "unit": "s", + "varType": 4, + "value": [ + 0 + ] + }, + "LapDeltaToBestLap": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToBestLap", + "description": "Delta time for best lap", + "unit": "s", + "varType": 4, + "value": [ + 0 + ] + }, + "LapDeltaToBestLap_DD": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToBestLap_DD", + "description": "Rate of change of delta time for best lap", + "unit": "s/s", + "varType": 4, + "value": [ + 0 + ] + }, + "LapDeltaToBestLap_OK": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToBestLap_OK", + "description": "Delta time for best lap is valid", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "LapDeltaToOptimalLap": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToOptimalLap", + "description": "Delta time for optimal lap", + "unit": "s", + "varType": 4, + "value": [ + 0 + ] + }, + "LapDeltaToOptimalLap_DD": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToOptimalLap_DD", + "description": "Rate of change of delta time for optimal lap", + "unit": "s/s", + "varType": 4, + "value": [ + 0 + ] + }, + "LapDeltaToOptimalLap_OK": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToOptimalLap_OK", + "description": "Delta time for optimal lap is valid", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "LapDeltaToSessionBestLap": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToSessionBestLap", + "description": "Delta time for session best lap", + "unit": "s", + "varType": 4, + "value": [ + 0 + ] + }, + "LapDeltaToSessionBestLap_DD": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToSessionBestLap_DD", + "description": "Rate of change of delta time for session best lap", + "unit": "s/s", + "varType": 4, + "value": [ + 0 + ] + }, + "LapDeltaToSessionBestLap_OK": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToSessionBestLap_OK", + "description": "Delta time for session best lap is valid", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "LapDeltaToSessionOptimalLap": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToSessionOptimalLap", + "description": "Delta time for session optimal lap", + "unit": "s", + "varType": 4, + "value": [ + 0 + ] + }, + "LapDeltaToSessionOptimalLap_DD": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToSessionOptimalLap_DD", + "description": "Rate of change of delta time for session optimal lap", + "unit": "s/s", + "varType": 4, + "value": [ + 0 + ] + }, + "LapDeltaToSessionOptimalLap_OK": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToSessionOptimalLap_OK", + "description": "Delta time for session optimal lap is valid", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "LapDeltaToSessionLastlLap": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToSessionLastlLap", + "description": "Delta time for session last lap", + "unit": "s", + "varType": 4, + "value": [ + 0 + ] + }, + "LapDeltaToSessionLastlLap_DD": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToSessionLastlLap_DD", + "description": "Rate of change of delta time for session last lap", + "unit": "s/s", + "varType": 4, + "value": [ + 0 + ] + }, + "LapDeltaToSessionLastlLap_OK": { + "countAsTime": false, + "length": 1, + "name": "LapDeltaToSessionLastlLap_OK", + "description": "Delta time for session last lap is valid", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "Speed": { + "countAsTime": false, + "length": 1, + "name": "Speed", + "description": "GPS vehicle speed", + "unit": "m/s", + "varType": 4, + "value": [ + 0 + ] + }, + "Yaw": { + "countAsTime": false, + "length": 1, + "name": "Yaw", + "description": "Yaw orientation", + "unit": "rad", + "varType": 4, + "value": [ + 0 + ] + }, + "YawNorth": { + "countAsTime": false, + "length": 1, + "name": "YawNorth", + "description": "Yaw orientation relative to north", + "unit": "rad", + "varType": 4, + "value": [ + 0 + ] + }, + "Pitch": { + "countAsTime": false, + "length": 1, + "name": "Pitch", + "description": "Pitch orientation", + "unit": "rad", + "varType": 4, + "value": [ + 0 + ] + }, + "Roll": { + "countAsTime": false, + "length": 1, + "name": "Roll", + "description": "Roll orientation", + "unit": "rad", + "varType": 4, + "value": [ + 0 + ] + }, + "EnterExitReset": { + "countAsTime": false, + "length": 1, + "name": "EnterExitReset", + "description": "Indicate action the reset key will take 0 enter 1 exit 2 reset", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "TrackTemp": { + "countAsTime": false, + "length": 1, + "name": "TrackTemp", + "description": "Deprecated set to TrackTempCrew", + "unit": "C", + "varType": 4, + "value": [ + 20.555572509765625 + ] + }, + "TrackTempCrew": { + "countAsTime": false, + "length": 1, + "name": "TrackTempCrew", + "description": "Temperature of track measured by crew around track", + "unit": "C", + "varType": 4, + "value": [ + 20.555572509765625 + ] + }, + "AirTemp": { + "countAsTime": false, + "length": 1, + "name": "AirTemp", + "description": "Temperature of air at start/finish line", + "unit": "C", + "varType": 4, + "value": [ + 19.44536018371582 + ] + }, + "TrackWetness": { + "countAsTime": false, + "length": 1, + "name": "TrackWetness", + "description": "How wet is the average track surface", + "unit": "irsdk_TrackWetness", + "varType": 2, + "value": [ + 1 + ] + }, + "Skies": { + "countAsTime": false, + "length": 1, + "name": "Skies", + "description": "Skies (0=clear/1=p cloudy/2=m cloudy/3=overcast)", + "unit": "", + "varType": 2, + "value": [ + 3 + ] + }, + "AirDensity": { + "countAsTime": false, + "length": 1, + "name": "AirDensity", + "description": "Density of air at start/finish line", + "unit": "kg/m^3", + "varType": 4, + "value": [ + 1.1859312057495117 + ] + }, + "AirPressure": { + "countAsTime": false, + "length": 1, + "name": "AirPressure", + "description": "Pressure of air at start/finish line", + "unit": "Pa", + "varType": 4, + "value": [ + 99914.734375 + ] + }, + "WindVel": { + "countAsTime": false, + "length": 1, + "name": "WindVel", + "description": "Wind velocity at start/finish line", + "unit": "m/s", + "varType": 4, + "value": [ + 2.283130645751953 + ] + }, + "WindDir": { + "countAsTime": false, + "length": 1, + "name": "WindDir", + "description": "Wind direction at start/finish line", + "unit": "rad", + "varType": 4, + "value": [ + 2.125577449798584 + ] + }, + "RelativeHumidity": { + "countAsTime": false, + "length": 1, + "name": "RelativeHumidity", + "description": "Relative Humidity at start/finish line", + "unit": "%", + "varType": 4, + "value": [ + 0.3647080063819885 + ] + }, + "FogLevel": { + "countAsTime": false, + "length": 1, + "name": "FogLevel", + "description": "Fog level at start/finish line", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "Precipitation": { + "countAsTime": false, + "length": 1, + "name": "Precipitation", + "description": "Precipitation at start/finish line", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "SolarAltitude": { + "countAsTime": false, + "length": 1, + "name": "SolarAltitude", + "description": "Sun angle above horizon in radians", + "unit": "rad", + "varType": 4, + "value": [ + 0.10499000549316406 + ] + }, + "SolarAzimuth": { + "countAsTime": false, + "length": 1, + "name": "SolarAzimuth", + "description": "Sun angle clockwise from north in radians", + "unit": "rad", + "varType": 4, + "value": [ + 4.137931823730469 + ] + }, + "WeatherDeclaredWet": { + "countAsTime": false, + "length": 1, + "name": "WeatherDeclaredWet", + "description": "The steward says rain tires can be used", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "DCLapStatus": { + "countAsTime": false, + "length": 1, + "name": "DCLapStatus", + "description": "Status of driver change lap requirements", + "unit": "", + "varType": 2, + "value": [ + 2 + ] + }, + "DCDriversSoFar": { + "countAsTime": false, + "length": 1, + "name": "DCDriversSoFar", + "description": "Number of team drivers who have run a stint", + "unit": "", + "varType": 2, + "value": [ + 1 + ] + }, + "OkToReloadTextures": { + "countAsTime": false, + "length": 1, + "name": "OkToReloadTextures", + "description": "True if it is ok to reload car textures at this time", + "unit": "", + "varType": 1, + "value": [ + true + ] + }, + "LoadNumTextures": { + "countAsTime": false, + "length": 1, + "name": "LoadNumTextures", + "description": "True if the car_num texture will be loaded", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "CarLeftRight": { + "countAsTime": false, + "length": 1, + "name": "CarLeftRight", + "description": "Notify if car is to the left or right of driver", + "unit": "irsdk_CarLeftRight", + "varType": 2, + "value": [ + 1 + ] + }, + "PitsOpen": { + "countAsTime": false, + "length": 1, + "name": "PitsOpen", + "description": "True if pit stop is allowed for the current player", + "unit": "", + "varType": 1, + "value": [ + true + ] + }, + "VidCapEnabled": { + "countAsTime": false, + "length": 1, + "name": "VidCapEnabled", + "description": "True if video capture system is enabled", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "VidCapActive": { + "countAsTime": false, + "length": 1, + "name": "VidCapActive", + "description": "True if video currently being captured", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "PitRepairLeft": { + "countAsTime": false, + "length": 1, + "name": "PitRepairLeft", + "description": "Time left for mandatory pit repairs if repairs are active", + "unit": "s", + "varType": 4, + "value": [ + 0 + ] + }, + "PitOptRepairLeft": { + "countAsTime": false, + "length": 1, + "name": "PitOptRepairLeft", + "description": "Time left for optional repairs if repairs are active", + "unit": "s", + "varType": 4, + "value": [ + 0 + ] + }, + "PitstopActive": { + "countAsTime": false, + "length": 1, + "name": "PitstopActive", + "description": "Is the player getting pit stop service", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "FastRepairUsed": { + "countAsTime": false, + "length": 1, + "name": "FastRepairUsed", + "description": "How many fast repairs used so far", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "FastRepairAvailable": { + "countAsTime": false, + "length": 1, + "name": "FastRepairAvailable", + "description": "How many fast repairs left 255 is unlimited", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "LFTiresUsed": { + "countAsTime": false, + "length": 1, + "name": "LFTiresUsed", + "description": "How many left front tires used so far", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "RFTiresUsed": { + "countAsTime": false, + "length": 1, + "name": "RFTiresUsed", + "description": "How many right front tires used so far", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "LRTiresUsed": { + "countAsTime": false, + "length": 1, + "name": "LRTiresUsed", + "description": "How many left rear tires used so far", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "RRTiresUsed": { + "countAsTime": false, + "length": 1, + "name": "RRTiresUsed", + "description": "How many right rear tires used so far", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "LeftTireSetsUsed": { + "countAsTime": false, + "length": 1, + "name": "LeftTireSetsUsed", + "description": "How many left tire sets used so far", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "RightTireSetsUsed": { + "countAsTime": false, + "length": 1, + "name": "RightTireSetsUsed", + "description": "How many right tire sets used so far", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "FrontTireSetsUsed": { + "countAsTime": false, + "length": 1, + "name": "FrontTireSetsUsed", + "description": "How many front tire sets used so far", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "RearTireSetsUsed": { + "countAsTime": false, + "length": 1, + "name": "RearTireSetsUsed", + "description": "How many rear tire sets used so far", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "TireSetsUsed": { + "countAsTime": false, + "length": 1, + "name": "TireSetsUsed", + "description": "How many tire sets used so far", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "LFTiresAvailable": { + "countAsTime": false, + "length": 1, + "name": "LFTiresAvailable", + "description": "How many left front tires are remaining 255 is unlimited", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "RFTiresAvailable": { + "countAsTime": false, + "length": 1, + "name": "RFTiresAvailable", + "description": "How many right front tires are remaining 255 is unlimited", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "LRTiresAvailable": { + "countAsTime": false, + "length": 1, + "name": "LRTiresAvailable", + "description": "How many left rear tires are remaining 255 is unlimited", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "RRTiresAvailable": { + "countAsTime": false, + "length": 1, + "name": "RRTiresAvailable", + "description": "How many right rear tires are remaining 255 is unlimited", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "LeftTireSetsAvailable": { + "countAsTime": false, + "length": 1, + "name": "LeftTireSetsAvailable", + "description": "How many left tire sets are remaining 255 is unlimited", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "RightTireSetsAvailable": { + "countAsTime": false, + "length": 1, + "name": "RightTireSetsAvailable", + "description": "How many right tire sets are remaining 255 is unlimited", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "FrontTireSetsAvailable": { + "countAsTime": false, + "length": 1, + "name": "FrontTireSetsAvailable", + "description": "How many front tire sets are remaining 255 is unlimited", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "RearTireSetsAvailable": { + "countAsTime": false, + "length": 1, + "name": "RearTireSetsAvailable", + "description": "How many rear tire sets are remaining 255 is unlimited", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "TireSetsAvailable": { + "countAsTime": false, + "length": 1, + "name": "TireSetsAvailable", + "description": "How many tire sets are remaining 255 is unlimited", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "CamCarIdx": { + "countAsTime": false, + "length": 1, + "name": "CamCarIdx", + "description": "Active camera's focus car index", + "unit": "", + "varType": 2, + "value": [ + 5 + ] + }, + "CamCameraNumber": { + "countAsTime": false, + "length": 1, + "name": "CamCameraNumber", + "description": "Active camera number", + "unit": "", + "varType": 2, + "value": [ + 1 + ] + }, + "CamGroupNumber": { + "countAsTime": false, + "length": 1, + "name": "CamGroupNumber", + "description": "Active camera group number", + "unit": "", + "varType": 2, + "value": [ + 21 + ] + }, + "CamCameraState": { + "countAsTime": false, + "length": 1, + "name": "CamCameraState", + "description": "State of camera system", + "unit": "irsdk_CameraState", + "varType": 3, + "value": [ + 81 + ] + }, + "IsOnTrackCar": { + "countAsTime": false, + "length": 1, + "name": "IsOnTrackCar", + "description": "1=Car on track physics running", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "IsInGarage": { + "countAsTime": false, + "length": 1, + "name": "IsInGarage", + "description": "1=Car in garage physics running", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "SteeringWheelAngleMax": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelAngleMax", + "description": "Steering wheel max angle", + "unit": "rad", + "varType": 4, + "value": [ + 9.544708251953125 + ] + }, + "ShiftPowerPct": { + "countAsTime": false, + "length": 1, + "name": "ShiftPowerPct", + "description": "Friction torque applied to gears when shifting or grinding", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "ShiftGrindRPM": { + "countAsTime": false, + "length": 1, + "name": "ShiftGrindRPM", + "description": "RPM of shifter grinding noise", + "unit": "RPM", + "varType": 4, + "value": [ + 0 + ] + }, + "ThrottleRaw": { + "countAsTime": false, + "length": 1, + "name": "ThrottleRaw", + "description": "Raw throttle input 0=off throttle to 1=full throttle", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "BrakeRaw": { + "countAsTime": false, + "length": 1, + "name": "BrakeRaw", + "description": "Raw brake input 0=brake released to 1=max pedal force", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "ClutchRaw": { + "countAsTime": false, + "length": 1, + "name": "ClutchRaw", + "description": "Raw clutch input 0=disengaged to 1=fully engaged", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "HandbrakeRaw": { + "countAsTime": false, + "length": 1, + "name": "HandbrakeRaw", + "description": "Raw handbrake input 0=handbrake released to 1=max force", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "BrakeABSactive": { + "countAsTime": false, + "length": 1, + "name": "BrakeABSactive", + "description": "true if abs is currently reducing brake force pressure", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "EngineWarnings": { + "countAsTime": false, + "length": 1, + "name": "EngineWarnings", + "description": "Bitfield for warning lights", + "unit": "irsdk_EngineWarnings", + "varType": 3, + "value": [ + 0 + ] + }, + "FuelLevelPct": { + "countAsTime": false, + "length": 1, + "name": "FuelLevelPct", + "description": "Percent fuel remaining", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "PitSvFlags": { + "countAsTime": false, + "length": 1, + "name": "PitSvFlags", + "description": "Bitfield of pit service checkboxes", + "unit": "irsdk_PitSvFlags", + "varType": 3, + "value": [ + 0 + ] + }, + "PitSvLFP": { + "countAsTime": false, + "length": 1, + "name": "PitSvLFP", + "description": "Pit service left front tire pressure", + "unit": "kPa", + "varType": 4, + "value": [ + 0 + ] + }, + "PitSvRFP": { + "countAsTime": false, + "length": 1, + "name": "PitSvRFP", + "description": "Pit service right front tire pressure", + "unit": "kPa", + "varType": 4, + "value": [ + 0 + ] + }, + "PitSvLRP": { + "countAsTime": false, + "length": 1, + "name": "PitSvLRP", + "description": "Pit service left rear tire pressure", + "unit": "kPa", + "varType": 4, + "value": [ + 0 + ] + }, + "PitSvRRP": { + "countAsTime": false, + "length": 1, + "name": "PitSvRRP", + "description": "Pit service right rear tire pressure", + "unit": "kPa", + "varType": 4, + "value": [ + 0 + ] + }, + "PitSvFuel": { + "countAsTime": false, + "length": 1, + "name": "PitSvFuel", + "description": "Pit service fuel add amount", + "unit": "l or kWh", + "varType": 4, + "value": [ + 0 + ] + }, + "PitSvTireCompound": { + "countAsTime": false, + "length": 1, + "name": "PitSvTireCompound", + "description": "Pit service pending tire compound", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "CarIdxP2P_Status": { + "countAsTime": false, + "length": 64, + "name": "CarIdxP2P_Status", + "description": "Push2Pass active or not", + "unit": "", + "varType": 1, + "value": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + }, + "CarIdxP2P_Count": { + "countAsTime": false, + "length": 64, + "name": "CarIdxP2P_Count", + "description": "Push2Pass count of usage (or remaining in Race)", + "unit": "", + "varType": 2, + "value": [ + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + ] + }, + "P2P_Status": { + "countAsTime": false, + "length": 1, + "name": "P2P_Status", + "description": "Push2Pass active or not on your car", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "P2P_Count": { + "countAsTime": false, + "length": 1, + "name": "P2P_Count", + "description": "Push2Pass count of usage (or remaining in Race) on your car", + "unit": "", + "varType": 2, + "value": [ + 0 + ] + }, + "SteeringWheelPctTorque": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelPctTorque", + "description": "Force feedback % max torque on steering shaft unsigned", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "SteeringWheelPctTorqueSign": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelPctTorqueSign", + "description": "Force feedback % max torque on steering shaft signed", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "SteeringWheelPctTorqueSignStops": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelPctTorqueSignStops", + "description": "Force feedback % max torque on steering shaft signed stops", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "SteeringWheelPctIntensity": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelPctIntensity", + "description": "Force feedback % max intensity", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "SteeringWheelPctSmoothing": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelPctSmoothing", + "description": "Force feedback % max smoothing", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "SteeringWheelPctDamper": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelPctDamper", + "description": "Force feedback % max damping", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "SteeringWheelLimiter": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelLimiter", + "description": "Force feedback limiter strength limits impacts and oscillation", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "SteeringWheelMaxForceNm": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelMaxForceNm", + "description": "Value of strength or max force slider in Nm for FFB", + "unit": "N*m", + "varType": 4, + "value": [ + 37.70986557006836 + ] + }, + "SteeringWheelPeakForceNm": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelPeakForceNm", + "description": "Peak torque mapping to direct input units for FFB", + "unit": "N*m", + "varType": 4, + "value": [ + -1 + ] + }, + "SteeringWheelUseLinear": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelUseLinear", + "description": "True if steering wheel force is using linear mode", + "unit": "", + "varType": 1, + "value": [ + true + ] + }, + "ShiftIndicatorPct": { + "countAsTime": false, + "length": 1, + "name": "ShiftIndicatorPct", + "description": "DEPRECATED use DriverCarSLBlinkRPM instead", + "unit": "%", + "varType": 4, + "value": [ + 0 + ] + }, + "ReplayPlaySpeed": { + "countAsTime": false, + "length": 1, + "name": "ReplayPlaySpeed", + "description": "Replay playback speed", + "unit": "", + "varType": 2, + "value": [ + 1 + ] + }, + "ReplayPlaySlowMotion": { + "countAsTime": false, + "length": 1, + "name": "ReplayPlaySlowMotion", + "description": "0=not slow motion 1=replay is in slow motion", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "ReplaySessionTime": { + "countAsTime": false, + "length": 1, + "name": "ReplaySessionTime", + "description": "Seconds since replay session start", + "unit": "s", + "varType": 5, + "value": [ + 1888.8932698567708 + ] + }, + "ReplaySessionNum": { + "countAsTime": false, + "length": 1, + "name": "ReplaySessionNum", + "description": "Replay session number", + "unit": "", + "varType": 2, + "value": [ + 2 + ] + }, + "TireLF_RumblePitch": { + "countAsTime": false, + "length": 1, + "name": "TireLF_RumblePitch", + "description": "Players LF Tire Sound rumblestrip pitch", + "unit": "Hz", + "varType": 4, + "value": [ + 0 + ] + }, + "TireRF_RumblePitch": { + "countAsTime": false, + "length": 1, + "name": "TireRF_RumblePitch", + "description": "Players RF Tire Sound rumblestrip pitch", + "unit": "Hz", + "varType": 4, + "value": [ + 0 + ] + }, + "TireLR_RumblePitch": { + "countAsTime": false, + "length": 1, + "name": "TireLR_RumblePitch", + "description": "Players LR Tire Sound rumblestrip pitch", + "unit": "Hz", + "varType": 4, + "value": [ + 0 + ] + }, + "TireRR_RumblePitch": { + "countAsTime": false, + "length": 1, + "name": "TireRR_RumblePitch", + "description": "Players RR Tire Sound rumblestrip pitch", + "unit": "Hz", + "varType": 4, + "value": [ + 0 + ] + }, + "IsGarageVisible": { + "countAsTime": false, + "length": 1, + "name": "IsGarageVisible", + "description": "1=Garage screen is visible", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "SteeringWheelTorque_ST": { + "countAsTime": true, + "length": 6, + "name": "SteeringWheelTorque_ST", + "description": "Output torque on steering shaft at 360 Hz", + "unit": "N*m", + "varType": 4, + "value": [ + -0.6029183268547058, + -0.6029183268547058, + -0.6029183268547058, + -0.6029183268547058, + -0.6029183268547058, + -0.6029183268547058 + ] + }, + "SteeringWheelTorque": { + "countAsTime": false, + "length": 1, + "name": "SteeringWheelTorque", + "description": "Output torque on steering shaft", + "unit": "N*m", + "varType": 4, + "value": [ + -0.6029183268547058 + ] + }, + "VelocityZ_ST": { + "countAsTime": true, + "length": 6, + "name": "VelocityZ_ST", + "description": "Z velocity", + "unit": "m/s at 360 Hz", + "varType": 4, + "value": [ + 0.00032954063499346375, + 0.00032954063499346375, + 0.00032954063499346375, + 0.00032954063499346375, + 0.00032954063499346375, + 0.00032954063499346375 + ] + }, + "VelocityY_ST": { + "countAsTime": true, + "length": 6, + "name": "VelocityY_ST", + "description": "Y velocity", + "unit": "m/s at 360 Hz", + "varType": 4, + "value": [ + 0.00003346385346958414, + 0.00003346385346958414, + 0.00003346385346958414, + 0.00003346385346958414, + 0.00003346385346958414, + 0.00003346385346958414 + ] + }, + "VelocityX_ST": { + "countAsTime": true, + "length": 6, + "name": "VelocityX_ST", + "description": "X velocity", + "unit": "m/s at 360 Hz", + "varType": 4, + "value": [ + 0.002668481320142746, + 0.002668481320142746, + 0.002668481320142746, + 0.002668481320142746, + 0.002668481320142746, + 0.002668481320142746 + ] + }, + "VelocityZ": { + "countAsTime": false, + "length": 1, + "name": "VelocityZ", + "description": "Z velocity", + "unit": "m/s", + "varType": 4, + "value": [ + 0.00032954063499346375 + ] + }, + "VelocityY": { + "countAsTime": false, + "length": 1, + "name": "VelocityY", + "description": "Y velocity", + "unit": "m/s", + "varType": 4, + "value": [ + 0.00003346385346958414 + ] + }, + "VelocityX": { + "countAsTime": false, + "length": 1, + "name": "VelocityX", + "description": "X velocity", + "unit": "m/s", + "varType": 4, + "value": [ + 0.002668481320142746 + ] + }, + "YawRate_ST": { + "countAsTime": true, + "length": 6, + "name": "YawRate_ST", + "description": "Yaw rate at 360 Hz", + "unit": "rad/s", + "varType": 4, + "value": [ + -0.00009917393617797643, + -0.00009917393617797643, + -0.00009917393617797643, + -0.00009917393617797643, + -0.00009917393617797643, + -0.00009917393617797643 + ] + }, + "PitchRate_ST": { + "countAsTime": true, + "length": 6, + "name": "PitchRate_ST", + "description": "Pitch rate at 360 Hz", + "unit": "rad/s", + "varType": 4, + "value": [ + -0.00008106313180178404, + -0.00008106313180178404, + -0.00008106313180178404, + -0.00008106313180178404, + -0.00008106313180178404, + -0.00008106313180178404 + ] + }, + "RollRate_ST": { + "countAsTime": true, + "length": 6, + "name": "RollRate_ST", + "description": "Roll rate at 360 Hz", + "unit": "rad/s", + "varType": 4, + "value": [ + -0.00016055135347414762, + -0.00016055135347414762, + -0.00016055135347414762, + -0.00016055135347414762, + -0.00016055135347414762, + -0.00016055135347414762 + ] + }, + "YawRate": { + "countAsTime": false, + "length": 1, + "name": "YawRate", + "description": "Yaw rate", + "unit": "rad/s", + "varType": 4, + "value": [ + -0.00009917393617797643 + ] + }, + "PitchRate": { + "countAsTime": false, + "length": 1, + "name": "PitchRate", + "description": "Pitch rate", + "unit": "rad/s", + "varType": 4, + "value": [ + -0.00008106313180178404 + ] + }, + "RollRate": { + "countAsTime": false, + "length": 1, + "name": "RollRate", + "description": "Roll rate", + "unit": "rad/s", + "varType": 4, + "value": [ + -0.00016055135347414762 + ] + }, + "VertAccel_ST": { + "countAsTime": true, + "length": 6, + "name": "VertAccel_ST", + "description": "Vertical acceleration (including gravity) at 360 Hz", + "unit": "m/s^2", + "varType": 4, + "value": [ + 9.799846649169922, + 9.799846649169922, + 9.799846649169922, + 9.799846649169922, + 9.799846649169922, + 9.799846649169922 + ] + }, + "LatAccel_ST": { + "countAsTime": true, + "length": 6, + "name": "LatAccel_ST", + "description": "Lateral acceleration (including gravity) at 360 Hz", + "unit": "m/s^2", + "varType": 4, + "value": [ + 0.1846942901611328, + 0.1846942901611328, + 0.1846942901611328, + 0.1846942901611328, + 0.1846942901611328, + 0.1846942901611328 + ] + }, + "LongAccel_ST": { + "countAsTime": true, + "length": 6, + "name": "LongAccel_ST", + "description": "Longitudinal acceleration (including gravity) at 360 Hz", + "unit": "m/s^2", + "varType": 4, + "value": [ + -0.014514584094285965, + -0.014514584094285965, + -0.014514584094285965, + -0.014514584094285965, + -0.014514584094285965, + -0.014514584094285965 + ] + }, + "VertAccel": { + "countAsTime": false, + "length": 1, + "name": "VertAccel", + "description": "Vertical acceleration (including gravity)", + "unit": "m/s^2", + "varType": 4, + "value": [ + 9.799846649169922 + ] + }, + "LatAccel": { + "countAsTime": false, + "length": 1, + "name": "LatAccel", + "description": "Lateral acceleration (including gravity)", + "unit": "m/s^2", + "varType": 4, + "value": [ + 0.1846942901611328 + ] + }, + "LongAccel": { + "countAsTime": false, + "length": 1, + "name": "LongAccel", + "description": "Longitudinal acceleration (including gravity)", + "unit": "m/s^2", + "varType": 4, + "value": [ + -0.014514584094285965 + ] + }, + "dcStarter": { + "countAsTime": false, + "length": 1, + "name": "dcStarter", + "description": "In car trigger car starter", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "dcTractionControlToggle": { + "countAsTime": false, + "length": 1, + "name": "dcTractionControlToggle", + "description": "In car traction control active", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "dcPitSpeedLimiterToggle": { + "countAsTime": false, + "length": 1, + "name": "dcPitSpeedLimiterToggle", + "description": "In car traction control active", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "dcHeadlightFlash": { + "countAsTime": false, + "length": 1, + "name": "dcHeadlightFlash", + "description": "In car headlight flash control active", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "dpRFTireChange": { + "countAsTime": false, + "length": 1, + "name": "dpRFTireChange", + "description": "Pitstop rf tire change request", + "unit": "", + "varType": 4, + "value": [ + 0 + ] + }, + "dpLFTireChange": { + "countAsTime": false, + "length": 1, + "name": "dpLFTireChange", + "description": "Pitstop lf tire change request", + "unit": "", + "varType": 4, + "value": [ + 0 + ] + }, + "dpRRTireChange": { + "countAsTime": false, + "length": 1, + "name": "dpRRTireChange", + "description": "Pitstop rr tire change request", + "unit": "", + "varType": 4, + "value": [ + 0 + ] + }, + "dpLRTireChange": { + "countAsTime": false, + "length": 1, + "name": "dpLRTireChange", + "description": "Pitstop lr tire change request", + "unit": "", + "varType": 4, + "value": [ + 0 + ] + }, + "dpFuelFill": { + "countAsTime": false, + "length": 1, + "name": "dpFuelFill", + "description": "Pitstop fuel fill flag", + "unit": "", + "varType": 4, + "value": [ + 0 + ] + }, + "dpFuelAutoFillEnabled": { + "countAsTime": false, + "length": 1, + "name": "dpFuelAutoFillEnabled", + "description": "Pitstop auto fill fuel system enabled", + "unit": "", + "varType": 4, + "value": [ + 0 + ] + }, + "dpFuelAutoFillActive": { + "countAsTime": false, + "length": 1, + "name": "dpFuelAutoFillActive", + "description": "Pitstop auto fill fuel next stop flag", + "unit": "", + "varType": 4, + "value": [ + 0 + ] + }, + "dpWindshieldTearoff": { + "countAsTime": false, + "length": 1, + "name": "dpWindshieldTearoff", + "description": "Pitstop windshield tearoff", + "unit": "", + "varType": 4, + "value": [ + 0 + ] + }, + "dpFuelAddKg": { + "countAsTime": false, + "length": 1, + "name": "dpFuelAddKg", + "description": "Pitstop fuel add amount", + "unit": "kg", + "varType": 4, + "value": [ + 0 + ] + }, + "dcToggleWindshieldWipers": { + "countAsTime": false, + "length": 1, + "name": "dcToggleWindshieldWipers", + "description": "In car turn wipers on or off", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "dcTriggerWindshieldWipers": { + "countAsTime": false, + "length": 1, + "name": "dcTriggerWindshieldWipers", + "description": "In car momentarily turn on wipers", + "unit": "", + "varType": 1, + "value": [ + false + ] + }, + "dpFastRepair": { + "countAsTime": false, + "length": 1, + "name": "dpFastRepair", + "description": "Pitstop fast repair set", + "unit": "", + "varType": 4, + "value": [ + 0 + ] + }, + "dcBrakeBias": { + "countAsTime": false, + "length": 1, + "name": "dcBrakeBias", + "description": "In car brake bias adjustment", + "unit": "", + "varType": 4, + "value": [ + 0 + ] + }, + "dpLFTireColdPress": { + "countAsTime": false, + "length": 1, + "name": "dpLFTireColdPress", + "description": "Pitstop lf tire cold pressure adjustment", + "unit": "Pa", + "varType": 4, + "value": [ + 0 + ] + }, + "dpRFTireColdPress": { + "countAsTime": false, + "length": 1, + "name": "dpRFTireColdPress", + "description": "Pitstop rf cold tire pressure adjustment", + "unit": "Pa", + "varType": 4, + "value": [ + 0 + ] + }, + "dpLRTireColdPress": { + "countAsTime": false, + "length": 1, + "name": "dpLRTireColdPress", + "description": "Pitstop lr tire cold pressure adjustment", + "unit": "Pa", + "varType": 4, + "value": [ + 0 + ] + }, + "dpRRTireColdPress": { + "countAsTime": false, + "length": 1, + "name": "dpRRTireColdPress", + "description": "Pitstop rr cold tire pressure adjustment", + "unit": "Pa", + "varType": 4, + "value": [ + 0 + ] + }, + "dcTractionControl": { + "countAsTime": false, + "length": 1, + "name": "dcTractionControl", + "description": "In car traction control adjustment", + "unit": "", + "varType": 4, + "value": [ + 0 + ] + }, + "dcThrottleShape": { + "countAsTime": false, + "length": 1, + "name": "dcThrottleShape", + "description": "In car throttle shape adjustment", + "unit": "", + "varType": 4, + "value": [ + 0 + ] + }, + "FuelUsePerHour": { + "countAsTime": false, + "length": 1, + "name": "FuelUsePerHour", + "description": "Engine fuel used instantaneous", + "unit": "kg/h", + "varType": 4, + "value": [ + 1.5353190898895264 + ] + }, + "Voltage": { + "countAsTime": false, + "length": 1, + "name": "Voltage", + "description": "Engine voltage", + "unit": "V", + "varType": 4, + "value": [ + 13.40000057220459 + ] + }, + "WaterTemp": { + "countAsTime": false, + "length": 1, + "name": "WaterTemp", + "description": "Engine coolant temp", + "unit": "C", + "varType": 4, + "value": [ + 85.42027282714844 + ] + }, + "WaterLevel": { + "countAsTime": false, + "length": 1, + "name": "WaterLevel", + "description": "Engine coolant level", + "unit": "l", + "varType": 4, + "value": [ + 22 + ] + }, + "FuelPress": { + "countAsTime": false, + "length": 1, + "name": "FuelPress", + "description": "Engine fuel pressure", + "unit": "bar", + "varType": 4, + "value": [ + 5.829999923706055 + ] + }, + "OilTemp": { + "countAsTime": false, + "length": 1, + "name": "OilTemp", + "description": "Engine oil temperature", + "unit": "C", + "varType": 4, + "value": [ + 96.9951171875 + ] + }, + "OilPress": { + "countAsTime": false, + "length": 1, + "name": "OilPress", + "description": "Engine oil pressure", + "unit": "bar", + "varType": 4, + "value": [ + 3.9375007152557373 + ] + }, + "OilLevel": { + "countAsTime": false, + "length": 1, + "name": "OilLevel", + "description": "Engine oil level", + "unit": "l", + "varType": 4, + "value": [ + 11 + ] + }, + "ManifoldPress": { + "countAsTime": false, + "length": 1, + "name": "ManifoldPress", + "description": "Engine manifold pressure", + "unit": "bar", + "varType": 4, + "value": [ + 0.5095105171203613 + ] + }, + "FuelLevel": { + "countAsTime": false, + "length": 1, + "name": "FuelLevel", + "description": "Liters of fuel remaining", + "unit": "l", + "varType": 4, + "value": [ + 0 + ] + }, + "Engine0_RPM": { + "countAsTime": false, + "length": 1, + "name": "Engine0_RPM", + "description": "Engine0Engine rpm", + "unit": "revs/min", + "varType": 4, + "value": [ + 962.0577392578125 + ] + }, + "RFbrakeLinePress": { + "countAsTime": false, + "length": 1, + "name": "RFbrakeLinePress", + "description": "RF brake line pressure", + "unit": "bar", + "varType": 4, + "value": [ + 0 + ] + }, + "RFcoldPressure": { + "countAsTime": false, + "length": 1, + "name": "RFcoldPressure", + "description": "RF tire cold pressure as set in the garage", + "unit": "kPa", + "varType": 4, + "value": [ + 158.5794219970703 + ] + }, + "RFtempCL": { + "countAsTime": false, + "length": 1, + "name": "RFtempCL", + "description": "RF tire left carcass temperature", + "unit": "C", + "varType": 4, + "value": [ + 69.13107299804688 + ] + }, + "RFtempCM": { + "countAsTime": false, + "length": 1, + "name": "RFtempCM", + "description": "RF tire middle carcass temperature", + "unit": "C", + "varType": 4, + "value": [ + 66.30838012695312 + ] + }, + "RFtempCR": { + "countAsTime": false, + "length": 1, + "name": "RFtempCR", + "description": "RF tire right carcass temperature", + "unit": "C", + "varType": 4, + "value": [ + 65.64447021484375 + ] + }, + "RFwearL": { + "countAsTime": false, + "length": 1, + "name": "RFwearL", + "description": "RF tire left percent tread remaining", + "unit": "%", + "varType": 4, + "value": [ + 0.9268516302108765 + ] + }, + "RFwearM": { + "countAsTime": false, + "length": 1, + "name": "RFwearM", + "description": "RF tire middle percent tread remaining", + "unit": "%", + "varType": 4, + "value": [ + 0.9309877753257751 + ] + }, + "RFwearR": { + "countAsTime": false, + "length": 1, + "name": "RFwearR", + "description": "RF tire right percent tread remaining", + "unit": "%", + "varType": 4, + "value": [ + 0.9541441202163696 + ] + }, + "LFbrakeLinePress": { + "countAsTime": false, + "length": 1, + "name": "LFbrakeLinePress", + "description": "LF brake line pressure", + "unit": "bar", + "varType": 4, + "value": [ + 0 + ] + }, + "LFcoldPressure": { + "countAsTime": false, + "length": 1, + "name": "LFcoldPressure", + "description": "LF tire cold pressure as set in the garage", + "unit": "kPa", + "varType": 4, + "value": [ + 158.5794219970703 + ] + }, + "LFtempCL": { + "countAsTime": false, + "length": 1, + "name": "LFtempCL", + "description": "LF tire left carcass temperature", + "unit": "C", + "varType": 4, + "value": [ + 70.70883178710938 + ] + }, + "LFtempCM": { + "countAsTime": false, + "length": 1, + "name": "LFtempCM", + "description": "LF tire middle carcass temperature", + "unit": "C", + "varType": 4, + "value": [ + 70.7677001953125 + ] + }, + "LFtempCR": { + "countAsTime": false, + "length": 1, + "name": "LFtempCR", + "description": "LF tire right carcass temperature", + "unit": "C", + "varType": 4, + "value": [ + 73.17410278320312 + ] + }, + "LFwearL": { + "countAsTime": false, + "length": 1, + "name": "LFwearL", + "description": "LF tire left percent tread remaining", + "unit": "%", + "varType": 4, + "value": [ + 0.9369999170303345 + ] + }, + "LFwearM": { + "countAsTime": false, + "length": 1, + "name": "LFwearM", + "description": "LF tire middle percent tread remaining", + "unit": "%", + "varType": 4, + "value": [ + 0.9103884100914001 + ] + }, + "LFwearR": { + "countAsTime": false, + "length": 1, + "name": "LFwearR", + "description": "LF tire right percent tread remaining", + "unit": "%", + "varType": 4, + "value": [ + 0.9066996574401855 + ] + }, + "RRbrakeLinePress": { + "countAsTime": false, + "length": 1, + "name": "RRbrakeLinePress", + "description": "RR brake line pressure", + "unit": "bar", + "varType": 4, + "value": [ + 0 + ] + }, + "RRcoldPressure": { + "countAsTime": false, + "length": 1, + "name": "RRcoldPressure", + "description": "RR tire cold pressure as set in the garage", + "unit": "kPa", + "varType": 4, + "value": [ + 165.4741973876953 + ] + }, + "RRtempCL": { + "countAsTime": false, + "length": 1, + "name": "RRtempCL", + "description": "RR tire left carcass temperature", + "unit": "C", + "varType": 4, + "value": [ + 65.87469482421875 + ] + }, + "RRtempCM": { + "countAsTime": false, + "length": 1, + "name": "RRtempCM", + "description": "RR tire middle carcass temperature", + "unit": "C", + "varType": 4, + "value": [ + 64.03207397460938 + ] + }, + "RRtempCR": { + "countAsTime": false, + "length": 1, + "name": "RRtempCR", + "description": "RR tire right carcass temperature", + "unit": "C", + "varType": 4, + "value": [ + 56.819366455078125 + ] + }, + "RRwearL": { + "countAsTime": false, + "length": 1, + "name": "RRwearL", + "description": "RR tire left percent tread remaining", + "unit": "%", + "varType": 4, + "value": [ + 0.9427630305290222 + ] + }, + "RRwearM": { + "countAsTime": false, + "length": 1, + "name": "RRwearM", + "description": "RR tire middle percent tread remaining", + "unit": "%", + "varType": 4, + "value": [ + 0.9425097703933716 + ] + }, + "RRwearR": { + "countAsTime": false, + "length": 1, + "name": "RRwearR", + "description": "RR tire right percent tread remaining", + "unit": "%", + "varType": 4, + "value": [ + 0.9717822670936584 + ] + }, + "LRbrakeLinePress": { + "countAsTime": false, + "length": 1, + "name": "LRbrakeLinePress", + "description": "LR brake line pressure", + "unit": "bar", + "varType": 4, + "value": [ + 0 + ] + }, + "LRcoldPressure": { + "countAsTime": false, + "length": 1, + "name": "LRcoldPressure", + "description": "LR tire cold pressure as set in the garage", + "unit": "kPa", + "varType": 4, + "value": [ + 165.4741973876953 + ] + }, + "LRtempCL": { + "countAsTime": false, + "length": 1, + "name": "LRtempCL", + "description": "LR tire left carcass temperature", + "unit": "C", + "varType": 4, + "value": [ + 62.40179443359375 + ] + }, + "LRtempCM": { + "countAsTime": false, + "length": 1, + "name": "LRtempCM", + "description": "LR tire middle carcass temperature", + "unit": "C", + "varType": 4, + "value": [ + 66.93789672851562 + ] + }, + "LRtempCR": { + "countAsTime": false, + "length": 1, + "name": "LRtempCR", + "description": "LR tire right carcass temperature", + "unit": "C", + "varType": 4, + "value": [ + 68.47793579101562 + ] + }, + "LRwearL": { + "countAsTime": false, + "length": 1, + "name": "LRwearL", + "description": "LR tire left percent tread remaining", + "unit": "%", + "varType": 4, + "value": [ + 0.9558197259902954 + ] + }, + "LRwearM": { + "countAsTime": false, + "length": 1, + "name": "LRwearM", + "description": "LR tire middle percent tread remaining", + "unit": "%", + "varType": 4, + "value": [ + 0.9370022416114807 + ] + }, + "LRwearR": { + "countAsTime": false, + "length": 1, + "name": "LRwearR", + "description": "LR tire right percent tread remaining", + "unit": "%", + "varType": 4, + "value": [ + 0.937549889087677 + ] + }, + "LRshockDefl": { + "countAsTime": false, + "length": 1, + "name": "LRshockDefl", + "description": "LR shock deflection", + "unit": "m", + "varType": 4, + "value": [ + 0.03430384397506714 + ] + }, + "LRshockDefl_ST": { + "countAsTime": true, + "length": 6, + "name": "LRshockDefl_ST", + "description": "LR shock deflection at 360 Hz", + "unit": "m", + "varType": 4, + "value": [ + 0.03430384397506714, + 0.03430384397506714, + 0.03430384397506714, + 0.03430384397506714, + 0.03430384397506714, + 0.03430384397506714 + ] + }, + "LRshockVel": { + "countAsTime": false, + "length": 1, + "name": "LRshockVel", + "description": "LR shock velocity", + "unit": "m/s", + "varType": 4, + "value": [ + 0.0004362000327091664 + ] + }, + "LRshockVel_ST": { + "countAsTime": true, + "length": 6, + "name": "LRshockVel_ST", + "description": "LR shock velocity at 360 Hz", + "unit": "m/s", + "varType": 4, + "value": [ + 0.0004362000327091664, + 0.0004362000327091664, + 0.0004362000327091664, + 0.0004362000327091664, + 0.0004362000327091664, + 0.0004362000327091664 + ] + }, + "RRshockDefl": { + "countAsTime": false, + "length": 1, + "name": "RRshockDefl", + "description": "RR shock deflection", + "unit": "m", + "varType": 4, + "value": [ + 0.03472417593002319 + ] + }, + "RRshockDefl_ST": { + "countAsTime": true, + "length": 6, + "name": "RRshockDefl_ST", + "description": "RR shock deflection at 360 Hz", + "unit": "m", + "varType": 4, + "value": [ + 0.03472417593002319, + 0.03472417593002319, + 0.03472417593002319, + 0.03472417593002319, + 0.03472417593002319, + 0.03472417593002319 + ] + }, + "RRshockVel": { + "countAsTime": false, + "length": 1, + "name": "RRshockVel", + "description": "RR shock velocity", + "unit": "m/s", + "varType": 4, + "value": [ + 0.00030791255994699895 + ] + }, + "RRshockVel_ST": { + "countAsTime": true, + "length": 6, + "name": "RRshockVel_ST", + "description": "RR shock velocity at 360 Hz", + "unit": "m/s", + "varType": 4, + "value": [ + 0.00030791255994699895, + 0.00030791255994699895, + 0.00030791255994699895, + 0.00030791255994699895, + 0.00030791255994699895, + 0.00030791255994699895 + ] + }, + "LFshockDefl": { + "countAsTime": false, + "length": 1, + "name": "LFshockDefl", + "description": "LF shock deflection", + "unit": "m", + "varType": 4, + "value": [ + 0.06302130222320557 + ] + }, + "LFshockDefl_ST": { + "countAsTime": true, + "length": 6, + "name": "LFshockDefl_ST", + "description": "LF shock deflection at 360 Hz", + "unit": "m", + "varType": 4, + "value": [ + 0.06302130222320557, + 0.06302130222320557, + 0.06302130222320557, + 0.06302130222320557, + 0.06302130222320557, + 0.06302130222320557 + ] + }, + "LFshockVel": { + "countAsTime": false, + "length": 1, + "name": "LFshockVel", + "description": "LF shock velocity", + "unit": "m/s", + "varType": 4, + "value": [ + -0.0007214706856757402 + ] + }, + "LFshockVel_ST": { + "countAsTime": true, + "length": 6, + "name": "LFshockVel_ST", + "description": "LF shock velocity at 360 Hz", + "unit": "m/s", + "varType": 4, + "value": [ + -0.0007214706856757402, + -0.0007214706856757402, + -0.0007214706856757402, + -0.0007214706856757402, + -0.0007214706856757402, + -0.0007214706856757402 + ] + }, + "RFshockDefl": { + "countAsTime": false, + "length": 1, + "name": "RFshockDefl", + "description": "RF shock deflection", + "unit": "m", + "varType": 4, + "value": [ + 0.06327173113822937 + ] + }, + "RFshockDefl_ST": { + "countAsTime": true, + "length": 6, + "name": "RFshockDefl_ST", + "description": "RF shock deflection at 360 Hz", + "unit": "m", + "varType": 4, + "value": [ + 0.06327173113822937, + 0.06327173113822937, + 0.06327173113822937, + 0.06327173113822937, + 0.06327173113822937, + 0.06327173113822937 + ] + }, + "RFshockVel": { + "countAsTime": false, + "length": 1, + "name": "RFshockVel", + "description": "RF shock velocity", + "unit": "m/s", + "varType": 4, + "value": [ + -0.0007424343493767083 + ] + }, + "RFshockVel_ST": { + "countAsTime": true, + "length": 6, + "name": "RFshockVel_ST", + "description": "RF shock velocity at 360 Hz", + "unit": "m/s", + "varType": 4, + "value": [ + -0.0007424343493767083, + -0.0007424343493767083, + -0.0007424343493767083, + -0.0007424343493767083, + -0.0007424343493767083, + -0.0007424343493767083 + ] + } +} \ No newline at end of file diff --git a/src/app/irsdk/node/utils/mock-sdk.ts b/src/app/irsdk/node/utils/mock-sdk.ts new file mode 100644 index 0000000..2ff22c9 --- /dev/null +++ b/src/app/irsdk/node/utils/mock-sdk.ts @@ -0,0 +1,112 @@ +import type { INativeSDK } from '../../native'; +import type { + TelemetryVarList, TelemetryVariable, BroadcastMessages, CameraState, ReplayPositionCommand, ReplaySearchCommand, ReplayStateCommand, ReloadTexturesCommand, ChatCommand, PitCommand, TelemetryCommand, FFBCommand, VideoCaptureCommand, +} from '../../types'; + +import { loadMockSessionData, loadMockTelemetry } from './mock-data/loader'; + +let mockTelemetry: TelemetryVarList | null = null; +let MOCK_SESSION: string | null = null; + +export class MockSDK implements INativeSDK { + public currDataVersion: number; + + public enableLogging: boolean; + + private _isRunning: boolean; + + constructor() { + this.currDataVersion = 1; + this.enableLogging = false; + this._isRunning = false; + void this._loadMockData(); + console.warn( + 'Attempting to access iRacing SDK on unsupported platform!', + '\nReturning mock SDK for testing purposes. (Only win32 supported)', + ); + } + + private async _loadMockData(): Promise { + const [session, telemetry] = await Promise.all([ + !MOCK_SESSION ? loadMockSessionData() : Promise.resolve(MOCK_SESSION), + !mockTelemetry ? loadMockTelemetry() : Promise.resolve(mockTelemetry), + ]); + MOCK_SESSION = session; + mockTelemetry = telemetry; + } + + public startSDK(): boolean { + this._isRunning = true; + return true; + } + + public stopSDK(): void { + this._isRunning = false; + } + + public isRunning(): boolean { + return this._isRunning && MOCK_SESSION !== null && mockTelemetry !== null; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public waitForData(_timeout?: number): boolean { + return this._isRunning; + } + + public getSessionData(): string { + return MOCK_SESSION ?? ''; + } + + public getTelemetryData(): TelemetryVarList { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return mockTelemetry!; + } + + public getTelemetryVariable(index: number): TelemetryVariable; + + // eslint-disable-next-line @typescript-eslint/unified-signatures + public getTelemetryVariable(name: keyof TelemetryVarList): TelemetryVariable; + + // Really need to fix the types here. + public getTelemetryVariable(name: keyof TelemetryVarList | number): TelemetryVariable { + if (typeof name === 'number') { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return Object.values(mockTelemetry!)[name] as TelemetryVariable; + } + return mockTelemetry?.[name] as TelemetryVariable; + } + + public broadcast(message: BroadcastMessages.CameraSwitchPos, pos: number, group: number, camera: number): void; + + // eslint-disable-next-line @typescript-eslint/unified-signatures + public broadcast(message: BroadcastMessages.CameraSwitchNum, driver: number, group: number, camera: number): void; + + public broadcast(message: BroadcastMessages.CameraSetState, state: CameraState): void; + + public broadcast(message: BroadcastMessages.ReplaySetPlaySpeed, speed: number, slowMotion: number): void; + + public broadcast(message: BroadcastMessages.ReplaySetPlayPosition, pos: ReplayPositionCommand, frame: number): void; + + public broadcast(message: BroadcastMessages.ReplaySearch, mode: ReplaySearchCommand): void; + + public broadcast(message: BroadcastMessages.ReplaySetState, state: ReplayStateCommand): void; + + public broadcast(message: BroadcastMessages.ReloadTextures, command: ReloadTexturesCommand, carIndex?: number): void; + + public broadcast(message: BroadcastMessages.ChatCommand, command: ChatCommand, macro?: number): void; + + public broadcast(message: BroadcastMessages.PitCommand, command: PitCommand, param?: number): void; + + public broadcast(message: BroadcastMessages.TelemCommand, command: TelemetryCommand): void; + + public broadcast(message: BroadcastMessages.FFBCommand, command: FFBCommand, value: number): void; + + // eslint-disable-next-line @typescript-eslint/unified-signatures + public broadcast(message: BroadcastMessages.ReplaySearchSessionTime, session: number, time: number): void; + + public broadcast(message: BroadcastMessages.VideoCapture, command: VideoCaptureCommand): void; + + public broadcast(...args: number[]): void { + console.log('Pretending to trigger SDK call:', ...args); + } +} diff --git a/src/app/irsdk/node/utils/sim-status.ts b/src/app/irsdk/node/utils/sim-status.ts new file mode 100644 index 0000000..dc7e6cf --- /dev/null +++ b/src/app/irsdk/node/utils/sim-status.ts @@ -0,0 +1,36 @@ +import http from 'http'; + +import { SIM_STATUS_URI } from '../constants'; +import { platform } from 'os'; + +/** + * Makes an http localhost request to check whether or not the iRacing sim is running. + * If the iRacing service is not running, it will throw with `err.code === ECONNREFUSED`. + * + * @returns {Promise} Whether the sim is running or not. + * @throws {Error} A generic NodeJS.ErrnoException / Error if something goes wrong. + */ +export const getSimStatus = (): Promise => new Promise((resolve, reject) => { + if (platform() !== 'win32') { + resolve(true); + return; + } + + http.get(SIM_STATUS_URI, (res) => { + let data = ''; + + res.on('data', (d) => { + data += d; + }); + + res.on('end', () => { + if (typeof data !== 'string') { + reject(new Error('Invalid payload from sim received')); + } + // This could be done more elegantly, but there is no need really :D + resolve(data.includes('running:1')); + }); + }).on('error', (err: NodeJS.ErrnoException) => { + reject(err); + }); +}); diff --git a/src/app/irsdk/types/_GENERATED_telemetry.ts b/src/app/irsdk/types/_GENERATED_telemetry.ts new file mode 100644 index 0000000..8ed44ad --- /dev/null +++ b/src/app/irsdk/types/_GENERATED_telemetry.ts @@ -0,0 +1,316 @@ +// ! THIS FILE IS AUTO-GENERATED, EDITS WILL BE OVERRIDDEN ! +// ! Make changes to the `generate-var-types` in `@irsk-node/native` ! + +/** + * A variable included in the telemetry. + */ +export interface TelemetryVariable { + /** The name of the variable. */ + name: string; + /** The description. */ + description: string; + /** The unit of the value (ex. "kg/m^2") */ + unit: string; + /** Should it be treated as a time? */ + countAsTime: boolean; + /** The number of values provided. */ + length: number; + /** The native variable type */ + varType: number; + /** The current value of this variable. */ + value: VarType; +} + +export interface TelemetryVarList { + SessionTime: TelemetryVariable; + SessionTick: TelemetryVariable; + SessionNum: TelemetryVariable; + SessionState: TelemetryVariable; + SessionUniqueID: TelemetryVariable; + SessionFlags: TelemetryVariable; + SessionTimeRemain: TelemetryVariable; + SessionLapsRemain: TelemetryVariable; + SessionLapsRemainEx: TelemetryVariable; + SessionTimeTotal: TelemetryVariable; + SessionLapsTotal: TelemetryVariable; + SessionJokerLapsRemain: TelemetryVariable; + SessionOnJokerLap: TelemetryVariable; + SessionTimeOfDay: TelemetryVariable; + RadioTransmitCarIdx: TelemetryVariable; + RadioTransmitRadioIdx: TelemetryVariable; + RadioTransmitFrequencyIdx: TelemetryVariable; + DisplayUnits: TelemetryVariable; + DriverMarker: TelemetryVariable; + PushToPass: TelemetryVariable; + ManualBoost: TelemetryVariable; + ManualNoBoost: TelemetryVariable; + IsOnTrack: TelemetryVariable; + IsReplayPlaying: TelemetryVariable; + ReplayFrameNum: TelemetryVariable; + ReplayFrameNumEnd: TelemetryVariable; + IsDiskLoggingEnabled: TelemetryVariable; + IsDiskLoggingActive: TelemetryVariable; + FrameRate: TelemetryVariable; + CpuUsageFG: TelemetryVariable; + GpuUsage: TelemetryVariable; + ChanAvgLatency: TelemetryVariable; + ChanLatency: TelemetryVariable; + ChanQuality: TelemetryVariable; + ChanPartnerQuality: TelemetryVariable; + CpuUsageBG: TelemetryVariable; + ChanClockSkew: TelemetryVariable; + MemPageFaultSec: TelemetryVariable; + PlayerCarPosition: TelemetryVariable; + PlayerCarClassPosition: TelemetryVariable; + PlayerCarClass: TelemetryVariable; + PlayerTrackSurface: TelemetryVariable; + PlayerTrackSurfaceMaterial: TelemetryVariable; + PlayerCarIdx: TelemetryVariable; + PlayerCarTeamIncidentCount: TelemetryVariable; + PlayerCarMyIncidentCount: TelemetryVariable; + PlayerCarDriverIncidentCount: TelemetryVariable; + PlayerCarWeightPenalty: TelemetryVariable; + PlayerCarPowerAdjust: TelemetryVariable; + PlayerCarDryTireSetLimit: TelemetryVariable; + PlayerCarTowTime: TelemetryVariable; + PlayerCarInPitStall: TelemetryVariable; + PlayerCarPitSvStatus: TelemetryVariable; + PlayerTireCompound: TelemetryVariable; + PlayerFastRepairsUsed: TelemetryVariable; + CarIdxLap: TelemetryVariable; + CarIdxLapCompleted: TelemetryVariable; + CarIdxLapDistPct: TelemetryVariable; + CarIdxTrackSurface: TelemetryVariable; + CarIdxTrackSurfaceMaterial: TelemetryVariable; + CarIdxOnPitRoad: TelemetryVariable; + CarIdxPosition: TelemetryVariable; + CarIdxClassPosition: TelemetryVariable; + CarIdxClass: TelemetryVariable; + CarIdxF2Time: TelemetryVariable; + CarIdxEstTime: TelemetryVariable; + CarIdxLastLapTime: TelemetryVariable; + CarIdxBestLapTime: TelemetryVariable; + CarIdxBestLapNum: TelemetryVariable; + CarIdxTireCompound: TelemetryVariable; + CarIdxQualTireCompound: TelemetryVariable; + CarIdxQualTireCompoundLocked: TelemetryVariable; + CarIdxFastRepairsUsed: TelemetryVariable; + PaceMode: TelemetryVariable; + CarIdxPaceLine: TelemetryVariable; + CarIdxPaceRow: TelemetryVariable; + CarIdxPaceFlags: TelemetryVariable; + OnPitRoad: TelemetryVariable; + CarIdxSteer: TelemetryVariable; + CarIdxRPM: TelemetryVariable; + CarIdxGear: TelemetryVariable; + SteeringWheelAngle: TelemetryVariable; + Throttle: TelemetryVariable; + Brake: TelemetryVariable; + Clutch: TelemetryVariable; + Gear: TelemetryVariable; + RPM: TelemetryVariable; + Lap: TelemetryVariable; + LapCompleted: TelemetryVariable; + LapDist: TelemetryVariable; + LapDistPct: TelemetryVariable; + RaceLaps: TelemetryVariable; + LapBestLap: TelemetryVariable; + LapBestLapTime: TelemetryVariable; + LapLastLapTime: TelemetryVariable; + LapCurrentLapTime: TelemetryVariable; + LapLasNLapSeq: TelemetryVariable; + LapLastNLapTime: TelemetryVariable; + LapBestNLapLap: TelemetryVariable; + LapBestNLapTime: TelemetryVariable; + LapDeltaToBestLap: TelemetryVariable; + LapDeltaToBestLap_DD: TelemetryVariable; + LapDeltaToBestLap_OK: TelemetryVariable; + LapDeltaToOptimalLap: TelemetryVariable; + LapDeltaToOptimalLap_DD: TelemetryVariable; + LapDeltaToOptimalLap_OK: TelemetryVariable; + LapDeltaToSessionBestLap: TelemetryVariable; + LapDeltaToSessionBestLap_DD: TelemetryVariable; + LapDeltaToSessionBestLap_OK: TelemetryVariable; + LapDeltaToSessionOptimalLap: TelemetryVariable; + LapDeltaToSessionOptimalLap_DD: TelemetryVariable; + LapDeltaToSessionOptimalLap_OK: TelemetryVariable; + LapDeltaToSessionLastlLap: TelemetryVariable; + LapDeltaToSessionLastlLap_DD: TelemetryVariable; + LapDeltaToSessionLastlLap_OK: TelemetryVariable; + Speed: TelemetryVariable; + Yaw: TelemetryVariable; + YawNorth: TelemetryVariable; + Pitch: TelemetryVariable; + Roll: TelemetryVariable; + EnterExitReset: TelemetryVariable; + TrackTemp: TelemetryVariable; + TrackTempCrew: TelemetryVariable; + AirTemp: TelemetryVariable; + WeatherType: TelemetryVariable; + Skies: TelemetryVariable; + AirDensity: TelemetryVariable; + AirPressure: TelemetryVariable; + WindVel: TelemetryVariable; + WindDir: TelemetryVariable; + RelativeHumidity: TelemetryVariable; + FogLevel: TelemetryVariable; + DCLapStatus: TelemetryVariable; + DCDriversSoFar: TelemetryVariable; + OkToReloadTextures: TelemetryVariable; + LoadNumTextures: TelemetryVariable; + CarLeftRight: TelemetryVariable; + PitsOpen: TelemetryVariable; + VidCapEnabled: TelemetryVariable; + VidCapActive: TelemetryVariable; + PitRepairLeft: TelemetryVariable; + PitOptRepairLeft: TelemetryVariable; + PitstopActive: TelemetryVariable; + FastRepairUsed: TelemetryVariable; + FastRepairAvailable: TelemetryVariable; + LFTiresUsed: TelemetryVariable; + RFTiresUsed: TelemetryVariable; + LRTiresUsed: TelemetryVariable; + RRTiresUsed: TelemetryVariable; + LeftTireSetsUsed: TelemetryVariable; + RightTireSetsUsed: TelemetryVariable; + FrontTireSetsUsed: TelemetryVariable; + RearTireSetsUsed: TelemetryVariable; + TireSetsUsed: TelemetryVariable; + LFTiresAvailable: TelemetryVariable; + RFTiresAvailable: TelemetryVariable; + LRTiresAvailable: TelemetryVariable; + RRTiresAvailable: TelemetryVariable; + LeftTireSetsAvailable: TelemetryVariable; + RightTireSetsAvailable: TelemetryVariable; + FrontTireSetsAvailable: TelemetryVariable; + RearTireSetsAvailable: TelemetryVariable; + TireSetsAvailable: TelemetryVariable; + CamCarIdx: TelemetryVariable; + CamCameraNumber: TelemetryVariable; + CamGroupNumber: TelemetryVariable; + CamCameraState: TelemetryVariable; + IsOnTrackCar: TelemetryVariable; + IsInGarage: TelemetryVariable; + SteeringWheelPctTorque: TelemetryVariable; + SteeringWheelPctTorqueSign: TelemetryVariable; + SteeringWheelPctTorqueSignStops: TelemetryVariable; + SteeringWheelPctDamper: TelemetryVariable; + SteeringWheelAngleMax: TelemetryVariable; + SteeringWheelLimiter: TelemetryVariable; + ShiftIndicatorPct: TelemetryVariable; + ShiftPowerPct: TelemetryVariable; + ShiftGrindRPM: TelemetryVariable; + ThrottleRaw: TelemetryVariable; + BrakeRaw: TelemetryVariable; + HandbrakeRaw: TelemetryVariable; + SteeringWheelPeakForceNm: TelemetryVariable; + SteeringWheelMaxForceNm: TelemetryVariable; + SteeringWheelUseLinear: TelemetryVariable; + BrakeABSactive: TelemetryVariable; + EngineWarnings: TelemetryVariable; + FuelLevel: TelemetryVariable; + FuelLevelPct: TelemetryVariable; + PitSvFlags: TelemetryVariable; + PitSvLFP: TelemetryVariable; + PitSvRFP: TelemetryVariable; + PitSvLRP: TelemetryVariable; + PitSvRRP: TelemetryVariable; + PitSvFuel: TelemetryVariable; + PitSvTireCompound: TelemetryVariable; + CarIdxP2P_Status: TelemetryVariable; + CarIdxP2P_Count: TelemetryVariable; + ReplayPlaySpeed: TelemetryVariable; + ReplayPlaySlowMotion: TelemetryVariable; + ReplaySessionTime: TelemetryVariable; + ReplaySessionNum: TelemetryVariable; + TireLF_RumblePitch: TelemetryVariable; + TireRF_RumblePitch: TelemetryVariable; + TireLR_RumblePitch: TelemetryVariable; + TireRR_RumblePitch: TelemetryVariable; + SteeringWheelTorque_ST: TelemetryVariable; + SteeringWheelTorque: TelemetryVariable; + VelocityZ_ST: TelemetryVariable; + VelocityY_ST: TelemetryVariable; + VelocityX_ST: TelemetryVariable; + VelocityZ: TelemetryVariable; + VelocityY: TelemetryVariable; + VelocityX: TelemetryVariable; + YawRate_ST: TelemetryVariable; + PitchRate_ST: TelemetryVariable; + RollRate_ST: TelemetryVariable; + YawRate: TelemetryVariable; + PitchRate: TelemetryVariable; + RollRate: TelemetryVariable; + VertAccel_ST: TelemetryVariable; + LatAccel_ST: TelemetryVariable; + LongAccel_ST: TelemetryVariable; + VertAccel: TelemetryVariable; + LatAccel: TelemetryVariable; + LongAccel: TelemetryVariable; + dcStarter: TelemetryVariable; + dpRFTireChange: TelemetryVariable; + dpLFTireChange: TelemetryVariable; + dpRRTireChange: TelemetryVariable; + dpLRTireChange: TelemetryVariable; + dcTearOffVisor: TelemetryVariable; + dpFuelFill: TelemetryVariable; + dpFuelAddKg: TelemetryVariable; + dpFastRepair: TelemetryVariable; + dpLFTireColdPress: TelemetryVariable; + dpRFTireColdPress: TelemetryVariable; + dpLRTireColdPress: TelemetryVariable; + dpRRTireColdPress: TelemetryVariable; + WaterTemp: TelemetryVariable; + WaterLevel: TelemetryVariable; + FuelPress: TelemetryVariable; + FuelUsePerHour: TelemetryVariable; + OilTemp: TelemetryVariable; + OilPress: TelemetryVariable; + OilLevel: TelemetryVariable; + Voltage: TelemetryVariable; + ManifoldPress: TelemetryVariable; + RRcoldPressure: TelemetryVariable; + RRtempCL: TelemetryVariable; + RRtempCM: TelemetryVariable; + RRtempCR: TelemetryVariable; + RRwearL: TelemetryVariable; + RRwearM: TelemetryVariable; + RRwearR: TelemetryVariable; + LRcoldPressure: TelemetryVariable; + LRtempCL: TelemetryVariable; + LRtempCM: TelemetryVariable; + LRtempCR: TelemetryVariable; + LRwearL: TelemetryVariable; + LRwearM: TelemetryVariable; + LRwearR: TelemetryVariable; + RFcoldPressure: TelemetryVariable; + RFtempCL: TelemetryVariable; + RFtempCM: TelemetryVariable; + RFtempCR: TelemetryVariable; + RFwearL: TelemetryVariable; + RFwearM: TelemetryVariable; + RFwearR: TelemetryVariable; + LFcoldPressure: TelemetryVariable; + LFtempCL: TelemetryVariable; + LFtempCM: TelemetryVariable; + LFtempCR: TelemetryVariable; + LFwearL: TelemetryVariable; + LFwearM: TelemetryVariable; + LFwearR: TelemetryVariable; + RRshockDefl: TelemetryVariable; + RRshockDefl_ST: TelemetryVariable; + RRshockVel: TelemetryVariable; + RRshockVel_ST: TelemetryVariable; + LRshockDefl: TelemetryVariable; + LRshockDefl_ST: TelemetryVariable; + LRshockVel: TelemetryVariable; + LRshockVel_ST: TelemetryVariable; + RFshockDefl: TelemetryVariable; + RFshockDefl_ST: TelemetryVariable; + RFshockVel: TelemetryVariable; + RFshockVel_ST: TelemetryVariable; + LFshockDefl: TelemetryVariable; + LFshockDefl_ST: TelemetryVariable; + LFshockVel: TelemetryVariable; + LFshockVel_ST: TelemetryVariable; +} diff --git a/src/app/irsdk/types/camera-info.ts b/src/app/irsdk/types/camera-info.ts new file mode 100644 index 0000000..89d77bc --- /dev/null +++ b/src/app/irsdk/types/camera-info.ts @@ -0,0 +1,15 @@ +export interface Camera { + CameraNum: number; + CameraName: string; +} + +export interface CameraGroup { + GroupNum: number; + GroupName: string; + IsScenic?: boolean; + Cameras: Camera[]; +} + +export interface CameraInfo { + Groups: CameraGroup[]; +} diff --git a/src/app/irsdk/types/driver-info.ts b/src/app/irsdk/types/driver-info.ts new file mode 100644 index 0000000..843037c --- /dev/null +++ b/src/app/irsdk/types/driver-info.ts @@ -0,0 +1,72 @@ +export interface Driver { + CarIdx: number; + UserName: string; + AbbrevName: string | null; + Initials: string | null; + UserID: number; + TeamID: number; + TeamName: string; + CarNumber: string; + CarNumberRaw: number; + CarPath: string; + CarClassID: number; + CarID: number; + CarIsPaceCar: number; // bool? + CarIsAI: number; // bool? + CarScreenName: string; + CarScreenNameShort: string; + CarClassShortName: string; + CarClassRelSpeed: number; + CarClassLicenseLevel: number; + CarClassMaxFuelPct: string; + CarClassWeightPenalty: string; + CarClassPowerAdjust: string; + CarClassDryTireSetLimit: string; + CarClassColor: number; + CarClassEstLapTime: number; + IRating: number; + LicLevel: number; + LicSubLevel: number; + LicString: string; + LicColor: number; + IsSpectator: number; + CarDesignStr: string; + HelmetDesignStr: string; + SuitDesignStr: string; + CarNumberDesignStr: string; + CarSponsor_1: number; + CarSponsor_2: number; + CurDriverIncidentCount: number; + TeamIncidentCount: number; +} + +export interface DriverInfo { + DriverCarIdx: number; + DriverUserID: number; + PaceCarIdx: number; + DriverHeadPosX: number; + DriverHeadPosY: number; + DriverHeadPosZ: number; + DriverCarIdleRPM: number; + DriverCarRedLine: number; + DriverCarEngCylinderCount: number; + DriverCarFuelKgPerLtr: number; + DriverCarFuelMaxLtr: number; + DriverCarMaxFuelPct: number; + DriverCarGearNumForward: number; + DriverCarGearNeutral: number; + DriverCarGearReverse: number; + DriverCarSLFirstRPM: number; + DriverCarSLShiftRPM: number; + DriverCarSLLastRPM: number; + DriverCarSLBlinkRPM: number; + DriverCarVersion: string; + DriverPitTrkPct: number; + DriverCarEstLapTime: number; + DriverSetupName: string; + DriverSetupIsModified: number; + DriverSetupLoadTypeName: string; + DriverSetupPassedTech: number; + DriverIncidentCount: number; + Drivers: Driver[]; +} diff --git a/src/app/irsdk/types/enums.ts b/src/app/irsdk/types/enums.ts new file mode 100644 index 0000000..273e4da --- /dev/null +++ b/src/app/irsdk/types/enums.ts @@ -0,0 +1,303 @@ +export enum SessionState { + Invalid = 0, + GetInCar, + Warmup, + ParadeLaps, + Racing, + Checkered, + CoolDown, +} + +export enum GlobalFlags { + // Global + Checkered = 0x00000001, + White = 0x00000002, + Green = 0x00000004, + Yellow = 0x00000008, + Red = 0x00000010, + Blue = 0x00000020, + Debris = 0x00000040, + Crossed = 0x00000080, + YellowWaving = 0x00000100, + OneLapToGreen = 0x00000200, + GreenHeld = 0x00000400, + TenToGo = 0x00000800, + FiveToGo = 0x00001000, + RandomWaving = 0x00002000, + Caution = 0x00004000, + CautionWaving = 0x00008000, + + // Drivers black flags + Black = 0x00010000, + Disqualify = 0x00020000, + Servicible = 0x00040000, + Furled = 0x00080000, + Repair = 0x00100000, + + // Start lights + StartHidden = 0x10000000, + StartReady = 0x20000000, + StartSet = 0x40000000, + StartGo = 0x80000000, +} + +export enum PitSvFlags { + LFTireChange = 0x0001, + RFTireChange = 0x0002, + LRTireChange = 0x0004, + RRTireChange = 0x0008, + // Non-tires + FuelFill = 0x0010, + WindshieldTearoff = 0x0020, + FastRepair = 0x0040, +} + +export enum PitSvStatus { + // Status + None = 0, + InProgress, + Complete, + + // Errors + TooFarLeft = 100, + TooFarRight, + TooFarForward, + TooFarBack, + BadAngle, + CantFixThat, +} + +export enum PaceMode { + SingleFileStart = 0, + DoubleFileStart, + SingleFileRestart, + DoubleFileRestart, + NotPacing, +} + +export enum PaceFlags { + EndOfLine = 0x01, + FreePass = 0x02, + WavedAround = 0x04, +} + +export enum CarLeftRight { + Off, + /** No cars around us */ + Clear, + /** Car to our left */ + CarLeft, + /** Car to our right */ + CarRight, + /** Cars on both sides */ + CarLeftRight, + /** 2 cars to our left */ + Cars2Left, + /** 2 cars to our right */ + Cars2Right, +} + +export enum TrackLocation { + NotInWorld = -1, + OffTrack, + InPitStall, + ApproachingPits, + OnTrack, +} + +// Enums +export interface VarTypes { + 0: string; + 1: boolean; + 2: number; + 3: number; + 4: number; + 5: number; +} + +export enum BroadcastMessages { + /** Switch the camera position. */ + CameraSwitchPos = 0, + /** Switch the driver number to follow. */ + CameraSwitchNum, + /** Change the camera state. */ + CameraSetState, + /** Change the play speed of a replay. */ + ReplaySetPlaySpeed, + /** Jump to a different part of the replay. */ + ReplaySetPlayPosition, + /** Enter replay search mode. */ + ReplaySearch, + /** Change the replay state. */ + ReplaySetState, + /** Trigger a texture reload. */ + ReloadTextures, + /** Broadcast a chat command. */ + ChatCommand, + /** Broadcast a pit command. */ + PitCommand, + /** Broadcast a telemetry command. */ + TelemCommand, + /** Broadcast a force feedback command. */ + FFBCommand, + /** Trigger searching to a replay time. */ + ReplaySearchSessionTime, + /** Trigger video capture. */ + VideoCapture, + /** Unused. */ + Last +} + +export enum CameraState { + /** the camera tool can only be activated if viewing the session screen (out of car) */ + irsdk_IsSessionScreen = 0x0001, + /** the scenic camera is active (no focus car) */ + irsdk_IsScenicActive = 0x0002, + /** CAN be changed with a broadcast message */ + irsdk_CamToolActive = 0x0004, + /** CAN be changed with a broadcast message */ + irsdk_UIHidden = 0x0008, + /** CAN be changed with a broadcast message */ + irsdk_UseAutoShotSelection = 0x0010, + /** CAN be changed with a broadcast message */ + irsdk_UseTemporaryEdits = 0x0020, + /** CAN be changed with a broadcast message */ + irsdk_UseKeyAcceleration = 0x0040, + /** CAN be changed with a broadcast message */ + irsdk_UseKey10xAcceleration = 0x0080, + /** CAN be changed with a broadcast message */ + irsdk_UseMouseAimMode = 0x0100, +} + +export enum ChatCommand { + /** Number from 1-15, representing the chat macros. */ + Macro = 0, + /** Open up new chat window. */ + BeginChat, + /** Reply to last private chat. */ + Reply, + /** Close chat. */ + Cancel, +} + +/** Only works when the driver is in the car! */ +export enum PitCommand { + /** Clear all pit checkboxes */ + Clear = 0, + /** Clean the winshield, using one tear off */ + WS, + /** Add fuel, optionally specify the amount to add in liters or pass '0' to use existing amount */ + Fuel, + /** Change the left front tire, optionally specifying the pressure in KPa or pass '0' to use existing pressure */ + LF, + /** right front */ + RF, + /** left rear */ + LR, + /** right rear */ + RR, + /** Clear tire pit checkboxes */ + ClearTires, + /** Request a fast repair */ + FR, + /** Uncheck Clean the windshield checkbox */ + ClearWS, + /** Uncheck request a fast repair */ + ClearFR, + /** Uncheck add fuel */ + ClearFuel, +} + +export enum TelemetryCommand { + /** Turn telemetry recording off */ + Stop = 0, + /** Turn telemetry recording on */ + Start, + /** Write current file to disk and start a new one */ + Restart, +} + +export enum ReplayStateCommand { + /** clear any data in the replay tape */ + EraseTape = 0, + /** unused place holder */ + Last, +} + +export enum ReloadTexturesCommand { + /** reload all textures */ + All = 0, + /** reload only textures for the specific car index */ + CarIndex, +} + +export enum ReplaySearchCommand { + /** Start of session */ + ToStart = 0, + /** End of session */ + ToEnd, + /** Previous session */ + PrevSession, + /** Next session */ + NextSession, + /** Previous lap */ + PrevLap, + /** Next lap */ + NextLap, + /** Previous frame */ + PrevFrame, + /** Next frame */ + NextFrame, + /** Previous incident */ + PrevIncident, + /** Next incident */ + NextIncident, + /** Unused */ + Last, +} + +export enum ReplayPositionCommand { + /** Beginning of the replay */ + Begin = 0, + /** Current position in the replay */ + Current, + /** End of the replay */ + End, + /** Unused */ + Last, +} + +export enum FFBCommand { + /** Set the maximum force when mapping steering torque force to direct input units (float in Nm) */ + MaxForce = 0, + /** Unused */ + Last, +} + +/** + * Used with BroadcastMessages.CameraSwitchPos and BroadcastMessages.CameraSwitchNum. + * Pass these in for the first parameter to select the 'focus at' types in the camera system. + * @todo: Not sure this will work with TS like it does in C++ :D + */ +export enum CameraFocusCommand { + FocusAtIncident = -3, + FocusAtLeader = -2, + FocusAtExiting = -1, + /** FocusAtDriver + car number... */ + FocusAtDriver = 0, +} + +export enum VideoCaptureCommand { + /** save a screenshot to disk */ + TriggerScreenShot = 0, + /** start capturing video */ + StartVideoCapture, + /** stop capturing video */ + EndVideoCapture, + /** toggle video capture on/off */ + ToggleVideoCapture, + /** show video timer in upper left corner of display */ + ShowVideoTimer, + /** hide video timer */ + HideVideoTimer, +} diff --git a/src/app/irsdk/types/index.ts b/src/app/irsdk/types/index.ts new file mode 100644 index 0000000..d398086 --- /dev/null +++ b/src/app/irsdk/types/index.ts @@ -0,0 +1,10 @@ +export * from './enums'; +export * from './camera-info'; +export * from './driver-info'; +export * from './radio-info'; +export * from './session-info'; +export * from './setup-info'; +export * from './split-info'; +export * from './weekend-info'; +export * from './session-yaml'; +export * from './_GENERATED_telemetry'; diff --git a/src/app/irsdk/types/radio-info.ts b/src/app/irsdk/types/radio-info.ts new file mode 100644 index 0000000..3a583d6 --- /dev/null +++ b/src/app/irsdk/types/radio-info.ts @@ -0,0 +1,27 @@ +export interface RadioFrequency { + FrequencyNum: number; + FrequencyName: string; + Priority: number; + CarIdx: number; + EntryIdx: number; + ClubID: number; + CanScan: number; // bool? + CanSquawk: number; // bool? + Muted: number; // bool? + IsMutable: number; // bool? + IsDeletable: number; // bool? +} + +export interface Radio { + RadioNum: number; + HopCount: number; + NumFrequencies: number; + TunedToFrequencyNum: number; + ScanningIsOn: number; // bool? + Frequencies: RadioFrequency[]; +} + +export interface RadioInfo { + SelectedRadioNum: number; + Radios: Radio[]; +} diff --git a/src/app/irsdk/types/session-info.ts b/src/app/irsdk/types/session-info.ts new file mode 100644 index 0000000..eef6d98 --- /dev/null +++ b/src/app/irsdk/types/session-info.ts @@ -0,0 +1,48 @@ +export interface SessionResultsPosition { + Position: number; + ClassPosition: number; + CarIdx: number; + Lap: number; + Time: number; + FastestLap: number; + FastestTime: number; + LastTime: number; + LapsLed: number; + LapsComplete: number; + JokerLapsComplete: number; + LapsDriven: number; + Incidents: number; + ReasonOutId: number; + ReasonOutStr: string; +} + +export interface SessionResultsFastestLap { + CarIdx: number; + FastestLap: number; + FastestTime: number; +} + +export interface SessionInfo { + SessionNum: number; + SessionLaps: string; + SessionTime: string; + SessionNumLapsToAvg: number; + SessionType: string; + SessionTrackRubberState: string; + SessionName: string; + SessionSubType: string | null; + SessionSkipped: number; + SessionRunGroupsUsed: number; + ResultsPositions: SessionResultsPosition[]; + ResultsFastestLap: SessionResultsFastestLap[]; + ResultsAverageLapTime: number; + ResultsNumCautionFlags: number; + ResultsNumCautionLaps: number; + ResultsNumLeadChanges: number; + ResultsLapsComplete: number; + ResultsOfficial: number; // bool? +} + +export interface SessionList { + Sessions: SessionInfo[]; +} diff --git a/src/app/irsdk/types/session-yaml.ts b/src/app/irsdk/types/session-yaml.ts new file mode 100644 index 0000000..90b36c8 --- /dev/null +++ b/src/app/irsdk/types/session-yaml.ts @@ -0,0 +1,22 @@ +import { RadioInfo } from './radio-info'; +import { CameraInfo } from './camera-info'; +import { SessionList } from './session-info'; +import { WeekendInfo } from './weekend-info'; +import { DriverInfo } from './driver-info'; +import { SplitTimeInfo } from './split-info'; +import { CarSetupInfo } from './setup-info'; + +/** + * Information about the current session, stored as yaml. + * Does not update as much as telemetry. + * @todo the CarSetup types are incomplete. Help wanted! + */ +export interface SessionData { + WeekendInfo: WeekendInfo; + SessionInfo: SessionList; + CameraInfo: CameraInfo; + RadioInfo: RadioInfo; + DriverInfo: DriverInfo; + SplitTimeInfo: SplitTimeInfo; + CarSetup: CarSetupInfo; +} diff --git a/src/app/irsdk/types/setup-info.ts b/src/app/irsdk/types/setup-info.ts new file mode 100644 index 0000000..eaad59b --- /dev/null +++ b/src/app/irsdk/types/setup-info.ts @@ -0,0 +1,113 @@ +export interface TireInfo { + StartingPressure: string; + LastHotPressure: string; + LastTempsOMI: string; + TreadRemaining: string; +} + +export interface TireCompoundInfo { + TireCompound: string; +} + +// Is this for everything, or just for the W12? +export interface AeroPackageInfo { + DownforceTrim: string; + FrontFlapOffset: string; + RearWingGurney: string; +} + +export interface AeroCalculatorInfo { + FrontRhAtSpeed: string; + RearRhAtSpeed: string; + AeroBalance: string; + DownforceToDrag: string; +} + +export interface TiresAeroInfo { + TireCompound: TireCompoundInfo; + LeftFrontTire: TireInfo; + LeftRearTire: TireInfo; + RightFrontTire: TireInfo; + RightRearTire: TireInfo; + AeroPackage: AeroPackageInfo; + AeroCalculator: AeroCalculatorInfo; +} + +export interface ChassisCornerInfo { + CornerWeight: string; + Camber: string; + ToeIn?: string; + ColdPressure?: string; + LastHotPressure?: string; + LastTempsOMI?: string; + TreadRemaining?: string; + RideHeight?: string; + SpringPerchOffset?: string; + BumpStiffness?: string; + ReboundStiffness?: string; +} + +export interface ChassisFrontInfo { + ToeIn?: string; + CrossWeight?: string; + AntiRollBar?: string; + // W12 stuff + TransparentHalo?: number; // bool + WeightDist?: string; + HeaveRate?: string; + RollRate?: string; + RideHeight?: string; +} + +export interface ChassisRearInfo { + FuelLevel: string; + ToeIn?: string; + AntiRollBar: string; + // W12 stuff + HeaveRate?: string; + RollRate?: string; + RideHeight?: string; +} + +export interface ChassisInfo { + Front: ChassisFrontInfo, + LeftFront: ChassisCornerInfo; + LeftRear: ChassisCornerInfo; + RightFront: ChassisCornerInfo; + RightRear: ChassisCornerInfo; + Rear: ChassisRearInfo; +} + +export interface DifferentialInfo { + Preload: string; + Entry: string; + Middle: string; + HighSpeed: string; +} + +export interface PowerUnitConfig { + MguKDeployMode: string; + EngineBraking: string; +} + +export interface BrakeSystemConfig { + BaseBrakeBias: string; + DynamicRamping: string; + BrakeMigration: string; + TotalBrakeBias: string; + BrakeMagicModifier: number; +} + +export interface DriveBrakeInfo { + Differential: DifferentialInfo; + PowerUnitConfig: PowerUnitConfig; + BrakeSystemConfig: BrakeSystemConfig; +} + +export interface CarSetupInfo { + UpdateCount: number; + Suspension?: ChassisInfo; + TiresAero?: TiresAeroInfo; + Chassis?: ChassisInfo; + DriveBrake?: DriveBrakeInfo; +} diff --git a/src/app/irsdk/types/split-info.ts b/src/app/irsdk/types/split-info.ts new file mode 100644 index 0000000..e59acf7 --- /dev/null +++ b/src/app/irsdk/types/split-info.ts @@ -0,0 +1,9 @@ +export interface Sector { + SectorNum: number; + /** 0 - 1 range; 50% is 0.5 */ + SectorStartPct: number; +} + +export interface SplitTimeInfo { + Sectors: Sector[]; +} diff --git a/src/app/irsdk/types/weekend-info.ts b/src/app/irsdk/types/weekend-info.ts new file mode 100644 index 0000000..f5298eb --- /dev/null +++ b/src/app/irsdk/types/weekend-info.ts @@ -0,0 +1,90 @@ +// @todo: This should be auto generated XD + +export interface WeekendOptions { + NumStarters: number; + StartingGrid: string; + QualifyScoring: string; + CourseCautions: string; + StandingStart: number; // maybe bool? + ShortParadeLap: number; // maybe bool? + Restarts: string; + WeatherType: string; // is there an enum for this? + Skies: string; // is there an enum for this? + WindDirection: string; // is there an enum for this? + WindSpeed: string; + WeatherTemp: string; + RelativeHumidity: string; + FogLevel: string; + TimeOfDay: string; + Date: string; + EarthRotationSpeedupFactor: number; + Unofficial: number; // bool? + CommercialMode: string; // is there an enum for this? + NightMode: string; + IsFixedSetup: number; // bool? + StrictLapsChecking: string; + HasOpenRegistration: number; // bool? + HardcoreLevel: number; + NumJokerLaps: number; + IncidentLimit: string; + FastRepairsLimit: number; + GreenWhiteCheckeredLimit: number; +} + +export interface TelemetryOptions { + TelemetryDiskFile: string; +} + +export interface WeekendInfo { + TrackName: string; + TrackID: number; + TrackLength: string; + TrackDisplayName: string; + TrackDisplayShortName: string; + TrackConfigName: string | null; + TrackCity: string; + TrackCountry: string; + TrackAltitude: string; + TrackLatitude: string; + TrackLongitude: string; + TrackNorthOffset: string; + TrackNumTurns: number; + TrackPitSpeedLimit: string; + TrackType: string; + TrackDirection: string; + TrackWeatherType: string; + TrackSkies: string; + TrackSurfaceTemp: string; + TrackAirTemp: string; + TrackAirPressure: string; + TrackWindVel: string; + TrackWindDir: string; + TrackRelativeHumidity: string; + TrackFogLevel: string; + TrackCleanup: number; + TrackDynamicTrack: number; + TrackVersion: string; + SeriesID: number; + SeasonID: number; + SessionID: number; + SubSessionID: number; + LeagueID: number; + Official: number; // bool? + RaceWeek: number; + EventType: string; // enum? + Category: string; // enum? + SimMode: string; + TeamRacing: number; + MinDrivers: number; + MaxDrivers: number; + DCRuleSet: string; + QualifierMustStartRace: number; // bool? + NumCarClasses: number; + NumCarTypes: number; + HeatRacing: number; + BuildType: string; + BuildTarget: string; + BuildVersion: string; + WeekendOptions: WeekendOptions; + TelemetryOptions: TelemetryOptions; +} diff --git a/src/types/session.ts b/src/types/session.ts index 4371ca5..1afd2ce 100644 --- a/src/types/session.ts +++ b/src/types/session.ts @@ -3,7 +3,7 @@ import type { SessionResultsPosition, SessionInfo as SdkSessionInfo, Driver as SdkDriver, -} from '@irsdk-node/types'; +} from '../app/irsdk/types'; export type Session = SessionData & { QualifyResultsInfo?: { Results: SessionResultsPosition[] }; diff --git a/src/types/telemetry.ts b/src/types/telemetry.ts index bcf72f9..c4cafea 100644 --- a/src/types/telemetry.ts +++ b/src/types/telemetry.ts @@ -1,4 +1,4 @@ -import type { TelemetryVariable, TelemetryVarList } from '@irsdk-node/types'; +import type { TelemetryVariable, TelemetryVarList } from '../app/irsdk/types'; export type Telemetry = TelemetryVarList & { TrackWetness?: TelemetryVariable; diff --git a/vite.main.config.ts b/vite.main.config.ts index bcfdef8..c4f478b 100644 --- a/vite.main.config.ts +++ b/vite.main.config.ts @@ -16,8 +16,8 @@ const getGitHash = () => { export default defineConfig({ plugins: [ irsdkNativeModule( - ['node_modules/@irsdk-node/native/build/Release/irsdk_node.node'], - '.vite/build/node_modules/@irsdk-node/native/build/Release/' + ['build/Release/irsdk_node.node'], + '.vite/build/Release/' ), ], resolve: {