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(); } } }