205 lines
6.0 KiB
C#
205 lines
6.0 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using Cysharp.Threading.Tasks;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using Oculus.Interaction;
|
|
using System.IO;
|
|
|
|
namespace GhostSystem
|
|
{
|
|
public class GhostRecorderBatch : MonoBehaviour
|
|
{
|
|
public string SceneId;
|
|
public float SampleRate = 0.05f;
|
|
public int BatchSize = 10;
|
|
public float FlushInterval = 2f;
|
|
|
|
public List<Transform> TrackedObjects;
|
|
private int doorCount;
|
|
|
|
private float _sampleTimer;
|
|
private float _flushTimer;
|
|
private bool _isRecording;
|
|
|
|
private bool supabaseReady = false;
|
|
private bool sceneIdReady = false;
|
|
|
|
private readonly List<FrameModel> _frameBuffer = new();
|
|
|
|
private string _offlinePath;
|
|
|
|
public static event Action OnRecord;
|
|
public static event Action OnStopRecord;
|
|
public static event Action OnUploadFinished;
|
|
|
|
/*private void Awake()
|
|
{
|
|
DontDestroyOnLoad(this);
|
|
}*/
|
|
|
|
private void OnEnable()
|
|
{
|
|
SupabaseManager.OnSuperbaseReady += HandleSupabaseReady;
|
|
RoomManager.OnSceneIdReady += HandleSceneIdReady;
|
|
//StopRecordingTrigger.OnRecordStop += HandleRecordStop;
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
SupabaseManager.OnSuperbaseReady -= HandleSupabaseReady;
|
|
RoomManager.OnSceneIdReady -= HandleSceneIdReady;
|
|
//StopRecordingTrigger.OnRecordStop -= HandleRecordStop;
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
_offlinePath = Path.Combine(Application.persistentDataPath, "offline_log.jsonl");
|
|
}
|
|
|
|
private void HandleSupabaseReady()
|
|
{
|
|
supabaseReady = true;
|
|
}
|
|
|
|
private void HandleSceneIdReady(string id, List<GameObject> doors)
|
|
{
|
|
SceneId = id;
|
|
sceneIdReady = true;
|
|
if (SceneId == "Base")
|
|
{
|
|
_flushTimer = 0f;
|
|
_ = FlushBatchAsync(); // Fire and forget
|
|
}
|
|
else
|
|
{
|
|
foreach (GameObject door in doors)
|
|
{
|
|
var rotator = door.GetComponentInChildren<OneGrabRotateTransformer>();
|
|
if (rotator != null)
|
|
{
|
|
TrackedObjects.Add(rotator.transform);
|
|
doorCount++;
|
|
}
|
|
}
|
|
//StartRecording();
|
|
}
|
|
}
|
|
|
|
/*private void HandleRecordStop()
|
|
{
|
|
StopRecording();
|
|
}*/
|
|
|
|
private void Update()
|
|
{
|
|
if (!_isRecording) return;
|
|
|
|
_sampleTimer += Time.deltaTime;
|
|
_flushTimer += Time.deltaTime;
|
|
|
|
if (_sampleTimer >= SampleRate)
|
|
{
|
|
_sampleTimer = 0f;
|
|
RecordSample();
|
|
}
|
|
|
|
/*if (_frameBuffer.Count >= BatchSize || _flushTimer >= FlushInterval)
|
|
{
|
|
_flushTimer = 0f;
|
|
_ = FlushBatchAsync(); // Fire and forget
|
|
}*/
|
|
}
|
|
|
|
private void RecordSample()
|
|
{
|
|
foreach (var obj in TrackedObjects)
|
|
{
|
|
var frame = new GhostFrame(SceneId, obj.name, obj.position, obj.rotation);
|
|
_frameBuffer.Add(FrameModel.FromGhostFrame(frame));
|
|
}
|
|
}
|
|
|
|
private async UniTaskVoid FlushBatchAsync()
|
|
{
|
|
if (_frameBuffer.Count == 0 || !supabaseReady) return;
|
|
|
|
var batch = new List<FrameModel>(_frameBuffer);
|
|
_frameBuffer.Clear();
|
|
Debug.Log("Flushing Frame Buffer");
|
|
|
|
try
|
|
{
|
|
var response = await SupabaseManager.instance.supabase.From<FrameModel>().Insert(batch);
|
|
if (!response.ResponseMessage.IsSuccessStatusCode)
|
|
{
|
|
Debug.LogWarning($"Batch insert failed: {response.ResponseMessage.StatusCode}, fallback to offline.");
|
|
await FallbackToOfflineAsync(batch);
|
|
}
|
|
if(response.ResponseMessage.IsSuccessStatusCode && sceneIdReady)
|
|
{
|
|
OnUploadFinished?.Invoke();
|
|
Debug.Log("Upload Finished");
|
|
}
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning($"Insert failed, fallback to offline: {ex.Message}");
|
|
await FallbackToOfflineAsync(batch);
|
|
OnUploadFinished?.Invoke();
|
|
Debug.Log("Upload Finished");
|
|
}
|
|
}
|
|
|
|
private async UniTask FallbackToOfflineAsync(List<FrameModel> batch)
|
|
{
|
|
try
|
|
{
|
|
using var writer = new StreamWriter(_offlinePath, append: true);
|
|
foreach (var model in batch)
|
|
{
|
|
string jsonLine = JsonConvert.SerializeObject(model);
|
|
await writer.WriteLineAsync(jsonLine);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogError($"Offline write failed: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
public void StartRecording()
|
|
{
|
|
if (!supabaseReady || !sceneIdReady) return;
|
|
_isRecording = true;
|
|
OnRecord?.Invoke();
|
|
Debug.Log($"Recording {SceneId}");
|
|
}
|
|
|
|
public void StopRecording()
|
|
{
|
|
_isRecording = false;
|
|
sceneIdReady = false;
|
|
OnStopRecord?.Invoke();
|
|
Debug.Log($"Stop recording: {SceneId}");
|
|
|
|
if (doorCount > 0 && TrackedObjects.Count >= doorCount)
|
|
{
|
|
TrackedObjects.RemoveRange(TrackedObjects.Count - doorCount, doorCount);
|
|
}
|
|
|
|
doorCount = 0;
|
|
}
|
|
|
|
public void Flush()
|
|
{
|
|
_flushTimer = 0f;
|
|
//FlushBatchAsync();
|
|
_ = FlushBatchAsync(); // Fire and forget
|
|
}
|
|
}
|
|
}
|
|
|