using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.IO; using UnityEngine; using UnityEditor; using UnityEngine.SceneManagement; public class Timing: MonoBehaviour { TimingUI ui; LapService lapService; public List sectorTimes; public bool timerEnabled; public string mapName; public double sectorTime; public double lapTime; public Sector[] sectors; double sectorStart; double lapStart; IEnumerator noticeLifecycle; void Awake() { ui = GetComponent(); sectorTimes = new List(); sectorStart = 0.0; sectorTime = 0.0; sectors = FindObjectsByType(FindObjectsSortMode.None).OrderBy(s => s.sector).ToArray(); // set map name Scene scene = SceneManager.GetActiveScene(); mapName = scene.name; Debug.Log("Track Sector Count - " + sectors.Length); lapService = new LapService(mapName); } void Start() { Debug.Log("Timing Starting..."); StartCoroutine(lapService.GetLapTimes()); } void Update() { // hmr if (lapService == null) { Awake(); Start(); } if (timerEnabled) { sectorTime = Time.timeAsDouble - sectorStart; lapTime = Time.timeAsDouble - lapStart; } } public void StartTimer() { if (sectors.Length == 0) { Debug.LogWarning("No Sectors found in timing"); return; } Debug.Log("Started Timer"); timerEnabled = true; lapStart = Time.timeAsDouble; sectorStart = Time.timeAsDouble; } public void StopTimer() { sectorTimes = new List(); timerEnabled = false; sectorTime = 0; lapTime = 0; Debug.Log("Timer Stopped"); } public void NextSector(int sector) { if (!timerEnabled) return; // they turned around or somethin? if (sectorTimes.Any(s => s.Sector == sector)) return; // this basically makes sure the timer doesn't do anything weird // due to respawns, driving in the wrong direction etc // you have to hit the sectors in numbered order // --------------- // make sure sectors are only accessible by being hit by following // the track correctly! if (sector != sectorTimes.Count + 1) return; // alright they legitimately finished a sector... double sTime = Time.timeAsDouble - sectorStart; SectorTime s = new SectorTime { Sector = sector, Seconds = sTime }; sectorTimes.Add(s); Debug.Log($"{sectorTimes.Count} / {sectors.Length}"); // restart the timer for the next sector sectorStart = Time.timeAsDouble; // they finished a lap! if (sectorTimes.Count == sectors.Length) { EndLap(); NextLap(); } } void NextLap() { sectorTimes = new List(); StartTimer(); } public void EndLap() { // when live reloading this happens if (sectorTimes == null) Awake(); Debug.Log($"Ending lap Sectors={sectorTimes.Count} Name={mapName}"); Lap l = new Lap { Map = mapName, Sectors = sectorTimes }; Debug.Log($"EndLap {l}"); // have to show this before we persist the lap in case it is the pb if (noticeLifecycle != null) StopCoroutine(noticeLifecycle); noticeLifecycle = RecentLapLifecycle(l); StartCoroutine(noticeLifecycle); StartCoroutine(lapService?.PostLap(l)); } IEnumerator RecentLapLifecycle(Lap l) { ui.ShowRecentLap(l); yield return new WaitForSeconds(5); ui.HideRecentLap(); } // these can be null after HMR public Lap LapRecord => lapService?.LapRecord; public Lap Pb => lapService?.Pb; public string Position => $"{lapService?.Position} / {lapService?.Completions}"; public TimingNotice CompareLap(Lap lap) { double? lrSeconds = LapRecord != null ? LapRecord.TotalTime : null; double? pbSeconds = Pb != null ? Pb.TotalTime : null; return TimingNotice.Compare(lap.TotalTime, pbSeconds, lrSeconds); } public TimingNotice CompareSector(SectorTime s) { double? lrSeconds = LapRecord switch { null => null, Lap lr => lr.Sectors.SingleOrDefault(lrs => lrs.Sector == s.Sector) switch { SectorTime lrSector => lrSector.Seconds, _ => null, }, }; double? pbSeconds = Pb switch { null => null, Lap pb => pb.Sectors.SingleOrDefault(pbs => pbs.Sector == s.Sector) switch { SectorTime pbSector => pbSector.Seconds, _ => null, }, }; return TimingNotice.Compare(s.Seconds, pbSeconds, lrSeconds); } }