A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
GripMotionControllerComponent.cpp
Go to the documentation of this file.
1// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
2
4#include "IHeadMountedDisplay.h"
5#include "HeadMountedDisplayTypes.h"
6//#include "DestructibleComponent.h" 4.18 moved apex destruct to a plugin
7#include "Misc/ScopeLock.h"
8#include "Net/UnrealNetwork.h"
9#include "PrimitiveSceneInfo.h"
10#include "Engine/World.h"
11#include "GameFramework/WorldSettings.h"
12#include "IXRSystemAssets.h"
13#include "Components/StaticMeshComponent.h"
14#include "MotionDelayBuffer.h"
15#include "UObject/VRObjectVersion.h"
16#include "UObject/UObjectGlobals.h" // for FindObject<>
17#include "IXRTrackingSystem.h"
18#include "IXRSystemAssets.h"
19#include "DrawDebugHelpers.h"
20#include "TimerManager.h"
21#include "VRBaseCharacter.h"
22
25
26#include "PhysicsPublic.h"
27#include "PhysicsEngine/BodySetup.h"
28#include "PhysicsEngine/ConstraintDrives.h"
29#include "PhysicsReplication.h"
30
31#if PHYSICS_INTERFACE_PHYSX
32#include "PhysXPublic.h"
33#elif WITH_CHAOS
34#include "Chaos/ParticleHandle.h"
35#include "Chaos/KinematicGeometryParticles.h"
36#include "Chaos/PBDJointConstraintTypes.h"
37#include "Chaos/PBDJointConstraintData.h"
38#include "Chaos/Sphere.h"
39#include "PhysicsProxy/SingleParticlePhysicsProxy.h"
40#include "Chaos/ChaosConstraintSettings.h"
41#endif
42
44
45#include "Features/IModularFeatures.h"
46
47DEFINE_LOG_CATEGORY(LogVRMotionController);
48//For UE4 Profiler ~ Stat
49DECLARE_CYCLE_STAT(TEXT("TickGrip ~ TickingGrip"), STAT_TickGrip, STATGROUP_TickGrip);
50DECLARE_CYCLE_STAT(TEXT("GetGripWorldTransform ~ GettingTransform"), STAT_GetGripTransform, STATGROUP_TickGrip);
51
52// MAGIC NUMBERS
53// Constraint multipliers for angular, to avoid having to have two sets of stiffness/damping variables
55const float ANGULAR_DAMPING_MULTIPLIER = 1.4f;
56
57// Multiplier for the Interactive Hybrid With Physics grip - When not colliding increases stiffness by this value
59
60namespace {
63 FCriticalSection CritSect;
64
65} // anonymous namespace
66
67 // CVars
69{
70 static int32 DrawDebugGripCOM = 0;
71 FAutoConsoleVariableRef CVarDrawCOMDebugSpheres(
72 TEXT("vr.DrawDebugCenterOfMassForGrips"),
74 TEXT("When on, will draw debug speheres for physics grips COM.\n")
75 TEXT("0: Disable, 1: Enable"),
76 ECVF_Default);
77}
78
79 //=============================================================================
80UGripMotionControllerComponent::UGripMotionControllerComponent(const FObjectInitializer& ObjectInitializer)
81 : Super(ObjectInitializer)
82{
83 PrimaryComponentTick.bCanEverTick = true;
84 PrimaryComponentTick.bStartWithTickEnabled = true;
85 PrimaryComponentTick.TickGroup = TG_PrePhysics;
86 PrimaryComponentTick.bTickEvenWhenPaused = true;
87
88 PlayerIndex = 0;
89 MotionSource = FXRMotionControllerBase::LeftHandSourceId;
90 //Hand = EControllerHand::Left;
91 bDisableLowLatencyUpdate = false;
92 bHasAuthority = false;
94 bUseWithoutTracking = false;
96 bAlwaysSendTickGrip = false;
97 bAutoActivate = true;
98
99 SetIsReplicatedByDefault(true);
100
101 // Default 100 htz update rate, same as the 100htz update rate of rep_notify, will be capped to 90/45 though because of vsync on HMD
102 //bReplicateControllerTransform = true;
103 ControllerNetUpdateRate = 100.0f; // 100 htz is default
106 bLerpingPosition = false;
108 bReppedOnce = false;
109 bScaleTracking = false;
110 TrackingScaler = FVector(1.0f);
111 bLimitMinHeight = false;
112 MinimumHeight = 0.0f;
113 bLimitMaxHeight = false;
114 MaximumHeight = 240.0f;
115 bOffsetByHMD = false;
116 bLeashToHMD = false;
117 LeashRange = 300.0f;
118 bConstrainToPivot = false;
119
120 bSmoothHandTracking = false;
121 bWasSmoothingHand = false;
123 LastSmoothRelativeTransform = FTransform::Identity;
124 SmoothingSpeed = 20.0f;
128
129 bIsPostTeleport = false;
130
132
133 // Pivot Variables
136
138 CurrentControllerProfileTransform = FTransform::Identity;
139
140 DefaultGripScript = nullptr;
141 DefaultGripScriptClass = UGS_Default::StaticClass();
142
144 LastRelativePosition = FTransform::Identity;
146 VelocitySamples = 30.f;
147
149 EndPhysicsTickFunction.TickGroup = TG_EndPhysics;
150 EndPhysicsTickFunction.bCanEverTick = true;
151 EndPhysicsTickFunction.bStartWithTickEnabled = false;
152}
153
155{
156 if (bRegister != EndPhysicsTickFunction.IsTickFunctionRegistered())
157 {
158 if (bRegister)
159 {
160 if (SetupActorComponentTickFunction(&EndPhysicsTickFunction))
161 {
163 // Make sure our EndPhysicsTick gets called after physics simulation is finished
164 UWorld* World = GetWorld();
165 if (World != nullptr)
166 {
167 EndPhysicsTickFunction.AddPrerequisite(World, World->EndPhysicsTickFunction);
168 }
169 }
170 }
171 else
172 {
173 EndPhysicsTickFunction.UnRegisterTickFunction();
174 }
175 }
176}
177
179{
180
181 if (this->IsPendingKill())
182 return;
183
184 // Now check if we should turn off any post physics ticking
185 FTransform baseTrans = this->GetAttachParent()->GetComponentTransform().Inverse();
186
187 for (int i = 0; i < LocallyGrippedObjects.Num(); ++i)
188 {
189 if (!LocallyGrippedObjects[i].GrippedObject || LocallyGrippedObjects[i].GrippedObject->IsPendingKill())
190 continue; // Skip, don't process this
191
192 if (LocallyGrippedObjects[i].GrippedObject && !LocallyGrippedObjects[i].GrippedObject->IsPendingKill() && LocallyGrippedObjects[i].GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
193 {
194 bool bSampleRelativeTransform = bProjectNonSimulatingGrips;
195
196 if (!bSampleRelativeTransform)
197 {
198 EGripInterfaceTeleportBehavior TeleportBehavior = IVRGripInterface::Execute_TeleportBehavior(LocallyGrippedObjects[i].GrippedObject);
199 bSampleRelativeTransform = TeleportBehavior == EGripInterfaceTeleportBehavior::DeltaTeleportation;
200 }
201
202 if (bSampleRelativeTransform)
203 {
204 switch(LocallyGrippedObjects[i].GripTargetType)
205 {
207 {
208 if (AActor* Actor = Cast<AActor>(LocallyGrippedObjects[i].GrippedObject))
209 {
210 if (UPrimitiveComponent* root = Cast<UPrimitiveComponent>(Actor->GetRootComponent()))
211 {
212 LocallyGrippedObjects[i].LastWorldTransform = root->GetComponentTransform() * baseTrans;
213 LocallyGrippedObjects[i].bSetLastWorldTransform = true;
214 }
215 }
216 }break;
218 {
219 if (UPrimitiveComponent* root = Cast<UPrimitiveComponent>(LocallyGrippedObjects[i].GrippedObject))
220 {
221 LocallyGrippedObjects[i].LastWorldTransform = root->GetComponentTransform() * baseTrans;
222 LocallyGrippedObjects[i].bSetLastWorldTransform = true;
223 }
224 }break;
225 }
226 }
227 }
228 }
229
230 for (int i = 0; i < GrippedObjects.Num(); ++i)
231 {
232 if (!GrippedObjects[i].GrippedObject || GrippedObjects[i].GrippedObject->IsPendingKill())
233 continue; // Skip, don't process this
234
235 if (GrippedObjects[i].GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
236 {
237 bool bSampleRelativeTransform = bProjectNonSimulatingGrips;
238
239 if (!bSampleRelativeTransform)
240 {
241 EGripInterfaceTeleportBehavior TeleportBehavior = IVRGripInterface::Execute_TeleportBehavior(GrippedObjects[i].GrippedObject);
242 bSampleRelativeTransform = TeleportBehavior == EGripInterfaceTeleportBehavior::DeltaTeleportation;
243 }
244
245 if (bSampleRelativeTransform)
246 {
247 switch (GrippedObjects[i].GripTargetType)
248 {
250 {
251 if (AActor* Actor = Cast<AActor>(GrippedObjects[i].GrippedObject))
252 {
253 if (UPrimitiveComponent* root = Cast<UPrimitiveComponent>(Actor->GetRootComponent()))
254 {
255 GrippedObjects[i].LastWorldTransform = root->GetComponentTransform() * baseTrans;
256 GrippedObjects[i].bSetLastWorldTransform = true;
257 }
258 }
259 }break;
261 {
262 if (UPrimitiveComponent* root = Cast<UPrimitiveComponent>(GrippedObjects[i].GrippedObject))
263 {
264 GrippedObjects[i].LastWorldTransform = root->GetComponentTransform() * baseTrans;
265 GrippedObjects[i].bSetLastWorldTransform = true;
266 }
267 }break;
268 }
269 }
270 }
271 }
272}
273
274void FGripComponentEndPhysicsTickFunction::ExecuteTick(float DeltaTime, enum ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
275{
276 QUICK_SCOPE_CYCLE_COUNTER(FGripComponentEndPhysicsTickFunction_ExecuteTick);
277 CSV_SCOPED_TIMING_STAT_EXCLUSIVE(Physics);
278
279 if (Target && !Target->IsPendingKill())
280 {
281 FActorComponentTickFunction::ExecuteTickHelper(Target, /*bTickInEditor=*/ false, DeltaTime, TickType, [this](float DilatedTime)
282 {
284 });
285 }
286}
287
289{
290 return TEXT("GripComponentEndPhysicsTickFunction");
291}
292
294{
295 return FName(TEXT("GripComponentEndPhysicsTick"));
296}
297
298
299//=============================================================================
301{
302 // Moved view extension destruction to BeginDestroy like the new controllers
303 // Epic had it listed as a crash in the private bug tracker I guess.
304}
305
310
312{
314 {
315 UVRGlobalSettings* VRSettings = GetMutableDefault<UVRGlobalSettings>();
316
317 if (VRSettings == nullptr)
318 return;
319
320 EControllerHand HandType;
321 this->GetHandType(HandType);
322
323 FTransform NewControllerProfileTransform = FTransform::Identity;
324
325 if (HandType == EControllerHand::Left || HandType == EControllerHand::AnyHand || !VRSettings->bUseSeperateHandTransforms)
326 {
327 NewControllerProfileTransform = VRSettings->CurrentControllerProfileTransform;
328 }
329 else if (HandType == EControllerHand::Right)
330 {
331 NewControllerProfileTransform = VRSettings->CurrentControllerProfileTransformRight;
332 }
333
334 if (bBindToNoticationDelegate && !NewControllerProfileEvent_Handle.IsValid())
335 {
337 }
338
339 if (!NewControllerProfileTransform.Equals(CurrentControllerProfileTransform))
340 {
341 FTransform OriginalControllerProfileTransform = CurrentControllerProfileTransform;
342 CurrentControllerProfileTransform = NewControllerProfileTransform;
343
344 // Auto adjust for FPS testing pawns
346 {
347 this->SetRelativeTransform(CurrentControllerProfileTransform * (OriginalControllerProfileTransform.Inverse() * this->GetRelativeTransform()));
348 }
349
351 }
352 }
353}
354
356{
357 Super::InitializeComponent();
358
360 DefaultGripScript = DefaultGripScriptClass.GetDefaultObject();
361 else
362 DefaultGripScript = GetMutableDefault<UGS_Default>();
363}
364
365void UGripMotionControllerComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
366{
367 Super::EndPlay(EndPlayReason);
368
369 // Cancel end physics tick
371
373 {
374 UVRGlobalSettings* VRSettings = GetMutableDefault<UVRGlobalSettings>();
375 if (VRSettings != nullptr)
376 {
379 }
380 }
381
382 for (int i = 0; i < GrippedObjects.Num(); i++)
383 {
385
386 if (/*HasGripAuthority(GrippedObjects[i]) || */IsServer())
387 {
388 DropObjectByInterface(nullptr, GrippedObjects[i].GripID);
389 }
390 else
391 {
392 if (GrippedObjects[i].GrippedObject)
393 {
394 bool bSimulateOnDrop = true;
395 if (GrippedObjects[i].GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
396 {
397 bSimulateOnDrop = IVRGripInterface::Execute_SimulateOnDrop(GrippedObjects[i].GrippedObject);
398 }
399
400 NotifyDrop(GrippedObjects[i], bSimulateOnDrop);
401 }
402 }
403 }
404 GrippedObjects.Empty();
405
406 for (int i = 0; i < LocallyGrippedObjects.Num(); i++)
407 {
409
410 if (/*HasGripAuthority(LocallyGrippedObjects[i]) || */IsServer())
411 {
413 }
414 else
415 {
416 if (LocallyGrippedObjects[i].GrippedObject)
417 {
418 bool bSimulateOnDrop = true;
419 if (LocallyGrippedObjects[i].GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
420 {
421 bSimulateOnDrop = IVRGripInterface::Execute_SimulateOnDrop(LocallyGrippedObjects[i].GrippedObject);
422 }
423
424 NotifyDrop(LocallyGrippedObjects[i], bSimulateOnDrop);
425 }
426 }
427 }
428 LocallyGrippedObjects.Empty();
429
430 for (int i = 0; i < PhysicsGrips.Num(); i++)
431 {
433 }
434 PhysicsGrips.Empty();
435
436 // Clear any timers that we are managing
437 if (UWorld * myWorld = GetWorld())
438 {
439 myWorld->GetTimerManager().ClearAllTimersForObject(this);
440 }
441
443}
444
446{
447 Super::OnUnregister();
448}
449
451{
452 Super::BeginDestroy();
453
454 if (GripViewExtension.IsValid())
455 {
456 {
457 // This component could be getting accessed from the render thread so it needs to wait
458 // before clearing MotionControllerComponent and allowing the destructor to continue
459 FScopeLock ScopeLock(&CritSect);
460 GripViewExtension->MotionControllerComponent = NULL;
461 }
462
463 GripViewExtension.Reset();
464 }
465}
466
468{
469 Super::BeginPlay();
470}
471
473{
474
475 // Don't bother updating this stuff if we aren't local or using them
476 if (bHasAuthority && !bDisableLowLatencyUpdate && IsActive())
477 {
482
485 {
486 if (UWorld* world = GetWorld())
487 {
488 LateUpdateParams.RenderLastDeltaTime = world->GetDeltaSeconds();
489 }
490
492
494 {
496 }
497 else
498 {
501 }
502 }
503 }
504
505 Super::Super::CreateRenderState_Concurrent(Context);
506}
507
509{
510 // Don't bother updating this stuff if we aren't local or using them
511 if (bHasAuthority && !bDisableLowLatencyUpdate && IsActive())
512 {
513 struct FPrimitiveUpdateRenderThreadRelativeTransformParams
514 {
515 FRenderTrackingParams LateUpdateParams;
516 };
517
518 FPrimitiveUpdateRenderThreadRelativeTransformParams UpdateParams;
519 UpdateParams.LateUpdateParams.GripRenderThreadRelativeTransform = GetRelativeTransform();
520 UpdateParams.LateUpdateParams.GripRenderThreadComponentScale = GetComponentScale();
521 UpdateParams.LateUpdateParams.GripRenderThreadProfileTransform = CurrentControllerProfileTransform;
522 UpdateParams.LateUpdateParams.GripRenderThreadLastLocationForLateUpdate = LastLocationForLateUpdate;
523
524 UpdateParams.LateUpdateParams.bRenderSmoothHandTracking = bSmoothHandTracking;
525 if (UpdateParams.LateUpdateParams.bRenderSmoothHandTracking)
526 {
527 if (UWorld* world = GetWorld())
528 {
529 UpdateParams.LateUpdateParams.RenderLastDeltaTime = world->GetDeltaSeconds();
530 }
531
532 UpdateParams.LateUpdateParams.bRenderSmoothWithEuroLowPassFunction = bSmoothWithEuroLowPassFunction;
533
534 if (UpdateParams.LateUpdateParams.bRenderSmoothWithEuroLowPassFunction)
535 {
536 UpdateParams.LateUpdateParams.RenderEuroSmoothingParams = EuroSmoothingParams;
537 }
538 else
539 {
540 UpdateParams.LateUpdateParams.RenderSmoothingSpeed = SmoothingSpeed;
541 UpdateParams.LateUpdateParams.RenderLastSmoothRelativeTransform = LastSmoothRelativeTransform;
542 }
543 }
544
545 ENQUEUE_RENDER_COMMAND(UpdateRTRelativeTransformCommand)(
546 [UpdateParams, this](FRHICommandListImmediate& RHICmdList)
547 {
548 LateUpdateParams = UpdateParams.LateUpdateParams;
549 });
550 }
551
552 // Skip bases motion controllers implementation, we don't want to double update to the render thread
553 Super::Super::SendRenderTransform_Concurrent();
554}
555
560
562{
563 return PhysicsGrips.FindByKey(GripID);
564}
565
567{
568 index = PhysicsGrips.IndexOfByKey(GripInfo);
569 return index != INDEX_NONE;
570}
571
573{
574 FBPActorPhysicsHandleInformation * HandleInfo = PhysicsGrips.FindByKey(GripInfo);
575
576 if (HandleInfo)
577 {
578 DestroyPhysicsHandle(HandleInfo);
579 return HandleInfo;
580 }
581
583 NewInfo.HandledObject = GripInfo.GrippedObject;
584 NewInfo.GripID = GripInfo.GripID;
585
586 int index = PhysicsGrips.Add(NewInfo);
587
588 return &PhysicsGrips[index];
589}
590
591
592//=============================================================================
593void UGripMotionControllerComponent::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const
594{
595 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
596
597 // Don't ever replicate these, they are getting replaced by my custom send anyway
598 DISABLE_REPLICATED_PRIVATE_PROPERTY(USceneComponent, RelativeLocation);
599 DISABLE_REPLICATED_PRIVATE_PROPERTY(USceneComponent, RelativeRotation);
600 DISABLE_REPLICATED_PRIVATE_PROPERTY(USceneComponent, RelativeScale3D);
601
602
603 // Skipping the owner with this as the owner will use the controllers location directly
604 DOREPLIFETIME_CONDITION(UGripMotionControllerComponent, ReplicatedControllerTransform, COND_SkipOwner);
609
610
611 DOREPLIFETIME_CONDITION(UGripMotionControllerComponent, LocallyGrippedObjects, COND_SkipOwner);
612 DOREPLIFETIME_CONDITION(UGripMotionControllerComponent, LocalTransactionBuffer, COND_OwnerOnly);
613// DOREPLIFETIME(UGripMotionControllerComponent, bReplicateControllerTransform);
614}
615
616/*void UGripMotionControllerComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker)
617{
618 Super::PreReplication(ChangedPropertyTracker);
619
620 // Don't ever replicate these, they are getting replaced by my custom send anyway
621 DOREPLIFETIME_ACTIVE_OVERRIDE(USceneComponent, RelativeLocation, false);
622 DOREPLIFETIME_ACTIVE_OVERRIDE(USceneComponent, RelativeRotation, false);
623 DOREPLIFETIME_ACTIVE_OVERRIDE(USceneComponent, RelativeScale3D, false);
624}*/
625
626void UGripMotionControllerComponent::Server_SendControllerTransform_Implementation(FBPVRComponentPosRep NewTransform)
627{
628 // Store new transform and trigger OnRep_Function
629 ReplicatedControllerTransform = NewTransform;
630
631 // Server should no longer call this RPC itself, but if is using non tracked then it will so keeping auth check
632 if(!bHasAuthority)
634}
635
636bool UGripMotionControllerComponent::Server_SendControllerTransform_Validate(FBPVRComponentPosRep NewTransform)
637{
638 return true;
639 // Optionally check to make sure that player is inside of their bounds and deny it if they aren't?
640}
641
643{
645 {
646 return;
647 }
648
649 // Set up the late update state for the controller component
650 LateUpdate.Setup(MotionControllerComponent->CalcNewComponentToWorld(FTransform()), MotionControllerComponent, false);
651}
652
653void UGripMotionControllerComponent::GetPhysicsVelocities(const FBPActorGripInformation &Grip, FVector &AngularVelocity, FVector &LinearVelocity)
654{
655 UPrimitiveComponent * primComp = Grip.GetGrippedComponent();//Grip.Component;
656 AActor * pActor = Grip.GetGrippedActor();
657
658 if (!primComp && pActor)
659 primComp = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
660
661 if (!primComp)
662 {
663 AngularVelocity = FVector::ZeroVector;
664 LinearVelocity = FVector::ZeroVector;
665 return;
666 }
667
668 AngularVelocity = primComp->GetPhysicsAngularVelocityInDegrees();
669 LinearVelocity = primComp->GetPhysicsLinearVelocity();
670}
671
672bool UGripMotionControllerComponent::GetPhysicsConstraintForce(const FBPActorGripInformation& Grip, FVector& AngularForce, FVector& LinearForce)
673{
675 {
676 if (PhysHandle->HandleData2.IsValid())
677 {
678 FPhysicsInterface::GetForce(PhysHandle->HandleData2, LinearForce, AngularForce);
679 return true;
680 }
681 }
682
683 return false;
684}
685
687{
688 UPrimitiveComponent* primComp = Grip.GetGrippedComponent();//Grip.Component;
689 AActor* pActor = Grip.GetGrippedActor();
690
691 if (!primComp && pActor)
692 primComp = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
693
694 if (!primComp || !primComp->IsSimulatingPhysics())
695 {
696 Mass = 0.f;
697 return;
698 }
699
700 Mass = primComp->GetMass();
701}
702
704{
705 if (!ActorToLookForGrip)
706 {
708 return;
709 }
710
711 FBPActorGripInformation * GripInfo = GrippedObjects.FindByKey(ActorToLookForGrip);
712 if(!GripInfo)
713 GripInfo = LocallyGrippedObjects.FindByKey(ActorToLookForGrip);
714
715 if (GripInfo)
716 {
717 Grip = *GripInfo;// GrippedObjects[i];
719 return;
720 }
721
723}
724
725void UGripMotionControllerComponent::GetGripByComponent(FBPActorGripInformation &Grip, UPrimitiveComponent * ComponentToLookForGrip, EBPVRResultSwitch &Result)
726{
727 if (!ComponentToLookForGrip)
728 {
730 return;
731 }
732
733 FBPActorGripInformation * GripInfo = GrippedObjects.FindByKey(ComponentToLookForGrip);
734 if(!GripInfo)
735 GripInfo = LocallyGrippedObjects.FindByKey(ComponentToLookForGrip);
736
737 if (GripInfo)
738 {
739 Grip = *GripInfo;// GrippedObjects[i];
741 return;
742 }
743
745}
746
748{
749 if (!ObjectToLookForGrip)
750 {
752 return;
753 }
754
755 FBPActorGripInformation * GripInfo = GrippedObjects.FindByKey(ObjectToLookForGrip);
756 if(!GripInfo)
757 GripInfo = LocallyGrippedObjects.FindByKey(ObjectToLookForGrip);
758
759 if (GripInfo)
760 {
761 Grip = *GripInfo;// GrippedObjects[i];
763 return;
764 }
765
767}
768
770{
771 if (IDToLookForGrip == INVALID_VRGRIP_ID)
772 {
773 return nullptr;
774 }
775
776 FBPActorGripInformation* GripInfo = GrippedObjects.FindByKey(IDToLookForGrip);
777 if (!GripInfo)
778 GripInfo = LocallyGrippedObjects.FindByKey(IDToLookForGrip);
779
780 return GripInfo;
781}
782
784{
785 if (IDToLookForGrip == INVALID_VRGRIP_ID)
786 {
788 return;
789 }
790
791 FBPActorGripInformation * GripInfo = GrippedObjects.FindByKey(IDToLookForGrip);
792 if (!GripInfo)
793 GripInfo = LocallyGrippedObjects.FindByKey(IDToLookForGrip);
794
795 if (GripInfo)
796 {
797 Grip = *GripInfo;// GrippedObjects[i];
799 return;
800 }
801
803}
804
806{
807 int fIndex = GrippedObjects.Find(Grip);
808
809 FBPActorGripInformation* GripInformation = nullptr;
810
811 if (fIndex != INDEX_NONE)
812 {
813 GripInformation = &GrippedObjects[fIndex];
814 }
815 else
816 {
817 fIndex = LocallyGrippedObjects.Find(Grip);
818
819 if (fIndex != INDEX_NONE)
820 {
821 GripInformation = &LocallyGrippedObjects[fIndex];
822 }
823 }
824
825 if (GripInformation != nullptr)
826 {
827 GripInformation->bLockHybridGrip = bIsLocked;
829 return;
830 }
831
833}
834
835void UGripMotionControllerComponent::SetGripPaused(const FBPActorGripInformation &Grip, EBPVRResultSwitch &Result, bool bIsPaused, bool bNoConstraintWhenPaused)
836{
837 int fIndex = GrippedObjects.Find(Grip);
838
839 FBPActorGripInformation * GripInformation = nullptr;
840
841 if (fIndex != INDEX_NONE)
842 {
843 GripInformation = &GrippedObjects[fIndex];
844 }
845 else
846 {
847 fIndex = LocallyGrippedObjects.Find(Grip);
848
849 if (fIndex != INDEX_NONE)
850 {
851 GripInformation = &LocallyGrippedObjects[fIndex];
852 }
853 }
854
855 if (GripInformation != nullptr)
856 {
857 if (bNoConstraintWhenPaused)
858 {
859 if (bIsPaused)
860 {
861 if (FBPActorPhysicsHandleInformation * PhysHandle = GetPhysicsGrip(*GripInformation))
862 {
863 DestroyPhysicsHandle(*GripInformation);
864 }
865 }
866 else
867 {
868 ReCreateGrip(*GripInformation);
869 }
870 }
871
872 GripInformation->bIsPaused = bIsPaused;
874 return;
875 }
876
878}
879
880void UGripMotionControllerComponent::SetPausedTransform(const FBPActorGripInformation &Grip, const FTransform & PausedTransform, bool bTeleport)
881{
882
883 FBPActorGripInformation * GripInformation = nullptr;
884
885 int fIndex = GrippedObjects.Find(Grip);
886
887 if (fIndex != INDEX_NONE)
888 {
889 GripInformation = &GrippedObjects[fIndex];
890 }
891 else
892 {
893 fIndex = LocallyGrippedObjects.Find(Grip);
894
895 if (fIndex != INDEX_NONE)
896 {
897 GripInformation = &LocallyGrippedObjects[fIndex];
898 }
899 }
900
901 if (GripInformation != nullptr && GripInformation->GrippedObject != nullptr)
902 {
903 if (bTeleport)
904 {
905 FTransform ProxyTrans = PausedTransform;
906 TeleportMoveGrip_Impl(*GripInformation, true, true, ProxyTrans);
907 }
908 else
909 {
911 {
912 UpdatePhysicsHandleTransform(*GripInformation, PausedTransform);
913 }
914 else
915 {
916 if (GripInformation->GripTargetType == EGripTargetType::ActorGrip)
917 {
918 GripInformation->GetGrippedActor()->SetActorTransform(PausedTransform);
919 }
920 else
921 {
922 GripInformation->GetGrippedComponent()->SetWorldTransform(PausedTransform);
923 }
924 }
925 }
926 }
927}
928
929
930
931
933{
934 int fIndex = GrippedObjects.Find(Grip);
935
936 if (fIndex != INDEX_NONE)
937 {
938 GrippedObjects[fIndex].GripCollisionType = NewGripCollisionType;
941 return;
942 }
943 else
944 {
945 fIndex = LocallyGrippedObjects.Find(Grip);
946
947 if (fIndex != INDEX_NONE)
948 {
949 LocallyGrippedObjects[fIndex].GripCollisionType = NewGripCollisionType;
950
951 if (GetNetMode() == ENetMode::NM_Client && !IsTornOff() && LocallyGrippedObjects[fIndex].GripMovementReplicationSetting == EGripMovementReplicationSettings::ClientSide_Authoritive)
952 {
955 }
956
958
960 return;
961 }
962 }
963
965}
966
968{
969 int fIndex = GrippedObjects.Find(Grip);
970
971 if (fIndex != INDEX_NONE)
972 {
973 GrippedObjects[fIndex].GripLateUpdateSetting = NewGripLateUpdateSetting;
975 return;
976 }
977 else
978 {
979 fIndex = LocallyGrippedObjects.Find(Grip);
980
981 if (fIndex != INDEX_NONE)
982 {
983 LocallyGrippedObjects[fIndex].GripLateUpdateSetting = NewGripLateUpdateSetting;
984
985 if (GetNetMode() == ENetMode::NM_Client && !IsTornOff() && LocallyGrippedObjects[fIndex].GripMovementReplicationSetting == EGripMovementReplicationSettings::ClientSide_Authoritive)
986 {
989 }
990
992 return;
993 }
994 }
995
997}
998
1000 const FBPActorGripInformation &Grip,
1001 EBPVRResultSwitch &Result,
1002 const FTransform & NewRelativeTransform
1003 )
1004{
1005 int fIndex = GrippedObjects.Find(Grip);
1006
1007 if (fIndex != INDEX_NONE)
1008 {
1009 GrippedObjects[fIndex].RelativeTransform = NewRelativeTransform;
1010 if (FBPActorPhysicsHandleInformation * HandleInfo = GetPhysicsGrip(Grip))
1011 {
1012 UpdatePhysicsHandle(Grip.GripID, true);
1014 }
1015
1017 return;
1018 }
1019 else
1020 {
1021 fIndex = LocallyGrippedObjects.Find(Grip);
1022
1023 if (fIndex != INDEX_NONE)
1024 {
1025 LocallyGrippedObjects[fIndex].RelativeTransform = NewRelativeTransform;
1026 if (FBPActorPhysicsHandleInformation * HandleInfo = GetPhysicsGrip(Grip))
1027 {
1028 UpdatePhysicsHandle(Grip.GripID, true);
1030 }
1031
1032 if (GetNetMode() == ENetMode::NM_Client && !IsTornOff() && LocallyGrippedObjects[fIndex].GripMovementReplicationSetting == EGripMovementReplicationSettings::ClientSide_Authoritive)
1033 {
1036 }
1037
1039 return;
1040 }
1041 }
1042
1044}
1045
1047 const FBPActorGripInformation &Grip,
1048 EBPVRResultSwitch &Result,
1049 const FTransform & NewAdditionTransform, bool bMakeGripRelative
1050 )
1051{
1052 int fIndex = GrippedObjects.Find(Grip);
1053
1054 if (fIndex != INDEX_NONE)
1055 {
1056 GrippedObjects[fIndex].AdditionTransform = CreateGripRelativeAdditionTransform(Grip, NewAdditionTransform, bMakeGripRelative);
1057
1059 return;
1060 }
1061 else
1062 {
1063 fIndex = LocallyGrippedObjects.Find(Grip);
1064
1065 if (fIndex != INDEX_NONE)
1066 {
1067 LocallyGrippedObjects[fIndex].AdditionTransform = CreateGripRelativeAdditionTransform(Grip, NewAdditionTransform, bMakeGripRelative);
1068
1070 return;
1071 }
1072 }
1074}
1075
1077 const FBPActorGripInformation &Grip,
1078 EBPVRResultSwitch &Result,
1079 float NewStiffness, float NewDamping, bool bAlsoSetAngularValues, float OptionalAngularStiffness, float OptionalAngularDamping
1080 )
1081{
1083 int fIndex = GrippedObjects.Find(Grip);
1084
1085 if (fIndex != INDEX_NONE)
1086 {
1087 GrippedObjects[fIndex].Stiffness = NewStiffness;
1088 GrippedObjects[fIndex].Damping = NewDamping;
1089
1090 if (bAlsoSetAngularValues)
1091 {
1092 GrippedObjects[fIndex].AdvancedGripSettings.PhysicsSettings.AngularStiffness = OptionalAngularStiffness;
1093 GrippedObjects[fIndex].AdvancedGripSettings.PhysicsSettings.AngularDamping = OptionalAngularDamping;
1094 }
1095
1098 //return;
1099 }
1100 else
1101 {
1102 fIndex = LocallyGrippedObjects.Find(Grip);
1103
1104 if (fIndex != INDEX_NONE)
1105 {
1106 LocallyGrippedObjects[fIndex].Stiffness = NewStiffness;
1107 LocallyGrippedObjects[fIndex].Damping = NewDamping;
1108
1109 if (bAlsoSetAngularValues)
1110 {
1111 LocallyGrippedObjects[fIndex].AdvancedGripSettings.PhysicsSettings.AngularStiffness = OptionalAngularStiffness;
1112 LocallyGrippedObjects[fIndex].AdvancedGripSettings.PhysicsSettings.AngularDamping = OptionalAngularDamping;
1113 }
1114
1115 if (GetNetMode() == ENetMode::NM_Client && !IsTornOff() && LocallyGrippedObjects[fIndex].GripMovementReplicationSetting == EGripMovementReplicationSettings::ClientSide_Authoritive)
1116 {
1119 }
1120
1123 // return;
1124 }
1125 }
1126}
1127
1129 const FBPActorGripInformation &GripToSample,
1130 const FTransform & AdditionTransform,
1131 bool bGripRelative
1132)
1133{
1134 return CreateGripRelativeAdditionTransform(GripToSample, AdditionTransform, bGripRelative);
1135}
1136
1138 UObject * ObjectToGrip,
1139 const FTransform &WorldOffset,
1140 bool bWorldOffsetIsRelative,
1141 FName OptionalSnapToSocketName,
1142 FName OptionalBoneToGripName,
1143 EGripCollisionType GripCollisionType,
1144 EGripLateUpdateSettings GripLateUpdateSetting,
1145 EGripMovementReplicationSettings GripMovementReplicationSetting,
1146 float GripStiffness,
1147 float GripDamping,
1148 bool bIsSlotGrip)
1149{
1150 if (UPrimitiveComponent * PrimComp = Cast<UPrimitiveComponent>(ObjectToGrip))
1151 {
1152 return GripComponent(PrimComp, WorldOffset, bWorldOffsetIsRelative, OptionalSnapToSocketName, OptionalBoneToGripName, GripCollisionType,GripLateUpdateSetting,GripMovementReplicationSetting,GripStiffness,GripDamping, bIsSlotGrip);
1153 }
1154 else if (AActor * Actor = Cast<AActor>(ObjectToGrip))
1155 {
1156 return GripActor(Actor, WorldOffset, bWorldOffsetIsRelative, OptionalSnapToSocketName, OptionalBoneToGripName, GripCollisionType, GripLateUpdateSetting, GripMovementReplicationSetting, GripStiffness, GripDamping, bIsSlotGrip);
1157 }
1158
1159 return false;
1160}
1161
1163 UObject * ObjectToDrop,
1164 uint8 GripIDToDrop,
1165 bool bSimulate,
1166 FVector OptionalAngularVelocity,
1167 FVector OptionalLinearVelocity)
1168{
1169
1170 if (ObjectToDrop != nullptr)
1171 {
1172 FBPActorGripInformation * GripInfo = GrippedObjects.FindByKey(ObjectToDrop);
1173 if (!GripInfo)
1174 GripInfo = LocallyGrippedObjects.FindByKey(ObjectToDrop);
1175
1176 if (GripInfo != nullptr)
1177 {
1178 return DropGrip_Implementation(*GripInfo, bSimulate, OptionalAngularVelocity, OptionalLinearVelocity);
1179 }
1180 }
1181 else if (GripIDToDrop != INVALID_VRGRIP_ID)
1182 {
1183 FBPActorGripInformation * GripInfo = GrippedObjects.FindByKey(GripIDToDrop);
1184 if (!GripInfo)
1185 GripInfo = LocallyGrippedObjects.FindByKey(GripIDToDrop);
1186
1187 if (GripInfo != nullptr)
1188 {
1189 return DropGrip_Implementation(*GripInfo, bSimulate, OptionalAngularVelocity, OptionalLinearVelocity);
1190 }
1191 }
1192
1193 return false;
1194}
1195
1196bool UGripMotionControllerComponent::GripObjectByInterface(UObject * ObjectToGrip, const FTransform &WorldOffset, bool bWorldOffsetIsRelative, FName OptionalBoneToGripName, FName OptionalSnapToSocketName, bool bIsSlotGrip)
1197{
1198 if (UPrimitiveComponent * PrimComp = Cast<UPrimitiveComponent>(ObjectToGrip))
1199 {
1200 AActor * Owner = PrimComp->GetOwner();
1201
1202 if (!Owner)
1203 return false;
1204
1205 if (PrimComp->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
1206 {
1207 EGripCollisionType CollisionType = IVRGripInterface::Execute_GetPrimaryGripType(PrimComp, bIsSlotGrip);
1208
1209 float Stiffness;
1210 float Damping;
1211 IVRGripInterface::Execute_GetGripStiffnessAndDamping(PrimComp, Stiffness, Damping);
1212
1213 return GripComponent(PrimComp, WorldOffset, bWorldOffsetIsRelative, OptionalSnapToSocketName,
1214 OptionalBoneToGripName,
1215 CollisionType,
1216 IVRGripInterface::Execute_GripLateUpdateSetting(PrimComp),
1217 IVRGripInterface::Execute_GripMovementReplicationType(PrimComp),
1218 Stiffness,
1219 Damping,
1220 bIsSlotGrip
1221 );
1222 }
1223 else if (Owner->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
1224 {
1225 EGripCollisionType CollisionType = IVRGripInterface::Execute_GetPrimaryGripType(Owner, bIsSlotGrip);
1226
1227 float Stiffness;
1228 float Damping;
1229 IVRGripInterface::Execute_GetGripStiffnessAndDamping(Owner, Stiffness, Damping);
1230
1231 return GripActor(Owner, WorldOffset, bWorldOffsetIsRelative, OptionalSnapToSocketName,
1232 OptionalBoneToGripName,
1233 CollisionType,
1234 IVRGripInterface::Execute_GripLateUpdateSetting(Owner),
1235 IVRGripInterface::Execute_GripMovementReplicationType(Owner),
1236 Stiffness,
1237 Damping,
1238 bIsSlotGrip
1239 );
1240 /*return GripComponent(PrimComp, WorldOffset, bWorldOffsetIsRelative, OptionalSnapToSocketName,
1241 OptionalBoneToGripName,
1242 CollisionType,
1243 IVRGripInterface::Execute_GripLateUpdateSetting(Owner),
1244 IVRGripInterface::Execute_GripMovementReplicationType(Owner),
1245 Stiffness,
1246 Damping,
1247 bIsSlotGrip
1248 );*/
1249 }
1250 else
1251 {
1252 // No interface, no grip
1253 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController GripObjectByInterface was called on an object that doesn't implement the interface and doesn't have a parent that implements the interface!"));
1254 return false;
1255 }
1256 }
1257 else if (AActor * Actor = Cast<AActor>(ObjectToGrip))
1258 {
1259 UPrimitiveComponent * root = Cast<UPrimitiveComponent>(Actor->GetRootComponent());
1260
1261 if (!root)
1262 return false;
1263
1264 if (root->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
1265 {
1266 EGripCollisionType CollisionType = IVRGripInterface::Execute_GetPrimaryGripType(root, bIsSlotGrip);
1267
1268 float Stiffness;
1269 float Damping;
1270 IVRGripInterface::Execute_GetGripStiffnessAndDamping(root, Stiffness, Damping);
1271
1272 return GripComponent(root, WorldOffset, bWorldOffsetIsRelative, OptionalSnapToSocketName,
1273 OptionalBoneToGripName,
1274 CollisionType,
1275 IVRGripInterface::Execute_GripLateUpdateSetting(root),
1276 IVRGripInterface::Execute_GripMovementReplicationType(root),
1277 Stiffness,
1278 Damping,
1279 bIsSlotGrip
1280 );
1281 /*return GripActor(Actor, WorldOffset, bWorldOffsetIsRelative, OptionalSnapToSocketName,
1282 OptionalBoneToGripName,
1283 CollisionType,
1284 IVRGripInterface::Execute_GripLateUpdateSetting(root),
1285 IVRGripInterface::Execute_GripMovementReplicationType(root),
1286 Stiffness,
1287 Damping,
1288 bIsSlotGrip
1289 );*/
1290 }
1291 else if (Actor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
1292 {
1293 EGripCollisionType CollisionType = IVRGripInterface::Execute_GetPrimaryGripType(Actor, bIsSlotGrip);
1294
1295 float Stiffness;
1296 float Damping;
1297 IVRGripInterface::Execute_GetGripStiffnessAndDamping(Actor, Stiffness, Damping);
1298
1299 return GripActor(Actor, WorldOffset, bWorldOffsetIsRelative, OptionalSnapToSocketName,
1300 OptionalBoneToGripName,
1301 CollisionType,
1302 IVRGripInterface::Execute_GripLateUpdateSetting(Actor),
1303 IVRGripInterface::Execute_GripMovementReplicationType(Actor),
1304 Stiffness,
1305 Damping,
1306 bIsSlotGrip
1307 );
1308 }
1309 else
1310 {
1311 // No interface, no grip
1312 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController GripObjectByInterface was called on an object that doesn't implement the interface and doesn't have a parent that implements the interface!"));
1313 return false;
1314 }
1315 }
1316
1317 return false;
1318}
1319
1320bool UGripMotionControllerComponent::DropObjectByInterface(UObject * ObjectToDrop, uint8 GripIDToDrop, FVector OptionalAngularVelocity, FVector OptionalLinearVelocity)
1321{
1322 FBPActorGripInformation * GripInfo = nullptr;
1323 if (ObjectToDrop != nullptr)
1324 {
1325 GripInfo = GrippedObjects.FindByKey(ObjectToDrop);
1326 if (!GripInfo)
1327 GripInfo = LocallyGrippedObjects.FindByKey(ObjectToDrop);
1328 }
1329 else if (GripIDToDrop != INVALID_VRGRIP_ID)
1330 {
1331 GripInfo = GrippedObjects.FindByKey(GripIDToDrop);
1332 if (!GripInfo)
1333 GripInfo = LocallyGrippedObjects.FindByKey(GripIDToDrop);
1334 }
1335
1336 if (GripInfo == nullptr)
1337 {
1338 return false;
1339 }
1340
1341 if (UPrimitiveComponent * PrimComp = Cast<UPrimitiveComponent>(GripInfo->GrippedObject))
1342 {
1343 AActor * Owner = PrimComp->GetOwner();
1344
1345 if (!Owner)
1346 return false;
1347
1348 if (PrimComp->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
1349 {
1350 return DropGrip_Implementation(*GripInfo, IVRGripInterface::Execute_SimulateOnDrop(PrimComp), OptionalAngularVelocity, OptionalLinearVelocity);
1351 //return DropComponent(PrimComp, IVRGripInterface::Execute_SimulateOnDrop(PrimComp), OptionalAngularVelocity, OptionalLinearVelocity);
1352 }
1353 else if (Owner->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
1354 {
1355 return DropGrip_Implementation(*GripInfo, IVRGripInterface::Execute_SimulateOnDrop(Owner), OptionalAngularVelocity, OptionalLinearVelocity);
1356 //return DropComponent(PrimComp, IVRGripInterface::Execute_SimulateOnDrop(Owner), OptionalAngularVelocity, OptionalLinearVelocity);
1357 }
1358 else
1359 {
1360 // Allowing for failsafe dropping here.
1361 return DropGrip_Implementation(*GripInfo, true, OptionalAngularVelocity, OptionalLinearVelocity);
1362 //return DropComponent(PrimComp, true, OptionalAngularVelocity, OptionalLinearVelocity);
1363 }
1364 }
1365 else if (AActor * Actor = Cast<AActor>(GripInfo->GrippedObject))
1366 {
1367 UPrimitiveComponent * root = Cast<UPrimitiveComponent>(Actor->GetRootComponent());
1368
1369 if (!root)
1370 return false;
1371
1372 if (root->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
1373 {
1374 return DropGrip_Implementation(*GripInfo, IVRGripInterface::Execute_SimulateOnDrop(root), OptionalAngularVelocity, OptionalLinearVelocity);
1375 }
1376 else if (Actor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
1377 {
1378 return DropGrip_Implementation(*GripInfo, IVRGripInterface::Execute_SimulateOnDrop(Actor), OptionalAngularVelocity, OptionalLinearVelocity);
1379 }
1380 else
1381 {
1382 // Failsafe drop here
1383 return DropGrip_Implementation(*GripInfo, true, OptionalAngularVelocity, OptionalLinearVelocity);
1384 }
1385 }
1386
1387 return false;
1388}
1389
1391 AActor* ActorToGrip,
1392 const FTransform &WorldOffset,
1393 bool bWorldOffsetIsRelative,
1394 FName OptionalSnapToSocketName,
1395 FName OptionalBoneToGripName,
1396 EGripCollisionType GripCollisionType,
1397 EGripLateUpdateSettings GripLateUpdateSetting,
1398 EGripMovementReplicationSettings GripMovementReplicationSetting,
1399 float GripStiffness,
1400 float GripDamping,
1401 bool bIsSlotGrip)
1402{
1403 bool bIsLocalGrip = (GripMovementReplicationSetting == EGripMovementReplicationSettings::ClientSide_Authoritive || GripMovementReplicationSetting == EGripMovementReplicationSettings::ClientSide_Authoritive_NoRep);
1404
1405 if (!IsServer() && !bIsLocalGrip)
1406 {
1407 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController grab function was called on the client side as a replicated grip"));
1408 return false;
1409 }
1410
1411 if (!ActorToGrip || ActorToGrip->IsPendingKill())
1412 {
1413 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController grab function was passed an invalid or pending kill actor"));
1414 return false;
1415 }
1416
1417 if (GetIsObjectHeld(ActorToGrip))
1418 {
1419 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController grab function was passed an already gripped actor"));
1420 return false;
1421 }
1422
1423 UPrimitiveComponent *root = Cast<UPrimitiveComponent>(ActorToGrip->GetRootComponent());
1424
1425 if (!root)
1426 {
1427 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController tried to grip an actor without a UPrimitiveComponent Root"));
1428 return false; // Need a primitive root
1429 }
1430
1431 // Has to be movable to work
1432 if (root->Mobility != EComponentMobility::Movable && (GripCollisionType != EGripCollisionType::CustomGrip && GripCollisionType != EGripCollisionType::EventsOnly))
1433 {
1434 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController tried to grip an actor set to static mobility not with a Custom Grip"));
1435 return false; // It is not movable, can't grip it
1436 }
1437
1438 FBPAdvGripSettings AdvancedGripSettings;
1439 UObject * ObjectToCheck = NULL; // Used if having to calculate the transform
1440 //bool bIgnoreHandRotation = false;
1441
1442 TArray<FBPGripPair> HoldingControllers;
1443 bool bIsHeld = false;
1444 bool bHadOriginalSettings = false;
1445 bool bOriginalGravity = false;
1446 bool bOriginalReplication = false;
1447
1448 if (root->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
1449 {
1450 if(IVRGripInterface::Execute_DenyGripping(root, this))
1451 return false; // Interface is saying not to grip it right now
1452
1453 IVRGripInterface::Execute_IsHeld(root, HoldingControllers, bIsHeld);
1454 bool bAllowMultipleGrips = IVRGripInterface::Execute_AllowsMultipleGrips(root);
1455 if (bIsHeld && !bAllowMultipleGrips)
1456 {
1457 return false; // Can't multiple grip this object
1458 }
1459 else if (bIsHeld)
1460 {
1461 // If we are held by multiple controllers then lets copy our original values from the first one
1462 if (HoldingControllers[0].HoldingController != nullptr)
1463 {
1464 FBPActorGripInformation* gripInfo = HoldingControllers[0].HoldingController->GetGripPtrByID(HoldingControllers[0].GripID);
1465
1466 if (gripInfo != nullptr)
1467 {
1468 bHadOriginalSettings = true;
1469 bOriginalGravity = gripInfo->bOriginalGravity;
1470 bOriginalReplication = gripInfo->bOriginalReplicatesMovement;
1471 }
1472 }
1473 }
1474
1475 AdvancedGripSettings = IVRGripInterface::Execute_AdvancedGripSettings(root);
1476 ObjectToCheck = root;
1477 }
1478 else if (ActorToGrip->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
1479 {
1480 if(IVRGripInterface::Execute_DenyGripping(ActorToGrip, this))
1481 return false; // Interface is saying not to grip it right now
1482
1483 IVRGripInterface::Execute_IsHeld(ActorToGrip, HoldingControllers, bIsHeld);
1484 bool bAllowMultipleGrips = IVRGripInterface::Execute_AllowsMultipleGrips(ActorToGrip);
1485 if (bIsHeld && !bAllowMultipleGrips)
1486 {
1487 return false; // Can't multiple grip this object
1488 }
1489 else if (bIsHeld)
1490 {
1491 // If we are held by multiple controllers then lets copy our original values from the first one
1492 if (HoldingControllers[0].HoldingController != nullptr)
1493 {
1494 FBPActorGripInformation* gripInfo = HoldingControllers[0].HoldingController->GetGripPtrByID(HoldingControllers[0].GripID);
1495
1496 if (gripInfo != nullptr)
1497 {
1498 bHadOriginalSettings = true;
1499 bOriginalGravity = gripInfo->bOriginalGravity;
1500 bOriginalReplication = gripInfo->bOriginalReplicatesMovement;
1501 }
1502 }
1503 }
1504
1505 AdvancedGripSettings = IVRGripInterface::Execute_AdvancedGripSettings(ActorToGrip);
1506 ObjectToCheck = ActorToGrip;
1507 }
1508
1509 // So that events caused by sweep and the like will trigger correctly
1510 ActorToGrip->AddTickPrerequisiteComponent(this);
1511
1512 FBPActorGripInformation newActorGrip;
1513 newActorGrip.GripID = GetNextGripID(bIsLocalGrip);
1514 newActorGrip.GripCollisionType = GripCollisionType;
1515 newActorGrip.GrippedObject = ActorToGrip;
1516 if (bHadOriginalSettings)
1517 {
1518 newActorGrip.bOriginalReplicatesMovement = bOriginalReplication;
1519 newActorGrip.bOriginalGravity = bOriginalGravity;
1520 }
1521 else
1522 {
1523 newActorGrip.bOriginalReplicatesMovement = ActorToGrip->IsReplicatingMovement();
1524 newActorGrip.bOriginalGravity = root->IsGravityEnabled();
1525 }
1526 newActorGrip.Stiffness = GripStiffness;
1527 newActorGrip.Damping = GripDamping;
1528 newActorGrip.AdvancedGripSettings = AdvancedGripSettings;
1529 newActorGrip.ValueCache.bWasInitiallyRepped = true; // Set this true on authority side so we can skip a function call on tick
1530 newActorGrip.bIsSlotGrip = bIsSlotGrip;
1531 newActorGrip.GrippedBoneName = OptionalBoneToGripName;
1532 newActorGrip.SlotName = OptionalSnapToSocketName;
1533
1534 // Ignore late update setting if it doesn't make sense with the grip
1535 switch(newActorGrip.GripCollisionType)
1536 {
1539 {
1540 newActorGrip.GripLateUpdateSetting = EGripLateUpdateSettings::LateUpdatesAlwaysOff; // Late updates are bad for this grip
1541 }break;
1542
1543 default:
1544 {
1545 newActorGrip.GripLateUpdateSetting = GripLateUpdateSetting;
1546 }break;
1547 }
1548
1549 if (GripMovementReplicationSetting == EGripMovementReplicationSettings::KeepOriginalMovement)
1550 {
1551 if (ActorToGrip->IsReplicatingMovement())
1552 {
1554 }
1555 else
1556 {
1558 }
1559 }
1560 else
1561 newActorGrip.GripMovementReplicationSetting = GripMovementReplicationSetting;
1562
1564
1565 if (OptionalSnapToSocketName.IsValid() && WorldOffset.Equals(FTransform::Identity) && root->DoesSocketExist(OptionalSnapToSocketName))
1566 {
1567 // I inverse it so that laying out the sockets makes sense
1568 FTransform sockTrans = root->GetSocketTransform(OptionalSnapToSocketName, ERelativeTransformSpace::RTS_Component);
1569 sockTrans.SetScale3D(FVector(1.f) / root->GetComponentScale()); // Prep this so that the inverse works correctly
1570 newActorGrip.RelativeTransform = sockTrans.Inverse();
1571 newActorGrip.bIsSlotGrip = true; // Set this to a slot grip
1572
1573 ObjectToCheck = NULL; // Null it back out, socketed grips don't use this
1574
1575 newActorGrip.SlotName = OptionalSnapToSocketName;
1576 }
1577 else if (bWorldOffsetIsRelative)
1578 {
1579 if (bSkipPivotTransformAdjustment && CustomPivotComponent.IsValid() && !bIsSlotGrip)
1580 {
1581 newActorGrip.RelativeTransform = (WorldOffset * this->GetComponentTransform()).GetRelativeTransform(CustomPivotComponent->GetComponentTransform());
1582 }
1583 else
1584 {
1585 newActorGrip.RelativeTransform = WorldOffset;
1586 }
1587 }
1588 else
1589 {
1590 newActorGrip.RelativeTransform = WorldOffset.GetRelativeTransform(GetPivotTransform());
1591 }
1592
1593 if (!bIsLocalGrip)
1594 {
1595 int32 Index = GrippedObjects.Add(newActorGrip);
1596 if (Index != INDEX_NONE)
1597 NotifyGrip(GrippedObjects[Index]);
1598 //NotifyGrip(newActorGrip);
1599 }
1600 else
1601 {
1602 if (!IsLocallyControlled())
1603 {
1604 LocalTransactionBuffer.Add(newActorGrip);
1605 }
1606
1607 int32 Index = LocallyGrippedObjects.Add(newActorGrip);
1608
1609 if (Index != INDEX_NONE)
1610 {
1611 if (!IsLocallyControlled())
1612 {
1614 {
1615 return true;
1616 }
1617 }
1618 else
1619 {
1620 if (!NotifyGrip(LocallyGrippedObjects[Index]))
1621 {
1622 return true;
1623 }
1624 }
1625
1626 if (bIsLocalGrip && GetNetMode() == ENetMode::NM_Client && !IsTornOff() && newActorGrip.GripMovementReplicationSetting == EGripMovementReplicationSettings::ClientSide_Authoritive)
1627 {
1628 Index = LocallyGrippedObjects.IndexOfByKey(newActorGrip.GripID);
1629 if (Index != INDEX_NONE)
1630 {
1633 }
1634 }
1635 }
1636 }
1637 //NotifyGrip(newActorGrip);
1638
1639 return true;
1640}
1641
1642bool UGripMotionControllerComponent::DropActor(AActor* ActorToDrop, bool bSimulate, FVector OptionalAngularVelocity, FVector OptionalLinearVelocity)
1643{
1644 if (!ActorToDrop)
1645 {
1646 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop function was passed an invalid actor"));
1647 return false;
1648 }
1649
1650 FBPActorGripInformation * GripToDrop = LocallyGrippedObjects.FindByKey(ActorToDrop);
1651
1652 if(GripToDrop)
1653 return DropGrip_Implementation(*GripToDrop, bSimulate, OptionalAngularVelocity, OptionalLinearVelocity);
1654
1655 if (!IsServer())
1656 {
1657 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop function was called on the client side with a replicated grip"));
1658 return false;
1659 }
1660
1661 GripToDrop = GrippedObjects.FindByKey(ActorToDrop);
1662 if (GripToDrop)
1663 return DropGrip_Implementation(*GripToDrop, bSimulate, OptionalAngularVelocity, OptionalLinearVelocity);
1664
1665 return false;
1666}
1667
1669 UPrimitiveComponent* ComponentToGrip,
1670 const FTransform &WorldOffset,
1671 bool bWorldOffsetIsRelative,
1672 FName OptionalSnapToSocketName,
1673 FName OptionalBoneToGripName,
1674 EGripCollisionType GripCollisionType,
1675 EGripLateUpdateSettings GripLateUpdateSetting,
1676 EGripMovementReplicationSettings GripMovementReplicationSetting,
1677 float GripStiffness,
1678 float GripDamping,
1679 bool bIsSlotGrip
1680 )
1681{
1682
1683 bool bIsLocalGrip = (GripMovementReplicationSetting == EGripMovementReplicationSettings::ClientSide_Authoritive || GripMovementReplicationSetting == EGripMovementReplicationSettings::ClientSide_Authoritive_NoRep);
1684
1685 if (!IsServer() && !bIsLocalGrip)
1686 {
1687 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController grab function was called on the client side with a replicating grip"));
1688 return false;
1689 }
1690
1691 if (!ComponentToGrip || ComponentToGrip->IsPendingKill())
1692 {
1693 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController grab function was passed an invalid or pending kill component"));
1694 return false;
1695 }
1696
1697 if (GetIsObjectHeld(ComponentToGrip))
1698 {
1699 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController grab function was passed an already gripped component"));
1700 return false;
1701 }
1702
1703 // Has to be movable to work
1704 if (ComponentToGrip->Mobility != EComponentMobility::Movable && (GripCollisionType != EGripCollisionType::CustomGrip && GripCollisionType != EGripCollisionType::EventsOnly))
1705 {
1706 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController tried to grip a component set to static mobility not in CustomGrip mode"));
1707 return false; // It is not movable, can't grip it
1708 }
1709
1710 FBPAdvGripSettings AdvancedGripSettings;
1711 UObject * ObjectToCheck = NULL;
1712 //bool bIgnoreHandRotation = false;
1713
1714 TArray<FBPGripPair> HoldingControllers;
1715 bool bIsHeld = false;
1716 bool bHadOriginalSettings = false;
1717 bool bOriginalGravity = false;
1718 bool bOriginalReplication = false;
1719
1720 if (ComponentToGrip->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
1721 {
1722 if(IVRGripInterface::Execute_DenyGripping(ComponentToGrip, this))
1723 return false; // Interface is saying not to grip it right now
1724
1725 IVRGripInterface::Execute_IsHeld(ComponentToGrip, HoldingControllers, bIsHeld);
1726 bool bAllowMultipleGrips = IVRGripInterface::Execute_AllowsMultipleGrips(ComponentToGrip);
1727 if (bIsHeld && !bAllowMultipleGrips)
1728 {
1729 return false; // Can't multiple grip this object
1730 }
1731 else if(bIsHeld)
1732 {
1733 // If we are held by multiple controllers then lets copy our original values from the first one
1734 if (HoldingControllers[0].HoldingController != nullptr)
1735 {
1736 FBPActorGripInformation gripInfo;
1737 EBPVRResultSwitch result;
1738 HoldingControllers[0].HoldingController->GetGripByID(gripInfo, HoldingControllers[0].GripID, result);
1739
1740 if (result != EBPVRResultSwitch::OnFailed)
1741 {
1742 bHadOriginalSettings = true;
1743 bOriginalGravity = gripInfo.bOriginalGravity;
1744 bOriginalReplication = gripInfo.bOriginalReplicatesMovement;
1745 }
1746 }
1747 }
1748
1749
1750 AdvancedGripSettings = IVRGripInterface::Execute_AdvancedGripSettings(ComponentToGrip);
1751 ObjectToCheck = ComponentToGrip;
1752 }
1753
1754 //ComponentToGrip->IgnoreActorWhenMoving(this->GetOwner(), true);
1755 // So that events caused by sweep and the like will trigger correctly
1756
1757 ComponentToGrip->AddTickPrerequisiteComponent(this);
1758
1759 FBPActorGripInformation newComponentGrip;
1760 newComponentGrip.GripID = GetNextGripID(bIsLocalGrip);
1761 newComponentGrip.GripCollisionType = GripCollisionType;
1762 newComponentGrip.GrippedObject = ComponentToGrip;
1763
1764 if (bHadOriginalSettings)
1765 {
1766 newComponentGrip.bOriginalReplicatesMovement = bOriginalReplication;
1767 newComponentGrip.bOriginalGravity = bOriginalGravity;
1768 }
1769 else
1770 {
1771 if (ComponentToGrip->GetOwner())
1772 newComponentGrip.bOriginalReplicatesMovement = ComponentToGrip->GetOwner()->IsReplicatingMovement();
1773
1774 newComponentGrip.bOriginalGravity = ComponentToGrip->IsGravityEnabled();
1775 }
1776 newComponentGrip.Stiffness = GripStiffness;
1777 newComponentGrip.Damping = GripDamping;
1778 newComponentGrip.AdvancedGripSettings = AdvancedGripSettings;
1780 newComponentGrip.ValueCache.bWasInitiallyRepped = true; // Set this true on authority side so we can skip a function call on tick
1781 newComponentGrip.bIsSlotGrip = bIsSlotGrip;
1782 newComponentGrip.GrippedBoneName = OptionalBoneToGripName;
1783 newComponentGrip.SlotName = OptionalSnapToSocketName;
1784
1785 // Ignore late update setting if it doesn't make sense with the grip
1786 switch (newComponentGrip.GripCollisionType)
1787 {
1790 {
1791 newComponentGrip.GripLateUpdateSetting = EGripLateUpdateSettings::LateUpdatesAlwaysOff; // Late updates are bad for this grip
1792 }break;
1793
1794 default:
1795 {
1796 newComponentGrip.GripLateUpdateSetting = GripLateUpdateSetting;
1797 }break;
1798 }
1799
1800
1801 if (GripMovementReplicationSetting == EGripMovementReplicationSettings::KeepOriginalMovement)
1802 {
1803 if (ComponentToGrip->GetOwner())
1804 {
1805 if (ComponentToGrip->GetOwner()->IsReplicatingMovement())
1806 {
1808 }
1809 else
1810 {
1812 }
1813 }
1814 else
1816 }
1817 else
1818 newComponentGrip.GripMovementReplicationSetting = GripMovementReplicationSetting;
1819
1820 if (OptionalSnapToSocketName.IsValid() && WorldOffset.Equals(FTransform::Identity) && ComponentToGrip->DoesSocketExist(OptionalSnapToSocketName))
1821 {
1822 // I inverse it so that laying out the sockets makes sense
1823 FTransform sockTrans = ComponentToGrip->GetSocketTransform(OptionalSnapToSocketName, ERelativeTransformSpace::RTS_Component);
1824 sockTrans.SetScale3D(FVector(1.f) / ComponentToGrip->GetComponentScale()); // Prep this so that the inverse works correctly
1825 newComponentGrip.RelativeTransform = sockTrans.Inverse();
1826 newComponentGrip.bIsSlotGrip = true; // Set this to a slot grip
1827
1828 ObjectToCheck = NULL; // Null it out, socketed grips don't use this
1829 }
1830 else if (bWorldOffsetIsRelative)
1831 {
1832 if (bSkipPivotTransformAdjustment && CustomPivotComponent.IsValid() && !bIsSlotGrip)
1833 {
1834 newComponentGrip.RelativeTransform = (WorldOffset * this->GetComponentTransform()).GetRelativeTransform(CustomPivotComponent->GetComponentTransform());
1835 }
1836 else
1837 {
1838 newComponentGrip.RelativeTransform = WorldOffset;
1839 }
1840 }
1841 else
1842 {
1843 newComponentGrip.RelativeTransform = WorldOffset.GetRelativeTransform(GetPivotTransform());
1844 }
1845
1846 if (!bIsLocalGrip)
1847 {
1848 int32 Index = GrippedObjects.Add(newComponentGrip);
1849 if (Index != INDEX_NONE)
1850 NotifyGrip(GrippedObjects[Index]);
1851
1852 //NotifyGrip(newComponentGrip);
1853 }
1854 else
1855 {
1856 if (!IsLocallyControlled())
1857 {
1858 LocalTransactionBuffer.Add(newComponentGrip);
1859 }
1860
1861 int32 Index = LocallyGrippedObjects.Add(newComponentGrip);
1862
1863 if (Index != INDEX_NONE)
1864 {
1865 if (!IsLocallyControlled())
1866 {
1868 {
1869 return true;
1870 }
1871 }
1872 else
1873 {
1874 if (!NotifyGrip(LocallyGrippedObjects[Index]))
1875 {
1876 return true;
1877 }
1878 }
1879
1880 if (bIsLocalGrip && GetNetMode() == ENetMode::NM_Client && !IsTornOff() && newComponentGrip.GripMovementReplicationSetting == EGripMovementReplicationSettings::ClientSide_Authoritive)
1881 {
1882 Index = LocallyGrippedObjects.IndexOfByKey(newComponentGrip.GripID);
1883 if (Index != INDEX_NONE)
1884 {
1887 }
1888 }
1889 }
1890 }
1891
1892 return true;
1893}
1894
1895bool UGripMotionControllerComponent::DropComponent(UPrimitiveComponent * ComponentToDrop, bool bSimulate, FVector OptionalAngularVelocity, FVector OptionalLinearVelocity)
1896{
1897
1898 FBPActorGripInformation *GripInfo;
1899
1900 // First check for it in the local grips
1901 GripInfo = LocallyGrippedObjects.FindByKey(ComponentToDrop);
1902
1903 if (GripInfo != nullptr)
1904 {
1905 return DropGrip_Implementation(*GripInfo, bSimulate, OptionalAngularVelocity, OptionalLinearVelocity);
1906 }
1907
1908 // If we aren't the server then fail out
1909 if (!IsServer())
1910 {
1911 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop function was called on the client side for a replicated grip"));
1912 return false;
1913 }
1914
1915 // Now check in the server auth gripsop)
1916 GripInfo = GrippedObjects.FindByKey(ComponentToDrop);
1917
1918 if (GripInfo != nullptr)
1919 {
1920 return DropGrip_Implementation(*GripInfo, bSimulate, OptionalAngularVelocity, OptionalLinearVelocity);
1921 }
1922 else
1923 {
1924 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop function was passed an invalid component"));
1925 return false;
1926 }
1927
1928 //return false;
1929}
1930
1931bool UGripMotionControllerComponent::DropGrip(const FBPActorGripInformation& Grip, bool bSimulate, FVector OptionalAngularVelocity, FVector OptionalLinearVelocity)
1932{
1933 return DropGrip_Implementation(Grip, bSimulate, OptionalAngularVelocity, OptionalLinearVelocity);
1934}
1935
1936bool UGripMotionControllerComponent::DropGrip_Implementation(const FBPActorGripInformation &Grip, bool bSimulate, FVector OptionalAngularVelocity, FVector OptionalLinearVelocity, bool bSkipNotify)
1937{
1938 int FoundIndex = 0;
1939 bool bIsServer = IsServer();
1940 bool bWasLocalGrip = false;
1941 if (!LocallyGrippedObjects.Find(Grip, FoundIndex)) // This auto checks if Actor and Component are valid in the == operator
1942 {
1943 if (!bIsServer)
1944 {
1945 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop function was called on the client side for a replicated grip"));
1946 return false;
1947 }
1948
1949 if (!GrippedObjects.Find(Grip, FoundIndex)) // This auto checks if Actor and Component are valid in the == operator
1950 {
1951 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop function was passed an invalid drop"));
1952 return false;
1953 }
1954
1955 bWasLocalGrip = false;
1956 }
1957 else
1958 bWasLocalGrip = true;
1959
1960 if (bWasLocalGrip && bIsServer)
1961 {
1962 for (int i = LocalTransactionBuffer.Num() - 1; i >= 0; i--)
1963 {
1964 if (LocalTransactionBuffer[i].GripID == Grip.GripID)
1965 LocalTransactionBuffer.RemoveAt(i);
1966 }
1967 }
1968
1969 UPrimitiveComponent * PrimComp = nullptr;
1970
1971 AActor * pActor = nullptr;
1972 if (bWasLocalGrip)
1973 {
1974 PrimComp = LocallyGrippedObjects[FoundIndex].GetGrippedComponent();
1975 pActor = LocallyGrippedObjects[FoundIndex].GetGrippedActor();
1976 }
1977 else
1978 {
1979 PrimComp = GrippedObjects[FoundIndex].GetGrippedComponent();
1980 pActor = GrippedObjects[FoundIndex].GetGrippedActor();
1981 }
1982
1983 if (!PrimComp && pActor)
1984 PrimComp = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
1985
1986 if(!PrimComp)
1987 {
1988 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop function was passed an invalid drop or CleanUpBadGrip wascalled"));
1989 //return false;
1990 }
1991 else
1992 {
1993 if (bSimulate && (!OptionalLinearVelocity.IsNearlyZero() || !OptionalAngularVelocity.IsNearlyZero()))
1994 {
1996 {
1997 // Need to set simulation in all of these cases, including if it isn't the root component (simulation isn't replicated on non roots)
1999 {
2000 if (PrimComp->IsSimulatingPhysics() != bSimulate)
2001 {
2002 PrimComp->SetSimulatePhysics(bSimulate);
2003 }
2004 }
2005 }
2006
2007 // Had to move in front of deletion to properly set velocity
2008 if (PrimComp->IsSimulatingPhysics())
2009 {
2010 PrimComp->SetPhysicsLinearVelocity(OptionalLinearVelocity);
2011 PrimComp->SetPhysicsAngularVelocityInDegrees(OptionalAngularVelocity);
2012 }
2013 }
2014 }
2015
2016 if (bWasLocalGrip)
2017 {
2018 if (GetNetMode() == ENetMode::NM_Client)
2019 {
2020 if (!IsTornOff())
2021 {
2022 FTransform_NetQuantize TransformAtDrop = FTransform::Identity;
2023
2024 switch (LocallyGrippedObjects[FoundIndex].GripTargetType)
2025 {
2027 {
2028 if (AActor * GrippedActor = LocallyGrippedObjects[FoundIndex].GetGrippedActor())
2029 {
2030 TransformAtDrop = GrippedActor->GetActorTransform();
2031 }
2032 }; break;
2034 {
2035 if (UPrimitiveComponent * GrippedPrim = LocallyGrippedObjects[FoundIndex].GetGrippedComponent())
2036 {
2037 TransformAtDrop = GrippedPrim->GetComponentTransform();
2038 }
2039 }break;
2040 default:break;
2041 }
2042
2043 if(!bSkipNotify)
2044 Server_NotifyLocalGripRemoved(LocallyGrippedObjects[FoundIndex].GripID, TransformAtDrop, OptionalAngularVelocity, OptionalLinearVelocity);
2045 }
2046
2047 // Have to call this ourselves
2048 Drop_Implementation(LocallyGrippedObjects[FoundIndex], bSimulate);
2049 }
2050 else // Server notifyDrop it
2051 {
2052 NotifyDrop(LocallyGrippedObjects[FoundIndex], bSimulate);
2053 }
2054 }
2055 else
2056 NotifyDrop(GrippedObjects[FoundIndex], bSimulate);
2057
2058 //GrippedObjects.RemoveAt(FoundIndex);
2059 return true;
2060}
2061
2062bool UGripMotionControllerComponent::DropAndSocketObject(const FTransform_NetQuantize & RelativeTransformToParent, UObject * ObjectToDrop, uint8 GripIDToDrop, USceneComponent * SocketingParent, FName OptionalSocketName, bool bWeldBodies)
2063{
2064 if (!SocketingParent)
2065 {
2066 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop and socket function was passed an invalid socketing parent"));
2067 return false;
2068 }
2069
2070 if (!ObjectToDrop && GripIDToDrop == INVALID_VRGRIP_ID)
2071 {
2072 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop and socket function was passed an invalid object"));
2073 return false;
2074 }
2075
2076 bool bWasLocalGrip = false;
2077 FBPActorGripInformation * GripInfo = nullptr;
2078
2079 if (ObjectToDrop)
2080 GripInfo = LocallyGrippedObjects.FindByKey(ObjectToDrop);
2081 else if (GripIDToDrop != INVALID_VRGRIP_ID)
2082 GripInfo = LocallyGrippedObjects.FindByKey(GripIDToDrop);
2083
2084 if(GripInfo) // This auto checks if Actor and Component are valid in the == operator
2085 {
2086 bWasLocalGrip = true;
2087 }
2088 else
2089 {
2090 if (!IsServer())
2091 {
2092 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop and socket function was called on the client side for a replicated grip"));
2093 return false;
2094 }
2095
2096 if(ObjectToDrop)
2097 GripInfo = GrippedObjects.FindByKey(ObjectToDrop);
2098 else if(GripIDToDrop != INVALID_VRGRIP_ID)
2099 GripInfo = GrippedObjects.FindByKey(GripIDToDrop);
2100
2101 if(GripInfo) // This auto checks if Actor and Component are valid in the == operator
2102 {
2103 bWasLocalGrip = false;
2104 }
2105 else
2106 {
2107 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop and socket function was passed an invalid drop"));
2108 return false;
2109 }
2110 }
2111
2112 if(GripInfo)
2113 return DropAndSocketGrip_Implementation(*GripInfo, SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2114
2115 return false;
2116}
2117
2118bool UGripMotionControllerComponent::DropAndSocketGrip(const FBPActorGripInformation& GripToDrop, USceneComponent* SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize& RelativeTransformToParent, bool bWeldBodies)
2119{
2120 return DropAndSocketGrip_Implementation(GripToDrop, SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2121}
2122
2123bool UGripMotionControllerComponent::DropAndSocketGrip_Implementation(const FBPActorGripInformation & GripToDrop, USceneComponent * SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize & RelativeTransformToParent, bool bWeldBodies, bool bSkipServerNotify)
2124{
2125 if (!SocketingParent || SocketingParent->IsPendingKill())
2126 {
2127 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop and socket function was passed an invalid socketing parent"));
2128 return false;
2129 }
2130
2131 bool bWasLocalGrip = false;
2132 FBPActorGripInformation * GripInfo = nullptr;
2133
2134 GripInfo = LocallyGrippedObjects.FindByKey(GripToDrop);
2135 if (GripInfo) // This auto checks if Actor and Component are valid in the == operator
2136 {
2137 bWasLocalGrip = true;
2138 }
2139 else
2140 {
2141 if (!IsServer())
2142 {
2143 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop and socket function was called on the client side for a replicated grip"));
2144 return false;
2145 }
2146
2147 GripInfo = GrippedObjects.FindByKey(GripToDrop);
2148
2149 if (GripInfo) // This auto checks if Actor and Component are valid in the == operator
2150 {
2151 bWasLocalGrip = false;
2152 }
2153 else
2154 {
2155 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop and socket function was passed an invalid drop"));
2156 return false;
2157 }
2158 }
2159
2160 UPrimitiveComponent * PrimComp = nullptr;
2161
2162 AActor * pActor = nullptr;
2163
2164 PrimComp = GripInfo->GetGrippedComponent();
2165 pActor = GripInfo->GetGrippedActor();
2166
2167 if (!PrimComp && pActor)
2168 PrimComp = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
2169
2170 if (!PrimComp)
2171 {
2172 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop and socket function was passed an invalid drop or CleanUpBadGrip wascalled"));
2173 //return false;
2174 }
2175
2176 UObject * GrippedObject = GripInfo->GrippedObject;
2177
2178 if (!GrippedObject || GrippedObject->IsPendingKill())
2179 {
2180 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController drop and socket function was passed an invalid or pending kill gripped object"));
2181 return false;
2182 }
2183
2184 int PhysicsHandleIndex = INDEX_NONE;
2185 GetPhysicsGripIndex(*GripInfo, PhysicsHandleIndex);
2186
2187 if (bWasLocalGrip)
2188 {
2189 if (GetNetMode() == ENetMode::NM_Client)
2190 {
2191 if (!IsTornOff() && !bSkipServerNotify)
2192 {
2193 Server_NotifyDropAndSocketGrip(GripInfo->GripID, SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2194 }
2195
2196 OnSocketingObject.Broadcast(*GripInfo, SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2197 Socket_Implementation(GrippedObject, (PhysicsHandleIndex != INDEX_NONE), SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2198
2199 // Have to call this ourselves
2201 }
2202 else // Server notifyDrop it
2203 {
2204 //Socket_Implementation(GrippedObject, (PhysicsHandleIndex != INDEX_NONE), SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2205 NotifyDropAndSocket(*GripInfo, SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2206 }
2207 }
2208 else
2209 {
2210 //Socket_Implementation(GrippedObject, (PhysicsHandleIndex != INDEX_NONE), SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2211 NotifyDropAndSocket(*GripInfo, SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2212 }
2213
2214 //GrippedObjects.RemoveAt(FoundIndex);
2215 return true;
2216}
2217
2218void UGripMotionControllerComponent::SetSocketTransform(UObject* ObjectToSocket, /*USceneComponent * SocketingParent,*/ const FTransform_NetQuantize RelativeTransformToParent/*, FName OptionalSocketName, bool bWeldBodies*/)
2219{
2220 if (ObjectsWaitingForSocketUpdate.RemoveSingle(ObjectToSocket) < 1)
2221 {
2222 // I know that technically it should never happen that the pointers get reset with a uproperty
2223 // But does it really hurt to add this pathway anyway?
2224 for (int i = ObjectsWaitingForSocketUpdate.Num() - 1; i >= 0; --i)
2225 {
2226 if (ObjectsWaitingForSocketUpdate[i] == nullptr)
2228 }
2229
2230 return;
2231 }
2232
2233 if (!ObjectToSocket || ObjectToSocket->IsPendingKill())
2234 return;
2235
2236 /*FAttachmentTransformRules TransformRule = FAttachmentTransformRules::KeepWorldTransform;//KeepWorldTransform;
2237 TransformRule.bWeldSimulatedBodies = bWeldBodies;*/
2238
2239 if (UPrimitiveComponent * root = Cast<UPrimitiveComponent>(ObjectToSocket))
2240 {
2241 //root->AttachToComponent(SocketingParent, TransformRule, OptionalSocketName);
2242 //root->SetRelativeTransform(RelativeTransformToParent);
2243
2244 if(root->GetAttachParent())
2245 root->SetRelativeTransform(RelativeTransformToParent);
2246 }
2247 else if (AActor * pActor = Cast<AActor>(ObjectToSocket))
2248 {
2249 //pActor->AttachToComponent(SocketingParent, TransformRule, OptionalSocketName);
2250 //pActor->SetActorRelativeTransform(RelativeTransformToParent);
2251
2252 if(pActor->GetAttachParentActor())
2253 pActor->SetActorRelativeTransform(RelativeTransformToParent);
2254 }
2255}
2256
2257
2258bool UGripMotionControllerComponent::Server_NotifyDropAndSocketGrip_Validate(uint8 GripID, USceneComponent * SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize & RelativeTransformToParent, bool bWeldBodies)
2259{
2260 return true;
2261}
2262
2263void UGripMotionControllerComponent::Server_NotifyDropAndSocketGrip_Implementation(uint8 GripID, USceneComponent * SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize & RelativeTransformToParent, bool bWeldBodies)
2264{
2265 FBPActorGripInformation FoundGrip;
2266 EBPVRResultSwitch Result;
2267
2268 GetGripByID(FoundGrip, GripID, Result);
2269
2270 if (Result == EBPVRResultSwitch::OnFailed)
2271 return;
2272
2273 int PhysicsHandleIndex = INDEX_NONE;
2274 GetPhysicsGripIndex(FoundGrip, PhysicsHandleIndex);
2275
2276 if (FoundGrip.GrippedObject)
2277 {
2278 OnSocketingObject.Broadcast(FoundGrip, SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2279 Socket_Implementation(FoundGrip.GrippedObject, (PhysicsHandleIndex != INDEX_NONE), SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2280 }
2281
2282 if (!DropAndSocketGrip_Implementation(FoundGrip, SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies))
2283 {
2284 DropGrip_Implementation(FoundGrip, false);
2285 }
2286
2287}
2288
2289void UGripMotionControllerComponent::Socket_Implementation(UObject * ObjectToSocket, bool bWasSimulating, USceneComponent * SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize & RelativeTransformToParent, bool bWeldBodies)
2290{
2291 // Check for valid objects
2292 if (!SocketingParent || !SocketingParent->IsValidLowLevelFast() || !ObjectToSocket || !ObjectToSocket->IsValidLowLevelFast())
2293 {
2294 if (!SocketingParent || !SocketingParent->IsValidLowLevelFast())
2295 {
2296 UE_LOG(LogVRMotionController, Error, TEXT("VRGripMotionController Socket_Implementation was called with an invalid Socketing Parent object"));
2297 }
2298 else
2299 {
2300 UE_LOG(LogVRMotionController, Error, TEXT("VRGripMotionController Socket_Implementation was called with an invalid Object to Socket"));
2301 }
2302 return;
2303 }
2304
2305 FAttachmentTransformRules TransformRule = FAttachmentTransformRules::KeepWorldTransform;//KeepWorldTransform;
2306 TransformRule.bWeldSimulatedBodies = bWeldBodies;
2307
2308 //UPrimitiveComponent * ParentPrim = Cast<UPrimitiveComponent>(SocketingParent);
2309
2310 if (UPrimitiveComponent * root = Cast<UPrimitiveComponent>(ObjectToSocket))
2311 {
2312
2313 if (FBodyInstance* rBodyInstance = root->GetBodyInstance())
2314 {
2315 if (rBodyInstance->OnRecalculatedMassProperties().IsBoundToObject(this))
2316 {
2317 rBodyInstance->OnRecalculatedMassProperties().RemoveAll(this);
2318 }
2319 }
2320
2321 // Stop simulation for socketing
2322 if (bWasSimulating || root->IsSimulatingPhysics())
2323 {
2324 root->SetSimulatePhysics(false);
2325 bWasSimulating = true;
2326 }
2327
2328 root->AttachToComponent(SocketingParent, TransformRule, OptionalSocketName);
2329 root->SetRelativeTransform(RelativeTransformToParent);
2330 }
2331 else if (AActor * pActor = Cast<AActor>(ObjectToSocket))
2332 {
2333
2334 if (UPrimitiveComponent * rootComp = Cast<UPrimitiveComponent>(pActor->GetRootComponent()))
2335 {
2336
2337 if (FBodyInstance* rBodyInstance = rootComp->GetBodyInstance())
2338 {
2339 if (rBodyInstance->OnRecalculatedMassProperties().IsBoundToObject(this))
2340 {
2341 rBodyInstance->OnRecalculatedMassProperties().RemoveAll(this);
2342 }
2343 }
2344
2345 if (bWasSimulating || rootComp->IsSimulatingPhysics())
2346 {
2347 // Stop simulation for socketing
2348 rootComp->SetSimulatePhysics(false);
2349 bWasSimulating = true;
2350 }
2351 }
2352
2353 pActor->AttachToComponent(SocketingParent, TransformRule, OptionalSocketName);
2354 pActor->SetActorRelativeTransform(RelativeTransformToParent);
2355
2356 //if (!bRetainOwnership)
2357 //pActor->SetOwner(nullptr);
2358 }
2359
2360 // It had a physics handle or was simulating, I need to delay a tick and set the transform to ensure it skips a race condition
2361 // I may need to consider running the entire attachment in here instead in the future
2362 if (bWasSimulating)
2363 {
2364 ObjectsWaitingForSocketUpdate.Add(ObjectToSocket);
2365 GetWorld()->GetTimerManager().SetTimerForNextTick(FTimerDelegate::CreateUObject(this, &UGripMotionControllerComponent::SetSocketTransform, ObjectToSocket, /*SocketingParent, */RelativeTransformToParent/*, OptionalSocketName, bWeldBodies*/));
2366 }
2367}
2368
2369void UGripMotionControllerComponent::NotifyDropAndSocket_Implementation(const FBPActorGripInformation &NewDrop, USceneComponent* SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize& RelativeTransformToParent, bool bWeldBodies)
2370{
2371 // Don't do this if we are the owning player on a local grip, there is no filter for multicast to not send to owner
2375 GetNetMode() == ENetMode::NM_Client)
2376 {
2377
2378 // If we still have the grip then the server is asking us to drop it even though it is locally controlled
2379 if (FBPActorGripInformation * GripInfo = GetGripPtrByID(NewDrop.GripID))
2380 {
2381 DropAndSocketGrip_Implementation(*GripInfo, SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies, true);
2382 }
2383 return;
2384 }
2385
2386 int PhysicsHandleIndex = INDEX_NONE;
2387 GetPhysicsGripIndex(NewDrop, PhysicsHandleIndex);
2388
2389 if (NewDrop.GrippedObject)
2390 {
2391 OnSocketingObject.Broadcast(NewDrop, SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2392 Socket_Implementation(NewDrop.GrippedObject, (PhysicsHandleIndex != INDEX_NONE), SocketingParent, OptionalSocketName, RelativeTransformToParent, bWeldBodies);
2393 }
2394
2396}
2397
2399{
2400 UGripMotionControllerComponent * HoldingController = nullptr;
2401 bool bIsHeld = false;
2402
2403 DestroyPhysicsHandle(NewDrop);
2404
2405 bool bHadGripAuthority = HasGripAuthority(NewDrop);
2406
2407 UPrimitiveComponent *root = NULL;
2408 AActor * pActor = NULL;
2409
2410 switch (NewDrop.GripTargetType)
2411 {
2413 //case EGripTargetType::InteractibleActorGrip:
2414 {
2415 pActor = NewDrop.GetGrippedActor();
2416
2417 if (pActor)
2418 {
2419 root = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
2420
2421 pActor->RemoveTickPrerequisiteComponent(this);
2422 //this->IgnoreActorWhenMoving(pActor, false);
2423
2424 if (APawn* OwningPawn = Cast<APawn>(GetOwner()))
2425 {
2426 OwningPawn->MoveIgnoreActorRemove(pActor);
2427
2428 // Clearing owner out here
2429 // Now I am setting the owner to the owning pawn if we are one
2430 // This makes sure that some special replication needs are taken care of
2431 // Only doing this for actor grips
2432 // #TODO: Add the removal back in?
2433 //pActor->SetOwner(nullptr);
2434 }
2435
2436 if (root)
2437 {
2438 //root->IgnoreActorWhenMoving(this->GetOwner(), false);
2439
2440 // Attachment already handles both of these
2441 //root->UpdateComponentToWorld(); // This fixes the late update offset
2442 //root->SetSimulatePhysics(false);
2443
2446 root->SetEnableGravity(NewDrop.bOriginalGravity);
2447
2448 // Stop Physics sim for socketing
2449 root->SetSimulatePhysics(false);
2450 }
2451
2452 if (IsServer()) //&& !bSkipFullDrop)
2453 {
2454 pActor->SetReplicateMovement(NewDrop.bOriginalReplicatesMovement);
2455 }
2456
2457 if (pActor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
2458 {
2459 IVRGripInterface::Execute_SetHeld(pActor, this, NewDrop.GripID, false);
2460
2461 if (NewDrop.SecondaryGripInfo.bHasSecondaryAttachment || SecondaryGripIDs.Contains(NewDrop.GripID))
2462 {
2463 IVRGripInterface::Execute_OnSecondaryGripRelease(pActor, this, NewDrop.SecondaryGripInfo.SecondaryAttachment, NewDrop);
2464 OnSecondaryGripRemoved.Broadcast(NewDrop);
2465 }
2466
2467 SecondaryGripIDs.Remove(NewDrop.GripID);
2468
2469 TArray<UVRGripScriptBase*> GripScripts;
2470 if (IVRGripInterface::Execute_GetGripScripts(pActor, GripScripts))
2471 {
2472 for (UVRGripScriptBase* Script : GripScripts)
2473 {
2474 if (Script)
2475 {
2477 Script->OnSecondaryGripRelease(this, NewDrop.SecondaryGripInfo.SecondaryAttachment, NewDrop);
2478
2479 Script->OnGripRelease(this, NewDrop, true);
2480 }
2481 }
2482 }
2483
2484 IVRGripInterface::Execute_OnGripRelease(pActor, this, NewDrop, true);
2485 if (IVRGripInterface* GripInterface = Cast<IVRGripInterface>(pActor))
2486 {
2487 GripInterface->Native_NotifyThrowGripDelegates(this, false, NewDrop, true);
2488 }
2489
2490 }
2491 }
2492 }break;
2493
2495 //case EGripTargetType::InteractibleComponentGrip:
2496 {
2497 root = NewDrop.GetGrippedComponent();
2498 if (root)
2499 {
2500 pActor = root->GetOwner();
2501
2502 root->RemoveTickPrerequisiteComponent(this);
2503 //root->IgnoreActorWhenMoving(this->GetOwner(), false);
2504
2505 // Attachment already handles both of these
2506 //root->UpdateComponentToWorld();
2507 //root->SetSimulatePhysics(false);
2508
2511 root->SetEnableGravity(NewDrop.bOriginalGravity);
2512
2513 // Stop Physics sim for socketing
2514 root->SetSimulatePhysics(false);
2515
2516 if (pActor)
2517 {
2518 if (IsServer() && root == pActor->GetRootComponent()) //&& !bSkipFullDrop)
2519 {
2520 pActor->SetReplicateMovement(NewDrop.bOriginalReplicatesMovement);
2521 }
2522
2523 if (pActor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
2524 {
2525 IVRGripInterface::Execute_OnChildGripRelease(pActor, this, NewDrop, true);
2526 }
2527 }
2528
2529 if (root->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
2530 {
2531 IVRGripInterface::Execute_SetHeld(root, this, NewDrop.GripID, false);
2532
2533 if (NewDrop.SecondaryGripInfo.bHasSecondaryAttachment || SecondaryGripIDs.Contains(NewDrop.GripID))
2534 {
2535 IVRGripInterface::Execute_OnSecondaryGripRelease(root, this, NewDrop.SecondaryGripInfo.SecondaryAttachment, NewDrop);
2536 OnSecondaryGripRemoved.Broadcast(NewDrop);
2537 }
2538
2539 SecondaryGripIDs.Remove(NewDrop.GripID);
2540
2541 TArray<UVRGripScriptBase*> GripScripts;
2542 if (IVRGripInterface::Execute_GetGripScripts(root, GripScripts))
2543 {
2544 for (UVRGripScriptBase* Script : GripScripts)
2545 {
2546 if (Script)
2547 {
2549 Script->OnSecondaryGripRelease(this, NewDrop.SecondaryGripInfo.SecondaryAttachment, NewDrop);
2550
2551 Script->OnGripRelease(this, NewDrop, true);
2552 }
2553 }
2554 }
2555
2556 IVRGripInterface::Execute_OnGripRelease(root, this, NewDrop, true);
2557 if (IVRGripInterface* GripInterface = Cast<IVRGripInterface>(root))
2558 {
2559 GripInterface->Native_NotifyThrowGripDelegates(this, false, NewDrop, true);
2560 }
2561 }
2562
2563 // Call on child grip release on attached parent component
2564 if (root->GetAttachParent() && root->GetAttachParent()->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
2565 {
2566 IVRGripInterface::Execute_OnChildGripRelease(root->GetAttachParent(), this, NewDrop, true);
2567 }
2568 }
2569 }break;
2570 }
2571
2572 // Copy over the information instead of working with a reference for the OnDroppedBroadcast
2573 FBPActorGripInformation DropBroadcastData = NewDrop;
2574
2575 int fIndex = 0;
2576 if (LocallyGrippedObjects.Find(NewDrop, fIndex))
2577 {
2578 if (HasGripAuthority(NewDrop) || GetNetMode() < ENetMode::NM_Client)
2579 {
2580 LocallyGrippedObjects.RemoveAt(fIndex);
2581 }
2582 else
2583 {
2584 LocallyGrippedObjects[fIndex].bIsPendingKill = true;
2585 LocallyGrippedObjects[fIndex].bIsPaused = true; // Pause it instead of dropping, dropping can corrupt the array in rare cases
2586 }
2587 }
2588 else
2589 {
2590 fIndex = 0;
2591 if (GrippedObjects.Find(NewDrop, fIndex))
2592 {
2593 if (HasGripAuthority(NewDrop) || GetNetMode() < ENetMode::NM_Client)
2594 {
2595 GrippedObjects.RemoveAt(fIndex);
2596 }
2597 else
2598 {
2599 GrippedObjects[fIndex].bIsPendingKill = true;
2600 GrippedObjects[fIndex].bIsPaused = true; // Pause it instead of dropping, dropping can corrupt the array in rare cases
2601 }
2602 }
2603 }
2604
2605 // Broadcast a new drop
2606 OnDroppedObject.Broadcast(DropBroadcastData, true);
2607}
2608
2609
2610// No longer an RPC, now is called from RepNotify so that joining clients also correctly set up grips
2612{
2613 UPrimitiveComponent *root = NULL;
2614 AActor *pActor = NULL;
2615
2616 bool bRootHasInterface = false;
2617 bool bActorHasInterface = false;
2618
2619 if (!NewGrip.GrippedObject || !NewGrip.GrippedObject->IsValidLowLevelFast())
2620 return false;
2621
2623 {
2624 // Init lerping
2625 InitializeLerpToHand(NewGrip);
2626 }
2627
2628 switch (NewGrip.GripTargetType)
2629 {
2631 //case EGripTargetType::InteractibleActorGrip:
2632 {
2633 pActor = NewGrip.GetGrippedActor();
2634
2635 if (pActor)
2636 {
2637 root = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
2638
2639 if (root->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
2640 {
2641 bRootHasInterface = true;
2642 }
2643 if (pActor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
2644 {
2645 // Actor grip interface is checked after component
2646 bActorHasInterface = true;
2647 }
2648
2649 if (APawn* OwningPawn = Cast<APawn>(GetOwner()))
2650 {
2652 {
2653 OwningPawn->MoveIgnoreActorAdd(pActor);
2654 }
2655
2656 // Now I am setting the owner to the owning pawn if we are one
2657 // This makes sure that some special replication needs are taken care of
2658 // Only doing this for actor grips
2660 {
2661 if (GetNetMode() < ENetMode::NM_Client)
2662 {
2663 pActor->SetOwner(OwningPawn);
2664 }
2665 }
2666 }
2667
2668 if (!bIsReInit && bActorHasInterface)
2669 {
2670 IVRGripInterface::Execute_SetHeld(pActor, this, NewGrip.GripID, true);
2671
2672 TArray<UVRGripScriptBase*> GripScripts;
2673 if (IVRGripInterface::Execute_GetGripScripts(pActor, GripScripts))
2674 {
2675 for (UVRGripScriptBase* Script : GripScripts)
2676 {
2677 if (Script)
2678 {
2679 Script->OnGrip(this, NewGrip);
2680 }
2681 }
2682 }
2683
2684 uint8 GripID = NewGrip.GripID;
2685 IVRGripInterface::Execute_OnGrip(pActor, this, NewGrip);
2686 if (!LocallyGrippedObjects.Contains(GripID) && !GrippedObjects.Contains(GripID))
2687 {
2688 return false;
2689 }
2690
2691 // Now check for c++ specific implementation and throw the native event if we need too
2692 if (IVRGripInterface* GripInterface = Cast<IVRGripInterface>(pActor))
2693 {
2694 GripInterface->Native_NotifyThrowGripDelegates(this, true, NewGrip, false);
2695
2696 if (!LocallyGrippedObjects.Contains(GripID) && !GrippedObjects.Contains(GripID))
2697 {
2698 return false;
2699 }
2700 }
2701
2702 }
2703
2704 if (root)
2705 {
2707 {
2708 // Have to turn off gravity locally
2711 root->SetEnableGravity(false);
2712 }
2713 //root->IgnoreActorWhenMoving(this->GetOwner(), true);
2714 }
2715
2716
2717 }
2718 else
2719 return false;
2720
2721 if (bActorHasInterface && !EndPhysicsTickFunction.IsTickFunctionRegistered())
2722 {
2724 {
2726 }
2727 else
2728 {
2729 EGripInterfaceTeleportBehavior TeleportBehavior = IVRGripInterface::Execute_TeleportBehavior(pActor);
2730
2732 {
2734 }
2735 }
2736 }
2737
2738 }break;
2739
2741 //case EGripTargetType::InteractibleComponentGrip:
2742 {
2743 root = NewGrip.GetGrippedComponent();
2744
2745 if (root)
2746 {
2747 pActor = root->GetOwner();
2748
2749 if (root->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
2750 {
2751 bRootHasInterface = true;
2752 }
2753 if (pActor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
2754 {
2755 // Actor grip interface is checked after component
2756 bActorHasInterface = true;
2757 }
2758
2759 if (!bIsReInit && bRootHasInterface)
2760 {
2761 IVRGripInterface::Execute_SetHeld(root, this, NewGrip.GripID, true);
2762
2763 TArray<UVRGripScriptBase*> GripScripts;
2764 if (IVRGripInterface::Execute_GetGripScripts(root, GripScripts))
2765 {
2766 for (UVRGripScriptBase* Script : GripScripts)
2767 {
2768 if (Script)
2769 {
2770 Script->OnGrip(this, NewGrip);
2771 }
2772 }
2773 }
2774
2775 uint8 GripID = NewGrip.GripID;
2776 IVRGripInterface::Execute_OnGrip(root, this, NewGrip);
2777 if (!LocallyGrippedObjects.Contains(GripID) && !GrippedObjects.Contains(GripID))
2778 {
2779 return false;
2780 }
2781
2782 // Now throw the native event if it implements the native interface
2783 if (IVRGripInterface* GripInterface = Cast<IVRGripInterface>(root))
2784 {
2785 //GripInterface->Execute_OnGrip(root, this, NewGrip);
2786 GripInterface->Native_NotifyThrowGripDelegates(this, true, NewGrip, false);
2787
2788 if (!LocallyGrippedObjects.Contains(GripID) && !GrippedObjects.Contains(GripID))
2789 {
2790 return false;
2791 }
2792
2793 }
2794
2795 }
2796
2797 if (pActor)
2798 {
2799 /*if (APawn* OwningPawn = Cast<APawn>(GetOwner()))
2800 {
2801 OwningPawn->MoveIgnoreActorAdd(root->GetOwner());
2802 }*/
2803
2804 if (!bIsReInit && bActorHasInterface)
2805 {
2806 uint8 GripID = NewGrip.GripID;
2807 IVRGripInterface::Execute_OnChildGrip(pActor, this, NewGrip);
2808 if (!LocallyGrippedObjects.Contains(GripID) && !GrippedObjects.Contains(GripID))
2809 {
2810 return false;
2811 }
2812 }
2813
2814 }
2815
2816 // Call OnChildGrip for attached grip parent
2817 if (!bIsReInit && root->GetAttachParent() && root->GetAttachParent()->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
2818 {
2819 uint8 GripID = NewGrip.GripID;
2820 IVRGripInterface::Execute_OnChildGrip(root->GetAttachParent(), this, NewGrip);
2821 if (!LocallyGrippedObjects.Contains(GripID) && !GrippedObjects.Contains(GripID))
2822 {
2823 return false;
2824 }
2825 }
2826
2828 {
2831 root->SetEnableGravity(false);
2832 }
2833
2834 //root->IgnoreActorWhenMoving(this->GetOwner(), true);
2835 }
2836 else
2837 return false;
2838
2839 if (bRootHasInterface && !EndPhysicsTickFunction.IsTickFunctionRegistered())
2840 {
2842 {
2844 }
2845 else
2846 {
2847 EGripInterfaceTeleportBehavior TeleportBehavior = IVRGripInterface::Execute_TeleportBehavior(root);
2848
2850 {
2852 }
2853 }
2854 }
2855
2856 }break;
2857 }
2858
2859 switch (NewGrip.GripMovementReplicationSetting)
2860 {
2864 {
2866 {
2867 if (IsServer() && pActor && ((NewGrip.GripTargetType == EGripTargetType::ActorGrip) || (root && root == pActor->GetRootComponent())))
2868 {
2869 pActor->SetReplicateMovement(false);
2870 }
2871 if (root)
2872 {
2873
2874 // #TODO: This is a hack until Epic fixes their new physics replication code
2875 // It forces the replication target to null on grip if we aren't repping movement.
2876//#if PHYSICS_INTERFACE_PHYSX
2877 if (UWorld* World = GetWorld())
2878 {
2879 if (FPhysScene* PhysScene = World->GetPhysicsScene())
2880 {
2881 if (FPhysicsReplication* PhysicsReplication = PhysScene->GetPhysicsReplication())
2882 {
2883 FBodyInstance* BI = root->GetBodyInstance(NewGrip.GrippedBoneName);
2884 if (BI && BI->IsInstanceSimulatingPhysics())
2885 {
2886 PhysicsReplication->RemoveReplicatedTarget(root);
2887 //PhysicsReplication->SetReplicatedTarget(this, BoneName, UpdatedState);
2888 }
2889 }
2890 }
2891 }
2892//#endif
2893 }
2894 }
2895
2896 }break;
2897
2899 {
2901 {
2902 if (IsServer() && pActor && ((NewGrip.GripTargetType == EGripTargetType::ActorGrip) || (root && root == pActor->GetRootComponent())))
2903 {
2904 pActor->SetReplicateMovement(true);
2905 }
2906 }
2907 }break;
2908
2910 default:
2911 {}break;
2912 }
2913
2914 bool bHasMovementAuthority = HasGripMovementAuthority(NewGrip);
2915
2916 switch (NewGrip.GripCollisionType)
2917 {
2922 {
2923 if (bHasMovementAuthority)
2924 {
2925 SetUpPhysicsHandle(NewGrip);
2926 }
2927 } break;
2928
2929
2931 {
2932 if (bHasMovementAuthority)
2933 {
2934 SetUpPhysicsHandle(NewGrip);
2935 }
2936 } break;
2937
2938 // Skip collision intersects with these types, they dont need it
2941 {
2942 // Should have never been turning off physics here, simulating is a valid custom grip state
2943 //if (root)
2944 //root->SetSimulatePhysics(false);
2945
2946 } break;
2947
2949 {
2950 if (root)
2951 root->SetSimulatePhysics(false);
2952
2953 // Move it to the correct location automatically
2954 if (bHasMovementAuthority)
2955 {
2956 if (!NewGrip.bIsLerping)
2957 {
2958 TeleportMoveGrip(NewGrip);
2959 }
2960 }
2961
2962 if (bHasMovementAuthority || IsServer())
2963 {
2964 FName BoneName = CustomPivotComponent.IsValid() ? CustomPivotComponentSocketName : NAME_None;
2965 root->AttachToComponent(CustomPivotComponent.IsValid() ? CustomPivotComponent.Get() : this, FAttachmentTransformRules(EAttachmentRule::KeepWorld, true), BoneName);
2966 }
2967
2968 }break;
2969
2974 default:
2975 {
2976
2977 if (root)
2978 {
2979 if (root->IsSimulatingPhysics())
2980 {
2981 root->SetSimulatePhysics(false);
2982 }
2983
2984 if(root->GetAttachParent())
2985 {
2986 root->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
2987 }
2988 }
2989
2990 // Move it to the correct location automatically
2991 if (bHasMovementAuthority)
2992 {
2993 if (!NewGrip.bIsLerping)
2994 {
2995 TeleportMoveGrip(NewGrip);
2996 }
2997 }
2998 } break;
2999
3000 }
3001
3002 if (!bIsReInit)
3003 {
3004 // Broadcast a new grip
3005 OnGrippedObject.Broadcast(NewGrip);
3006 if (!LocallyGrippedObjects.Contains(NewGrip.GripID) && !GrippedObjects.Contains(NewGrip.GripID))
3007 {
3008 return false;
3009 }
3010 }
3011
3012 return true;
3013}
3014
3016{
3017 const UVRGlobalSettings& VRSettings = *GetDefault<UVRGlobalSettings>();
3018
3019 if (!VRSettings.bUseGlobalLerpToHand || VRSettings.LerpDuration <= 0.f)
3020 return;
3021
3022 EBPVRResultSwitch Result;
3023 TSubclassOf<class UVRGripScriptBase> Class = UGS_LerpToHand::StaticClass();
3024 UVRGripScriptBase::GetGripScriptByClass(GripInformation.GrippedObject, Class, Result);
3025 if (Result == EBPVRResultSwitch::OnSucceeded)
3026 {
3027 return;
3028 }
3029
3030 if (USceneComponent* PrimParent = Cast<USceneComponent>(GripInformation.GrippedObject))
3031 {
3032 if (GripInformation.GrippedBoneName != NAME_None)
3033 {
3034 GripInformation.OnGripTransform = PrimParent->GetSocketTransform(GripInformation.GrippedBoneName);
3035 }
3036 else
3037 {
3038 GripInformation.OnGripTransform = PrimParent->GetComponentTransform();
3039 }
3040 }
3041 else if (AActor* ParentActor = Cast<AActor>(GripInformation.GrippedObject))
3042 {
3043 GripInformation.OnGripTransform = ParentActor->GetActorTransform();
3044 }
3045
3046 FTransform TargetTransform = GripInformation.RelativeTransform * this->GetPivotTransform();
3047 float Distance = FVector::Dist(GripInformation.OnGripTransform.GetLocation(), TargetTransform.GetLocation());
3048 if (VRSettings.MinDistanceForLerp > 0.0f && Distance < VRSettings.MinDistanceForLerp)
3049 {
3050 // Don't init
3051 GripInformation.bIsLerping = false;
3052 //OnLerpToHandFinished.Broadcast(GripInformation);
3053 return;
3054 }
3055 else
3056 {
3057 float LerpScaler = 1.0f;
3058 float DistanceToSpeed = Distance / VRSettings.LerpDuration;
3059 if (DistanceToSpeed < VRSettings.MinSpeedForLerp)
3060 {
3061 LerpScaler = VRSettings.MinSpeedForLerp / DistanceToSpeed;
3062 }
3063 else if (VRSettings.MaxSpeedForLerp > 0.f && DistanceToSpeed > VRSettings.MaxSpeedForLerp)
3064 {
3065 LerpScaler = VRSettings.MaxSpeedForLerp / DistanceToSpeed;
3066 }
3067 else
3068 {
3069 LerpScaler = 1.0f;
3070 }
3071
3072 // Get the modified lerp speed
3073 GripInformation.LerpSpeed = ((1.f / VRSettings.LerpDuration) * LerpScaler);
3074 GripInformation.bIsLerping = true;
3075 GripInformation.CurrentLerpTime = 0.0f;
3076 }
3077
3078 GripInformation.CurrentLerpTime = 0.0f;
3079}
3080
3081void UGripMotionControllerComponent::HandleGlobalLerpToHand(FBPActorGripInformation& GripInformation, FTransform& WorldTransform, float DeltaTime)
3082{
3083 UVRGlobalSettings* VRSettings = GetMutableDefault<UVRGlobalSettings>();
3084
3085 if (!VRSettings->bUseGlobalLerpToHand || !GripInformation.bIsLerping)
3086 return;
3087
3088 if (VRSettings->bSkipLerpToHandIfHeld && GripInformation.GrippedObject && GripInformation.GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
3089 {
3090 bool bIsHeld = false;
3091 TArray<FBPGripPair> HoldingControllers;
3092 // Check if a different controller is holding it
3093 IVRGripInterface::Execute_IsHeld(GripInformation.GrippedObject, HoldingControllers, bIsHeld);
3094
3095 if (HoldingControllers.Num() > 0)
3096 {
3097 for (FBPGripPair& ControllerPair : HoldingControllers)
3098 {
3099 if (ControllerPair.HoldingController && ControllerPair.HoldingController != this)
3100 {
3102 EBPVRResultSwitch Result;
3103 ControllerPair.HoldingController->GetGripByID(Grip, ControllerPair.GripID, Result);
3104
3105 if (Result != EBPVRResultSwitch::OnFailed)
3106 {
3107 if (Grip.IsValid())
3108 {
3109 // We are skipping lerping now
3110 GripInformation.bIsLerping = false;
3111 GripInformation.CurrentLerpTime = 0.f;
3112 OnLerpToHandFinished.Broadcast(GripInformation);
3113 return;
3114 }
3115 }
3116 }
3117 }
3118 }
3119 }
3120
3121 EBPVRResultSwitch Result;
3122 TSubclassOf<class UVRGripScriptBase> Class = UGS_LerpToHand::StaticClass();
3123 UVRGripScriptBase * LerpScript = UVRGripScriptBase::GetGripScriptByClass(GripInformation.GrippedObject, Class, Result);
3124 if (Result == EBPVRResultSwitch::OnSucceeded && LerpScript && LerpScript->IsScriptActive())
3125 {
3126 return;
3127 }
3128
3129 if (VRSettings->LerpDuration <= 0.f)
3130 {
3131 GripInformation.bIsLerping = false;
3132 GripInformation.CurrentLerpTime = 0.f;
3133 OnLerpToHandFinished.Broadcast(GripInformation);
3134 return;
3135 }
3136
3137 FTransform NA = GripInformation.OnGripTransform;//root->GetComponentTransform();
3138 float Alpha = 0.0f;
3139
3140 GripInformation.CurrentLerpTime += DeltaTime * GripInformation.LerpSpeed;
3141 float OrigAlpha = FMath::Clamp(GripInformation.CurrentLerpTime, 0.f, 1.0f);
3142 Alpha = OrigAlpha;
3143
3144 if (VRSettings->bUseCurve)
3145 {
3146 if (FRichCurve* richCurve = VRSettings->OptionalCurveToFollow.GetRichCurve())
3147 {
3148 /*if (CurrentLerpTime > richCurve->GetLastKey().Time)
3149 {
3150 // Stop lerping
3151 OnLerpToHandFinished.Broadcast();
3152 CurrentLerpTime = 0.0f;
3153 bIsActive = false;
3154 return true;
3155 }
3156 else*/
3157 {
3158 Alpha = FMath::Clamp(richCurve->Eval(Alpha), 0.f, 1.f);
3159 //CurrentLerpTime += DeltaTime;
3160 }
3161 }
3162 }
3163
3164 FTransform NB = WorldTransform;
3165 NA.NormalizeRotation();
3166 NB.NormalizeRotation();
3167
3168 // Quaternion interpolation
3170 {
3171 WorldTransform.Blend(NA, NB, Alpha);
3172 }
3173
3174 // Euler Angle interpolation
3176 {
3177 WorldTransform.SetTranslation(FMath::Lerp(NA.GetTranslation(), NB.GetTranslation(), Alpha));
3178 WorldTransform.SetScale3D(FMath::Lerp(NA.GetScale3D(), NB.GetScale3D(), Alpha));
3179
3180 FRotator A = NA.Rotator();
3181 FRotator B = NB.Rotator();
3182 WorldTransform.SetRotation(FQuat(A + (Alpha * (B - A))));
3183 }
3184 // Dual quaternion interpolation
3185 else
3186 {
3187 if ((NB.GetRotation() | NA.GetRotation()) < 0.0f)
3188 {
3189 NB.SetRotation(NB.GetRotation() * -1.0f);
3190 }
3191 WorldTransform = (FDualQuat(NA) * (1 - Alpha) + FDualQuat(NB) * Alpha).Normalized().AsFTransform(FMath::Lerp(NA.GetScale3D(), NB.GetScale3D(), Alpha));
3192 }
3193
3194 // Turn it off if we need to
3195 if (OrigAlpha >= 1.0f)
3196 {
3197 GripInformation.CurrentLerpTime = 0.0f;
3198 GripInformation.bIsLerping = false;
3199
3201 {
3202 DestroyPhysicsHandle(GripInformation, false);
3203 SetUpPhysicsHandle(GripInformation);
3204 }
3205
3206
3207 OnLerpToHandFinished.Broadcast(GripInformation);
3208 }
3209}
3210
3212{
3213 FBPActorGripInformation* GripToUse = nullptr;
3214 if (GripID != INVALID_VRGRIP_ID)
3215 {
3216 GripToUse = GrippedObjects.FindByKey(GripID);
3217 if (!GripToUse)
3218 {
3219 GripToUse = LocallyGrippedObjects.FindByKey(GripID);
3220 }
3221
3222 if (GripToUse)
3223 {
3224 GripToUse->bIsLerping = false;
3225
3227 {
3228 DestroyPhysicsHandle(*GripToUse, false);
3229 SetUpPhysicsHandle(*GripToUse);
3230 }
3231
3232 GripToUse->CurrentLerpTime = 0.0f;
3233 OnLerpToHandFinished.Broadcast(*GripToUse);
3234 }
3235 }
3236}
3237
3238void UGripMotionControllerComponent::NotifyDrop_Implementation(const FBPActorGripInformation &NewDrop, bool bSimulate)
3239{
3240 // Don't do this if we are the owning player on a local grip, there is no filter for multicast to not send to owner
3244 GetNetMode() == ENetMode::NM_Client)
3245 {
3246 // If we still have the grip then the server is asking us to drop it even though it is locally controlled
3247 if (FBPActorGripInformation * GripInfo = GetGripPtrByID(NewDrop.GripID))
3248 {
3249 DropGrip_Implementation(*GripInfo, bSimulate, FVector::ZeroVector, FVector::ZeroVector, true);
3250 }
3251
3252 return;
3253 }
3254
3255 Drop_Implementation(NewDrop, bSimulate);
3256}
3257
3259{
3260
3261 bool bSkipFullDrop = false;
3262 bool bHadAnotherSelfGrip = false;
3263 TArray<FBPGripPair> HoldingControllers;
3264 bool bIsHeld = false;
3265
3266 // Check if a different controller is holding it
3267 if(NewDrop.GrippedObject && NewDrop.GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
3268 IVRGripInterface::Execute_IsHeld(NewDrop.GrippedObject, HoldingControllers, bIsHeld);
3269
3270 if (bIsHeld && (!HoldingControllers.Contains(this) || HoldingControllers.Num() > 1))
3271 {
3272 // Skip the full drop if held
3273 bSkipFullDrop = true;
3274 }
3275 else // Now check for this same hand with duplicate grips on this object
3276 {
3277 for (int i = 0; i < LocallyGrippedObjects.Num(); ++i)
3278 {
3279 if (LocallyGrippedObjects[i].GrippedObject == NewDrop.GrippedObject && LocallyGrippedObjects[i].GripID != NewDrop.GripID)
3280 {
3281 bSkipFullDrop = true;
3282 bHadAnotherSelfGrip = true;
3283 }
3284 }
3285 for (int i = 0; i < GrippedObjects.Num(); ++i)
3286 {
3287 if (GrippedObjects[i].GrippedObject == NewDrop.GrippedObject && GrippedObjects[i].GripID != NewDrop.GripID)
3288 {
3289 bSkipFullDrop = true;
3290 bHadAnotherSelfGrip = true;
3291 }
3292 }
3293 }
3294
3295 DestroyPhysicsHandle(NewDrop, bHadAnotherSelfGrip);
3296
3297 bool bHadGripAuthority = HasGripAuthority(NewDrop);
3298
3299 UPrimitiveComponent *root = NULL;
3300 AActor * pActor = NULL;
3301
3302 switch (NewDrop.GripTargetType)
3303 {
3305 //case EGripTargetType::InteractibleActorGrip:
3306 {
3307 pActor = NewDrop.GetGrippedActor();
3308
3309 if (pActor)
3310 {
3311 root = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
3312
3313 if (!bSkipFullDrop)
3314 {
3315
3316 pActor->RemoveTickPrerequisiteComponent(this);
3317 //this->IgnoreActorWhenMoving(pActor, false);
3318
3320 {
3321 if (APawn * OwningPawn = Cast<APawn>(GetOwner()))
3322 {
3323 OwningPawn->MoveIgnoreActorRemove(pActor);
3324
3325 // Clearing owner out here
3326 // Now I am setting the owner to the owning pawn if we are one
3327 // This makes sure that some special replication needs are taken care of
3328 // Only doing this for actor grips
3329 // #TODO: Add the removal back in?
3330 //pActor->SetOwner(nullptr);
3331 }
3332 }
3333
3334 if (root)
3335 {
3336
3338 root->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
3339
3340 //root->IgnoreActorWhenMoving(this->GetOwner(), false);
3341
3343 {
3344 if (IsServer() || bHadGripAuthority || !NewDrop.bOriginalReplicatesMovement || !pActor->GetIsReplicated())
3345 {
3347 {
3348 if (root->IsSimulatingPhysics() != bSimulate)
3349 {
3350 root->SetSimulatePhysics(bSimulate);
3351 }
3352
3353 if (bSimulate)
3354 root->WakeAllRigidBodies();
3355 }
3356 }
3357
3358 root->UpdateComponentToWorld(); // This fixes the late update offset
3359 }
3360
3361 /*if (NewDrop.GrippedBoneName == NAME_None)
3362 {
3363 root->SetSimulatePhysics(bSimulate);
3364 root->UpdateComponentToWorld(); // This fixes the late update offset
3365 if (bSimulate)
3366 root->WakeAllRigidBodies();
3367 }
3368 else
3369 {
3370 USkeletalMeshComponent * skele = Cast<USkeletalMeshComponent>(root);
3371 if (skele)
3372 {
3373 skele->SetAllBodiesBelowSimulatePhysics(NewDrop.GrippedBoneName, bSimulate);
3374 root->UpdateComponentToWorld(); // This fixes the late update offset
3375 }
3376 else
3377 {
3378 root->SetSimulatePhysics(bSimulate);
3379 root->UpdateComponentToWorld(); // This fixes the late update offset
3380 if (bSimulate)
3381 root->WakeAllRigidBodies();
3382 }
3383 }*/
3384
3386 {
3389 root->SetEnableGravity(NewDrop.bOriginalGravity);
3390 }
3391 }
3392 }
3393
3394 if (IsServer() && !bSkipFullDrop)
3395 {
3396 pActor->SetReplicateMovement(NewDrop.bOriginalReplicatesMovement);
3397 }
3398
3399 if (pActor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
3400 {
3401 IVRGripInterface::Execute_SetHeld(pActor, this, NewDrop.GripID, false);
3402
3403 if (NewDrop.SecondaryGripInfo.bHasSecondaryAttachment || SecondaryGripIDs.Contains(NewDrop.GripID))
3404 {
3405 IVRGripInterface::Execute_OnSecondaryGripRelease(pActor, this, NewDrop.SecondaryGripInfo.SecondaryAttachment, NewDrop);
3406 OnSecondaryGripRemoved.Broadcast(NewDrop);
3407 }
3408
3409 SecondaryGripIDs.Remove(NewDrop.GripID);
3410
3411 TArray<UVRGripScriptBase*> GripScripts;
3412 if (IVRGripInterface::Execute_GetGripScripts(pActor, GripScripts))
3413 {
3414 for (UVRGripScriptBase* Script : GripScripts)
3415 {
3416 if (Script)
3417 {
3419 Script->OnSecondaryGripRelease(this, NewDrop.SecondaryGripInfo.SecondaryAttachment, NewDrop);
3420
3421 Script->OnGripRelease(this, NewDrop, false);
3422 }
3423 }
3424 }
3425
3426 IVRGripInterface::Execute_OnGripRelease(pActor, this, NewDrop, false);
3427 if (IVRGripInterface* GripInterface = Cast<IVRGripInterface>(pActor))
3428 {
3429 //GripInterface->Execute_OnGripRelease(pActor, this, NewDrop, false);
3430 GripInterface->Native_NotifyThrowGripDelegates(this, false, NewDrop, false);
3431 }
3432 }
3433 }
3434 }break;
3435
3437 //case EGripTargetType::InteractibleComponentGrip:
3438 {
3439 root = NewDrop.GetGrippedComponent();
3440 if (root)
3441 {
3442 pActor = root->GetOwner();
3443
3444 if (!bSkipFullDrop)
3445 {
3446 root->RemoveTickPrerequisiteComponent(this);
3447
3448 /*if (APawn* OwningPawn = Cast<APawn>(GetOwner()))
3449 {
3450 OwningPawn->MoveIgnoreActorRemove(pActor);
3451 }*/
3452
3454 root->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
3455
3456 //root->IgnoreActorWhenMoving(this->GetOwner(), false);
3457
3459 {
3460 // Need to set simulation in all of these cases, including if it isn't the root component (simulation isn't replicated on non roots)
3461 if (IsServer() || bHadGripAuthority || !NewDrop.bOriginalReplicatesMovement || (pActor && (pActor->GetRootComponent() != root || !pActor->GetIsReplicated())))
3462 {
3464 {
3465 if (root->IsSimulatingPhysics() != bSimulate)
3466 {
3467 root->SetSimulatePhysics(bSimulate);
3468 }
3469
3470 if (bSimulate)
3471 root->WakeAllRigidBodies();
3472 }
3473 }
3474
3475 root->UpdateComponentToWorld(); // This fixes the late update offset
3476 }
3477 /*if (NewDrop.GrippedBoneName == NAME_None)
3478 {
3479 root->SetSimulatePhysics(bSimulate);
3480 root->UpdateComponentToWorld(); // This fixes the late update offset
3481 if (bSimulate)
3482 root->WakeAllRigidBodies();
3483 }
3484 else
3485 {
3486 USkeletalMeshComponent * skele = Cast<USkeletalMeshComponent>(root);
3487 if (skele)
3488 {
3489 skele->SetAllBodiesBelowSimulatePhysics(NewDrop.GrippedBoneName, bSimulate);
3490 root->UpdateComponentToWorld(); // This fixes the late update offset
3491 }
3492 else
3493 {
3494 root->SetSimulatePhysics(bSimulate);
3495 root->UpdateComponentToWorld(); // This fixes the late update offset
3496 if (bSimulate)
3497 root->WakeAllRigidBodies();
3498 }
3499 }*/
3500
3502 {
3505 root->SetEnableGravity(NewDrop.bOriginalGravity);
3506 }
3507 }
3508
3509 if (pActor)
3510 {
3511 if (IsServer() && root == pActor->GetRootComponent() && !bSkipFullDrop)
3512 {
3513 pActor->SetReplicateMovement(NewDrop.bOriginalReplicatesMovement);
3514 }
3515
3516 if (pActor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
3517 {
3518 IVRGripInterface::Execute_OnChildGripRelease(pActor, this, NewDrop, false);
3519 }
3520
3521 }
3522
3523 if (root->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
3524 {
3525 IVRGripInterface::Execute_SetHeld(root, this, NewDrop.GripID, false);
3526
3527 if (NewDrop.SecondaryGripInfo.bHasSecondaryAttachment || SecondaryGripIDs.Contains(NewDrop.GripID))
3528 {
3529 IVRGripInterface::Execute_OnSecondaryGripRelease(root, this, NewDrop.SecondaryGripInfo.SecondaryAttachment, NewDrop);
3530 OnSecondaryGripRemoved.Broadcast(NewDrop);
3531 }
3532
3533 SecondaryGripIDs.Remove(NewDrop.GripID);
3534
3535 TArray<UVRGripScriptBase*> GripScripts;
3536 if (IVRGripInterface::Execute_GetGripScripts(root, GripScripts))
3537 {
3538 for (UVRGripScriptBase* Script : GripScripts)
3539 {
3540 if (Script)
3541 {
3543 Script->OnSecondaryGripRelease(this, NewDrop.SecondaryGripInfo.SecondaryAttachment, NewDrop);
3544
3545 Script->OnGripRelease(this, NewDrop, false);
3546 }
3547 }
3548 }
3549
3550 IVRGripInterface::Execute_OnGripRelease(root, this, NewDrop, false);
3551 if (IVRGripInterface* GripInterface = Cast<IVRGripInterface>(root))
3552 {
3553 GripInterface->Native_NotifyThrowGripDelegates(this, false, NewDrop, false);
3554 }
3555
3556 }
3557
3558 // Call on child grip release on attached parent component
3559 if (root->GetAttachParent() && root->GetAttachParent()->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
3560 {
3561 IVRGripInterface::Execute_OnChildGripRelease(root->GetAttachParent(), this, NewDrop, false);
3562 }
3563 }
3564 }break;
3565 }
3566
3567
3568 switch (NewDrop.GripMovementReplicationSetting)
3569 {
3573 {
3575 {
3576 if (root)
3577 {
3578 // #TODO: This is a hack until Epic fixes their new physics replication code
3579 // It forces the replication target to null on grip if we aren't repping movement.
3580//#if PHYSICS_INTERFACE_PHYSX
3581 if (UWorld * World = GetWorld())
3582 {
3583 if (FPhysScene * PhysScene = World->GetPhysicsScene())
3584 {
3585 if (FPhysicsReplication * PhysicsReplication = PhysScene->GetPhysicsReplication())
3586 {
3587 FBodyInstance* BI = root->GetBodyInstance(NewDrop.GrippedBoneName);
3588 if (BI && BI->IsInstanceSimulatingPhysics())
3589 {
3590 PhysicsReplication->RemoveReplicatedTarget(root);
3591 //PhysicsReplication->SetReplicatedTarget(this, BoneName, UpdatedState);
3592 }
3593 }
3594 }
3595 }
3596//#endif
3597 }
3598 }
3599
3600 }break;
3601
3602 };
3603
3604
3605
3606
3607 // Copy over the information instead of working with a reference for the OnDroppedBroadcast
3608 FBPActorGripInformation DropBroadcastData = NewDrop;
3609
3610 int fIndex = 0;
3611 if (LocallyGrippedObjects.Find(NewDrop, fIndex))
3612 {
3613 if (HasGripAuthority(NewDrop) || GetNetMode() < ENetMode::NM_Client)
3614 {
3615 LocallyGrippedObjects.RemoveAt(fIndex);
3616 }
3617 else
3618 {
3619 LocallyGrippedObjects[fIndex].bIsPendingKill = true;
3620 LocallyGrippedObjects[fIndex].bIsPaused = true; // Pause it instead of dropping, dropping can corrupt the array in rare cases
3621 }
3622 }
3623 else
3624 {
3625 fIndex = 0;
3626 if (GrippedObjects.Find(NewDrop, fIndex))
3627 {
3628 if (HasGripAuthority(NewDrop) || GetNetMode() < ENetMode::NM_Client)
3629 {
3630 GrippedObjects.RemoveAt(fIndex);
3631 }
3632 else
3633 {
3634 GrippedObjects[fIndex].bIsPendingKill = true;
3635 GrippedObjects[fIndex].bIsPaused = true; // Pause it instead of dropping, dropping can corrupt the array in rare cases
3636 }
3637 }
3638 }
3639
3640 // Broadcast a new drop
3641 OnDroppedObject.Broadcast(DropBroadcastData, false);
3642
3643
3644 // Now check if we should turn off any post physics ticking
3645 if (EndPhysicsTickFunction.IsTickFunctionRegistered())
3646 {
3647 bool bNeedsPhysicsTick = false;
3648
3649
3650
3651 if (LocallyGrippedObjects.Num() > 0 || GrippedObjects.Num() > 0)
3652 {
3654 {
3655 bNeedsPhysicsTick = true;
3656 }
3657 else
3658 {
3659
3660 for (int i = 0; i < LocallyGrippedObjects.Num(); ++i)
3661 {
3662 if ((LocallyGrippedObjects[i].GrippedObject != nullptr && !LocallyGrippedObjects[i].GrippedObject->IsPendingKill()) && LocallyGrippedObjects[i].GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
3663 {
3664 EGripInterfaceTeleportBehavior TeleportBehavior = IVRGripInterface::Execute_TeleportBehavior(LocallyGrippedObjects[i].GrippedObject);
3666 {
3667 bNeedsPhysicsTick = true;
3668 break;
3669 }
3670 }
3671 }
3672
3673 if (!bNeedsPhysicsTick)
3674 {
3675 for (int i = 0; i < GrippedObjects.Num(); ++i)
3676 {
3677 if ((GrippedObjects[i].GrippedObject != nullptr && !GrippedObjects[i].GrippedObject->IsPendingKill()) && GrippedObjects[i].GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
3678 {
3679 EGripInterfaceTeleportBehavior TeleportBehavior = IVRGripInterface::Execute_TeleportBehavior(GrippedObjects[i].GrippedObject);
3681 {
3682 bNeedsPhysicsTick = true;
3683 break;
3684 }
3685 }
3686 }
3687 }
3688 }
3689 }
3690
3691 if (!bNeedsPhysicsTick)
3692 {
3694 }
3695 }
3696}
3697
3702
3707
3709{
3710 return HasGripAuthority(ObjToCheck);
3711}
3712
3717
3718bool UGripMotionControllerComponent::AddSecondaryAttachmentPoint(UObject * GrippedObjectToAddAttachment, USceneComponent * SecondaryPointComponent, const FTransform & OriginalTransform, bool bTransformIsAlreadyRelative, float LerpToTime,/* float SecondarySmoothingScaler,*/ bool bIsSlotGrip, FName SecondarySlotName)
3719{
3720 if (!GrippedObjectToAddAttachment || !SecondaryPointComponent || (!GrippedObjects.Num() && !LocallyGrippedObjects.Num()))
3721 return false;
3722
3723 FBPActorGripInformation * GripToUse = nullptr;
3724
3725 GripToUse = LocallyGrippedObjects.FindByKey(GrippedObjectToAddAttachment);
3726
3727 // Search replicated grips if not found in local
3728 if (!GripToUse)
3729 {
3730 // Replicated grips need to be called from server side
3731 if (!IsServer())
3732 {
3733 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController add secondary attachment function was called on the client side with a replicated grip"));
3734 return false;
3735 }
3736
3737 GripToUse = GrippedObjects.FindByKey(GrippedObjectToAddAttachment);
3738 }
3739
3740 if (GripToUse)
3741 {
3742 return AddSecondaryAttachmentToGrip(*GripToUse, SecondaryPointComponent, OriginalTransform, bTransformIsAlreadyRelative, LerpToTime, bIsSlotGrip, SecondarySlotName);
3743 }
3744
3745 return false;
3746}
3747
3748bool UGripMotionControllerComponent::AddSecondaryAttachmentToGripByID(const uint8 GripID, USceneComponent* SecondaryPointComponent, const FTransform& OriginalTransform, bool bTransformIsAlreadyRelative, float LerpToTime, bool bIsSlotGrip, FName SecondarySlotName)
3749{
3750 FBPActorGripInformation* GripToUse = nullptr;
3751 if (GripID != INVALID_VRGRIP_ID)
3752 {
3753 GripToUse = GrippedObjects.FindByKey(GripID);
3754 if (!GripToUse)
3755 {
3756 GripToUse = LocallyGrippedObjects.FindByKey(GripID);
3757 }
3758
3759 if (GripToUse)
3760 {
3761 return AddSecondaryAttachmentToGrip(*GripToUse, SecondaryPointComponent, OriginalTransform, bTransformIsAlreadyRelative, LerpToTime, bIsSlotGrip, SecondarySlotName);
3762 }
3763 }
3764
3765 return false;
3766}
3767
3768bool UGripMotionControllerComponent::AddSecondaryAttachmentToGrip(const FBPActorGripInformation & GripToAddAttachment, USceneComponent * SecondaryPointComponent, const FTransform &OriginalTransform, bool bTransformIsAlreadyRelative, float LerpToTime, bool bIsSlotGrip, FName SecondarySlotName)
3769{
3770 if (!SecondaryPointComponent)
3771 {
3772 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController add secondary attachment function was called with a bad secondary component target!"));
3773 return false;
3774 }
3775
3776 FBPActorGripInformation* GripToUse = nullptr;
3777 bool bWasLocal = false;
3778 if (GripToAddAttachment.GrippedObject && GripToAddAttachment.GripID != INVALID_VRGRIP_ID)
3779 {
3780 GripToUse = GrippedObjects.FindByKey(GripToAddAttachment.GripID);
3781 if (!GripToUse)
3782 {
3783 GripToUse = LocallyGrippedObjects.FindByKey(GripToAddAttachment.GripID);
3784 bWasLocal = true;
3785 }
3786 }
3787
3788 if (!GripToUse || GripToUse->GripID == INVALID_VRGRIP_ID)
3789 {
3790 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController add secondary attachment function was called with a bad grip! It was not valid / found."));
3791 return false;
3792 }
3793
3794 if (!GripToUse->GrippedObject)
3795 {
3796 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController add secondary attachment function was called with a bad grip (gripped object invalid)!"));
3797 return false;
3798 }
3799
3800 // Replicated grips need to be called from server side
3801 if (!bWasLocal && !IsServer())
3802 {
3803 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController add secondary attachment function was called on the client side with a replicated grip"));
3804 return false;
3805 }
3806
3807 bool bGrippedObjectIsInterfaced = GripToUse->GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass());
3808
3809 if (bGrippedObjectIsInterfaced)
3810 {
3811 ESecondaryGripType SecondaryType = IVRGripInterface::Execute_SecondaryGripType(GripToUse->GrippedObject);
3812
3813 if (SecondaryType == ESecondaryGripType::SG_None)
3814 {
3815 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController add secondary attachment function was called on an interface object set to SG_None!"));
3816 return false;
3817 }
3818 }
3819
3820 UPrimitiveComponent * root = nullptr;
3821
3822 switch (GripToUse->GripTargetType)
3823 {
3825 {
3826 AActor * pActor = GripToUse->GetGrippedActor();
3827
3828 if (pActor)
3829 {
3830 root = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
3831 }
3832 }
3833 break;
3835 {
3836 root = GripToUse->GetGrippedComponent();
3837 }
3838 break;
3839 }
3840
3841 if (!root)
3842 {
3843 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController add secondary attachment function was unable to get root component or gripped component."));
3844 return false;
3845 }
3846
3847 if (bTransformIsAlreadyRelative)
3848 GripToUse->SecondaryGripInfo.SecondaryRelativeTransform = OriginalTransform;
3849 else
3850 GripToUse->SecondaryGripInfo.SecondaryRelativeTransform = OriginalTransform.GetRelativeTransform(root->GetComponentTransform());
3851
3852 GripToUse->SecondaryGripInfo.SecondaryAttachment = SecondaryPointComponent;
3854 GripToUse->SecondaryGripInfo.SecondaryGripDistance = 0.0f;
3855 GripToUse->SecondaryGripInfo.SecondarySlotName = SecondarySlotName;
3856
3857 /*const UVRGlobalSettings& VRSettings = *GetDefault<UVRGlobalSettings>();
3858 GripToUse->AdvancedGripSettings.SecondaryGripSettings.SecondarySmoothing.CutoffSlope = VRSettings.OneEuroCutoffSlope;
3859 GripToUse->AdvancedGripSettings.SecondaryGripSettings.SecondarySmoothing.DeltaCutoff = VRSettings.OneEuroDeltaCutoff;
3860 GripToUse->AdvancedGripSettings.SecondaryGripSettings.SecondarySmoothing.MinCutoff = VRSettings.OneEuroMinCutoff;
3861
3862 GripToUse->AdvancedGripSettings.SecondaryGripSettings.SecondarySmoothing.ResetSmoothingFilter();*/
3863 // GripToUse->SecondaryGripInfo.SecondarySmoothingScaler = FMath::Clamp(SecondarySmoothingScaler, 0.01f, 1.0f);
3864 GripToUse->SecondaryGripInfo.bIsSlotGrip = bIsSlotGrip;
3865
3867 LerpToTime = 0.0f;
3868
3869 if (LerpToTime > 0.0f)
3870 {
3871 GripToUse->SecondaryGripInfo.LerpToRate = LerpToTime;
3873 GripToUse->SecondaryGripInfo.curLerp = LerpToTime;
3874 }
3875
3876 if (bGrippedObjectIsInterfaced)
3877 {
3878 SecondaryGripIDs.Add(GripToUse->GripID);
3879
3880 IVRGripInterface::Execute_OnSecondaryGrip(GripToUse->GrippedObject, this, SecondaryPointComponent, *GripToUse);
3881
3882 TArray<UVRGripScriptBase*> GripScripts;
3883 if (IVRGripInterface::Execute_GetGripScripts(GripToUse->GrippedObject, GripScripts))
3884 {
3885 for (UVRGripScriptBase* Script : GripScripts)
3886 {
3887 if (Script)
3888 {
3889 Script->OnSecondaryGrip(this, SecondaryPointComponent, *GripToUse);
3890 }
3891 }
3892 }
3893 }
3894
3895 if (GripToUse->GripMovementReplicationSetting == EGripMovementReplicationSettings::ClientSide_Authoritive && GetNetMode() == ENetMode::NM_Client && !IsTornOff())
3896 {
3898 }
3899
3900 OnSecondaryGripAdded.Broadcast(*GripToUse);
3901 GripToUse = nullptr;
3902
3903 return true;
3904}
3905
3906bool UGripMotionControllerComponent::RemoveSecondaryAttachmentPoint(UObject * GrippedObjectToRemoveAttachment, float LerpToTime)
3907{
3908 if (!GrippedObjectToRemoveAttachment || (!GrippedObjects.Num() && !LocallyGrippedObjects.Num()))
3909 return false;
3910
3911 FBPActorGripInformation * GripToUse = nullptr;
3912
3913 // Duplicating the logic for each array for now
3914 GripToUse = LocallyGrippedObjects.FindByKey(GrippedObjectToRemoveAttachment);
3915
3916 // Check replicated grips if it wasn't found in local
3917 if (!GripToUse)
3918 {
3919 if (!IsServer())
3920 {
3921 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController remove secondary attachment function was called on the client side for a replicating grip"));
3922 return false;
3923 }
3924
3925 GripToUse = GrippedObjects.FindByKey(GrippedObjectToRemoveAttachment);
3926 }
3927
3928 // Handle the grip if it was found
3929 if (GripToUse && GripToUse->GrippedObject)
3930 {
3931 return RemoveSecondaryAttachmentFromGrip(*GripToUse, LerpToTime);
3932 }
3933
3934 return false;
3935}
3937{
3938 FBPActorGripInformation* GripToUse = nullptr;
3939 if (GripID != INVALID_VRGRIP_ID)
3940 {
3941 GripToUse = GrippedObjects.FindByKey(GripID);
3942 if (!GripToUse)
3943 {
3944 GripToUse = LocallyGrippedObjects.FindByKey(GripID);
3945 }
3946
3947 if (GripToUse)
3948 {
3949 return RemoveSecondaryAttachmentFromGrip(*GripToUse, LerpToTime);
3950 }
3951 }
3952
3953 return false;
3954}
3955
3957{
3958 FBPActorGripInformation* GripToUse = nullptr;
3959 bool bWasLocal = false;
3960 if (GripToRemoveAttachment.GrippedObject && GripToRemoveAttachment.GripID != INVALID_VRGRIP_ID)
3961 {
3962 GripToUse = GrippedObjects.FindByKey(GripToRemoveAttachment.GripID);
3963 if (!GripToUse)
3964 {
3965 GripToUse = LocallyGrippedObjects.FindByKey(GripToRemoveAttachment.GripID);
3966 bWasLocal = true;
3967 }
3968 }
3969
3970 if (GripToUse && !bWasLocal && !IsServer())
3971 {
3972 UE_LOG(LogVRMotionController, Warning, TEXT("VRGripMotionController remove secondary attachment function was called on the client side for a replicating grip"));
3973 return false;
3974 }
3975
3976 // Handle the grip if it was found
3977 if (GripToUse && GripToUse->GrippedObject && GripToUse->GripID != INVALID_VRGRIP_ID)
3978 {
3979 SecondaryGripIDs.Remove(GripToUse->GripID);
3980
3982 LerpToTime = 0.0f;
3983
3984 //if (LerpToTime > 0.0f)
3985 //{
3986 UPrimitiveComponent * primComp = nullptr;
3987
3988 switch (GripToUse->GripTargetType)
3989 {
3991 {
3992 primComp = GripToUse->GetGrippedComponent();
3993 }break;
3995 {
3996 AActor * pActor = GripToUse->GetGrippedActor();
3997 if (pActor)
3998 primComp = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
3999 } break;
4000 }
4001
4002 bool bGripObjectHasInterface = GripToUse->GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass());
4003
4005 if (bGripObjectHasInterface)
4006 {
4007 SecondaryType = IVRGripInterface::Execute_SecondaryGripType(GripToUse->GrippedObject);
4008 //else if (SecondaryType == ESecondaryGripType::SG_FreeWithScaling || SecondaryType == ESecondaryGripType::SG_SlotOnlyWithScaling)
4009 //LerpToTime = 0.0f;
4010 }
4011
4012 if (primComp)
4013 {
4014 switch (SecondaryType)
4015 {
4016 // All of these retain the position on release
4022 {
4023 GripToUse->RelativeTransform = primComp->GetComponentTransform().GetRelativeTransform(GetPivotTransform());
4024 GripToUse->SecondaryGripInfo.LerpToRate = 0.0f;
4026 }break;
4027 default:
4028 {
4029 if (LerpToTime > 0.0f)
4030 {
4031 // #TODO: This had a hitch in it just prior to lerping back, fix it eventually and allow lerping from scaling secondaries
4032 //GripToUse->RelativeTransform.SetScale3D(GripToUse->RelativeTransform.GetScale3D() * FVector(GripToUse->SecondaryScaler));
4033 GripToUse->SecondaryGripInfo.LerpToRate = LerpToTime;
4035 GripToUse->SecondaryGripInfo.curLerp = LerpToTime;
4036 }
4037 }break;
4038 }
4039
4040 }
4041 else
4042 {
4043 GripToUse->SecondaryGripInfo.LerpToRate = 0.0f;
4045 }
4046
4047 if (bGripObjectHasInterface)
4048 {
4049 IVRGripInterface::Execute_OnSecondaryGripRelease(GripToUse->GrippedObject, this, GripToUse->SecondaryGripInfo.SecondaryAttachment, *GripToUse);
4050
4051 TArray<UVRGripScriptBase*> GripScripts;
4052 if (IVRGripInterface::Execute_GetGripScripts(GripToUse->GrippedObject, GripScripts))
4053 {
4054 for (UVRGripScriptBase* Script : GripScripts)
4055 {
4056 if (Script)
4057 {
4058 Script->OnSecondaryGripRelease(this, GripToUse->SecondaryGripInfo.SecondaryAttachment, *GripToUse);
4059 }
4060 }
4061 }
4062 }
4063
4064 GripToUse->SecondaryGripInfo.SecondaryAttachment = nullptr;
4065 GripToUse->SecondaryGripInfo.bHasSecondaryAttachment = false;
4066
4067 if (GripToUse->GripMovementReplicationSetting == EGripMovementReplicationSettings::ClientSide_Authoritive && GetNetMode() == ENetMode::NM_Client)
4068 {
4069 switch (SecondaryType)
4070 {
4071 // All of these retain the position on release
4077 {
4078 if (!IsTornOff())
4080 }break;
4081 default:
4082 {
4083 if (!IsTornOff())
4085 }break;
4086 }
4087
4088 }
4089
4090 SecondaryGripIDs.Remove(GripToUse->GripID);
4091 OnSecondaryGripRemoved.Broadcast(*GripToUse);
4092 GripToUse = nullptr;
4093 return true;
4094 }
4095
4096 return false;
4097}
4098
4099bool UGripMotionControllerComponent::TeleportMoveGrippedActor(AActor * GrippedActorToMove, bool bTeleportPhysicsGrips)
4100{
4101 if (!GrippedActorToMove || (!GrippedObjects.Num() && !LocallyGrippedObjects.Num()))
4102 return false;
4103
4104 FBPActorGripInformation * GripInfo = LocallyGrippedObjects.FindByKey(GrippedActorToMove);
4105 if (!GripInfo)
4106 GrippedObjects.FindByKey(GrippedActorToMove);
4107
4108 if (GripInfo)
4109 {
4110 return TeleportMoveGrip(*GripInfo, bTeleportPhysicsGrips);
4111 }
4112
4113 return false;
4114}
4115
4116bool UGripMotionControllerComponent::TeleportMoveGrippedComponent(UPrimitiveComponent * ComponentToMove, bool bTeleportPhysicsGrips)
4117{
4118 if (!ComponentToMove || (!GrippedObjects.Num() && !LocallyGrippedObjects.Num()))
4119 return false;
4120
4121 FBPActorGripInformation * GripInfo = LocallyGrippedObjects.FindByKey(ComponentToMove);
4122 if (!GripInfo)
4123 GrippedObjects.FindByKey(ComponentToMove);
4124
4125 if (GripInfo)
4126 {
4127 return TeleportMoveGrip(*GripInfo, bTeleportPhysicsGrips);
4128 }
4129
4130 return false;
4131}
4132
4133void UGripMotionControllerComponent::TeleportMoveGrips(bool bTeleportPhysicsGrips, bool bIsForPostTeleport)
4134{
4135 FTransform EmptyTransform = FTransform::Identity;
4137 {
4138 TeleportMoveGrip_Impl(GripInfo, bTeleportPhysicsGrips, bIsForPostTeleport, EmptyTransform);
4139 }
4140
4141 for (FBPActorGripInformation& GripInfo : GrippedObjects)
4142 {
4143 TeleportMoveGrip_Impl(GripInfo, bTeleportPhysicsGrips, bIsForPostTeleport, EmptyTransform);
4144 }
4145}
4146
4147bool UGripMotionControllerComponent::TeleportMoveGrip(FBPActorGripInformation &Grip, bool bTeleportPhysicsGrips, bool bIsForPostTeleport)
4148{
4149 FTransform EmptyTransform = FTransform::Identity;
4150 return TeleportMoveGrip_Impl(Grip, bTeleportPhysicsGrips, bIsForPostTeleport, EmptyTransform);
4151}
4152
4153bool UGripMotionControllerComponent::TeleportMoveGrip_Impl(FBPActorGripInformation &Grip, bool bTeleportPhysicsGrips, bool bIsForPostTeleport, FTransform & OptionalTransform)
4154{
4155 bool bHasMovementAuthority = HasGripMovementAuthority(Grip);
4156
4157 if (!bHasMovementAuthority)
4158 return false;
4159
4160 UPrimitiveComponent * PrimComp = NULL;
4161 AActor * actor = NULL;
4162
4163 // Check if either implements the interface
4164 bool bRootHasInterface = false;
4165 bool bActorHasInterface = false;
4166
4167 switch (Grip.GripTargetType)
4168 {
4170 //case EGripTargetType::InteractibleActorGrip:
4171 {
4172 actor = Grip.GetGrippedActor();
4173 if (actor)
4174 {
4175 PrimComp = Cast<UPrimitiveComponent>(actor->GetRootComponent());
4176 if (actor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
4177 {
4178 bActorHasInterface = true;
4179 }
4180 }
4181 }break;
4182
4184 //case EGripTargetType::InteractibleComponentGrip:
4185 {
4186 PrimComp = Grip.GetGrippedComponent();
4187
4188 if (PrimComp)
4189 {
4190 actor = PrimComp->GetOwner();
4191 if (PrimComp->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
4192 {
4193 bRootHasInterface = true;
4194 }
4195 }
4196
4197 }break;
4198
4199 }
4200
4201 if (!PrimComp || !actor || actor->IsPendingKill() || PrimComp->IsPendingKill())
4202 return false;
4203
4204 // Only use with actual teleporting
4205
4207 bool bSimulateOnDrop = false;
4208
4209 // Check for interaction interface
4210 if (bRootHasInterface)
4211 {
4212 TeleportBehavior = IVRGripInterface::Execute_TeleportBehavior(PrimComp);
4213 bSimulateOnDrop = IVRGripInterface::Execute_SimulateOnDrop(PrimComp);
4214 }
4215 else if (bActorHasInterface)
4216 {
4217 // Actor grip interface is checked after component
4218 TeleportBehavior = IVRGripInterface::Execute_TeleportBehavior(actor);
4219 bSimulateOnDrop = IVRGripInterface::Execute_SimulateOnDrop(actor);
4220 }
4221
4222 if (bIsForPostTeleport)
4223 {
4225 {
4226 if (AActor * owner = PrimComp->GetOwner())
4227 {
4228 if (PrimComp != owner->GetRootComponent())
4229 {
4230 return false;
4231 }
4232 }
4233 }
4234 else if (TeleportBehavior == EGripInterfaceTeleportBehavior::DropOnTeleport)
4235 {
4236 if (IsServer() ||
4239 {
4240 DropObjectByInterface(nullptr, Grip.GripID);
4241 }
4242
4243 return false; // Didn't teleport
4244 }
4245 else if (TeleportBehavior == EGripInterfaceTeleportBehavior::DontTeleport)
4246 {
4247 return false; // Didn't teleport
4248 }
4249 }
4250 else
4251 {
4252 switch (TeleportBehavior)
4253 {
4256 {
4257 return false;
4258 }break;
4259 default:break;
4260 }
4261 }
4262
4263 FTransform WorldTransform;
4264 FTransform ParentTransform = GetPivotTransform();
4265
4266 FBPActorGripInformation copyGrip = Grip;
4267
4268 if (!OptionalTransform.Equals(FTransform::Identity))
4269 {
4270 WorldTransform = OptionalTransform;
4271 }
4272 else
4273 {
4274 TArray<UVRGripScriptBase*> Scripts;
4275
4276 if (bRootHasInterface)
4277 {
4278 IVRGripInterface::Execute_GetGripScripts(PrimComp, Scripts);
4279 }
4280 else if (bActorHasInterface)
4281 {
4282 IVRGripInterface::Execute_GetGripScripts(actor, Scripts);
4283 }
4284
4285 bool bForceADrop = false;
4286 bool bHadValidWorldTransform = GetGripWorldTransform(Scripts, 0.0f, WorldTransform, ParentTransform, copyGrip, actor, PrimComp, bRootHasInterface, bActorHasInterface, true, bForceADrop);
4287
4288 if (!bHadValidWorldTransform)
4289 return false;
4290 }
4291
4292 if (!WorldTransform.IsValid())
4293 {
4294 UE_LOG(LogVRMotionController, Warning, TEXT("Something went wrong, TeleportGrip_Impl's target transform contained NAN."));
4295 return false;
4296 }
4297
4298
4299 // Saving this out prior as we are still setting our physics thread to the correct value, the delta is only applied to the object
4300 FTransform physicsTrans = WorldTransform;
4301 if (TeleportBehavior == EGripInterfaceTeleportBehavior::DeltaTeleportation && !Grip.LastWorldTransform.Equals(FTransform::Identity))
4302 {
4303 FTransform baseTrans = this->GetAttachParent()->GetComponentTransform();
4304 WorldTransform = Grip.LastWorldTransform * baseTrans;
4305
4306 //physicsTrans = WorldTransform;
4307
4308 // Cancel out all other holding controllers teleport operations, we hit first
4309 if (!Grip.bSkipNextTeleportCheck && (bRootHasInterface || bActorHasInterface))
4310 {
4311 TArray<FBPGripPair> HoldingControllers;
4312 bool bIsHeld = false;
4313 IVRGripInterface::Execute_IsHeld(Grip.GrippedObject, HoldingControllers, bIsHeld);
4314
4315 for (FBPGripPair pair : HoldingControllers)
4316 {
4317 if (pair.HoldingController && pair.HoldingController != this && pair.HoldingController->bIsPostTeleport)
4318 {
4319 FBPActorGripInformation* pGrip = pair.HoldingController->GetGripPtrByID(pair.GripID);
4320
4321 if (pGrip)
4322 {
4323 pGrip->bSkipNextTeleportCheck = true;
4324 }
4325 }
4326 }
4327 }
4328 }
4329
4330 // Run some error checks and logging against the resulting transform
4331 if (!WorldTransform.IsValid())
4332 {
4333 if (WorldTransform.ContainsNaN())
4334 {
4335 UE_LOG(LogVRMotionController, Error, TEXT("Failed to teleport grip, bad transform, NaN detected with object: %s"), *Grip.GrippedObject->GetName());
4336 return false;
4337 }
4338 else if (!WorldTransform.GetRotation().IsNormalized())
4339 {
4340 WorldTransform.NormalizeRotation();
4341
4342 if (!WorldTransform.IsValid())
4343 {
4344 UE_LOG(LogVRMotionController, Error, TEXT("Failed to teleport grip, bad transform, rotation normalization issue: %s"), *Grip.GrippedObject->GetName());
4345 return false;
4346 }
4347 else
4348 {
4349 UE_LOG(LogVRMotionController, Error, TEXT("Error during teleport grip, rotation not normalized for object: %s"), *Grip.GrippedObject->GetName());
4350 }
4351 }
4352 }
4353
4354 // Need to use WITH teleport for this function so that the velocity isn't updated and without sweep so that they don't collide
4356
4357 if (!Handle)
4358 {
4359 PrimComp->SetWorldTransform(WorldTransform, false, NULL, ETeleportType::TeleportPhysics);
4360 }
4361 else if (Handle && FPhysicsInterface::IsValid(Handle->KinActorData2) && bTeleportPhysicsGrips)
4362 {
4363
4364#if PHYSICS_INTERFACE_PHYSX
4365 // Early out check for this
4366 // Think this may be an engine issue where I have to call this directly in physx only
4367 if (!Handle->KinActorData2.IsValid())
4368 {
4369 return true;
4370 }
4371#endif
4372
4373 // Don't try to autodrop on next tick, let the physx constraint update its local frame first
4374 if (HasGripAuthority(Grip))
4376
4377 if (Grip.bSkipNextTeleportCheck)
4378 {
4379 Grip.bSkipNextTeleportCheck = false;
4380 }
4381 else
4382 {
4383 PrimComp->SetWorldTransform(WorldTransform, false, NULL, ETeleportType::TeleportPhysics);
4384 }
4385
4386 // Zero out our scale now that we are working outside of physx
4387 physicsTrans.SetScale3D(FVector(1.0f));
4388
4389 if (Grip.bIsLerping || !bConstrainToPivot)
4390 {
4391 FBodyInstance* pInstance = PrimComp->GetBodyInstance();
4392 FPhysicsActorHandle ActorHandle = Handle->KinActorData2;
4393 FTransform newTrans = Handle->COMPosition * (Handle->RootBoneRotation * physicsTrans);
4394 if (pInstance && pInstance->IsValidBodyInstance())
4395 {
4396 FPhysicsCommand::ExecuteWrite(pInstance->GetPhysicsScene(), [&]()
4397 {
4398 if (FPhysicsInterface::IsValid(ActorHandle) && FPhysicsInterface::GetCurrentScene(ActorHandle))
4399 {
4400 FPhysicsInterface::SetKinematicTarget_AssumesLocked(ActorHandle, newTrans);
4401 FPhysicsInterface::SetGlobalPose_AssumesLocked(ActorHandle, newTrans);
4402 }
4403 });
4404 }
4405 }
4406 }
4407
4408 return true;
4409}
4410
4412{
4413 if (!GrippedObjects.Num() && !LocallyGrippedObjects.Num())
4414 return;
4415
4416 this->bIsPostTeleport = true;
4417}
4418
4419
4421{
4422 Super::Deactivate();
4423
4424 if (IsActive() == false && GripViewExtension.IsValid())
4425 {
4426 {
4427 // This component could be getting accessed from the render thread so it needs to wait
4428 // before clearing MotionControllerComponent
4429 FScopeLock ScopeLock(&CritSect);
4430 GripViewExtension->MotionControllerComponent = NULL;
4431 }
4432
4433 GripViewExtension.Reset();
4434 }
4435}
4436
4438{
4439 if (AVRBaseCharacter* CharacterOwner = Cast<AVRBaseCharacter>(this->GetOwner()))
4440 {
4441 AttachChar = CharacterOwner;
4442 }
4443 else
4444 {
4445 AttachChar.Reset();
4446 }
4447
4448 Super::OnAttachmentChanged();
4449}
4450
4452{
4453 //ReplicatedControllerTransform.Unpack();
4454
4455 if (GetNetMode() < ENetMode::NM_Client && HasTrackingParameters())
4456 {
4457 // Ensure that the client is sending valid boundries
4459 }
4460
4462 {
4463 if (bReppedOnce)
4464 {
4465 bLerpingPosition = true;
4467 LastUpdatesRelativePosition = this->GetRelativeLocation();
4468 LastUpdatesRelativeRotation = this->GetRelativeRotation();
4469
4471 {
4473 float NewDistance = OldToNewVector.SizeSquared();
4474
4475 // Too far, snap to the new value
4476 if (NewDistance >= FMath::Square(NetworkNoSmoothUpdateDistance))
4477 {
4479 bLerpingPosition = false;
4480 }
4481 // Outside of the buffer distance, snap within buffer and keep smoothing from there
4482 else if (NewDistance >= FMath::Square(NetworkMaxSmoothUpdateDistance))
4483 {
4484 FVector Offset = (OldToNewVector.Size() - NetworkMaxSmoothUpdateDistance) * OldToNewVector.GetSafeNormal();
4485 SetRelativeLocation(LastUpdatesRelativePosition + Offset);
4486 }
4487 }
4488 }
4489 else
4490 {
4492 bReppedOnce = true;
4493 }
4494 }
4495 else
4497}
4498
4500{
4501 // Server/remote clients don't set the controller position in VR
4502 // Don't call positional checks and don't create the late update scene view
4503 if (bHasAuthority)
4504 {
4506 {
4508 }
4509
4510 FVector Position = GetRelativeLocation();
4511 FRotator Orientation = GetRelativeRotation();
4512
4514 {
4515 if (!GripViewExtension.IsValid() && GEngine)
4516 {
4517 GripViewExtension = FSceneViewExtensions::NewExtension<FGripViewExtension>(this);
4518 }
4519
4520 float WorldToMeters = GetWorld() ? GetWorld()->GetWorldSettings()->WorldToMeters : 100.0f;
4521 ETrackingStatus LastTrackingStatus = CurrentTrackingStatus;
4522 const bool bNewTrackedState = GripPollControllerState(Position, Orientation, WorldToMeters);
4523
4524 bTracked = bNewTrackedState && (bIgnoreTrackingStatus || CurrentTrackingStatus != ETrackingStatus::NotTracked);
4525 if (bTracked)
4526 {
4528 {
4529 FTransform CalcedTransform = FTransform(Orientation, Position, this->GetRelativeScale3D());
4530
4532 {
4533 SetRelativeTransform(EuroSmoothingParams.RunFilterSmoothing(CalcedTransform, DeltaTime));
4534 }
4535 else
4536 {
4537 if (SmoothingSpeed <= 0.f || LastSmoothRelativeTransform.Equals(FTransform::Identity))
4538 {
4539 SetRelativeTransform(CalcedTransform);
4540 LastSmoothRelativeTransform = CalcedTransform;
4541 }
4542 else
4543 {
4544 const float Alpha = FMath::Clamp(DeltaTime * SmoothingSpeed, 0.f, 1.f);
4545 LastSmoothRelativeTransform.Blend(LastSmoothRelativeTransform, CalcedTransform, Alpha);
4546 SetRelativeTransform(LastSmoothRelativeTransform);
4547 }
4548 }
4549
4550 bWasSmoothingHand = true;
4551 }
4552 else
4553 {
4555 {
4556 // Clear the smoothing information so that we start with a fresh log when its enabled again
4557 LastSmoothRelativeTransform = FTransform::Identity;
4559
4560 bWasSmoothingHand = false;
4561 }
4562
4563 SetRelativeTransform(FTransform(Orientation, Position, this->GetRelativeScale3D()));
4564 }
4565 }
4566
4567 // if controller tracking just changed
4568 if (LastTrackingStatus != CurrentTrackingStatus)
4569 {
4570 OnTrackingChanged.Broadcast(CurrentTrackingStatus);
4571
4572 if (LastTrackingStatus == ETrackingStatus::NotTracked)
4573 {
4574 // Handle the display component
4575 // #TODO: Don't run if already has a display model, can't access yet
4576 if (bDisplayDeviceModel && DisplayModelSource != UMotionControllerComponent::CustomModelSourceId)
4577 RefreshDisplayComponent();
4578 }
4579 }
4580 }
4581
4583 return; // Don't update anything including location
4584
4585 // Don't bother with any of this if not replicating transform
4586 if (GetIsReplicated() && (bTracked || bReplicateWithoutTracking))
4587 {
4588 FVector RelLoc = GetRelativeLocation();
4589 FRotator RelRot = GetRelativeRotation();
4590
4591 // Don't rep if no changes
4593 {
4594 ControllerNetUpdateCount += DeltaTime;
4596 {
4598
4599 // Tracked doesn't matter, already set the relative location above in that case
4602
4603 // I would keep the torn off check here, except this can be checked on tick if they
4604 // Set 100 htz updates, and in the TornOff case, it actually can't hurt any besides some small
4605 // Perf difference.
4606 if (GetNetMode() == NM_Client/* && !IsTornOff()*/)
4607 {
4608 AVRBaseCharacter* OwningChar = Cast<AVRBaseCharacter>(GetOwner());
4609 if (OverrideSendTransform != nullptr && OwningChar != nullptr)
4610 {
4612 }
4613 else
4615 }
4616 }
4617 }
4618 }
4619 }
4620 else
4621 {
4622 // Clear the view extension if active after unpossessing, just in case
4623 if (GripViewExtension.IsValid())
4624 {
4625 {
4626 // This component could be getting accessed from the render thread so it needs to wait
4627 // before clearing MotionControllerComponent and allowing the destructor to continue
4628 FScopeLock ScopeLock(&CritSect);
4629 GripViewExtension->MotionControllerComponent = NULL;
4630 }
4631
4632 GripViewExtension.Reset();
4633 }
4634
4635 // Run any networked smoothing
4636 RunNetworkedSmoothing(DeltaTime);
4637 }
4638}
4639
4641{
4642 if (bLerpingPosition)
4643 {
4645 {
4646 ControllerNetUpdateCount += DeltaTime;
4647 float LerpVal = FMath::Clamp(ControllerNetUpdateCount / (1.0f / ControllerNetUpdateRate), 0.0f, 1.0f);
4648
4649 if (LerpVal >= 1.0f)
4650 {
4652
4653 // Stop lerping, wait for next update if it is delayed or lost then it will hitch here
4654 // Actual prediction might be something to consider in the future, but rough to do in VR
4655 // considering the speed and accuracy of movements
4656 // would like to consider sub stepping but since there is no server rollback...not sure how useful it would be
4657 // and might be perf taxing enough to not make it worth it.
4658 bLerpingPosition = false;
4660 }
4661 else
4662 {
4663 // Removed variables to speed this up a bit
4664 SetRelativeLocationAndRotation(
4667 );
4668 }
4669 }
4670 else // Exponential Smoothing
4671 {
4672 if (InterpolationSpeed <= 0.f)
4673 {
4674 SetRelativeLocationAndRotation((FVector)ReplicatedControllerTransform.Position, ReplicatedControllerTransform.Rotation);
4675 bLerpingPosition = false;
4676 return;
4677 }
4678
4679 const float Alpha = FMath::Clamp(DeltaTime * InterpolationSpeed, 0.f, 1.f);
4680
4681 FTransform NA = FTransform(GetRelativeRotation(), GetRelativeLocation(), FVector(1.0f));
4682 FTransform NB = FTransform(ReplicatedControllerTransform.Rotation, (FVector)ReplicatedControllerTransform.Position, FVector(1.0f));
4683 NA.NormalizeRotation();
4684 NB.NormalizeRotation();
4685
4686 NA.Blend(NA, NB, Alpha);
4687
4688 // If we are nearly equal then snap to final position
4689 if (NA.EqualsNoScale(NB))
4690 {
4692 bLerpingPosition = false;
4693 }
4694 else // Else just keep going
4695 {
4696 SetRelativeLocationAndRotation(NA.GetTranslation(), NA.Rotator());
4697 }
4698 }
4699 }
4700}
4701
4702void UGripMotionControllerComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
4703{
4704 // Skip motion controller tick, we override a lot of things that it does and we don't want it to perform the same functions
4705 Super::Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
4706
4707 if (!IsActive())
4708 return;
4709
4710 // Moved this here instead of in the polling function, it was ticking once per frame anyway so no loss of perf
4711 // It doesn't need to be there and now I can pre-check
4712 // Also epics implementation in the polling function didn't work anyway as it was based off of playercontroller which is not the owner of this controller
4713
4714 // Cache state from the game thread for use on the render thread
4715 // No need to check if in game thread here as tick always is
4717
4718 // No longer updating in character, was a waste as it wouldn't scope this component anyway
4719 UpdateTracking(DeltaTime);
4720
4721 /*if (!bUpdateInCharacterMovement)
4722 {
4723 UpdateTracking(DeltaTime);
4724 }
4725 else if (AttachChar.IsValid())
4726 {
4727 UCharacterMovementComponent* CharMove = AttachChar->GetCharacterMovement();
4728 if (!CharMove || !CharMove->IsComponentTickEnabled() || !CharMove->IsActive() || (GetWorld()->IsPaused() && !AttachChar->GetCharacterMovement()->PrimaryComponentTick.bTickEvenWhenPaused))
4729 {
4730 // Our character movement isn't handling our updates, lets do it ourself.
4731 UpdateTracking(DeltaTime);
4732 }
4733 }*/
4734
4735 // Process the gripped actors
4736 TickGrip(DeltaTime);
4737}
4738
4739bool UGripMotionControllerComponent::GetGripWorldTransform(TArray<UVRGripScriptBase*>& GripScripts, float DeltaTime, FTransform & WorldTransform, const FTransform &ParentTransform, FBPActorGripInformation &Grip, AActor * actor, UPrimitiveComponent * root, bool bRootHasInterface, bool bActorHasInterface, bool bIsForTeleport, bool &bForceADrop)
4740{
4741 SCOPE_CYCLE_COUNTER(STAT_GetGripTransform);
4742
4743 bool bHasValidTransform = true;
4744
4745 if (GripScripts.Num())
4746 {
4747 bool bGetDefaultTransform = true;
4748
4749 // Get grip script world transform overrides (if there are any)
4750 for (UVRGripScriptBase* Script: GripScripts)
4751 {
4752 if (Script && Script->IsScriptActive() && Script->GetWorldTransformOverrideType() == EGSTransformOverrideType::OverridesWorldTransform)
4753 {
4754 // One of the grip scripts overrides the default transform
4755 bGetDefaultTransform = false;
4756 break;
4757 }
4758 }
4759
4760 // If none of the scripts override the base transform
4761 if (bGetDefaultTransform && DefaultGripScript)
4762 {
4763 bHasValidTransform = DefaultGripScript->CallCorrect_GetWorldTransform(this, DeltaTime, WorldTransform, ParentTransform, Grip, actor, root, bRootHasInterface, bActorHasInterface, bIsForTeleport);
4764 bForceADrop = DefaultGripScript->Wants_ToForceDrop();
4765 }
4766
4767 // Get grip script world transform modifiers (if there are any)
4768 for (UVRGripScriptBase* Script : GripScripts)
4769 {
4770 if (Script && Script->IsScriptActive() && Script->GetWorldTransformOverrideType() != EGSTransformOverrideType::None)
4771 {
4772 bHasValidTransform = Script->CallCorrect_GetWorldTransform(this, DeltaTime, WorldTransform, ParentTransform, Grip, actor, root, bRootHasInterface, bActorHasInterface, bIsForTeleport);
4773 bForceADrop = Script->Wants_ToForceDrop();
4774
4775 // Early out, one of the scripts is telling us that the transform isn't valid, something went wrong or the grip is flagged for drop
4776 if (!bHasValidTransform || bForceADrop)
4777 break;
4778 }
4779 }
4780 }
4781 else
4782 {
4784 {
4785 bHasValidTransform = DefaultGripScript->CallCorrect_GetWorldTransform(this, DeltaTime, WorldTransform, ParentTransform, Grip, actor, root, bRootHasInterface, bActorHasInterface, bIsForTeleport);
4786 bForceADrop = DefaultGripScript->Wants_ToForceDrop();
4787 }
4788 }
4789
4790 HandleGlobalLerpToHand(Grip, WorldTransform, DeltaTime);
4791
4792 if (bHasValidTransform && !WorldTransform.IsValid())
4793 {
4794 UE_LOG(LogVRMotionController, Warning, TEXT("Something went wrong, GetGripWorldTransform tried to return NAN!."));
4795 bHasValidTransform = false;
4796 }
4797
4798 return bHasValidTransform;
4799}
4800
4802{
4803 SCOPE_CYCLE_COUNTER(STAT_TickGrip);
4804
4805 // Debug test that we aren't floating physics handles
4806 if (PhysicsGrips.Num() > (GrippedObjects.Num() + LocallyGrippedObjects.Num()))
4807 {
4809 UE_LOG(LogVRMotionController, Warning, TEXT("Something went wrong, there were too many physics handles for how many grips exist! Cleaned up bad handles."));
4810 }
4811 //check(PhysicsGrips.Num() <= (GrippedObjects.Num() + LocallyGrippedObjects.Num()));
4812
4813 FTransform ParentTransform = GetPivotTransform();
4814
4815 // Check for floating server sided client auth grips and handle them if we need too
4816 if(!IsServer())
4818
4819 bool bOriginalPostTeleport = bIsPostTeleport;
4820
4821 // Split into separate functions so that I didn't have to combine arrays since I have some removal going on
4822 HandleGripArray(GrippedObjects, ParentTransform, DeltaTime, true);
4823 HandleGripArray(LocallyGrippedObjects, ParentTransform, DeltaTime);
4824
4825 // Empty out the teleport flag, checking original state just in case the player changed it while processing bps
4826 if (bOriginalPostTeleport)
4827 {
4828 if ((GrippedObjects.Num() || LocallyGrippedObjects.Num()))
4829 {
4830 OnTeleportedGrips.Broadcast();
4831 }
4832
4833 bIsPostTeleport = false;
4834 }
4835
4836 // Save out the component velocity from this and last frame
4837
4838 FVector newVelocitySample = ((bSampleVelocityInWorldSpace ? GetComponentLocation() : GetRelativeLocation()) - LastRelativePosition.GetTranslation()) / DeltaTime;
4839
4841 {
4843 {
4844 ComponentVelocity = newVelocitySample;
4845 }break;
4847 {
4848 UVRExpansionFunctionLibrary::LowPassFilter_RollingAverage(ComponentVelocity, newVelocitySample, ComponentVelocity, VelocitySamples);
4849 }break;
4851 {
4855 }break;
4856 }
4857
4858 // #TODO:
4859 // Relative angular velocity too?
4860 // Maybe add some running averaging here to make it work across frames?
4861 // Or Valves 30 frame high point average buffer
4862 LastRelativePosition = bSampleVelocityInWorldSpace ? this->GetComponentTransform() : this->GetRelativeTransform();
4863}
4864
4866{
4868 {
4869 return PeakFilter.GetPeak();
4870 }
4871
4872 return Super::GetComponentVelocity();
4873}
4874
4875void UGripMotionControllerComponent::HandleGripArray(TArray<FBPActorGripInformation> &GrippedObjectsArray, const FTransform & ParentTransform, float DeltaTime, bool bReplicatedArray)
4876{
4877 if (GrippedObjectsArray.Num())
4878 {
4879 FTransform WorldTransform;
4880
4881 for (int i = GrippedObjectsArray.Num() - 1; i >= 0; --i)
4882 {
4883 if (!HasGripMovementAuthority(GrippedObjectsArray[i]))
4884 continue;
4885
4886 FBPActorGripInformation * Grip = &GrippedObjectsArray[i];
4887
4888 if (!Grip) // Shouldn't be possible, but why not play it safe
4889 continue;
4890
4891 // Double checking here for a failed rep due to out of order replication from a spawned actor
4893 continue; // If we didn't successfully handle the replication (out of order) then continue on.
4894
4895 if (Grip->IsValid() && !Grip->GrippedObject->IsPendingKill())
4896 {
4897 // Continue if the grip is paused
4898 if (Grip->bIsPaused)
4899 continue;
4900
4902 continue; // Earliest safe spot to continue at, we needed to check if the object is pending kill or invalid first
4903
4904 UPrimitiveComponent *root = NULL;
4905 AActor *actor = NULL;
4906
4907 // Getting the correct variables depending on the grip target type
4908 switch (Grip->GripTargetType)
4909 {
4911 //case EGripTargetType::InteractibleActorGrip:
4912 {
4913 actor = Grip->GetGrippedActor();
4914 if(actor)
4915 root = Cast<UPrimitiveComponent>(actor->GetRootComponent());
4916 }break;
4917
4919 //case EGripTargetType::InteractibleComponentGrip :
4920 {
4921 root = Grip->GetGrippedComponent();
4922 if(root)
4923 actor = root->GetOwner();
4924 }break;
4925
4926 default:break;
4927 }
4928
4929 // Last check to make sure the variables are valid
4930 if (!root || !actor || root->IsPendingKill() || actor->IsPendingKill())
4931 continue;
4932
4933 // Keep checking for pending kill on gripped objects, and ptr removals, but don't run grip logic when seamless
4934 // traveling, to avoid physx scene issues.
4935 if (GetWorld()->IsInSeamlessTravel())
4936 {
4937 continue;
4938 }
4939
4940 // Check if either implements the interface
4941 bool bRootHasInterface = false;
4942 bool bActorHasInterface = false;
4943
4944 if (root->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
4945 {
4946 bRootHasInterface = true;
4947 }
4948 else if (actor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
4949 {
4950 // Actor grip interface is checked after component
4951 bActorHasInterface = true;
4952 }
4953
4955 {
4956 // Don't perform logic on the movement for this object, just pass in the GripTick() event with the controller difference instead
4957 if(bRootHasInterface)
4958 IVRGripInterface::Execute_TickGrip(root, this, *Grip, DeltaTime);
4959 else if(bActorHasInterface)
4960 IVRGripInterface::Execute_TickGrip(actor, this, *Grip, DeltaTime);
4961
4962 continue;
4963 }
4964
4965 bool bRescalePhysicsGrips = false;
4966
4967 TArray<UVRGripScriptBase*> GripScripts;
4968
4969 if (bRootHasInterface)
4970 {
4971 IVRGripInterface::Execute_GetGripScripts(root, GripScripts);
4972 }
4973 else if (bActorHasInterface)
4974 {
4975 IVRGripInterface::Execute_GetGripScripts(actor, GripScripts);
4976 }
4977
4978
4979 bool bForceADrop = false;
4980
4981 // Get the world transform for this grip after handling secondary grips and interaction differences
4982 bool bHasValidWorldTransform = GetGripWorldTransform(GripScripts, DeltaTime, WorldTransform, ParentTransform, *Grip, actor, root, bRootHasInterface, bActorHasInterface, false, bForceADrop);
4983
4984 // If a script or behavior is telling us to skip this and continue on (IE: it dropped the grip)
4985 if (bForceADrop)
4986 {
4987 if (HasGripAuthority(*Grip))
4988 {
4989 if (bRootHasInterface)
4990 DropGrip_Implementation(*Grip, IVRGripInterface::Execute_SimulateOnDrop(root));
4991 else if (bActorHasInterface)
4992 DropGrip_Implementation(*Grip, IVRGripInterface::Execute_SimulateOnDrop(actor));
4993 else
4994 DropGrip_Implementation(*Grip, true);
4995 }
4996
4997 continue;
4998 }
4999 else if (!bHasValidWorldTransform)
5000 {
5001 continue;
5002 }
5003
5004 if (Grip->GrippedBoneName == NAME_None && !root->GetComponentTransform().GetScale3D().Equals(WorldTransform.GetScale3D()))
5005 bRescalePhysicsGrips = true;
5006
5007 // If we just teleported, skip this update and just teleport forward
5008 if (bIsPostTeleport)
5009 {
5010
5011 bool bSkipTeleport = false;
5012 for (UVRGripScriptBase* Script : GripScripts)
5013 {
5014 if (Script && Script->IsScriptActive() && Script->Wants_DenyTeleport(this))
5015 {
5016 bSkipTeleport = true;
5017 break;
5018 }
5019 }
5020
5021
5022 if (!bSkipTeleport)
5023 {
5024 TeleportMoveGrip_Impl(*Grip, true, true, WorldTransform);
5025 continue;
5026 }
5027 }
5028 else
5029 {
5030 //Grip->LastWorldTransform = WorldTransform;
5031 }
5032
5033 // Auto drop based on distance from expected point
5034 // Not perfect, should be done post physics or in next frame prior to changing controller location
5035 // However I don't want to recalculate world transform
5036 // Maybe add a grip variable of "expected loc" and use that to check next frame, but for now this will do.
5037 if ((bRootHasInterface || bActorHasInterface) &&
5038 (
5043 )
5044 {
5045
5046 // After initial teleportation the constraint local pose can be not updated yet, so lets delay a frame to let it update
5047 // Otherwise may cause unintended auto drops
5049 {
5050 Grip->bSkipNextConstraintLengthCheck = false;
5051 }
5052 else
5053 {
5054 float BreakDistance = 0.0f;
5055 if (bRootHasInterface)
5056 {
5057 BreakDistance = IVRGripInterface::Execute_GripBreakDistance(root);
5058 }
5059 else if (bActorHasInterface)
5060 {
5061 // Actor grip interface is checked after component
5062 BreakDistance = IVRGripInterface::Execute_GripBreakDistance(actor);
5063 }
5064
5065 FVector CheckDistance;
5066 if (!GetPhysicsJointLength(*Grip, root, CheckDistance))
5067 {
5068 CheckDistance = (WorldTransform.GetLocation() - root->GetComponentLocation());
5069 }
5070
5071 // Set grip distance now for people to use
5072 Grip->GripDistance = CheckDistance.Size();
5073
5074 if (BreakDistance > 0.0f)
5075 {
5076 if (Grip->GripDistance >= BreakDistance)
5077 {
5078 bool bIgnoreDrop = false;
5079 for (UVRGripScriptBase* Script : GripScripts)
5080 {
5081 if (Script && Script->IsScriptActive() && Script->Wants_DenyAutoDrop())
5082 {
5083 bIgnoreDrop = true;
5084 break;
5085 }
5086 }
5087
5088 if (bIgnoreDrop)
5089 {
5090 // Script canceled this out
5091 }
5092 else if (OnGripOutOfRange.IsBound())
5093 {
5094 uint8 GripID = Grip->GripID;
5095 OnGripOutOfRange.Broadcast(*Grip, Grip->GripDistance);
5096
5097 // Check if we still have the grip or not
5098 FBPActorGripInformation GripInfo;
5099 EBPVRResultSwitch Result;
5100 GetGripByID(GripInfo, GripID, Result);
5101 if (Result == EBPVRResultSwitch::OnFailed)
5102 {
5103 // Don't bother moving it, it is dropped now
5104 continue;
5105 }
5106 }
5107 else if(HasGripAuthority(*Grip))
5108 {
5109 if(bRootHasInterface)
5110 DropGrip_Implementation(*Grip, IVRGripInterface::Execute_SimulateOnDrop(root));
5111 else
5112 DropGrip_Implementation(*Grip, IVRGripInterface::Execute_SimulateOnDrop(actor));
5113
5114 // Don't bother moving it, it is dropped now
5115 continue;
5116 }
5117 }
5118 }
5119 }
5120 }
5121
5122 // Start handling the grip types and their functions
5123 switch (Grip->GripCollisionType)
5124 {
5127 {
5128 UpdatePhysicsHandleTransform(*Grip, WorldTransform);
5129
5130 if (bRescalePhysicsGrips)
5131 root->SetWorldScale3D(WorldTransform.GetScale3D());
5132
5133
5134 // Sweep current collision state, only used for client side late update removal
5135 if (
5136 (bHasAuthority && !this->bDisableLowLatencyUpdate &&
5139 )
5140 {
5141 //TArray<FOverlapResult> Hits;
5142 FComponentQueryParams Params(NAME_None, this->GetOwner());
5143 //Params.bTraceAsyncScene = root->bCheckAsyncSceneOnMove;
5144 Params.AddIgnoredActor(actor);
5145 Params.AddIgnoredActors(root->MoveIgnoreActors);
5146
5147 actor->ForEachAttachedActors([&Params](AActor* Actor)
5148 {
5149 Params.AddIgnoredActor(Actor);
5150 return true;
5151 });
5152
5153 TArray<FHitResult> Hits;
5154
5155 // Switched over to component sweep because it picks up on pivot offsets without me manually calculating it
5156 if (
5157 GetWorld()->ComponentSweepMulti(Hits, root, root->GetComponentLocation(), WorldTransform.GetLocation(), WorldTransform.GetRotation(), Params)
5158 )
5159 {
5160
5161 // Check if the two components are ignoring collisions with each other
5162 UCollisionIgnoreSubsystem* CollisionIgnoreSubsystem = GetWorld()->GetSubsystem<UCollisionIgnoreSubsystem>();
5163
5164 if (CollisionIgnoreSubsystem->HasCollisionIgnorePairs())
5165 {
5166 // Pre-set this so it falls back to false if none of these hits are valid
5167 Grip->bColliding = false;
5168
5169 for (const FHitResult& Hit : Hits)
5170 {
5171 if (Hit.bBlockingHit && !CollisionIgnoreSubsystem->AreComponentsIgnoringCollisions(root, Hit.Component.Get()))
5172 {
5173 Grip->bColliding = true;
5174 break;
5175 }
5176 }
5177 }
5178 else
5179 {
5180 Grip->bColliding = true;
5181 }
5182 }
5183 else
5184 {
5185 Grip->bColliding = false;
5186 }
5187 }
5188
5189 }break;
5190
5192 {
5193 FVector OriginalPosition(root->GetComponentLocation());
5194 FVector NewPosition(WorldTransform.GetTranslation());
5195
5196 if (!Grip->bIsLocked)
5197 root->ComponentVelocity = (NewPosition - OriginalPosition) / DeltaTime;
5198
5199 if (Grip->bIsLocked)
5200 WorldTransform.SetRotation(Grip->LastLockedRotation);
5201
5202 FHitResult OutHit;
5203 // Need to use without teleport so that the physics velocity is updated for when the actor is released to throw
5204
5206 {
5207 FScopedMovementUpdate ScopedMovementUpdate(root, EScopedUpdate::DeferredUpdates);
5208 FTransform baseTrans = this->GetAttachParent()->GetComponentTransform();
5209 root->SetWorldTransform(Grip->LastWorldTransform * baseTrans, false, nullptr, ETeleportType::None);
5210 root->SetWorldTransform(WorldTransform, true, &OutHit);
5211 }
5212 else
5213 {
5214 root->SetWorldTransform(WorldTransform, true, &OutHit);
5215 }
5216
5217 if (OutHit.bBlockingHit)
5218 {
5219 Grip->bColliding = true;
5220
5221 if (!Grip->bIsLocked)
5222 {
5223 Grip->bIsLocked = true;
5224 Grip->LastLockedRotation = root->GetComponentQuat();
5225 }
5226 }
5227 else
5228 {
5229 Grip->bColliding = false;
5230
5231 if (Grip->bIsLocked)
5232 Grip->bIsLocked = false;
5233 }
5234 }break;
5235
5237 {
5238 UpdatePhysicsHandleTransform(*Grip, WorldTransform);
5239
5240 if (bRescalePhysicsGrips)
5241 root->SetWorldScale3D(WorldTransform.GetScale3D());
5242
5243 // Always Sweep current collision state with this, used for constraint strength
5244 //TArray<FOverlapResult> Hits;
5245 FComponentQueryParams Params(NAME_None, this->GetOwner());
5246 //Params.bTraceAsyncScene = root->bCheckAsyncSceneOnMove;
5247 Params.AddIgnoredActor(actor);
5248 Params.AddIgnoredActors(root->MoveIgnoreActors);
5249
5250 actor->ForEachAttachedActors([&Params](AActor* Actor)
5251 {
5252 Params.AddIgnoredActor(Actor);
5253 return true;
5254 });
5255
5256 TArray<FHitResult> Hits;
5257 // Checking both current and next position for overlap using this grip type
5258 // Switched over to component sweep because it picks up on pivot offsets without me manually calculating it
5259 if (Grip->bLockHybridGrip)
5260 {
5261 if (!Grip->bColliding)
5262 {
5264 }
5265
5266 Grip->bColliding = true;
5267 }
5268 else if (GetWorld()->ComponentSweepMulti(Hits, root, root->GetComponentLocation(), WorldTransform.GetLocation(), WorldTransform.GetRotation(), Params))
5269 {
5270 // Check if the two components are ignoring collisions with each other
5271 UCollisionIgnoreSubsystem* CollisionIgnoreSubsystem = GetWorld()->GetSubsystem<UCollisionIgnoreSubsystem>();
5272
5273 if (CollisionIgnoreSubsystem->HasCollisionIgnorePairs())
5274 {
5275
5276 bool bOriginalColliding = Grip->bColliding;
5277 // Pre-set this so it falls back to false if none of these hits are valid
5278 Grip->bColliding = false;
5279
5280 for (const FHitResult& Hit : Hits)
5281 {
5282 if (Hit.bBlockingHit && !CollisionIgnoreSubsystem->AreComponentsIgnoringCollisions(root, Hit.Component.Get()))
5283 {
5284 if (!bOriginalColliding)
5285 {
5287 }
5288 Grip->bColliding = true;
5289 break;
5290 }
5291 }
5292
5293 if (!Grip->bColliding)
5294 {
5295 if (bOriginalColliding)
5296 {
5298 }
5299 }
5300 }
5301 else
5302 {
5303 if (!Grip->bColliding)
5304 {
5306 }
5307 Grip->bColliding = true;
5308 }
5309 }
5310 else
5311 {
5312 if (Grip->bColliding)
5313 {
5315 }
5316
5317 Grip->bColliding = false;
5318 }
5319
5320 }break;
5321
5323 {
5324
5325 // Make sure that there is no collision on course before turning off collision and snapping to controller
5327
5328 TArray<FHitResult> Hits;
5329 FComponentQueryParams Params(NAME_None, this->GetOwner());
5330 //Params.bTraceAsyncScene = root->bCheckAsyncSceneOnMove;
5331 Params.AddIgnoredActor(actor);
5332 Params.AddIgnoredActors(root->MoveIgnoreActors);
5333
5334 actor->ForEachAttachedActors([&Params](AActor* Actor)
5335 {
5336 Params.AddIgnoredActor(Actor);
5337 return true;
5338 });
5339
5340 FTransform BaseTransform = root->GetComponentTransform();
5341
5343 {
5344 FTransform baseTrans = this->GetAttachParent()->GetComponentTransform();
5345 BaseTransform = Grip->LastWorldTransform * baseTrans;
5346 }
5347
5348 bool bWasColliding = Grip->bColliding;
5349 bool bLerpCollisions = false;
5350 bool bLerpRotationOnly = false;
5351 bool bDistanceBasedInterpolation = false;
5352 float LerpSpeed = 0.0f;
5353 const UVRGlobalSettings* VRSettings = GetDefault<UVRGlobalSettings>();
5354
5355 if (VRSettings)
5356 {
5357 bLerpCollisions = VRSettings->bLerpHybridWithSweepGrips;
5358 LerpSpeed = VRSettings->HybridWithSweepLerpDuration;
5359 bLerpRotationOnly = VRSettings->bOnlyLerpHybridRotation;
5360 bDistanceBasedInterpolation = VRSettings->bHybridWithSweepUseDistanceBasedLerp;
5361 }
5362
5363 if (Grip->bLockHybridGrip)
5364 {
5365 Grip->bColliding = true;
5366 }
5367 // Check our target rotation
5368 else if (GetWorld()->ComponentSweepMulti(Hits, root, BaseTransform.GetLocation(), WorldTransform.GetLocation(), WorldTransform.GetRotation(), Params))
5369 {
5370 // Check if the two components are ignoring collisions with each other
5371 UCollisionIgnoreSubsystem* CollisionIgnoreSubsystem = GetWorld()->GetSubsystem<UCollisionIgnoreSubsystem>();
5372
5373 if (CollisionIgnoreSubsystem->HasCollisionIgnorePairs())
5374 {
5375 // Pre-set this so it falls back to false if none of these hits are valid
5376 Grip->bColliding = false;
5377
5378 for (const FHitResult& Hit : Hits)
5379 {
5380 if (Hit.bBlockingHit && !CollisionIgnoreSubsystem->AreComponentsIgnoringCollisions(root, Hit.Component.Get()))
5381 {
5382 Grip->bColliding = true;
5383 break;
5384 }
5385 }
5386
5387 // We need to also check the other rotation here as a fallback
5388 if (bLerpCollisions && !Grip->bColliding)
5389 {
5390 if (bLerpCollisions && GetWorld()->ComponentSweepMulti(Hits, root, BaseTransform.GetLocation(), WorldTransform.GetLocation(), root->GetComponentRotation(), Params))
5391 {
5392 for (const FHitResult& Hit : Hits)
5393 {
5394 if (Hit.bBlockingHit && !CollisionIgnoreSubsystem->AreComponentsIgnoringCollisions(root, Hit.Component.Get()))
5395 {
5396 Grip->bColliding = true;
5397 break;
5398 }
5399 }
5400 }
5401 }
5402 }
5403 else
5404 {
5405 Grip->bColliding = true;
5406 }
5407 }
5408 // Check the other rotation
5409 else if (bLerpCollisions && GetWorld()->ComponentSweepMulti(Hits, root, BaseTransform.GetLocation(), WorldTransform.GetLocation(), root->GetComponentRotation(), Params))
5410 {
5411 // Check if the two components are ignoring collisions with each other
5412 UCollisionIgnoreSubsystem* CollisionIgnoreSubsystem = GetWorld()->GetSubsystem<UCollisionIgnoreSubsystem>();
5413
5414 if (CollisionIgnoreSubsystem->HasCollisionIgnorePairs())
5415 {
5416 // Pre-set this so it falls back to false if none of these hits are valid
5417 Grip->bColliding = false;
5418
5419 for (const FHitResult& Hit : Hits)
5420 {
5421 if (Hit.bBlockingHit && !CollisionIgnoreSubsystem->AreComponentsIgnoringCollisions(root, Hit.Component.Get()))
5422 {
5423 Grip->bColliding = true;
5424 break;
5425 }
5426 }
5427 }
5428 else
5429 {
5430 Grip->bColliding = true;
5431 }
5432 }
5433 else
5434 {
5435 Grip->bColliding = false;
5436 }
5437
5438 if (!Grip->bColliding)
5439 {
5440 if (GripHandle && !GripHandle->bIsPaused)
5441 {
5442 PausePhysicsHandle(GripHandle);
5443 //DestroyPhysicsHandle(*Grip);
5444
5445 switch (Grip->GripTargetType)
5446 {
5448 {
5449 root->SetSimulatePhysics(false);
5450 }break;
5452 {
5453 root->SetSimulatePhysics(false);
5454 //actor->DisableComponentsSimulatePhysics();
5455 } break;
5456 }
5457 }
5458
5459 if (bLerpCollisions && !Grip->bIsLerping)
5460 {
5461 if (bWasColliding && !Grip->bIsLerping)
5462 {
5463 // Store relative transform and base movements off of lerping out of it to the target transform
5464
5465 // Re-use this transform as it will let us not add additional variables
5466 Grip->OnGripTransform = root->GetComponentTransform().GetRelativeTransform(this->GetPivotTransform());
5467 Grip->CurrentLerpTime = 1.0f;
5468 Grip->LerpSpeed = (1.f / LerpSpeed);
5469
5470 if (bDistanceBasedInterpolation)
5471 {
5472 // Just multiplying to make the values easier
5473 Grip->LerpSpeed *= 10.0f;
5474 }
5475 }
5476
5477 if (Grip->CurrentLerpTime > 0.0f)
5478 {
5479 FTransform NB = (Grip->OnGripTransform * this->GetPivotTransform());
5480 float Alpha = 0.0f;
5481
5482 if (bDistanceBasedInterpolation)
5483 {
5484 if (Grip->LerpSpeed <= 0.f)
5485 {
5486 Alpha = 1.0f;
5487 Grip->CurrentLerpTime = 0.0f;
5488 }
5489
5490 Alpha = FMath::Clamp(DeltaTime * Grip->LerpSpeed, 0.f, 1.f);
5491 }
5492 else
5493 {
5494 Grip->CurrentLerpTime -= DeltaTime * Grip->LerpSpeed;
5495 float OrigAlpha = FMath::Clamp(1.0f - Grip->CurrentLerpTime, 0.f, 1.0f);
5496 Alpha = OrigAlpha;
5497 }
5498
5499 FTransform NA = WorldTransform;
5500 NA.NormalizeRotation();
5501 NB.NormalizeRotation();
5502
5503 if (!bLerpRotationOnly)
5504 {
5505 WorldTransform.Blend(NB, NA, Alpha);
5506 }
5507 else
5508 {
5509 WorldTransform.SetRotation(FQuat::Slerp(NB.GetRotation(), NA.GetRotation(), Alpha));
5510 }
5511
5512 if (bDistanceBasedInterpolation)
5513 {
5514 if (NA.Equals(WorldTransform))
5515 {
5516 Grip->CurrentLerpTime = 0.0f;
5517 }
5518 else
5519 {
5520 // Save out current distance back to the originating transform
5521 Grip->OnGripTransform = WorldTransform.GetRelativeTransform(this->GetPivotTransform());
5522 }
5523 }
5524 }
5525 }
5526
5528 {
5529 FScopedMovementUpdate ScopedMovementUpdate(root, EScopedUpdate::DeferredUpdates);
5530 FTransform baseTrans = this->GetAttachParent()->GetComponentTransform();
5531 root->SetWorldTransform(Grip->LastWorldTransform * baseTrans, false, nullptr, ETeleportType::None);
5532 root->SetWorldTransform(WorldTransform, false);// , &OutHit);
5533 }
5534 else
5535 {
5536 root->SetWorldTransform(WorldTransform, false);// , &OutHit);
5537 }
5538
5539 if (GripHandle)
5540 {
5541 UpdatePhysicsHandleTransform(*Grip, WorldTransform);
5542 }
5543
5544 }
5545 else if (Grip->bColliding)
5546 {
5547 if (!GripHandle)
5548 {
5549 //root->SetSimulatePhysics(true);
5550 SetUpPhysicsHandle(*Grip, &GripScripts);
5551 }
5552 else if(GripHandle->bIsPaused)
5553 {
5554 UnPausePhysicsHandle(*Grip, GripHandle);
5555 }
5556
5557 if (GripHandle)
5558 {
5559 UpdatePhysicsHandleTransform(*Grip, WorldTransform);
5560 if (bRescalePhysicsGrips)
5561 root->SetWorldScale3D(WorldTransform.GetScale3D());
5562 }
5563 }
5564 else
5565 {
5566 // Shouldn't be a grip handle if not server when server side moving
5567 if (GripHandle)
5568 {
5569 UpdatePhysicsHandleTransform(*Grip, WorldTransform);
5570 if (bRescalePhysicsGrips)
5571 root->SetWorldScale3D(WorldTransform.GetScale3D());
5572 }
5573 }
5574
5575 }break;
5576
5578 {
5579 // Ensure physics simulation is off in case something sneaked it on
5580 if (root->IsSimulatingPhysics())
5581 {
5582 root->SetSimulatePhysics(false);
5583 }
5584
5585 FVector OriginalPosition(root->GetComponentLocation());
5586 FRotator OriginalOrientation(root->GetComponentRotation());
5587
5588 FVector NewPosition(WorldTransform.GetTranslation());
5589 FRotator NewOrientation(WorldTransform.GetRotation());
5590
5591 root->ComponentVelocity = (NewPosition - OriginalPosition) / DeltaTime;
5592
5593 // Now sweep collision separately so we can get hits but not have the location altered
5594 if (bUseWithoutTracking || NewPosition != OriginalPosition || NewOrientation != OriginalOrientation)
5595 {
5596 FVector move = NewPosition - OriginalPosition;
5597
5598 // ComponentSweepMulti does nothing if moving < KINDA_SMALL_NUMBER in distance, so it's important to not try to sweep distances smaller than that.
5599 const float MinMovementDistSq = (FMath::Square(4.f*KINDA_SMALL_NUMBER));
5600
5601 if (bUseWithoutTracking || move.SizeSquared() > MinMovementDistSq || NewOrientation != OriginalOrientation)
5602 {
5603 if (CheckComponentWithSweep(root, move, OriginalOrientation, false))
5604 {
5605 Grip->bColliding = true;
5606 }
5607 else
5608 {
5609 Grip->bColliding = false;
5610 }
5611
5612 TArray<USceneComponent* > PrimChildren;
5613 root->GetChildrenComponents(true, PrimChildren);
5614 for (USceneComponent * Prim : PrimChildren)
5615 {
5616 if (UPrimitiveComponent * primComp = Cast<UPrimitiveComponent>(Prim))
5617 {
5618 CheckComponentWithSweep(primComp, move, primComp->GetComponentRotation(), false);
5619 }
5620 }
5621 }
5622 }
5623
5625 {
5626 FScopedMovementUpdate ScopedMovementUpdate(root, EScopedUpdate::DeferredUpdates);
5627 FTransform baseTrans = this->GetAttachParent()->GetComponentTransform();
5628 root->SetWorldTransform(Grip->LastWorldTransform * baseTrans, false, nullptr, ETeleportType::None);
5629 // Move the actor, we are not offsetting by the hit result anyway
5630 root->SetWorldTransform(WorldTransform, false);
5631 }
5632 else
5633 {
5634 // Move the actor, we are not offsetting by the hit result anyway
5635 root->SetWorldTransform(WorldTransform, false);
5636 }
5637
5638 }break;
5639
5641 {
5642 // Ensure physics simulation is off in case something sneaked it on
5643 if (root->IsSimulatingPhysics())
5644 {
5645 root->SetSimulatePhysics(false);
5646 }
5647
5649 {
5650 FScopedMovementUpdate ScopedMovementUpdate(root, EScopedUpdate::DeferredUpdates);
5651 FTransform baseTrans = this->GetAttachParent()->GetComponentTransform();
5652 root->SetWorldTransform(Grip->LastWorldTransform * baseTrans, false, nullptr, ETeleportType::None);
5653 // Move the actor, we are not offsetting by the hit result anyway
5654 root->SetWorldTransform(WorldTransform, false);
5655 }
5656 else
5657 {
5658 // Move the actor, we are not offsetting by the hit result anyway
5659 root->SetWorldTransform(WorldTransform, false);
5660 }
5661
5662 }break;
5663
5665 {
5666 FTransform RelativeTrans = WorldTransform.GetRelativeTransform(ParentTransform);
5667
5668 if (!root->GetAttachParent() || root->IsSimulatingPhysics())
5669 {
5670 UE_LOG(LogVRMotionController, Warning, TEXT("Attachment Grip was missing attach parent - Attempting to Re-attach"));
5671
5672 if (HasGripMovementAuthority(*Grip) || IsServer())
5673 {
5674 root->SetSimulatePhysics(false);
5675 if (root->AttachToComponent(CustomPivotComponent.IsValid() ? CustomPivotComponent.Get() : this, FAttachmentTransformRules::KeepWorldTransform))
5676 {
5677 UE_LOG(LogVRMotionController, Warning, TEXT("Re-attached"));
5678 if (!root->GetRelativeTransform().Equals(RelativeTrans))
5679 {
5680 root->SetRelativeTransform(RelativeTrans);
5681 }
5682 }
5683 }
5684 }
5685 else
5686 {
5687 if (!root->GetRelativeTransform().Equals(RelativeTrans))
5688 {
5689 root->SetRelativeTransform(RelativeTrans);
5690 }
5691 }
5692
5693 }break;
5694
5697 {
5698 UpdatePhysicsHandleTransform(*Grip, WorldTransform);
5699 if (bRescalePhysicsGrips)
5700 root->SetWorldScale3D(WorldTransform.GetScale3D());
5701
5702 }break;
5703
5704 default:
5705 {}break;
5706 }
5707
5708 // We only do this if specifically requested, it has a slight perf hit and isn't normally needed for non Custom Grip types
5710 {
5711 // All non custom grips tick after translation, this is still pre physics so interactive grips location will be wrong, but others will be correct
5712 if (bRootHasInterface)
5713 {
5714 IVRGripInterface::Execute_TickGrip(root, this, *Grip, DeltaTime);
5715 }
5716
5717 if (bActorHasInterface)
5718 {
5719 IVRGripInterface::Execute_TickGrip(actor, this, *Grip, DeltaTime);
5720 }
5721 }
5722 }
5723 else
5724 {
5725 // Object has been destroyed without notification to plugin or is pending kill
5726 if (!Grip->bIsPendingKill)
5727 {
5728 CleanUpBadGrip(GrippedObjectsArray, i, bReplicatedArray);
5729 }
5730 }
5731 }
5732 }
5733}
5734
5735
5736void UGripMotionControllerComponent::CleanUpBadGrip(TArray<FBPActorGripInformation> &GrippedObjectsArray, int GripIndex, bool bReplicatedArray)
5737{
5738 // Object has been destroyed without notification to plugin
5739 if (!DestroyPhysicsHandle(GrippedObjectsArray[GripIndex]))
5740 {
5741 // Clean up tailing physics handles with null objects
5742 for (int g = PhysicsGrips.Num() - 1; g >= 0; --g)
5743 {
5744 if (!PhysicsGrips[g].HandledObject || PhysicsGrips[g].HandledObject == GrippedObjectsArray[GripIndex].GrippedObject || PhysicsGrips[g].HandledObject->IsPendingKill())
5745 {
5746 // Need to delete it from the physics thread
5748 PhysicsGrips.RemoveAt(g);
5749 }
5750 }
5751 }
5752
5753 if (IsServer() || HasGripAuthority(GrippedObjectsArray[GripIndex]))
5754 {
5755 DropGrip_Implementation(GrippedObjectsArray[GripIndex], false);
5756 UE_LOG(LogVRMotionController, Warning, TEXT("Gripped object was null or destroying, auto dropping it"));
5757 }
5758 else
5759 {
5760 GrippedObjectsArray[GripIndex].bIsPendingKill = true;
5761 GrippedObjectsArray[GripIndex].bIsPaused = true;
5762 }
5763}
5764
5766{
5767 // Clean up tailing physics handles with null objects
5768 for (int g = PhysicsGrips.Num() - 1; g >= 0; --g)
5769 {
5770 FBPActorGripInformation * GripInfo = LocallyGrippedObjects.FindByKey(PhysicsGrips[g].GripID);
5771 if(!GripInfo)
5772 GrippedObjects.FindByKey(PhysicsGrips[g].GripID);
5773
5774 if (!GripInfo)
5775 {
5776 // Need to delete it from the physics thread
5778 PhysicsGrips.RemoveAt(g);
5779 }
5780 }
5781}
5782
5783bool UGripMotionControllerComponent::UpdatePhysicsHandle(uint8 GripID, bool bFullyRecreate)
5784{
5785 FBPActorGripInformation* GripInfo = GrippedObjects.FindByKey(GripID);
5786 if (!GripInfo)
5787 GripInfo = LocallyGrippedObjects.FindByKey(GripID);
5788
5789 if (!GripInfo)
5790 return false;
5791
5792 return UpdatePhysicsHandle(*GripInfo, bFullyRecreate);
5793}
5794
5796{
5797 int HandleIndex = 0;
5798 FBPActorPhysicsHandleInformation* HandleInfo = GetPhysicsGrip(GripInfo);
5799
5800 // Don't update if the handle doesn't exist or is currently paused
5801 if (!HandleInfo || HandleInfo->bIsPaused || !HandleInfo->bInitiallySetup)
5802 {
5803 return false;
5804 }
5805#if !PHYSICS_INTERFACE_PHYSX
5806 // We don't have access to the shortcuts outside of physx
5807 return SetUpPhysicsHandle(GripInfo);
5808#else
5809 if (bFullyRecreate || !HandleInfo->HandleData2.IsValid() || HandleInfo->bSkipResettingCom)
5810 {
5811 return SetUpPhysicsHandle(GripInfo);
5812 }
5813
5814 // Not fully recreating
5815
5816
5817 UPrimitiveComponent* root = GripInfo.GetGrippedComponent();
5818 AActor* pActor = GripInfo.GetGrippedActor();
5819
5820 if (!root && pActor)
5821 root = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
5822
5823 if (!root)
5824 return false;
5825
5826 FBodyInstance* rBodyInstance = root->GetBodyInstance(GripInfo.GrippedBoneName);
5827 if (!rBodyInstance || !rBodyInstance->IsValidBodyInstance() || !FPhysicsInterface::IsValid(rBodyInstance->ActorHandle))
5828 {
5829 return false;
5830 }
5831
5832 check(rBodyInstance->BodySetup->GetCollisionTraceFlag() != CTF_UseComplexAsSimple);
5833
5834 FPhysicsCommand::ExecuteWrite(rBodyInstance->ActorHandle, [&](const FPhysicsActorHandle& Actor)
5835 {
5836 if (HandleInfo)
5837 {
5838 if (PxRigidDynamic * PActor = FPhysicsInterface::GetPxRigidDynamic_AssumesLocked(Actor))
5839 {
5840 if(HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.ConstraintData)
5841 HandleInfo->HandleData2.ConstraintData->setActors(PActor, FPhysicsInterface::GetPxRigidDynamic_AssumesLocked(HandleInfo->KinActorData2));
5842 }
5843
5844 if (HandleInfo->bSetCOM && !HandleInfo->bSkipResettingCom)
5845 {
5846 /*FVector Loc = (FTransform((HandleInfo->RootBoneRotation * GripInfo.RelativeTransform).ToInverseMatrixWithScale())).GetLocation();
5847 Loc *= rBodyInstance->Scale3D;*/
5848
5849 FTransform localCom = FPhysicsInterface::GetComTransformLocal_AssumesLocked(Actor);
5850 //localCom.SetLocation(Loc);
5851 localCom.SetLocation(HandleInfo->COMPosition.GetTranslation());//Loc);
5852 FPhysicsInterface::SetComLocalPose_AssumesLocked(Actor, localCom);
5853 }
5854 }
5855
5856 });
5857
5858 return true;
5859#endif
5860
5861 return false;
5862}
5863
5865{
5866 if (!HandleInfo)
5867 return false;
5868
5869 HandleInfo->bIsPaused = true;
5870 HandleInfo->bInitiallySetup = false;
5871 FPhysicsInterface::ReleaseConstraint(HandleInfo->HandleData2);
5872 return true;
5873}
5874
5876{
5877 if (!HandleInfo)
5878 return false;
5879
5880 HandleInfo->bIsPaused = false;
5881 SetUpPhysicsHandle(GripInfo);
5882
5883 return true;
5884}
5885
5887{
5888 if (!HandleInfo)
5889 return false;
5890
5891 FPhysicsInterface::ReleaseConstraint(HandleInfo->HandleData2);
5892
5893 if (!HandleInfo->bSkipDeletingKinematicActor)
5894 {
5895 if (FPhysicsInterface::IsValid(HandleInfo->KinActorData2))
5896 {
5897 FPhysicsActorHandle ActorHandle = HandleInfo->KinActorData2;
5898 FPhysicsCommand::ExecuteWrite(ActorHandle, [&](const FPhysicsActorHandle& Actor)
5899 {
5900 FPhysicsInterface::ReleaseActor(HandleInfo->KinActorData2, FPhysicsInterface::GetCurrentScene(HandleInfo->KinActorData2));
5901 });
5902 }
5903 }
5904
5905 return true;
5906}
5907
5909{
5911
5912 if (!HandleInfo)
5913 {
5914 return true;
5915 }
5916
5917 UPrimitiveComponent *root = Grip.GetGrippedComponent();
5918 AActor * pActor = Grip.GetGrippedActor();
5919
5920 if (!root && pActor)
5921 root = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
5922
5923 if (root)
5924 {
5925 if (FBodyInstance * rBodyInstance = root->GetBodyInstance(Grip.GrippedBoneName))
5926 {
5927 // #TODO: Should this be done on drop instead?
5928 // Remove event registration
5929 if (!bSkipUnregistering)
5930 {
5931 if (rBodyInstance->OnRecalculatedMassProperties().IsBoundToObject(this))
5932 {
5933 rBodyInstance->OnRecalculatedMassProperties().RemoveAll(this);
5934 }
5935 }
5936
5937 if (HandleInfo->bSetCOM)
5938 {
5939 // Reset center of mass to zero
5940 // Get our original values
5941 FVector vel = rBodyInstance->GetUnrealWorldVelocity();
5942 FVector aVel = rBodyInstance->GetUnrealWorldAngularVelocityInRadians();
5943 FVector originalCOM = rBodyInstance->GetCOMPosition();
5944
5945 if (rBodyInstance->IsValidBodyInstance() && rBodyInstance->BodySetup.IsValid())
5946 {
5947 rBodyInstance->UpdateMassProperties();
5948 }
5949
5950 if (rBodyInstance->IsInstanceSimulatingPhysics())
5951 {
5952 // Offset the linear velocity by the new COM position and set it
5953 vel += FVector::CrossProduct(aVel, rBodyInstance->GetCOMPosition() - originalCOM);
5954 rBodyInstance->SetLinearVelocity(vel, false);
5955 }
5956 }
5957 }
5958 }
5959
5960 DestroyPhysicsHandle(HandleInfo);
5961
5962 int index;
5963 if (GetPhysicsGripIndex(Grip, index))
5964 PhysicsGrips.RemoveAt(index);
5965
5966 return true;
5967}
5968
5969void UGripMotionControllerComponent::OnGripMassUpdated(FBodyInstance* GripBodyInstance)
5970{
5971 TArray<FBPActorGripInformation> GripArray;
5972 this->GetAllGrips(GripArray);
5974
5975 for (int i = 0; i < GripArray.Num(); i++)
5976 {
5977 NewGrip = GripArray[i];
5978
5979 UPrimitiveComponent *root = NewGrip.GetGrippedComponent();
5980 AActor * pActor = NewGrip.GetGrippedActor();
5981
5982 if (!root && pActor)
5983 {
5984 if (pActor->IsPendingKill())
5985 continue;
5986
5987 root = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
5988 }
5989
5990 if (!root || root != GripBodyInstance->OwnerComponent)
5991 continue;
5992
5993 if (!root->IsPendingKill())
5994 {
5995 UpdatePhysicsHandle(NewGrip, false);
5996 }
5997 break;
5998 }
5999}
6000
6001bool UGripMotionControllerComponent::SetUpPhysicsHandle(const FBPActorGripInformation &NewGrip, TArray<UVRGripScriptBase*> * GripScripts)
6002{
6003 UPrimitiveComponent *root = NewGrip.GetGrippedComponent();
6004 AActor * pActor = NewGrip.GetGrippedActor();
6005
6006 if(!root && pActor)
6007 root = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
6008
6009 if (!root)
6010 return false;
6011
6012 FBPActorPhysicsHandleInformation* HandleInfo = GetPhysicsGrip(NewGrip);
6013 if (HandleInfo == nullptr)
6014 {
6015 HandleInfo = CreatePhysicsGrip(NewGrip);
6016 }
6017
6018 // If currently paused lets skip this step
6019 if (HandleInfo->bIsPaused)
6020 {
6021 return false;
6022 }
6023
6024 HandleInfo->bSetCOM = false; // Zero this out in case it is a re-init
6025 HandleInfo->bSkipDeletingKinematicActor = (bConstrainToPivot && !NewGrip.bIsLerping);
6026
6027 // Check for grip scripts if we weren't passed in any
6028 TArray<UVRGripScriptBase*> LocalGripScripts;
6029 if (GripScripts == nullptr)
6030 {
6031 if (root && root->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
6032 {
6033 if (IVRGripInterface::Execute_GetGripScripts(root, LocalGripScripts))
6034 {
6035 GripScripts = &LocalGripScripts;
6036 }
6037 }
6038 else if (pActor && pActor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
6039 {
6040 if (IVRGripInterface::Execute_GetGripScripts(pActor, LocalGripScripts))
6041 {
6042 GripScripts = &LocalGripScripts;
6043 }
6044 }
6045 }
6046
6047 // Needs to be simulating in order to run physics
6049 {
6050 // This is a temp fix anyway for a physx bug that appears to only exist in 4.27 from the chaos code merges.
6051 // It breaks physics constraints so I don't want to use it on the other grip types.
6052 // The potential slow downs it can cause really only rear their heads on this grip type anyway
6054 {
6055 root->RecreatePhysicsState();
6056 }
6057
6058 if(!root->IsSimulatingPhysics())
6059 {
6060 root->SetSimulatePhysics(true);
6061 }
6062 }
6063
6064 // Get the PxRigidDynamic that we want to grab.
6065 FBodyInstance* rBodyInstance = root->GetBodyInstance(NewGrip.GrippedBoneName);
6066 if (!rBodyInstance || !rBodyInstance->IsValidBodyInstance() || !FPhysicsInterface::IsValid(rBodyInstance->ActorHandle) || !rBodyInstance->BodySetup.IsValid())
6067 {
6068 return false;
6069 }
6070
6071 check(rBodyInstance->BodySetup->GetCollisionTraceFlag() != CTF_UseComplexAsSimple);
6072
6073 if (!HandleInfo->bSkipResettingCom && !FPhysicsInterface::IsValid(HandleInfo->KinActorData2) && !rBodyInstance->OnRecalculatedMassProperties().IsBoundToObject(this))
6074 {
6075 // Reset the mass properties, this avoids an issue with some weird replication issues
6076 // We only do this on initial grip
6077 rBodyInstance->UpdateMassProperties();
6078
6079 }
6080
6081 FPhysicsCommand::ExecuteWrite(rBodyInstance->ActorHandle, [&](const FPhysicsActorHandle& Actor)
6082 {
6083
6084 FTransform KinPose;
6085 FTransform trans = FPhysicsInterface::GetGlobalPose_AssumesLocked(Actor);
6086 FTransform RootBoneRotation = FTransform::Identity;
6087
6088 if (NewGrip.GrippedBoneName != NAME_None)
6089 {
6090 // Skip root bone rotation
6091 }
6092 else
6093 {
6094 // I actually don't need any of this code anymore or the HandleInfo->RootBoneRotation
6095 // However I would have to expect people to pass in the bone transform without it.
6096 // For now I am keeping it to keep it backwards compatible as it will adjust for root bone rotation automatically then
6097 if (USkeletalMeshComponent * skele = Cast<USkeletalMeshComponent>(root))
6098 {
6099 int32 RootBodyIndex = INDEX_NONE;
6100 if (const UPhysicsAsset* PhysicsAsset = skele->GetPhysicsAsset())
6101 {
6102 for (int32 i = 0; i < skele->GetNumBones(); i++)
6103 {
6104 if (PhysicsAsset->FindBodyIndex(skele->GetBoneName(i)) != INDEX_NONE)
6105 {
6106 RootBodyIndex = i;
6107 break;
6108 }
6109 }
6110 }
6111
6112 if (RootBodyIndex != INDEX_NONE)
6113 {
6114 RootBoneRotation = FTransform(skele->GetBoneTransform(RootBodyIndex, FTransform::Identity));
6115 RootBoneRotation.SetScale3D(FVector(1.f));
6116 RootBoneRotation.NormalizeRotation();
6117 HandleInfo->RootBoneRotation = RootBoneRotation;
6118 }
6119 }
6120 }
6121
6122 EPhysicsGripCOMType COMType = NewGrip.AdvancedGripSettings.PhysicsSettings.PhysicsGripLocationSettings;
6123
6124 if (!NewGrip.AdvancedGripSettings.PhysicsSettings.bUsePhysicsSettings || COMType == EPhysicsGripCOMType::COM_Default)
6125 {
6126 if (NewGrip.GripCollisionType == EGripCollisionType::ManipulationGrip || NewGrip.GripCollisionType == EGripCollisionType::ManipulationGripWithWristTwist)
6127 {
6128 COMType = EPhysicsGripCOMType::COM_GripAtControllerLoc;
6129 }
6130 else
6131 {
6132 COMType = EPhysicsGripCOMType::COM_SetAndGripAt;
6133 }
6134 }
6135
6136
6138 {
6139 // Update the center of mass
6140 FTransform ForwardTrans = (RootBoneRotation * NewGrip.RelativeTransform);
6141 ForwardTrans.NormalizeRotation();
6142 FVector Loc = (FTransform(ForwardTrans.ToInverseMatrixWithScale())).GetLocation();
6143 Loc *= rBodyInstance->Scale3D;
6144
6145 FTransform localCom = FPhysicsInterface::GetComTransformLocal_AssumesLocked(Actor);
6146 localCom.SetLocation(Loc);
6147 FPhysicsInterface::SetComLocalPose_AssumesLocked(Actor, localCom);
6148
6149 FVector ComLoc = FPhysicsInterface::GetComTransform_AssumesLocked(Actor).GetLocation();
6150 trans.SetLocation(ComLoc);
6151 HandleInfo->COMPosition = FTransform(rBodyInstance->GetUnrealWorldTransform().InverseTransformPosition(ComLoc));
6152 HandleInfo->bSetCOM = true;
6153 }
6155 {
6156 FVector ControllerLoc = (FTransform(NewGrip.RelativeTransform.ToInverseMatrixWithScale()) * root->GetComponentTransform()).GetLocation();
6157 trans.SetLocation(ControllerLoc);
6158 HandleInfo->COMPosition = FTransform(rBodyInstance->GetUnrealWorldTransform().InverseTransformPosition(ControllerLoc));
6159 }
6160 else if (COMType != EPhysicsGripCOMType::COM_AtPivot)
6161 {
6162 FVector ComLoc = FPhysicsInterface::GetComTransform_AssumesLocked(Actor).GetLocation();
6163 trans.SetLocation(ComLoc);
6164 HandleInfo->COMPosition = FTransform(rBodyInstance->GetUnrealWorldTransform().InverseTransformPosition(ComLoc));
6165 }
6166
6167 KinPose = trans;
6168 bool bRecreatingConstraint = false;
6169
6170
6171 // If using twist only, lets rotate the kinematic actor to face the controller X+
6172 if (NewGrip.GripCollisionType == EGripCollisionType::ManipulationGripWithWristTwist)
6173 {
6174 FTransform PivTrans = GetPivotTransform();
6175
6176 FQuat DeltaQuat = (PivTrans.GetRotation().Inverse() * KinPose.GetRotation()).Inverse();
6177
6178 // This moves the kinematic actor to face the pivot components X+ direction
6179 KinPose.SetRotation(KinPose.GetRotation() * DeltaQuat);
6180 HandleInfo->COMPosition.SetRotation(HandleInfo->COMPosition.GetRotation()* DeltaQuat);
6181 }
6182
6183 if (GripScripts)
6184 {
6185 bool bResetCom = false;
6186
6187 // Inject any alterations that the grip scripts want to make
6188 for (UVRGripScriptBase* Script : *GripScripts)
6189 {
6190 if (Script && Script->IsScriptActive() && Script->InjectPrePhysicsHandle())
6191 {
6192 Script->HandlePrePhysicsHandle(this, NewGrip, HandleInfo, KinPose);
6193 bResetCom = true;
6194 }
6195 }
6196
6197 if (HandleInfo->bSetCOM && bResetCom)
6198 {
6199 FTransform localCom = FPhysicsInterface::GetComTransformLocal_AssumesLocked(Actor);
6200 localCom.SetLocation(HandleInfo->COMPosition.GetTranslation());//Loc);
6201
6202 FPhysicsInterface::SetComLocalPose_AssumesLocked(Actor, localCom);
6203 }
6204 }
6205
6206 if (!NewGrip.bIsLerping && bConstrainToPivot && CustomPivotComponent.IsValid())
6207 {
6208 if (UPrimitiveComponent* PivotPrim = Cast<UPrimitiveComponent>(CustomPivotComponent))
6209 {
6210 if (FBodyInstance* Bodyinst = PivotPrim->GetBodyInstance(CustomPivotComponentSocketName))
6211 {
6212 HandleInfo->KinActorData2 = Bodyinst->GetPhysicsActorHandle();
6213 }
6214 }
6215 }
6216
6217 if (!FPhysicsInterface::IsValid(HandleInfo->KinActorData2))
6218 {
6219 // Create kinematic actor we are going to create joint with. This will be moved around with calls to SetLocation/SetRotation.
6220
6221 //FString DebugName(TEXT("KinematicGripActor"));
6222 //TSharedPtr<TArray<ANSICHAR>> PhysXName = MakeShareable(new TArray<ANSICHAR>(StringToArray<ANSICHAR>(*DebugName, DebugName.Len() + 1)));
6223
6224 FActorCreationParams ActorParams;
6225 ActorParams.InitialTM = KinPose;
6226 ActorParams.DebugName = nullptr;//PhysXName->GetData();
6227 ActorParams.bEnableGravity = false;
6228 ActorParams.bQueryOnly = false;// true; // True or false?
6229 ActorParams.bStatic = false;
6230 ActorParams.Scene = FPhysicsInterface::GetCurrentScene(Actor);
6231 FPhysicsInterface::CreateActor(ActorParams, HandleInfo->KinActorData2);
6232
6233 if (FPhysicsInterface::IsValid(HandleInfo->KinActorData2))
6234 {
6235 FPhysicsInterface::SetMass_AssumesLocked(HandleInfo->KinActorData2, 1.0f);
6236 FPhysicsInterface::SetMassSpaceInertiaTensor_AssumesLocked(HandleInfo->KinActorData2, FVector(1.f));
6237 FPhysicsInterface::SetIsKinematic_AssumesLocked(HandleInfo->KinActorData2, true);
6238 FPhysicsInterface::SetMaxDepenetrationVelocity_AssumesLocked(HandleInfo->KinActorData2, MAX_FLT);
6239 //FPhysicsInterface::SetActorUserData_AssumesLocked(HandleInfo->KinActorData2, NULL);
6240 }
6241
6242#if PHYSICS_INTERFACE_PHYSX
6243 // Correct method is missing an ENGINE_API flag, so I can't use the function
6244 ActorParams.Scene->GetPxScene()->addActor(*FPhysicsInterface_PhysX::GetPxRigidActor_AssumesLocked(HandleInfo->KinActorData2));
6245#elif WITH_CHAOS
6246 using namespace Chaos;
6247 // Missing from physx, not sure how it is working for them currently.
6248 //TArray<FPhysicsActorHandle> ActorHandles;
6249 HandleInfo->KinActorData2->GetGameThreadAPI().SetGeometry(TUniquePtr<FImplicitObject>(new TSphere<FReal, 3>(TVector<FReal, 3>(0.f), 1000.f)));
6250 HandleInfo->KinActorData2->GetGameThreadAPI().SetObjectState(EObjectStateType::Kinematic);
6251 FPhysicsInterface::AddActorToSolver(HandleInfo->KinActorData2, ActorParams.Scene->GetSolver());
6252 //ActorHandles.Add(HandleInfo->KinActorData2);
6253 //ActorParams.Scene->AddActorsToScene_AssumesLocked(ActorHandles);
6254#endif
6255 }
6256
6257 // If we don't already have a handle - make one now.
6258 if (!HandleInfo->HandleData2.IsValid())
6259 {
6260 // If this is true we will totally ignore the COM type, either we are gripping unstable or the com was set to our controller, we never accept
6261 // Grip at COM
6262 if (!NewGrip.bIsLerping && bConstrainToPivot)
6263 {
6264 FTransform TargetTrans(FTransform(NewGrip.RelativeTransform.ToMatrixNoScale().Inverse()) * HandleInfo->RootBoneRotation.Inverse());
6265 HandleInfo->HandleData2 = FPhysicsInterface::CreateConstraint(HandleInfo->KinActorData2, Actor, FTransform::Identity, TargetTrans);
6266 }
6267 else
6268 {
6269 HandleInfo->HandleData2 = FPhysicsInterface::CreateConstraint(HandleInfo->KinActorData2, Actor, FTransform::Identity, KinPose.GetRelativeTransform(FPhysicsInterface::GetGlobalPose_AssumesLocked(Actor)));
6270 }
6271 }
6272 else
6273 {
6274 bRecreatingConstraint = true;
6275
6276 /*
6277 FTransform newTrans = HandleInfo->COMPosition * (HandleInfo->RootBoneRotation * HandleInfo->LastPhysicsTransform);
6278 */
6279#if PHYSICS_INTERFACE_PHYSX
6280 // If we have physx then we can directly set the actors to ensure that they are correct
6281 if (HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.ConstraintData)
6282 {
6283 if (!NewGrip.bIsLerping && bConstrainToPivot)
6284 {
6285 HandleInfo->HandleData2.ConstraintData->setActors(FPhysicsInterface_PhysX::GetPxRigidDynamic_AssumesLocked(Actor), FPhysicsInterface_PhysX::GetPxRigidDynamic_AssumesLocked(HandleInfo->KinActorData2));
6286
6287 FTransform TargetTrans(NewGrip.RelativeTransform.ToMatrixNoScale().Inverse());
6288 FPhysicsInterface::SetLocalPose(HandleInfo->HandleData2, TargetTrans, EConstraintFrame::Frame2);
6289 }
6290 else
6291 {
6292 HandleInfo->HandleData2.ConstraintData->setActors(FPhysicsInterface_PhysX::GetPxRigidDynamic_AssumesLocked(Actor), FPhysicsInterface_PhysX::GetPxRigidDynamic_AssumesLocked(HandleInfo->KinActorData2));
6293 FPhysicsInterface::SetLocalPose(HandleInfo->HandleData2, KinPose.GetRelativeTransform(FPhysicsInterface::GetGlobalPose_AssumesLocked(Actor)), EConstraintFrame::Frame2);
6294 }
6295 }
6296#elif WITH_CHAOS
6297
6298 // There isn't a direct set for the particles, so keep it as a recreation instead.
6299 FPhysicsInterface::ReleaseConstraint(HandleInfo->HandleData2);
6300
6301 if (!NewGrip.bIsLerping && bConstrainToPivot)
6302 {
6303 FTransform TargetTrans(NewGrip.RelativeTransform.ToMatrixNoScale().Inverse());
6304 HandleInfo->HandleData2 = FPhysicsInterface::CreateConstraint(HandleInfo->KinActorData2, Actor, FTransform::Identity, TargetTrans);
6305 }
6306 else
6307 {
6308 HandleInfo->HandleData2 = FPhysicsInterface::CreateConstraint(HandleInfo->KinActorData2, Actor, FTransform::Identity, KinPose.GetRelativeTransform(FPhysicsInterface::GetGlobalPose_AssumesLocked(Actor)));
6309 }
6310#endif
6311
6312 }
6313
6314 if (HandleInfo->HandleData2.IsValid())
6315 {
6316 FPhysicsInterface::SetBreakForces_AssumesLocked(HandleInfo->HandleData2, MAX_FLT, MAX_FLT);
6317
6318
6319 if (NewGrip.GripCollisionType == EGripCollisionType::LockedConstraint)
6320 {
6321 FPhysicsInterface::SetLinearMotionLimitType_AssumesLocked(HandleInfo->HandleData2, PhysicsInterfaceTypes::ELimitAxis::X, ELinearConstraintMotion::LCM_Locked);
6322 FPhysicsInterface::SetLinearMotionLimitType_AssumesLocked(HandleInfo->HandleData2, PhysicsInterfaceTypes::ELimitAxis::Y, ELinearConstraintMotion::LCM_Locked);
6323 FPhysicsInterface::SetLinearMotionLimitType_AssumesLocked(HandleInfo->HandleData2, PhysicsInterfaceTypes::ELimitAxis::Z, ELinearConstraintMotion::LCM_Locked);
6324 FPhysicsInterface::SetAngularMotionLimitType_AssumesLocked(HandleInfo->HandleData2, PhysicsInterfaceTypes::ELimitAxis::Twist, EAngularConstraintMotion::ACM_Locked);
6325 FPhysicsInterface::SetAngularMotionLimitType_AssumesLocked(HandleInfo->HandleData2, PhysicsInterfaceTypes::ELimitAxis::Swing1, EAngularConstraintMotion::ACM_Locked);
6326 FPhysicsInterface::SetAngularMotionLimitType_AssumesLocked(HandleInfo->HandleData2, PhysicsInterfaceTypes::ELimitAxis::Swing2, EAngularConstraintMotion::ACM_Locked);
6327 FPhysicsInterface::SetProjectionEnabled_AssumesLocked(HandleInfo->HandleData2, true, 0.01f, 0.01f);
6328 }
6329 else
6330 {
6331 FPhysicsInterface::SetLinearMotionLimitType_AssumesLocked(HandleInfo->HandleData2, PhysicsInterfaceTypes::ELimitAxis::X, ELinearConstraintMotion::LCM_Free);
6332 FPhysicsInterface::SetLinearMotionLimitType_AssumesLocked(HandleInfo->HandleData2, PhysicsInterfaceTypes::ELimitAxis::Y, ELinearConstraintMotion::LCM_Free);
6333 FPhysicsInterface::SetLinearMotionLimitType_AssumesLocked(HandleInfo->HandleData2, PhysicsInterfaceTypes::ELimitAxis::Z, ELinearConstraintMotion::LCM_Free);
6334 FPhysicsInterface::SetAngularMotionLimitType_AssumesLocked(HandleInfo->HandleData2, PhysicsInterfaceTypes::ELimitAxis::Twist, EAngularConstraintMotion::ACM_Free);
6335 FPhysicsInterface::SetAngularMotionLimitType_AssumesLocked(HandleInfo->HandleData2, PhysicsInterfaceTypes::ELimitAxis::Swing1, EAngularConstraintMotion::ACM_Free);
6336 FPhysicsInterface::SetAngularMotionLimitType_AssumesLocked(HandleInfo->HandleData2, PhysicsInterfaceTypes::ELimitAxis::Swing2, EAngularConstraintMotion::ACM_Free);
6337 FPhysicsInterface::SetProjectionEnabled_AssumesLocked(HandleInfo->HandleData2, false);
6338 }
6339
6340 FPhysicsInterface::SetDrivePosition(HandleInfo->HandleData2, FVector::ZeroVector);
6341
6342 bool bUseForceDrive = (NewGrip.AdvancedGripSettings.PhysicsSettings.bUsePhysicsSettings && NewGrip.AdvancedGripSettings.PhysicsSettings.PhysicsConstraintType == EPhysicsGripConstraintType::ForceConstraint);
6343
6344 float Stiffness = NewGrip.Stiffness;
6345 float Damping = NewGrip.Damping;
6346 float MaxForce;
6347 float AngularStiffness;
6348 float AngularDamping;
6349 float AngularMaxForce;
6350
6351 if (NewGrip.AdvancedGripSettings.PhysicsSettings.bUsePhysicsSettings && NewGrip.AdvancedGripSettings.PhysicsSettings.bUseCustomAngularValues)
6352 {
6353 AngularStiffness = NewGrip.AdvancedGripSettings.PhysicsSettings.AngularStiffness;
6354 AngularDamping = NewGrip.AdvancedGripSettings.PhysicsSettings.AngularDamping;
6355 }
6356 else
6357 {
6358 AngularStiffness = Stiffness * ANGULAR_STIFFNESS_MULTIPLIER; // Default multiplier
6359 AngularDamping = Damping * ANGULAR_DAMPING_MULTIPLIER; // Default multiplier
6360 }
6361
6362#if WITH_CHAOS
6363 const UVRGlobalSettings& VRSettings = *GetDefault<UVRGlobalSettings>();
6364
6365 Stiffness *= VRSettings.LinearDriveStiffnessScale;
6366 Damping *= VRSettings.LinearDriveDampingScale;
6367 AngularStiffness *= VRSettings.AngularDriveStiffnessScale;
6368 AngularDamping *= VRSettings.AngularDriveDampingScale;
6369#endif
6370
6371 AngularMaxForce = (float)FMath::Clamp<double>((double)AngularStiffness * (double)NewGrip.AdvancedGripSettings.PhysicsSettings.AngularMaxForceCoefficient, 0, (double)MAX_FLT);
6372 MaxForce = (float)FMath::Clamp<double>((double)Stiffness * (double)NewGrip.AdvancedGripSettings.PhysicsSettings.LinearMaxForceCoefficient, 0, (double)MAX_FLT);
6373
6374 // Different settings for manip grip
6375 if (NewGrip.GripCollisionType == EGripCollisionType::ManipulationGrip || NewGrip.GripCollisionType == EGripCollisionType::ManipulationGripWithWristTwist)
6376 {
6377 if (!bRecreatingConstraint)
6378 {
6379 FConstraintDrive NewLinDrive;
6380 NewLinDrive.bEnablePositionDrive = true;
6381 NewLinDrive.bEnableVelocityDrive = true;
6382 NewLinDrive.Damping = Damping;
6383 NewLinDrive.Stiffness = Stiffness;
6384 NewLinDrive.MaxForce = MaxForce;
6385
6386 HandleInfo->LinConstraint.bEnablePositionDrive = true;
6387 HandleInfo->LinConstraint.XDrive = NewLinDrive;
6388 HandleInfo->LinConstraint.YDrive = NewLinDrive;
6389 HandleInfo->LinConstraint.ZDrive = NewLinDrive;
6390 }
6391
6392
6393 if (NewGrip.GripCollisionType == EGripCollisionType::ManipulationGripWithWristTwist)
6394 {
6395 if (!bRecreatingConstraint)
6396 {
6397 FConstraintDrive NewAngDrive;
6398 NewAngDrive.bEnablePositionDrive = true;
6399 NewAngDrive.bEnableVelocityDrive = true;
6400 NewAngDrive.Damping = AngularDamping;
6401 NewAngDrive.Stiffness = AngularStiffness;
6402 NewAngDrive.MaxForce = AngularMaxForce;
6403 //NewAngDrive.MaxForce = MAX_FLT;
6404
6405 HandleInfo->AngConstraint.AngularDriveMode = EAngularDriveMode::TwistAndSwing;
6406 //AngParams.AngularDriveMode = EAngularDriveMode::SLERP;
6407 HandleInfo->AngConstraint.TwistDrive = NewAngDrive;
6408 }
6409 }
6410
6411 if (GripScripts)
6412 {
6413 // Inject any alterations that the grip scripts want to make
6414 for (UVRGripScriptBase* Script : *GripScripts)
6415 {
6416 if (Script && Script->IsScriptActive() && Script->InjectPostPhysicsHandle())
6417 {
6418 Script->HandlePostPhysicsHandle(this, HandleInfo);
6419 }
6420 }
6421 }
6422
6423 FPhysicsInterface::UpdateLinearDrive_AssumesLocked(HandleInfo->HandleData2, HandleInfo->LinConstraint);
6424 FPhysicsInterface::UpdateAngularDrive_AssumesLocked(HandleInfo->HandleData2, HandleInfo->AngConstraint);
6425 }
6426 else
6427 {
6428 if (NewGrip.GripCollisionType == EGripCollisionType::InteractiveHybridCollisionWithPhysics)
6429 {
6430 // Do not effect damping, just increase stiffness so that it is stronger
6431 // Default multiplier
6432 Stiffness *= HYBRID_PHYSICS_GRIP_MULTIPLIER;
6433 AngularStiffness *= HYBRID_PHYSICS_GRIP_MULTIPLIER;
6434 AngularMaxForce = (float)FMath::Clamp<double>((double)AngularStiffness * (double)NewGrip.AdvancedGripSettings.PhysicsSettings.AngularMaxForceCoefficient, 0, (double)MAX_FLT);
6435 MaxForce = (float)FMath::Clamp<double>((double)Stiffness * (double)NewGrip.AdvancedGripSettings.PhysicsSettings.LinearMaxForceCoefficient, 0, (double)MAX_FLT);
6436 }
6437
6438 if (!bRecreatingConstraint)
6439 {
6440 if (NewGrip.GripCollisionType != EGripCollisionType::LockedConstraint)
6441 {
6442 FConstraintDrive NewLinDrive;
6443 NewLinDrive.bEnablePositionDrive = true;
6444 NewLinDrive.bEnableVelocityDrive = true;
6445 NewLinDrive.Damping = Damping;
6446 NewLinDrive.Stiffness = Stiffness;
6447 NewLinDrive.MaxForce = MaxForce;
6448 //NewLinDrive.MaxForce = MAX_FLT;
6449
6450 FConstraintDrive NewAngDrive;
6451 NewAngDrive.bEnablePositionDrive = true;
6452 NewAngDrive.bEnableVelocityDrive = true;
6453 NewAngDrive.Damping = AngularDamping;
6454 NewAngDrive.Stiffness = AngularStiffness;
6455 NewAngDrive.MaxForce = AngularMaxForce;
6456 //NewAngDrive.MaxForce = MAX_FLT;
6457
6458 HandleInfo->LinConstraint.bEnablePositionDrive = true;
6459 HandleInfo->LinConstraint.XDrive = NewLinDrive;
6460 HandleInfo->LinConstraint.YDrive = NewLinDrive;
6461 HandleInfo->LinConstraint.ZDrive = NewLinDrive;
6462
6463 HandleInfo->AngConstraint.AngularDriveMode = EAngularDriveMode::SLERP;
6464 HandleInfo->AngConstraint.SlerpDrive = NewAngDrive;
6465 }
6466 }
6467
6468 if (GripScripts)
6469 {
6470 // Inject any alterations that the grip scripts want to make
6471 for (UVRGripScriptBase* Script : *GripScripts)
6472 {
6473 if (Script && Script->IsScriptActive() && Script->InjectPostPhysicsHandle())
6474 {
6475 Script->HandlePostPhysicsHandle(this, HandleInfo);
6476 }
6477 }
6478 }
6479
6480 FPhysicsInterface::UpdateLinearDrive_AssumesLocked(HandleInfo->HandleData2, HandleInfo->LinConstraint);
6481 FPhysicsInterface::UpdateAngularDrive_AssumesLocked(HandleInfo->HandleData2, HandleInfo->AngConstraint);
6482 }
6483
6484
6485 // This is a temp workaround until epic fixes the drive creation to allow force constraints
6486 // I wanted to use the new interface and not directly set the drive so that it is ready to delete this section
6487 // When its fixed
6488#if PHYSICS_INTERFACE_PHYSX
6489 if (bUseForceDrive && HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.ConstraintData)
6490 {
6491 if (NewGrip.GripCollisionType != EGripCollisionType::LockedConstraint)
6492 {
6493 PxD6JointDrive driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eX);
6494 driveVal.flags = PxD6JointDriveFlags();//&= ~PxD6JointDriveFlag::eACCELERATION;
6495 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eX, driveVal);
6496
6497 driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eY);
6498 driveVal.flags = PxD6JointDriveFlags();//&= ~PxD6JointDriveFlag::eACCELERATION;
6499 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eY, driveVal);
6500
6501 driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eZ);
6502 driveVal.flags = PxD6JointDriveFlags();//&= ~PxD6JointDriveFlag::eACCELERATION;
6503 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eZ, driveVal);
6504
6505 driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eTWIST);
6506 driveVal.flags = PxD6JointDriveFlags();//&= ~PxD6JointDriveFlag::eACCELERATION;
6507 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eTWIST, driveVal);
6508
6509 driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eSWING);
6510 driveVal.flags = PxD6JointDriveFlags();//&= ~PxD6JointDriveFlag::eACCELERATION;
6511 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eTWIST, driveVal);
6512
6513 driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eSLERP);
6514 driveVal.flags = PxD6JointDriveFlags();//&= ~PxD6JointDriveFlag::eACCELERATION;
6515 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eSLERP, driveVal);
6516 }
6517 }
6518#elif WITH_CHAOS
6519 if (bUseForceDrive && HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.Constraint)
6520 {
6521 if (HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.Constraint->IsType(Chaos::EConstraintType::JointConstraintType))
6522 {
6523 if (Chaos::FJointConstraint* Constraint = static_cast<Chaos::FJointConstraint*>(HandleInfo->HandleData2.Constraint))
6524 {
6525 Constraint->SetLinearDriveForceMode(Chaos::EJointForceMode::Force);
6526 Constraint->SetAngularDriveForceMode(Chaos::EJointForceMode::Force);
6527 }
6528 }
6529 }
6530#endif
6531 }
6532 });
6533
6534 HandleInfo->bInitiallySetup = true;
6535
6536 // Bind to further updates in order to keep it alive
6537 if (!rBodyInstance->OnRecalculatedMassProperties().IsBoundToObject(this))
6538 {
6539 rBodyInstance->OnRecalculatedMassProperties().AddUObject(this, &UGripMotionControllerComponent::OnGripMassUpdated);
6540 }
6541
6542 return true;
6543}
6544
6546{
6547 if (!Grip)
6548 return false;
6549
6551
6552 if (HandleInfo)
6553 {
6554 if (HandleInfo->HandleData2.IsValid())
6555 {
6556 FPhysicsInterface::ExecuteOnUnbrokenConstraintReadWrite(HandleInfo->HandleData2, [&](const FPhysicsConstraintHandle& InUnbrokenConstraint)
6557 {
6558 bool bUseForceDrive = (Grip->AdvancedGripSettings.PhysicsSettings.bUsePhysicsSettings && Grip->AdvancedGripSettings.PhysicsSettings.PhysicsConstraintType == EPhysicsGripConstraintType::ForceConstraint);
6559
6560 float Stiffness = Grip->Stiffness;
6561 float Damping = Grip->Damping;
6562 float MaxForce;
6563 float AngularStiffness;
6564 float AngularDamping;
6565 float AngularMaxForce;
6566
6567 if (Grip->AdvancedGripSettings.PhysicsSettings.bUsePhysicsSettings && Grip->AdvancedGripSettings.PhysicsSettings.bUseCustomAngularValues)
6568 {
6569 AngularStiffness = Grip->AdvancedGripSettings.PhysicsSettings.AngularStiffness;
6570 AngularDamping = Grip->AdvancedGripSettings.PhysicsSettings.AngularDamping;
6571 }
6572 else
6573 {
6574 AngularStiffness = Stiffness * ANGULAR_STIFFNESS_MULTIPLIER; // Default multiplier
6575 AngularDamping = Damping * ANGULAR_DAMPING_MULTIPLIER; // Default multiplier
6576 }
6577
6578#if WITH_CHAOS
6579 const UVRGlobalSettings& VRSettings = *GetDefault<UVRGlobalSettings>();
6580
6581 Stiffness *= VRSettings.LinearDriveStiffnessScale;
6582 Damping *= VRSettings.LinearDriveDampingScale;
6583 AngularStiffness *= VRSettings.AngularDriveStiffnessScale;
6584 AngularDamping *= VRSettings.AngularDriveDampingScale;
6585#endif
6586
6587 AngularMaxForce = (float)FMath::Clamp<double>((double)AngularStiffness * (double)Grip->AdvancedGripSettings.PhysicsSettings.AngularMaxForceCoefficient, 0, (double)MAX_FLT);
6588 MaxForce = (float)FMath::Clamp<double>((double)Stiffness * (double)Grip->AdvancedGripSettings.PhysicsSettings.LinearMaxForceCoefficient, 0, (double)MAX_FLT);
6589
6590
6591 // Different settings for manip grip
6593 {
6594 HandleInfo->LinConstraint.XDrive.Damping = Damping;
6595 HandleInfo->LinConstraint.XDrive.Stiffness = Stiffness;
6596 HandleInfo->LinConstraint.XDrive.MaxForce = MaxForce;
6597 HandleInfo->LinConstraint.YDrive.Damping = Damping;
6598 HandleInfo->LinConstraint.YDrive.Stiffness = Stiffness;
6599 HandleInfo->LinConstraint.YDrive.MaxForce = MaxForce;
6600 HandleInfo->LinConstraint.ZDrive.Damping = Damping;
6601 HandleInfo->LinConstraint.ZDrive.Stiffness = Stiffness;
6602 HandleInfo->LinConstraint.ZDrive.MaxForce = MaxForce;
6603
6604 FPhysicsInterface::UpdateLinearDrive_AssumesLocked(HandleInfo->HandleData2, HandleInfo->LinConstraint);
6605#if PHYSICS_INTERFACE_PHYSX
6606 if (bUseForceDrive && HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.ConstraintData)
6607 {
6608 PxD6JointDrive driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eX);
6609 driveVal.flags &= ~PxD6JointDriveFlag::eACCELERATION;
6610 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eX, driveVal);
6611
6612 driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eY);
6613 driveVal.flags &= ~PxD6JointDriveFlag::eACCELERATION;
6614 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eY, driveVal);
6615
6616 driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eZ);
6617 driveVal.flags &= ~PxD6JointDriveFlag::eACCELERATION;
6618 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eZ, driveVal);
6619 }
6620#elif WITH_CHAOS
6621 if (bUseForceDrive && HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.Constraint)
6622 {
6623 if (HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.Constraint->IsType(Chaos::EConstraintType::JointConstraintType))
6624 {
6625 if (Chaos::FJointConstraint* Constraint = static_cast<Chaos::FJointConstraint*>(HandleInfo->HandleData2.Constraint))
6626 {
6627 Constraint->SetLinearDriveForceMode(Chaos::EJointForceMode::Force);
6628 Constraint->SetAngularDriveForceMode(Chaos::EJointForceMode::Force);
6629 }
6630 }
6631 }
6632#endif
6633
6635 {
6636 HandleInfo->AngConstraint.TwistDrive.Damping = AngularDamping;
6637 HandleInfo->AngConstraint.TwistDrive.Stiffness = AngularStiffness;
6638 HandleInfo->AngConstraint.TwistDrive.MaxForce = AngularMaxForce;
6639
6640 FPhysicsInterface::UpdateAngularDrive_AssumesLocked(HandleInfo->HandleData2, HandleInfo->AngConstraint);
6641
6642#if PHYSICS_INTERFACE_PHYSX
6643 if (bUseForceDrive && HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.ConstraintData)
6644 {
6645 PxD6JointDrive driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eTWIST);
6646 driveVal.flags &= ~PxD6JointDriveFlag::eACCELERATION;
6647 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eTWIST, driveVal);
6648 }
6649#endif
6650 }
6651
6652 FPhysicsInterface::SetDrivePosition(HandleInfo->HandleData2, FVector::ZeroVector);
6653 FPhysicsInterface::SetDriveOrientation(HandleInfo->HandleData2, FQuat::Identity);
6654 }
6655 else
6656 {
6658 {
6659 // Do not effect damping, just increase stiffness so that it is stronger
6660 // Default multiplier
6661 Stiffness *= HYBRID_PHYSICS_GRIP_MULTIPLIER;
6662 AngularStiffness *= HYBRID_PHYSICS_GRIP_MULTIPLIER;
6663
6664 AngularMaxForce = (float)FMath::Clamp<double>((double)AngularStiffness * (double)Grip->AdvancedGripSettings.PhysicsSettings.AngularMaxForceCoefficient, 0, (double)MAX_FLT);
6665 MaxForce = (float)FMath::Clamp<double>((double)Stiffness * (double)Grip->AdvancedGripSettings.PhysicsSettings.LinearMaxForceCoefficient, 0, (double)MAX_FLT);
6666 }
6667
6668 HandleInfo->LinConstraint.XDrive.Damping = Damping;
6669 HandleInfo->LinConstraint.XDrive.Stiffness = Stiffness;
6670 HandleInfo->LinConstraint.XDrive.MaxForce = MaxForce;
6671 HandleInfo->LinConstraint.YDrive.Damping = Damping;
6672 HandleInfo->LinConstraint.YDrive.Stiffness = Stiffness;
6673 HandleInfo->LinConstraint.YDrive.MaxForce = MaxForce;
6674 HandleInfo->LinConstraint.ZDrive.Damping = Damping;
6675 HandleInfo->LinConstraint.ZDrive.Stiffness = Stiffness;
6676 HandleInfo->LinConstraint.ZDrive.MaxForce = MaxForce;
6677
6678 FPhysicsInterface::UpdateLinearDrive_AssumesLocked(HandleInfo->HandleData2, HandleInfo->LinConstraint);
6679
6680#if PHYSICS_INTERFACE_PHYSX
6681 if (bUseForceDrive && HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.ConstraintData)
6682 {
6683 PxD6JointDrive driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eX);
6684 driveVal.flags &= ~PxD6JointDriveFlag::eACCELERATION;
6685 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eX, driveVal);
6686
6687 driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eY);
6688 driveVal.flags &= ~PxD6JointDriveFlag::eACCELERATION;
6689 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eY, driveVal);
6690
6691 driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eZ);
6692 driveVal.flags &= ~PxD6JointDriveFlag::eACCELERATION;
6693 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eZ, driveVal);
6694 }
6695#elif WITH_CHAOS
6696 if (bUseForceDrive && HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.Constraint)
6697 {
6698 if (HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.Constraint->IsType(Chaos::EConstraintType::JointConstraintType))
6699 {
6700 if (Chaos::FJointConstraint* Constraint = static_cast<Chaos::FJointConstraint*>(HandleInfo->HandleData2.Constraint))
6701 {
6702 Constraint->SetLinearDriveForceMode(Chaos::EJointForceMode::Force);
6703 }
6704 }
6705 }
6706#endif
6707
6708
6709 HandleInfo->AngConstraint.SlerpDrive.Damping = AngularDamping;
6710 HandleInfo->AngConstraint.SlerpDrive.Stiffness = AngularStiffness;
6711 HandleInfo->AngConstraint.SlerpDrive.MaxForce = AngularMaxForce;
6712 FPhysicsInterface::UpdateAngularDrive_AssumesLocked(HandleInfo->HandleData2, HandleInfo->AngConstraint);
6713
6714#if PHYSICS_INTERFACE_PHYSX
6715 if (bUseForceDrive && HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.ConstraintData)
6716 {
6717 PxD6JointDrive driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eTWIST);
6718 driveVal.flags &= ~PxD6JointDriveFlag::eACCELERATION;
6719 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eTWIST, driveVal);
6720
6721 driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eSWING);
6722 driveVal.flags &= ~PxD6JointDriveFlag::eACCELERATION;
6723 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eSWING, driveVal);
6724
6725 driveVal = HandleInfo->HandleData2.ConstraintData->getDrive(PxD6Drive::Enum::eSLERP);
6726 driveVal.flags &= ~PxD6JointDriveFlag::eACCELERATION;
6727 HandleInfo->HandleData2.ConstraintData->setDrive(PxD6Drive::Enum::eSLERP, driveVal);
6728 }
6729#elif WITH_CHAOS
6730 if (bUseForceDrive && HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.Constraint)
6731 {
6732 if (HandleInfo->HandleData2.IsValid() && HandleInfo->HandleData2.Constraint->IsType(Chaos::EConstraintType::JointConstraintType))
6733 {
6734 if (Chaos::FJointConstraint* Constraint = static_cast<Chaos::FJointConstraint*>(HandleInfo->HandleData2.Constraint))
6735 {
6736 Constraint->SetAngularDriveForceMode(Chaos::EJointForceMode::Force);
6737 }
6738 }
6739 }
6740#endif
6741 }
6742
6743 });
6744
6745 }
6746 return true;
6747 }
6748
6749 return false;
6750}
6751
6752bool UGripMotionControllerComponent::GetPhysicsJointLength(const FBPActorGripInformation &GrippedActor, UPrimitiveComponent * rootComp, FVector & LocOut)
6753{
6754 if (!GrippedActor.GrippedObject)
6755 return false;
6756
6757 FBPActorPhysicsHandleInformation * HandleInfo = GetPhysicsGrip(GrippedActor);
6758
6759 if (!HandleInfo || !FPhysicsInterface::IsValid(HandleInfo->KinActorData2))
6760 return false;
6761
6762 if (!HandleInfo->HandleData2.IsValid())
6763 return false;
6764
6765 // Not using com with skipping mass check as the COM can change on us
6766 // Also skipping it on skip resetting com as we aren't gripped to the COM then
6767 bool bUseComLoc =
6768 (
6769 !HandleInfo->bSkipResettingCom &&
6770 (HandleInfo->bSetCOM ||
6772 );
6773
6774 // This is supposed to be the difference between the actor and the kinactor / constraint base
6775 FTransform tran3 = FTransform::Identity;
6776
6777 FBodyInstance* rBodyInstance = rootComp->GetBodyInstance(GrippedActor.GrippedBoneName);
6778
6779 if (bUseComLoc && rBodyInstance && rBodyInstance->IsValidBodyInstance())
6780 {
6781 tran3 = FTransform(rBodyInstance->GetCOMPosition());
6782 }
6783 else
6784 {
6785 FTransform rr;
6786 tran3 = FPhysicsInterface::GetLocalPose(HandleInfo->HandleData2, EConstraintFrame::Frame2);
6787
6788 if (!rBodyInstance || !rBodyInstance->IsValidBodyInstance())
6789 {
6790 rr = rootComp->GetComponentTransform();
6791 // Physx location throws out scale, this is where the problem was
6792 rr.SetScale3D(FVector(1, 1, 1));
6793 }
6794 else
6795 rr = rBodyInstance->GetUnrealWorldTransform();
6796
6797 // Make the local pose global
6798 tran3 = tran3 * rr;
6799 }
6800
6801 // Get the global pose for the kin actor
6802 FTransform kinPose = FTransform::Identity;
6803 FPhysicsCommand::ExecuteRead(HandleInfo->KinActorData2, [&](const FPhysicsActorHandle & Actor)
6804 {
6805 kinPose = FPhysicsInterface::GetGlobalPose_AssumesLocked(Actor);
6806 });
6807
6808 // Return the difference
6809 LocOut = FTransform::SubtractTranslations(kinPose, tran3);
6810
6811 return true;
6812}
6813
6814void UGripMotionControllerComponent::UpdatePhysicsHandleTransform(const FBPActorGripInformation &GrippedActor, const FTransform& NewTransform)
6815{
6816 if (!GrippedActor.GrippedObject || (bConstrainToPivot && !GrippedActor.bIsLerping) || GetWorld()->IsInSeamlessTravel())
6817 return;
6818
6819 if (!NewTransform.IsValid())
6820 {
6821 UE_LOG(LogVRMotionController, Warning, TEXT("Something went wrong, UpdatePhysicsHandeTransforms target transform contained NAN!."));
6822 return;
6823 }
6824
6825 FBPActorPhysicsHandleInformation * HandleInfo = GetPhysicsGrip(GrippedActor);
6826
6827 if (!HandleInfo || !FPhysicsInterface::IsValid(HandleInfo->KinActorData2))// || !HandleInfo->HandleData2.IsValid())
6828 return;
6829
6830#if PHYSICS_INTERFACE_PHYSX
6831 // Early out check for this
6832 // Think this may be an engine issue where I have to call this directly in physx only
6833 if (!HandleInfo->KinActorData2.IsValid())
6834 {
6835 return;
6836 }
6837#endif
6838
6839 // Don't call moveKinematic if it hasn't changed - that will stop bodies from going to sleep.
6840//#if PHYSICS_INTERFACE_PHYSX
6841 if (!HandleInfo->LastPhysicsTransform.EqualsNoScale(NewTransform))
6842//#endif
6843 {
6844 HandleInfo->LastPhysicsTransform = NewTransform;
6845 HandleInfo->LastPhysicsTransform.SetScale3D(FVector(1.0f));
6846 FPhysicsActorHandle ActorHandle = HandleInfo->KinActorData2;
6847 FTransform newTrans = HandleInfo->COMPosition * (HandleInfo->RootBoneRotation * HandleInfo->LastPhysicsTransform);
6848 FPhysicsCommand::ExecuteWrite(ActorHandle, [&](const FPhysicsActorHandle & Actor)
6849 {
6850 FPhysicsInterface::SetKinematicTarget_AssumesLocked(Actor, newTrans);
6851 });
6852 }
6853
6854 // Debug draw for COM movement with physics grips
6855#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
6857 {
6858 UPrimitiveComponent* me = Cast<UPrimitiveComponent>(GrippedActor.GripTargetType == EGripTargetType::ActorGrip ? GrippedActor.GetGrippedActor()->GetRootComponent() : GrippedActor.GetGrippedComponent());
6859 FVector curCOMPosition = me->GetBodyInstance(GrippedActor.GrippedBoneName)->GetCOMPosition();
6860 DrawDebugSphere(GetWorld(), curCOMPosition, 4, 32, FColor::Red, false);
6861 FTransform TargetTransform = (HandleInfo->COMPosition * (HandleInfo->RootBoneRotation * HandleInfo->LastPhysicsTransform));
6862 DrawDebugSphere(GetWorld(), TargetTransform.GetLocation(), 4, 32, FColor::Cyan, false);
6863 DrawDebugLine(GetWorld(), TargetTransform.GetTranslation(), TargetTransform.GetTranslation() + (TargetTransform.GetRotation().GetForwardVector() * 20.f), FColor::Red);
6864 DrawDebugLine(GetWorld(), TargetTransform.GetTranslation(), TargetTransform.GetTranslation() + (TargetTransform.GetRotation().GetRightVector() * 20.f), FColor::Green);
6865 DrawDebugLine(GetWorld(), TargetTransform.GetTranslation(), TargetTransform.GetTranslation() + (TargetTransform.GetRotation().GetUpVector() * 20.f), FColor::Blue);
6866 }
6867#endif
6868
6869}
6870
6871static void PullBackHitComp(FHitResult& Hit, const FVector& Start, const FVector& End, const float Dist)
6872{
6873 const float DesiredTimeBack = FMath::Clamp(0.1f, 0.1f / Dist, 1.f / Dist) + 0.001f;
6874 Hit.Time = FMath::Clamp(Hit.Time - DesiredTimeBack, 0.f, 1.f);
6875}
6876
6877bool UGripMotionControllerComponent::CheckComponentWithSweep(UPrimitiveComponent * ComponentToCheck, FVector Move, FRotator newOrientation, bool bSkipSimulatingComponents/*, bool &bHadBlockingHitOut*/)
6878{
6879 TArray<FHitResult> Hits;
6880 // WARNING: HitResult is only partially initialized in some paths. All data is valid only if bFilledHitResult is true.
6881 FHitResult BlockingHit(NoInit);
6882 BlockingHit.bBlockingHit = false;
6883 BlockingHit.Time = 1.f;
6884 bool bFilledHitResult = false;
6885 bool bMoved = false;
6886 bool bIncludesOverlapsAtEnd = false;
6887 bool bRotationOnly = false;
6888
6889 UPrimitiveComponent *root = ComponentToCheck;
6890
6891 if (!root || !root->IsQueryCollisionEnabled())
6892 return false;
6893
6894 FVector start(root->GetComponentLocation());
6895
6896 const bool bCollisionEnabled = root->IsQueryCollisionEnabled();
6897
6898 if (bCollisionEnabled)
6899 {
6900#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
6901 if (!root->IsRegistered())
6902 {
6903 UE_LOG(LogVRMotionController, Warning, TEXT("MovedComponent %s not initialized in grip motion controller"), *root->GetFullName());
6904 }
6905#endif
6906
6907 UWorld* const MyWorld = GetWorld();
6908 FComponentQueryParams Params(TEXT("sweep_params"), root->GetOwner());
6909
6910 FCollisionResponseParams ResponseParam;
6911 root->InitSweepCollisionParams(Params, ResponseParam);
6912
6913 FVector end = start + Move;
6914 bool const bHadBlockingHit = MyWorld->ComponentSweepMulti(Hits, root, start, end, newOrientation.Quaternion(), Params);
6915
6916 if (Hits.Num() > 0)
6917 {
6918 const float DeltaSize = FVector::Dist(start, end);
6919 for (int32 HitIdx = 0; HitIdx < Hits.Num(); HitIdx++)
6920 {
6921 PullBackHitComp(Hits[HitIdx], start, end, DeltaSize);
6922 }
6923 }
6924
6925 if (bHadBlockingHit)
6926 {
6927 int32 BlockingHitIndex = INDEX_NONE;
6928 float BlockingHitNormalDotDelta = BIG_NUMBER;
6929 for (int32 HitIdx = 0; HitIdx < Hits.Num(); HitIdx++)
6930 {
6931 const FHitResult& TestHit = Hits[HitIdx];
6932
6933 // Ignore the owning actor to the motion controller
6934 if (TestHit.Actor == this->GetOwner() || (bSkipSimulatingComponents && TestHit.Component->IsSimulatingPhysics()))
6935 {
6936 if (Hits.Num() == 1)
6937 {
6938 //bHadBlockingHitOut = false;
6939 return false;
6940 }
6941 else
6942 continue;
6943 }
6944
6945 if (TestHit.bBlockingHit && TestHit.IsValidBlockingHit())
6946 {
6947 if (TestHit.Time == 0.f)
6948 {
6949 // We may have multiple initial hits, and want to choose the one with the normal most opposed to our movement.
6950 const float NormalDotDelta = (TestHit.ImpactNormal | Move);
6951 if (NormalDotDelta < BlockingHitNormalDotDelta)
6952 {
6953 BlockingHitNormalDotDelta = NormalDotDelta;
6954 BlockingHitIndex = HitIdx;
6955 }
6956 }
6957 else if (BlockingHitIndex == INDEX_NONE)
6958 {
6959 // First non-overlapping blocking hit should be used, if an overlapping hit was not.
6960 // This should be the only non-overlapping blocking hit, and last in the results.
6961 BlockingHitIndex = HitIdx;
6962 break;
6963 }
6964 //}
6965 }
6966 }
6967
6968 // Update blocking hit, if there was a valid one.
6969 if (BlockingHitIndex >= 0)
6970 {
6971 BlockingHit = Hits[BlockingHitIndex];
6972 bFilledHitResult = true;
6973 }
6974 }
6975 }
6976
6977 // Handle blocking hit notifications. Avoid if pending kill (which could happen after overlaps).
6978 if (BlockingHit.bBlockingHit && !root->IsPendingKill())
6979 {
6980 check(bFilledHitResult);
6981 if (root->IsDeferringMovementUpdates())
6982 {
6983 FScopedMovementUpdate* ScopedUpdate = root->GetCurrentScopedMovement();
6984 ScopedUpdate->AppendBlockingHitAfterMove(BlockingHit);
6985 }
6986 else
6987 {
6988
6989 if(root->GetOwner())
6990 root->DispatchBlockingHit(*root->GetOwner(), BlockingHit);
6991 }
6992
6993 return true;
6994 }
6995
6996 return false;
6997}
6998
7003
7004void UGripMotionControllerComponent::ApplyTrackingParameters(FVector& OriginalPosition, bool bIsInGameThread)
7005{
7006 if (bScaleTracking)
7007 {
7008 OriginalPosition *= TrackingScaler;
7009 }
7010
7011 if (bLimitMinHeight)
7012 {
7013 OriginalPosition.Z = FMath::Max(OriginalPosition.Z, MinimumHeight);
7014 }
7015
7016 if (bLimitMaxHeight)
7017 {
7018 OriginalPosition.Z = FMath::Min(OriginalPosition.Z, MaximumHeight);
7019 }
7020
7022 {
7023 if (bIsInGameThread)
7024 {
7025 if (IsLocallyControlled() && GEngine->XRSystem.IsValid() && GEngine->XRSystem->IsHeadTrackingAllowedForWorld(*GetWorld()))
7026 {
7027 FQuat curRot;
7028 FVector curLoc;
7029 if (GEngine->XRSystem->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, curRot, curLoc))
7030 {
7031
7032 if (AttachChar.IsValid() && AttachChar->VRReplicatedCamera)
7033 {
7034 AttachChar->VRReplicatedCamera->ApplyTrackingParameters(curLoc);
7035 }
7036
7037 //curLoc.Z = 0;
7039 }
7040 }
7041 else
7042 {
7043 if (AttachChar.IsValid() && AttachChar->VRReplicatedCamera)
7044 {
7045 // Sample camera location instead
7046 LastLocationForLateUpdate = AttachChar->VRReplicatedCamera->GetRelativeLocation();
7047 }
7048 }
7049 }
7050
7051 // #TODO: This is technically unsafe, need to use a seperate value like the transforms for the render thread
7052 // If I ever delete the simple char then this setup can just go away anyway though
7053 // It has a data race condition right now though
7054 FVector CorrectLastLocation = bIsInGameThread ? LastLocationForLateUpdate : LateUpdateParams.GripRenderThreadLastLocationForLateUpdate;
7055
7056 if (bOffsetByHMD)
7057 {
7058 OriginalPosition -= FVector(CorrectLastLocation.X, CorrectLastLocation.Y, 0.0f);
7059 }
7060
7061 if (bLeashToHMD)
7062 {
7063 FVector DifferenceVec = bOffsetByHMD ? OriginalPosition : (OriginalPosition - CorrectLastLocation);
7064
7065 if (DifferenceVec.SizeSquared() > FMath::Square(LeashRange))
7066 {
7067 OriginalPosition = CorrectLastLocation + (DifferenceVec.GetSafeNormal() * LeashRange);
7068 }
7069 }
7070 }
7071}
7072
7073//=============================================================================
7074bool UGripMotionControllerComponent::GripPollControllerState(FVector& Position, FRotator& Orientation , float WorldToMetersScale)
7075{
7076 // Not calling PollControllerState from the parent because its private.......
7077
7078 bool bIsInGameThread = IsInGameThread();
7079
7080 if (bHasAuthority)
7081 {
7082 // New iteration and retrieval for 4.12
7083 TArray<IMotionController*> MotionControllers = IModularFeatures::Get().GetModularFeatureImplementations<IMotionController>(IMotionController::GetModularFeatureName());
7084 for (auto MotionController : MotionControllers)
7085 {
7086 if (MotionController == nullptr)
7087 {
7088 continue;
7089 }
7090
7091#if !PLATFORM_PS4
7092 if (bIsInGameThread)
7093 {
7094 CurrentTrackingStatus = MotionController->GetControllerTrackingStatus(PlayerIndex, MotionSource);
7095 if (!bIgnoreTrackingStatus && CurrentTrackingStatus == ETrackingStatus::NotTracked)
7096 continue;
7097 }
7098#endif
7099
7100 if (MotionController->GetControllerOrientationAndPosition(PlayerIndex, MotionSource, Orientation, Position, WorldToMetersScale))
7101 {
7102#if PLATFORM_PS4
7103 // Moving this in here to work around a PSVR module bug
7104 if (bIsInGameThread)
7105 {
7106 CurrentTrackingStatus = MotionController->GetControllerTrackingStatus(PlayerIndex, MotionSource);
7107 if (!bIgnoreTrackingStatus && CurrentTrackingStatus == ETrackingStatus::NotTracked)
7108 continue;
7109 }
7110#endif
7111
7113 {
7114 ApplyTrackingParameters(Position, bIsInGameThread);
7115 }
7116
7118 {
7119 FTransform FinalControllerTransform(Orientation,Position);
7120 if (bIsInGameThread)
7121 {
7122 FinalControllerTransform = CurrentControllerProfileTransform * FinalControllerTransform;
7123 }
7124 else
7125 {
7126 FinalControllerTransform = LateUpdateParams.GripRenderThreadProfileTransform * FinalControllerTransform;
7127 }
7128
7129 Orientation = FinalControllerTransform.Rotator();
7130 Position = FinalControllerTransform.GetTranslation();
7131 }
7132
7133 // Render thread also calls this, shouldn't be flagging this event in the render thread.
7134 if (bIsInGameThread)
7135 {
7136 InUseMotionController = MotionController;
7137 OnMotionControllerUpdated();
7138 InUseMotionController = nullptr;
7139 }
7140
7141 return true;
7142 }
7143#if PLATFORM_PS4
7144 else if (bIsInGameThread)
7145 {
7146 CurrentTrackingStatus = MotionController->GetControllerTrackingStatus(PlayerIndex, MotionSource);
7147 }
7148#endif
7149 }
7150
7151 // #NOTE: This was adding in 4.20, I presume to allow for HMDs as tracking sources for mixed reality.
7152 // Skipping all of my special logic here for now
7153 if (MotionSource == FXRMotionControllerBase::HMDSourceId)
7154 {
7155 IXRTrackingSystem* TrackingSys = GEngine->XRSystem.Get();
7156 if (TrackingSys)
7157 {
7158 FQuat OrientationQuat = FQuat::Identity;
7159 if (TrackingSys->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, OrientationQuat, Position))
7160 {
7161 Orientation = OrientationQuat.Rotator();
7162 return true;
7163 }
7164 }
7165 }
7166 }
7167 return false;
7168}
7169
7170//=============================================================================
7172 : FSceneViewExtensionBase(AutoRegister)
7173 , MotionControllerComponent(InMotionControllerComponent)
7174{
7175 FSceneViewExtensionIsActiveFunctor IsActiveFunc;
7176 IsActiveFunc.IsActiveFunction = [this](const ISceneViewExtension* SceneViewExtension, const FSceneViewExtensionContext& Context)
7177 {
7178 check(IsInGameThread());
7179
7180 static const auto CVarEnableMotionControllerLateUpdate = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("vr.EnableMotionControllerLateUpdate"));
7181 return MotionControllerComponent && !MotionControllerComponent->bDisableLowLatencyUpdate && MotionControllerComponent->bTracked && CVarEnableMotionControllerLateUpdate->GetValueOnGameThread();
7182 };
7183
7184 IsActiveThisFrameFunctions.Add(IsActiveFunc);
7185}
7186
7187
7188void UGripMotionControllerComponent::FGripViewExtension::PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily)
7189{
7190 FTransform OldTransform;
7191 FTransform NewTransform;
7192
7193 {
7194 FScopeLock ScopeLock(&CritSect);
7195
7196 if (!MotionControllerComponent)
7197 return;
7198
7199 // Find a view that is associated with this player.
7200 float WorldToMetersScale = -1.0f;
7201 for (const FSceneView* SceneView : InViewFamily.Views)
7202 {
7203 if (SceneView && SceneView->PlayerIndex == MotionControllerComponent->PlayerIndex)
7204 {
7205 WorldToMetersScale = SceneView->WorldToMetersScale;
7206 break;
7207 }
7208 }
7209
7210 // If there are no views associated with this player use view 0.
7211 if (WorldToMetersScale < 0.0f)
7212 {
7213 check(InViewFamily.Views.Num() > 0);
7214 WorldToMetersScale = InViewFamily.Views[0]->WorldToMetersScale;
7215 }
7216
7217 // Poll state for the most recent controller transform
7218 FVector Position = MotionControllerComponent->LateUpdateParams.GripRenderThreadRelativeTransform.GetTranslation();
7219 FRotator Orientation = MotionControllerComponent->LateUpdateParams.GripRenderThreadRelativeTransform.GetRotation().Rotator();
7220
7221 if (!MotionControllerComponent->GripPollControllerState(Position, Orientation, WorldToMetersScale))
7222 {
7223 return;
7224 }
7225
7226 if (MotionControllerComponent->LateUpdateParams.bRenderSmoothHandTracking)
7227 {
7228 FTransform CalcedTransform = FTransform(Orientation, Position, MotionControllerComponent->LateUpdateParams.GripRenderThreadComponentScale);
7229
7230 if (MotionControllerComponent->LateUpdateParams.bRenderSmoothWithEuroLowPassFunction)
7231 {
7232 CalcedTransform = MotionControllerComponent->LateUpdateParams.RenderEuroSmoothingParams.RunFilterSmoothing(CalcedTransform, MotionControllerComponent->LateUpdateParams.RenderLastDeltaTime);
7233 //SetRelativeTransform(RenderEuroSmoothingParams.RunFilterSmoothing(CalcedTransform, RenderLastDeltaTime));
7234 }
7235 else
7236 {
7237 if (MotionControllerComponent->LateUpdateParams.RenderSmoothingSpeed <= 0.f || MotionControllerComponent->LateUpdateParams.RenderLastSmoothRelativeTransform.Equals(FTransform::Identity))
7238 {
7239 //SetRelativeTransform(CalcedTransform);
7240 }
7241 else
7242 {
7243 const float Alpha = FMath::Clamp(MotionControllerComponent->LateUpdateParams.RenderLastDeltaTime * MotionControllerComponent->LateUpdateParams.RenderSmoothingSpeed, 0.f, 1.f);
7244 MotionControllerComponent->LateUpdateParams.RenderLastSmoothRelativeTransform.Blend(MotionControllerComponent->LateUpdateParams.RenderLastSmoothRelativeTransform, CalcedTransform, Alpha);
7245 CalcedTransform = MotionControllerComponent->LateUpdateParams.RenderLastSmoothRelativeTransform;
7246 //SetRelativeTransform(LastSmoothRelativeTransform);
7247 }
7248 }
7249
7250 // Set smoothed properties
7251 NewTransform = CalcedTransform;
7252 }
7253 else
7254 {
7255 NewTransform = FTransform(Orientation, Position, MotionControllerComponent->LateUpdateParams.GripRenderThreadComponentScale);
7256 }
7257
7258 OldTransform = MotionControllerComponent->LateUpdateParams.GripRenderThreadRelativeTransform;
7259 //NewTransform = FTransform(Orientation, Position, MotionControllerComponent->GripRenderThreadComponentScale);
7260 MotionControllerComponent->LateUpdateParams.GripRenderThreadRelativeTransform = NewTransform;
7261 } // Release lock on motion controller component
7262
7263 // Tell the late update manager to apply the offset to the scene components
7264 LateUpdate.Apply_RenderThread(InViewFamily.Scene, InViewFamily.bLateLatchingEnabled ? InViewFamily.FrameNumber : -1, OldTransform, NewTransform);
7265}
7266
7267void UGripMotionControllerComponent::FGripViewExtension::LateLatchingViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily)
7268{
7269 SCOPED_NAMED_EVENT(UMotionControllerComponent_Latch, FColor::Orange);
7270 if (!MotionControllerComponent)
7271 {
7272 return;
7273 }
7274
7275 FTransform OldTransform;
7276 FTransform NewTransform;
7277 {
7278 FScopeLock ScopeLock(&CritSect);
7279 if (!MotionControllerComponent)
7280 {
7281 return;
7282 }
7283
7284 // Find a view that is associated with this player.
7285 float WorldToMetersScale = -1.0f;
7286 for (const FSceneView* SceneView : InViewFamily.Views)
7287 {
7288 if (SceneView && SceneView->PlayerIndex == MotionControllerComponent->PlayerIndex)
7289 {
7290 WorldToMetersScale = SceneView->WorldToMetersScale;
7291 break;
7292 }
7293 }
7294 // If there are no views associated with this player use view 0.
7295 if (WorldToMetersScale < 0.0f)
7296 {
7297 check(InViewFamily.Views.Num() > 0);
7298 WorldToMetersScale = InViewFamily.Views[0]->WorldToMetersScale;
7299 }
7300
7301 // Poll state for the most recent controller transform
7302 FVector Position;
7303 FRotator Orientation;
7304
7305 if (!MotionControllerComponent->GripPollControllerState(Position, Orientation, WorldToMetersScale))
7306 {
7307 return;
7308 }
7309
7310 if (MotionControllerComponent->LateUpdateParams.bRenderSmoothHandTracking)
7311 {
7312 FTransform CalcedTransform = FTransform(Orientation, Position, MotionControllerComponent->LateUpdateParams.GripRenderThreadComponentScale);
7313
7314 if (MotionControllerComponent->LateUpdateParams.bRenderSmoothWithEuroLowPassFunction)
7315 {
7316 CalcedTransform = MotionControllerComponent->LateUpdateParams.RenderEuroSmoothingParams.RunFilterSmoothing(CalcedTransform, MotionControllerComponent->LateUpdateParams.RenderLastDeltaTime);
7317 //SetRelativeTransform(RenderEuroSmoothingParams.RunFilterSmoothing(CalcedTransform, RenderLastDeltaTime));
7318 }
7319 else
7320 {
7321 if (MotionControllerComponent->LateUpdateParams.RenderSmoothingSpeed <= 0.f || MotionControllerComponent->LateUpdateParams.RenderLastSmoothRelativeTransform.Equals(FTransform::Identity))
7322 {
7323 //SetRelativeTransform(CalcedTransform);
7324 }
7325 else
7326 {
7327 const float Alpha = FMath::Clamp(MotionControllerComponent->LateUpdateParams.RenderLastDeltaTime * MotionControllerComponent->LateUpdateParams.RenderSmoothingSpeed, 0.f, 1.f);
7328 MotionControllerComponent->LateUpdateParams.RenderLastSmoothRelativeTransform.Blend(MotionControllerComponent->LateUpdateParams.RenderLastSmoothRelativeTransform, CalcedTransform, Alpha);
7329 CalcedTransform = MotionControllerComponent->LateUpdateParams.RenderLastSmoothRelativeTransform;
7330 //SetRelativeTransform(LastSmoothRelativeTransform);
7331 }
7332 }
7333
7334 // Set smoothed properties
7335 NewTransform = CalcedTransform;
7336 }
7337 else
7338 {
7339 NewTransform = FTransform(Orientation, Position, MotionControllerComponent->LateUpdateParams.GripRenderThreadComponentScale);
7340 }
7341
7342 OldTransform = MotionControllerComponent->LateUpdateParams.GripRenderThreadRelativeTransform;
7343 //NewTransform = FTransform(Orientation, Position, MotionControllerComponent->GripRenderThreadComponentScale);
7344 MotionControllerComponent->LateUpdateParams.GripRenderThreadRelativeTransform = NewTransform;
7345
7346 } // Release the lock on the MotionControllerComponent
7347
7348 // Tell the late update manager to apply the offset to the scene components
7349 LateUpdate.Apply_RenderThread(InViewFamily.Scene, InViewFamily.FrameNumber, OldTransform, NewTransform);
7350}
7351
7353{
7355
7356 if (FirstGrip)
7357 {
7358 FirstActiveGrip = *FirstGrip;
7359 return true;
7360 }
7361
7362 return false;
7363}
7364
7366{
7368 {
7369 if (Grip.IsValid() && !Grip.bIsPaused)
7370 {
7371 return &Grip;
7372 }
7373 }
7374
7376 {
7377 if (LocalGrip.IsValid() && !LocalGrip.bIsPaused)
7378 {
7379 return &LocalGrip;
7380 }
7381 }
7382
7383 return nullptr;
7384}
7385
7386void UGripMotionControllerComponent::GetAllGrips(TArray<FBPActorGripInformation> &GripArray)
7387{
7388 GripArray.Append(GrippedObjects);
7389 GripArray.Append(LocallyGrippedObjects);
7390}
7391
7392void UGripMotionControllerComponent::GetGrippedObjects(TArray<UObject*> &GrippedObjectsArray)
7393{
7394 for (int i = 0; i < GrippedObjects.Num(); ++i)
7395 {
7396 if (GrippedObjects[i].GrippedObject)
7397 GrippedObjectsArray.Add(GrippedObjects[i].GrippedObject);
7398 }
7399
7400 for (int i = 0; i < LocallyGrippedObjects.Num(); ++i)
7401 {
7402 if (LocallyGrippedObjects[i].GrippedObject)
7403 GrippedObjectsArray.Add(LocallyGrippedObjects[i].GrippedObject);
7404 }
7405
7406}
7407
7408void UGripMotionControllerComponent::GetGrippedActors(TArray<AActor*> &GrippedObjectsArray)
7409{
7410 for (int i = 0; i < GrippedObjects.Num(); ++i)
7411 {
7412 if(GrippedObjects[i].GetGrippedActor())
7413 GrippedObjectsArray.Add(GrippedObjects[i].GetGrippedActor());
7414 }
7415
7416 for (int i = 0; i < LocallyGrippedObjects.Num(); ++i)
7417 {
7418 if (LocallyGrippedObjects[i].GetGrippedActor())
7419 GrippedObjectsArray.Add(LocallyGrippedObjects[i].GetGrippedActor());
7420 }
7421
7422}
7423
7424void UGripMotionControllerComponent::GetGrippedComponents(TArray<UPrimitiveComponent*> &GrippedComponentsArray)
7425{
7426 for (int i = 0; i < GrippedObjects.Num(); ++i)
7427 {
7428 if (GrippedObjects[i].GetGrippedComponent())
7429 GrippedComponentsArray.Add(GrippedObjects[i].GetGrippedComponent());
7430 }
7431
7432 for (int i = 0; i < LocallyGrippedObjects.Num(); ++i)
7433 {
7434 if (LocallyGrippedObjects[i].GetGrippedComponent())
7435 GrippedComponentsArray.Add(LocallyGrippedObjects[i].GetGrippedComponent());
7436 }
7437}
7438
7439// Locally gripped functions
7440void UGripMotionControllerComponent::Client_NotifyInvalidLocalGrip_Implementation(UObject * LocallyGrippedObject, uint8 GripID, bool bWasAGripConflict)
7441{
7442 if (GripID != INVALID_VRGRIP_ID)
7443 {
7444 if (FBPActorGripInformation* GripInfo = GetGripPtrByID(GripID))
7445 {
7446 DropObjectByInterface(nullptr, GripID);
7447
7448 if (LocallyGrippedObject && bWasAGripConflict)
7449 {
7450 OnClientAuthGripConflict.Broadcast(LocallyGrippedObject, ClientAuthConflictResolutionMethod);
7451 }
7452 return;
7453 }
7454 }
7455
7456 FBPActorGripInformation FoundGrip;
7457 EBPVRResultSwitch Result;
7458
7459 GetGripByObject(FoundGrip, LocallyGrippedObject, Result);
7460
7461 if (Result == EBPVRResultSwitch::OnFailed)
7462 return;
7463
7464 // Drop it, server told us that it was a bad grip
7465 DropObjectByInterface(nullptr, FoundGrip.GripID);
7466
7467 if (LocallyGrippedObject && bWasAGripConflict)
7468 {
7469 OnClientAuthGripConflict.Broadcast(LocallyGrippedObject, ClientAuthConflictResolutionMethod);
7470 }
7471}
7472
7473bool UGripMotionControllerComponent::Server_NotifyHandledTransaction_Validate(uint8 GripID)
7474{
7475 return true;
7476}
7477
7478void UGripMotionControllerComponent::Server_NotifyHandledTransaction_Implementation(uint8 GripID)
7479{
7480 for (int i = LocalTransactionBuffer.Num() - 1; i >= 0; i--)
7481 {
7482 if(LocalTransactionBuffer[i].GripID == GripID)
7483 LocalTransactionBuffer.RemoveAt(i);
7484 }
7485}
7486
7487bool UGripMotionControllerComponent::Server_NotifyLocalGripAddedOrChanged_Validate(const FBPActorGripInformation & newGrip)
7488{
7489 return true;
7490}
7491
7492void UGripMotionControllerComponent::Server_NotifyLocalGripAddedOrChanged_Implementation(const FBPActorGripInformation & newGrip)
7493{
7495 {
7497 return;
7498 }
7499
7500 if (!LocallyGrippedObjects.Contains(newGrip))
7501 {
7502 bool bImplementsInterface = newGrip.GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass());
7503
7504 TArray<FBPGripPair> HoldingControllers;
7505 bool bIsHeld = false;
7506 if (bImplementsInterface)
7507 {
7508 IVRGripInterface::Execute_IsHeld(newGrip.GrippedObject, HoldingControllers, bIsHeld);
7509
7511 {
7512 // Its held and doesn't allow more than one grip at a time
7513 if (!IVRGripInterface::Execute_AllowsMultipleGrips(newGrip.GrippedObject))
7514 {
7515 // Lets see if a different owner is holding it, if so, deny this request
7516 for (FBPGripPair& GripPair : HoldingControllers)
7517 {
7518 if (!GripPair.HoldingController || GripPair.GripID == INVALID_VRGRIP_ID)
7519 {
7520 continue;
7521 }
7522
7523 // If the controllers have different owners (if its the same then consider them as locally transacting and let it go)
7524 if (GripPair.HoldingController->GetOwner()->GetNetOwner() != this->GetOwner()->GetNetOwner())
7525 {
7527 {
7529 {
7530 // Deny the grip, another connection already came and gripped it
7531 Client_NotifyInvalidLocalGrip(newGrip.GrippedObject, newGrip.GripID, true);
7532
7534 return;
7535 }break;
7537 {
7538 // Deny the old grip, another connection came and gripped it
7539 GripPair.HoldingController->DropObjectByInterface(newGrip.GrippedObject, GripPair.GripID);
7540 GripPair.HoldingController->Client_NotifyInvalidLocalGrip(newGrip.GrippedObject, GripPair.GripID, true);
7542 return;
7543 }break;
7545 {
7546 // Deny both grips
7547 Client_NotifyInvalidLocalGrip(newGrip.GrippedObject, newGrip.GripID, true);
7548 GripPair.HoldingController->DropObjectByInterface(newGrip.GrippedObject, GripPair.GripID);
7549 GripPair.HoldingController->Client_NotifyInvalidLocalGrip(newGrip.GrippedObject, GripPair.GripID, true);
7551 return;
7552 }break;
7554 default:
7555 {
7557 }break;
7558
7559 }
7560 }
7561 }
7562 }
7563 }
7564 }
7565
7566 UPrimitiveComponent* PrimComp = nullptr;
7567 AActor* pActor = nullptr;
7568
7569 PrimComp = newGrip.GetGrippedComponent();
7570 pActor = newGrip.GetGrippedActor();
7571
7572 if (!PrimComp && pActor)
7573 {
7574 PrimComp = Cast<UPrimitiveComponent>(pActor->GetRootComponent());
7575 }
7576 else if (!pActor && PrimComp)
7577 {
7578 pActor = PrimComp->GetOwner();
7579 }
7580
7581 if (!PrimComp || !pActor)
7582 {
7584 return;
7585 }
7586
7587 bool bHadOriginalSettings = false;
7588 bool bOriginalGravity = false;
7589 bool bOriginalReplication = false;
7590
7591 if (bImplementsInterface)
7592 {
7593 //if (IVRGripInterface::Execute_DenyGripping(root))
7594 // return false; // Interface is saying not to grip it right now
7595 if (bIsHeld)
7596 {
7597 // If we are held by multiple controllers then lets copy our original values from the first one
7598 if (HoldingControllers.Num() > 0 && HoldingControllers[0].HoldingController != nullptr)
7599 {
7600 FBPActorGripInformation* gripInfo = HoldingControllers[0].HoldingController->GetGripPtrByID(HoldingControllers[0].GripID);
7601
7602 if (gripInfo != nullptr)
7603 {
7604 bHadOriginalSettings = true;
7605 bOriginalGravity = gripInfo->bOriginalGravity;
7606 bOriginalReplication = gripInfo->bOriginalReplicatesMovement;
7607 }
7608 }
7609 }
7610 }
7611
7612 int32 NewIndex = LocallyGrippedObjects.Add(newGrip);
7613
7614 if (NewIndex != INDEX_NONE && LocallyGrippedObjects.Num() > 0)
7615 {
7616 if (bHadOriginalSettings)
7617 {
7618 LocallyGrippedObjects[NewIndex].bOriginalReplicatesMovement = bOriginalReplication;
7619 LocallyGrippedObjects[NewIndex].bOriginalGravity = bOriginalGravity;
7620 }
7621 else
7622 {
7623 LocallyGrippedObjects[NewIndex].bOriginalReplicatesMovement = pActor->IsReplicatingMovement();
7624 LocallyGrippedObjects[NewIndex].bOriginalGravity = PrimComp->IsGravityEnabled();
7625 }
7626
7628 }
7629
7630 // Initialize the differences, clients will do this themselves on the rep back, this sets up the cache
7631 //HandleGripReplication(LocallyGrippedObjects[LocallyGrippedObjects.Num() - 1]);
7632 }
7633 else
7634 {
7635 int32 IndexFound = INDEX_NONE;
7636 if (LocallyGrippedObjects.Find(newGrip, IndexFound) && IndexFound != INDEX_NONE)
7637 {
7638 FBPActorGripInformation OriginalGrip = LocallyGrippedObjects[IndexFound];
7639 LocallyGrippedObjects[IndexFound].RepCopy(newGrip);
7640 HandleGripReplication(LocallyGrippedObjects[IndexFound], &OriginalGrip);
7641 }
7642 }
7643
7644 // Server has to call this themselves
7645 //OnRep_LocallyGrippedObjects();
7646}
7647
7648
7649bool UGripMotionControllerComponent::Server_NotifyLocalGripRemoved_Validate(uint8 GripID, const FTransform_NetQuantize &TransformAtDrop, FVector_NetQuantize100 AngularVelocity, FVector_NetQuantize100 LinearVelocity)
7650{
7651 return true;
7652}
7653
7654void UGripMotionControllerComponent::Server_NotifyLocalGripRemoved_Implementation(uint8 GripID, const FTransform_NetQuantize &TransformAtDrop, FVector_NetQuantize100 AngularVelocity, FVector_NetQuantize100 LinearVelocity)
7655{
7656 FBPActorGripInformation FoundGrip;
7657 EBPVRResultSwitch Result;
7658 GetGripByID(FoundGrip, GripID, Result);
7659
7660 if (Result == EBPVRResultSwitch::OnFailed)
7661 return;
7662
7664 {
7665 switch (FoundGrip.GripTargetType)
7666 {
7668 {
7669 if (AActor* DroppingActor = FoundGrip.GetGrippedActor())
7670 {
7671 if (!DroppingActor->IsPendingKill() && TransformAtDrop.IsValid())
7672 {
7673 DroppingActor->SetActorTransform(TransformAtDrop, false, nullptr, ETeleportType::TeleportPhysics);
7674 }
7675 }
7676 }break;
7678 {
7679 if (UPrimitiveComponent* DroppingComp = FoundGrip.GetGrippedComponent())
7680 {
7681 if (!DroppingComp->IsPendingKill() && TransformAtDrop.IsValid())
7682 {
7683 DroppingComp->SetWorldTransform(TransformAtDrop, false, nullptr, ETeleportType::TeleportPhysics);
7684 }
7685 }
7686 }break;
7687 default:break;
7688 }
7689 }
7690
7691 if (!DropObjectByInterface(nullptr, FoundGrip.GripID, AngularVelocity, LinearVelocity))
7692 {
7693 DropGrip_Implementation(FoundGrip, false, AngularVelocity, LinearVelocity);
7694 }
7695}
7696
7697
7698bool UGripMotionControllerComponent::Server_NotifySecondaryAttachmentChanged_Validate(
7699 uint8 GripID,
7700 const FBPSecondaryGripInfo& SecondaryGripInfo)
7701{
7702 return true;
7703}
7704
7705void UGripMotionControllerComponent::Server_NotifySecondaryAttachmentChanged_Implementation(
7706 uint8 GripID,
7707 const FBPSecondaryGripInfo& SecondaryGripInfo)
7708{
7709
7710 FBPActorGripInformation * GripInfo = LocallyGrippedObjects.FindByKey(GripID);
7711 if (GripInfo != nullptr)
7712 {
7713 FBPActorGripInformation OriginalGrip = *GripInfo;
7714
7715 // I override the = operator now so that it won't set the lerp components
7716 GripInfo->SecondaryGripInfo.RepCopy(SecondaryGripInfo);
7717
7718 // Initialize the differences, clients will do this themselves on the rep back
7719 HandleGripReplication(*GripInfo, &OriginalGrip);
7720 }
7721
7722}
7723
7724bool UGripMotionControllerComponent::Server_NotifySecondaryAttachmentChanged_Retain_Validate(
7725 uint8 GripID,
7726 const FBPSecondaryGripInfo& SecondaryGripInfo, const FTransform_NetQuantize & NewRelativeTransform)
7727{
7728 return true;
7729}
7730
7731void UGripMotionControllerComponent::Server_NotifySecondaryAttachmentChanged_Retain_Implementation(
7732 uint8 GripID,
7733 const FBPSecondaryGripInfo& SecondaryGripInfo, const FTransform_NetQuantize & NewRelativeTransform)
7734{
7735
7736 FBPActorGripInformation * GripInfo = LocallyGrippedObjects.FindByKey(GripID);
7737 if (GripInfo != nullptr)
7738 {
7739 FBPActorGripInformation OriginalGrip = *GripInfo;
7740
7741 // I override the = operator now so that it won't set the lerp components
7742 GripInfo->SecondaryGripInfo.RepCopy(SecondaryGripInfo);
7743 GripInfo->RelativeTransform = NewRelativeTransform;
7744
7745 // Initialize the differences, clients will do this themselves on the rep back
7746 HandleGripReplication(*GripInfo, &OriginalGrip);
7747 }
7748
7749}
7750void UGripMotionControllerComponent::GetControllerDeviceID(FXRDeviceId & DeviceID, EBPVRResultSwitch &Result, bool bCheckOpenVROnly)
7751{
7752 EControllerHand ControllerHandIndex;
7753 if (!FXRMotionControllerBase::GetHandEnumForSourceName(MotionSource, ControllerHandIndex))
7754 {
7756 return;
7757 }
7758
7759 TArray<IXRSystemAssets*> XRAssetSystems = IModularFeatures::Get().GetModularFeatureImplementations<IXRSystemAssets>(IXRSystemAssets::GetModularFeatureName());
7760 for (IXRSystemAssets* AssetSys : XRAssetSystems)
7761 {
7762 if (bCheckOpenVROnly && !AssetSys->GetSystemName().IsEqual(FName(TEXT("SteamVR"))))
7763 continue;
7764
7765 const int32 XRID = AssetSys->GetDeviceId(ControllerHandIndex);
7766
7767 if (XRID != INDEX_NONE)
7768 {
7769 DeviceID = FXRDeviceId(AssetSys, XRID);
7771 return;
7772 }
7773 }
7774
7775 DeviceID = FXRDeviceId();
7777 return;
7778}
7779
7780
7781/*
7782*
7783* Custom late update manager implementation
7784*
7785*/
7786
7788 : LateUpdateGameWriteIndex(0)
7789 , LateUpdateRenderReadIndex(0)
7790{
7791}
7792
7793void FExpandedLateUpdateManager::Setup(const FTransform& ParentToWorld, UGripMotionControllerComponent* Component, bool bSkipLateUpdate)
7794{
7795 if (!Component)
7796 return;
7797
7798 check(IsInGameThread());
7799
7800
7803
7804 //Add additional late updates registered to this controller that aren't children and aren't gripped
7805 //This array is editable in blueprint and can be used for things like arms or the like.
7806 for (UPrimitiveComponent* primComp : Component->AdditionalLateUpdateComponents)
7807 {
7808 if (primComp)
7810 }
7811
7814
7815 GatherLateUpdatePrimitives(Component);
7816 //GatherLateUpdatePrimitives(Component);
7817
7818 UpdateStates[LateUpdateGameWriteIndex].bSkip = bSkipLateUpdate;
7820
7821 int32 NextFrameRenderReadIndex = LateUpdateGameWriteIndex;
7823
7824 ENQUEUE_RENDER_COMMAND(UpdateLateUpdateRenderReadIndexCommand)(
7825 [NextFrameRenderReadIndex, this](FRHICommandListImmediate& RHICmdList)
7826 {
7827 LateUpdateRenderReadIndex = NextFrameRenderReadIndex;
7828 });
7829
7830}
7831
7832void FExpandedLateUpdateManager::Apply_RenderThread(FSceneInterface* Scene, const int32 FrameNumber, const FTransform& OldRelativeTransform, const FTransform& NewRelativeTransform)
7833{
7834 check(IsInRenderingThread());
7835
7836
7838 {
7839 return;
7840 }
7841
7842 const FTransform OldCameraTransform = OldRelativeTransform * UpdateStates[LateUpdateRenderReadIndex].ParentToWorld;
7843 const FTransform NewCameraTransform = NewRelativeTransform * UpdateStates[LateUpdateRenderReadIndex].ParentToWorld;
7844 const FMatrix LateUpdateTransform = (OldCameraTransform.Inverse() * NewCameraTransform).ToMatrixWithScale();
7845
7846 bool bIndicesHaveChanged = false;
7847
7848
7849 // Under HMD late-latching senario, Apply_RenderThread will be called twice in same frame under PreRenderViewFamily_RenderThread and
7850 // LateLatchingViewFamily_RenderThread. We don't want to apply PrimitivePair.Value = -1 directly on UpdateStates[LateUpdateRenderReadIndex].Primitives
7851 // because the modification will affect second Apply_RenderThread's logic under LateLatchingViewFamily_RenderThread.
7852 // Since the list is very small(only affect stuff attaching to the controller), we just make a local copy PrimitivesLocal.
7853 TMap<FPrimitiveSceneInfo*, int32> PrimitivesLocal = UpdateStates[LateUpdateRenderReadIndex].Primitives;
7854 for (auto& PrimitivePair : PrimitivesLocal)
7855 {
7856 if (PrimitivePair.Value == -1)
7857 continue;
7858
7859 FPrimitiveSceneInfo* RetrievedSceneInfo = Scene->GetPrimitiveSceneInfo(PrimitivePair.Value);
7860 FPrimitiveSceneInfo* CachedSceneInfo = PrimitivePair.Key;
7861
7862 // If the retrieved scene info is different than our cached scene info then the scene has changed in the meantime
7863 // and we need to search through the entire scene to make sure it still exists.
7864 if (CachedSceneInfo != RetrievedSceneInfo)
7865 {
7866 bIndicesHaveChanged = true;
7867 break; // No need to continue here, as we are going to brute force the scene primitives below anyway.
7868 }
7869 else if (CachedSceneInfo->Proxy)
7870 {
7871 CachedSceneInfo->Proxy->ApplyLateUpdateTransform(LateUpdateTransform);
7872 PrimitivePair.Value = -1; // Set the cached index to -1 to indicate that this primitive was already processed
7873 if (FrameNumber >= 0)
7874 {
7875 CachedSceneInfo->Proxy->SetPatchingFrameNumber(FrameNumber);
7876 }
7877 }
7878 }
7879
7880 // Indices have changed, so we need to scan the entire scene for primitives that might still exist
7881 if (bIndicesHaveChanged)
7882 {
7883 int32 Index = 0;
7884 FPrimitiveSceneInfo* RetrievedSceneInfo = Scene->GetPrimitiveSceneInfo(Index++);
7885 while (RetrievedSceneInfo)
7886 {
7887
7888 int32* PrimitiveIndex = PrimitivesLocal.Find(RetrievedSceneInfo);
7889 if (RetrievedSceneInfo->Proxy && PrimitiveIndex != nullptr && *PrimitiveIndex >= 0)
7890 {
7891 RetrievedSceneInfo->Proxy->ApplyLateUpdateTransform(LateUpdateTransform);
7892 if (FrameNumber >= 0)
7893 {
7894 RetrievedSceneInfo->Proxy->SetPatchingFrameNumber(FrameNumber);
7895 }
7896 }
7897 RetrievedSceneInfo = Scene->GetPrimitiveSceneInfo(Index++);
7898 }
7899 }
7900}
7901
7903{
7904 ensureMsgf(!Component->IsUsingAbsoluteLocation() && !Component->IsUsingAbsoluteRotation(), TEXT("SceneComponents that use absolute location or rotation are not supported by the LateUpdateManager"));
7905 // If a scene proxy is present, cache it
7906 UPrimitiveComponent* PrimitiveComponent = dynamic_cast<UPrimitiveComponent*>(Component);
7907 if (PrimitiveComponent && PrimitiveComponent->SceneProxy)
7908 {
7909 FPrimitiveSceneInfo* PrimitiveSceneInfo = PrimitiveComponent->SceneProxy->GetPrimitiveSceneInfo();
7910 if (PrimitiveSceneInfo && PrimitiveSceneInfo->IsIndexValid())
7911 {
7912 UpdateStates[LateUpdateGameWriteIndex].Primitives.Emplace(PrimitiveSceneInfo, PrimitiveSceneInfo->GetIndex());
7913 }
7914 }
7915}
7916
7918{
7919 CacheSceneInfo(ParentComponent);
7920 TArray<USceneComponent*> DirectComponents;
7921
7922 // Std late updates
7923 ParentComponent->GetChildrenComponents(true, DirectComponents);
7924 for (USceneComponent* Component : DirectComponents)
7925 {
7926 if (Component != nullptr)
7927 {
7928 CacheSceneInfo(Component);
7929 }
7930 }
7931}
7932
7933void FExpandedLateUpdateManager::ProcessGripArrayLateUpdatePrimitives(UGripMotionControllerComponent * MotionControllerComponent, TArray<FBPActorGripInformation> & GripArray)
7934{
7935 for (FBPActorGripInformation actor : GripArray)
7936 {
7937 // Skip actors that are colliding if turning off late updates during collision.
7938 // Also skip turning off late updates for SweepWithPhysics, as it should always be locked to the hand
7939 if (!actor.GrippedObject || actor.GripCollisionType == EGripCollisionType::EventsOnly)
7940 continue;
7941
7942 // Handle late updates even with attachment, we need to add it to a skip list for the primary gatherer to process
7943 if (actor.GripCollisionType == EGripCollisionType::AttachmentGrip)
7944 {
7945 continue;
7946 }
7947
7948 // Don't allow late updates with server sided movement, there is no point
7949 if (actor.GripMovementReplicationSetting == EGripMovementReplicationSettings::ForceServerSideMovement && !MotionControllerComponent->IsServer())
7950 continue;
7951
7952 // Don't late update paused grips
7953 if (actor.bIsPaused)
7954 continue;
7955
7956 switch (actor.GripLateUpdateSetting)
7957 {
7959 {
7960 continue;
7961 }break;
7963 {
7964 if (actor.bColliding && actor.GripCollisionType != EGripCollisionType::SweepWithPhysics &&
7965 actor.GripCollisionType != EGripCollisionType::PhysicsOnly)
7966 continue;
7967 }break;
7969 {
7970 if (actor.SecondaryGripInfo.bHasSecondaryAttachment)
7971 continue;
7972 }break;
7974 {
7975 if (
7976 (actor.bColliding && actor.GripCollisionType != EGripCollisionType::SweepWithPhysics && actor.GripCollisionType != EGripCollisionType::PhysicsOnly) ||
7977 (actor.SecondaryGripInfo.bHasSecondaryAttachment)
7978 )
7979 {
7980 continue;
7981 }
7982 }break;
7984 default:
7985 {}break;
7986 }
7987
7988 // Don't run late updates if we have a grip script that denies it
7989 if (actor.GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
7990 {
7991 TArray<UVRGripScriptBase*> GripScripts;
7992 if (IVRGripInterface::Execute_GetGripScripts(actor.GrippedObject, GripScripts))
7993 {
7994 bool bContinueOn = false;
7995 for (UVRGripScriptBase* Script : GripScripts)
7996 {
7997 if (Script && Script->IsScriptActive() && Script->Wants_DenyLateUpdates())
7998 {
7999 bContinueOn = true;
8000 break;
8001 }
8002 }
8003
8004 if (bContinueOn)
8005 continue;
8006 }
8007 }
8008
8009 // Get late update primitives
8010 switch (actor.GripTargetType)
8011 {
8013 //case EGripTargetType::InteractibleActorGrip:
8014 {
8015 AActor * pActor = actor.GetGrippedActor();
8016 if (pActor)
8017 {
8018 if (USceneComponent * rootComponent = pActor->GetRootComponent())
8019 {
8020 GatherLateUpdatePrimitives(rootComponent);
8021 }
8022 }
8023
8024 }break;
8025
8027 //case EGripTargetType::InteractibleComponentGrip:
8028 {
8029 UPrimitiveComponent * cPrimComp = actor.GetGrippedComponent();
8030 if (cPrimComp)
8031 {
8032 GatherLateUpdatePrimitives(cPrimComp);
8033 }
8034 }break;
8035 }
8036 }
8037}
8038
8040{
8041 if (!FXRMotionControllerBase::GetHandEnumForSourceName(MotionSource, Hand))
8042 {
8043 Hand = EControllerHand::Left;
8044 }
8045}
8046
8047void UGripMotionControllerComponent::SetCustomPivotComponent(USceneComponent * NewCustomPivotComponent, FName PivotSocketName)
8048{
8049 CustomPivotComponent = NewCustomPivotComponent;
8050 CustomPivotComponentSocketName = PivotSocketName;
8051}
8052
8057
8062
8064{
8065 return InTransform.GetRelativeTransform(!bSkipPivotTransformAdjustment && CustomPivotComponent.IsValid() ? CustomPivotComponent->GetSocketTransform(CustomPivotComponentSocketName) : this->GetComponentTransform());
8066}
8067
8068FTransform UGripMotionControllerComponent::ConvertToGripRelativeTransform(const FTransform& GrippedActorTransform, const FTransform & InTransform)
8069{
8070 return InTransform.GetRelativeTransform(GrippedActorTransform);
8071}
8072
8074{
8075 if (!ObjectToCheck)
8076 return false;
8077
8078 return (GrippedObjects.FindByKey(ObjectToCheck) || LocallyGrippedObjects.FindByKey(ObjectToCheck));
8079}
8080
8082{
8083 if (!ActorToCheck)
8084 return false;
8085
8086 return (GrippedObjects.FindByKey(ActorToCheck) || LocallyGrippedObjects.FindByKey(ActorToCheck));
8087}
8088
8089bool UGripMotionControllerComponent::GetIsComponentHeld(const UPrimitiveComponent * ComponentToCheck)
8090{
8091 if (!ComponentToCheck)
8092 return false;
8093
8094 return (GrippedObjects.FindByKey(ComponentToCheck) || LocallyGrippedObjects.FindByKey(ComponentToCheck));
8095
8096 return false;
8097}
8098
8100{
8101 if (!ComponentToCheck)
8102 return false;
8103
8104 for (int i = 0; i < GrippedObjects.Num(); ++i)
8105 {
8106 if (GrippedObjects[i].SecondaryGripInfo.bHasSecondaryAttachment && GrippedObjects[i].SecondaryGripInfo.SecondaryAttachment == ComponentToCheck)
8107 {
8108 Grip = GrippedObjects[i];
8109 return true;
8110 }
8111 }
8112
8113 for (int i = 0; i < LocallyGrippedObjects.Num(); ++i)
8114 {
8115 if (LocallyGrippedObjects[i].SecondaryGripInfo.bHasSecondaryAttachment && LocallyGrippedObjects[i].SecondaryGripInfo.SecondaryAttachment == ComponentToCheck)
8116 {
8117 Grip = LocallyGrippedObjects[i];
8118 return true;
8119 }
8120 }
8121
8122 return false;
8123}
8124
8129
8134
8139
8141{
8142 return UpdatePhysicsHandle(Grip.GripID, bFullyRecreate);
8143}
8144
8146{
8148
8149 if (!HandleInfo)
8150 return false;
8151
8152 PhysicsHandleSettingsOut.FillFrom(HandleInfo);
8153 return true;
8154}
8155
8157{
8159
8160 if (!HandleInfo)
8161 return false;
8162
8163 PhysicsHandleSettingsIn.FillTo(HandleInfo);
8164 return UpdatePhysicsHandle(Grip, true);
8165}
8166
8167
8169{
8170 return UpdatePhysicsHandleTransform(GrippedActor, NewTransform);
8171}
8172
8173bool UGripMotionControllerComponent::GetGripDistance_BP(FBPActorGripInformation &Grip, FVector ExpectedLocation, float & CurrentDistance)
8174{
8175 if (!Grip.GrippedObject)
8176 return false;
8177
8178 UPrimitiveComponent * RootComp = nullptr;
8179
8181 {
8182 RootComp = Cast<UPrimitiveComponent>(Grip.GetGrippedActor()->GetRootComponent());
8183 }
8184 else
8185 RootComp = Grip.GetGrippedComponent();
8186
8187 if (!RootComp)
8188 return false;
8189
8190 FVector CheckDistance;
8191 if (!GetPhysicsJointLength(Grip, RootComp, CheckDistance))
8192 {
8193 CheckDistance = (ExpectedLocation - RootComp->GetComponentLocation());
8194 }
8195
8196 // Set grip distance now for people to use
8197 CurrentDistance = CheckDistance.Size();
8198 return true;
8199}
8200
DECLARE_CYCLE_STAT(TEXT("TickGrip ~ TickingGrip"), STAT_TickGrip, STATGROUP_TickGrip)
static void PullBackHitComp(FHitResult &Hit, const FVector &Start, const FVector &End, const float Dist)
const float ANGULAR_DAMPING_MULTIPLIER
const float ANGULAR_STIFFNESS_MULTIPLIER
DEFINE_LOG_CATEGORY(LogVRMotionController)
const float HYBRID_PHYSICS_GRIP_MULTIPLIER
EGripMovementReplicationSettings
UENUM(Blueprintable)
ESecondaryGripType
UENUM(Blueprintable)
EBPVRResultSwitch
UENUM()
EGripCollisionType
UENUM(Blueprintable)
@ InteractiveHybridCollisionWithPhysics
@ InteractiveHybridCollisionWithSweep
#define INVALID_VRGRIP_ID
EGripLateUpdateSettings
UENUM(Blueprintable)
EGripInterfaceTeleportBehavior
UENUM(Blueprintable)
EPhysicsGripCOMType
UENUM(Blueprintable)
void CacheSceneInfo(USceneComponent *Component)
void GatherLateUpdatePrimitives(USceneComponent *ParentComponent)
void Apply_RenderThread(FSceneInterface *Scene, const int32 FrameNumber, const FTransform &OldRelativeTransform, const FTransform &NewRelativeTransform)
void Setup(const FTransform &ParentToWorld, UGripMotionControllerComponent *Component, bool bSkipLateUpdate)
void ProcessGripArrayLateUpdatePrimitives(UGripMotionControllerComponent *MotionController, TArray< FBPActorGripInformation > &GripArray)
bool AreComponentsIgnoringCollisions(UPrimitiveComponent *Prim1, UPrimitiveComponent *Prim2)
virtual void PreRenderViewFamily_RenderThread(FRHICommandListImmediate &RHICmdList, FSceneViewFamily &InViewFamily) override
FGripViewExtension(const FAutoRegister &AutoRegister, UGripMotionControllerComponent *InMotionControllerComponent)
virtual void LateLatchingViewFamily_RenderThread(FRHICommandListImmediate &RHICmdList, FSceneViewFamily &InViewFamily) override
virtual void BeginRenderViewFamily(FSceneViewFamily &InViewFamily) override
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = MotionController)
bool UpdatePhysicsHandle(uint8 GripID, bool bFullyRecreate=true)
bool GetGripDistance_BP(UPARAM(ref) FBPActorGripInformation &Grip, FVector ExpectedLocation, float &CurrentDistance)
UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "GetGrip...
void Server_NotifySecondaryAttachmentChanged_Retain(uint8 GripID, const FBPSecondaryGripInfo &SecondaryGripInfo, const FTransform_NetQuantize &NewRelativeTransform)
UFUNCTION(Reliable, Server, WithValidation)
void SetSocketTransform(UObject *ObjectToSocket, const FTransform_NetQuantize RelativeTransformToParent)
UFUNCTION()
bool bSmoothHandTracking
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Smoothing")
FTransform CreateGripRelativeAdditionTransform_BP(const FBPActorGripInformation &GripToSample, const FTransform &AdditionTransform, bool bGripRelative=false)
UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "CreateGripRelative...
void Drop_Implementation(const FBPActorGripInformation &NewDrop, bool bSimulate)
bool UpdatePhysicsHandle_BP(UPARAM(ref) const FBPActorGripInformation &Grip, bool bFullyRecreate=true)
UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "UpdateP...
bool DropAndSocketGrip(const FBPActorGripInformation &GripToDrop, USceneComponent *SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize &RelativeTransformToParent, bool bWeldBodies=true)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
FBPVRComponentPosRep ReplicatedControllerTransform
UPROPERTY(EditDefaultsOnly, ReplicatedUsing = OnRep_ReplicatedControllerTransform,...
TArray< FBPActorPhysicsHandleInformation > PhysicsGrips
float SmoothingSpeed
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Smoothing")
void NotifyDrop(const FBPActorGripInformation &NewDrop, bool bSimulate)
UFUNCTION(Reliable, NetMulticast)
TArray< UObject * > ObjectsWaitingForSocketUpdate
UPROPERTY()
bool GripObject(UObject *ObjectToGrip, const FTransform &WorldOffset, bool bWorldOffsetIsRelative=false, FName OptionalSnapToSocketName=NAME_None, FName OptionalBoneToGripName=NAME_None, EGripCollisionType GripCollisionType=EGripCollisionType::InteractiveCollisionWithPhysics, EGripLateUpdateSettings GripLateUpdateSetting=EGripLateUpdateSettings::NotWhenCollidingOrDoubleGripping, EGripMovementReplicationSettings GripMovementReplicationSetting=EGripMovementReplicationSettings::ForceClientSideMovement, float GripStiffness=1500.0f, float GripDamping=200.0f, bool bIsSlotGrip=false)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
FTransform CreateGripRelativeAdditionTransform(const FBPActorGripInformation &GripToSample, const FTransform &AdditionTransform, bool bGripRelative=false)
bool HandleGripReplication(FBPActorGripInformation &Grip, FBPActorGripInformation *OldGripInfo=nullptr)
bool bSmoothReplicatedMotion
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "GripMotionController|Networking")
bool DropAndSocketGrip_Implementation(const FBPActorGripInformation &GripToDrop, USceneComponent *SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize &RelativeTransformToParent, bool bWeldBodies=true, bool bSkipServerNotify=false)
float InterpolationSpeed
UPROPERTY(EditAnywhere, Category = "GripMotionController|Networking|Smoothing", meta = (editcondition...
void PostTeleportMoveGrippedObjects()
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool bAlwaysSendTickGrip
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController")
bool bLimitMinHeight
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
void GetGripMass(const FBPActorGripInformation &Grip, float &Mass)
UFUNCTION(BlueprintPure, Category = "GripMotionController")
void ApplyTrackingParameters(FVector &OriginalPosition, bool bIsInGameThread)
bool bReplicateWithoutTracking
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "GripMotionController|Networking")
void UpdatePhysicsHandleTransform_BP(UPARAM(ref) const FBPActorGripInformation &GrippedActor, UPARAM(ref) const FTransform &NewTransform)
UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "UpdateP...
bool bOffsetByControllerProfile
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController")
FBPEuroLowPassFilterTrans EuroSmoothingParams
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Smoothing")
bool SetGripConstraintStiffnessAndDamping(const FBPActorGripInformation *Grip, bool bUseHybridMultiplier=false)
void CancelGlobalLerpToHand(uint8 GripID)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool GetPhysicsJointLength(const FBPActorGripInformation &GrippedActor, UPrimitiveComponent *rootComp, FVector &LocOut)
void NotifyGripTransformChanged(const FBPActorGripInformation &GripInfo)
bool bSmoothWithEuroLowPassFunction
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Smoothing")
bool AddSecondaryAttachmentPoint(UObject *GrippedObjectToAddAttachment, USceneComponent *SecondaryPointComponent, const FTransform &OriginalTransform, bool bTransformIsAlreadyRelative=false, float LerpToTime=0.25f, bool bIsSlotGrip=false, FName SecondarySlotName=NAME_None)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool RemoveSecondaryAttachmentFromGrip(const FBPActorGripInformation &GripToRemoveAttachment, float LerpToTime=0.25f)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
FTransform ConvertToControllerRelativeTransform(const FTransform &InTransform)
UFUNCTION(BlueprintPure, Category = "GripMotionController")
TWeakObjectPtr< AVRBaseCharacter > AttachChar
UPROPERTY()
bool bScaleTracking
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
bool HasGrippedObjects()
UFUNCTION(BlueprintPure, Category = "GripMotionController")
TArray< FBPActorGripInformation > LocalTransactionBuffer
UPROPERTY(BlueprintReadOnly, Replicated, Category = "GripMotionController", ReplicatedUsing = OnRep_L...
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
bool K2_GetFirstActiveGrip(FBPActorGripInformation &FirstActiveGrip)
UFUNCTION(BlueprintCallable, meta = (Keywords = "Grip", DisplayName = "GetFirstActiveGrip",...
bool HasGripAuthority(const FBPActorGripInformation &Grip)
void DropAndSocket_Implementation(const FBPActorGripInformation &NewDrop)
bool DestroyPhysicsHandle(const FBPActorGripInformation &Grip, bool bSkipUnregistering=false)
bool bSkipPivotTransformAdjustment
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "GripMotionController|CustomPivot")
UGripMotionControllerComponent(const FObjectInitializer &ObjectInitializer)
void NotifyDropAndSocket(const FBPActorGripInformation &NewDrop, USceneComponent *SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize &RelativeTransformToParent, bool bWeldBodies=true)
UFUNCTION(Reliable, NetMulticast)
FVROnControllerTeleportedGripsSignature OnTeleportedGrips
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
void EndPhysicsTickComponent(FGripComponentEndPhysicsTickFunction &ThisTickFunction)
bool DropComponent(UPrimitiveComponent *ComponentToDrop, bool bSimulate, FVector OptionalAngularVelocity=FVector::ZeroVector, FVector OptionalLinearVelocity=FVector::ZeroVector)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
void SetGripLateUpdateSetting(const FBPActorGripInformation &Grip, EBPVRResultSwitch &Result, EGripLateUpdateSettings NewGripLateUpdateSetting=EGripLateUpdateSettings::NotWhenCollidingOrDoubleGripping)
UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result")...
void InitializeLerpToHand(FBPActorGripInformation &GripInfo)
void GetGripByObject(FBPActorGripInformation &Grip, UObject *ObjectToLookForGrip, EBPVRResultSwitch &Result)
UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result")...
void Server_SendControllerTransform(FBPVRComponentPosRep NewTransform)
UFUNCTION(Unreliable, Server, WithValidation)
float NetworkMaxSmoothUpdateDistance
UPROPERTY(EditAnywhere, Category = "GripMotionController|Networking|Smoothing", meta = (editcondition...
void Server_NotifyLocalGripRemoved(uint8 GripID, const FTransform_NetQuantize &TransformAtDrop, FVector_NetQuantize100 AngularVelocity, FVector_NetQuantize100 LinearVelocity)
UFUNCTION(Reliable, Server, WithValidation)
bool GetIsSecondaryAttachment(const USceneComponent *ComponentToCheck, FBPActorGripInformation &Grip)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
FVector GetPivotLocation_BP()
UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "GetPivotLocation")...
void GetControllerDeviceID(FXRDeviceId &DeviceID, EBPVRResultSwitch &Result, bool bCheckOpenVROnly=false)
UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result")...
void Socket_Implementation(UObject *ObjectToSocket, bool bWasSimulating, USceneComponent *SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize &RelativeTransformToParent, bool bWeldBodies=true)
bool RemoveSecondaryAttachmentFromGripByID(const uint8 GripID=0, float LerpToTime=0.25f)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
void GetGrippedActors(TArray< AActor * > &GrippedActorArray)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
FBPActorPhysicsHandleInformation * GetPhysicsGrip(const FBPActorGripInformation &GripInfo)
bool TeleportMoveGrip_Impl(FBPActorGripInformation &Grip, bool bTeleportPhysicsGrips, bool bIsForPostTeleport, FTransform &OptionalTransform)
bool SetUpPhysicsHandle(const FBPActorGripInformation &NewGrip, TArray< UVRGripScriptBase * > *GripScripts=nullptr)
void SetGripStiffnessAndDamping(const FBPActorGripInformation &Grip, EBPVRResultSwitch &Result, float NewStiffness, float NewDamping, bool bAlsoSetAngularValues=false, float OptionalAngularStiffness=0.0f, float OptionalAngularDamping=0.0f)
UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result")...
bool DestroyPhysicsHandle_BP(UPARAM(ref) const FBPActorGripInformation &Grip)
UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "Destroy...
void Server_NotifyLocalGripAddedOrChanged(const FBPActorGripInformation &newGrip)
UFUNCTION(Reliable, Server, WithValidation, Category = "GripMotionController")
bool NotifyGrip(FBPActorGripInformation &NewGrip, bool bIsReInit=false)
virtual bool GripPollControllerState(FVector &Position, FRotator &Orientation, float WorldToMetersScale)
FVROnControllerDropSignature OnDroppedObject
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
void GetCurrentProfileTransform(bool bBindToNoticationDelegate)
void Client_NotifyInvalidLocalGrip(UObject *LocallyGrippedObject, uint8 GripID, bool bWasAGripConflict=false)
UFUNCTION(Reliable, Client, Category = "GripMotionController")
virtual void CreateRenderState_Concurrent(FRegisterComponentContext *Context) override
bool bUseWithoutTracking
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController")
FVROnControllerGripSignature OnLerpToHandFinished
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
bool DropAndSocketObject(const FTransform_NetQuantize &RelativeTransformToParent, UObject *ObjectToDrop=nullptr, uint8 GripIDToDrop=0, USceneComponent *SocketingParent=nullptr, FName OptionalSocketName=NAME_None, bool bWeldBodies=true)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
TArray< FBPActorGripInformation > GrippedObjects
UPROPERTY(BlueprintReadOnly, Replicated, Category = "GripMotionController", ReplicatedUsing = OnRep_G...
void GetAllGrips(TArray< FBPActorGripInformation > &GripArray)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
TSubclassOf< class UVRGripScriptBase > DefaultGripScriptClass
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced")
UVRGripScriptBase * DefaultGripScript
UPROPERTY(VisibleAnywhere, Transient, BlueprintReadOnly, Category = "GripMotionController|Advanced")
FVROnControllerGripSignature OnSecondaryGripRemoved
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
void HandleGlobalLerpToHand(FBPActorGripInformation &GripInformation, FTransform &WorldTransform, float DeltaTime)
float ControllerNetUpdateRate
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "GripMotionController|Networking",...
FBPActorGripInformation * GetGripPtrByID(uint8 IDToLookForGrip)
bool GripObjectByInterface(UObject *ObjectToGrip, const FTransform &WorldOffset, bool bWorldOffsetIsRelative=false, FName OptionalBoneToGripName=NAME_None, FName OptionalSnapToSocketName=NAME_None, bool bIsSlotGrip=false)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool GripComponent(UPrimitiveComponent *ComponentToGrip, const FTransform &WorldOffset, bool bWorldOffsetIsRelative=false, FName OptionalsnapToSocketName=NAME_None, FName OptionalBoneToGripName=NAME_None, EGripCollisionType GripCollisionType=EGripCollisionType::InteractiveCollisionWithPhysics, EGripLateUpdateSettings GripLateUpdateSetting=EGripLateUpdateSettings::NotWhenCollidingOrDoubleGripping, EGripMovementReplicationSettings GripMovementReplicationSetting=EGripMovementReplicationSettings::ForceClientSideMovement, float GripStiffness=1500.0f, float GripDamping=200.0f, bool bIsSlotGrip=false)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool DropGrip_Implementation(const FBPActorGripInformation &Grip, bool bSimulate=false, FVector OptionalAngularVelocity=FVector::ZeroVector, FVector OptionalLinearVelocity=FVector::ZeroVector, bool bSkipNotify=false)
bool CheckComponentWithSweep(UPrimitiveComponent *ComponentToCheck, FVector Move, FRotator newOrientation, bool bSkipSimulatingComponents)
void CleanUpBadGrip(TArray< FBPActorGripInformation > &GrippedObjectsArray, int GripIndex, bool bReplicatedArray)
void GetGripByID(FBPActorGripInformation &Grip, uint8 IDToLookForGrip, EBPVRResultSwitch &Result)
UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result")...
bool TeleportMoveGrippedActor(AActor *GrippedActorToMove, bool bTeleportPhysicsGrips=true)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool AddSecondaryAttachmentToGripByID(const uint8 GripID, USceneComponent *SecondaryPointComponent, const FTransform &OriginalTransform, bool bTransformIsAlreadyRelative=false, float LerpToTime=0.25f, bool bIsSlotGrip=false, FName SecondarySlotName=NAME_None)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool bOffsetByHMD
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
FVRGripControllerOnTrackingEventSignature OnTrackingChanged
UPROPERTY(BlueprintAssignable, Category = "GripMotionController")
void SetCustomPivotComponent(USceneComponent *NewCustomPivotComponent, FName PivotSocketName=NAME_None)
UFUNCTION(BlueprintCallable, Category = "GripMotionController|CustomPivot")
void SetPausedTransform(const FBPActorGripInformation &Grip, const FTransform &PausedTransform, bool bTeleport=false)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
float MinimumHeight
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking",...
bool bIgnoreTrackingStatus
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController")
void GetGripByComponent(FBPActorGripInformation &Grip, UPrimitiveComponent *ComponentToLookForGrip, EBPVRResultSwitch &Result)
UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result")...
void GetGripByActor(FBPActorGripInformation &Grip, AActor *ActorToLookForGrip, EBPVRResultSwitch &Result)
UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result")...
void GetGrippedObjects(TArray< UObject * > &GrippedObjectsArray)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
virtual FVector GetComponentVelocity() const override
FVRGripControllerOnGripOutOfRange OnGripOutOfRange
UPROPERTY(BlueprintAssignable, Category = "GripMotionController")
bool BP_HasGripMovementAuthority(const FBPActorGripInformation &Grip)
UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "HasGripMovementAut...
FVector TrackingScaler
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking",...
void TeleportMoveGrips(bool bTeleportPhysicsGrips=true, bool bIsForPostTeleport=false)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool GetPhysicsConstraintForce(const FBPActorGripInformation &Grip, FVector &AngularForce, FVector &LinearForce)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
float NetworkNoSmoothUpdateDistance
UPROPERTY(EditAnywhere, Category = "GripMotionController|Networking|Smoothing", meta = (editcondition...
void SetGripAdditionTransform(const FBPActorGripInformation &Grip, EBPVRResultSwitch &Result, const FTransform &NewAdditionTransform, bool bMakeGripRelative=false)
UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result")...
bool bLeashToHMD
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
void ReCreateGrip(FBPActorGripInformation &GripInfo)
void Server_NotifySecondaryAttachmentChanged(uint8 GripID, const FBPSecondaryGripInfo &SecondaryGripInfo)
UFUNCTION(Reliable, Server, WithValidation)
void GetPhysicsVelocities(const FBPActorGripInformation &Grip, FVector &AngularVelocity, FVector &LinearVelocity)
UFUNCTION(BlueprintPure, Category = "GripMotionController")
void SetGripCollisionType(const FBPActorGripInformation &Grip, EBPVRResultSwitch &Result, EGripCollisionType NewGripCollisionType=EGripCollisionType::InteractiveCollisionWithPhysics)
UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result")...
bool bConstrainToPivot
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced")
TWeakObjectPtr< USceneComponent > CustomPivotComponent
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "GripMotionController|CustomPivot")
bool GripControllerIsTracked() const
UFUNCTION(BlueprintPure, Category = "GripMotionController")
EVRClientAuthConflictResolutionMode ClientAuthConflictResolutionMethod
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|ClientAuth")
void OnGripMassUpdated(FBodyInstance *GripBodyInstance)
VRBaseCharTransformRPC_Pointer OverrideSendTransform
bool RemoveSecondaryAttachmentPoint(UObject *GrippedObjectToRemoveAttachment, float LerpToTime=0.25f)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool GetIsComponentHeld(const UPrimitiveComponent *ComponentToCheck)
UFUNCTION(BlueprintPure, Category = "GripMotionController")
FVRGripControllerOnProfileTransformChanged OnControllerProfileTransformChanged
UPROPERTY(BlueprintAssignable, Category = "GripMotionController")
bool DropObjectByInterface(UObject *ObjectToDrop=nullptr, uint8 GripIDToDrop=0, FVector OptionalAngularVelocity=FVector::ZeroVector, FVector OptionalLinearVelocity=FVector::ZeroVector)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
TSharedPtr< FGripViewExtension, ESPMode::ThreadSafe > GripViewExtension
bool DropObject(UObject *ObjectToDrop=nullptr, uint8 GripIdToDrop=0, bool bSimulate=false, FVector OptionalAngularVelocity=FVector::ZeroVector, FVector OptionalLinearVelocity=FVector::ZeroVector)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool bProjectNonSimulatingGrips
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "GripMotionController|Advanced")
static FTransform ConvertToGripRelativeTransform(const FTransform &GrippedActorTransform, const FTransform &InTransform)
UFUNCTION(BlueprintPure, Category = "GripMotionController")
float MaximumHeight
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking",...
FVROnControllerSocketSignature OnSocketingObject
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
FVROnClientAuthGripConflict OnClientAuthGripConflict
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
void SetGripPaused(const FBPActorGripInformation &Grip, EBPVRResultSwitch &Result, bool bIsPaused=false, bool bNoConstraintWhenPaused=false)
UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result")...
FGripComponentEndPhysicsTickFunction EndPhysicsTickFunction
struct UGripMotionControllerComponent::FRenderTrackingParams LateUpdateParams
FVROnControllerGripSignature OnSecondaryGripAdded
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
bool bUseExponentialSmoothing
UPROPERTY(EditAnywhere, Category = "GripMotionController|Networking|Smoothing", meta = (editcondition...
bool HasGripMovementAuthority(const FBPActorGripInformation &Grip)
FName CustomPivotComponentSocketName
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "GripMotionController|CustomPivot")
bool PausePhysicsHandle(FBPActorPhysicsHandleInformation *HandleInfo)
void GetHandType(EControllerHand &Hand)
UFUNCTION(BlueprintPure, Category = "VRExpansionFunctions", meta = (bIgnoreSelf = "true",...
TArray< UPrimitiveComponent * > AdditionalLateUpdateComponents
UPROPERTY(BlueprintReadWrite, Category = "GripMotionController")
void SetGripRelativeTransform(const FBPActorGripInformation &Grip, EBPVRResultSwitch &Result, const FTransform &NewRelativeTransform)
UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result")...
bool GetPhysicsGripIndex(const FBPActorGripInformation &GripInfo, int &index)
TArray< FBPActorGripInformation > LocallyGrippedObjects
UPROPERTY(BlueprintReadOnly, Replicated, Category = "GripMotionController", ReplicatedUsing = OnRep_L...
EVRVelocityType VelocityCalculationType
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|ComponentVelocity")
void Server_NotifyDropAndSocketGrip(uint8 GripID, USceneComponent *SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize &RelativeTransformToParent, bool bWeldBodies=true)
UFUNCTION(Reliable, Server, WithValidation, Category = "GripMotionController")
int32 VelocitySamples
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|ComponentVelocity")
bool BP_HasGripAuthority(const FBPActorGripInformation &Grip)
UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "HasGripAuthority")...
FTransform GetPivotTransform_BP()
UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "GetPivotTransform"...
bool BP_IsLocallyControlled()
UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "IsLocallyControlle...
bool GripActor(AActor *ActorToGrip, const FTransform &WorldOffset, bool bWorldOffsetIsRelative=false, FName OptionalSnapToSocketName=NAME_None, FName OptionalBoneToGripName=NAME_None, EGripCollisionType GripCollisionType=EGripCollisionType::InteractiveCollisionWithPhysics, EGripLateUpdateSettings GripLateUpdateSetting=EGripLateUpdateSettings::NotWhenCollidingOrDoubleGripping, EGripMovementReplicationSettings GripMovementReplicationSetting=EGripMovementReplicationSettings::ForceClientSideMovement, float GripStiffness=1500.0f, float GripDamping=200.0f, bool bIsSlotGrip=false)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
void HandleGripArray(TArray< FBPActorGripInformation > &GrippedObjectsArray, const FTransform &ParentTransform, float DeltaTime, bool bReplicatedArray=false)
bool DropActor(AActor *ActorToDrop, bool bSimulate, FVector OptionalAngularVelocity=FVector::ZeroVector, FVector OptionalLinearVelocity=FVector::ZeroVector)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
void UpdatePhysicsHandleTransform(const FBPActorGripInformation &GrippedActor, const FTransform &NewTransform)
void GetGrippedComponents(TArray< UPrimitiveComponent * > &GrippedComponentsArray)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool bLimitMaxHeight
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
bool bSampleVelocityInWorldSpace
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|ComponentVelocity")
float LeashRange
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking",...
bool TeleportMoveGrippedComponent(UPrimitiveComponent *ComponentToMove, bool bTeleportPhysicsGrips=true)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool GetGripWorldTransform(TArray< UVRGripScriptBase * > &GripScripts, float DeltaTime, FTransform &WorldTransform, const FTransform &ParentTransform, FBPActorGripInformation &Grip, AActor *actor, UPrimitiveComponent *root, bool bRootHasInterface, bool bActorHasInterface, bool bIsForTeleport, bool &bForceADrop)
bool GetPhysicsHandleSettings(UPARAM(ref) const FBPActorGripInformation &Grip, FBPAdvancedPhysicsHandleSettings &PhysicsHandleSettingsOut)
UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "GetPhys...
bool GetIsHeld(const AActor *ActorToCheck)
UFUNCTION(BlueprintPure, Category = "GripMotionController")
void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override
bool BP_HasGripAuthorityForObject(const UObject *ObjToCheck)
UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "HasGripAuthorityFo...
virtual void OnRep_ReplicatedControllerTransform()
UFUNCTION()
bool UnPausePhysicsHandle(FBPActorGripInformation &GripInfo, FBPActorPhysicsHandleInformation *HandleInfo)
bool DropGrip(const FBPActorGripInformation &Grip, bool bSimulate=false, FVector OptionalAngularVelocity=FVector::ZeroVector, FVector OptionalLinearVelocity=FVector::ZeroVector)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool SetPhysicsHandleSettings(UPARAM(ref) const FBPActorGripInformation &Grip, UPARAM(ref) const FBPAdvancedPhysicsHandleSettings &PhysicsHandleSettingsIn)
UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "SetPhys...
void SetGripHybridLock(const FBPActorGripInformation &Grip, EBPVRResultSwitch &Result, bool bIsLocked=false)
UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result")...
bool GetIsObjectHeld(const UObject *ObjectToCheck)
UFUNCTION(BlueprintPure, Category = "GripMotionController")
bool SetUpPhysicsHandle_BP(UPARAM(ref) const FBPActorGripInformation &Grip)
UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "SetUpPh...
bool TeleportMoveGrip(UPARAM(ref) FBPActorGripInformation &Grip, bool bTeleportPhysicsGrips=true, bool bIsForPostTeleport=false)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
FVROnControllerGripSignature OnGrippedObject
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
FBPActorPhysicsHandleInformation * CreatePhysicsGrip(const FBPActorGripInformation &GripInfo)
bool AddSecondaryAttachmentToGrip(const FBPActorGripInformation &GripToAddAttachment, USceneComponent *SecondaryPointComponent, const FTransform &OriginalTransform, bool bTransformIsAlreadyRelative=false, float LerpToTime=0.25f, bool bIsSlotGrip=false, FName SecondarySlotName=NAME_None)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
static void UpdatePeakLowPassFilter(UPARAM(ref) FBPLowPassPeakFilter &TargetPeakFilter, FVector NewSample)
UFUNCTION(BlueprintCallable, Category = "LowPassFilter_Peak")
static void LowPassFilter_RollingAverage(FVector lastAverage, FVector newSample, FVector &newAverage, int32 numSamples=10)
UFUNCTION(BlueprintPure, Category = "VRExpansionFunctions", meta = (bIgnoreSelf = "true",...
UCLASS(config = Engine, defaultconfig)
float LinearDriveDampingScale
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "ChaosPhysics")
bool bHybridWithSweepUseDistanceBasedLerp
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "HybridWithSweepLerp")
float LerpDuration
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "GlobalLerpToHand")
float AngularDriveDampingScale
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "ChaosPhysics")
FVRControllerProfileChangedEvent OnControllerProfileChangedEvent
float HybridWithSweepLerpDuration
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "HybridWithSweepLerp")
bool bLerpHybridWithSweepGrips
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "HybridWithSweepLerp")
float MaxSpeedForLerp
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "GlobalLerpToHand")
float MinSpeedForLerp
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "GlobalLerpToHand")
FRuntimeFloatCurve OptionalCurveToFollow
UPROPERTY(config, Category = "GlobalLerpToHand|Curve", EditAnywhere, meta = (editcondition = "bUseCur...
FTransform CurrentControllerProfileTransform
float MinDistanceForLerp
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "GlobalLerpToHand")
EVRLerpInterpolationMode LerpInterpolationMode
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "GlobalLerpToHand")
float AngularDriveStiffnessScale
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "ChaosPhysics")
bool bUseGlobalLerpToHand
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "GlobalLerpToHand")
bool bOnlyLerpHybridRotation
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "HybridWithSweepLerp")
float LinearDriveStiffnessScale
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "ChaosPhysics")
bool bUseCurve
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "GlobalLerpToHand|Curve")
bool bSkipLerpToHandIfHeld
UPROPERTY(config, BlueprintReadWrite, EditAnywhere, Category = "GlobalLerpToHand")
FTransform CurrentControllerProfileTransformRight
UCLASS(NotBlueprintable, BlueprintType, EditInlineNew, DefaultToInstanced, Abstract,...
FORCEINLINE bool Wants_ToForceDrop()
virtual bool CallCorrect_GetWorldTransform(UGripMotionControllerComponent *OwningController, float DeltaTime, FTransform &WorldTransform, const FTransform &ParentTransform, FBPActorGripInformation &Grip, AActor *actor, UPrimitiveComponent *root, bool bRootHasInterface, bool bActorHasInterface, bool bIsForTeleport)
static UVRGripScriptBase * GetGripScriptByClass(UObject *WorldContextObject, TSubclassOf< UVRGripScriptBase > GripScriptClass, EBPVRResultSwitch &Result)
UFUNCTION(BlueprintCallable, Category = "VRGripScript|Functions", meta = (WorldContext = "WorldContex...
FAutoConsoleVariableRef CVarDrawCOMDebugSpheres(TEXT("vr.DrawDebugCenterOfMassForGrips"), DrawDebugGripCOM, TEXT("0: Disable, 1: Enable"), ECVF_Default)
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
FBPAdvGripSettings AdvancedGripSettings
UPROPERTY(BlueprintReadOnly, Category = "Settings")
bool bIsPendingKill
UPROPERTY(BlueprintReadOnly, NotReplicated, Category = "Settings")
bool bIsSlotGrip
UPROPERTY(BlueprintReadWrite, Category = "Settings")
bool bIsPaused
UPROPERTY(BlueprintReadWrite, NotReplicated, Category = "Settings")
bool bOriginalGravity
UPROPERTY()
struct FBPActorGripInformation::FGripValueCache ValueCache
bool bOriginalReplicatesMovement
UPROPERTY()
FTransform_NetQuantize RelativeTransform
UPROPERTY(BlueprintReadWrite, Category = "Settings")
EGripTargetType GripTargetType
UPROPERTY(BlueprintReadOnly, Category = "Settings")
FName SlotName
UPROPERTY(BlueprintReadWrite, Category = "Settings")
FORCEINLINE AActor * GetGrippedActor() const
bool bColliding
UPROPERTY(BlueprintReadOnly, NotReplicated, Category = "Settings")
float Stiffness
UPROPERTY(BlueprintReadOnly, Category = "Settings")
FBPSecondaryGripInfo SecondaryGripInfo
UPROPERTY(BlueprintReadOnly, Category = "Settings")
EGripCollisionType GripCollisionType
UPROPERTY(BlueprintReadOnly, Category = "Settings")
EGripLateUpdateSettings GripLateUpdateSetting
UPROPERTY(BlueprintReadWrite, Category = "Settings")
UObject * GrippedObject
UPROPERTY(BlueprintReadOnly, Category = "Settings")
uint8 GripID
UPROPERTY(BlueprintReadOnly, Category = "Settings")
FName GrippedBoneName
UPROPERTY(BlueprintReadWrite, Category = "Settings")
bool bIsLerping
UPROPERTY(BlueprintReadOnly, NotReplicated, Category = "Settings")
FORCEINLINE UPrimitiveComponent * GetGrippedComponent() const
EGripMovementReplicationSettings GripMovementReplicationSetting
UPROPERTY(BlueprintReadOnly, Category = "Settings")
bool bLockHybridGrip
UPROPERTY(BlueprintReadWrite, NotReplicated, Category = "Settings")
float Damping
UPROPERTY(BlueprintReadOnly, Category = "Settings")
float GripDistance
UPROPERTY(BlueprintReadOnly, NotReplicated, Category = "Settings")
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
FAngularDriveConstraint AngConstraint
FPhysicsConstraintHandle HandleData2
FLinearDriveConstraint LinConstraint
UObject * HandledObject
UPROPERTY(BlueprintReadOnly, Category = "Settings")
EPhysicsGripCOMType PhysicsGripLocationSettings
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PhysicsSettings", meta = (editcondition = "bU...
bool bUsePhysicsSettings
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PhysicsSettings")
bool bTurnOffGravityDuringGrip
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PhysicsSettings", meta = (editcondition = "bU...
bool bSkipSettingSimulating
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PhysicsSettings", meta = (editcondition = "bU...
float LinearMaxForceCoefficient
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PhysicsSettings", meta = (editcondition = "bU...
float AngularMaxForceCoefficient
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PhysicsSettings", meta = (editcondition = "bU...
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
bool bSetOwnerOnGrip
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AdvancedGripSettings")
FBPAdvGripPhysicsSettings PhysicsSettings
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AdvancedGripSettings")
bool bDisallowLerping
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AdvancedGripSettings")
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
bool FillFrom(FBPActorPhysicsHandleInformation *HandleInfo)
bool FillTo(FBPActorPhysicsHandleInformation *HandleInfo) const
float CutoffSlope
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FilterSettings")
FTransform RunFilterSmoothing(const FTransform &InRawValue, const float &InDeltaTime)
float MinCutoff
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FilterSettings")
float DeltaCutoff
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FilterSettings")
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
int32 VelocitySamples
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Samples")
FVector GetPeak() const
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
USceneComponent * SecondaryAttachment
UPROPERTY(BlueprintReadOnly, Category = "SecondaryGripInfo")
FName SecondarySlotName
UPROPERTY(BlueprintReadWrite, Category = "SecondaryGripInfo")
EGripLerpState GripLerpState
float LerpToRate
UPROPERTY()
float SecondaryGripDistance
UPROPERTY(BlueprintReadOnly, NotReplicated, Category = "SecondaryGripInfo")
FORCEINLINE FBPSecondaryGripInfo & RepCopy(const FBPSecondaryGripInfo &Other)
bool bIsSlotGrip
UPROPERTY(BlueprintReadWrite, Category = "SecondaryGripInfo")
bool bHasSecondaryAttachment
UPROPERTY(BlueprintReadOnly, Category = "SecondaryGripInfo")
FTransform_NetQuantize SecondaryRelativeTransform
UPROPERTY(BlueprintReadOnly, Category = "SecondaryGripInfo")
FVector Position
UPROPERTY(Transient)
FRotator Rotation
UPROPERTY(Transient)
virtual void ExecuteTick(float DeltaTime, enum ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef &MyCompletionGraphEvent) override
virtual FName DiagnosticContext(bool bDetailed) override
USTRUCT(BlueprintType, Category = "VRExpansionLibrary|TransformNetQuantize", meta = (HasNativeMake = ...