using Godot;
using System;
using System.Threading.Tasks;
using BSEnroll; // Namespace for UserDataManager
///
/// Mutable for surfacing upload progress
///
public class UploadProgress
{
public TestAcquisition acquisition;
private float current;
public float Current
{
get => current;
set
{
current = value;
// Use deferred to ensure the signal emission happens on the main thread
acquisition.CallDeferred("emit_signal", TestAcquisition.SignalName.UploadProgression, value);
}
}
}
///
/// Test script to demonstrate the use of the AcquisitionManager.
///
[GlobalClass]
public partial class TestAcquisition : Node3D
{
[Export]
public Camera3D VrCamera { get; set; }
[Export]
public XROrigin3D XrOrigin { get; set; }
[Export]
public Node3D Target { get; set; }
private UploadProgress _uploadProgress;
private AcquisitionManager _acquisitionManager;
private bool _isRecording = false;
[Signal]
public delegate void RecordingErrorEventHandler(string error);
[Signal]
public delegate void RecordingResultEventHandler(string error);
[Signal]
public delegate void UploadStatusEventHandler(string error);
[Signal]
public delegate void UploadProgressionEventHandler(double progress);
[Export]
public Vector2 TargetInScreenSpace
{
get
{
return _acquisitionManager.TargetInScreenSpace;
}
private set { }
}
///
/// Called when the node enters the scene tree for the first time.
///
public override void _Ready()
{
GetTree().AutoAcceptQuit = false;
// Check required references
if (VrCamera == null || XrOrigin == null || Target == null)
{
GD.PrintErr("Missing required references. Please assign VrCamera, XrOrigin, and Target in the Inspector.");
EmitSignal(SignalName.RecordingError, "Required scene resources not found.");
return;
}
_uploadProgress = new UploadProgress();
_uploadProgress.acquisition = this;
// Create the acquisition manager
_acquisitionManager = new AcquisitionManager();
_acquisitionManager.VrCamera = VrCamera;
_acquisitionManager.XrOrigin = XrOrigin;
_acquisitionManager.Target = Target;
_acquisitionManager.AcquisitionSource = this;
AddChild(_acquisitionManager);
}
///
/// When the user closes the app
///
public override void _Notification(int what)
{
if (what == NotificationWMCloseRequest)
{
_acquisitionManager.AppQuitting = true;
GD.Print("Received application quit request");
// Restore brightness
if (_acquisitionManager != null && _acquisitionManager.OriginalHeadsetBrightness > 0)
{
GD.Print("Restores headset brightness back to: " + _acquisitionManager.OriginalHeadsetBrightness);
_acquisitionManager.ForceHeadsetBrightness(_acquisitionManager.OriginalHeadsetBrightness);
}
GetTree().Quit(); // default behavior
}
}
public bool HasDoneEnrollment()
{
return _acquisitionManager != null && _acquisitionManager.etSettings != null && _acquisitionManager.etSettings.downloaded_models.Count > 0;
}
///
/// Called every frame.
///
public override void _Process(double delta)
{
// All recording and uploading is now handled automatically
// No need to check for key presses
}
///
/// Flags the data recorder to write blink notation.
///
public void Set_DemoBlinkingNotation(int opened)
{
_acquisitionManager.DemoBlinkNotation = opened;
}
///
/// Starts the recording process.
///
public void Wrap_StartRecording()
{
StartRecording();
}
private async Task StartRecording()
{
if (_isRecording)
{
GD.Print("Already recording");
return;
}
GD.Print("Starting recording...");
try
{
bool success = await _acquisitionManager.Start();
if (success)
{
_isRecording = true;
GD.Print("Recording started");
}
else
{
GD.PrintErr("Failed to start recording");
EmitSignal(SignalName.RecordingError, "Failed to start recording.");
}
}
catch (Exception ex)
{
GD.PrintErr("Failed to start recording: " + ex.Message);
EmitSignal(SignalName.RecordingError, ex.Message);
}
}
///
/// Stops the recording process and automatically starts the upload.
///
public void Wrap_StopRecording()
{
StopRecording();
}
private async Task StopRecording()
{
if (!_isRecording)
{
GD.Print("Not recording");
return;
}
GD.Print("Stopping recording...");
await _acquisitionManager.Stop();
_isRecording = false;
EmitSignal(SignalName.RecordingResult, "Success");
GD.Print("Recording stopped automatically - Starting upload process");
// Automatically start the upload process
await UploadData();
}
///
/// Pauses the recording process.
///
public void Wrap_PauseRecording()
{
PauseRecording();
}
private async Task PauseRecording()
{
if (!_isRecording)
{
GD.Print("Not recording");
return;
}
if (_acquisitionManager.IsPaused)
{
GD.Print("Already paused");
return;
}
GD.Print("Pausing recording...");
bool success = _acquisitionManager.Pause();
if (success)
{
GD.Print("Recording paused - Will automatically resume after 2 seconds");
}
else
{
GD.PrintErr("Failed to pause recording");
}
}
///
/// Resumes the recording process.
///
public void Wrap_ResumeRecording()
{
ResumeRecording();
}
private async Task ResumeRecording()
{
if (!_isRecording)
{
GD.Print("Not recording");
return;
}
if (!_acquisitionManager.IsPaused)
{
GD.Print("Not paused");
return;
}
GD.Print("Resuming recording...");
bool success = _acquisitionManager.Resume();
if (success)
{
GD.Print("Recording resumed");
}
else
{
GD.PrintErr("Failed to resume recording");
}
}
///
/// Uploads the recorded data.
///
private async Task UploadData()
{
// Make sure recording is stopped
if (_isRecording)
{
await StopRecording();
}
GD.Print("Uploading data...");
EmitSignal(SignalName.UploadStatus, "Uploading");
try
{
// Upload with user ID from UserDataManager
bool success = await _acquisitionManager.UploadData(userId: UserDataManager.Instance.UserId, progress: _uploadProgress);
if (success)
{
GD.Print("Data uploaded successfully");
EmitSignal(SignalName.UploadStatus, "Success");
}
else
{
GD.PrintErr("Failed to upload data");
EmitSignal(SignalName.UploadStatus, "Failed to process capture.");
}
}
catch (Exception ex)
{
EmitSignal(SignalName.UploadStatus, ex.Message);
}
}
///
/// Called when the node is about to be removed from the scene.
///
public override void _ExitTree()
{
// Make sure to stop recording and clean up
if (_isRecording)
{
_ = StopRecording();
}
}
}