Full notes
Full City-Racing update
Read the full published notes in a cleaner layout. The original post stays linked below.
What changed
- Events
- Performance
- Gameplay
City-Racing changes
π Division of Responsibilities
CRCarInfo.cs - Individual Car Tracking
Purpose: Tracks per-car data and player-specific information
β Mileage tracking (total, session, race)
β Speed calculations (current, average)
β Lap timing for individual car
β Waypoint navigation (arrow, beacon)
β Player GUI (diagnostics, countdown messages)
β File Creation:
Β· RaceData_{trackName}_{timestamp}.csv - Player's lap-by-lap data
Β· MileageReport_{trackName}_{timestamp}.txt - Player's mileage report
Β· car_mileage.json - Persistent mileage database
Β· race_history.json - Player's race history
FirstSecThird.cs - Real-Time Race Position Tracking
Purpose: Tracks all racers during the active race
Β·β Position calculations (1st, 2nd, 3rd, etc.)
Β·β Comparative race data (all cars' laps, waypoints)
Β·β Real-time sorting using Jobs System
Β·β Race results display when race ends
Β·β Best lap times tracking
Β·β File Creation: NONE (purely runtime tracking)
CRRaceManager.cs - Campaign & Scene Management
Purpose: Manages cross-scene race progression
β Persistent positions across multiple tracks
β Scene transitions and countdown coordination
β Campaign progress (which track, who's winning overall)
β Final standings across all races
β File Creation:
Β· race_save.json - Campaign save file with positions across scenes
---
π How They Work Together
During Race Start:
CRRaceManager (fires events)
β
OnRaceStart event
β
CRCarInfo (subscribes) β Resets lap timer, mileage
FirstSecThird (subscribes) β Starts position tracking
During Race:
CRCarInfo (each car)
β Updates waypoints, lap times
β Reports to FirstSecThird
β
FirstSecThird
β Calculates positions for ALL cars
β Updates race manager
β
CRRaceManager
β Stores positions for next scene
When Player Finishes:
CRCarInfo (player)
β Detects lap completion
β Calls FinishRaceAndAllOtherRacers()
β
FirstSecThird.ForceFinishAllRacers()
β Finalizes all AI positions
β Calls CRRaceManager.MarkRacerFinished()
β
CRRaceManager
β Updates campaign standings
β Saves progress
β Triggers scene transition
File Creation Summary:
CRCarInfo β Creates CSV/TXT after EACH race (player stats)
FirstSecThird β No files (runtime only)
CRRaceManager β Saves JSON when positions change (campaign save)
β Evidence They're Integrated:
Event System:
// CRRaceManager fires:
CRRaceManager.OnRaceStart?.Invoke();
// CRCarInfo subscribes:
CRRaceManager.OnRaceStart += OnRaceManagerRaceStart;
Cross-Script Communication:
// CRCarInfo talks to FirstSecThird:
FirstSecThird raceTracker = FindObjectOfType ();
firstSecThird.ForceFinishAllRacers();
// FirstSecThird talks to CRRaceManager:
raceManager.MarkRacerFinished(racerName, totalRaceTime);
Data Synchronization:
// CRCarInfo syncs with CRRaceManager:
private void SyncSavedDataWithCurrentScene(FirstSecThird raceTracker, ...)
{
foreach (var savedRacer in raceManager.racers) {
var matchingSceneRacer = FindMatchingFirstSecThirdRacer(...);
matchingSceneRacer.position = savedRacer.currentPosition;
}
}
π― Why This Architecture Makes Sense:
| Script | Scope | Lifespan | Saves Files? |
| CRCarInfo | Single Car | Per Scene | β Yes (player only) |
| FirstSecThird | All Cars | Per Scene | β No |
| CRRaceManager | Campaign | Persistent | β Yes (save game) |
---
π Bottom Line:
No, they're not redundant! Each has a specific role:
Β· CRCarInfo = "What's MY car doing?"
Β· FirstSecThird = "Where is EVERYONE right now?"
Β· CRRaceManager = "How's the CAMPAIGN going?"
The files they create serve different purposes:
Β· CSV/TXT (CRCarInfo) = Detailed player performance analysis
Β· JSON (CRRaceManager) = Campaign save/load system
They communicate through events, method calls, and shared data structures (like FirstSecThird.RacerInfo and CRRaceManager.RacerData).
Recommendation: Keep this architecture! It follows good separation of concerns. However, you could add a single centralized file manager if you want to consolidate the file I/O operations for consistency.
____________________________________________________________________________________
If FirstSecThird does not save a file what is laptimes.json for?
. Saving laptimes.json (Lines ~638-675)
Loading laptimes.json (Lines ~677-707)
β±οΈ What laptimes.json Contains
{
"bestLapTimes": [
{
"trackName": "CityRacing1",
"bestTime": 45.234
},
{
"trackName": "CityRacing2",
"bestTime": 52.891
}
],
"allTrackTimes": [
{
"trackName": "CityRacing1",
"lapTimes": [
{
"trackName": "CityRacing1",
"lapTime": 47.123,
"dateTime": "2026-01-03T19:27:18"
},
{
"trackName": "CityRacing1",
"lapTime": 45.234,
"dateTime": "2026-01-03T19:30:45"
}
]
}
]
}
π When Files Are Saved
FirstSecThird saves laptimes.json:
Β· On OnDestroy() (line ~236) - When the script is destroyed
Β· After displaying race results (line ~618) - In HideResultsAfterDelay()
private void OnDestroy()
{
// Clean up native arrays when object is destroyed
CleanupJobResources();
// Save lap times to persistent storage
SaveLapTimes(); // β SAVES HERE
}
private System.Collections.IEnumerator HideResultsAfterDelay()
{
yield return new WaitForSeconds(raceResultsDuration);
showingResults = false;
// Save lap times before potentially leaving the scene
SaveLapTimes(); // β SAVES HERE
}
π Summary - File Responsibilities
| Script | File Created | Purpose |
| CRCarInfo | RaceData_{track}_{timestamp}.csv | Player lap-by-lap CSV data |
| CRCarInfo | MileageReport_{track}_{timestamp}.txt | Player mileage report |
| CRCarInfo | car_mileage.json | Persistent mileage database |
| CRCarInfo | race_history.json | Player race history |
| FirstSecThird | laptimes.json | Best lap times for ALL tracks |
| CRRaceManager | race_progress.json | Campaign save file |
---
β Conclusion
Your initial statement was incorrect - FirstSecThird.cs DOES save a file: laptimes.json
This file stores:
Β· Best lap times per track (for leaderboards)
Β· All lap times history (for statistics)
Β· Track-specific records (persistent across game sessions)
It's different from the CSV/TXT files that CRCarInfo creates because:
Β· CRCarInfo: Creates new timestamped files each race (detailed per-race reports)
Β· FirstSecThird: Updates one persistent file with best times (cumulative records)
The architecture makes sense:
Β· FirstSecThird = Historical best times (like a hall of fame)
Β· CRCarInfo = Individual race reports (like race receipts)
Β· CRRaceManager = Campaign progress (save game)
Source
Changelog.gg summarizes and formats this update. How we read updates.
