using System; using System.Collections.Generic; using System.Linq; using System.IO; using UnityEngine; using UnityEngine.UIElements; public enum NoticeCategory { Initial, Slower, Faster, Fastest, } public class TimingNotice { public double Seconds; NoticeCategory Category = NoticeCategory.Initial; public TimingNotice Compare(double comparison) { double s = Math.Abs(comparison - Seconds); NoticeCategory cat = comparison switch { double c when Seconds < c => NoticeCategory.Faster, _ => NoticeCategory.Slower, }; return new TimingNotice { Seconds = s, Category = cat, }; } public Label ToLabel() { Label l = Category switch { NoticeCategory.Initial => new Label($"{TimeSpan.FromSeconds(Seconds):m\\:ss\\.fff}"), NoticeCategory.Slower => new Label($"+{Seconds:0.000}"), NoticeCategory.Faster => new Label($"-{Seconds:0.000}"), NoticeCategory.Fastest => new Label($"-{Seconds:0.000}"), _ => new Label($"-{Seconds:0.000}"), }; string colourClass = Category switch { NoticeCategory.Initial => "", NoticeCategory.Slower => "yellow", NoticeCategory.Faster => "green", NoticeCategory.Fastest => "purple", _ => "", }; l.AddToClassList(colourClass); return l; } } public enum DiffColour { Green, Purple, White, Yellow, } [Serializable] public class SectorTime { public int Sector; public double Seconds; public override string ToString() => $"{Seconds:0.000}"; } [Serializable] public class Lap { public string Map; public List Sectors; // 0:1:39 public override string ToString() { return $"{TimeSpan.FromSeconds(TotalTime):m\\:ss\\.fff}"; } public double TotalTime => Sectors.Sum(s => s.Seconds); } [Serializable] public class LapJSON { public string Map; public List Laps = new(); } // We can't save a dictionary with the Unity JSONUtility // so we use this to hold a list of maps public class LapStorage { public List Laps = new(); } static class LapStorageService { static Dictionary 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 EnsureMap(mapName); return currentLaps; } public static LapJSON EnsureMap(string mapName) { LapJSON lapJson = new LapJSON { Map = mapName, Laps = new List() }; lapsByMap[mapName] = lapJson; return lapJson; } 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 = GetPlayerLaps(lap.Map); lapJson.Laps.Add(lap); lapsByMap[lap.Map] = lapJson; // not needed? Persist(); } public static Lap PB(string mapName) { return lapsByMap[mapName].Laps .MinBy(l => l.TotalTime); } } // Add this magic code, you will be able to use record and init. // I only tested in editor, not sure whether it would work on other platforms. namespace System.Runtime.CompilerServices { class IsExternalInit {} }