A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
PixoVRToolBase.cpp
Go to the documentation of this file.
1// Copyright(c) Pixo Group. All Rights Reserved.
2
4#include "Net/UnrealNetwork.h"
5#include "AudioDevice.h"
6#include "ActiveSound.h"
8#include "PixoVRHand.h"
9#include "Components/StaticMeshComponent.h"
10#include "Components/BoxComponent.h"
11#include "Components/AudioComponent.h"
12#include "Kismet/GameplayStatics.h"
13#include "Sound/SoundAttenuation.h"
14
15// Sets default values
17 : Super()
18 , bDestroyOnExit(true)
19 , bToggleCollisionOnUsage(true)
20{
21 // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
22 PrimaryActorTick.bCanEverTick = true;
23
24 GrabBoxComponent = CreateDefaultSubobject<UBoxComponent>(FName("GrabBox"));
26 {
27 RootComponent = GrabBoxComponent;
28 }
29
30 ToolMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(FName("ToolMesh"));
32 {
33 ToolMeshComponent->SetupAttachment(RootComponent);
34 }
35
36 bReplicates = true;
37 SetReplicateMovement(true);
38
39 DestroyState.bIsPendingKill = false;
40 DestroyState.TimeBeforeKilled = 0.f;
41}
42
43// Called when the game starts or when spawned
45{
46 Super::BeginPlay();
47
48 bIsGripAllowed = true;
49
50 if (bAdvancedDrop)
51 {
52 GrabBoxComponent->OnComponentBeginOverlap.AddDynamic(this, &APixoVRToolBase::OnOverlapBegin);
53 }
54}
55
56void APixoVRToolBase::Tick(float DeltaSeconds)
57{
58 Super::Tick(DeltaSeconds);
59
60 if (DestroyState.bIsPendingKill)
61 {
62 DestroyState.TimeBeforeKilled -= DeltaSeconds;
63 if (DestroyState.TimeBeforeKilled <= 0.f && IsDestroyable())
64 {
66 }
67 }
68}
69
70void APixoVRToolBase::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
71{
72 if (!bIsGripped && OtherActor != this && OtherActor != GetOwner())
73 {
74 FRotator NewRotation = GetActorRotation();
75 NewRotation.Roll = 0.0f;
76 NewRotation.Pitch = 0.0f;
77
78 GrabBoxComponent->SetAllPhysicsLinearVelocity(FVector::ZeroVector);
79 SetActorRotation(NewRotation);
80 }
81}
82
83bool APixoVRToolBase::IsDestroyable_Implementation()
84{
85 return true;
86}
87
88void APixoVRToolBase::HandleDestroy_Implementation()
89{
90 Destroy();
91}
92
94{
95 return bIsGripped;
96}
97
98void APixoVRToolBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
99{
100 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
101
102 DOREPLIFETIME(APixoVRToolBase, GrabHand);
103 DOREPLIFETIME(APixoVRToolBase, bIsGripped);
104 DOREPLIFETIME(APixoVRToolBase, bIsPaused);
105 DOREPLIFETIME(APixoVRToolBase, ToolData);
106}
107
109{
110 if (GrippingController)
111 {
112 ServerUseTool(GrippingController, GrippedActor);
113 }
114}
115
118{
119 ToolData = InToolData;
121
123 {
125 }
126 else
127 {
128 DestroyDelay = -1.f;
129 }
130}
131
137
142
144{
145 return false;
146}
147
151
156
161
162void APixoVRToolBase::GripTriggerTransform_Implementation(UGripMotionControllerComponent* GrippingController, bool& bUseCustomTransform, FTransform& CustomTransform)
163{
164 bUseCustomTransform = true;
165 CustomTransform = IsRightHand(GrippingController) ? RightHandGrip : LeftHandGrip;
166}
167
172
177
179{
180 ToolMeshComponent->SetVisibility(false);
181 SetActorEnableCollision(false);
182 bIsPaused = true;
183}
184
186{
187 ToolMeshComponent->SetVisibility(true);
188 SetActorEnableCollision(true);
189 bIsPaused = false;
190}
191
192void APixoVRToolBase::MulticastToggleCollision_Implementation(ECollisionEnabled::Type Type)
193{
194 GrabBoxComponent->SetCollisionEnabled(Type);
195 ToolMeshComponent->SetCollisionEnabled(Type);
196}
197
199
200void APixoVRToolBase::ServerStartPlayingSound_Implementation(USoundBase* Sound, const FVector& SoundLocation, float VolumeMultiplier /*= 1.0f*/)
201{
202 MulticastStartPlayingSound(Sound, SoundLocation, VolumeMultiplier);
203}
204
205bool APixoVRToolBase::ServerStartPlayingSound_Validate(USoundBase* Sound, const FVector& SoundLocation, float VolumeMultiplier /*= 1.0f*/)
206{
207 return true;
208}
209
210void APixoVRToolBase::MulticastStartPlayingSound_Implementation(USoundBase* Sound, const FVector& SoundLocation, float VolumeMultiplier)
211{
212 UWorld* ThisWorld = GetWorld();
213 if (!Sound || !ThisWorld || !ThisWorld->bAllowAudioPlayback || ThisWorld->IsNetMode(NM_DedicatedServer))
214 {
215 return;
216 }
217
218 if (FAudioDevice* AudioDevice = ThisWorld->GetAudioDevice().GetAudioDevice())
219 {
220 USoundAttenuation* AttenuationSettings = Sound->AttenuationSettings;
221 if(!AttenuationSettings)
222 {
223 AttenuationSettings = GetDefaultAttenuationSettings();
224
225 UE_LOG(LogTemp, Warning, TEXT("Attenuation settings for sound = %s - nullptr, used default settings"), *Sound->GetName());
226 }
227
228 AudioDevice->PlaySoundAtLocation(Sound, ThisWorld, VolumeMultiplier, 1.f, 0.f, SoundLocation, FRotator::ZeroRotator, AttenuationSettings, nullptr, nullptr, nullptr);
229 }
230}
231
232void APixoVRToolBase::ServerStopPlayingSound_Implementation(USoundBase* sound)
233{
235}
236
237bool APixoVRToolBase::ServerStopPlayingSound_Validate(USoundBase* sound)
238{
239 return true;
240}
241
242void APixoVRToolBase::MulticastStopPlayingSound_Implementation(USoundBase* Sound)
243{
244 UWorld* ThisWorld = GetWorld();
245 if (!Sound || !ThisWorld || !ThisWorld->bAllowAudioPlayback || ThisWorld->IsNetMode(NM_DedicatedServer))
246 {
247 return;
248 }
249
250 if (FAudioDevice* AudioDevice = ThisWorld->GetAudioDevice().GetAudioDevice())
251 {
252 auto StopSound = [AudioDevice, Sound]()
253 {
254 if(AudioDevice && Sound)
255 {
256 const TArray<FActiveSound*>& ActiveSounds = AudioDevice->GetActiveSounds();
257 for (FActiveSound* ActiveSound : ActiveSounds)
258 {
259 if (ActiveSound->GetSound() == Sound)
260 {
261 AudioDevice->StopActiveSound(ActiveSound);
262 }
263 }
264 }
265 };
266
267 if(IsInAudioThread())
268 {
269 StopSound();
270 }
271 else
272 {
273 if(IsAudioThreadRunning())
274 {
275 FAudioThread::RunCommandOnAudioThread(StopSound);
276 }
277 }
278 }
279}
280
281void APixoVRToolBase::ServerOnDropped_Implementation()
282{
284}
285
286bool APixoVRToolBase::ServerOnDropped_Validate()
287{
288 return true;
289}
290
291void APixoVRToolBase::ServerStartPlayingSoundViaComponent_Implementation(USoundBase* Sound, float VolumeMultiplier /*= 1.0f*/)
292{
293 MulticastStartPlayingSoundViaComponent(Sound, VolumeMultiplier);
294}
295
296bool APixoVRToolBase::ServerStartPlayingSoundViaComponent_Validate(USoundBase* Sound, float VolumeMultiplier /*= 1.0f*/)
297{
298 return true;
299}
300
301void APixoVRToolBase::MulticastStartPlayingSoundViaComponent_Implementation(USoundBase* Sound, float VolumeMultiplier)
302{
303 UWorld* ThisWorld = GetWorld();
304 if (!Sound || (AudioComponent && AudioComponent->IsPlaying()) || !ThisWorld || !ThisWorld->bAllowAudioPlayback || ThisWorld->IsNetMode(NM_DedicatedServer))
305 {
306 return;
307 }
308
309 USoundAttenuation* AttenuationSettings = Sound->AttenuationSettings;
310 if(!AttenuationSettings)
311 {
312 AttenuationSettings = GetDefaultAttenuationSettings();
313
314 UE_LOG(LogTemp, Warning, TEXT("Attenuation settings for sound = %s - nullptr, used default settings"), *Sound->GetName());
315 }
316
317 AudioComponent = UGameplayStatics::SpawnSoundAttached(Sound, RootComponent, "RootComponent", FVector(ForceInit), FRotator::ZeroRotator, EAttachLocation::KeepRelativeOffset, true, VolumeMultiplier, 1.f, 0.f, AttenuationSettings, nullptr, true);
318
319 ensure(AudioComponent);
320}
321
322void APixoVRToolBase::ServerStopPlayingSoundViaComponent_Implementation()
323{
325}
326
327bool APixoVRToolBase::ServerStopPlayingSoundViaComponent_Validate()
328{
329 return true;
330}
331
332void APixoVRToolBase::MulticastStopPlayingSoundViaComponent_Implementation()
333{
334 UWorld* ThisWorld = GetWorld();
335 if (!ThisWorld || !ThisWorld->bAllowAudioPlayback || ThisWorld->IsNetMode(NM_DedicatedServer))
336 {
337 return;
338 }
339
340 if (IsValid(AudioComponent))
341 {
342 AudioComponent->Stop();
343 }
344}
345
346void APixoVRToolBase::ServerAdjustPlayingSoundVolumeViaComponent_Implementation(float InVolumeMultiplier /*= 1.0f*/)
347{
349}
350
351bool APixoVRToolBase::ServerAdjustPlayingSoundVolumeViaComponent_Validate(float InVolumeMultiplier)
352{
353 return true;
354}
355
356void APixoVRToolBase::MulticastAdjustPlayingSoundVolumeViaComponent_Implementation(float InVolumeMultiplier)
357{
358 if (IsValid(AudioComponent) && AudioComponent->VolumeMultiplier != InVolumeMultiplier)
359 {
360 if (InVolumeMultiplier == 0.f || FMath::Abs(AudioComponent->VolumeMultiplier - InVolumeMultiplier) >= 0.05f)
361 {
362 AudioComponent->SetVolumeMultiplier(InVolumeMultiplier);
363 }
364 }
365}
366
367void APixoVRToolBase::ServerUseTool_Implementation(UGripMotionControllerComponent* GrippingController, AActor* GrippedActor)
368{
369 if (bIsGripAllowed)
370 {
371 DestroyState.bIsPendingKill = false;
372
373 GrabHand = IsRightHand(GrippingController) ? EControllerHand::Right : EControllerHand::Left;
374 bIsGripped = true;
375
376 if (bAdvancedDrop)
377 {
378 SetActorRotation(Cast<APixoVRHand>(GrippingController->GetOwner())->GrabSphere->GetComponentRotation());
379 SetActorRelativeRotation(IsRightHand(GrippingController) ? RightHandGrip.GetRotation() : LeftHandGrip.GetRotation());
380 }
381
382 SetActorRelativeTransform(IsRightHand(GrippingController) ? RightHandGrip : LeftHandGrip);
383
385 {
386 GrabBoxComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
387 ToolMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
388 MulticastToggleCollision(ECollisionEnabled::NoCollision);
389 }
390
391 OnGripAction.Broadcast(false);
392 ServerStartPlayingSound(GripSound, GetActorLocation());
393 }
394}
395
396bool APixoVRToolBase::ServerUseTool_Validate(UGripMotionControllerComponent* GrippingController, AActor* GrippedActor)
397{
398 return true;
399}
400
401void APixoVRToolBase::ServerDestroyTool_Implementation()
402{
403 DestroyState.bIsPendingKill = bDestroyOnDrop;
404 DestroyState.TimeBeforeKilled = DestroyDelay;
405
407 {
408 GrabBoxComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
409 ToolMeshComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
410 MulticastToggleCollision(ECollisionEnabled::QueryAndPhysics);
411 }
412
413 GrabHand = EControllerHand::AnyHand;
414 bIsGripped = false;
415
416 OnGripAction.Broadcast(true);
417}
418
419bool APixoVRToolBase::ServerDestroyTool_Validate()
420{
421 return true;
422}
423
425{
426 const auto HandType = Cast<APixoVRHand>(GrippingController->GetOwner())->HandMotionSource;
427 return HandType == EControllerHand::Right ? true : false;
428}
429
431{
433 {
434 DefaultAttenuationSettings = NewObject<USoundAttenuation>();
435 DefaultAttenuationSettings->Attenuation.FalloffDistance = 2000.f;
436 }
437
439}
EPixoVRGripModeEnum
UENUM(BlueprintType)
EPixoVRGripTriggerModeEnum
UENUM(BlueprintType)
Base class for PixoVR tools.
virtual void Tick(float DeltaSeconds) override
FPixoToolData ToolData
UPROPERTY(Replicated, BlueprintReadOnly, Category = ToolData)
virtual void OnOverlapBegin(UPrimitiveComponent *OverlappedComp, AActor *OtherActor, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex, bool FromSweep, const FHitResult &SweepResult)
UFUNCTION()
bool bIsGripped
UPROPERTY(Replicated, BlueprintReadOnly, Category = GripBehavior)
virtual bool DenyDropping_Implementation() override
virtual void OnObjectUnPaused_Implementation() override
USoundAttenuation * GetDefaultAttenuationSettings()
FTransform LeftHandGrip
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = TransformOffset)
void ServerOnDropped()
UFUNCTION(Server, Reliable, WithValidation)
EControllerHand GrabHand
UPROPERTY(Replicated, BlueprintReadOnly, Category = GripBehavior)
virtual void OnGripObjectRelease_Implementation(UGripMotionControllerComponent *GrippingController, AActor *GrippedActor) override
virtual void OnTryGripObject_Implementation(UGripMotionControllerComponent *GrippingController, AActor *GrippedActor) override
float DestroyDelay
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = DropBehavior)
bool bIsGripAllowed
UPROPERTY(BlueprintReadOnly, Category = GripBehavior)
void ServerDestroyTool()
UFUNCTION(Server, Reliable, WithValidation)
void GripTriggerMode(EPixoVRGripTriggerModeEnum &GripTriggerMode)
Will be used to determine how the gripping trigger should behave.
FGripAction OnGripAction
USoundAttenuation * DefaultAttenuationSettings
UPROPERTY()
virtual void BeginPlay() override
void MulticastAdjustPlayingSoundVolumeViaComponent(float InVolumeMultiplier)
UFUNCTION(NetMulticast, Reliable)
UStaticMeshComponent * ToolMeshComponent
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Tool)
virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > &OutLifetimeProps) const override
bool bToggleCollisionOnUsage
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = GripBehavior)
void MulticastStartPlayingSoundViaComponent(USoundBase *Sound, float VolumeMultiplier)
UFUNCTION(NetMulticast, Reliable)
USoundBase * GripSound
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = GripBehavior)
virtual void OnGripObject_Implementation(UGripMotionControllerComponent *GrippingController, AActor *GrippedActor) override
virtual void GripTriggerTransform_Implementation(UGripMotionControllerComponent *GrippingController, bool &bUseCustomTransform, FTransform &CustomTransform) override
void MulticastStartPlayingSound(USoundBase *Sound, const FVector &SoundLocation, float VolumeMultiplier)
UFUNCTION(NetMulticast, Reliable)
virtual bool DenyTriggerGripping_Implementation() override
FTransform RightHandGrip
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = TransformOffset)
bool bIsPaused
UPROPERTY(Replicated, BlueprintReadOnly, Category = ToolBehavior)
bool IsRightHand(UGripMotionControllerComponent *GrippingController) const
void ServerStartPlayingSound(USoundBase *Sound, const FVector &SoundLocation, float VolumeMultiplier=1.0f)
UFUNCTION(Server, Reliable, WithValidation)
UAudioComponent * AudioComponent
UPROPERTY(VisibleAnywhere, Category = Tool)
virtual bool DisablePhysicsOnDrop_Implementation() override
virtual void GripMode_Implementation(EPixoVRGripModeEnum &GripMode) override
bool bAdvancedDrop
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = DropBehavior)
UBoxComponent * GrabBoxComponent
UPROPERTY(VisibleAnywhere, Category = Tool)
void MulticastStopPlayingSoundViaComponent()
UFUNCTION(NetMulticast, Reliable)
virtual void GripTriggerMode_Implementation(EPixoVRGripTriggerModeEnum &GripTriggerMode) override
void MulticastToggleCollision(ECollisionEnabled::Type Type)
UFUNCTION(NetMulticast, Reliable)
void GripMode(EPixoVRGripModeEnum &GripMode)
Will be used to determine how to do the grabbing. Using normal attachment or a physics constraint.
void ServerUseTool(UGripMotionControllerComponent *GrippingController, AActor *GrippedActor)
UFUNCTION(Server, Reliable, WithValidation)
bool bDestroyOnDrop
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = DropBehavior)
virtual bool DenyGrippingPixoVR_Implementation(UGripMotionControllerComponent *GrippingController) override
virtual void OnObjectPaused_Implementation() override
bool IsDestroyable()
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PixoVRToolbox | Tools")
bool IsGripped()
UFUNCTION(BlueprintCallable, Category = Tool)
virtual void InitializeTool_Implementation(const FPixoToolData &InToolData) override
void HandleDestroy()
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PixoVRToolbox | Tools")
struct APixoVRToolBase::@0 DestroyState
void MulticastStopPlayingSound(USoundBase *Sound)
UFUNCTION(NetMulticast, Reliable)
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = MotionController)
Represents data for a tool in PixoCore.
bool DestroyAfterDelay
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool DestroyOnDrop
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float DestroyDelay
UPROPERTY(EditAnywhere, BlueprintReadWrite)