Protect & storage lists: - protect.csv: unlocked garage cars (state != 0, locked == false) worth locking more copies of. Needed copies = best configs surviving the RQ-band thresholds (prize cars and RQ >= 80 always count); already locked copies (copy_count) are subtracted, surplus drops off the list. - storage.csv: Keep/Trash recommendation for storage cars (state == 0) using the same copy-count logic; surplus unlocked copies are fusion material. - user_data.rs now parses card state (garage vs storage), garage slots (user.garageSlots/garageSlotsUsed), and unlocked card maps. Dynamic trash thresholds: - TrashThresholds derive RQ 20-29/30-39 as half/a quarter of a base value (--trash-base-count, default 4); RQ 40+ never covered. - plan_trash_rules escalates the base automatically while projected free garage slots (capacity - used + unlocked non-best copies + new trash candidates, copies counted per card) stay below --garage-min-free (default 20), stopping when no further cars qualify. Effective thresholds and projection are printed. - Improve-based low-value cars (best target count at or below the band threshold) land in trash.csv; collect_improve_entries is shared with improve.csv and computed once per run. Same-car tie resolution: - resolve_tied_configs collapses tie-equivalent configs of the same car per track (compute_car_counts, write_details_csv), preferring the player's owned final-build config. Fixes phantom rows like the Mercedes 280 SL 332 entry tied at 61.31 by its owned 323, inflated per-config track counts, and pointless second-copy recommendations. Wishlist: - Prize cars are excluded from the ideal wishlist and surface in remove.csv via the ideal-set difference. CLI: new protect command; --trash-base-count/--garage-min-free on trash/protect/all; details command reuses counts for tie resolution. README updated for all new files, flags, and criteria.
429 lines
15 KiB
Markdown
429 lines
15 KiB
Markdown
# Top Drives Records Analyzer
|
|
|
|
A comprehensive Rust-based tool for analyzing car performance data in the Top Drives racing game. This tool fetches track times from a community-maintained repository and provides detailed analysis including best cars, trash identification, and wishlist optimization.
|
|
|
|
## 🚀 Features
|
|
|
|
- **Best Car Analysis**: Find the best performing cars across all tracks and conditions
|
|
- **Wishlist Optimization**: Identify cars to add to or remove from your wishlist
|
|
- **Collection Cleanup**: Identify cars that can be safely removed from your collection
|
|
- **Upgrade Prioritization**: Find owned cars not yet at their final tune build
|
|
- **Track-Specific Analysis**: Get detailed performance data for specific tracks and conditions
|
|
- **RQ-Based Filtering**: Filter results by car rarity (RQ) levels
|
|
- **Multiple Surface Types**: Support for Dry, Wet, Dirt, Snow, and other track conditions
|
|
|
|
## 📋 Table of Contents
|
|
|
|
- [Installation](#installation)
|
|
- [Quick Start](#quick-start)
|
|
- [Usage Guide](#usage-guide)
|
|
- [Commands Reference](#commands-reference)
|
|
- [Daily Workflow](#daily-workflow)
|
|
- [Data Sources](#data-sources)
|
|
- [Configuration](#configuration)
|
|
- [Development](#development)
|
|
- [Contributing](#contributing)
|
|
|
|
## 🛠️ Installation
|
|
|
|
### Prerequisites
|
|
|
|
- [Rust](https://rustup.rs/) (latest stable version)
|
|
- Internet connection for fetching data
|
|
|
|
### Setup
|
|
|
|
1. **Clone the repository**
|
|
```bash
|
|
git clone <repository-url>
|
|
cd top_drives
|
|
```
|
|
|
|
2. **Build the project**
|
|
```bash
|
|
cargo build --release
|
|
```
|
|
|
|
3. **Run the analyzer**
|
|
```bash
|
|
cargo run --bin records -- fetch
|
|
```
|
|
|
|
## 🚦 Quick Start
|
|
|
|
1. **Initial Setup**: Fetch the latest car and track data
|
|
```bash
|
|
cargo run --bin records -- fetch
|
|
```
|
|
|
|
2. **Full Analysis**: Generate all output files in a single pass
|
|
```bash
|
|
cargo run --bin records -- all
|
|
```
|
|
|
|
3. **Best Cars**: Find the best cars across all tracks
|
|
```bash
|
|
cargo run --bin records -- best
|
|
```
|
|
|
|
4. **Collection Cleanup**: Identify cars safe to remove
|
|
```bash
|
|
cargo run --bin records -- trash
|
|
```
|
|
|
|
5. **Wishlist Management**: Optimize your wishlist
|
|
```bash
|
|
cargo run --bin records -- wishlist
|
|
```
|
|
|
|
6. **Upgrade Prioritization**: Find cars that need upgrading
|
|
```bash
|
|
cargo run --bin records -- improve
|
|
```
|
|
|
|
## 📖 Usage Guide
|
|
|
|
### Basic Commands
|
|
|
|
#### Fetch Data
|
|
```bash
|
|
cargo run --bin records -- fetch
|
|
```
|
|
Downloads the latest car database and track information from the community repository.
|
|
|
|
#### Best Cars Analysis
|
|
```bash
|
|
cargo run --bin records -- best
|
|
```
|
|
Generates `best.csv` (all cars best on at least one track) and `very_best.csv` (cars best on ≥10 tracks). Both files are sorted by RQ.
|
|
|
|
**Output Files:**
|
|
```
|
|
best.csv — All cars best on at least one track
|
|
very_best.csv — Cars best on ≥10 tracks (default)
|
|
```
|
|
|
|
Use `--min-count N` to change the threshold for `very_best.csv`:
|
|
```bash
|
|
cargo run --bin records -- best --min-count 5
|
|
```
|
|
|
|
#### Trash Analysis
|
|
```bash
|
|
cargo run --bin records -- trash
|
|
```
|
|
Generates `trash.csv` — owned cars that are not best on any track, have RQ < 80, and are not prize cars, plus low-value upgrade fodder: unfinished cars whose best config reaches at most a per-RQ-band track count (RQ 10-19: ≤4, RQ 20-29: ≤2, RQ 30-39: ≤1 by default). Sorted by RQ.
|
|
|
|
**Output File:**
|
|
```
|
|
trash.csv — Owned cars safe to remove or use as fusion material
|
|
```
|
|
|
|
The band thresholds derive from a single base value (`--trash-base-count`, default 4); each higher band gets half of the previous one. The tool prints the effective thresholds and a garage-space projection (`user.garageSlots`/`garageSlotsUsed` from the export). When the projected free slots after clean-up fall below `--garage-min-free` (default 20), the base count is raised automatically — and printed — until the target is reached or no more cars qualify:
|
|
|
|
```bash
|
|
cargo run --bin records -- trash --trash-base-count 5 --garage-min-free 30
|
|
```
|
|
|
|
Pass `--trash-base-count 0` to disable the improve-based criteria entirely.
|
|
|
|
#### Protect & Storage Analysis
|
|
```bash
|
|
cargo run --bin records -- protect
|
|
```
|
|
Generates `protect.csv` — cars in the **garage** that are currently **not locked** and are worth locking more copies of — and `storage.csv`, a keep/trash recommendation for cars in the **storage** ("Lager", `state == 0` in the export). Both apply the same dynamic criteria (including garage-space escalation and its printed plan) as the trash command.
|
|
|
|
**Output Files:**
|
|
```
|
|
protect.csv — Unlocked garage cars worth locking
|
|
storage.csv — Keep/Trash recommendation for storage cars
|
|
```
|
|
|
|
`protect.csv` columns: `RQ,Brand,Model,Year,FinalBuild,Count,ToLock`. A car drops off the list once its locked copies cover every best config surviving the RQ-band thresholds; `ToLock` is the number of additional copies worth locking. Cars not best on any track never appear.
|
|
|
|
`storage.csv` columns: `RQ,Brand,Model,Year,FinalBuild,Count,Recommendation`. Cars not best on any track, best only in configs at or below their RQ-band threshold, or with enough locked copies already (surplus unlocked copies are fusion material), are `Trash`; prize cars and RQ ≥ 80 are always `Keep`.
|
|
|
|
The trash criteria flags apply here as well:
|
|
|
|
```bash
|
|
cargo run --bin records -- protect --trash-base-count 5 --garage-min-free 30
|
|
```
|
|
|
|
#### Wishlist Management
|
|
```bash
|
|
cargo run --bin records -- wishlist
|
|
```
|
|
Generates `wishlist.csv` (ideal wishlist: very_best unowned cars, capped at 300), `add.csv` (cars that should be on your wishlist but aren't), and `remove.csv` (cars on your wishlist that shouldn't be). All sorted by RQ. Prize cars are excluded from the ideal wishlist; prize cars still on your actual wishlist appear in `remove.csv`.
|
|
|
|
**Output Files:**
|
|
```
|
|
wishlist.csv — Ideal wishlist (very_best unowned, capped)
|
|
add.csv — Cars to add to wishlist
|
|
remove.csv — Cars to remove from wishlist
|
|
```
|
|
|
|
Use `--min-count N` to change the threshold for very_best cars (default 10):
|
|
```bash
|
|
cargo run --bin records -- wishlist --min-count 5
|
|
```
|
|
|
|
Use `--max-wishlist M` to change the wishlist cap (default 300):
|
|
```bash
|
|
cargo run --bin records -- wishlist --max-wishlist 500
|
|
```
|
|
|
|
#### Full Analysis
|
|
```bash
|
|
cargo run --bin records -- all
|
|
```
|
|
Generates all 10 CSV files in a single parse pass. Equivalent to running `best`, `trash`, `wishlist`, `improve`, and `protect` together, but more efficient.
|
|
|
|
**Output Files:**
|
|
```
|
|
best.csv — All cars best on at least one track
|
|
very_best.csv — Cars best on ≥10 tracks
|
|
trash.csv — Owned cars safe to remove
|
|
wishlist.csv — Ideal wishlist (very_best unowned, capped)
|
|
add.csv — Cars to add to wishlist
|
|
remove.csv — Cars to remove from wishlist
|
|
improve.csv — Owned cars not yet at final build config
|
|
protect.csv — Unlocked garage cars worth locking
|
|
storage.csv — Keep/Trash recommendation for storage cars
|
|
```
|
|
|
|
Supports `--min-count N` (default 10), `--max-wishlist M` (default 300), and the trash criteria flags:
|
|
```bash
|
|
cargo run --bin records -- all --min-count 5 --max-wishlist 500 --trash-base-count 4 --garage-min-free 20
|
|
```
|
|
|
|
#### Detailed Performance Data
|
|
```bash
|
|
cargo run --bin records -- details
|
|
```
|
|
Generates `details.csv` with comprehensive timing data for all tracks and conditions.
|
|
|
|
**Sample Output:**
|
|
```
|
|
RQ,TrackID,Condition,CarRQ,Brand,Model,Year,Config,Time
|
|
85,laguna,Dry,85,McLaren,F1,1993,233,112.45
|
|
82,monaco,Dry,82,Ferrari,250 GTO,1962,111,45.23
|
|
```
|
|
|
|
#### Track-Specific Analysis
|
|
```bash
|
|
cargo run --bin records -- track "Laguna Seca" "Dry" "85"
|
|
```
|
|
Prints the best car for a specific track, condition, and RQ combination to stdout.
|
|
|
|
### Advanced Usage
|
|
|
|
#### Multiple RQ Analysis
|
|
The tool supports analyzing performance across different RQ ranges. Use the `best` and `wishlist` commands to see how cars perform at various rarity levels.
|
|
|
|
#### Track Conditions
|
|
The analyzer supports multiple track conditions:
|
|
- **Dry**: Standard asphalt conditions
|
|
- **Wet**: Rain-affected tracks
|
|
- **Dirt**: Off-road conditions
|
|
- **Snow**: Winter conditions
|
|
- **Gravel**: Loose surface conditions
|
|
|
|
## 🗃️ Commands Reference
|
|
|
|
| Command | Description | Arguments |
|
|
|---------|-------------|-----------|
|
|
| `fetch` | Download latest car and track data | None |
|
|
| `best` | Generate `best.csv` and `very_best.csv` | `[--min-count N]` |
|
|
| `trash` | Generate `trash.csv` (owned cars safe to remove) | `[--trash-base-count N] [--garage-min-free N]` |
|
|
| `protect` | Generate `protect.csv` (unlocked garage cars) and `storage.csv` (storage keep/trash) | `[--trash-base-count N] [--garage-min-free N]` |
|
|
| `wishlist` | Generate `wishlist.csv`, `add.csv`, `remove.csv` | `[--min-count N] [--max-wishlist M]` |
|
|
| `all` | Generate all 10 CSV files in a single pass | `[--min-count N] [--max-wishlist M] [--trash-base-count N] [--garage-min-free N]` |
|
|
| `details` | Print detailed timing data for all tracks (stdout) | None |
|
|
| `track` | Print best car for specific track (stdout) | `<track_name> <condition> <rq>` |
|
|
| `improve` | Generate `improve.csv` (owned cars not at final build) | None |
|
|
|
|
### Flags
|
|
|
|
| Flag | Default | Description |
|
|
|------|---------|-------------|
|
|
| `--min-count N` | `10` | Minimum number of tracks a car must be best on to qualify as "very best" |
|
|
| `--max-wishlist M` | `300` | Maximum number of cars on the ideal wishlist |
|
|
| `--trash-base-count N` | `4` | Maximum improve track count for RQ 10-19 to count as trash; RQ 20-29/30-39 get half/a quarter. `0` disables the criteria |
|
|
| `--garage-min-free N` | `20` | Minimum projected free garage slots; the trash base count is raised automatically when the projection falls short |
|
|
|
|
## 📅 Daily Workflow
|
|
|
|
The typical daily workflow uses the `all` command, which runs all analysis in a single efficient parse pass:
|
|
|
|
```bash
|
|
cargo run --bin records -- fetch
|
|
cargo run --bin records -- all
|
|
```
|
|
|
|
Or combine them:
|
|
```bash
|
|
cargo run --bin records -- fetch && cargo run --bin records -- all
|
|
```
|
|
|
|
This generates the following output files (all sorted by car RQ):
|
|
|
|
| File | Format | Description |
|
|
|------|--------|-------------|
|
|
| `best.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | All cars best on at least one track |
|
|
| `very_best.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | Cars best on ≥ min_count tracks |
|
|
| `trash.csv` | `RQ,Brand,Model,Year` | Owned cars not best on any track (RQ<80, not prize) |
|
|
| `wishlist.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | Ideal wishlist (very_best unowned, capped) |
|
|
| `add.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | Cars to add to wishlist |
|
|
| `remove.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | Cars to remove from wishlist |
|
|
| `improve.csv` | `RQ,Brand,Model,Year,Target,Count` | Owned cars not yet at final build config |
|
|
|
|
### Workflow Steps
|
|
|
|
1. **Fetch** fresh data from the community repository
|
|
2. **Analyze** your collection with `all` to generate all CSV files
|
|
3. **Review** `best.csv` to see how your cars rank
|
|
4. **Check** `add.csv` for cars worth adding to your wishlist
|
|
5. **Clean up** `remove.csv` entries from your wishlist
|
|
6. **Sell** cars listed in `trash.csv` that are no longer useful
|
|
7. **Upgrade** cars listed in `improve.csv` to their target final build
|
|
|
|
## 📊 Data Sources
|
|
|
|
### Car Data
|
|
- **Source**: Community-maintained GitHub repository
|
|
- **Format**: JSON files with performance data per car
|
|
- **Update Frequency**: Regular updates from community contributors
|
|
|
|
### Track Data
|
|
- **Source**: Same community repository
|
|
- **Coverage**: All tracks and conditions in Top Drives
|
|
- **Format**: Structured track definitions with conditions
|
|
|
|
### Track Names
|
|
- **Source**: `track_names.json` (included in repository)
|
|
- **Format**: JSON mapping track codes to human-readable names
|
|
- **Loaded**: At compile time via `include_str!`
|
|
|
|
### User Collection
|
|
- **File**: `my_cars.json`
|
|
- **Format**: Top Drives game export format
|
|
- **Usage**: Identifies owned cars for analysis
|
|
|
|
## ⚙️ Configuration
|
|
|
|
### Files Structure
|
|
```
|
|
top_drives/
|
|
├── src/
|
|
│ ├── records.rs # Main analyzer binary
|
|
│ └── lib.rs # Shared library (track name translations)
|
|
├── times/ # Car performance data (1000+ files)
|
|
├── cars_repo.json # Car database
|
|
├── tracks_repo.json # Track definitions
|
|
├── track_names.json # Track code → name mappings
|
|
├── my_cars.json # Your car collection
|
|
└── Cargo.toml # Rust project configuration
|
|
```
|
|
|
|
### Dependencies
|
|
- **reqwest**: HTTP client for data fetching
|
|
- **serde** / **serde_json**: JSON parsing and serialization (with `serde::Deserialize` derive for `Car`)
|
|
- **tokio**: Asynchronous runtime (rt-multi-thread, macros, fs, sync, io-util)
|
|
- **futures**: Async utility combinators
|
|
- **clap**: CLI argument parsing (with derive macros)
|
|
- **thiserror**: Ergonomic error type definitions
|
|
|
|
## 🔧 Development
|
|
|
|
### Project Structure
|
|
The project consists of a single binary with a shared library:
|
|
|
|
1. **records**: Primary analysis tool using JSON data (`src/records.rs`)
|
|
2. **lib**: Shared library with track name translations (`src/lib.rs`)
|
|
|
|
### Key Constants
|
|
|
|
- `MAX_RQ: u8 = 113` — Maximum RQ level used in analysis (defined in `records.rs`)
|
|
|
|
### Key Data Structures
|
|
|
|
#### Car Information
|
|
```rust
|
|
struct Car {
|
|
rid: String, // Unique car identifier
|
|
brand: String, // Manufacturer name
|
|
only_name: String, // Model name
|
|
year: u16, // Model year
|
|
rq: u8, // Rarity level (10-113)
|
|
prize: bool, // Whether car is prize-only
|
|
guid: String, // Game-specific identifier
|
|
}
|
|
```
|
|
|
|
#### Performance Records
|
|
```rust
|
|
struct BestCarRecord {
|
|
car_rid: String, // Car identifier
|
|
brand: String, // Manufacturer
|
|
only_name: String, // Model name
|
|
year: u16, // Year
|
|
rq: u8, // Rarity level
|
|
config: String, // Original tune config from JSON
|
|
normalized_config: String, // Normalized final build (323, 233, or 332)
|
|
time: f64, // Track time
|
|
owned: bool, // Whether you own this car
|
|
prize: bool, // Whether this is a prize car
|
|
guid: String, // Game identifier
|
|
}
|
|
```
|
|
|
|
### Building
|
|
```bash
|
|
# Debug build
|
|
cargo build
|
|
|
|
# Release build
|
|
cargo build --release
|
|
|
|
# Run the analyzer
|
|
cargo run --bin records
|
|
```
|
|
|
|
## 🤝 Contributing
|
|
|
|
1. Fork the repository
|
|
2. Create a feature branch
|
|
3. Make your changes
|
|
4. Add tests if applicable
|
|
5. Submit a pull request
|
|
|
|
### Adding New Tracks
|
|
Track definitions are stored in `tracks_repo.json`. Each track includes:
|
|
- Unique identifier
|
|
- Display name
|
|
- Supported conditions
|
|
- Track type classification
|
|
|
|
Track name mappings are stored in `track_names.json` and loaded at compile time.
|
|
|
|
### Adding Car Data
|
|
New car performance data should be submitted to the upstream repository following their contribution guidelines.
|
|
|
|
## 📄 License
|
|
|
|
This project is open source. Please check the upstream data repositories for their respective licenses.
|
|
|
|
## 🆘 Support
|
|
|
|
For issues and questions:
|
|
1. Check existing documentation
|
|
2. Review open issues
|
|
3. Create new issue with detailed description
|
|
|
|
## 🔄 Updates
|
|
|
|
The tool fetches fresh data each time you run the `fetch` command. Keep your local data updated for best results.
|
|
|
|
---
|
|
|
|
*Built with ❤️ for the Top Drives community*
|