Files
spacerace/Assets/Src/Timing.cs
T
2023-10-02 19:18:36 +11:00

198 lines
5.5 KiB
C#

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<SectorTime> sectorTimes;
public bool timerEnabled;
[SerializeField]
ShipAudio audio;
public string mapName;
public double sectorTime;
public double lapTime;
public Sector[] sectors;
double sectorStart;
double lapStart;
IEnumerator noticeLifecycle;
IEnumerator msgLifecycle;
void Awake() {
ui = GetComponent<TimingUI>();
sectorTimes = new List<SectorTime>();
sectorStart = 0.0;
sectorTime = 0.0;
sectors = FindObjectsByType<Sector>(FindObjectsSortMode.None).OrderBy(s => s.sector).ToArray();
// set map name
Scene scene = SceneManager.GetActiveScene();
mapName = scene.name;
Debug.Log("Track Sector Count - " + sectors.Length);
// just poke the timing ui cause sometimes it fires early and misses that we actually have sectors
ui.Init();
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<SectorTime>();
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}");
// play a sound :)
if (audio != null) audio.PlayNoise();
// 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<SectorTime>();
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(10);
ui.HideRecentLap();
}
public void Message(string msg) {
if (msgLifecycle != null) StopCoroutine(msgLifecycle);
msgLifecycle = ShowMessage(msg);
StartCoroutine(msgLifecycle);
}
IEnumerator ShowMessage(string msg) {
ui.ShowMessage(msg);
yield return new WaitForSeconds(5);
ui.HideMessage();
}
// 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);
}
}