7.1 KiB
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
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)
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
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)
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
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:
- Base RQ: Car's natural rarity level
- RQ Range: Tests from car's RQ up to maximum (115)
- 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:
- Minimum Time: Times below 1.2 seconds are discarded
- Downvote Filter: Community-downvoted times are excluded
- 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
- Update
tracks_repo.jsonwith new track definitions - Add track name mappings in
translate_track_name() - Add condition mappings in
translate_track_type()
Adding New Analysis Types
- Create new output functions (similar to
print_best_cars()) - Add command parsing in main function
- Update help text and documentation
Custom Data Sources
- Implement new scraping module (similar to club.rs)
- Add data source selection logic
- 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
- Caching Layer: Cache web scraping results
- Database Backend: Replace in-memory HashMap with persistent storage
- Configuration Files: External configuration for analysis parameters
- GUI Interface: Web-based interface for non-technical users
- Export Formats: Multiple output formats (JSON, XML, etc.)
Scalability Considerations
- Pagination: Handle large datasets with pagination
- Incremental Updates: Only fetch changed data
- Compression: Compress large timing files
- Streaming: Process data without loading everything into memory