From c579721f9ccfa3845722712e46eb502985168062 Mon Sep 17 00:00:00 2001 From: Marlus Wellmann Date: Thu, 9 Apr 2026 16:00:23 +0200 Subject: [PATCH 01/10] fix: changed LICENSE to md and added metafile --- LICENSE => LICENSE.md | 0 LICENSE.md.meta | 7 +++++++ 2 files changed, 7 insertions(+) rename LICENSE => LICENSE.md (100%) create mode 100644 LICENSE.md.meta diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/LICENSE.md.meta b/LICENSE.md.meta new file mode 100644 index 0000000..cb1e8f5 --- /dev/null +++ b/LICENSE.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 19cc458417b2b8741953fcb6487d7dfe +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From fa824670eebcb34a6e1da1bba709abd42b8322fa Mon Sep 17 00:00:00 2001 From: Marlus Wellmann Date: Thu, 9 Apr 2026 17:10:18 +0200 Subject: [PATCH 02/10] fix: fixed typo in RegistartionUI.prefab --- Runtime/{RegistartionUI.prefab => RegistrationUI.prefab} | 8 ++++++-- ...istartionUI.prefab.meta => RegistrationUI.prefab.meta} | 0 2 files changed, 6 insertions(+), 2 deletions(-) rename Runtime/{RegistartionUI.prefab => RegistrationUI.prefab} (99%) rename Runtime/{RegistartionUI.prefab.meta => RegistrationUI.prefab.meta} (100%) diff --git a/Runtime/RegistartionUI.prefab b/Runtime/RegistrationUI.prefab similarity index 99% rename from Runtime/RegistartionUI.prefab rename to Runtime/RegistrationUI.prefab index c300f71..199fe84 100644 --- a/Runtime/RegistartionUI.prefab +++ b/Runtime/RegistrationUI.prefab @@ -105,6 +105,7 @@ MonoBehaviour: m_VerticalAlignment: 256 m_textAlignment: 65535 m_characterSpacing: 0 + m_characterHorizontalScale: 1 m_wordSpacing: 0 m_lineSpacing: 0 m_lineSpacingMax: 0 @@ -274,6 +275,7 @@ MonoBehaviour: m_VerticalAlignment: 256 m_textAlignment: 65535 m_characterSpacing: 0 + m_characterHorizontalScale: 1 m_wordSpacing: 0 m_lineSpacing: 0 m_lineSpacingMax: 0 @@ -410,6 +412,7 @@ MonoBehaviour: m_VerticalAlignment: 256 m_textAlignment: 65535 m_characterSpacing: 0 + m_characterHorizontalScale: 1 m_wordSpacing: 0 m_lineSpacing: 0 m_lineSpacingMax: 0 @@ -623,6 +626,7 @@ MonoBehaviour: m_VerticalAlignment: 512 m_textAlignment: 65535 m_characterSpacing: 0 + m_characterHorizontalScale: 1 m_wordSpacing: 0 m_lineSpacing: 0 m_lineSpacingMax: 0 @@ -702,7 +706,7 @@ GameObject: - component: {fileID: 7148892776856201653} - component: {fileID: 6634393656915495675} m_Layer: 5 - m_Name: RegistartionUI + m_Name: RegistrationUI m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -776,7 +780,7 @@ MonoBehaviour: m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 m_DynamicPixelsPerUnit: 1 - m_PresetInfoIsWorld: 0 + m_PresetInfoIsWorld: 1 --- !u!114 &7148892776856201653 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Runtime/RegistartionUI.prefab.meta b/Runtime/RegistrationUI.prefab.meta similarity index 100% rename from Runtime/RegistartionUI.prefab.meta rename to Runtime/RegistrationUI.prefab.meta From 6b5c7da67da760a980e68198c628f0f923c095e3 Mon Sep 17 00:00:00 2001 From: Marlus Wellmann Date: Fri, 10 Apr 2026 00:01:43 +0200 Subject: [PATCH 03/10] refactor: changed RegistrationVrController so it is inheritable * This is needed to be able to create a version which supports Unity XRI Rigs instead of Meta [BuildingBlock] Camera Rig --- Runtime/Scripts/RegistrationVrController.cs | 63 ++++++++++++--------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/Runtime/Scripts/RegistrationVrController.cs b/Runtime/Scripts/RegistrationVrController.cs index 00cd4a7..870f45a 100644 --- a/Runtime/Scripts/RegistrationVrController.cs +++ b/Runtime/Scripts/RegistrationVrController.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using UnityEngine; /// @@ -18,19 +17,24 @@ public class RegistrationVrController : MonoBehaviour [SerializeField] private bool calibrateObject; [HideInInspector] public GameObject controllerInUse; - private Calibrator _calibrator; - private Vector3 _tipPosition; + protected Calibrator _calibrator; + protected Vector3 _tipPosition; private GameObject _demoObject; private bool _isRecordingTipPosition; - private List _tipPositionsOverTime = new List(); + private readonly List _tipPositionsOverTime = new List(); public readonly Vector3 PredefinedTipPosition = new Vector3(0.01211928f,-0.08250856f,-0.08393941f); + + protected Handedness ControllerSelection => controllerSelection; + protected bool CalibrateObject => calibrateObject; + protected virtual float TipForwardOffset => 0.06f; + public enum Handedness { RightHanded, LeftHanded } - private void Awake() + protected virtual void Awake() { _calibrator = gameObject.AddComponent(); SetupController(); @@ -41,7 +45,7 @@ private void Awake() } - private void Start() + protected virtual void Start() { if (calibrateObject) registration.SetState(Registration.State.Calibration); @@ -50,7 +54,7 @@ private void Start() _calibrator.SetRelativePostition(PredefinedTipPosition); } - private void OnStateChanged() + protected virtual void OnStateChanged() { switch (registration.currentState) { @@ -66,18 +70,23 @@ private void OnStateChanged() } } - private void OnEnable() + protected virtual void OnEnable() { SetupController(); } - private void SetupController() + protected virtual void OnDisable() + { + } + + protected virtual void SetupController() { controllerInUse = SearchForController(controllerSelection); - _calibrator.toCalibrate = controllerInUse; + if (_calibrator != null) + _calibrator.toCalibrate = controllerInUse; } - private void Update() + protected virtual void Update() { if (registration.currentState == Registration.State.Inactive) return; switch (registration.currentState) @@ -94,7 +103,7 @@ private void Update() } } - private void CalibrationActions() + protected virtual void CalibrationActions() { UpdateTipPosition(); UpdateDemoObject(); @@ -110,7 +119,7 @@ private void CalibrationActions() } - private void MarkerStateActions() + protected virtual void MarkerStateActions() { UpdateTipPosition(); UpdateDemoObject(); @@ -121,7 +130,7 @@ private void MarkerStateActions() RightHandMarkerInteractions(); } - private void ConfirmationStateActions() + protected virtual void ConfirmationStateActions() { if (CommitButtonPressed()) { @@ -135,17 +144,17 @@ private void ConfirmationStateActions() } } - private void UpdateTipPosition() + protected virtual void UpdateTipPosition() { if (calibrateObject) _tipPosition = _calibrator.GetCalibratedCurrentPosition(); else if (controllerInUse != null) - _tipPosition = controllerInUse.transform.position + controllerInUse.transform.forward * 0.06f; + _tipPosition = controllerInUse.transform.position + controllerInUse.transform.forward * TipForwardOffset; else Debug.LogWarning("No Controller in Use!"); } - private void UpdateDemoObject() + protected virtual void UpdateDemoObject() { if (_demoObject == null) return; @@ -153,19 +162,20 @@ private void UpdateDemoObject() Helper.SetColor(_demoObject, Helper.GetColorForIndex(registration.markers.Count)); } - private void RightHandMarkerInteractions() + protected virtual void RightHandMarkerInteractions() { if (_isRecordingTipPosition && AnyTriggerUp()) EndRecordingTipPosition(); if (!_isRecordingTipPosition && AnyTriggerDown()) StartRecordingTipPosition(); if (CancelButtonPressed()) registration.ResetEverything(); } - private void StartRecordingTipPosition() + protected virtual void StartRecordingTipPosition() { _isRecordingTipPosition = true; _tipPositionsOverTime.Clear(); } - private void EndRecordingTipPosition() + + protected virtual void EndRecordingTipPosition() { if(_tipPositionsOverTime == null || _tipPositionsOverTime.Count < 1)return; _isRecordingTipPosition = false; @@ -175,7 +185,8 @@ private void EndRecordingTipPosition() _tipPositionsOverTime.Clear(); registration.AddMarker(midPoint); } - private GameObject SearchForController(Handedness handedness) + + protected virtual GameObject SearchForController(Handedness handedness) { string controllerName = handedness == Handedness.RightHanded ? "RightControllerAnchor" : "LeftControllerAnchor"; @@ -183,7 +194,7 @@ private GameObject SearchForController(Handedness handedness) return controllerToUse; } - private void LeftHandMarkerInteractions() + protected virtual void LeftHandMarkerInteractions() { if (OVRInput.GetDown(OVRInput.Button.One, OVRInput.Controller.LTouch)) { @@ -191,23 +202,23 @@ private void LeftHandMarkerInteractions() } } - private static bool CommitButtonPressed() + protected virtual bool CommitButtonPressed() { return OVRInput.GetDown(OVRInput.Button.One, OVRInput.Controller.RTouch); } - private static bool CancelButtonPressed() + protected virtual bool CancelButtonPressed() { return OVRInput.GetDown(OVRInput.Button.Two, OVRInput.Controller.RTouch); } - private static bool AnyTriggerDown() + protected virtual bool AnyTriggerDown() { return OVRInput.GetDown(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.RTouch) || OVRInput.GetDown(OVRInput.Button.PrimaryIndexTrigger, OVRInput.Controller.RTouch); } - private static bool AnyTriggerUp() + protected virtual bool AnyTriggerUp() { return OVRInput.GetUp(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.RTouch) || OVRInput.GetUp(OVRInput.Button.PrimaryIndexTrigger, OVRInput.Controller.RTouch); From e7f548107f949a2e658e9ff16b078fea1a0decde Mon Sep 17 00:00:00 2001 From: Marlus Wellmann Date: Fri, 10 Apr 2026 13:30:31 +0200 Subject: [PATCH 04/10] feat: modifications to switch scene after alignment --- Runtime/Scripts/AnchorLoader.cs | 34 ++++--- Runtime/Scripts/AnchorLoaderManager.cs | 119 +++++++++++++++++++++++-- Runtime/Scripts/Registration.cs | 97 ++++++++++++++++---- 3 files changed, 216 insertions(+), 34 deletions(-) diff --git a/Runtime/Scripts/AnchorLoader.cs b/Runtime/Scripts/AnchorLoader.cs index 0a19b75..90ad823 100644 --- a/Runtime/Scripts/AnchorLoader.cs +++ b/Runtime/Scripts/AnchorLoader.cs @@ -37,7 +37,10 @@ public async void LoadAnchorsByUuid(RegiTarget target) RemoveExistingAnchor(target); var uuids = LoadAnchorUuidsFromPrefs(); - if (uuids.Length == 0) return; + if (uuids.Length == 0) + { + return; + } _spatialAnchorManager.Uuids.AddRange(uuids); @@ -63,35 +66,40 @@ private Guid[] LoadAnchorUuidsFromPrefs() if (!PlayerPrefs.HasKey(key)) PlayerPrefs.SetInt(key, 0); - int count = PlayerPrefs.GetInt(key); - if (count == 0) + int storedCount = PlayerPrefs.GetInt(key); + if (storedCount == 0) return Array.Empty(); - var uuids = new Guid[count]; - for (int i = 0; i < count; i++) + var uuids = new List(storedCount); + for (int i = 0; i < storedCount; i++) { var uuidStr = PlayerPrefs.GetString("uuid" + i, string.Empty); - if (Guid.TryParse(uuidStr, out var uuid)) + if (Guid.TryParse(uuidStr, out var uuid) && uuid != Guid.Empty) { - uuids[i] = uuid; + uuids.Add(uuid); } else { - Debug.LogWarning($"Invalid UUID at index {i}: {uuidStr}"); + Debug.LogWarning($"[AnchorLoader] Invalid UUID at key 'uuid{i}': '{uuidStr}'"); } } - return uuids; + return uuids.ToArray(); } private async Task> LoadUnboundAnchorsAsync(Guid[] uuids) { var unboundAnchors = new List(); - var result = await OVRSpatialAnchor.LoadUnboundAnchorsAsync(uuids, unboundAnchors); + var loadTask = OVRSpatialAnchor.LoadUnboundAnchorsAsync(uuids, unboundAnchors); + while (!loadTask.IsCompleted) + { + await Task.Yield(); + } + var result = loadTask.GetResult(); if (!result.Success) { - Debug.LogError($"Load anchors failed with status: {result.Status}"); + Debug.LogError($"[AnchorLoader] Load anchors failed. status={result.Status}"); return new List(); } @@ -111,7 +119,7 @@ private void OnLocalized(bool success, OVRSpatialAnchor.UnboundAnchor unboundAnc { if (!success) { - Debug.Log("NO SUCCESS"); + Debug.LogWarning("[AnchorLoader] Localization failed for one unbound anchor."); return; } unboundAnchor.TryGetPose(out Pose pose); @@ -122,4 +130,4 @@ private void OnLocalized(bool success, OVRSpatialAnchor.UnboundAnchor unboundAnc unboundAnchor.BindTo(LoadedObject.gameObject.GetComponent()); _spatialAnchorManager.LinkNewAnchor(spatialAnchor); } -} \ No newline at end of file +} diff --git a/Runtime/Scripts/AnchorLoaderManager.cs b/Runtime/Scripts/AnchorLoaderManager.cs index 8f9359b..e9198b1 100644 --- a/Runtime/Scripts/AnchorLoaderManager.cs +++ b/Runtime/Scripts/AnchorLoaderManager.cs @@ -15,6 +15,20 @@ /// public class AnchorLoaderManager : MonoBehaviour { + public readonly struct SaveAnchorOutcome + { + public bool Persisted { get; } + public Guid Uuid { get; } + public string Status { get; } + + public SaveAnchorOutcome(bool persisted, Guid uuid, string status) + { + Persisted = persisted; + Uuid = uuid; + Status = status; + } + } + public string numUuidsPlayerPref = "NumUuids"; public List anchors; public AnchorLoader AnchorLoader; @@ -41,7 +55,6 @@ public async Task DeleteAllAnchors() Uuids.Clear(); anchors.Clear(); - Debug.Log($"Anchors erased."); DeleteSavedUuids(); } @@ -52,8 +65,46 @@ public void LinkNewAnchor(OVRSpatialAnchor anchor) public void SaveAnchor(OVRSpatialAnchor anchor) { - anchor.SaveAnchorAsync(); - SaveUuid(anchor.Uuid); + _ = SaveAnchorAndPersistIfValidAsync(anchor); + } + + public async Task SaveAnchorAndPersistIfValidAsync(OVRSpatialAnchor anchor) + { + if (anchor == null) + { + Debug.LogWarning("[AnchorLoaderManager] SaveAnchorAndPersistIfValidAsync called with null anchor."); + return new SaveAnchorOutcome(false, Guid.Empty, "NullAnchor"); + } + + Guid initialUuid = anchor.Uuid; + + try + { + var saveTask = anchor.SaveAnchorAsync(); + while (!saveTask.IsCompleted) + { + await Task.Yield(); + } + + object saveResult = saveTask.GetResult(); + bool success = TryGetResultSuccess(saveResult, false); + string status = GetResultStatus(saveResult); + Guid finalUuid = anchor.Uuid; + + if (!success || finalUuid == Guid.Empty) + { + Debug.LogWarning($"[AnchorLoaderManager] Not persisting UUID. saveSuccess={success}, finalUuid={finalUuid}, status={status}"); + return new SaveAnchorOutcome(false, finalUuid, status); + } + + OverwriteSavedUuids(finalUuid); + return new SaveAnchorOutcome(true, finalUuid, status); + } + catch (Exception ex) + { + Debug.LogError($"[AnchorLoaderManager] SaveAnchorAsync threw for uuid={initialUuid}: {ex}"); + return new SaveAnchorOutcome(false, Guid.Empty, "Exception"); + } } private void SaveUuid(Guid uuid) @@ -64,7 +115,8 @@ private void SaveUuid(Guid uuid) } int playerNumUuids = PlayerPrefs.GetInt(numUuidsPlayerPref); - PlayerPrefs.SetString("uuid" + playerNumUuids, uuid.ToString()); + string key = "uuid" + playerNumUuids; + PlayerPrefs.SetString(key, uuid.ToString()); PlayerPrefs.SetInt(numUuidsPlayerPref, ++playerNumUuids); PlayerPrefs.Save(); } @@ -72,13 +124,18 @@ private void SaveUuid(Guid uuid) private void DeleteSavedUuids() { if (!PlayerPrefs.HasKey(numUuidsPlayerPref)) + { return; + } + int numUuids = PlayerPrefs.GetInt(numUuidsPlayerPref); for (int i = 0; i < numUuids; i++) { string key = $"uuid{i}"; if (PlayerPrefs.HasKey(key)) + { PlayerPrefs.DeleteKey(key); + } } PlayerPrefs.DeleteKey(numUuidsPlayerPref); @@ -97,4 +154,56 @@ private IEnumerator AnchorCreated(OVRSpatialAnchor instancedAnchor) tracker.uuidName = anchorGuid; anchors.Add(instancedAnchor); } -} \ No newline at end of file + + public List GetSavedUuids() + { + var result = new List(); + if (!PlayerPrefs.HasKey(numUuidsPlayerPref)) + return result; + + int numUuids = PlayerPrefs.GetInt(numUuidsPlayerPref); + for (int i = 0; i < numUuids; i++) + { + string uuidString = PlayerPrefs.GetString($"uuid{i}", string.Empty); + if (Guid.TryParse(uuidString, out Guid uuid) && uuid != Guid.Empty) + { + result.Add(uuid); + } + else if (!string.IsNullOrWhiteSpace(uuidString)) + { + Debug.LogWarning($"[AnchorLoaderManager] Invalid UUID in PlayerPrefs key 'uuid{i}': '{uuidString}'"); + } + } + + return result; + } + + private static bool TryGetResultSuccess(object result, bool defaultValue) + { + if (result == null) + return defaultValue; + + Type resultType = result.GetType(); + var successProperty = resultType.GetProperty("Success"); + if (successProperty == null) + return defaultValue; + + object successValue = successProperty.GetValue(result); + return successValue is bool success ? success : defaultValue; + } + + private static string GetResultStatus(object result) + { + if (result == null) + return "Unknown"; + + object status = result.GetType().GetProperty("Status")?.GetValue(result); + return status?.ToString() ?? "Unknown"; + } + + private void OverwriteSavedUuids(Guid uuid) + { + DeleteSavedUuids(); + SaveUuid(uuid); + } +} diff --git a/Runtime/Scripts/Registration.cs b/Runtime/Scripts/Registration.cs index d396d43..383f756 100644 --- a/Runtime/Scripts/Registration.cs +++ b/Runtime/Scripts/Registration.cs @@ -2,7 +2,9 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using UnityEngine; +using UnityEngine.SceneManagement; /// /// Manages registration workflow, including marker setup, state changes, and alignment algorithms for a target object. @@ -10,7 +12,7 @@ /// /// David Mertens, TH Koeln. /// -/// +/// public class Registration : MonoBehaviour { public RegiTarget regiTarget; @@ -19,6 +21,8 @@ public class Registration : MonoBehaviour public event Action StateChanged; public string numUuidsKey = "demoTargetUuidKey"; public bool onlyCorrectYAxis; + [SerializeField] private bool loadSceneAfterSaveForTest; + [SerializeField] private string sceneToLoadAfterSave = "DatahubTest"; [HideInInspector] public State currentState; [HideInInspector] public List markers; @@ -83,7 +87,7 @@ public void SetState(State nextState) public void AddMarker(Vector3 position) { if (markers.Count >= regiTarget.amountControlPoints) return; - + GameObject go = Helper.CreateSmallSphere(); go.transform.position = position; go.AddComponent(); @@ -115,15 +119,17 @@ public void ResetEverything() ResetTarget(); ResetMarker(); } - + /// /// Saves the current registration data asynchronously. /// - public async void SaveRegistration() + public void SaveRegistration() { - Debug.Log("Save ANCHOR"); - await _anchorLoaderManager.DeleteAllAnchors(); - regiTarget.gameObject.AddComponent(); + if (regiTarget.GetComponent() == null) + { + regiTarget.gameObject.AddComponent(); + } + StartCoroutine(SaveAnchorsDelayed()); } @@ -133,7 +139,7 @@ private void ResetTarget() regiTarget.transform.position = Vector3.zero; regiTarget.transform.rotation = Quaternion.identity; } - + private void ResetMarker() { markers.ForEach(Destroy); @@ -142,29 +148,88 @@ private void ResetMarker() private void LinkPositionFromDevice() { - List uuids = AnchorStorage.LoadAllAnchorUuids(); - Debug.Log("LOAD ANCHORS: " + uuids.Count); _anchorLoaderManager.AnchorLoader.LoadAnchorsByUuid(regiTarget); SetState(State.Confirmation); } private IEnumerator SaveAnchorsDelayed() { - yield return new WaitForSeconds(0.01f); - _anchorLoaderManager.SaveAnchor(regiTarget.GetComponent()); + OVRSpatialAnchor anchor = regiTarget.GetComponent(); + if (anchor == null) + { + anchor = regiTarget.gameObject.AddComponent(); + } + + const float maxWaitSeconds = 10f; + float startTime = Time.realtimeSinceStartup; + while (anchor != null && (!anchor.Created || anchor.Uuid == Guid.Empty)) + { + if (Time.realtimeSinceStartup - startTime >= maxWaitSeconds) + { + Debug.LogWarning($"[Registration] SaveAnchorsDelayed aborted: anchor not ready within {maxWaitSeconds}s. created={anchor.Created}, uuid={anchor.Uuid}"); + yield break; + } + + yield return null; + anchor = regiTarget.GetComponent(); + } + + if (anchor == null) + { + Debug.LogWarning("[Registration] SaveAnchorsDelayed aborted: target has no OVRSpatialAnchor component after wait."); + yield break; + } + + Task saveTask = _anchorLoaderManager.SaveAnchorAndPersistIfValidAsync(anchor); + while (!saveTask.IsCompleted) + { + yield return null; + } + + if (saveTask.IsFaulted) + { + Debug.LogError($"[Registration] SaveAnchorsDelayed failed with exception: {saveTask.Exception}"); + yield break; + } + + AnchorLoaderManager.SaveAnchorOutcome saveOutcome = saveTask.Result; + if (!saveOutcome.Persisted) + { + Debug.LogWarning($"[Registration] SaveAnchorsDelayed did not persist UUID. status={saveOutcome.Status}, uuid={saveOutcome.Uuid}"); + yield break; + } + + if (!loadSceneAfterSaveForTest) + { + yield break; + } + + yield return new WaitForSeconds(2); + LoadSceneForSaveTest(); + } + + private void LoadSceneForSaveTest() + { + if (string.IsNullOrWhiteSpace(sceneToLoadAfterSave)) + { + Debug.LogWarning("Scene load after save is enabled, but no target scene is configured."); + return; + } + + SceneManager.LoadScene(sceneToLoadAfterSave, LoadSceneMode.Single); } private void Align(RegiTarget target) { if (markers == null || markers.Count == 0 || target == null) return; - + if (algorithmToUse == Algorithm.Kabsch) AlignMeshKabsch(markers.Select(marker => marker.transform.position).ToList(), target); - + if (algorithmToUse == Algorithm.ProjectionPlaneMapping) RegistrationPlaneProjection.AlignMesh(markers.Select(marker => marker.transform.position).ToList(), target); - + } private void AlignMeshKabsch(List selectedPositions, RegiTarget toTransform) @@ -191,4 +256,4 @@ private bool ReachedMaxMarkerAmount() { return markers.Count >= regiTarget.amountControlPoints; } -} \ No newline at end of file +} From bd6a3311d14d783afb129fbe196adc3860598f77 Mon Sep 17 00:00:00 2001 From: Marlus Wellmann Date: Fri, 10 Apr 2026 16:38:45 +0200 Subject: [PATCH 05/10] feat: added onAlignmentAccepted event * removed not used customObject SerializeField --- Runtime/Scripts/Registration.cs | 4 +-- Runtime/Scripts/RegistrationVrController.cs | 28 +++++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Runtime/Scripts/Registration.cs b/Runtime/Scripts/Registration.cs index 383f756..d36151e 100644 --- a/Runtime/Scripts/Registration.cs +++ b/Runtime/Scripts/Registration.cs @@ -21,7 +21,7 @@ public class Registration : MonoBehaviour public event Action StateChanged; public string numUuidsKey = "demoTargetUuidKey"; public bool onlyCorrectYAxis; - [SerializeField] private bool loadSceneAfterSaveForTest; + [SerializeField] private bool loadSceneAfterSave; [SerializeField] private string sceneToLoadAfterSave = "DatahubTest"; [HideInInspector] public State currentState; @@ -199,7 +199,7 @@ private IEnumerator SaveAnchorsDelayed() yield break; } - if (!loadSceneAfterSaveForTest) + if (!loadSceneAfterSave) { yield break; } diff --git a/Runtime/Scripts/RegistrationVrController.cs b/Runtime/Scripts/RegistrationVrController.cs index 870f45a..df26c10 100644 --- a/Runtime/Scripts/RegistrationVrController.cs +++ b/Runtime/Scripts/RegistrationVrController.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using UnityEngine; +using UnityEngine.Events; /// /// Handles controller assignment, calibration, and registration workflow in VR registration scenarios. @@ -10,19 +11,19 @@ public class RegistrationVrController : MonoBehaviour { public Registration registration; - + [SerializeField] private Handedness controllerSelection; - [SerializeField] private GameObject customObject; - + [SerializeField] private UnityEvent onAlignmentAccepted; + [SerializeField] private bool calibrateObject; [HideInInspector] public GameObject controllerInUse; - + protected Calibrator _calibrator; protected Vector3 _tipPosition; private GameObject _demoObject; private bool _isRecordingTipPosition; private readonly List _tipPositionsOverTime = new List(); - public readonly Vector3 PredefinedTipPosition = new Vector3(0.01211928f,-0.08250856f,-0.08393941f); + public readonly Vector3 PredefinedTipPosition = new Vector3(0.01211928f, -0.08250856f, -0.08393941f); protected Handedness ControllerSelection => controllerSelection; protected bool CalibrateObject => calibrateObject; @@ -43,7 +44,7 @@ protected virtual void Awake() _demoObject.transform.SetParent(transform); registration.StateChanged += OnStateChanged; } - + protected virtual void Start() { @@ -116,24 +117,25 @@ protected virtual void CalibrationActions() } if (AnyTriggerUp()) _calibrator.StopRecording(); if (CancelButtonPressed()) _calibrator.SetRelativePostition(PredefinedTipPosition); - + } protected virtual void MarkerStateActions() { UpdateTipPosition(); UpdateDemoObject(); - - if(_isRecordingTipPosition)_tipPositionsOverTime.Add(_tipPosition); - + + if (_isRecordingTipPosition) _tipPositionsOverTime.Add(_tipPosition); + LeftHandMarkerInteractions(); RightHandMarkerInteractions(); } - + protected virtual void ConfirmationStateActions() { if (CommitButtonPressed()) { + onAlignmentAccepted?.Invoke(); registration.SaveRegistration(); registration.SetState(Registration.State.Inactive); } @@ -177,7 +179,7 @@ protected virtual void StartRecordingTipPosition() protected virtual void EndRecordingTipPosition() { - if(_tipPositionsOverTime == null || _tipPositionsOverTime.Count < 1)return; + if (_tipPositionsOverTime == null || _tipPositionsOverTime.Count < 1) return; _isRecordingTipPosition = false; Vector3 midPoint = Vector3.zero; _tipPositionsOverTime.ForEach(pos => midPoint += pos); @@ -217,7 +219,7 @@ protected virtual bool AnyTriggerDown() return OVRInput.GetDown(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.RTouch) || OVRInput.GetDown(OVRInput.Button.PrimaryIndexTrigger, OVRInput.Controller.RTouch); } - + protected virtual bool AnyTriggerUp() { return OVRInput.GetUp(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.RTouch) || From e9bdd03b76f6ac25453893d9180ab782464b5609 Mon Sep 17 00:00:00 2001 From: Marlus Wellmann Date: Sat, 11 Apr 2026 16:52:40 +0200 Subject: [PATCH 06/10] fix: _demoObject now shows up in builds * replaced _demoObject via Helper.CreateSmallSphere with a SerilaizedField aligmentTarget --- Runtime/Scripts/RegistrationUI.cs | 4 ++-- Runtime/Scripts/RegistrationVrController.cs | 25 +++++++++------------ 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/Runtime/Scripts/RegistrationUI.cs b/Runtime/Scripts/RegistrationUI.cs index cae7f75..cd4d34a 100644 --- a/Runtime/Scripts/RegistrationUI.cs +++ b/Runtime/Scripts/RegistrationUI.cs @@ -3,7 +3,7 @@ using UnityEngine.UI; [RequireComponent(typeof(RegistrationVrController))] -public class SpatialPanel : MonoBehaviour +public class RegistrationUI : MonoBehaviour { public Image colorImage; @@ -97,4 +97,4 @@ public void SetColor(Color color) { colorImage.color = color; } -} \ No newline at end of file +} diff --git a/Runtime/Scripts/RegistrationVrController.cs b/Runtime/Scripts/RegistrationVrController.cs index df26c10..83fa814 100644 --- a/Runtime/Scripts/RegistrationVrController.cs +++ b/Runtime/Scripts/RegistrationVrController.cs @@ -17,13 +17,13 @@ public class RegistrationVrController : MonoBehaviour [SerializeField] private bool calibrateObject; [HideInInspector] public GameObject controllerInUse; + [SerializeField] protected GameObject aligmentTarget; protected Calibrator _calibrator; protected Vector3 _tipPosition; - private GameObject _demoObject; - private bool _isRecordingTipPosition; - private readonly List _tipPositionsOverTime = new List(); - public readonly Vector3 PredefinedTipPosition = new Vector3(0.01211928f, -0.08250856f, -0.08393941f); + protected bool _isRecordingTipPosition; + protected readonly List _tipPositionsOverTime = new List(); + protected readonly Vector3 PredefinedTipPosition = new Vector3(0.01211928f, -0.08250856f, -0.08393941f); protected Handedness ControllerSelection => controllerSelection; protected bool CalibrateObject => calibrateObject; @@ -39,9 +39,6 @@ protected virtual void Awake() { _calibrator = gameObject.AddComponent(); SetupController(); - _demoObject = Helper.CreateSmallSphere(); - _demoObject.name = "Demo Object"; - _demoObject.transform.SetParent(transform); registration.StateChanged += OnStateChanged; } @@ -60,13 +57,13 @@ protected virtual void OnStateChanged() switch (registration.currentState) { case Registration.State.Calibration: - _demoObject.SetActive(true); + aligmentTarget.SetActive(true); break; case Registration.State.MarkerSetup: - _demoObject.SetActive(true); + aligmentTarget.SetActive(true); break; case Registration.State.Confirmation: - _demoObject.SetActive(false); + aligmentTarget.SetActive(false); break; } } @@ -112,7 +109,7 @@ protected virtual void CalibrationActions() if (CommitButtonPressed()) registration.SetState(Registration.State.MarkerSetup); if (AnyTriggerDown()) { - _demoObject.SetActive(true); + aligmentTarget.SetActive(true); _calibrator.StartRecording(); } if (AnyTriggerUp()) _calibrator.StopRecording(); @@ -158,10 +155,10 @@ protected virtual void UpdateTipPosition() protected virtual void UpdateDemoObject() { - if (_demoObject == null) return; + if (aligmentTarget == null) return; - _demoObject.transform.position = _tipPosition; - Helper.SetColor(_demoObject, Helper.GetColorForIndex(registration.markers.Count)); + aligmentTarget.transform.position = _tipPosition; + Helper.SetColor(aligmentTarget, Helper.GetColorForIndex(registration.markers.Count)); } protected virtual void RightHandMarkerInteractions() From 537f02a11981fa635c012344433d0af71fefdf09 Mon Sep 17 00:00:00 2001 From: Markus Wellmann Date: Tue, 5 May 2026 15:21:21 +0200 Subject: [PATCH 07/10] Refactor: Netter name for LoadConfiguredScene in Registration --- Runtime/Scripts/Registration.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Runtime/Scripts/Registration.cs b/Runtime/Scripts/Registration.cs index d36151e..e66feca 100644 --- a/Runtime/Scripts/Registration.cs +++ b/Runtime/Scripts/Registration.cs @@ -205,10 +205,10 @@ private IEnumerator SaveAnchorsDelayed() } yield return new WaitForSeconds(2); - LoadSceneForSaveTest(); + LoadConfiguredScene(); } - private void LoadSceneForSaveTest() + private void LoadConfiguredScene() { if (string.IsNullOrWhiteSpace(sceneToLoadAfterSave)) { From 6a2810e709e0f45517acc1fd0a960f1d3a00c5e9 Mon Sep 17 00:00:00 2001 From: Markus Wellmann Date: Wed, 6 May 2026 09:13:07 +0200 Subject: [PATCH 08/10] feat: visible registration marker via RegistartionSphere in builds --- Runtime/DemoTarget.prefab | 6 ++ Runtime/RegistrationSphere.prefab | 92 ++++++++++++++++++++++++++ Runtime/RegistrationSphere.prefab.meta | 7 ++ Runtime/RegistrationUI.prefab | 6 +- Runtime/Scripts/Registration.cs | 15 ++++- Runtime/Scripts/RegistrationTarget.cs | 9 ++- 6 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 Runtime/RegistrationSphere.prefab create mode 100644 Runtime/RegistrationSphere.prefab.meta diff --git a/Runtime/DemoTarget.prefab b/Runtime/DemoTarget.prefab index 713b7d7..485bef7 100644 --- a/Runtime/DemoTarget.prefab +++ b/Runtime/DemoTarget.prefab @@ -293,6 +293,8 @@ MeshRenderer: m_RayTracingAccelStructBuildFlagsOverride: 0 m_RayTracingAccelStructBuildFlags: 1 m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -314,9 +316,11 @@ MeshRenderer: m_AutoUVMaxDistance: 0.5 m_AutoUVMaxAngle: 89 m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 + m_MaskInteraction: 0 m_AdditionalVertexStreams: {fileID: 0} --- !u!65 &3225371635357050969 BoxCollider: @@ -352,6 +356,8 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: amountControlPoints: 3 + regiTargetVisualisation: {fileID: 4787713077208734620, guid: 9f46f9d192fa65c43829763b6b4fadcc, + type: 3} markers: - {fileID: 749095979477038632} - {fileID: 3836611436156247953} diff --git a/Runtime/RegistrationSphere.prefab b/Runtime/RegistrationSphere.prefab new file mode 100644 index 0000000..af78474 --- /dev/null +++ b/Runtime/RegistrationSphere.prefab @@ -0,0 +1,92 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &4787713077208734620 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1684654262528886088} + - component: {fileID: 4948061992107643806} + - component: {fileID: 2450485364167766399} + m_Layer: 0 + m_Name: RegistrationSphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1684654262528886088 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4787713077208734620} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.01, y: 0.01, z: 0.01} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &4948061992107643806 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4787713077208734620} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2450485364167766399 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4787713077208734620} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 + m_AdditionalVertexStreams: {fileID: 0} diff --git a/Runtime/RegistrationSphere.prefab.meta b/Runtime/RegistrationSphere.prefab.meta new file mode 100644 index 0000000..e5a1e72 --- /dev/null +++ b/Runtime/RegistrationSphere.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9f46f9d192fa65c43829763b6b4fadcc +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/RegistrationUI.prefab b/Runtime/RegistrationUI.prefab index 199fe84..1640d8d 100644 --- a/Runtime/RegistrationUI.prefab +++ b/Runtime/RegistrationUI.prefab @@ -795,9 +795,13 @@ MonoBehaviour: m_EditorClassIdentifier: registration: {fileID: 0} controllerSelection: 0 - customObject: {fileID: 0} + onAlignmentAccepted: + m_PersistentCalls: + m_Calls: [] calibrateObject: 0 controllerInUse: {fileID: 0} + aligmentTarget: {fileID: 4787713077208734620, guid: 9f46f9d192fa65c43829763b6b4fadcc, + type: 3} --- !u!114 &6634393656915495675 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Runtime/Scripts/Registration.cs b/Runtime/Scripts/Registration.cs index e66feca..930b207 100644 --- a/Runtime/Scripts/Registration.cs +++ b/Runtime/Scripts/Registration.cs @@ -88,7 +88,7 @@ public void AddMarker(Vector3 position) { if (markers.Count >= regiTarget.amountControlPoints) return; - GameObject go = Helper.CreateSmallSphere(); + GameObject go = CreateMarkerVisual(); go.transform.position = position; go.AddComponent(); Helper.SetColor(go, Helper.GetColorForIndex(markers.Count)); @@ -146,6 +146,19 @@ private void ResetMarker() markers.Clear(); } + private GameObject CreateMarkerVisual() + { + if (regiTarget != null && regiTarget.RegiTargetVisualisation != null) + { + GameObject markerVisual = Instantiate(regiTarget.RegiTargetVisualisation, transform); + markerVisual.name = regiTarget.RegiTargetVisualisation.name; + return markerVisual; + } + + Debug.LogWarning($"[{nameof(Registration)}:{name}] RegiTargetVisualisation reference is missing. Created backup marker via Helper. Marker will not be visible in builds.", this); + return Helper.CreateSmallSphere(); + } + private void LinkPositionFromDevice() { _anchorLoaderManager.AnchorLoader.LoadAnchorsByUuid(regiTarget); diff --git a/Runtime/Scripts/RegistrationTarget.cs b/Runtime/Scripts/RegistrationTarget.cs index a93ddd4..edd9b3d 100644 --- a/Runtime/Scripts/RegistrationTarget.cs +++ b/Runtime/Scripts/RegistrationTarget.cs @@ -7,9 +7,12 @@ public class RegiTarget : MonoBehaviour { [Range(3, 5)] public int amountControlPoints; + [SerializeField] private GameObject regiTargetVisualisation; [HideInInspector][SerializeField] public RegiMarker[] markers; - [HideInInspector]public Vector3[] relativeMarkerPositions; - [HideInInspector]public Guid uuidName; + [HideInInspector] public Vector3[] relativeMarkerPositions; + [HideInInspector] public Guid uuidName; + + public GameObject RegiTargetVisualisation { get => regiTargetVisualisation; } private void OnValidate() { @@ -80,4 +83,4 @@ private void InitMarkers() markers[i].color = Helper.GetColorForIndex(i); } } -} \ No newline at end of file +} From fc9f8a740a0f5dd79df3e21d70b35e16f0bf2c1b Mon Sep 17 00:00:00 2001 From: Markus Wellmann Date: Wed, 6 May 2026 09:44:04 +0200 Subject: [PATCH 09/10] feat: visible registration marker via RegistartionSphere in builds --- Runtime/Scripts/Registration.cs | 1 - Runtime/Scripts/RegistrationVrController.cs | 39 ++++++++++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Runtime/Scripts/Registration.cs b/Runtime/Scripts/Registration.cs index 930b207..2c18260 100644 --- a/Runtime/Scripts/Registration.cs +++ b/Runtime/Scripts/Registration.cs @@ -71,7 +71,6 @@ public void SetState(State nextState) ResetEverything(); OVRSpatialAnchor anchor = regiTarget.GetComponent(); if (anchor != null) Destroy(anchor); - regiTarget.SetVisible(false); break; case State.Inactive: diff --git a/Runtime/Scripts/RegistrationVrController.cs b/Runtime/Scripts/RegistrationVrController.cs index 83fa814..c3caaf1 100644 --- a/Runtime/Scripts/RegistrationVrController.cs +++ b/Runtime/Scripts/RegistrationVrController.cs @@ -17,7 +17,8 @@ public class RegistrationVrController : MonoBehaviour [SerializeField] private bool calibrateObject; [HideInInspector] public GameObject controllerInUse; - [SerializeField] protected GameObject aligmentTarget; + [SerializeField] private GameObject aligmentTarget; + private GameObject aligmentTargetInstance; protected Calibrator _calibrator; protected Vector3 _tipPosition; @@ -29,6 +30,28 @@ public class RegistrationVrController : MonoBehaviour protected bool CalibrateObject => calibrateObject; protected virtual float TipForwardOffset => 0.06f; + public GameObject AligmentTarget + { + get + { + if (aligmentTargetInstance != null) + { + return aligmentTargetInstance; + } + + if (aligmentTarget != null) + { + aligmentTargetInstance = Instantiate(aligmentTarget, transform, false); + aligmentTargetInstance.name = aligmentTarget.name; + return aligmentTargetInstance; + } + + aligmentTargetInstance = Helper.CreateSmallSphere(); + aligmentTargetInstance.transform.SetParent(transform, false); + return aligmentTargetInstance; + } + } + public enum Handedness { RightHanded, @@ -57,13 +80,13 @@ protected virtual void OnStateChanged() switch (registration.currentState) { case Registration.State.Calibration: - aligmentTarget.SetActive(true); + AligmentTarget.SetActive(true); break; case Registration.State.MarkerSetup: - aligmentTarget.SetActive(true); + AligmentTarget.SetActive(true); break; case Registration.State.Confirmation: - aligmentTarget.SetActive(false); + AligmentTarget.SetActive(false); break; } } @@ -109,7 +132,7 @@ protected virtual void CalibrationActions() if (CommitButtonPressed()) registration.SetState(Registration.State.MarkerSetup); if (AnyTriggerDown()) { - aligmentTarget.SetActive(true); + AligmentTarget.SetActive(true); _calibrator.StartRecording(); } if (AnyTriggerUp()) _calibrator.StopRecording(); @@ -155,10 +178,10 @@ protected virtual void UpdateTipPosition() protected virtual void UpdateDemoObject() { - if (aligmentTarget == null) return; + if (AligmentTarget == null) return; - aligmentTarget.transform.position = _tipPosition; - Helper.SetColor(aligmentTarget, Helper.GetColorForIndex(registration.markers.Count)); + AligmentTarget.transform.position = _tipPosition; + Helper.SetColor(AligmentTarget, Helper.GetColorForIndex(registration.markers.Count)); } protected virtual void RightHandMarkerInteractions() From f878c17079be4a3db4786482a1c6053b49cf6f0f Mon Sep 17 00:00:00 2001 From: Markus Wellmann Date: Tue, 12 May 2026 16:34:52 +0200 Subject: [PATCH 10/10] feat: removed unused sceneToLoadAfterSave --- Runtime/Scripts/Registration.cs | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/Runtime/Scripts/Registration.cs b/Runtime/Scripts/Registration.cs index 2c18260..1446bcf 100644 --- a/Runtime/Scripts/Registration.cs +++ b/Runtime/Scripts/Registration.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading.Tasks; using UnityEngine; -using UnityEngine.SceneManagement; /// /// Manages registration workflow, including marker setup, state changes, and alignment algorithms for a target object. @@ -21,8 +20,6 @@ public class Registration : MonoBehaviour public event Action StateChanged; public string numUuidsKey = "demoTargetUuidKey"; public bool onlyCorrectYAxis; - [SerializeField] private bool loadSceneAfterSave; - [SerializeField] private string sceneToLoadAfterSave = "DatahubTest"; [HideInInspector] public State currentState; [HideInInspector] public List markers; @@ -208,27 +205,9 @@ private IEnumerator SaveAnchorsDelayed() if (!saveOutcome.Persisted) { Debug.LogWarning($"[Registration] SaveAnchorsDelayed did not persist UUID. status={saveOutcome.Status}, uuid={saveOutcome.Uuid}"); - yield break; - } - - if (!loadSceneAfterSave) - { - yield break; - } - - yield return new WaitForSeconds(2); - LoadConfiguredScene(); - } - - private void LoadConfiguredScene() - { - if (string.IsNullOrWhiteSpace(sceneToLoadAfterSave)) - { - Debug.LogWarning("Scene load after save is enabled, but no target scene is configured."); - return; } - SceneManager.LoadScene(sceneToLoadAfterSave, LoadSceneMode.Single); + yield break; }