A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
GripMotionControllerComponent.h
Go to the documentation of this file.
1// Fill out your copyright notice in the Description page of Project Settings.
2
3#pragma once
4
5#include "CoreMinimal.h"
6#include "Engine/Engine.h"
7#include "IMotionController.h"
8#include "SceneViewExtension.h"
9#include "VRBPDatatypes.h"
10#include "MotionControllerComponent.h"
11#include "LateUpdateManager.h"
12#include "IIdentifiableXRDevice.h" // for FXRDeviceId
13#include "IXRTrackingSystem.h"
14#include "VRGripInterface.h"
15#include "VRGlobalSettings.h"
17#include "Math/DualQuat.h"
18#include "XRMotionControllerBase.h" // for GetHandEnumForSourceName()
19#include "GripMotionControllerComponent.generated.h"
20
22
28// This is a temp macro until epic adds their own equivilant
29#define DOREPLIFETIME_ACTIVE_OVERRIDE_PRIVATE_PROPERTY(c,v,active) \
30{ \
31 static FProperty* sp##v = GetReplicatedProperty(StaticClass(), c::StaticClass(),FName(TEXT(#v))); \
32 for (int32 i = 0; i < sp##v->ArrayDim; i++) \
33 { \
34 ChangedPropertyTracker.SetCustomIsActiveOverride(this, sp##v->RepIndex + i, active); \
35 } \
36}
37
38#define RESET_REPLIFETIME_CONDITION_PRIVATE_PROPERTY(c,v,cond) ResetReplicatedLifetimeProperty(StaticClass(), c::StaticClass(), FName(TEXT(#v)), cond, OutLifetimeProps);
39
40DECLARE_LOG_CATEGORY_EXTERN(LogVRMotionController, Log, All);
41//For UE4 Profiler ~ Stat Group
42DECLARE_STATS_GROUP(TEXT("TICKGrip"), STATGROUP_TickGrip, STATCAT_Advanced);
43
45DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FVRGripControllerOnTrackingEventSignature, const ETrackingStatus &, NewTrackingStatus);
46
48DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FVROnControllerGripSignature, const FBPActorGripInformation &, GripInformation);
49
51DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FVROnControllerDropSignature, const FBPActorGripInformation &, GripInformation, bool, bWasSocketed);
52
54DECLARE_DYNAMIC_MULTICAST_DELEGATE_FiveParams(FVROnControllerSocketSignature, const FBPActorGripInformation&, GripInformation, const USceneComponent*, NewParentComp, FName, OptionalSocketName, FTransform, RelativeTransformToParent, bool, bWeldingBodies);
55
57DECLARE_DYNAMIC_MULTICAST_DELEGATE(FVROnControllerTeleportedGripsSignature);
58
60DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FVRGripControllerOnGripOutOfRange, const FBPActorGripInformation &, GripInformation, float, Distance);
61
63DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FVRGripControllerOnProfileTransformChanged, const FTransform &, NewRelTransForProcComps, const FTransform &, NewProfileTransform);
64
67
71class VREXPANSIONPLUGIN_API FExpandedLateUpdateManager
72{
73public:
75
77
79 void Setup(const FTransform& ParentToWorld, UGripMotionControllerComponent* Component, bool bSkipLateUpdate);
80
82 void Apply_RenderThread(FSceneInterface* Scene, const int32 FrameNumber, const FTransform& OldRelativeTransform, const FTransform& NewRelativeTransform);
83
85 bool GetSkipLateUpdate_RenderThread() const { return UpdateStates[LateUpdateRenderReadIndex].bSkip; }
86
87public:
88
90 void GatherLateUpdatePrimitives(USceneComponent* ParentComponent);
91 void ProcessGripArrayLateUpdatePrimitives(UGripMotionControllerComponent* MotionController, TArray<FBPActorGripInformation> & GripArray);
92
94 void CacheSceneInfo(USceneComponent* Component);
95
97 {
99 : ParentToWorld(FTransform::Identity)
100 , bSkip(false)
101 , TrackingNumber(-1)
102 {}
103
105 FTransform ParentToWorld;
107 TMap<FPrimitiveSceneInfo*, int32> Primitives;
109 bool bSkip;
112 };
113
114 FLateUpdateState UpdateStates[2];
117};
118
122USTRUCT()
124{
125 GENERATED_USTRUCT_BODY()
126
128
136 virtual void ExecuteTick(float DeltaTime, enum ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) override;
138 virtual FString DiagnosticMessage() override;
140 virtual FName DiagnosticContext(bool bDetailed) override;
141};
142
143template<>
145{
146 enum
147 {
148 WithCopy = false
149 };
150};
155UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = MotionController)
156class VREXPANSIONPLUGIN_API UGripMotionControllerComponent : public UMotionControllerComponent//PrimitiveComponent
157{
158
159public:
160
163
165 void EndPhysicsTickComponent(FGripComponentEndPhysicsTickFunction& ThisTickFunction);
166 void RegisterEndPhysicsTick(bool bRegister);
168 // If true then we will sample the post physics scene to get the relative location of this object.
169 // This lets us reproject that relative position prior to running the grip logic.
170 UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "GripMotionController|Advanced")
171 bool bProjectNonSimulatingGrips;
172
173 // The grip script that defines the default behaviors of grips
174 // Don't edit this unless you really know what you are doing, leave it empty
175 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced")
176 TSubclassOf<class UVRGripScriptBase> DefaultGripScriptClass;
177
178 // This is the pointer to the default grip script
179 // It is here to access so if you want to set some variables on your override then you can
180 // Due to a bug with instanced variables and parent classes you can't directly edit this in subclass in the details panel
181 UPROPERTY(VisibleAnywhere, Transient, BlueprintReadOnly, Category = "GripMotionController|Advanced")
182 UVRGripScriptBase* DefaultGripScript;
183
184 // Lerping functions and events
185 void InitializeLerpToHand(FBPActorGripInformation& GripInfo);
186 void HandleGlobalLerpToHand(FBPActorGripInformation& GripInformation, FTransform& WorldTransform, float DeltaTime);
187
188 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
189 void CancelGlobalLerpToHand(uint8 GripID);
190
191 //UPROPERTY(BlueprintAssignable, Category = "Grip Events")
192 // FVROnControllerGripSignature OnLerpToHandBegin;
193
194 UPROPERTY(BlueprintAssignable, Category = "Grip Events")
195 FVROnControllerGripSignature OnLerpToHandFinished;
196
197 // If true we will scale the tracking of the motion controller by the TrackingScaler value
198 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
199 bool bScaleTracking;
201 // A scale to be applied to the tracked positions of the controller if bScaleTracking is true
202 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking", meta = (ClampMin = "0.1", UIMin = "0.1", EditCondition = "bScaleTracking"))
203 FVector TrackingScaler;
204
205 // If true we will use the minimum height value to clamp the Z too
206 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
207 bool bLimitMinHeight;
208
209 // The minimum height to allow for this controller
210 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking", meta = (ClampMin = "0.0", UIMin = "0.0", EditCondition = "bLimitMinHeight"))
211 float MinimumHeight;
212
213 // If true we will use the maximum height value to clamp the Z too
214 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
215 bool bLimitMaxHeight;
216
217 // The maximum height to allow for this controller
218 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking", meta = (ClampMin = "0.1", UIMin = "0.1", EditCondition = "bLimitMinHeight"))
219 float MaximumHeight;
220
221 // If true will subtract the HMD's location from the position, useful for if the actors base is set to the HMD location always (simple character).
222 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
223 bool bOffsetByHMD;
224
225 // If true this controller will attempt to stay within its LeashRange distance from the HMD
226 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
227 bool bLeashToHMD;
228
229 // How far away from the HMD the controller should stay max (vector distance)
230 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking", meta = (ClampMin = "0.1", UIMin = "0.1", EditCondition = "bLeashToHMD"))
231 float LeashRange;
232
233 void ApplyTrackingParameters(FVector& OriginalPosition, bool bIsInGameThread);
234 bool HasTrackingParameters();
236 // When true any physics constraints will be attached to the grip pivot instead of a new kinematic actor in the scene
237 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced")
238 bool bConstrainToPivot;
239
240 UPROPERTY()
241 TWeakObjectPtr<AVRBaseCharacter> AttachChar;
242 void UpdateTracking(float DeltaTime);
243 virtual void OnAttachmentChanged() override;
244
245 FVector LastLocationForLateUpdate;
246 FTransform LastRelativePosition;
247
248 // If true will smooth the hand tracking data with a TInterp function
249 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Smoothing")
250 bool bSmoothHandTracking;
252 bool bWasSmoothingHand;
253
254 // If true will smooth hand tracking with the Linear and Rotational 1 Euro low pass settings instead
255 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Smoothing")
256 bool bSmoothWithEuroLowPassFunction;
257
258 // The interp speed to use if smoothing is enabled and not using the 1 Euro smoothing
259 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Smoothing")
260 float SmoothingSpeed;
261
262 // Smoothing parameters when using the 1 Euro low pass option
263 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Smoothing")
264 FBPEuroLowPassFilterTrans EuroSmoothingParams;
265
266 FTransform LastSmoothRelativeTransform;
268 // Type of velocity calculation to use for the motion controller
269 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|ComponentVelocity")
270 EVRVelocityType VelocityCalculationType;
271
272 // If we should sample the velocity in world or local space
273 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|ComponentVelocity")
274 bool bSampleVelocityInWorldSpace;
276 // If not using velocity mode "default" this is the number of sample to keep
277 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|ComponentVelocity")
278 int32 VelocitySamples;
279
280 FBPLowPassPeakFilter PeakFilter;
281
282 virtual FVector GetComponentVelocity() const override;
284 // If true will offset the tracked location of the controller by the controller profile that is currently loaded.
285 // Thows the event OnControllerProfileTransformChanged when it happens so that you can adjust specific components
286 // Like procedural ones for the offset (procedural meshes are already correctly offset for the controller and
287 // need rewound.
288 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController")
289 bool bOffsetByControllerProfile;
290
291 // Stores current transform so we don't have to keep casting
292 FTransform CurrentControllerProfileTransform;
293
294 // Called when the controller profile changed and we have a new transform (only if bOffsetByControllerProfile is true)
295 UPROPERTY(BlueprintAssignable, Category = "GripMotionController")
296 FVRGripControllerOnProfileTransformChanged OnControllerProfileTransformChanged;
297
298 // Called when the controller profile changed and we have a new transform (only if bOffsetByControllerProfile is true)
299 UPROPERTY(BlueprintAssignable, Category = "GripMotionController")
300 FVRGripControllerOnGripOutOfRange OnGripOutOfRange;
301
302private:
303
304 GENERATED_BODY()
305
306public:
307 UGripMotionControllerComponent(const FObjectInitializer& ObjectInitializer);
308
310
311 // Custom version of the component sweep function to remove that aggravating warning epic is throwing about skeletal mesh components.
312 void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
313 virtual void InitializeComponent() override;
314 virtual void OnUnregister() override;
315 //virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override;
316 virtual void Deactivate() override;
317 virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
318 virtual void BeginDestroy() override;
319 virtual void BeginPlay() override;
322 //UPROPERTY()
323 // FTickFunction PostPhysicsTickFunction;
324
325protected:
326 //~ Begin UActorComponent Interface.
327 virtual void CreateRenderState_Concurrent(FRegisterComponentContext* Context) override;
328 virtual void SendRenderTransform_Concurrent() override;
329 //~ End UActorComponent Interface.
331 // Late update control variables (should likely struct these soon)
333 {
334 FTransform GripRenderThreadRelativeTransform = FTransform::Identity;
335 FVector GripRenderThreadComponentScale = FVector::ZeroVector;
336 FTransform GripRenderThreadProfileTransform = FTransform::Identity;
337 FVector GripRenderThreadLastLocationForLateUpdate = FVector::ZeroVector;
339 // Smoothing info
340 bool bRenderSmoothHandTracking = false;
341 bool bRenderSmoothWithEuroLowPassFunction = false;
342 float RenderSmoothingSpeed = 0.0f;
343 FBPEuroLowPassFilterTrans RenderEuroSmoothingParams;
344 FTransform RenderLastSmoothRelativeTransform = FTransform::Identity;
345 float RenderLastDeltaTime = 0.0f;
346 }LateUpdateParams;
347
348 FDelegateHandle NewControllerProfileEvent_Handle;
349 UFUNCTION()
350 void NewControllerProfileLoaded();
351 void GetCurrentProfileTransform(bool bBindToNoticationDelegate);
352
353public:
354
355 // Called when a controller first gets a valid tracked frame
356 UPROPERTY(BlueprintAssignable, Category = "GripMotionController")
357 FVRGripControllerOnTrackingEventSignature OnTrackingChanged;
358
359 // Called when a object is gripped
360 UPROPERTY(BlueprintAssignable, Category = "Grip Events")
361 FVROnControllerGripSignature OnGrippedObject;
362
363 // Called when a object is dropped
364 UPROPERTY(BlueprintAssignable, Category = "Grip Events")
365 FVROnControllerDropSignature OnDroppedObject;
366
367 // Called when a object is being socketed, prior to OnDrop being called and prior to the actual socketing being performed
368 // Generally an early entry to detach hands and handle pre-socketing logic
369 UPROPERTY(BlueprintAssignable, Category = "Grip Events")
370 FVROnControllerSocketSignature OnSocketingObject;
371
372 // Called when a gripped object has been teleported
373 UPROPERTY(BlueprintAssignable, Category = "Grip Events")
374 FVROnControllerTeleportedGripsSignature OnTeleportedGrips;
375
376 // Called when an object we hold is secondary gripped
377 UPROPERTY(BlueprintAssignable, Category = "Grip Events")
378 FVROnControllerGripSignature OnSecondaryGripAdded;
379
380 // Called when an object we hold is secondary dropped
381 UPROPERTY(BlueprintAssignable, Category = "Grip Events")
382 FVROnControllerGripSignature OnSecondaryGripRemoved;
383
384 // Storage for remote players for secondary grips specifically
385 // Its more than a little hacky, but ordering of drop and the secondaries being
386 // removed on the rep notify require this in rare cases. If Epic ever fixes the last array state not containing removed
387 // grips then this would be a lot cleaner.
388 TArray<uint8> SecondaryGripIDs;
389
390 // Called when an object we hold has its grip transform changed
391 UPROPERTY(BlueprintAssignable, Category = "Grip Events")
392 FVROnControllerGripSignature OnGripTransformChanged;
393
394 // Gets the hand enum
395 UFUNCTION(BlueprintPure, Category = "VRExpansionFunctions", meta = (bIgnoreSelf = "true", DisplayName = "HandType", CompactNodeTitle = "HandType"))
396 void GetHandType(EControllerHand& Hand);
398 // The component to use for basing the grip off of instead of the motion controller
399 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "GripMotionController|CustomPivot")
400 TWeakObjectPtr<USceneComponent> CustomPivotComponent;
401
402 // The socket for the component to use for basing the grip off of instead of the motion controller
403 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "GripMotionController|CustomPivot")
404 FName CustomPivotComponentSocketName;
405
406 // If true then we will skip the pivot transform adjustment when gripping an object with the custom pivot
407 // This is here for legacy support for anyone not using "ConvertToControllerRelativeTransform".
408 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "GripMotionController|CustomPivot")
409 bool bSkipPivotTransformAdjustment;
410
411 // Set the custom pivot component, allows you to use remote grips easier
412 UFUNCTION(BlueprintCallable, Category = "GripMotionController|CustomPivot")
413 void SetCustomPivotComponent(USceneComponent * NewCustomPivotComponent, FName PivotSocketName = NAME_None);
414
415 // Set the custom pivot component, allows you to use remote grips easier
416 UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "GetPivotTransform"))
417 FTransform GetPivotTransform_BP();
418
419 // Set the custom pivot component, allows you to use remote grips easier
420 UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "GetPivotLocation"))
421 FVector GetPivotLocation_BP();
422
423 FORCEINLINE FTransform GetPivotTransform()
424 {
425 return CustomPivotComponent.IsValid() ? CustomPivotComponent->GetSocketTransform(CustomPivotComponentSocketName) : this->GetComponentTransform();
426 }
427
428 FORCEINLINE FVector GetPivotLocation()
429 {
430 return CustomPivotComponent.IsValid() ? CustomPivotComponent->GetSocketLocation(CustomPivotComponentSocketName) : this->GetComponentLocation();
431 }
432
433 // Increments with each grip, wraps back to 0 after max due to modulo operation
434 // I don't think that a 254 (126 total grips) grip index is going to be used up and allow duplicates unless
435 // someone does something crazy
436 uint8 GripIDIncrementer;
437
439 // INVALID_VRGRIP_ID is 0, so + 1 is 1
440 inline uint8 GetNextGripID(bool bIsLocalGrip)
442 // We are skipping index 0 to leave it for INVALID_GRIP_ID index;
443
444 if (!bIsLocalGrip) // We need to split them between 0-126 for gripped objects server side
446 if (GripIDIncrementer < 127)
447 GripIDIncrementer++;
448 else
449 GripIDIncrementer = (INVALID_VRGRIP_ID + 1);
451 return GripIDIncrementer;
453 else // And 128 - 254 for local grips client side, with half for server initiated and half for client
454 {
455
456 if (!IsServer())
457 {
458 if (GripIDIncrementer < 63)
459 GripIDIncrementer++;
460 else
461 GripIDIncrementer = (INVALID_VRGRIP_ID + 1);
462
463 return GripIDIncrementer + 128;
464 }
465 else
467 if (GripIDIncrementer < 63)
468 GripIDIncrementer++;
469 else
470 GripIDIncrementer = (INVALID_VRGRIP_ID + 1);
471
472 return GripIDIncrementer + 128 + 64;
474 }
475 }
476
477 // When possible I suggest that you use GetAllGrips/GetGrippedObjects instead of directly referencing this
478 UPROPERTY(BlueprintReadOnly, Replicated, Category = "GripMotionController", ReplicatedUsing = OnRep_GrippedObjects)
479 TArray<FBPActorGripInformation> GrippedObjects;
481 // When possible I suggest that you use GetAllGrips/GetGrippedObjects instead of directly referencing this
482 UPROPERTY(BlueprintReadOnly, Replicated, Category = "GripMotionController", ReplicatedUsing = OnRep_LocallyGrippedObjects)
483 TArray<FBPActorGripInformation> LocallyGrippedObjects;
484
485 // Local Grip TransactionalBuffer to store server sided grips that need to be emplaced into the local buffer
486 UPROPERTY(BlueprintReadOnly, Replicated, Category = "GripMotionController", ReplicatedUsing = OnRep_LocalTransaction)
487 TArray<FBPActorGripInformation> LocalTransactionBuffer;
489 // Locally Gripped Array functions
490
491 // Notify a client that their local grip was bad
492 UFUNCTION(Reliable, Client, Category = "GripMotionController")
493 void Client_NotifyInvalidLocalGrip(UObject * LocallyGrippedObject, uint8 GripID, bool bWasAGripConflict = false);
494
495 // Notify the server that we locally gripped something
496 UFUNCTION(Reliable, Server, WithValidation, Category = "GripMotionController")
497 void Server_NotifyLocalGripAddedOrChanged(const FBPActorGripInformation & newGrip);
498
499 // Notify the server that we changed some secondary attachment information
500 UFUNCTION(Reliable, Server, WithValidation)
501 void Server_NotifySecondaryAttachmentChanged(
502 uint8 GripID,
503 const FBPSecondaryGripInfo& SecondaryGripInfo);
504
505 // Notify the server that we changed some secondary attachment information
506 // This one specifically sends out the new relative location for a retain secondary grip
507 UFUNCTION(Reliable, Server, WithValidation)
508 void Server_NotifySecondaryAttachmentChanged_Retain(
509 uint8 GripID,
510 const FBPSecondaryGripInfo& SecondaryGripInfo, const FTransform_NetQuantize & NewRelativeTransform);
511
512 // Notify change on relative position editing as well, make RPCS callable in blueprint
513 // Notify the server that we locally gripped something
514 UFUNCTION(Reliable, Server, WithValidation)
515 void Server_NotifyLocalGripRemoved(uint8 GripID, const FTransform_NetQuantize &TransformAtDrop, FVector_NetQuantize100 AngularVelocity, FVector_NetQuantize100 LinearVelocity);
516
517 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|ClientAuth")
518 EVRClientAuthConflictResolutionMode ClientAuthConflictResolutionMethod;
519
520 UPROPERTY(BlueprintAssignable, Category = "Grip Events")
521 FVROnClientAuthGripConflict OnClientAuthGripConflict;
523 // Handle a server initiated grip
524 UFUNCTION(Reliable, Server, WithValidation, Category = "GripMotionController")
525 void Server_NotifyHandledTransaction(uint8 GripID);
526
527 // Enable this to send the TickGrip event every tick even for non custom grip types - has a slight performance hit
528 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController")
529 bool bAlwaysSendTickGrip;
530
531 // Clean up a grip that is "bad", object is being destroyed or was a bad destructible mesh
532 void CleanUpBadGrip(TArray<FBPActorGripInformation> &GrippedObjectsArray, int GripIndex, bool bReplicatedArray);
533 void CleanUpBadPhysicsHandles();
534
535 // Recreates a grip physics handle bodies
536 // If FullRecreate is false then it will only set the COM and actors, otherwise will re-init the entire grip
537 bool UpdatePhysicsHandle(uint8 GripID, bool bFullyRecreate = true);
538 bool UpdatePhysicsHandle(const FBPActorGripInformation & GripInfo, bool bFullyRecreate = true);
539
540 inline void NotifyGripTransformChanged(const FBPActorGripInformation & GripInfo)
541 {
542 if (OnGripTransformChanged.IsBound())
543 {
544 FBPActorGripInformation CurrentGrip;
546 GetGripByID(CurrentGrip, GripInfo.GripID, Result);
547 if (Result == EBPVRResultSwitch::OnSucceeded)
548 {
549 OnGripTransformChanged.Broadcast(CurrentGrip);
550 }
551 }
552 }
553
554 // Recreates a grip in situations where the collision type or movement replication type may have been changed
555 inline void ReCreateGrip(FBPActorGripInformation & GripInfo)
556 {
557 int HandleIndex = 0;
558 if (GetPhysicsGripIndex(GripInfo, HandleIndex))
559 {
560 DestroyPhysicsHandle(GripInfo);
561 }
562
563 // Grip Type or replication was changed
564 NotifyGrip(GripInfo, true);
565 }
566
567 // Handles variable state changes and specific actions on a grip replication
568 inline bool HandleGripReplication(FBPActorGripInformation & Grip, FBPActorGripInformation * OldGripInfo = nullptr)
569 {
571 {
572 // There appears to be a bug with TArray replication where if you replace an index with another value of that
573 // Index, it doesn't fully re-init the object, this is a workaround to re-zero non replicated variables
574 // when that happens.
576 }
578 // Ignore server down no rep grips, this is kind of unavoidable unless I make yet another list which I don't want to do
580 {
581 // skip init
583
584 // null ptr so this doesn't block grip operations
585 Grip.GrippedObject = nullptr;
586
587 // Set to paused so iteration skips it
588 Grip.bIsPaused = true;
589 }
591 if (!Grip.ValueCache.bWasInitiallyRepped) // Hasn't already been initialized
592 {
593 Grip.ValueCache.bWasInitiallyRepped = NotifyGrip(Grip); // Grip it
595 // Tick will keep checking from here on out locally
597 {
598 //UE_LOG(LogVRMotionController, Warning, TEXT("Replicated grip Notify grip failed, was grip called before the object was replicated to the client?"));
599 return false;
600 }
601
603 {
604 // Reset the secondary grip distance
606
607 if (FMath::IsNearlyZero(Grip.SecondaryGripInfo.LerpToRate)) // Zero, could use IsNearlyZero instead
609 else
610 {
613 }
614
615 if (Grip.GrippedObject && Grip.GrippedObject->IsValidLowLevelFast() && Grip.GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
616 {
617 SecondaryGripIDs.Add(Grip.GripID);
618 IVRGripInterface::Execute_OnSecondaryGrip(Grip.GrippedObject, this, Grip.SecondaryGripInfo.SecondaryAttachment, Grip);
619
620 TArray<UVRGripScriptBase*> GripScripts;
621 if (IVRGripInterface::Execute_GetGripScripts(Grip.GrippedObject, GripScripts))
622 {
623 for (UVRGripScriptBase* Script : GripScripts)
624 {
625 if (Script)
626 {
627 Script->OnSecondaryGrip(this, Grip.SecondaryGripInfo.SecondaryAttachment, Grip);
628 }
629 }
630 }
631 }
632
633 OnSecondaryGripAdded.Broadcast(Grip);
634 }
635 //Grip.ValueCache.bWasInitiallyRepped = true; // Set has been initialized
636 }
637 else if(OldGripInfo != nullptr) // Check for changes from cached information if we aren't skipping the delta check
638 {
639 // Manage lerp states
640 if ((OldGripInfo->SecondaryGripInfo.bHasSecondaryAttachment != Grip.SecondaryGripInfo.bHasSecondaryAttachment) ||
641 (OldGripInfo->SecondaryGripInfo.SecondaryAttachment != Grip.SecondaryGripInfo.SecondaryAttachment) ||
642 (!OldGripInfo->SecondaryGripInfo.SecondaryRelativeTransform.Equals(Grip.SecondaryGripInfo.SecondaryRelativeTransform)))
643 {
644 // Reset the secondary grip distance
646
647 if (FMath::IsNearlyZero(Grip.SecondaryGripInfo.LerpToRate)) // Zero, could use IsNearlyZero instead
649 else
650 {
651 // New lerp
656 }
657 else // Post Lerp
658 {
661 }
662 }
664 bool bSendReleaseEvent = ((!Grip.SecondaryGripInfo.bHasSecondaryAttachment && OldGripInfo->SecondaryGripInfo.bHasSecondaryAttachment) ||
665 ((Grip.SecondaryGripInfo.bHasSecondaryAttachment && OldGripInfo->SecondaryGripInfo.bHasSecondaryAttachment) &&
666 (OldGripInfo->SecondaryGripInfo.SecondaryAttachment != Grip.SecondaryGripInfo.SecondaryAttachment)));
667
668 bool bSendGripEvent = (Grip.SecondaryGripInfo.bHasSecondaryAttachment &&
669 (!OldGripInfo->SecondaryGripInfo.bHasSecondaryAttachment || (OldGripInfo->SecondaryGripInfo.SecondaryAttachment != Grip.SecondaryGripInfo.SecondaryAttachment)));
670
671 if (bSendReleaseEvent)
673 if (Grip.GrippedObject && Grip.GrippedObject->IsValidLowLevelFast() && Grip.GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
674 {
675 IVRGripInterface::Execute_OnSecondaryGripRelease(Grip.GrippedObject, this, OldGripInfo->SecondaryGripInfo.SecondaryAttachment, Grip);
676
677 TArray<UVRGripScriptBase*> GripScripts;
678 if (IVRGripInterface::Execute_GetGripScripts(Grip.GrippedObject, GripScripts))
679 {
680 for (UVRGripScriptBase* Script : GripScripts)
682 if (Script)
683 {
684 Script->OnSecondaryGripRelease(this, OldGripInfo->SecondaryGripInfo.SecondaryAttachment, Grip);
685 }
686 }
687 }
688 }
689
690 SecondaryGripIDs.Remove(Grip.GripID);
691 OnSecondaryGripRemoved.Broadcast(Grip);
692 }
694 if (bSendGripEvent)
695 {
696 if (Grip.GrippedObject && Grip.GrippedObject->IsValidLowLevelFast() && Grip.GrippedObject->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
697 {
698 SecondaryGripIDs.Add(Grip.GripID);
699 IVRGripInterface::Execute_OnSecondaryGrip(Grip.GrippedObject, this, Grip.SecondaryGripInfo.SecondaryAttachment, Grip);
700
701 TArray<UVRGripScriptBase*> GripScripts;
702 if (IVRGripInterface::Execute_GetGripScripts(Grip.GrippedObject, GripScripts))
703 {
704 for (UVRGripScriptBase* Script : GripScripts)
706 if (Script)
707 {
708 Script->OnSecondaryGrip(this, Grip.SecondaryGripInfo.SecondaryAttachment, Grip);
709 }
710 }
711 }
713
714 OnSecondaryGripAdded.Broadcast(Grip);
715 }
716 }
717
718 if (OldGripInfo->GripCollisionType != Grip.GripCollisionType ||
719 OldGripInfo->GripMovementReplicationSetting != Grip.GripMovementReplicationSetting ||
720 OldGripInfo->GrippedBoneName != Grip.GrippedBoneName ||
721 OldGripInfo->AdvancedGripSettings.PhysicsSettings.bUsePhysicsSettings != Grip.AdvancedGripSettings.PhysicsSettings.bUsePhysicsSettings
722 )
723 {
724 ReCreateGrip(Grip); // Need to re-create grip
725 }
726 else // If re-creating the grip anyway we don't need to do the below
728 bool bTransformChanged = !OldGripInfo->RelativeTransform.Equals(Grip.RelativeTransform);
729
730 // If physics settings got changed server side
731 if (!FMath::IsNearlyEqual(OldGripInfo->Stiffness, Grip.Stiffness) ||
732 !FMath::IsNearlyEqual(OldGripInfo->Damping, Grip.Damping) ||
733 OldGripInfo->AdvancedGripSettings.PhysicsSettings != Grip.AdvancedGripSettings.PhysicsSettings ||
734 bTransformChanged
736 {
737 UpdatePhysicsHandle(Grip);
738
739 if (bTransformChanged)
740 {
741 NotifyGripTransformChanged(Grip);
742 }
743 }
744 }
745 }
747 // Set caches now for next rep
748 Grip.ValueCache.CachedGripID = Grip.GripID;
749
750 return true;
751 }
752
753 inline void CheckTransactionBuffer()
754 {
755 if (LocalTransactionBuffer.Num())
756 {
757 for (int i = LocalTransactionBuffer.Num() - 1; i >= 0; --i)
758 {
759 if (LocalTransactionBuffer[i].ValueCache.bWasInitiallyRepped && LocalTransactionBuffer[i].GripID != LocalTransactionBuffer[i].ValueCache.CachedGripID)
760 {
761 // There appears to be a bug with TArray replication where if you replace an index with another value of that
762 // Index, it doesn't fully re-init the object, this is a workaround to re-zero non replicated variables
763 // when that happens.
764 LocalTransactionBuffer[i].ClearNonReppingItems();
765 }
766
767 if (!LocalTransactionBuffer[i].ValueCache.bWasInitiallyRepped && LocalTransactionBuffer[i].GrippedObject->IsValidLowLevelFast())
768 {
769 LocalTransactionBuffer[i].ValueCache.bWasInitiallyRepped = true;
770 LocalTransactionBuffer[i].ValueCache.CachedGripID = LocalTransactionBuffer[i].GripID;
771
772 int32 Index = LocallyGrippedObjects.Add(LocalTransactionBuffer[i]);
773
774 if (Index != INDEX_NONE)
775 {
776 NotifyGrip(LocallyGrippedObjects[Index]);
777 }
778
779 Server_NotifyHandledTransaction(LocalTransactionBuffer[i].GripID);
780 }
781 }
782 }
783 }
784
785 UFUNCTION()
786 virtual void OnRep_LocalTransaction(TArray<FBPActorGripInformation> OriginalArrayState) // Original array state is useless without full serialize, it just hold last delta
787 {
788 CheckTransactionBuffer();
789 }
790
791 UFUNCTION()
792 virtual void OnRep_GrippedObjects(TArray<FBPActorGripInformation> OriginalArrayState) // Original array state is useless without full serialize, it just hold last delta
793 {
794 // Need to think about how best to handle the simulating flag here, don't handle for now
795 // Check for removed gripped actors
796 // This might actually be better left as an RPC multicast
797
798 for (int i = GrippedObjects.Num() - 1; i >= 0; --i)
799 {
800 HandleGripReplication(GrippedObjects[i], OriginalArrayState.FindByKey(GrippedObjects[i].GripID));
801 }
802 }
803
804 UFUNCTION()
805 virtual void OnRep_LocallyGrippedObjects(TArray<FBPActorGripInformation> OriginalArrayState)
806 {
807 for (int i = LocallyGrippedObjects.Num() - 1; i >= 0; --i)
808 {
809 HandleGripReplication(LocallyGrippedObjects[i], OriginalArrayState.FindByKey(LocallyGrippedObjects[i].GripID));
810 }
811 }
812
813 UPROPERTY(BlueprintReadWrite, Category = "GripMotionController")
814 TArray<UPrimitiveComponent *> AdditionalLateUpdateComponents;
815
816 // Movement Replication
817 // Actor needs to be replicated for this to work
818
819 UPROPERTY(EditDefaultsOnly, ReplicatedUsing = OnRep_ReplicatedControllerTransform, Category = "GripMotionController|Networking")
820 FBPVRComponentPosRep ReplicatedControllerTransform;
821
822 FBPVRComponentPosRep MotionSampleUpdateBuffer[2];
823
824 FVector LastUpdatesRelativePosition;
825 FRotator LastUpdatesRelativeRotation;
826
827 bool bLerpingPosition;
828 bool bReppedOnce;
829
830 UFUNCTION()
831 virtual void OnRep_ReplicatedControllerTransform();
832
833 // Run the smoothing step
834 void RunNetworkedSmoothing(float DeltaTime);
835
836 // Rate to update the position to the server, 100htz is default (same as replication rate, should also hit every tick).
837 UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "GripMotionController|Networking", meta = (ClampMin = "0", UIMin = "0"))
838 float ControllerNetUpdateRate;
839
840 // Used in Tick() to accumulate before sending updates, didn't want to use a timer in this case, also used for remotes to lerp position
841 float ControllerNetUpdateCount;
842
843 // Whether to smooth (lerp) between ticks for the replicated motion, DOES NOTHING if update rate is larger than FPS!
844 UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "GripMotionController|Networking")
845 bool bSmoothReplicatedMotion;
846
847 // If true then we will use exponential smoothing with buffered correction
848 UPROPERTY(EditAnywhere, Category = "GripMotionController|Networking|Smoothing", meta = (editcondition = "bSmoothReplicatedMotion"))
849 bool bUseExponentialSmoothing = true;
850
851 // Timestep of smoothing translation
852 UPROPERTY(EditAnywhere, Category = "GripMotionController|Networking|Smoothing", meta = (editcondition = "bUseExponentialSmoothing"))
853 float InterpolationSpeed = 50.0f;
854
855 // Max distance to allow smoothing before snapping the remainder
856 UPROPERTY(EditAnywhere, Category = "GripMotionController|Networking|Smoothing", meta = (editcondition = "bUseExponentialSmoothing"))
857 float NetworkMaxSmoothUpdateDistance = 50.f;
858
859 // Max distance to allow smoothing before snapping entirely to the new position
860 UPROPERTY(EditAnywhere, Category = "GripMotionController|Networking|Smoothing", meta = (editcondition = "bUseExponentialSmoothing"))
861 float NetworkNoSmoothUpdateDistance = 100.f;
862
863 // Whether to replicate even if no tracking (FPS or test characters)
864 UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "GripMotionController|Networking")
865 bool bReplicateWithoutTracking;
866
867 // I'm sending it unreliable because it is being resent pretty often
868 UFUNCTION(Unreliable, Server, WithValidation)
869 void Server_SendControllerTransform(FBPVRComponentPosRep NewTransform);
870
871 // Pointer to an override to call from the owning character - this saves 7 bits a rep avoiding component IDs on the RPC
872 typedef void (AVRBaseCharacter::*VRBaseCharTransformRPC_Pointer)(FBPVRComponentPosRep NewTransform);
873 VRBaseCharTransformRPC_Pointer OverrideSendTransform;
874
875 // Need this as I can't think of another way for an actor component to make sure it isn't on the server
876 inline bool IsLocallyControlled() const
877 {
878 // I like epics new authority check more than mine
879 const AActor* MyOwner = GetOwner();
880 return MyOwner->HasLocalNetOwner();
881 //const APawn* MyPawn = Cast<APawn>(MyOwner);
882 //return MyPawn ? MyPawn->IsLocallyControlled() : (MyOwner && MyOwner->Role == ENetRole::ROLE_Authority);
883 }
884
885 // Returns if this is the owning connection for the motion controller
886 UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "IsLocallyControlled"))
887 bool BP_IsLocallyControlled();
888
889 // Checks if the controllers own is torn off on the network, used to skip some RPCS
890 inline bool IsTornOff() const
891 {
892 const AActor* MyOwner = GetOwner();
893 return MyOwner ? MyOwner->GetTearOff() : false;
894 }
895
896
897 inline bool IsServer() const
898 {
899 if (GEngine != nullptr && GWorld != nullptr)
900 {
901 return GEngine->GetNetMode(GWorld) < NM_Client;
902 }
903
904 return false;
905 }
906
907 // Drops a gripped object and sockets it to the given component at the given relative transform.
908 // *Note*: If both the parent and the child are simulating it also delays a single tick and then re-applies the relative transform.
909 // This is to avoid a race condition where we need to wait for the next physics update.
910 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
911 bool DropAndSocketObject(const FTransform_NetQuantize & RelativeTransformToParent, UObject * ObjectToDrop = nullptr, uint8 GripIDToDrop = 0, USceneComponent * SocketingParent = nullptr, FName OptionalSocketName = NAME_None, bool bWeldBodies = true);
912
913 // Drops a grip and sockets it to the given component at the given relative transform.
914 // *Note*: If both the parent and the child are simulating it also delays a single tick and then re-applies the relative transform.
915 // This is to avoid a race condition where we need to wait for the next physics update.
916 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
917 bool DropAndSocketGrip(const FBPActorGripInformation &GripToDrop, USceneComponent * SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize & RelativeTransformToParent, bool bWeldBodies = true);
918 bool DropAndSocketGrip_Implementation(const FBPActorGripInformation& GripToDrop, USceneComponent* SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize& RelativeTransformToParent, bool bWeldBodies = true, bool bSkipServerNotify = false);
919
920 // Notify the server about a new drop and socket
921 UFUNCTION(Reliable, Server, WithValidation, Category = "GripMotionController")
922 void Server_NotifyDropAndSocketGrip(uint8 GripID, USceneComponent * SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize & RelativeTransformToParent, bool bWeldBodies = true);
923
924 UFUNCTION(Reliable, NetMulticast)
925 void NotifyDropAndSocket(const FBPActorGripInformation &NewDrop, USceneComponent* SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize& RelativeTransformToParent, bool bWeldBodies = true);
926
927 void DropAndSocket_Implementation(const FBPActorGripInformation &NewDrop);
928 void Socket_Implementation(UObject * ObjectToSocket, bool bWasSimulating, USceneComponent * SocketingParent, FName OptionalSocketName, const FTransform_NetQuantize & RelativeTransformToParent, bool bWeldBodies = true);
929
930 // Keep a hard reference to the drop to avoid deletion errors
931 UPROPERTY()
932 TArray<UObject*> ObjectsWaitingForSocketUpdate;
933
934 // Resets the transform of a socketed grip 1 tick later, this is to avoid a race condition with simulating grips.
935 // Their constraint can change the transform before or after the attachment happens if the parent and the child are both simulating.
936 UFUNCTION()
937 void SetSocketTransform(UObject* ObjectToSocket, /*USceneComponent * SocketingParent,*/ const FTransform_NetQuantize RelativeTransformToParent/*, FName OptionalSocketName, bool bWeldBodies*/);
938
939 /* Auto grip any uobject that is/root is a primitive component and has the VR Grip Interface
940 these are stored in a Tarray that will prevent destruction of the object, you MUST ungrip an actor if you want to kill it
941 The WorldOffset is the transform that it will remain away from the controller, if you use the world position of the actor then it will grab
942 at the point of intersection.
943
944 If WorldOffsetIsRelative is true then it will not convert the transform from world space but will instead use that offset directly.
945 You could pass in a socket relative transform with this set for snapping or an empty transform to snap the object at its 0,0,0 point.
946
947 If you declare a valid OptionSnapToSocketName then it will instead snap the actor to the relative offset
948 location that the socket is to its parent actor.
949
950 It will only do this if the WorldOffset value is left default, if it is not, then it will treat this as the name of the slot
951 that you already have the transform for.
952
953 If you declare a valid OptionalBoneToGripName then it will grip that physics body with physics grips (It will expect a bone worldspace transform then,
954 if you pass in the normal actor/root component world space transform then the grip will not be positioned correctly).
955 */
956 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
957 bool GripObject(
958 UObject * ObjectToGrip,
959 const FTransform &WorldOffset,
960 bool bWorldOffsetIsRelative = false,
961 FName OptionalSnapToSocketName = NAME_None,
962 FName OptionalBoneToGripName = NAME_None,
966 float GripStiffness = 1500.0f,
967 float GripDamping = 200.0f, bool bIsSlotGrip = false);
968
969
970 // Auto drop any uobject that is/root is a primitive component and has the VR Grip Interface
971 // If an object is passed in it will attempt to drop it, otherwise it will attempt to find and drop the given grip id
972 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
973 bool DropObject(
974 UObject * ObjectToDrop = nullptr,
975 uint8 GripIdToDrop = 0,
976 bool bSimulate = false,
977 FVector OptionalAngularVelocity = FVector::ZeroVector,
978 FVector OptionalLinearVelocity = FVector::ZeroVector);
979
980 // Auto grip any uobject that is/root is a primitive component
981 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
982 bool GripObjectByInterface(UObject * ObjectToGrip, const FTransform &WorldOffset, bool bWorldOffsetIsRelative = false, FName OptionalBoneToGripName = NAME_None, FName OptionalSnapToSocketName = NAME_None, bool bIsSlotGrip = false);
983
984 // Auto drop any uobject that is/root is a primitive component and has the VR Grip Interface
985 // If an object is passed in it will attempt to drop it, otherwise it will attempt to find and drop the given grip id
986 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
987 bool DropObjectByInterface(UObject * ObjectToDrop = nullptr, uint8 GripIDToDrop = 0, FVector OptionalAngularVelocity = FVector::ZeroVector, FVector OptionalLinearVelocity = FVector::ZeroVector);
988
989 /* Grip an actor, these are stored in a Tarray that will prevent destruction of the object, you MUST ungrip an actor if you want to kill it
990 The WorldOffset is the transform that it will remain away from the controller, if you use the world position of the actor then it will grab
991 at the point of intersection.
992
993 If WorldOffsetIsRelative is true then it will not convert the transform from world space but will instead use that offset directly.
994 You could pass in a socket relative transform with this set for snapping or an empty transform to snap the object at its 0,0,0 point.
995
996 If you declare a valid OptionSnapToSocketName then it will instead snap the actor to the relative offset
997 location that the socket is to its parent actor.
998
999 It will only do this if the WorldOffset value is left default, if it is not, then it will treat this as the name of the slot
1000 that you already have the transform for.
1001
1002 If you declare a valid OptionalBoneToGripName then it will grip that physics body with physics grips (It will expect a bone worldspace transform then,
1003 if you pass in the normal actor/root component world space transform then the grip will not be positioned correctly).
1004 */
1005 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1006 bool GripActor(
1007 AActor* ActorToGrip,
1008 const FTransform &WorldOffset,
1009 bool bWorldOffsetIsRelative = false,
1010 FName OptionalSnapToSocketName = NAME_None,
1011 FName OptionalBoneToGripName = NAME_None,
1015 float GripStiffness = 1500.0f,
1016 float GripDamping = 200.0f,
1017 bool bIsSlotGrip = false);
1018
1019 // Drop a gripped actor
1020 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1021 bool DropActor(
1022 AActor* ActorToDrop,
1023 bool bSimulate,
1024 FVector OptionalAngularVelocity = FVector::ZeroVector,
1025 FVector OptionalLinearVelocity = FVector::ZeroVector
1026 );
1027
1028 // Grip a component
1029 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1030 bool GripComponent(
1031 UPrimitiveComponent* ComponentToGrip,
1032 const FTransform &WorldOffset, bool bWorldOffsetIsRelative = false,
1033 FName OptionalsnapToSocketName = NAME_None,
1034 FName OptionalBoneToGripName = NAME_None,
1038 float GripStiffness = 1500.0f,
1039 float GripDamping = 200.0f,
1040 bool bIsSlotGrip = false);
1041
1042 // Drop a gripped component
1043 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1044 bool DropComponent(
1045 UPrimitiveComponent* ComponentToDrop,
1046 bool bSimulate,
1047 FVector OptionalAngularVelocity = FVector::ZeroVector,
1048 FVector OptionalLinearVelocity = FVector::ZeroVector
1049 );
1050
1051 // Master function for dropping a grip
1052 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1053 bool DropGrip(
1054 const FBPActorGripInformation &Grip,
1055 bool bSimulate = false,
1056 FVector OptionalAngularVelocity = FVector::ZeroVector,
1057 FVector OptionalLinearVelocity = FVector::ZeroVector);
1058
1059 bool DropGrip_Implementation(
1060 const FBPActorGripInformation& Grip,
1061 bool bSimulate = false,
1062 FVector OptionalAngularVelocity = FVector::ZeroVector,
1063 FVector OptionalLinearVelocity = FVector::ZeroVector,
1064 bool bSkipNotify = false);
1065
1066 // No Longer replicated, called via on rep now instead.
1067 //UFUNCTION(Reliable, NetMulticast)
1068 bool NotifyGrip(FBPActorGripInformation &NewGrip, bool bIsReInit = false);
1069
1070 UFUNCTION(Reliable, NetMulticast)
1071 void NotifyDrop(const FBPActorGripInformation &NewDrop, bool bSimulate);
1072
1073 // Used so drop logic can be filtered
1074 void Drop_Implementation(const FBPActorGripInformation &NewDrop, bool bSimulate);
1076 // Get a grip by actor
1077 UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result"))
1078 void GetGripByActor(FBPActorGripInformation &Grip, AActor * ActorToLookForGrip, EBPVRResultSwitch &Result);
1079
1080 // Get a grip by component
1081 UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result"))
1082 void GetGripByComponent(FBPActorGripInformation &Grip, UPrimitiveComponent * ComponentToLookForGrip, EBPVRResultSwitch &Result);
1083
1084 // Gets a grip by object, will auto use ByComponent or ByActor
1085 UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result"))
1086 void GetGripByObject(FBPActorGripInformation &Grip, UObject * ObjectToLookForGrip, EBPVRResultSwitch &Result);
1087
1088 // Gets a grip by its grip ID *NOTE*: Grip IDs are only unique to their controller, do NOT use them as cross controller identifiers
1089 UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result"))
1090 void GetGripByID(FBPActorGripInformation &Grip, uint8 IDToLookForGrip, EBPVRResultSwitch &Result);
1091
1092 // Gets a grip by its grip ID *NOTE*: Grip IDs are only unique to their controller, do NOT use them as cross controller identifiers
1093 FBPActorGripInformation * GetGripPtrByID(uint8 IDToLookForGrip);
1094
1095 // Get the physics velocities of a grip
1096 UFUNCTION(BlueprintPure, Category = "GripMotionController")
1097 void GetPhysicsVelocities(const FBPActorGripInformation &Grip, FVector &AngularVelocity, FVector &LinearVelocity);
1098
1099 // Get the physics constraint force of a simulating grip
1100 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1101 bool GetPhysicsConstraintForce(const FBPActorGripInformation& Grip, FVector& AngularForce, FVector& LinearForce);
1102
1103 // Get the root components mass of a grip
1104 UFUNCTION(BlueprintPure, Category = "GripMotionController")
1105 void GetGripMass(const FBPActorGripInformation& Grip, float& Mass);
1106
1107 // Sets whether an active grip is paused or not (is not replicated by default as it is likely you will want to pass variables with this setting).
1108 // If you want it server authed you should RPC a bool down with any additional information (ie: attach location).
1109 UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result"))
1110 void SetGripPaused(
1111 const FBPActorGripInformation &Grip,
1113 bool bIsPaused = false,
1114 bool bNoConstraintWhenPaused = false
1115 );
1116
1117 // Sets whether an active hybrid grip is locked to its soft setting (is not replicated by default as it is likely you will want to pass variables with this setting).
1118 UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result"))
1119 void SetGripHybridLock(
1120 const FBPActorGripInformation& Grip,
1122 bool bIsLocked = false
1123 );
1125 // Sets the transform to stay at during pause
1126 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1127 void SetPausedTransform(
1129 const FTransform & PausedTransform,
1130 bool bTeleport = false
1131 );
1132
1133 // Set the Grip Collision Type of a grip, call server side if not a local grip
1134 UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result"))
1135 void SetGripCollisionType(
1136 const FBPActorGripInformation &Grip,
1137 EBPVRResultSwitch &Result,
1139 );
1140
1141
1142 // Set the late update setting of a grip, call server side if not a local grip
1143 UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result"))
1144 void SetGripLateUpdateSetting(
1150 // Set the relative transform of a grip, call server side if not a local grip
1151 // Can check HasGripAuthority to decide if callable locally
1152 UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result"))
1153 void SetGripRelativeTransform(
1154 const FBPActorGripInformation &Grip,
1155 EBPVRResultSwitch &Result,
1156 const FTransform & NewRelativeTransform
1157 );
1158
1159 // Set the addition transform of a grip, CALL LOCALLY, not server side, Addition transform is not replicated
1160 UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result"))
1161 void SetGripAdditionTransform(
1162 const FBPActorGripInformation &Grip,
1163 EBPVRResultSwitch &Result,
1164 const FTransform & NewAdditionTransform, bool bMakeGripRelative = false
1165 );
1166
1167 // Set the constraint stiffness and dampening of a grip, call server side if not a local grip
1168 // Can check HasGripAuthority to decide if callable locally
1169 UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result"))
1170 void SetGripStiffnessAndDamping(
1171 const FBPActorGripInformation &Grip,
1172 EBPVRResultSwitch &Result,
1173 float NewStiffness, float NewDamping, bool bAlsoSetAngularValues = false, float OptionalAngularStiffness = 0.0f, float OptionalAngularDamping = 0.0f
1174 );
1175
1176 // Used to convert an offset transform to grip relative, useful for storing an initial offset and then lerping back to 0 without re-calculating every tick
1177 UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "CreateGripRelativeAdditionTransform"))
1178 FTransform CreateGripRelativeAdditionTransform_BP(
1179 const FBPActorGripInformation &GripToSample,
1180 const FTransform & AdditionTransform,
1181 bool bGripRelative = false
1182 );
1183
1184 inline FTransform CreateGripRelativeAdditionTransform(
1185 const FBPActorGripInformation &GripToSample,
1186 const FTransform & AdditionTransform,
1187 bool bGripRelative = false
1189
1190
1191 // Checks if we have grip authority
1192 inline bool HasGripAuthority(const FBPActorGripInformation &Grip);
1193
1194 // Checks if we have grip authority over a given object
1195 inline bool HasGripAuthority(const UObject * ObjToCheck);
1196
1197 // Returns if we have grip authority (can call drop / grip on this grip)
1198 // Mostly for networked games as local grips are client authed and all others are server authed
1199 UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "HasGripAuthority"))
1200 bool BP_HasGripAuthority(const FBPActorGripInformation & Grip);
1201
1202 // Returns if we have grip authority (can call drop / grip on this grip)
1203 // Mostly for networked games as local grips are client authed and all others are server authed
1204 UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "HasGripAuthorityForObject"))
1205 bool BP_HasGripAuthorityForObject(const UObject* ObjToCheck);
1206
1207 // Checks if we should be handling the movement of a grip based on settings for it
1208 inline bool HasGripMovementAuthority(const FBPActorGripInformation & Grip);
1209
1210 // Returns if we have grip movement authority (we handle movement of the grip)
1211 // Mostly for networked games where ClientSide will be true for all and ServerSide will be true for server only
1212 UFUNCTION(BlueprintPure, Category = "GripMotionController", meta = (DisplayName = "HasGripMovementAuthority"))
1213 bool BP_HasGripMovementAuthority(const FBPActorGripInformation & Grip);
1214
1215 // Running the gripping logic in its own function as the main tick was getting bloated
1216 void TickGrip(float DeltaTime);
1217
1218 // Splitting logic into separate function
1219 void HandleGripArray(TArray<FBPActorGripInformation> &GrippedObjectsArray, const FTransform & ParentTransform, float DeltaTime, bool bReplicatedArray = false);
1220
1221 // Gets the world transform of a grip, modified by secondary grips, returns if it has a valid transform, if not then this tick will be skipped for the object
1222 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);
1223
1224 // Calculate component to world without the protected tag, doesn't set it, just returns it
1225 inline FTransform CalcControllerComponentToWorld(FRotator Orientation, FVector Position)
1226 {
1227 return this->CalcNewComponentToWorld(FTransform(Orientation, Position));
1228 }
1229
1230 // Converts a worldspace transform into being relative to this motion controller
1231 UFUNCTION(BlueprintPure, Category = "GripMotionController")
1232 FTransform ConvertToControllerRelativeTransform(const FTransform & InTransform);
1233
1234 // Creates a secondary grip relative transform
1235 UFUNCTION(BlueprintPure, Category = "GripMotionController")
1236 static FTransform ConvertToGripRelativeTransform(const FTransform& GrippedActorTransform, const FTransform & InTransform);
1237
1238 // Gets if the given object is held by this controller
1239 UFUNCTION(BlueprintPure, Category = "GripMotionController")
1240 bool GetIsObjectHeld(const UObject * ObjectToCheck);
1241
1242 // Gets if the given actor is held by this controller
1243 UFUNCTION(BlueprintPure, Category = "GripMotionController")
1244 bool GetIsHeld(const AActor * ActorToCheck);
1245
1246 // Gets if the given component is held by this controller
1247 UFUNCTION(BlueprintPure, Category = "GripMotionController")
1248 bool GetIsComponentHeld(const UPrimitiveComponent * ComponentToCheck);
1249
1250 // Gets if the given Component is a secondary attach point to a gripped actor
1251 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1252 bool GetIsSecondaryAttachment(const USceneComponent * ComponentToCheck, FBPActorGripInformation & Grip);
1253
1254 // Get if we have gripped objects, local or replicated
1255 UFUNCTION(BlueprintPure, Category = "GripMotionController")
1256 bool HasGrippedObjects();
1257
1258 // Get the first active and valid grip (local and remote auth both, priority remote)
1259 // Returns nullptr if there is none
1260 UFUNCTION(BlueprintCallable, meta = (Keywords = "Grip", DisplayName = "GetFirstActiveGrip", ScriptName = "GetFirstActiveGrip"), Category = "GripMotionController")
1261 bool K2_GetFirstActiveGrip(FBPActorGripInformation& FirstActiveGrip);
1262 FBPActorGripInformation* GetFirstActiveGrip();
1263
1264 // Get list of all gripped objects grip info structures (local and normal both)
1265 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1266 void GetAllGrips(TArray<FBPActorGripInformation> &GripArray);
1267
1268 // Get list of all gripped actors
1269 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1270 void GetGrippedActors(TArray<AActor*> &GrippedActorArray);
1271
1272 // Get list of all gripped objects
1273 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1274 void GetGrippedObjects(TArray<UObject*> &GrippedObjectsArray);
1275
1276 // Get list of all gripped components
1277 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1278 void GetGrippedComponents(TArray<UPrimitiveComponent*> &GrippedComponentsArray);
1279
1280 // After teleporting a pawn you NEED to call this, otherwise gripped objects will travel with a sweeped move and can get caught on geometry
1281 // The base Teleport() function automatically calls this already, but when you manually set location you should do it yourself.
1282 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1283 void PostTeleportMoveGrippedObjects();
1284
1285 bool bIsPostTeleport;
1286
1287 // Move a single gripped item back into position ignoring collision in the way
1288 // bTeleportPhysicsGrips says whether we should teleport any physics grips as well
1289 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1290 bool TeleportMoveGrippedActor(AActor * GrippedActorToMove, bool bTeleportPhysicsGrips = true);
1291
1292 // Move a single gripped item back into position ignoring collision in the way
1293 // bTeleportPhysicsGrips says whether we should teleport any physics grips as well
1294 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1295 bool TeleportMoveGrippedComponent(UPrimitiveComponent * ComponentToMove, bool bTeleportPhysicsGrips = true);
1296
1297 // Move a single grip back into position ignoring collision in the way
1298 // bTeleportPhysicsGrips says whether we should teleport any physics grips as well
1299 // bIsForPostTeleport says whether we shuld allow the DropOnTeleport logic to apply or not
1300 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1301 bool TeleportMoveGrip(UPARAM(ref)FBPActorGripInformation &Grip, bool bTeleportPhysicsGrips = true, bool bIsForPostTeleport = false);
1302 bool TeleportMoveGrip_Impl(FBPActorGripInformation &Grip, bool bTeleportPhysicsGrips, bool bIsForPostTeleport, FTransform & OptionalTransform);
1303
1304 // Moves all grips back into position immediately
1305 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1306 void TeleportMoveGrips(bool bTeleportPhysicsGrips = true, bool bIsForPostTeleport = false);
1307
1308 // Adds a secondary attachment point to the grip
1309 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1310 bool AddSecondaryAttachmentPoint(UObject * GrippedObjectToAddAttachment, USceneComponent * SecondaryPointComponent, const FTransform &OriginalTransform, bool bTransformIsAlreadyRelative = false, float LerpToTime = 0.25f, bool bIsSlotGrip = false, FName SecondarySlotName = NAME_None);
1311
1312 // Adds a secondary attachment point to the grip
1313 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1314 bool AddSecondaryAttachmentToGrip(const FBPActorGripInformation & GripToAddAttachment, USceneComponent * SecondaryPointComponent, const FTransform &OriginalTransform, bool bTransformIsAlreadyRelative = false, float LerpToTime = 0.25f, bool bIsSlotGrip = false, FName SecondarySlotName = NAME_None);
1315
1316 // Adds a secondary attachment point to the grip
1317 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1318 bool AddSecondaryAttachmentToGripByID(const uint8 GripID, USceneComponent* SecondaryPointComponent, const FTransform& OriginalTransform, bool bTransformIsAlreadyRelative = false, float LerpToTime = 0.25f, bool bIsSlotGrip = false, FName SecondarySlotName = NAME_None);
1319
1320 // Removes a secondary attachment point from a grip
1321 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1322 bool RemoveSecondaryAttachmentPoint(UObject * GrippedObjectToRemoveAttachment, float LerpToTime = 0.25f);
1323
1324 // Removes a secondary attachment point from a grip
1325 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1326 bool RemoveSecondaryAttachmentFromGrip(const FBPActorGripInformation & GripToRemoveAttachment, float LerpToTime = 0.25f);
1327
1328 // Removes a secondary attachment point from a grip
1329 UFUNCTION(BlueprintCallable, Category = "GripMotionController")
1330 bool RemoveSecondaryAttachmentFromGripByID(const uint8 GripID = 0, float LerpToTime = 0.25f);
1331
1332 // If this is true the controller will always attempt to get the current tracking information, regardless of it TrackingStatus is Untracked or not
1333 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController")
1334 bool bIgnoreTrackingStatus;
1335
1336 // This is for testing, setting it to true allows you to test grip with a non VR enabled pawn
1337 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController")
1338 bool bUseWithoutTracking;
1339
1340 bool CheckComponentWithSweep(UPrimitiveComponent * ComponentToCheck, FVector Move, FRotator newOrientation, bool bSkipSimulatingComponents/*, bool & bHadBlockingHitOut*/);
1341
1342 // For physics handle operations
1343 void OnGripMassUpdated(FBodyInstance* GripBodyInstance);
1344 bool SetUpPhysicsHandle(const FBPActorGripInformation &NewGrip, TArray<UVRGripScriptBase*> * GripScripts = nullptr);
1345 bool DestroyPhysicsHandle(const FBPActorGripInformation &Grip, bool bSkipUnregistering = false);
1346 void UpdatePhysicsHandleTransform(const FBPActorGripInformation &GrippedActor, const FTransform& NewTransform);
1347 bool SetGripConstraintStiffnessAndDamping(const FBPActorGripInformation *Grip, bool bUseHybridMultiplier = false);
1348 bool GetPhysicsJointLength(const FBPActorGripInformation &GrippedActor, UPrimitiveComponent * rootComp, FVector & LocOut);
1349
1350 TArray<FBPActorPhysicsHandleInformation> PhysicsGrips;
1351 FBPActorPhysicsHandleInformation * GetPhysicsGrip(const FBPActorGripInformation & GripInfo);
1352 FBPActorPhysicsHandleInformation * GetPhysicsGrip(const uint8 GripID);
1353 bool GetPhysicsGripIndex(const FBPActorGripInformation & GripInfo, int & index);
1354 FBPActorPhysicsHandleInformation * CreatePhysicsGrip(const FBPActorGripInformation & GripInfo);
1355 bool DestroyPhysicsHandle(FBPActorPhysicsHandleInformation * HandleInfo);
1356 bool PausePhysicsHandle(FBPActorPhysicsHandleInformation* HandleInfo);
1357 bool UnPausePhysicsHandle(FBPActorGripInformation& GripInfo, FBPActorPhysicsHandleInformation* HandleInfo);
1358
1359 // Gets the advanced physics handle settings
1360 UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "GetPhysicsHandleSettings"))
1361 bool GetPhysicsHandleSettings(UPARAM(ref)const FBPActorGripInformation & Grip, FBPAdvancedPhysicsHandleSettings& PhysicsHandleSettingsOut);
1362
1363 // Sets the advanced physics handle settings, also automatically updates it
1364 UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "SetPhysicsHandleSettings"))
1365 bool SetPhysicsHandleSettings(UPARAM(ref)const FBPActorGripInformation& Grip, UPARAM(ref) const FBPAdvancedPhysicsHandleSettings& PhysicsHandleSettingsIn);
1366
1367 // Creates a physics handle for this grip
1368 UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "SetUpPhysicsHandle"))
1369 bool SetUpPhysicsHandle_BP(UPARAM(ref)const FBPActorGripInformation &Grip);
1370
1371 // Destroys a physics handle for this grip
1372 UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "DestroyPhysicsHandle"))
1373 bool DestroyPhysicsHandle_BP(UPARAM(ref)const FBPActorGripInformation &Grip);
1374
1375 // Re-creates a physics handle for this grip
1376 // If bFullyRecreate is true then it will set all of the handle properties, if not then it will only reset the physics actors and COM positions
1377 UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "UpdatePhysicsHandle"))
1378 bool UpdatePhysicsHandle_BP(UPARAM(ref)const FBPActorGripInformation& Grip, bool bFullyRecreate = true);
1379
1380 // Update the location of the physics handle
1381 UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "UpdatePhysicsHandleTransform"))
1382 void UpdatePhysicsHandleTransform_BP(UPARAM(ref)const FBPActorGripInformation &GrippedActor, UPARAM(ref)const FTransform& NewTransform);
1383
1384 // Get the grip distance of either the physics handle if there is one, or the difference from the hand to the root component if there isn't
1385 UFUNCTION(BlueprintCallable, Category = "GripMotionController|Custom", meta = (DisplayName = "GetGripDistance"))
1386 bool GetGripDistance_BP(UPARAM(ref)FBPActorGripInformation &Grip, FVector ExpectedLocation, float & CurrentDistance);
1387
1389 virtual bool GripPollControllerState(FVector& Position, FRotator& Orientation, float WorldToMetersScale);
1390
1392 bool bTracked;
1393
1399 UFUNCTION(BlueprintPure, Category = "GripMotionController")
1400 bool GripControllerIsTracked() const;
1401
1406 UFUNCTION(BlueprintCallable, Category = "GripMotionController", meta = (ExpandEnumAsExecs = "Result"))
1407 void GetControllerDeviceID(FXRDeviceId & DeviceID, EBPVRResultSwitch &Result, bool bCheckOpenVROnly = false);
1408
1410 bool bHasAuthority;
1411
1412private:
1414 //bool bIsServer;
1415
1418 {
1419
1420 // #TODO: 4.18 - Uses an auto register base now, revise declaration and implementation
1421 public:
1422 FGripViewExtension(const FAutoRegister& AutoRegister, UGripMotionControllerComponent* InMotionControllerComponent);
1423
1424 virtual ~FGripViewExtension() {}
1425
1427 virtual void SetupViewFamily(FSceneViewFamily& InViewFamily) override {}
1428 virtual void SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView) override {}
1429 virtual void BeginRenderViewFamily(FSceneViewFamily& InViewFamily) override;
1430 virtual void PreRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) override {}
1431 virtual void PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) override;
1432 virtual void LateLatchingViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) override;
1433
1434 virtual int32 GetPriority() const override { return -10; }
1435
1436 private:
1437 friend class UGripMotionControllerComponent;
1438
1440 UGripMotionControllerComponent* MotionControllerComponent;
1441
1442 FExpandedLateUpdateManager LateUpdate;
1443 };
1444 TSharedPtr< FGripViewExtension, ESPMode::ThreadSafe > GripViewExtension;
1445
1446};
1447
1449 const FBPActorGripInformation &GripToSample,
1450 const FTransform & AdditionTransform,
1451 bool bGripRelative
1452)
1453{
1454
1455 FTransform FinalTransform;
1456
1457 if (bGripRelative)
1458 {
1459 FinalTransform = FTransform(AdditionTransform.GetRotation(), GripToSample.RelativeTransform.GetRotation().RotateVector(AdditionTransform.GetLocation()), AdditionTransform.GetScale3D());
1460 }
1461 else
1462 {
1463 const FTransform PivotToWorld = FTransform(FQuat::Identity, GripToSample.RelativeTransform.GetLocation());
1464 const FTransform WorldToPivot = FTransform(FQuat::Identity, -GripToSample.RelativeTransform.GetLocation());
1465
1466 // Create a transform from it
1467 FTransform RotationOffsetTransform(AdditionTransform.GetRotation(), FVector::ZeroVector);
1468 FinalTransform = FTransform(FQuat::Identity, AdditionTransform.GetLocation(), AdditionTransform.GetScale3D()) * WorldToPivot * RotationOffsetTransform * PivotToWorld;
1469 }
1470
1471 return FinalTransform;
1472}
1473
1475{
1480 {
1481 return true;
1482 }
1483
1484 return false;
1485}
1486
1487bool inline UGripMotionControllerComponent::HasGripAuthority(const UObject * ObjToCheck)
1488{
1489 if (!ObjToCheck)
1490 return false;
1491
1492 // If it isn't interfaced and we are the server, then allow gripping it
1493 if (!ObjToCheck->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()) && IsServer())
1494 return true;
1495
1496 // I know that it is bad practice to const_cast here, but I want the object to be passed in const
1497 EGripMovementReplicationSettings MovementRepType = IVRGripInterface::Execute_GripMovementReplicationType(const_cast<UObject*>(ObjToCheck));
1498
1503 {
1504 return true;
1505 }
1506
1507 return false;
1508}
1509
1511{
1512 if (IsServer())
1513 {
1514 return true;
1515 }
1516 else
1517 {
1521 {
1522 return true;
1523 }
1525 {
1526 return false;
1527 }
1528
1529 // Use original movement type is overridden when initializing the grip and shouldn't happen
1531 }
1532
1533 return false;
1534}
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FiveParams(FVROnControllerSocketSignature, const FBPActorGripInformation &, GripInformation, const USceneComponent *, NewParentComp, FName, OptionalSocketName, FTransform, RelativeTransformToParent, bool, bWeldingBodies)
DECLARE_LOG_CATEGORY_EXTERN(LogVRMotionController, Log, All)
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FVROnControllerTeleportedGripsSignature)
DECLARE_STATS_GROUP(TEXT("TICKGrip"), STATGROUP_TickGrip, STATCAT_Advanced)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FVRGripControllerOnTrackingEventSignature, const ETrackingStatus &, NewTrackingStatus)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FVROnControllerDropSignature, const FBPActorGripInformation &, GripInformation, bool, bWasSocketed)
EGripMovementReplicationSettings
UENUM(Blueprintable)
EBPVRResultSwitch
UENUM()
EGripCollisionType
UENUM(Blueprintable)
EVRVelocityType
UENUM(BlueprintType)
#define INVALID_VRGRIP_ID
EGripLateUpdateSettings
UENUM(Blueprintable)
EVRClientAuthConflictResolutionMode
UENUM(BlueprintType)
virtual void PreRenderView_RenderThread(FRHICommandListImmediate &RHICmdList, FSceneView &InView) override
virtual void SetupViewFamily(FSceneViewFamily &InViewFamily) override
virtual void SetupView(FSceneViewFamily &InViewFamily, FSceneView &InView) override
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = MotionController)
void Server_NotifySecondaryAttachmentChanged_Retain(uint8 GripID, const FBPSecondaryGripInfo &SecondaryGripInfo, const FTransform_NetQuantize &NewRelativeTransform)
UFUNCTION(Reliable, Server, WithValidation)
bool bSmoothHandTracking
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Smoothing")
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()
FVROnControllerGripSignature OnGripTransformChanged
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
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 bAlwaysSendTickGrip
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController")
bool bLimitMinHeight
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
bool bReplicateWithoutTracking
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "GripMotionController|Networking")
bool bOffsetByControllerProfile
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController")
FBPEuroLowPassFilterTrans EuroSmoothingParams
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Smoothing")
void NotifyGripTransformChanged(const FBPActorGripInformation &GripInfo)
bool bSmoothWithEuroLowPassFunction
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Smoothing")
TWeakObjectPtr< AVRBaseCharacter > AttachChar
UPROPERTY()
bool bScaleTracking
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
TArray< FBPActorGripInformation > LocalTransactionBuffer
UPROPERTY(BlueprintReadOnly, Replicated, Category = "GripMotionController", ReplicatedUsing = OnRep_L...
virtual void OnRep_LocalTransaction(TArray< FBPActorGripInformation > OriginalArrayState)
UFUNCTION()
bool HasGripAuthority(const FBPActorGripInformation &Grip)
bool bSkipPivotTransformAdjustment
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "GripMotionController|CustomPivot")
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 Server_SendControllerTransform(FBPVRComponentPosRep NewTransform)
UFUNCTION(Unreliable, Server, WithValidation)
void Server_NotifyLocalGripRemoved(uint8 GripID, const FTransform_NetQuantize &TransformAtDrop, FVector_NetQuantize100 AngularVelocity, FVector_NetQuantize100 LinearVelocity)
UFUNCTION(Reliable, Server, WithValidation)
virtual void OnRep_GrippedObjects(TArray< FBPActorGripInformation > OriginalArrayState)
UFUNCTION()
void Server_NotifyLocalGripAddedOrChanged(const FBPActorGripInformation &newGrip)
UFUNCTION(Reliable, Server, WithValidation, Category = "GripMotionController")
FVROnControllerDropSignature OnDroppedObject
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
void Client_NotifyInvalidLocalGrip(UObject *LocallyGrippedObject, uint8 GripID, bool bWasAGripConflict=false)
UFUNCTION(Reliable, Client, Category = "GripMotionController")
bool bUseWithoutTracking
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController")
FVROnControllerGripSignature OnLerpToHandFinished
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
TArray< FBPActorGripInformation > GrippedObjects
UPROPERTY(BlueprintReadOnly, Replicated, Category = "GripMotionController", ReplicatedUsing = OnRep_G...
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")
float ControllerNetUpdateRate
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "GripMotionController|Networking",...
bool bOffsetByHMD
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
FTransform CalcControllerComponentToWorld(FRotator Orientation, FVector Position)
void Server_NotifyHandledTransaction(uint8 GripID)
UFUNCTION(Reliable, Server, WithValidation, Category = "GripMotionController")
FVRGripControllerOnTrackingEventSignature OnTrackingChanged
UPROPERTY(BlueprintAssignable, Category = "GripMotionController")
float MinimumHeight
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking",...
bool bIgnoreTrackingStatus
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController")
FVRGripControllerOnGripOutOfRange OnGripOutOfRange
UPROPERTY(BlueprintAssignable, Category = "GripMotionController")
FVector TrackingScaler
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking",...
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)
bool bConstrainToPivot
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced")
TWeakObjectPtr< USceneComponent > CustomPivotComponent
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "GripMotionController|CustomPivot")
EVRClientAuthConflictResolutionMode ClientAuthConflictResolutionMethod
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|ClientAuth")
VRBaseCharTransformRPC_Pointer OverrideSendTransform
FVRGripControllerOnProfileTransformChanged OnControllerProfileTransformChanged
UPROPERTY(BlueprintAssignable, Category = "GripMotionController")
TSharedPtr< FGripViewExtension, ESPMode::ThreadSafe > GripViewExtension
bool bProjectNonSimulatingGrips
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "GripMotionController|Advanced")
float MaximumHeight
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking",...
FVROnControllerSocketSignature OnSocketingObject
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
FVROnClientAuthGripConflict OnClientAuthGripConflict
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
FGripComponentEndPhysicsTickFunction EndPhysicsTickFunction
FVROnControllerGripSignature OnSecondaryGripAdded
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
bool HasGripMovementAuthority(const FBPActorGripInformation &Grip)
FName CustomPivotComponentSocketName
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "GripMotionController|CustomPivot")
TArray< UPrimitiveComponent * > AdditionalLateUpdateComponents
UPROPERTY(BlueprintReadWrite, Category = "GripMotionController")
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 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",...
virtual void OnRep_LocallyGrippedObjects(TArray< FBPActorGripInformation > OriginalArrayState)
UFUNCTION()
FVROnControllerGripSignature OnGrippedObject
UPROPERTY(BlueprintAssignable, Category = "Grip Events")
UCLASS(NotBlueprintable, BlueprintType, EditInlineNew, DefaultToInstanced, Abstract,...
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
FBPAdvGripSettings AdvancedGripSettings
UPROPERTY(BlueprintReadOnly, Category = "Settings")
bool bIsPaused
UPROPERTY(BlueprintReadWrite, NotReplicated, Category = "Settings")
struct FBPActorGripInformation::FGripValueCache ValueCache
FTransform_NetQuantize RelativeTransform
UPROPERTY(BlueprintReadWrite, Category = "Settings")
float Stiffness
UPROPERTY(BlueprintReadOnly, Category = "Settings")
FBPSecondaryGripInfo SecondaryGripInfo
UPROPERTY(BlueprintReadOnly, Category = "Settings")
EGripCollisionType GripCollisionType
UPROPERTY(BlueprintReadOnly, Category = "Settings")
UObject * GrippedObject
UPROPERTY(BlueprintReadOnly, Category = "Settings")
uint8 GripID
UPROPERTY(BlueprintReadOnly, Category = "Settings")
FName GrippedBoneName
UPROPERTY(BlueprintReadWrite, Category = "Settings")
EGripMovementReplicationSettings GripMovementReplicationSetting
UPROPERTY(BlueprintReadOnly, Category = "Settings")
float Damping
UPROPERTY(BlueprintReadOnly, Category = "Settings")
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
bool bUsePhysicsSettings
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PhysicsSettings")
FBPAdvGripPhysicsSettings PhysicsSettings
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AdvancedGripSettings")
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
USceneComponent * SecondaryAttachment
UPROPERTY(BlueprintReadOnly, Category = "SecondaryGripInfo")
EGripLerpState GripLerpState
float LerpToRate
UPROPERTY()
float SecondaryGripDistance
UPROPERTY(BlueprintReadOnly, NotReplicated, Category = "SecondaryGripInfo")
bool bHasSecondaryAttachment
UPROPERTY(BlueprintReadOnly, Category = "SecondaryGripInfo")
FTransform_NetQuantize SecondaryRelativeTransform
UPROPERTY(BlueprintReadOnly, Category = "SecondaryGripInfo")
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 = ...