fix virtual hand crashes and editor visibility issues
This commit is contained in:
@@ -117,6 +117,8 @@ struct USGVirtualHandComponent::FImpl
|
|||||||
USkeleton* GetSkeleton() const;
|
USkeleton* GetSkeleton() const;
|
||||||
const FReferenceSkeleton& GetRefSkeleton() const;
|
const FReferenceSkeleton& GetRefSkeleton() const;
|
||||||
|
|
||||||
|
bool InitializeBackend() const;
|
||||||
|
bool UninitializeBackend() const;
|
||||||
bool CheckGlove() const;
|
bool CheckGlove() const;
|
||||||
|
|
||||||
void SetVisibility(bool bVisible) const;
|
void SetVisibility(bool bVisible) const;
|
||||||
@@ -200,7 +202,7 @@ USGVirtualHandComponent::USGVirtualHandComponent(const FObjectInitializer& Objec
|
|||||||
Super::SetAnimClass(USGVirtualHandAnimInstance::StaticClass());
|
Super::SetAnimClass(USGVirtualHandAnimInstance::StaticClass());
|
||||||
|
|
||||||
bRight = true;
|
bRight = true;
|
||||||
bHiddenInGameIfNoGloveDetected = true;
|
bHiddenInGameIfNoGloveDetected = false;
|
||||||
|
|
||||||
const FString SkeletalMeshPath{Pimpl->GetDefaultMeshPath()};
|
const FString SkeletalMeshPath{Pimpl->GetDefaultMeshPath()};
|
||||||
const ConstructorHelpers::FObjectFinder<USkeletalMesh> SkeletalMesh{*SkeletalMeshPath};
|
const ConstructorHelpers::FObjectFinder<USkeletalMesh> SkeletalMesh{*SkeletalMeshPath};
|
||||||
@@ -208,7 +210,7 @@ USGVirtualHandComponent::USGVirtualHandComponent(const FObjectInitializer& Objec
|
|||||||
TEXT("Failed to load the skeletal mesh: '%s'"), *SkeletalMeshPath);
|
TEXT("Failed to load the skeletal mesh: '%s'"), *SkeletalMeshPath);
|
||||||
Super::SetSkeletalMesh(SkeletalMesh.Object, true);
|
Super::SetSkeletalMesh(SkeletalMesh.Object, true);
|
||||||
|
|
||||||
bSGConnectInitialized = false;
|
bBackendInitialized = false;
|
||||||
Glove = nullptr;
|
Glove = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +261,34 @@ void USGVirtualHandComponent::InitializeComponent()
|
|||||||
Pimpl->SetDefaultMesh();
|
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(
|
void USGVirtualHandComponent::TickComponent(
|
||||||
@@ -271,20 +300,13 @@ void USGVirtualHandComponent::TickComponent(
|
|||||||
EditorTick(DeltaTime, TickType, ThisTickFunction);
|
EditorTick(DeltaTime, TickType, ThisTickFunction);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* WITH_EDITOR */
|
||||||
|
|
||||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||||
|
|
||||||
(void) Pimpl->CheckGlove();
|
(void) Pimpl->CheckGlove();
|
||||||
}
|
}
|
||||||
|
|
||||||
void USGVirtualHandComponent::BeginPlay()
|
|
||||||
{
|
|
||||||
Super::BeginPlay();
|
|
||||||
|
|
||||||
(void) Pimpl->CheckGlove();
|
|
||||||
}
|
|
||||||
|
|
||||||
void USGVirtualHandComponent::SetSkeletalMesh(USkeletalMesh* NewMesh, const bool bReinitPose)
|
void USGVirtualHandComponent::SetSkeletalMesh(USkeletalMesh* NewMesh, const bool bReinitPose)
|
||||||
{
|
{
|
||||||
if (IsValid(NewMesh))
|
if (IsValid(NewMesh))
|
||||||
@@ -404,7 +426,7 @@ USGVirtualHandComponent::FImpl::~FImpl() = default;
|
|||||||
bool USGVirtualHandComponent::FImpl::IsEditor() const
|
bool USGVirtualHandComponent::FImpl::IsEditor() const
|
||||||
{
|
{
|
||||||
const UWorld* World{Owner->GetWorld()};
|
const UWorld* World{Owner->GetWorld()};
|
||||||
if (World && World->WorldType == EWorldType::Editor)
|
if (World && (World->WorldType == EWorldType::Editor || World->WorldType == EWorldType::EditorPreview))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -494,24 +516,103 @@ const FReferenceSkeleton& USGVirtualHandComponent::FImpl::GetRefSkeleton() const
|
|||||||
return SkeletalMesh->GetRefSkeleton();
|
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::Dispose();
|
||||||
FSGDeviceList::Reinitialize();
|
FSGDeviceList::Reinitialize();
|
||||||
|
|
||||||
// Load the latest hand profiles.
|
// Load the latest hand profiles.
|
||||||
FSGHapticGloveHandProfiles::TryLoadingFromDisk();
|
FSGHapticGloveHandProfiles::TryLoadingFromDisk();
|
||||||
|
|
||||||
const int32_t Result = FSGConnect::Init();
|
Owner->bBackendInitialized = true;
|
||||||
if (Result != 1)
|
|
||||||
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Owner->bSGConnectInitialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool bGloveWasPresent = IsValid(Owner->Glove);
|
const bool bGloveWasPresent = IsValid(Owner->Glove);
|
||||||
@@ -523,9 +624,34 @@ bool USGVirtualHandComponent::FImpl::CheckGlove() const
|
|||||||
(Owner->bRight ? TEXT("right-handed") : TEXT("left-handed"))));
|
(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;
|
return bFoundGlove;
|
||||||
@@ -534,7 +660,6 @@ bool USGVirtualHandComponent::FImpl::CheckGlove() const
|
|||||||
void USGVirtualHandComponent::FImpl::SetVisibility(const bool bVisible) const
|
void USGVirtualHandComponent::FImpl::SetVisibility(const bool bVisible) const
|
||||||
{
|
{
|
||||||
Owner->SetVisibility(bVisible, true);
|
Owner->SetVisibility(bVisible, true);
|
||||||
Owner->SetHiddenInGame(!bVisible, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void USGVirtualHandComponent::FImplDeleter::operator()(const FImpl* P) const
|
void USGVirtualHandComponent::FImplDeleter::operator()(const FImpl* P) const
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ ASGPawn::ASGPawn(const FObjectInitializer& ObjectInitializer)
|
|||||||
HandLeft->SetupAttachment(MotionControllerLeft);
|
HandLeft->SetupAttachment(MotionControllerLeft);
|
||||||
HandLeft->SetCanEverAffectNavigation(false);
|
HandLeft->SetCanEverAffectNavigation(false);
|
||||||
HandLeft->SetRight(false);
|
HandLeft->SetRight(false);
|
||||||
|
HandLeft->SetHiddenIfNoGloveDetected(true);
|
||||||
|
|
||||||
MotionControllerRight = ObjectInitializer.CreateDefaultSubobject<UMotionControllerComponent>(
|
MotionControllerRight = ObjectInitializer.CreateDefaultSubobject<UMotionControllerComponent>(
|
||||||
this, TEXT("MotionControllerRight"));
|
this, TEXT("MotionControllerRight"));
|
||||||
@@ -107,6 +108,7 @@ ASGPawn::ASGPawn(const FObjectInitializer& ObjectInitializer)
|
|||||||
HandRight->SetupAttachment(MotionControllerRight);
|
HandRight->SetupAttachment(MotionControllerRight);
|
||||||
HandRight->SetCanEverAffectNavigation(false);
|
HandRight->SetCanEverAffectNavigation(false);
|
||||||
HandRight->SetRight(true);
|
HandRight->SetRight(true);
|
||||||
|
HandRight->SetHiddenIfNoGloveDetected(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASGPawn::FImpl::FImpl(ASGPawn* InOwner)
|
ASGPawn::FImpl::FImpl(ASGPawn* InOwner)
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
UPROPERTY(Transient)
|
UPROPERTY(Transient)
|
||||||
uint8 bSGConnectInitialized : 1;
|
uint8 bBackendInitialized : 1;
|
||||||
|
|
||||||
UPROPERTY(Transient)
|
UPROPERTY(Transient)
|
||||||
USGHapticGlove* Glove;
|
USGHapticGlove* Glove;
|
||||||
@@ -124,12 +124,16 @@ public:
|
|||||||
|
|
||||||
virtual void InitializeComponent() override;
|
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,
|
virtual void TickComponent(float DeltaTime,
|
||||||
enum ELevelTick TickType,
|
enum ELevelTick TickType,
|
||||||
FActorComponentTickFunction* ThisTickFunction) override;
|
FActorComponentTickFunction* ThisTickFunction) override;
|
||||||
|
|
||||||
virtual void BeginPlay() override;
|
|
||||||
|
|
||||||
virtual void SetSkeletalMesh(USkeletalMesh* NewMesh, bool bReinitPose = true) override;
|
virtual void SetSkeletalMesh(USkeletalMesh* NewMesh, bool bReinitPose = true) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
Reference in New Issue
Block a user