diff --git a/Assets/Src/LapStorage.cs b/Assets/Src/LapService.cs similarity index 64% rename from Assets/Src/LapStorage.cs rename to Assets/Src/LapService.cs index c55793f..81ed3d6 100644 --- a/Assets/Src/LapStorage.cs +++ b/Assets/Src/LapService.cs @@ -16,26 +16,21 @@ public class PlayerData { public Guid Id; } -public class LapFetchService { +public class LapService { static string playerDataPath = Path.Combine(Application.persistentDataPath, "playerData.json"); string _mapName; - PlayerData player; + PlayerData _player; + PbDTO _pb; - public LapFetchService(string mapName) { + public Lap PB; + + public LapService(string mapName) { _mapName = mapName; - try { - string json = File.ReadAllText(playerDataPath); - player = JsonConvert.DeserializeObject(json); - Debug.Log($"Loaded player data {player}"); - } catch { - Debug.Log("No existing playerData.json"); - CreatePlayerData(); - } + LoadPlayerData(); } public IEnumerator GetPb() { - string uri = $"localhost:40080/Pb?userId={player.Id}&mapName={_mapName}"; - // Debug.Log(uri); + string uri = $"localhost:40080/Pb?userId={_player.Id}&mapName={_mapName}"; using (UnityWebRequest req = UnityWebRequest.Get(uri)) { yield return req.SendWebRequest(); @@ -49,21 +44,35 @@ public class LapFetchService { break; case UnityWebRequest.Result.Success: Debug.Log("Received: " + req.downloadHandler.text); + SetPb(req.downloadHandler.text); break; } } } + PbDTO SetPb(string json) { + PbDTO dto = JsonConvert.DeserializeObject(json); + _pb = dto; + + PB = new Lap { + Map = _pb.Map, + Sectors = dto.Sectors.Select((d, i) => new SectorTime { Sector = i + 1, Seconds = d }).ToList(), + }; + + return dto; + } + public IEnumerator PostLap(Lap lap) { LapDTO dto = new LapDTO { Id = Guid.NewGuid(), - UserId = player.Id, + UserId = _player.Id, Map = _mapName, Time = lap.TotalTime, + Sectors = lap.Sectors.Select(s => s.Seconds).ToList(), Created = DateTimeOffset.UtcNow, }; - // Debug.Log(JsonConvert.SerializeObject(dto)); + Debug.Log(JsonConvert.SerializeObject(dto)); using (UnityWebRequest req = UnityWebRequest.Post("localhost:40080/Lap", JsonConvert.SerializeObject(dto), "application/json")) { yield return req.SendWebRequest(); @@ -72,20 +81,25 @@ public class LapFetchService { Debug.Log(req.error); } - Debug.Log("posted lap"); + Debug.Log($"posted lap {dto}"); } } - // laps.count - public int NumberOfCompletions() { return 0; } - - // finds your PB in all completions - public int Position() { return 1; } + void LoadPlayerData() { + try { + string json = File.ReadAllText(playerDataPath); + _player = JsonConvert.DeserializeObject(json); + Debug.Log($"Loaded player data {_player}"); + } catch { + Debug.Log("No existing playerData.json"); + CreatePlayerData(); + } + } PlayerData CreatePlayerData() { - player = new PlayerData { Id = Guid.NewGuid() }; - Debug.Log(JsonConvert.SerializeObject(player)); - File.WriteAllText(playerDataPath, JsonConvert.SerializeObject(player)); - return player; + _player = new PlayerData { Id = Guid.NewGuid() }; + Debug.Log(JsonConvert.SerializeObject(_player)); + File.WriteAllText(playerDataPath, JsonConvert.SerializeObject(_player)); + return _player; } } diff --git a/Assets/Src/LapStorage.cs.meta b/Assets/Src/LapService.cs.meta similarity index 100% rename from Assets/Src/LapStorage.cs.meta rename to Assets/Src/LapService.cs.meta diff --git a/Assets/Src/Laps.cs b/Assets/Src/Laps.cs index f1ae99a..761b9b6 100644 --- a/Assets/Src/Laps.cs +++ b/Assets/Src/Laps.cs @@ -59,14 +59,12 @@ public enum DiffColour { 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; @@ -78,76 +76,3 @@ public class Lap { 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 Position() { 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 {} -} \ No newline at end of file diff --git a/Assets/Src/Timing.cs b/Assets/Src/Timing.cs index 5fd643a..fbd7bdb 100644 --- a/Assets/Src/Timing.cs +++ b/Assets/Src/Timing.cs @@ -11,6 +11,7 @@ using UnityEngine.SceneManagement; public class Timing: MonoBehaviour { TimingUI ui; + LapService lapService; public List sectorTimes; public bool timerEnabled; @@ -25,8 +26,6 @@ public class Timing: MonoBehaviour { IEnumerator noticeLifecycle; - LapFetchService lapFetchService; - void Awake() { ui = GetComponent(); sectorTimes = new List(); @@ -39,10 +38,8 @@ public class Timing: MonoBehaviour { mapName = scene.name; Debug.Log("Track Sector Count - " + sectors.Length); - LapStorageService.GetPlayerLaps(mapName); - - lapFetchService = new LapFetchService(mapName); - StartCoroutine(lapFetchService.GetPb()); + lapService = new LapService(mapName); + StartCoroutine(lapService.GetPb()); } void Update() { @@ -125,8 +122,7 @@ public class Timing: MonoBehaviour { noticeLifecycle = RecentLapLifecycle(l); StartCoroutine(noticeLifecycle); - LapStorageService.PersistLap(l); - StartCoroutine(lapFetchService.PostLap(l)); + StartCoroutine(lapService.PostLap(l)); } IEnumerator RecentLapLifecycle(Lap l) { @@ -135,9 +131,9 @@ public class Timing: MonoBehaviour { ui.HideRecentLap(); } - public Lap PB() => LapStorageService.PB(mapName); + public Lap PB => lapService.PB; - public TimingNotice PBSectorDiff(SectorTime s) => PB() switch { + public TimingNotice PBSectorDiff(SectorTime s) => PB switch { Lap pb => pb.Sectors.SingleOrDefault(fls => fls.Sector == s.Sector) switch { SectorTime fastestSector => (new TimingNotice { Seconds = s.Seconds }).Compare(fastestSector.Seconds), null => new TimingNotice { Seconds = s.Seconds }, // this one should never happen @@ -145,7 +141,7 @@ public class Timing: MonoBehaviour { null => new TimingNotice { Seconds = s.Seconds }, // there is no pb }; - public TimingNotice PBLapDiff(Lap lap) => PB() switch { + public TimingNotice PBLapDiff(Lap lap) => PB switch { Lap pb => (new TimingNotice { Seconds = lap.TotalTime }).Compare(pb.TotalTime), null => new TimingNotice { Seconds = lap.TotalTime }, }; diff --git a/Assets/Src/UI/TimingUI.cs b/Assets/Src/UI/TimingUI.cs index e9cbc63..191d369 100644 --- a/Assets/Src/UI/TimingUI.cs +++ b/Assets/Src/UI/TimingUI.cs @@ -64,7 +64,7 @@ public class TimingUI : MonoBehaviour { if (timerSectors == null) Debug.LogWarning("null timerSectors"); - Lap timerPbLap = timing.PB(); + Lap timerPbLap = timing.PB; if (timerPbLap != null) timerPb.text = $"{timerPbLap.ToString()}"; diff --git a/Server/Controllers/LapController.cs b/Server/Controllers/LapController.cs index 0f2e1c2..2387619 100644 --- a/Server/Controllers/LapController.cs +++ b/Server/Controllers/LapController.cs @@ -37,6 +37,7 @@ public class LapController : ControllerBase { UserId = dto.UserId, Map = dto.Map, Time = dto.Time, + Sectors = dto.Sectors, Created = DateTimeOffset.UtcNow, }; diff --git a/Server/Models/SpaceRaceShared.cs b/Server/Models/SpaceRaceShared.cs index b8fe253..4ad9432 100644 --- a/Server/Models/SpaceRaceShared.cs +++ b/Server/Models/SpaceRaceShared.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; namespace SpaceRace.Shared { public class LapDTO { diff --git a/docker-compose.yaml b/docker-compose.yaml index 2704c5d..c7ff806 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -4,17 +4,17 @@ services: file: common.yaml service: pg - # server: - # image: mcr.microsoft.com/dotnet/sdk:7.0 - # depends_on: - # - 'pg' - # ports: - # - '40080:80' - # environment: - # CONNECTIONSTRINGS__SPACERACE: "Server=pg;Port=5432;Database=${POSTGRES_DB};User Id=${POSTGRES_USER};Password=${POSTGRES_PASSWORD}" - # DOTNET_WATCH_RESTART_ON_RUDE_EDIT: 1 - # command: dotnet watch - # working_dir: "/Server" - # volumes: - # - "./Server:/Server" + server: + image: mcr.microsoft.com/dotnet/sdk:7.0 + depends_on: + - 'pg' + ports: + - '40080:80' + environment: + CONNECTIONSTRINGS__SPACERACE: "Server=pg;Port=5432;Database=${POSTGRES_DB};User Id=${POSTGRES_USER};Password=${POSTGRES_PASSWORD}" + DOTNET_WATCH_RESTART_ON_RUDE_EDIT: 1 + command: dotnet watch + working_dir: "/Server" + volumes: + - "./Server:/Server"