From 1266ca5feb9897767df8baac26b7404498bf600e Mon Sep 17 00:00:00 2001 From: Mamadou Babaei Date: Wed, 15 Mar 2023 17:16:19 +0100 Subject: [PATCH] fix virtual hand crashes and editor visibility issues --- .../Components/SGVirtualHandComponent.cpp | 169 +++++++++++++++--- .../SenseGlove/GameFramework/SGPawn.cpp | 2 + .../Components/SGVirtualHandComponent.h | 10 +- 3 files changed, 156 insertions(+), 25 deletions(-) diff --git a/Source/SenseGlove/Private/SenseGlove/Components/SGVirtualHandComponent.cpp b/Source/SenseGlove/Private/SenseGlove/Components/SGVirtualHandComponent.cpp index cf7c0984..01950adf 100644 --- a/Source/SenseGlove/Private/SenseGlove/Components/SGVirtualHandComponent.cpp +++ b/Source/SenseGlove/Private/SenseGlove/Components/SGVirtualHandComponent.cpp @@ -117,6 +117,8 @@ struct USGVirtualHandComponent::FImpl USkeleton* GetSkeleton() const; const FReferenceSkeleton& GetRefSkeleton() const; + bool InitializeBackend() const; + bool UninitializeBackend() const; bool CheckGlove() const; void SetVisibility(bool bVisible) const; @@ -200,7 +202,7 @@ USGVirtualHandComponent::USGVirtualHandComponent(const FObjectInitializer& Objec Super::SetAnimClass(USGVirtualHandAnimInstance::StaticClass()); bRight = true; - bHiddenInGameIfNoGloveDetected = true; + bHiddenInGameIfNoGloveDetected = false; const FString SkeletalMeshPath{Pimpl->GetDefaultMeshPath()}; const ConstructorHelpers::FObjectFinder SkeletalMesh{*SkeletalMeshPath}; @@ -208,7 +210,7 @@ USGVirtualHandComponent::USGVirtualHandComponent(const FObjectInitializer& Objec TEXT("Failed to load the skeletal mesh: '%s'"), *SkeletalMeshPath); Super::SetSkeletalMesh(SkeletalMesh.Object, true); - bSGConnectInitialized = false; + bBackendInitialized = false; Glove = nullptr; } @@ -259,7 +261,34 @@ void USGVirtualHandComponent::InitializeComponent() Pimpl->SetDefaultMesh(); } - (void) Pimpl->CheckGlove(); + if (Pimpl->InitializeBackend()) + { + (void) Pimpl->CheckGlove(); + } +} + +void USGVirtualHandComponent::UninitializeComponent() +{ + Super::UninitializeComponent(); + + (void) Pimpl->UninitializeBackend(); +} + +void USGVirtualHandComponent::BeginPlay() +{ + Super::BeginPlay(); + + if (Pimpl->InitializeBackend()) + { + (void) Pimpl->CheckGlove(); + } +} + +void USGVirtualHandComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + Super::EndPlay(EndPlayReason); + + (void) Pimpl->UninitializeBackend(); } void USGVirtualHandComponent::TickComponent( @@ -271,20 +300,13 @@ void USGVirtualHandComponent::TickComponent( EditorTick(DeltaTime, TickType, ThisTickFunction); return; } -#endif +#endif /* WITH_EDITOR */ Super::TickComponent(DeltaTime, TickType, ThisTickFunction); (void) Pimpl->CheckGlove(); } -void USGVirtualHandComponent::BeginPlay() -{ - Super::BeginPlay(); - - (void) Pimpl->CheckGlove(); -} - void USGVirtualHandComponent::SetSkeletalMesh(USkeletalMesh* NewMesh, const bool bReinitPose) { if (IsValid(NewMesh)) @@ -404,7 +426,7 @@ USGVirtualHandComponent::FImpl::~FImpl() = default; bool USGVirtualHandComponent::FImpl::IsEditor() const { const UWorld* World{Owner->GetWorld()}; - if (World && World->WorldType == EWorldType::Editor) + if (World && (World->WorldType == EWorldType::Editor || World->WorldType == EWorldType::EditorPreview)) { return true; } @@ -494,24 +516,103 @@ const FReferenceSkeleton& USGVirtualHandComponent::FImpl::GetRefSkeleton() const return SkeletalMesh->GetRefSkeleton(); } -bool USGVirtualHandComponent::FImpl::CheckGlove() const +bool USGVirtualHandComponent::FImpl::InitializeBackend() const { - if (!Owner->bSGConnectInitialized) + if (!Owner->bBackendInitialized) { - // Ensure the device list is empty before doing anything. +#if PLATFORM_ANDROID + const int32_t Result = FSGConnect::Init(); + switch (Result) + { + case -3: + SGLOG_ERROR("An Unexpected error occurred. Please try again."); + return false; + case -2: + SGLOG_ERROR("Device Scanning is already running within a different program."); + return false; + case -1: + SGLOG_ERROR("Device Scanning already being initialized (function called twice in short succession)."); + return false; + case 0: + SGLOG_ERROR("Device Scanning is already running within this program."); + return false; + case 1: + SGLOG_ERROR("Successfully started up DeviceScanning from the current program."); + break;; + default: + ensureAlwaysMsgf(false, TEXT("Unhandled Init return status code!")); + return false; + } +#endif /* PLATFORM_ANDROID */ + + // Ensure that the device list is empty before doing anything. FSGDeviceList::Dispose(); FSGDeviceList::Reinitialize(); // Load the latest hand profiles. FSGHapticGloveHandProfiles::TryLoadingFromDisk(); - const int32_t Result = FSGConnect::Init(); - if (Result != 1) + Owner->bBackendInitialized = true; + + return true; + } + + return false; +} + +bool USGVirtualHandComponent::FImpl::UninitializeBackend() const +{ + // NOTE + // In Editor builds we should be avoiding dispose, since stopping the game in PIE mode, causes the virtual-hand + // to disappear in the editor as the plugin won't be able to retrieve the glove status anymore. +#if ! WITH_EDITOR + if (Owner->bBackendInitialized) + { + FSGDeviceList::Dispose(); + +#if PLATFORM_ANDROID + const int32_t Result = FSGConnect::Dispose(); + switch (Result) + { + case -3: + SGLOG_ERROR("An Unexpected error occurred. Please try again."); + return false; + case -2: + SGLOG_ERROR("Not allowed to dispose of Device Scanning because this is not the program which started it."); + return false; + case -1: + SGLOG_ERROR("Device Scanning is currently being disposed off. This takes a second or two. (function called twice in short succession)."); + return false; + case 0: + SGLOG_ERROR("There is no deviceScanner running from any program, so disposing is skipped."); + return false; + case 1: + SGLOG_ERROR("Successfully disposed of DeviceScanner resources."); + break;; + default: + ensureAlwaysMsgf(false, TEXT("Unhandled Dispose return status code!")); + return false; + } +#endif /* PLATFORM_ANDROID */ + + Owner->bBackendInitialized = false; + + return true; + } +#endif /* ! WITH_EDITOR */ + + return false; +} + +bool USGVirtualHandComponent::FImpl::CheckGlove() const +{ + if (!Owner->bBackendInitialized) + { + const bool bSucceeded = InitializeBackend(); + if (!bSucceeded) { return false; } - - Owner->bSGConnectInitialized = true; } const bool bGloveWasPresent = IsValid(Owner->Glove); @@ -523,9 +624,34 @@ bool USGVirtualHandComponent::FImpl::CheckGlove() const (Owner->bRight ? TEXT("right-handed") : TEXT("left-handed")))); } - if (!IsEditor() && Owner->IsVisible() != bFoundGlove) + const bool bIsEditor = IsEditor(); + if (!bIsEditor) { - SetVisibility(bFoundGlove); + const bool bIsVisible = Owner->IsVisible(); + if (Owner->bHiddenInGameIfNoGloveDetected) + { + if (bFoundGlove) + { + if (!bIsVisible) + { + SetVisibility(true); + } + } + else + { + if (bIsVisible) + { + SetVisibility(false); + } + } + } + else + { + if (!bIsVisible) + { + SetVisibility(true); + } + } } return bFoundGlove; @@ -534,7 +660,6 @@ bool USGVirtualHandComponent::FImpl::CheckGlove() const void USGVirtualHandComponent::FImpl::SetVisibility(const bool bVisible) const { Owner->SetVisibility(bVisible, true); - Owner->SetHiddenInGame(!bVisible, false); } void USGVirtualHandComponent::FImplDeleter::operator()(const FImpl* P) const diff --git a/Source/SenseGlove/Private/SenseGlove/GameFramework/SGPawn.cpp b/Source/SenseGlove/Private/SenseGlove/GameFramework/SGPawn.cpp index 846c364a..a0111615 100644 --- a/Source/SenseGlove/Private/SenseGlove/GameFramework/SGPawn.cpp +++ b/Source/SenseGlove/Private/SenseGlove/GameFramework/SGPawn.cpp @@ -95,6 +95,7 @@ ASGPawn::ASGPawn(const FObjectInitializer& ObjectInitializer) HandLeft->SetupAttachment(MotionControllerLeft); HandLeft->SetCanEverAffectNavigation(false); HandLeft->SetRight(false); + HandLeft->SetHiddenIfNoGloveDetected(true); MotionControllerRight = ObjectInitializer.CreateDefaultSubobject( this, TEXT("MotionControllerRight")); @@ -107,6 +108,7 @@ ASGPawn::ASGPawn(const FObjectInitializer& ObjectInitializer) HandRight->SetupAttachment(MotionControllerRight); HandRight->SetCanEverAffectNavigation(false); HandRight->SetRight(true); + HandRight->SetHiddenIfNoGloveDetected(true); } ASGPawn::FImpl::FImpl(ASGPawn* InOwner) diff --git a/Source/SenseGlove/Public/SenseGlove/Components/SGVirtualHandComponent.h b/Source/SenseGlove/Public/SenseGlove/Components/SGVirtualHandComponent.h index b8186770..1a3cc741 100644 --- a/Source/SenseGlove/Public/SenseGlove/Components/SGVirtualHandComponent.h +++ b/Source/SenseGlove/Public/SenseGlove/Components/SGVirtualHandComponent.h @@ -87,7 +87,7 @@ private: private: UPROPERTY(Transient) - uint8 bSGConnectInitialized : 1; + uint8 bBackendInitialized : 1; UPROPERTY(Transient) USGHapticGlove* Glove; @@ -124,12 +124,16 @@ public: virtual void InitializeComponent() override; + virtual void UninitializeComponent() override; + + virtual void BeginPlay() override; + + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; - virtual void BeginPlay() override; - virtual void SetSkeletalMesh(USkeletalMesh* NewMesh, bool bReinitPose = true) override; protected: