242 lines
No EOL
7.1 KiB
Markdown
242 lines
No EOL
7.1 KiB
Markdown
# Architecture Documentation
|
|
|
|
## System Overview
|
|
|
|
The Top Drives Records Analyzer consists of two main components working together to provide comprehensive car performance analysis for the Top Drives racing game.
|
|
|
|
## Component Architecture
|
|
|
|
### 1. Records Module (`src/records.rs`)
|
|
|
|
**Primary analysis engine** that processes pre-downloaded JSON timing data.
|
|
|
|
#### Key Responsibilities
|
|
- **Data Fetching**: Downloads car and track databases from GitHub repository
|
|
- **File Processing**: Parses JSON timing files for each car configuration
|
|
- **Performance Analysis**: Compares timing data across RQ ranges and track conditions
|
|
- **Collection Management**: Identifies owned cars and optimization opportunities
|
|
|
|
#### Data Flow
|
|
|
|
```
|
|
GitHub Repository
|
|
↓
|
|
cars_repo.json + tracks_repo.json
|
|
↓
|
|
times/*.json (1000+ car files)
|
|
↓
|
|
JSON Parsing → BestCarRecord Analysis
|
|
↓
|
|
User Collection (my_cars.json)
|
|
↓
|
|
Output: CSV/Terminal Results
|
|
```
|
|
|
|
### 2. Club Module (`src/club.rs`)
|
|
|
|
**Alternative data source** that scrapes live data from topdrives.club website.
|
|
|
|
#### Key Responsibilities
|
|
- **Web Scraping**: Fetches HTML content from topdrives.club
|
|
- **HTML Parsing**: Extracts car performance data using CSS selectors
|
|
- **Real-time Data**: Provides fresh data without pre-downloaded files
|
|
|
|
#### Data Flow
|
|
|
|
```
|
|
topdrives.club Website
|
|
↓
|
|
HTML Content
|
|
↓
|
|
CSS Selector Parsing
|
|
↓
|
|
Car Data Extraction
|
|
↓
|
|
Output: Terminal Results
|
|
```
|
|
|
|
## Data Structures
|
|
|
|
### Core Types
|
|
|
|
#### TripletKey
|
|
```rust
|
|
type TripletKey = (String, u8, String);
|
|
// ↓ ↓ ↓
|
|
// Track ID RQ Level Surface Condition
|
|
```
|
|
|
|
**Purpose**: Composite key for uniquely identifying track conditions
|
|
**Usage**: HashMap key for storing best car records
|
|
|
|
#### Car (Records Module)
|
|
```rust
|
|
struct Car {
|
|
rid: String, // Repository ID
|
|
brand: String, // Manufacturer
|
|
only_name: String, // Model name
|
|
year: u16, // Model year
|
|
rq: u8, // Rarity level
|
|
prize: bool, // Prize car status
|
|
guid: String, // Game GUID
|
|
}
|
|
```
|
|
|
|
#### BestCarRecord
|
|
```rust
|
|
struct BestCarRecord {
|
|
car_rid: String, // Car identifier
|
|
brand: String, // Manufacturer
|
|
only_name: String, // Model name
|
|
year: u16, // Year
|
|
rq: u8, // RQ level
|
|
config: String, // Tune config (111, 233, etc.)
|
|
time: f64, // Track time (seconds)
|
|
owned: bool, // User ownership status
|
|
guid: String, // Game identifier
|
|
}
|
|
```
|
|
|
|
#### Car (Club Module)
|
|
```rust
|
|
struct Car {
|
|
class: String, // Class letter (S, A, B, etc.)
|
|
rq: u8, // Rarity level
|
|
manufacturer: String, // Brand
|
|
model: String, // Model
|
|
year: u16, // Year
|
|
upgrade: String, // Upgrade config
|
|
}
|
|
```
|
|
|
|
## Global State Management
|
|
|
|
### BEST_CARS Cache
|
|
```rust
|
|
static BEST_CARS: Lazy<Mutex<HashMap<TripletKey, Vec<BestCarRecord>>>>
|
|
```
|
|
|
|
**Thread Safety**: Protected by `Mutex` for concurrent access during parsing
|
|
**Initialization**: Uses `once_cell::Lazy` for one-time setup
|
|
**Structure**: HashMap with composite keys for efficient lookups
|
|
|
|
## Algorithm Details
|
|
|
|
### RQ Range Analysis
|
|
|
|
The system analyzes car performance across multiple RQ brackets:
|
|
|
|
1. **Base RQ**: Car's natural rarity level
|
|
2. **RQ Range**: Tests from car's RQ up to maximum (115)
|
|
3. **Cross-RQ Competition**: Allows cars to compete above their base level
|
|
|
|
**Example**: A RQ 85 car might perform well at RQ 90-95 levels against higher-rated cars
|
|
|
|
### Time Validation
|
|
|
|
Multiple validation layers ensure data quality:
|
|
|
|
1. **Minimum Time**: Times below 1.2 seconds are discarded
|
|
2. **Downvote Filter**: Community-downvoted times are excluded
|
|
3. **Special Cases**: Test Bowl track uses inverted time calculation (2000.0 / time)
|
|
|
|
### Concurrent Processing
|
|
|
|
#### Records Module
|
|
- **Task Spawning**: One async task per car file
|
|
- **Rate Limiting**: Semaphore limits concurrent downloads (20 max)
|
|
- **Error Isolation**: Individual car failures don't stop batch processing
|
|
|
|
#### Synchronization
|
|
- **Join Handles**: Waits for all parsing tasks to complete
|
|
- **Mutex Protection**: Safe concurrent access to shared BEST_CARS cache
|
|
|
|
## File Organization
|
|
|
|
### Input Files
|
|
```
|
|
├── cars_repo.json # Car database from repository
|
|
├── tracks_repo.json # Track definitions
|
|
├── my_cars.json # User's car collection (game export)
|
|
└── times/ # Individual car timing files
|
|
├── Ferrari_F40_1987.json
|
|
├── McLaren_F1_1993.json
|
|
└── ...
|
|
```
|
|
|
|
### Output Files
|
|
```
|
|
├── best.csv # Best cars analysis results
|
|
├── missing.csv # Missing recommended cars
|
|
└── details.csv # Detailed timing data
|
|
```
|
|
|
|
## Performance Characteristics
|
|
|
|
### Records Module
|
|
- **Startup Time**: Fast (uses cached JSON files)
|
|
- **Memory Usage**: Moderate (loads all timing data into memory)
|
|
- **Accuracy**: High (comprehensive dataset)
|
|
- **Update Frequency**: Manual refresh required
|
|
|
|
### Club Module
|
|
- **Startup Time**: Slow (web scraping required)
|
|
- **Memory Usage**: Low (processes one track at a time)
|
|
- **Accuracy**: Variable (depends on website structure)
|
|
- **Update Frequency**: Real-time on each run
|
|
|
|
## Error Handling Strategy
|
|
|
|
### Graceful Degradation
|
|
- **Missing Files**: Continue with available data
|
|
- **Network Errors**: Log errors but don't crash
|
|
- **Parse Failures**: Use default values or skip invalid entries
|
|
|
|
### User Feedback
|
|
- **Progress Indication**: Shows fetching/download progress
|
|
- **Error Messages**: Clear descriptions of what went wrong
|
|
- **Fallback Options**: Multiple data sources available
|
|
|
|
## Extension Points
|
|
|
|
### Adding New Tracks
|
|
1. Update `tracks_repo.json` with new track definitions
|
|
2. Add track name mappings in `translate_track_name()`
|
|
3. Add condition mappings in `translate_track_type()`
|
|
|
|
### Adding New Analysis Types
|
|
1. Create new output functions (similar to `print_best_cars()`)
|
|
2. Add command parsing in main function
|
|
3. Update help text and documentation
|
|
|
|
### Custom Data Sources
|
|
1. Implement new scraping module (similar to club.rs)
|
|
2. Add data source selection logic
|
|
3. Update configuration system
|
|
|
|
## Security Considerations
|
|
|
|
### Network Access
|
|
- **HTTPS Only**: All external requests use HTTPS
|
|
- **Certificate Validation**: Accepts invalid certificates for compatibility
|
|
- **Rate Limiting**: Respects server limits with controlled concurrency
|
|
|
|
### Local File Access
|
|
- **Read Only**: No modification of game files
|
|
- **User Data**: Only reads exported collection data
|
|
- **No Persistence**: Analysis results are output-only
|
|
|
|
## Future Enhancements
|
|
|
|
### Potential Improvements
|
|
1. **Caching Layer**: Cache web scraping results
|
|
2. **Database Backend**: Replace in-memory HashMap with persistent storage
|
|
3. **Configuration Files**: External configuration for analysis parameters
|
|
4. **GUI Interface**: Web-based interface for non-technical users
|
|
5. **Export Formats**: Multiple output formats (JSON, XML, etc.)
|
|
|
|
### Scalability Considerations
|
|
1. **Pagination**: Handle large datasets with pagination
|
|
2. **Incremental Updates**: Only fetch changed data
|
|
3. **Compression**: Compress large timing files
|
|
4. **Streaming**: Process data without loading everything into memory |