LapService

This commit is contained in:
ntr committed 2023-08-29 21:05:43 +10:00
1 parent c66c6654c5
commit cebc2ef588
8 files changed
+63 -125

No files matched your search

@@ -16,26 +16,21 @@ public class PlayerData {
public Guid Id; public Guid Id;
} }
public class LapFetchService { public class LapService {
static string playerDataPath = Path.Combine(Application.persistentDataPath, "playerData.json"); static string playerDataPath = Path.Combine(Application.persistentDataPath, "playerData.json");
string _mapName; string _mapName;
PlayerData player; PlayerData _player;
PbDTO _pb;
public LapFetchService(string mapName) { public Lap PB;
public LapService(string mapName) {
_mapName = mapName; _mapName = mapName;
try { LoadPlayerData();
string json = File.ReadAllText(playerDataPath);
player = JsonConvert.DeserializeObject<PlayerData>(json);
Debug.Log($"Loaded player data {player}");
} catch {
Debug.Log("No existing playerData.json");
CreatePlayerData();
}
} }
public IEnumerator GetPb() { public IEnumerator GetPb() {
string uri = $"localhost:40080/Pb?userId={player.Id}&mapName={_mapName}"; string uri = $"localhost:40080/Pb?userId={_player.Id}&mapName={_mapName}";
// Debug.Log(uri);
using (UnityWebRequest req = UnityWebRequest.Get(uri)) { using (UnityWebRequest req = UnityWebRequest.Get(uri)) {
yield return req.SendWebRequest(); yield return req.SendWebRequest();
@@ -49,21 +44,35 @@ public class LapFetchService {
break; break;
case UnityWebRequest.Result.Success: case UnityWebRequest.Result.Success:
Debug.Log("Received: " + req.downloadHandler.text); Debug.Log("Received: " + req.downloadHandler.text);
SetPb(req.downloadHandler.text);
break; break;
} }
} }
} }
PbDTO SetPb(string json) {
PbDTO dto = JsonConvert.DeserializeObject<PbDTO>(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) { public IEnumerator PostLap(Lap lap) {
LapDTO dto = new LapDTO { LapDTO dto = new LapDTO {
Id = Guid.NewGuid(), Id = Guid.NewGuid(),
UserId = player.Id, UserId = _player.Id,
Map = _mapName, Map = _mapName,
Time = lap.TotalTime, Time = lap.TotalTime,
Sectors = lap.Sectors.Select(s => s.Seconds).ToList(),
Created = DateTimeOffset.UtcNow, 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")) { using (UnityWebRequest req = UnityWebRequest.Post("localhost:40080/Lap", JsonConvert.SerializeObject(dto), "application/json")) {
yield return req.SendWebRequest(); yield return req.SendWebRequest();
@@ -72,20 +81,25 @@ public class LapFetchService {
Debug.Log(req.error); Debug.Log(req.error);
} }
Debug.Log("posted lap"); Debug.Log($"posted lap {dto}");
} }
} }
// laps.count void LoadPlayerData() {
public int NumberOfCompletions() { return 0; } try {
string json = File.ReadAllText(playerDataPath);
// finds your PB in all completions _player = JsonConvert.DeserializeObject<PlayerData>(json);
public int Position() { return 1; } Debug.Log($"Loaded player data {_player}");
} catch {
Debug.Log("No existing playerData.json");
CreatePlayerData();
}
}
PlayerData CreatePlayerData() { PlayerData CreatePlayerData() {
player = new PlayerData { Id = Guid.NewGuid() }; _player = new PlayerData { Id = Guid.NewGuid() };
Debug.Log(JsonConvert.SerializeObject(player)); Debug.Log(JsonConvert.SerializeObject(_player));
File.WriteAllText(playerDataPath, JsonConvert.SerializeObject(player)); File.WriteAllText(playerDataPath, JsonConvert.SerializeObject(_player));
return player; return _player;
} }
} }
File renamed without changes.
-75
View File
@@ -59,14 +59,12 @@ public enum DiffColour {
Yellow, Yellow,
} }
[Serializable]
public class SectorTime { public class SectorTime {
public int Sector; public int Sector;
public double Seconds; public double Seconds;
public override string ToString() => $"{Seconds:0.000}"; public override string ToString() => $"{Seconds:0.000}";
} }
[Serializable]
public class Lap { public class Lap {
public string Map; public string Map;
public List<SectorTime> Sectors; public List<SectorTime> Sectors;
@@ -78,76 +76,3 @@ public class Lap {
public double TotalTime => Sectors.Sum(s => s.Seconds); public double TotalTime => Sectors.Sum(s => s.Seconds);
} }
[Serializable]
public class LapJSON {
public string Map;
public List<Lap> 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<LapJSON> Laps = new();
}
static class LapStorageService {
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 EnsureMap(mapName);
return currentLaps;
}
public static LapJSON EnsureMap(string mapName) {
LapJSON lapJson = new LapJSON { Map = mapName, Laps = new List<Lap>() };
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 {}
}
+7 -11
View File
@@ -11,6 +11,7 @@ using UnityEngine.SceneManagement;
public class Timing: MonoBehaviour { public class Timing: MonoBehaviour {
TimingUI ui; TimingUI ui;
LapService lapService;
public List<SectorTime> sectorTimes; public List<SectorTime> sectorTimes;
public bool timerEnabled; public bool timerEnabled;
@@ -25,8 +26,6 @@ public class Timing: MonoBehaviour {
IEnumerator noticeLifecycle; IEnumerator noticeLifecycle;
LapFetchService lapFetchService;
void Awake() { void Awake() {
ui = GetComponent<TimingUI>(); ui = GetComponent<TimingUI>();
sectorTimes = new List<SectorTime>(); sectorTimes = new List<SectorTime>();
@@ -39,10 +38,8 @@ public class Timing: MonoBehaviour {
mapName = scene.name; mapName = scene.name;
Debug.Log("Track Sector Count - " + sectors.Length); Debug.Log("Track Sector Count - " + sectors.Length);
LapStorageService.GetPlayerLaps(mapName); lapService = new LapService(mapName);
StartCoroutine(lapService.GetPb());
lapFetchService = new LapFetchService(mapName);
StartCoroutine(lapFetchService.GetPb());
} }
void Update() { void Update() {
@@ -125,8 +122,7 @@ public class Timing: MonoBehaviour {
noticeLifecycle = RecentLapLifecycle(l); noticeLifecycle = RecentLapLifecycle(l);
StartCoroutine(noticeLifecycle); StartCoroutine(noticeLifecycle);
LapStorageService.PersistLap(l); StartCoroutine(lapService.PostLap(l));
StartCoroutine(lapFetchService.PostLap(l));
} }
IEnumerator RecentLapLifecycle(Lap l) { IEnumerator RecentLapLifecycle(Lap l) {
@@ -135,9 +131,9 @@ public class Timing: MonoBehaviour {
ui.HideRecentLap(); 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 { Lap pb => pb.Sectors.SingleOrDefault(fls => fls.Sector == s.Sector) switch {
SectorTime fastestSector => (new TimingNotice { Seconds = s.Seconds }).Compare(fastestSector.Seconds), SectorTime fastestSector => (new TimingNotice { Seconds = s.Seconds }).Compare(fastestSector.Seconds),
null => new TimingNotice { Seconds = s.Seconds }, // this one should never happen 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 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), Lap pb => (new TimingNotice { Seconds = lap.TotalTime }).Compare(pb.TotalTime),
null => new TimingNotice { Seconds = lap.TotalTime }, null => new TimingNotice { Seconds = lap.TotalTime },
}; };
+1 -1
View File
@@ -64,7 +64,7 @@ public class TimingUI : MonoBehaviour {
if (timerSectors == null) if (timerSectors == null)
Debug.LogWarning("null timerSectors"); Debug.LogWarning("null timerSectors");
Lap timerPbLap = timing.PB(); Lap timerPbLap = timing.PB;
if (timerPbLap != null) if (timerPbLap != null)
timerPb.text = $"{timerPbLap.ToString()}"; timerPb.text = $"{timerPbLap.ToString()}";
+1
View File
@@ -37,6 +37,7 @@ public class LapController : ControllerBase {
UserId = dto.UserId, UserId = dto.UserId,
Map = dto.Map, Map = dto.Map,
Time = dto.Time, Time = dto.Time,
Sectors = dto.Sectors,
Created = DateTimeOffset.UtcNow, Created = DateTimeOffset.UtcNow,
}; };
+2
View File
@@ -1,4 +1,6 @@
using System; using System;
using System.Collections;
using System.Collections.Generic;
namespace SpaceRace.Shared { namespace SpaceRace.Shared {
public class LapDTO { public class LapDTO {
+13 -13
View File
@@ -4,17 +4,17 @@ services:
file: common.yaml file: common.yaml
service: pg service: pg
# server: server:
# image: mcr.microsoft.com/dotnet/sdk:7.0 image: mcr.microsoft.com/dotnet/sdk:7.0
# depends_on: depends_on:
# - 'pg' - 'pg'
# ports: ports:
# - '40080:80' - '40080:80'
# environment: environment:
# CONNECTIONSTRINGS__SPACERACE: "Server=pg;Port=5432;Database=${POSTGRES_DB};User Id=${POSTGRES_USER};Password=${POSTGRES_PASSWORD}" CONNECTIONSTRINGS__SPACERACE: "Server=pg;Port=5432;Database=${POSTGRES_DB};User Id=${POSTGRES_USER};Password=${POSTGRES_PASSWORD}"
# DOTNET_WATCH_RESTART_ON_RUDE_EDIT: 1 DOTNET_WATCH_RESTART_ON_RUDE_EDIT: 1
# command: dotnet watch command: dotnet watch
# working_dir: "/Server" working_dir: "/Server"
# volumes: volumes:
# - "./Server:/Server" - "./Server:/Server"