225 lines
5.9 KiB
C#
225 lines
5.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
using System.IO;
|
|
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
public enum SectorColour {
|
|
Green,
|
|
Purple,
|
|
White,
|
|
Yellow,
|
|
}
|
|
|
|
[Serializable]
|
|
public struct SectorTime {
|
|
public int Sector;
|
|
public double Seconds;
|
|
public override string ToString() => $"{Seconds:0.000}";
|
|
}
|
|
|
|
[Serializable]
|
|
public struct Lap {
|
|
public string Map;
|
|
public int Number;
|
|
public List<SectorTime> Sectors;
|
|
|
|
// 0:1:39
|
|
public override string ToString() {
|
|
return $"{TimeSpan.FromSeconds(TotalTime()):m\\:ss\\.fff}";
|
|
}
|
|
|
|
public double TotalTime() {
|
|
return Sectors.Sum(s => s.Seconds);
|
|
}
|
|
}
|
|
|
|
|
|
[Serializable]
|
|
public class LapJSON {
|
|
public string Map;
|
|
public List<Lap> Laps = new();
|
|
}
|
|
|
|
public class LapStorage {
|
|
public List<LapJSON> Laps = new();
|
|
}
|
|
|
|
static class LapStorageService {
|
|
// static Dictionary<string, LapJSON> lapsByMap = new Dictionary<string, LapJSON>();
|
|
static Dictionary<string, LapJSON> lapsByMap = new();
|
|
static string lapStoragePath = Path.Combine(Application.persistentDataPath, "lapStorage.json");
|
|
|
|
static LapStorageService() {
|
|
LapStorage lapStorage = new LapStorage();
|
|
|
|
try {
|
|
string json = File.ReadAllText(lapStoragePath);
|
|
JsonUtility.FromJsonOverwrite(json, lapStorage);
|
|
} catch {
|
|
Debug.Log("No existing lapStorage.json");
|
|
}
|
|
|
|
lapsByMap = lapStorage.Laps.ToDictionary((lapJson) => lapJson.Map);
|
|
}
|
|
|
|
public static LapJSON GetPlayerLaps(string mapName) {
|
|
LapJSON currentLaps;
|
|
bool found = lapsByMap.TryGetValue(mapName, out currentLaps);
|
|
if (!found)
|
|
return new LapJSON { Map = mapName, Laps = new List<Lap>() };
|
|
return currentLaps;
|
|
}
|
|
|
|
static void Persist() {
|
|
LapStorage lapStorage = new LapStorage { Laps = lapsByMap.Values.ToList() };
|
|
File.WriteAllText(lapStoragePath, JsonUtility.ToJson(lapStorage));
|
|
}
|
|
|
|
// laps.count
|
|
public static int NumberOfCompletions() { return 0; }
|
|
|
|
// finds your PB in all completions
|
|
public static int Rank() { return 1; }
|
|
|
|
public static void PersistLap(Lap lap) {
|
|
LapJSON lapJson;
|
|
bool found = lapsByMap.TryGetValue(lap.Map, out lapJson);
|
|
if (!found)
|
|
lapJson = new LapJSON { Map = lap.Map, Laps = new List<Lap>() };
|
|
|
|
// Add lap and persist
|
|
lapJson.Laps.Add(lap);
|
|
lapsByMap[lap.Map] = lapJson;
|
|
Persist();
|
|
}
|
|
}
|
|
|
|
public class Timing: MonoBehaviour {
|
|
[SerializeField]
|
|
public List<Lap> lapTimes;
|
|
[SerializeField]
|
|
public List<SectorTime> sectorTimes;
|
|
public bool timerEnabled;
|
|
|
|
public double sectorTime;
|
|
public double lapTime;
|
|
double sectorStart;
|
|
double lapStart;
|
|
public Sector[] sectors;
|
|
|
|
public LapStorage lapStorage;
|
|
|
|
public string mapName;
|
|
|
|
void Awake() {
|
|
lapTimes = new();
|
|
sectorTimes = new List<SectorTime>();
|
|
sectorStart = 0.0;
|
|
sectorTime = 0.0;
|
|
sectors = GetComponentsInChildren<Sector>().OrderBy(s => s.sector).ToArray();
|
|
|
|
// set map name
|
|
Scene scene = SceneManager.GetActiveScene();
|
|
mapName = scene.name;
|
|
Debug.Log("Track Sector Count - " + sectors.Length);
|
|
}
|
|
|
|
void Update() {
|
|
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;
|
|
|
|
double sTime = Time.timeAsDouble - sectorStart;
|
|
|
|
SectorTime s = new SectorTime { Sector = sector, Seconds = sTime };
|
|
sectorTimes.Add(s);
|
|
sectorStart = Time.timeAsDouble;
|
|
|
|
Debug.Log($"{sectorTimes.Count} / {sectors.Length}");
|
|
|
|
if (sectorTimes.Count == sectors.Length) {
|
|
EndLap();
|
|
NextLap();
|
|
}
|
|
}
|
|
|
|
void NextLap() {
|
|
Debug.Log("NextLap" + lapTimes.Count);
|
|
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={lapTimes.Count}");
|
|
Lap l = new Lap { Map = mapName, Number = lapTimes.Count, Sectors = sectorTimes };
|
|
Debug.Log($"EndLap {l}");
|
|
lapTimes.Add(l);
|
|
|
|
LapStorageService.PersistLap(l);
|
|
Debug.Log($"Laps Stored {LapStorageService.GetPlayerLaps(mapName)}");
|
|
}
|
|
|
|
public SectorColour GetSectorColour(SectorTime s) {
|
|
if (lapTimes.Count == 0)
|
|
return SectorColour.Green;
|
|
|
|
var fastestLap = lapTimes.MinBy(l => l.TotalTime());
|
|
var fastestSector = fastestLap.Sectors.Single(fls => fls.Sector == s.Sector);
|
|
|
|
return (s.Seconds < fastestSector.Seconds) switch {
|
|
true => SectorColour.Green,
|
|
false => SectorColour.Yellow,
|
|
};
|
|
}
|
|
}
|
|
|