Files
RoomAwareVR/Assets/_Scripts/GhostSystem/GhostReplayManager.cs
T
2025-05-26 01:23:52 +02:00

232 lines
7.4 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System.Threading.Tasks;
using System;
using System.Reactive;
using UnityEngine.UI;
namespace GhostSystem
{
public class GhostReplayManager : MonoBehaviour
{
[Header("Replay Settings")]
public string SceneId;
public string UserFilter = null; // optional: filtere nach User-ID
public bool Loop = true;
public DateTime selectedStartTime;
public DateSelector dateSelector;
[Header("Target Objects")]
public List<TrackedObjectBinding> TrackedObjects;
[Header("Playback")]
public float PlaybackSpeed = 1f;
public bool AutoStart = true;
public Slider playbackSlider;
private bool isScrubbing = false;
private bool isPlaying = false;
private float playbackTime = 0f;
private float totalDuration = 0f;
private Dictionary<string, List<FrameModel>> objectTracks = new();
private bool supabaseReady = false;
private bool sceneIdReady = false;
private string loadedSceneId;
[Serializable]
public class TrackedObjectBinding
{
public string objectId;
public GameObject targetObject;
}
private async void OnEnable()
{
SupabaseManager.OnSuperbaseReady += HandleSupabaseReady;
RoomManager.OnSceneIdReady += HandleSceneIdReady;
}
private void OnDisable()
{
SupabaseManager.OnSuperbaseReady -= HandleSupabaseReady;
RoomManager.OnSceneIdReady -= HandleSceneIdReady;
}
private void HandleSupabaseReady()
{
supabaseReady = true;
TryInitializeReplay();
}
private void HandleSceneIdReady(string id)
{
sceneIdReady = true;
loadedSceneId = id;
TryInitializeReplay();
}
private async void TryInitializeReplay()
{
if (!supabaseReady || !sceneIdReady) return;
SceneId = loadedSceneId;
await LoadFrames();
StartReplay();
}
public async Task LoadFrames()
{
Debug.Log("SceneId used in query: " + SceneId);
var query = SupabaseManager.instance.supabase
.From<FrameModel>()
.Filter("scene_id", Postgrest.Constants.Operator.Equals, SceneId)
.Filter("timestamp", Postgrest.Constants.Operator.GreaterThanOrEqual, dateSelector.selectedDateTime().ToString("o"))
.Order("timestamp", Postgrest.Constants.Ordering.Ascending);
if (!string.IsNullOrEmpty(UserFilter))
query = query.Filter("user_id", Postgrest.Constants.Operator.Equals, UserFilter);
var result = await query.Get();
var frames = result.Models;
Debug.LogError("Frames: " + frames.Count);
objectTracks.Clear();
foreach (var frame in frames)
{
if (!objectTracks.ContainsKey(frame.ObjectId))
objectTracks[frame.ObjectId] = new List<FrameModel>();
objectTracks[frame.ObjectId].Add(frame);
//Debug.Log($"Loaded frame: {frame.ObjectId} at {frame.Timestamp}");
Debug.Log($"Loaded frame: {frame.ObjectId} at {frame.TimestampParsed} Pos: {frame.Position}");
Debug.Log($"Parsed timestamp: {frame.Timestamp} -> {frame.TimestampParsed.ToString("o")}" + "Pos JSON: " + frame.PositionJson);
}
Debug.LogWarning("Got the Data!");
Debug.LogWarning(objectTracks.Count);
// Gesamtzeit berechnen (in Sekunden)
if (frames.Count > 1)
{
totalDuration = (float)(frames.Last().TimestampParsed - frames.First().TimestampParsed).TotalSeconds;
}
}
public void StartReplay() // Für das Play UI-Element, um das Replay zu starten
{
isPlaying = true;
playbackTime = 0f;
Debug.LogError("Replay started: total duration = " + totalDuration);
}
public void PauseReplay() => isPlaying = false; // Für das Pause UI-Element, um das Replay zu pausieren
public void StopReplay() // Für das Stop UI-Element, um das Replay zu beenden
{
isPlaying = false;
playbackTime = 0f;
}
public void SetPlaybackTime(float time) // Für das Slider UI-Element zum Scrubben
{
playbackTime = Mathf.Clamp(time, 0f, totalDuration);
}
private void Update()
{
if (!isPlaying || objectTracks.Count == 0)
return;
playbackTime += Time.deltaTime * PlaybackSpeed;
if (playbackTime > totalDuration)
{
if (Loop)
playbackTime = 0f;
else
isPlaying = false;
}
DateTime currentTimestamp = objectTracks.Values
.SelectMany(list => list)
.First().TimestampParsed + TimeSpan.FromSeconds(playbackTime);
foreach (var binding in TrackedObjects)
{
if (!objectTracks.ContainsKey(binding.objectId))
continue;
var frames = objectTracks[binding.objectId];
if (frames.Count < 2)
continue;
FrameModel a = null, b = null;
for (int i = 0; i < frames.Count - 1; i++)
{
var tA = frames[i].TimestampParsed;
var tB = frames[i + 1].TimestampParsed;
if (tA <= currentTimestamp && tB >= currentTimestamp)
{
a = frames[i];
b = frames[i + 1];
break;
}
}
if (a != null && b != null)
{
double tA = a.TimestampParsed.Subtract(DateTime.UnixEpoch).TotalSeconds;
double tB = b.TimestampParsed.Subtract(DateTime.UnixEpoch).TotalSeconds;
double tCurrent = currentTimestamp.Subtract(DateTime.UnixEpoch).TotalSeconds;
float t = Mathf.Clamp01((float)((tCurrent - tA) / (tB - tA)));
Vector3 pos = Vector3.Lerp(a.Position, b.Position, t);
Quaternion rot = Quaternion.Slerp(a.Rotation, b.Rotation, t);
binding.targetObject.transform.SetPositionAndRotation(pos, rot);
}
}
if (!isScrubbing && playbackSlider != null && totalDuration > 0f)
{
playbackSlider.value = playbackTime / totalDuration;
}
}
/*public void OnSliderValueChanged(float value)
{
if (totalDuration <= 0f) return;
isScrubbing = true;
SetPlaybackTime(value * totalDuration);
}*/
public void SetSliderScrubValue(float sliderValue)
{
if (isScrubbing)
SetPlaybackTime(sliderValue * totalDuration);
}
public void OnSliderStartDrag()
{
isScrubbing = true;
}
public void OnSliderEndDrag()
{
isScrubbing = false;
SetPlaybackTime(playbackSlider.value * totalDuration);
}
}
}