A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
VRRootComponent.cpp
Go to the documentation of this file.
1// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
2
3#include "VRRootComponent.h"
4//#include "Runtime/Engine/Private/EnginePrivate.h"
5#include "WorldCollision.h"
6#include "PhysicsPublic.h"
7#include "DrawDebugHelpers.h"
8#include "IHeadMountedDisplay.h"
9#include "VRCharacter.h"
10#include "Algo/Copy.h"
11
12#if PHYSICS_INTERFACE_PHYSX
13//#include "PhysXSupport.h"
14#endif // WITH_PHYSX
15
16
17#include "Components/PrimitiveComponent.h"
18
19DEFINE_LOG_CATEGORY(LogVRRootComponent);
20#define LOCTEXT_NAMESPACE "VRRootComponent"
21
22DECLARE_CYCLE_STAT(TEXT("VRRootMovement"), STAT_VRRootMovement, STATGROUP_VRRootComponent);
23DECLARE_CYCLE_STAT(TEXT("PerformOverlapQueryVR Time"), STAT_PerformOverlapQueryVR, STATGROUP_VRRootComponent);
24DECLARE_CYCLE_STAT(TEXT("UpdateOverlapsVRRoot Time"), STAT_UpdateOverlapsVRRoot, STATGROUP_VRRootComponent);
25
26typedef TArray<const FOverlapInfo*, TInlineAllocator<8>> TInlineOverlapPointerArray;
27
28// Helper to see if two components can possibly generate overlaps with each other.
29FORCEINLINE_DEBUGGABLE static bool CanComponentsGenerateOverlap(const UPrimitiveComponent* MyComponent, /*const*/ UPrimitiveComponent* OtherComp)
30{
31 return OtherComp
32 && OtherComp->GetGenerateOverlapEvents()
33 && MyComponent
34 && MyComponent->GetGenerateOverlapEvents()
35 && MyComponent->GetCollisionResponseToComponent(OtherComp) == ECR_Overlap;
36}
37
38// Predicate to identify components from overlaps array that can overlap
40{
41 FPredicateFilterCanOverlap(const UPrimitiveComponent& OwningComponent)
42 : MyComponent(OwningComponent)
43 {
44 }
45
46 bool operator() (const FOverlapInfo& Info) const
47 {
48 return CanComponentsGenerateOverlap(&MyComponent, Info.OverlapInfo.GetComponent());
49 }
50
51private:
52 const UPrimitiveComponent& MyComponent;
53};
54
55// Predicate to remove components from overlaps array that can no longer overlap
57{
58 FPredicateFilterCannotOverlap(const UPrimitiveComponent& OwningComponent)
59 : MyComponent(OwningComponent)
60 {
61 }
62
63 bool operator() (const FOverlapInfo& Info) const
64 {
65 return !CanComponentsGenerateOverlap(&MyComponent, Info.OverlapInfo.GetComponent());
66 }
67
68private:
69 const UPrimitiveComponent& MyComponent;
70};
71
72// Helper to initialize an array to point to data members in another array.
73template <class ElementType, class AllocatorType1, class AllocatorType2>
74FORCEINLINE_DEBUGGABLE static void GetPointersToArrayData(TArray<const ElementType*, AllocatorType1>& Pointers, const TArray<ElementType, AllocatorType2>& DataArray)
75{
76 const int32 NumItems = DataArray.Num();
77 Pointers.SetNumUninitialized(NumItems);
78 for (int32 i = 0; i < NumItems; i++)
79 {
80 Pointers[i] = &(DataArray[i]);
81 }
82}
83
84template <class ElementType, class AllocatorType1>
85FORCEINLINE_DEBUGGABLE static void GetPointersToArrayData(TArray<const ElementType*, AllocatorType1>& Pointers, const TArrayView<const ElementType>& DataArray)
86{
87 const int32 NumItems = DataArray.Num();
88 Pointers.SetNumUninitialized(NumItems);
89 for (int32 i = 0; i < NumItems; i++)
90 {
91 Pointers[i] = &(DataArray[i]);
92 }
93}
94
95// Helper to initialize an array to point to data members in another array which satisfy a predicate.
96template <class ElementType, class AllocatorType1, class AllocatorType2, typename PredicateT>
97FORCEINLINE_DEBUGGABLE static void GetPointersToArrayDataByPredicate(TArray<const ElementType*, AllocatorType1>& Pointers, const TArray<ElementType, AllocatorType2>& DataArray, PredicateT Predicate)
98{
99 Pointers.Reserve(Pointers.Num() + DataArray.Num());
100 for (const ElementType& Item : DataArray)
101 {
102 if (Invoke(Predicate, Item))
103 {
104 Pointers.Add(&Item);
105 }
106 }
107}
108
109template <class ElementType, class AllocatorType1, typename PredicateT>
110FORCEINLINE_DEBUGGABLE static void GetPointersToArrayDataByPredicate(TArray<const ElementType*, AllocatorType1>& Pointers, const TArrayView<const ElementType>& DataArray, PredicateT Predicate)
111{
112 Pointers.Reserve(Pointers.Num() + DataArray.Num());
113 for (const ElementType& Item : DataArray)
114 {
115 if (Invoke(Predicate, Item))
116 {
117 Pointers.Add(&Item);
118 }
119 }
120}
121
122static int32 bEnableFastOverlapCheck = 1;
123
124// Returns true if we should check the GetGenerateOverlapEvents() flag when gathering overlaps, otherwise we'll always just do it.
125static bool ShouldCheckOverlapFlagToQueueOverlaps(const UPrimitiveComponent& ThisComponent)
126{
127 const FScopedMovementUpdate* CurrentUpdate = ThisComponent.GetCurrentScopedMovement();
128 if (CurrentUpdate)
129 {
130 return CurrentUpdate->RequiresOverlapsEventFlag();
131 }
132 // By default we require the GetGenerateOverlapEvents() to queue up overlaps, since we require it to trigger events.
133 return true;
134}
135
136// LOOKING_FOR_PERF_ISSUES
137#define PERF_MOVECOMPONENT_STATS 0
138
140{
141 //static const FText MobilityWarnText = LOCTEXT("InvalidMove", "move");
142 static const FName MoveComponentName(TEXT("MoveComponent"));
143 static const FName UpdateOverlapsName(TEXT("UpdateOverlaps"));
144}
145
146// Predicate to determine if an overlap is with a certain AActor.
148{
150 : MyOwnerPtr(&Owner)
151 {
152 }
153
154 bool operator() (const FOverlapInfo& Info)
155 {
156 // MyOwnerPtr is always valid, so we don't need the IsValid() checks in the WeakObjectPtr comparison operator.
157 return MyOwnerPtr.HasSameIndexAndSerialNumber(Info.OverlapInfo.Actor);
158 }
159
160private:
161 const TWeakObjectPtr<const AActor> MyOwnerPtr;
162};
163
164// Predicate to determine if an overlap is *NOT* with a certain AActor.
166{
168 : MyOwnerPtr(&Owner)
169 {
170 }
171
172 bool operator() (const FOverlapInfo& Info)
173 {
174 // MyOwnerPtr is always valid, so we don't need the IsValid() checks in the WeakObjectPtr comparison operator.
175 return !MyOwnerPtr.HasSameIndexAndSerialNumber(Info.OverlapInfo.Actor);
176 }
177
178private:
179 const TWeakObjectPtr<const AActor> MyOwnerPtr;
180};
181
182/*
183* Predicate for comparing FOverlapInfos when exact weak object pointer index/serial numbers should match, assuming one is not null and not invalid.
184* Compare to operator== for WeakObjectPtr which does both HasSameIndexAndSerialNumber *and* IsValid() checks on both pointers.
185*/
187{
188 FFastOverlapInfoCompare(const FOverlapInfo& BaseInfo)
189 : MyBaseInfo(BaseInfo)
190 {
191 }
192
193 bool operator() (const FOverlapInfo& Info)
194 {
195 return MyBaseInfo.OverlapInfo.Component.HasSameIndexAndSerialNumber(Info.OverlapInfo.Component)
196 && MyBaseInfo.GetBodyIndex() == Info.GetBodyIndex();
197 }
198
199 bool operator() (const FOverlapInfo* Info)
200 {
201 return MyBaseInfo.OverlapInfo.Component.HasSameIndexAndSerialNumber(Info->OverlapInfo.Component)
202 && MyBaseInfo.GetBodyIndex() == Info->GetBodyIndex();
203 }
204
205private:
206 const FOverlapInfo& MyBaseInfo;
207
208};
209
210
211// Helper for finding the index of an FOverlapInfo in an Array using the FFastOverlapInfoCompare predicate, knowing that at least one overlap is valid (non-null).
212template<class AllocatorType>
213FORCEINLINE_DEBUGGABLE int32 IndexOfOverlapFast(const TArray<FOverlapInfo, AllocatorType>& OverlapArray, const FOverlapInfo& SearchItem)
214{
215 return OverlapArray.IndexOfByPredicate(FFastOverlapInfoCompare(SearchItem));
216}
217
218// Version that works with arrays of pointers and pointers to search items.
219template<class AllocatorType>
220FORCEINLINE_DEBUGGABLE int32 IndexOfOverlapFast(const TArray<const FOverlapInfo*, AllocatorType>& OverlapPtrArray, const FOverlapInfo* SearchItem)
221{
222 return OverlapPtrArray.IndexOfByPredicate(FFastOverlapInfoCompare(*SearchItem));
223}
224
225// Helper for adding an FOverlapInfo uniquely to an Array, using IndexOfOverlapFast and knowing that at least one overlap is valid (non-null).
226template<class AllocatorType>
227FORCEINLINE_DEBUGGABLE void AddUniqueOverlapFast(TArray<FOverlapInfo, AllocatorType>& OverlapArray, FOverlapInfo& NewOverlap)
228{
229 if (IndexOfOverlapFast(OverlapArray, NewOverlap) == INDEX_NONE)
230 {
231 OverlapArray.Add(NewOverlap);
232 }
233}
234
235template<class AllocatorType>
236FORCEINLINE_DEBUGGABLE void AddUniqueOverlapFast(TArray<FOverlapInfo, AllocatorType>& OverlapArray, FOverlapInfo&& NewOverlap)
237{
238 if (IndexOfOverlapFast(OverlapArray, NewOverlap) == INDEX_NONE)
239 {
240 OverlapArray.Add(NewOverlap);
241 }
242}
243
244static void PullBackHit(FHitResult& Hit, const FVector& Start, const FVector& End, const float Dist)
245{
246 const float DesiredTimeBack = FMath::Clamp(0.1f, 0.1f / Dist, 1.f / Dist) + 0.001f;
247 Hit.Time = FMath::Clamp(Hit.Time - DesiredTimeBack, 0.f, 1.f);
248}
249
250static bool ShouldIgnoreHitResult(const UWorld* InWorld, bool bAllowSimulatingCollision, FHitResult const& TestHit, FVector const& MovementDirDenormalized, const AActor* MovingActor, EMoveComponentFlags MoveFlags)
251{
252 if (TestHit.bBlockingHit)
253 {
254 // VR Pawns need to totally ignore simulating components with movement to prevent sickness
255 if (!bAllowSimulatingCollision && TestHit.Component.IsValid() && TestHit.Component->IsSimulatingPhysics())
256 return true;
257
258 // check "ignore bases" functionality
259 if ((MoveFlags & MOVECOMP_IgnoreBases) && MovingActor) //we let overlap components go through because their overlap is still needed and will cause beginOverlap/endOverlap events
260 {
261 // ignore if there's a base relationship between moving actor and hit actor
262 AActor const* const HitActor = TestHit.GetActor();
263 if (HitActor)
264 {
265 if (MovingActor->IsBasedOnActor(HitActor) || HitActor->IsBasedOnActor(MovingActor))
266 {
267 return true;
268 }
269 }
270 }
271
272 // If we started penetrating, we may want to ignore it if we are moving out of penetration.
273 // This helps prevent getting stuck in walls.
274 static const auto CVarHitDistanceTolerance = IConsoleManager::Get().FindConsoleVariable(TEXT("p.HitDistanceTolerance"));
275 if ((TestHit.Distance < CVarHitDistanceTolerance->GetFloat() || TestHit.bStartPenetrating) && !(MoveFlags & MOVECOMP_NeverIgnoreBlockingOverlaps))
276 {
277 static const auto CVarInitialOverlapTolerance = IConsoleManager::Get().FindConsoleVariable(TEXT("p.InitialOverlapTolerance"));
278 const float DotTolerance = CVarInitialOverlapTolerance->GetFloat();
279
280 // Dot product of movement direction against 'exit' direction
281 const FVector MovementDir = MovementDirDenormalized.GetSafeNormal();
282 const float MoveDot = (TestHit.ImpactNormal | MovementDir);
283
284 const bool bMovingOut = MoveDot > DotTolerance;
285
286#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
287
288 static const auto CVarShowInitialOverlaps = IConsoleManager::Get().FindConsoleVariable(TEXT("p.ShowInitialOverlaps"));
289 if (CVarShowInitialOverlaps->GetInt() != 0)
290 {
291 UE_LOG(LogVRRootComponent, Log, TEXT("Overlapping %s Dir %s Dot %f Normal %s Depth %f"), *GetNameSafe(TestHit.Component.Get()), *MovementDir.ToString(), MoveDot, *TestHit.ImpactNormal.ToString(), TestHit.PenetrationDepth);
292 DrawDebugDirectionalArrow(InWorld, TestHit.TraceStart, TestHit.TraceStart + 30.f * TestHit.ImpactNormal, 5.f, bMovingOut ? FColor(64, 128, 255) : FColor(255, 64, 64), true, 4.f);
293 if (TestHit.PenetrationDepth > KINDA_SMALL_NUMBER)
294 {
295 DrawDebugDirectionalArrow(InWorld, TestHit.TraceStart, TestHit.TraceStart + TestHit.PenetrationDepth * TestHit.Normal, 5.f, FColor(64, 255, 64), true, 4.f);
296 }
297 }
298 // }
299#endif
300
301 // If we are moving out, ignore this result!
302 if (bMovingOut)
303 {
304 return true;
305 }
306 }
307 }
308
309 return false;
310}
311static FORCEINLINE_DEBUGGABLE bool ShouldIgnoreOverlapResult(const UWorld* World, const AActor* ThisActor, const UPrimitiveComponent& ThisComponent, const AActor* OtherActor, const UPrimitiveComponent& OtherComponent, bool bCheckOverlapFlags)
312{
313 // Don't overlap with self
314 if (&ThisComponent == &OtherComponent)
315 {
316 return true;
317 }
318
319 if (bCheckOverlapFlags)
320 {
321 // Both components must set GetGenerateOverlapEvents()
322 if (!ThisComponent.GetGenerateOverlapEvents() || !OtherComponent.GetGenerateOverlapEvents())
323 {
324 return true;
325 }
326 }
327
328 if (!ThisActor || !OtherActor)
329 {
330 return true;
331 }
332
333 if (!World || OtherActor == (AActor*)World->GetWorldSettings() || !OtherActor->IsActorInitialized())
334 {
335 return true;
336 }
337
338 return false;
339}
340
341
342UVRRootComponent::UVRRootComponent(const FObjectInitializer& ObjectInitializer)
343 : Super(ObjectInitializer)
344{
345 PrimaryComponentTick.bCanEverTick = true;
346 PrimaryComponentTick.bStartWithTickEnabled = true;
347 PrimaryComponentTick.TickGroup = TG_PrePhysics;
348
349 bWantsInitializeComponent = true;
350
351 this->SetRelativeScale3D(FVector(1.f));
352 this->SetRelativeLocation(FVector::ZeroVector);
353
354 // 2.15f is ((MIN_FLOOR_DIST + MAX_FLOOR_DIST) / 2), same value that walking attempts to retain
355 // 1.9f is MIN_FLOOR_DIST, this would not go below ledges when hanging off
356 VRCapsuleOffset = FVector(-8.0f, 0.0f, 2.15f /*0.0f*/);
357
358 bCenterCapsuleOnHMD = false;
359 bPauseTracking = false;
360
361
362 ShapeColor = FColor(223, 149, 157, 255);
363
364 CapsuleRadius = 20.0f;
365 CapsuleHalfHeight = 96.0f;
366 bUseEditorCompositing = true;
367 OffsetComponentToWorld = FTransform(FQuat(0.0f,0.0f,0.0f,1.0f), FVector::ZeroVector, FVector(1.0f));
368
369 // Fixes a problem where headset stays at 0,0,0
370 lastCameraLoc = FVector::ZeroVector;
371 lastCameraRot = FRotator::ZeroRotator;
372 curCameraRot = FRotator::ZeroRotator;
373 curCameraLoc = FVector::ZeroVector;
374 StoredCameraRotOffset = FRotator::ZeroRotator;
376 owningVRChar = NULL;
377 //VRCameraCollider = NULL;
378
381 WalkingCollisionOverride = ECollisionChannel::ECC_Pawn;
382
384
385 CanCharacterStepUpOn = ECB_No;
386 //bShouldUpdatePhysicsVolume = true;
387// bCheckAsyncSceneOnMove = false;
388 SetCanEverAffectNavigation(false);
389 bDynamicObstacle = true;
390
391 //bOffsetByHMD = false;
392}
393
396{
397public:
398 SIZE_T GetTypeHash() const override
399 {
400 static size_t UniquePointer;
401 return reinterpret_cast<size_t>(&UniquePointer);
402 }
403
405 : FPrimitiveSceneProxy(InComponent)
407 , CapsuleRadius(InComponent->GetScaledCapsuleRadius())
408 , CapsuleHalfHeight(InComponent->GetScaledCapsuleHalfHeight())
409 , ShapeColor(InComponent->ShapeColor)
410 , VRCapsuleOffset(InComponent->VRCapsuleOffset)
411 , bSimulating(false)
412 //, OffsetComponentToWorld(InComponent->OffsetComponentToWorld)
413 , LocalToWorld(InComponent->OffsetComponentToWorld.ToMatrixWithScale())
414 {
415 bWillEverBeLit = false;
416 }
417
418 virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override
419 {
420 QUICK_SCOPE_CYCLE_COUNTER(STAT_GetDynamicMeshElements_DrawDynamicElements);
421
422 //const FMatrix& LocalToWorld = OffsetComponentToWorld.ToMatrixWithScale();//GetLocalToWorld();
423 const int32 CapsuleSides = FMath::Clamp<int32>(CapsuleRadius / 4.f, 16, 64);
424
425 for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
426 {
427
428 if (VisibilityMap & (1 << ViewIndex))
429 {
430 const FSceneView* View = Views[ViewIndex];
431 const FLinearColor DrawCapsuleColor = GetViewSelectionColor(ShapeColor, *View, IsSelected(), IsHovered(), false, IsIndividuallySelected());
432
433 FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);
434
435 // If in editor views, lets offset the capsule upwards so that it views correctly
436
437 if (bSimulating)
438 {
439 DrawWireCapsule(PDI, LocalToWorld.GetOrigin() - FVector(0.f, 0.f, CapsuleHalfHeight), LocalToWorld.GetScaledAxis(EAxis::X), LocalToWorld.GetScaledAxis(EAxis::Y), LocalToWorld.GetScaledAxis(EAxis::Z), DrawCapsuleColor, CapsuleRadius, CapsuleHalfHeight, CapsuleSides, SDPG_World);
440 }
441 else if (UseEditorCompositing(View))
442 {
443 DrawWireCapsule(PDI, LocalToWorld.GetOrigin() /*+ FVector(0.f, 0.f, CapsuleHalfHeight)*/, LocalToWorld.GetScaledAxis(EAxis::X), LocalToWorld.GetScaledAxis(EAxis::Y), LocalToWorld.GetScaledAxis(EAxis::Z), DrawCapsuleColor, CapsuleRadius, CapsuleHalfHeight, CapsuleSides, SDPG_World, 1.25f);
444 }
445 else
446 DrawWireCapsule(PDI, LocalToWorld.GetOrigin(), LocalToWorld.GetScaledAxis(EAxis::X), LocalToWorld.GetScaledAxis(EAxis::Y), LocalToWorld.GetScaledAxis(EAxis::Z), DrawCapsuleColor, CapsuleRadius, CapsuleHalfHeight, CapsuleSides, SDPG_World, 1.25f);
447 }
448 }
449 }
450
452 void UpdateTransform_RenderThread(const FTransform &NewTransform, float NewHalfHeight, bool bIsSimulating)
453 {
454 check(IsInRenderingThread());
455 LocalToWorld = NewTransform.ToMatrixWithScale();
456 //OffsetComponentToWorld = NewTransform;
457 CapsuleHalfHeight = NewHalfHeight;
458 bSimulating = bIsSimulating;
459 }
460
461 virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override
462 {
463 const bool bProxyVisible = !bDrawOnlyIfSelected || IsSelected();
464
465 // Should we draw this because collision drawing is enabled, and we have collision
466 const bool bShowForCollision = View->Family->EngineShowFlags.Collision && IsCollisionEnabled();
467
468 FPrimitiveViewRelevance Result;
469 Result.bDrawRelevance = (IsShown(View) && bProxyVisible) || bShowForCollision;
470 Result.bDynamicRelevance = true;
471 Result.bShadowRelevance = IsShadowCast(View);
472 Result.bEditorPrimitiveRelevance = UseEditorCompositing(View);
473 return Result;
474 }
475 virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
476 uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
477
478private:
479 const uint32 bDrawOnlyIfSelected : 1;
480 const float CapsuleRadius;
483 const FVector VRCapsuleOffset;
485 //FTransform OffsetComponentToWorld;
487};
488
490{
491 //GenerateOffsetToWorld();
492 return new FDrawVRCylinderSceneProxy(this);
493}
494
496{
497 Super::InitializeComponent();
499}
500
502{
503 Super::BeginPlay();
504
505 if(AVRBaseCharacter * vrOwner = Cast<AVRBaseCharacter>(this->GetOwner()))
506 {
507 TargetPrimitiveComponent = vrOwner->VRReplicatedCamera;
508 owningVRChar = vrOwner;
509 //VRCameraCollider = vrOwner->VRCameraCollider;
510 return;
511 }
512 else
513 {
514 TArray<USceneComponent*> children = this->GetAttachChildren();
515
516 for (int i = 0; i < children.Num(); i++)
517 {
518 if (children[i]->IsA(UCameraComponent::StaticClass()))
519 {
520 TargetPrimitiveComponent = children[i];
521 owningVRChar = NULL;
522 return;
523 }
524 }
525 }
526
527 //VRCameraCollider = NULL;
529 owningVRChar = NULL;
530}
531
533{
534 bPauseTracking = bPaused;
535}
536
537void UVRRootComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
538{
539
540 if (this->IsSimulatingPhysics())
541 {
542 return Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
543 }
544
545 // Skip updates and stay in place if we have paused tracking to the HMD
546 if (bPauseTracking)
547 {
548 bHadRelativeMovement = false;
549 DifferenceFromLastFrame = FVector::ZeroVector;
550 return;
551 }
552
553 UVRBaseCharacterMovementComponent * CharMove = nullptr;
554
555 // Need these for passing physics updates to character movement
556 if (ACharacter * OwningCharacter = Cast<ACharacter>(GetOwner()))
557 {
558 CharMove = Cast<UVRBaseCharacterMovementComponent>(OwningCharacter->GetCharacterMovement());
559 }
560
562 {
564 {
566 curCameraRot = FRotator(0.f, owningVRChar->PausedTrackingRot, 0.f);
567 }
569 {
571 curCameraLoc = NewTrans.GetTranslation();
572 curCameraRot = NewTrans.Rotator();
573 }
574 else if (GEngine->XRSystem.IsValid() && GEngine->XRSystem->IsHeadTrackingAllowedForWorld(*GetWorld()))
575 {
576 FQuat curRot;
577 if (!GEngine->XRSystem->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, curRot, curCameraLoc))
578 {
581 }
582 else
583 {
585 {
587 }
588 curCameraRot = curRot.Rotator();
589 }
590 }
592 {
593 curCameraRot = TargetPrimitiveComponent->GetRelativeRotation();
594 curCameraLoc = TargetPrimitiveComponent->GetRelativeLocation();
595 }
596 else
597 {
598 curCameraRot = FRotator::ZeroRotator;
599 curCameraLoc = FVector::ZeroVector;
600 }
601
602 // Store a leveled yaw value here so it is only calculated once
604
605 // Pre-Process this for network sends
606 curCameraLoc.X = FMath::RoundToFloat(curCameraLoc.X * 100.f) / 100.f;
607 curCameraLoc.Y = FMath::RoundToFloat(curCameraLoc.Y * 100.f) / 100.f;
608 curCameraLoc.Z = FMath::RoundToFloat(curCameraLoc.Z * 100.f) / 100.f;
609
610 // Can adjust the relative tolerances to remove jitter and some update processing
611 if (!curCameraLoc.Equals(lastCameraLoc, 0.01f) || !curCameraRot.Equals(lastCameraRot, 0.01f))
612 {
613 // Also calculate vector of movement for the movement component
614 FVector LastPosition = OffsetComponentToWorld.GetLocation();
615
617
618 // If the character movement doesn't exist or is not active/ticking
619 if (!CharMove || !CharMove->IsComponentTickEnabled() || !CharMove->IsActive())
620 {
621 OnUpdateTransform(EUpdateTransformFlags::None, ETeleportType::None);
622 }
623 else // Let the character movement move the capsule instead
624 {
625 // Skip physics update, let the movement component handle it instead
626 OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, ETeleportType::None);
627 }
628
629 // Get the correct next transform to use
630 /*FTransform NextTransform;
631 if (bOffsetByHMD) // Manually generate it, the current isn't correct
632 {
633 FVector Camdiff = curCameraLoc - lastCameraLoc;
634 NextTransform = FTransform(StoredCameraRotOffset.Quaternion(), FVector(Camdiff.X, Camdiff.Y, bCenterCapsuleOnHMD ? curCameraLoc.Z : CapsuleHalfHeight) + StoredCameraRotOffset.RotateVector(VRCapsuleOffset), FVector(1.0f)) * GetComponentTransform();
635 }
636 else
637 NextTransform = OffsetComponentToWorld;*/
638
639 FHitResult OutHit;
640 FCollisionQueryParams Params("RelativeMovementSweep", false, GetOwner());
641 FCollisionResponseParams ResponseParam;
642
643 InitSweepCollisionParams(Params, ResponseParam);
644 Params.bFindInitialOverlaps = true;
645 bool bBlockingHit = false;
646
647
649 {
650 bool bAllowWalkingCollision = false;
651 if (CharMove != nullptr)
652 {
653 if (CharMove->MovementMode == EMovementMode::MOVE_Walking || CharMove->MovementMode == EMovementMode::MOVE_NavWalking)
654 bAllowWalkingCollision = true;
655 }
656
657 if (bAllowWalkingCollision)
658 bBlockingHit = GetWorld()->SweepSingleByChannel(OutHit, LastPosition, OffsetComponentToWorld.GetLocation()/*NextTransform.GetLocation()*/, FQuat::Identity, WalkingCollisionOverride, GetCollisionShape(), Params, ResponseParam);
659
660 if (bBlockingHit && OutHit.Component.IsValid())
661 {
662 if (CharMove != nullptr && CharMove->bIgnoreSimulatingComponentsInFloorCheck && OutHit.Component->IsSimulatingPhysics())
663 bHadRelativeMovement = false;
664 else
666 }
667 else
668 bHadRelativeMovement = false;
669 }
670 else
672
674 {
675 DifferenceFromLastFrame = OffsetComponentToWorld.GetLocation() - LastPosition;
676 //DifferenceFromLastFrame = (NextTransform.GetLocation() - LastPosition);// .GetSafeNormal2D();
677 DifferenceFromLastFrame.X = FMath::RoundToFloat(DifferenceFromLastFrame.X * 100.f) / 100.f;
678 DifferenceFromLastFrame.Y = FMath::RoundToFloat(DifferenceFromLastFrame.Y * 100.f) / 100.f;
679 DifferenceFromLastFrame.Z = 0.0f; // Reset Z to zero, its not used anyway and this lets me reuse the Z component for capsule half height
680 }
681 else // Zero it out so we don't process off of the change (multiplayer sends this)
682 DifferenceFromLastFrame = FVector::ZeroVector;
683 }
684 else
685 {
686 bHadRelativeMovement = false;
687 DifferenceFromLastFrame = FVector::ZeroVector;
688 }
689
692 }
693 else
694 {
696 {
698 curCameraRot = FRotator(0.f, owningVRChar->PausedTrackingRot, 0.f);
699 }
701 {
702 curCameraRot = TargetPrimitiveComponent->GetRelativeRotation();
703 curCameraLoc = TargetPrimitiveComponent->GetRelativeLocation();
704 }
705 else
706 {
707 curCameraRot = FRotator(0.0f, 0.0f, 0.0f);// = FRotator::ZeroRotator;
708 curCameraLoc = FVector(0.0f, 0.0f, 0.0f);//FVector::ZeroVector;
709 }
710
711 // Store a leveled yaw value here so it is only calculated once
713
714 // Can adjust the relative tolerances to remove jitter and some update processing
715 if (!curCameraLoc.Equals(lastCameraLoc, 0.01f) || !curCameraRot.Equals(lastCameraRot, 0.01f))
716 {
718
719 // If the character movement doesn't exist or is not active/ticking
720 if (!CharMove || !CharMove->IsActive())
721 {
722 OnUpdateTransform(EUpdateTransformFlags::None, ETeleportType::None);
723 if (bNavigationRelevant && bRegistered)
724 {
725 UpdateNavigationData();
726 PostUpdateNavigationData();
727 }
728 }
729 else // Let the character movement move the capsule instead
730 {
731 // Skip physics update, let the movement component handle it instead
732 OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, ETeleportType::None);
733
734 // This is an edge case, need to check if the nav data needs updated client side
735 if (this->GetOwner()->GetLocalRole() == ENetRole::ROLE_SimulatedProxy)
736 {
737 if (bNavigationRelevant && bRegistered)
738 {
739 UpdateNavigationData();
740 PostUpdateNavigationData();
741 }
742 }
743 }
744
745
748 }
749 }
750
751 Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
752}
753
754
755void UVRRootComponent::SendPhysicsTransform(ETeleportType Teleport)
756{
757 BodyInstance.SetBodyTransform(OffsetComponentToWorld, Teleport);
758 BodyInstance.UpdateBodyScale(OffsetComponentToWorld.GetScale3D());
759}
760
762{
763 Super::SetSimulatePhysics(bSimulate);
764
765 if (bSimulate)
766 {
767 if (AVRCharacter* OwningCharacter = Cast<AVRCharacter>(GetOwner()))
768 {
769 OwningCharacter->NetSmoother->SetRelativeLocation(FVector(0.f,0.f, -this->GetUnscaledCapsuleHalfHeight()));
770 }
771 this->AddWorldOffset(this->GetComponentRotation().RotateVector(FVector(0.f, 0.f, this->GetScaledCapsuleHalfHeight())), false, nullptr, ETeleportType::TeleportPhysics);
772 }
773 else
774 {
775 if (AVRCharacter* OwningCharacter = Cast<AVRCharacter>(GetOwner()))
776 {
777 OwningCharacter->NetSmoother->SetRelativeLocation(FVector(0.f, 0.f, 0));
778 }
779 this->AddWorldOffset(this->GetComponentRotation().RotateVector(FVector(0.f, 0.f, -this->GetScaledCapsuleHalfHeight())), false, nullptr, ETeleportType::TeleportPhysics);
780 }
781}
782
783// Override this so that the physics representation is in the correct location
784void UVRRootComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport)
785{
786 if (this->IsSimulatingPhysics())
787 {
788 if (this->ShouldRender() && this->SceneProxy)
789 {
790 FTransform lOffsetComponentToWorld = OffsetComponentToWorld;
791 float lCapsuleHalfHeight = CapsuleHalfHeight;
792 bool bIsSimulating = this->IsSimulatingPhysics();
793 FDrawVRCylinderSceneProxy* CylinderSceneProxy = (FDrawVRCylinderSceneProxy*)SceneProxy;
794 ENQUEUE_RENDER_COMMAND(VRRootComponent_SendNewDebugTransform)(
795 [CylinderSceneProxy, lOffsetComponentToWorld, lCapsuleHalfHeight, bIsSimulating](FRHICommandList& RHICmdList)
796 {
797 CylinderSceneProxy->UpdateTransform_RenderThread(lOffsetComponentToWorld, lCapsuleHalfHeight, bIsSimulating);
798 });
799 }
800
801 return Super::OnUpdateTransform(UpdateTransformFlags, Teleport);
802 }
803
805 // Using the physics flag for all of this anyway, no reason for a custom flag, it handles it fine
806 if (!(UpdateTransformFlags & EUpdateTransformFlags::SkipPhysicsUpdate))
807 {
809
810 // Just using the
811 if (this->ShouldRender() && this->SceneProxy)
812 {
813 /*ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(
814 FDrawCylinderTransformUpdate,
815 FDrawVRCylinderSceneProxy*, CylinderSceneProxy, (FDrawVRCylinderSceneProxy*)SceneProxy,
816 FTransform, OffsetComponentToWorld, OffsetComponentToWorld, float, CapsuleHalfHeight, CapsuleHalfHeight,
817 {
818 CylinderSceneProxy->UpdateTransform_RenderThread(OffsetComponentToWorld, CapsuleHalfHeight);
819 }
820 );*/
821
822 FTransform lOffsetComponentToWorld = OffsetComponentToWorld;
823 float lCapsuleHalfHeight = CapsuleHalfHeight;
824 bool bIsSimulating = this->IsSimulatingPhysics();
825 FDrawVRCylinderSceneProxy* CylinderSceneProxy = (FDrawVRCylinderSceneProxy*)SceneProxy;
826 ENQUEUE_RENDER_COMMAND(VRRootComponent_SendNewDebugTransform)(
827 [CylinderSceneProxy, lOffsetComponentToWorld, lCapsuleHalfHeight, bIsSimulating](FRHICommandList& RHICmdList)
828 {
829 CylinderSceneProxy->UpdateTransform_RenderThread(lOffsetComponentToWorld, lCapsuleHalfHeight, bIsSimulating);
830 });
831
832 }
833
834 // Don't want to call primitives version, and the scenecomponents version does nothing
835 //Super::OnUpdateTransform(UpdateTransformFlags, Teleport);
836
837 // Always send new transform to physics
838 if (bPhysicsStateCreated)
839 {
840 //If we update transform of welded bodies directly (i.e. on the actual component) we need to update the shape transforms of the parent.
841 //If the parent is updated, any welded shapes are automatically updated so we don't need to do this physx update.
842 //If the parent is updated and we are NOT welded, the child still needs to update physx
843 const bool bTransformSetDirectly = !(UpdateTransformFlags & EUpdateTransformFlags::PropagateFromParent);
844 if (bTransformSetDirectly || !IsWelded())
845 {
846 SendPhysicsTransform(Teleport);
847 }
848 }
849 }
850}
851
852FBoxSphereBounds UVRRootComponent::CalcBounds(const FTransform& LocalToWorld) const
853{
854 FVector BoxPoint = FVector(CapsuleRadius, CapsuleRadius, CapsuleHalfHeight);
855 //FRotator CamRotOffset(0.0f, curCameraRot.Yaw, 0.0f);
856
857 //FRotator CamRotOffset = UVRExpansionFunctionLibrary::GetHMDPureYaw(curCameraRot);
858 /*if(bOffsetByHMD)
859 return FBoxSphereBounds(FVector(0, 0, CapsuleHalfHeight) + StoredCameraRotOffset.RotateVector(VRCapsuleOffset), BoxPoint, BoxPoint.Size()).TransformBy(LocalToWorld);
860 else*/
861 return FBoxSphereBounds(FVector(curCameraLoc.X, curCameraLoc.Y, CapsuleHalfHeight) + StoredCameraRotOffset.RotateVector(VRCapsuleOffset), BoxPoint, BoxPoint.Size()).TransformBy(LocalToWorld);
862
863}
864
865void UVRRootComponent::GetNavigationData(FNavigationRelevantData& Data) const
866{
867 if (bDynamicObstacle)
868 {
869 //Data.Modifiers.CreateAreaModifiers(this, AreaClass);
870 UBodySetup* BodySetup = ((UPrimitiveComponent*)this)->GetBodySetup();
871 if (BodySetup == nullptr)
872 {
873 return;
874 }
875
876 for (int32 Idx = 0; Idx < BodySetup->AggGeom.BoxElems.Num(); Idx++)
877 {
878 const FKBoxElem& BoxElem = BodySetup->AggGeom.BoxElems[Idx];
879 const FBox BoxSize = BoxElem.CalcAABB(FTransform::Identity, 1.0f);
880
881 FAreaNavModifier AreaMod(BoxSize, OffsetComponentToWorld, AreaClass);
882 Data.Modifiers.Add(AreaMod);
883 }
884
885 for (int32 Idx = 0; Idx < BodySetup->AggGeom.SphylElems.Num(); Idx++)
886 {
887 const FKSphylElem& SphylElem = BodySetup->AggGeom.SphylElems[Idx];
888 const FTransform AreaOffset(FVector(0, 0, -SphylElem.Length));
889
890 FAreaNavModifier AreaMod(SphylElem.Radius, SphylElem.Length * 2.0f, AreaOffset * OffsetComponentToWorld, AreaClass);
891 Data.Modifiers.Add(AreaMod);
892 }
893
894 for (int32 Idx = 0; Idx < BodySetup->AggGeom.ConvexElems.Num(); Idx++)
895 {
896 const FKConvexElem& ConvexElem = BodySetup->AggGeom.ConvexElems[Idx];
897
898 FAreaNavModifier AreaMod(ConvexElem.VertexData, 0, ConvexElem.VertexData.Num(), ENavigationCoordSystem::Unreal, OffsetComponentToWorld, AreaClass);
899 Data.Modifiers.Add(AreaMod);
900 }
901
902 for (int32 Idx = 0; Idx < BodySetup->AggGeom.SphereElems.Num(); Idx++)
903 {
904 const FKSphereElem& SphereElem = BodySetup->AggGeom.SphereElems[Idx];
905 const FTransform AreaOffset(FVector(0, 0, -SphereElem.Radius));
906
907 FAreaNavModifier AreaMod(SphereElem.Radius, SphereElem.Radius * 2.0f, AreaOffset * OffsetComponentToWorld, AreaClass);
908 Data.Modifiers.Add(AreaMod);
909 }
910 }
911}
912
913#if WITH_EDITOR
914void UVRRootComponent::PreEditChange(FProperty* PropertyThatWillChange)
915{
916 // This is technically not correct at all to do...however when overloading a root component the preedit gets called twice for some reason.
917 // Calling it twice attempts to double register it in the list and causes an assert to be thrown.
918 if (this->GetOwner()->IsA(AVRCharacter::StaticClass()))
919 return;
920 else
921 Super::PreEditChange(PropertyThatWillChange);
922}
923
924void UVRRootComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
925{
926 const FName PropertyName = PropertyChangedEvent.Property ? PropertyChangedEvent.Property->GetFName() : NAME_None;
927
928 // We only want to modify the property that was changed at this point
929 // things like propagation from CDO to instances don't work correctly if changing one property causes a different property to change
930 if (PropertyName == GET_MEMBER_NAME_CHECKED(UVRRootComponent, CapsuleHalfHeight))
931 {
932 CapsuleHalfHeight = FMath::Max3(0.f, CapsuleHalfHeight, CapsuleRadius);
933 }
934 else if (PropertyName == GET_MEMBER_NAME_CHECKED(UVRRootComponent, CapsuleRadius))
935 {
936 CapsuleRadius = FMath::Clamp(CapsuleRadius, 0.f, CapsuleHalfHeight);
937 }
938 else if (PropertyName == GET_MEMBER_NAME_CHECKED(UVRRootComponent, VRCapsuleOffset))
939 {
940 }
941
942 if (!IsTemplate())
943 {
944 //UpdateBodySetup(); // do this before reregistering components so that new values are used for collision
945 }
946
947 return;
948
949 // Overrode the defaults for this, don't call the parent
950 //Super::PostEditChangeProperty(PropertyChangedEvent);
951}
952#endif // WITH_EDITOR
953
954
955// This overrides the movement logic to use the offset location instead of the default location for sweeps.
956bool UVRRootComponent::MoveComponentImpl(const FVector& Delta, const FQuat& NewRotationQuat, bool bSweep, FHitResult* OutHit, EMoveComponentFlags MoveFlags, ETeleportType Teleport)
957{
958 SCOPE_CYCLE_COUNTER(STAT_VRRootMovement);
959 //CSV_SCOPED_TIMING_STAT(PrimitiveComponent, MoveComponentTime);
960
961 // static things can move before they are registered (e.g. immediately after streaming), but not after.
962 if (IsPendingKill() || (this->Mobility == EComponentMobility::Static && IsRegistered()))//|| CheckStaticMobilityAndWarn(PrimitiveComponentStatics::MobilityWarnText))
963 {
964 if (OutHit)
965 {
966 OutHit->Init();
967 }
968 return false;
969 }
970
971 const bool bSkipPhysicsMove = ((MoveFlags & MOVECOMP_SkipPhysicsMove) != MOVECOMP_NoFlags);
972
973 if (!this->IsSimulatingPhysics() && bSkipPhysicsMove)
974 {
975 // Phys thread is updating this when we don't want it to, stop it chaos!
976 return false;
977 }
978
979 ConditionalUpdateComponentToWorld();
980
981 // Init HitResult
982 //FHitResult BlockingHit(1.f);
983 const FVector TraceStart = OffsetComponentToWorld.GetLocation();// .GetLocation();//GetComponentLocation();
984 const FVector TraceEnd = TraceStart + Delta;
985 //BlockingHit.TraceStart = TraceStart;
986 //BlockingHit.TraceEnd = TraceEnd;
987 float DeltaSizeSq = (TraceEnd - TraceStart).SizeSquared(); // Recalc here to account for precision loss of float addition
988
989 // Set up.
990// float DeltaSizeSq = Delta.SizeSquared();
991 const FQuat InitialRotationQuat = GetComponentTransform().GetRotation();//ComponentToWorld.GetRotation();
992
993 // ComponentSweepMulti does nothing if moving < KINDA_SMALL_NUMBER in distance, so it's important to not try to sweep distances smaller than that.
994 const float MinMovementDistSq = (bSweep ? FMath::Square(4.f*KINDA_SMALL_NUMBER) : 0.f);
995 if (DeltaSizeSq <= MinMovementDistSq)
996 {
997 // Skip if no vector or rotation.
998 if (NewRotationQuat.Equals(InitialRotationQuat, SCENECOMPONENT_QUAT_TOLERANCE))
999 {
1000 // copy to optional output param
1001 if (OutHit)
1002 {
1003 OutHit->Init(TraceStart, TraceEnd);
1004 }
1005 return true;
1006 }
1007 DeltaSizeSq = 0.f;
1008 }
1009
1010 //const bool bSkipPhysicsMove = ((MoveFlags & MOVECOMP_SkipPhysicsMove) != MOVECOMP_NoFlags);
1011
1012 // WARNING: HitResult is only partially initialized in some paths. All data is valid only if bFilledHitResult is true.
1013 FHitResult BlockingHit(NoInit);
1014 BlockingHit.bBlockingHit = false;
1015 BlockingHit.Time = 1.f;
1016 bool bFilledHitResult = false;
1017 bool bMoved = false;
1018 bool bIncludesOverlapsAtEnd = false;
1019 bool bRotationOnly = false;
1020 TInlineOverlapInfoArray PendingOverlaps;
1021 AActor* const Actor = GetOwner();
1022 FVector OrigLocation = GetComponentLocation();
1023
1024 if (!bSweep)
1025 {
1026 // not sweeping, just go directly to the new transform
1027 bMoved = InternalSetWorldLocationAndRotation(/*TraceEnd*/OrigLocation + Delta, NewRotationQuat, bSkipPhysicsMove, Teleport);
1029 bRotationOnly = (DeltaSizeSq == 0);
1030 bIncludesOverlapsAtEnd = bRotationOnly && (AreSymmetricRotations(InitialRotationQuat, NewRotationQuat, GetComponentScale())) && IsCollisionEnabled();
1031 }
1032 else
1033 {
1034 TArray<FHitResult> Hits;
1035 FVector NewLocation = OrigLocation;//TraceStart;
1036 // Perform movement collision checking if needed for this actor.
1037 const bool bCollisionEnabled = IsQueryCollisionEnabled();
1038 if (bCollisionEnabled && (DeltaSizeSq > 0.f))
1039 {
1040#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
1041 if (!IsRegistered())
1042 {
1043 if (Actor)
1044 {
1045 ensureMsgf(IsRegistered(), TEXT("%s MovedComponent %s not initialized deleteme %d"),*Actor->GetName(), *GetName(), Actor->IsPendingKill());
1046 }
1047 else
1048 { //-V523
1049 ensureMsgf(IsRegistered(), TEXT("MovedComponent %s not initialized"), *GetFullName());
1050 }
1051 }
1052#endif
1053#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) && PERF_MOVECOMPONENT_STATS
1054 MoveTimer.bDidLineCheck = true;
1055#endif
1056 UWorld* const MyWorld = GetWorld();
1057
1058 static const FName TraceTagName = TEXT("MoveComponent");
1059 const bool bForceGatherOverlaps = !ShouldCheckOverlapFlagToQueueOverlaps(*this);
1060 FComponentQueryParams Params(/*PrimitiveComponentStatics::MoveComponentName*//*"MoveComponent"*/SCENE_QUERY_STAT(MoveComponent), Actor);
1061 FCollisionResponseParams ResponseParam;
1062 InitSweepCollisionParams(Params, ResponseParam);
1063 Params.bIgnoreTouches |= !(GetGenerateOverlapEvents() || bForceGatherOverlaps);
1064 Params.TraceTag = TraceTagName;
1065 bool const bHadBlockingHit = MyWorld->ComponentSweepMulti(Hits, this, TraceStart, TraceEnd, InitialRotationQuat, Params);
1066 //bool const bHadBlockingHit = MyWorld->SweepMultiByChannel(Hits, TraceStart, TraceEnd, InitialRotationQuat, this->GetCollisionObjectType(), this->GetCollisionShape(), Params, ResponseParam);
1067
1068 if (Hits.Num() > 0)
1069 {
1070 const float DeltaSize = FMath::Sqrt(DeltaSizeSq);
1071 for (int32 HitIdx = 0; HitIdx < Hits.Num(); HitIdx++)
1072 {
1073 PullBackHit(Hits[HitIdx], TraceStart, TraceEnd, DeltaSize);
1074 }
1075 }
1076
1077 // If we had a valid blocking hit, store it.
1078 // If we are looking for overlaps, store those as well.
1079 int32 FirstNonInitialOverlapIdx = INDEX_NONE;
1080 if (bHadBlockingHit || (GetGenerateOverlapEvents() || bForceGatherOverlaps))
1081 {
1082 int32 BlockingHitIndex = INDEX_NONE;
1083 float BlockingHitNormalDotDelta = BIG_NUMBER;
1084 for (int32 HitIdx = 0; HitIdx < Hits.Num(); HitIdx++)
1085 {
1086 const FHitResult& TestHit = Hits[HitIdx];
1087
1088 if (TestHit.bBlockingHit)
1089 {
1090 if (!ShouldIgnoreHitResult(MyWorld, bAllowSimulatingCollision, TestHit, Delta, Actor, MoveFlags))
1091 {
1092 if (TestHit.bStartPenetrating)
1093 {
1094 // We may have multiple initial hits, and want to choose the one with the normal most opposed to our movement.
1095 const float NormalDotDelta = (TestHit.ImpactNormal | Delta);
1096 if (NormalDotDelta < BlockingHitNormalDotDelta)
1097 {
1098 BlockingHitNormalDotDelta = NormalDotDelta;
1099 BlockingHitIndex = HitIdx;
1100 }
1101 }
1102 else if (BlockingHitIndex == INDEX_NONE)
1103 {
1104 // First non-overlapping blocking hit should be used, if an overlapping hit was not.
1105 // This should be the only non-overlapping blocking hit, and last in the results.
1106 BlockingHitIndex = HitIdx;
1107 break;
1108 }
1109 }
1110 }
1111 else if (GetGenerateOverlapEvents() || bForceGatherOverlaps)
1112 {
1113 UPrimitiveComponent* OverlapComponent = TestHit.Component.Get();
1114 if (OverlapComponent && (OverlapComponent->GetGenerateOverlapEvents() || bForceGatherOverlaps))
1115 {
1116 if (!ShouldIgnoreOverlapResult(MyWorld, Actor, *this, TestHit.GetActor(), *OverlapComponent,!bForceGatherOverlaps))
1117 {
1118 // don't process touch events after initial blocking hits
1119 if (BlockingHitIndex >= 0 && TestHit.Time > Hits[BlockingHitIndex].Time)
1120 {
1121 break;
1122 }
1123
1124 if (FirstNonInitialOverlapIdx == INDEX_NONE && TestHit.Time > 0.f)
1125 {
1126 // We are about to add the first non-initial overlap.
1127 FirstNonInitialOverlapIdx = PendingOverlaps.Num();
1128 }
1129
1130 // cache touches
1131 AddUniqueOverlapFast(PendingOverlaps, FOverlapInfo(TestHit));
1132 }
1133 }
1134 }
1135 }
1136
1137 // Update blocking hit, if there was a valid one.
1138 if (BlockingHitIndex >= 0)
1139 {
1140 BlockingHit = Hits[BlockingHitIndex];
1141 bFilledHitResult = true;
1142 }
1143 }
1144
1145 // Update NewLocation based on the hit result
1146 if (!BlockingHit.bBlockingHit)
1147 {
1148 NewLocation += (TraceEnd - TraceStart);
1149 }
1150 else
1151 {
1152 check(bFilledHitResult);
1153 NewLocation += (BlockingHit.Time * (TraceEnd - TraceStart));
1154
1155 // Sanity check
1156 const FVector ToNewLocation = (NewLocation - OrigLocation/*TraceStart*/);
1157 if (ToNewLocation.SizeSquared() <= MinMovementDistSq)
1158 {
1159 // We don't want really small movements to put us on or inside a surface.
1160 NewLocation = OrigLocation;//TraceStart;
1161 BlockingHit.Time = 0.f;
1162
1163 // Remove any pending overlaps after this point, we are not going as far as we swept.
1164 if (FirstNonInitialOverlapIdx != INDEX_NONE)
1165 {
1166 const bool bAllowShrinking = false;
1167 PendingOverlaps.SetNum(FirstNonInitialOverlapIdx, bAllowShrinking);
1168 }
1169 }
1170 }
1171
1172 bIncludesOverlapsAtEnd = AreSymmetricRotations(InitialRotationQuat, NewRotationQuat, GetComponentScale());
1173 }
1174 else if (DeltaSizeSq > 0.f)
1175 {
1176 // apply move delta even if components has collisions disabled
1177 NewLocation += Delta;
1178 bIncludesOverlapsAtEnd = false;
1179 }
1180 else if (DeltaSizeSq == 0.f && bCollisionEnabled)
1181 {
1182 bIncludesOverlapsAtEnd = AreSymmetricRotations(InitialRotationQuat, NewRotationQuat, GetComponentScale());
1183 bRotationOnly = true;
1184 }
1185
1186 // Update the location. This will teleport any child components as well (not sweep).
1187 bMoved = InternalSetWorldLocationAndRotation(NewLocation, NewRotationQuat, bSkipPhysicsMove, Teleport);
1189 }
1190
1191 // Handle overlap notifications.
1192 if (bMoved)
1193 {
1194 if (IsDeferringMovementUpdates())
1195 {
1196 // Defer UpdateOverlaps until the scoped move ends.
1197 FScopedMovementUpdate* ScopedUpdate = GetCurrentScopedMovement();
1198 if (bRotationOnly && bIncludesOverlapsAtEnd)
1199 {
1200 ScopedUpdate->KeepCurrentOverlapsAfterRotation(bSweep);
1201 }
1202 else
1203 {
1204 ScopedUpdate->AppendOverlapsAfterMove(PendingOverlaps, bSweep, bIncludesOverlapsAtEnd);
1205 }
1206 }
1207 else
1208 {
1209 if (bIncludesOverlapsAtEnd)
1210 {
1211 TInlineOverlapInfoArray OverlapsAtEndLocation;
1212 bool bHasEndOverlaps = false;
1213 if (bRotationOnly)
1214 {
1215 // bHasEndOverlaps = ConvertRotationOverlapsToCurrentOverlaps(OverlapsAtEndLocation, OverlappingComponents);
1216 }
1217 else
1218 {
1219 // bHasEndOverlaps = ConvertSweptOverlapsToCurrentOverlaps(OverlapsAtEndLocation, PendingOverlaps, 0, OffsetComponentToWorld.GetLocation(), GetComponentQuat());
1220 }
1221 TOverlapArrayView PendingOverlapsView(PendingOverlaps);
1222 TOverlapArrayView OverlapsAtEndView(OverlapsAtEndLocation);
1223 UpdateOverlaps(&PendingOverlapsView, true, bHasEndOverlaps ? &OverlapsAtEndView : nullptr);
1224 }
1225 else
1226 {
1227 TOverlapArrayView PendingOverlapsView(PendingOverlaps);
1228 UpdateOverlaps(&PendingOverlapsView, true, nullptr);
1229 }
1230 }
1231 }
1232
1233 // Handle blocking hit notifications. Avoid if pending kill (which could happen after overlaps).
1234 const bool bAllowHitDispatch = !BlockingHit.bStartPenetrating || !(MoveFlags & MOVECOMP_DisableBlockingOverlapDispatch);
1235 if (BlockingHit.bBlockingHit && bAllowHitDispatch && !IsPendingKill())
1236 {
1237 check(bFilledHitResult);
1238 if (IsDeferringMovementUpdates())
1239 {
1240 FScopedMovementUpdate* ScopedUpdate = GetCurrentScopedMovement();
1241 ScopedUpdate->AppendBlockingHitAfterMove(BlockingHit);
1242 }
1243 else
1244 {
1245 DispatchBlockingHit(*Actor, BlockingHit);
1246 }
1247 }
1248
1249 // copy to optional output param
1250 if (OutHit)
1251 {
1252 if (bFilledHitResult)
1253 {
1254 *OutHit = BlockingHit;
1255 }
1256 else
1257 {
1258 OutHit->Init(TraceStart, TraceEnd);
1259 }
1260 }
1261
1262 // Return whether we moved at all.
1263 return bMoved;
1264}
1265
1266bool UVRRootComponent::UpdateOverlapsImpl(const TOverlapArrayView* NewPendingOverlaps, bool bDoNotifies, const TOverlapArrayView* OverlapsAtEndLocation)
1267{
1268 //SCOPE_CYCLE_COUNTER(STAT_UpdateOverlaps);
1269 SCOPE_CYCLE_COUNTER(STAT_UpdateOverlapsVRRoot);
1270 SCOPE_CYCLE_UOBJECT(ComponentScope, this);
1271
1272 // if we haven't begun play, we're still setting things up (e.g. we might be inside one of the construction scripts)
1273 // so we don't want to generate overlaps yet. There is no need to update children yet either, they will update once we are allowed to as well.
1274 const AActor* const MyActor = GetOwner();
1275 if (MyActor && !MyActor->HasActorBegunPlay() && !MyActor->IsActorBeginningPlay())
1276 {
1277 return false;
1278 }
1279
1280 bool bCanSkipUpdateOverlaps = true;
1281
1282 // first, dispatch any pending overlaps
1283 if (GetGenerateOverlapEvents() && IsQueryCollisionEnabled()) //TODO: should modifying query collision remove from mayoverlapevents?
1284 {
1285 bCanSkipUpdateOverlaps = false;
1286
1287 if (MyActor)
1288 {
1289 const FTransform PrevTransform = GetComponentTransform();
1290 // If we are the root component we ignore child components. Those children will update their overlaps when we descend into the child tree.
1291 // This aids an optimization in MoveComponent.
1292 const bool bIgnoreChildren = (MyActor->GetRootComponent() == this);
1293
1294 if (NewPendingOverlaps)
1295 {
1296 // Note: BeginComponentOverlap() only triggers overlaps where GetGenerateOverlapEvents() is true on both components.
1297 const int32 NumNewPendingOverlaps = NewPendingOverlaps->Num();
1298 for (int32 Idx = 0; Idx < NumNewPendingOverlaps; ++Idx)
1299 {
1300 BeginComponentOverlap((*NewPendingOverlaps)[Idx], bDoNotifies);
1301 }
1302 }
1303
1304 const TOverlapArrayView* OverlapsAtEndLocationPtr = OverlapsAtEndLocation;
1305
1306 // #TODO: Filter this better so it runs even less often?
1307 // Its not that bad currently running off of NewPendingOverlaps
1308 // It forces checking for end location overlaps again if none are registered, just in case
1309 // the capsule isn't setting things correctly.
1310
1311 TArray<FOverlapInfo> OverlapsAtEnd;
1312 TOverlapArrayView OverlapsAtEndLoc;
1313 if (/*(!OverlapsAtEndLocation || OverlapsAtEndLocation->Num() < 1) &&*/ NewPendingOverlaps && NewPendingOverlaps->Num() > 0)
1314 {
1315 ConvertSweptOverlapsToCurrentOverlaps(OverlapsAtEnd, *NewPendingOverlaps, -1, OffsetComponentToWorld.GetLocation(), GetComponentQuat());
1316 OverlapsAtEndLoc = TOverlapArrayView(OverlapsAtEnd);
1317 OverlapsAtEndLocationPtr = &OverlapsAtEndLoc;
1318 }
1319
1320 // now generate full list of new touches, so we can compare to existing list and determine what changed
1321
1322 TInlineOverlapInfoArray OverlapMultiResult;
1323 TInlineOverlapPointerArray NewOverlappingComponentPtrs;
1324
1325 // If pending kill, we should not generate any new overlaps. Also not if overlaps were just disabled during BeginComponentOverlap.
1326 if (!IsPendingKill() && GetGenerateOverlapEvents())
1327 {
1328 // 4.17 converted to auto cvar
1329 static const auto CVarAllowCachedOverlaps = IConsoleManager::Get().FindConsoleVariable(TEXT("p.AllowCachedOverlaps"));
1330 // Might be able to avoid testing for new overlaps at the end location.
1331 if (OverlapsAtEndLocationPtr != nullptr && CVarAllowCachedOverlaps->GetInt() > 0 && PrevTransform.Equals(GetComponentTransform()))
1332 {
1333 UE_LOG(LogVRRootComponent, VeryVerbose, TEXT("%s->%s Skipping overlap test!"), *GetNameSafe(GetOwner()), *GetName());
1334 const bool bCheckForInvalid = (NewPendingOverlaps && NewPendingOverlaps->Num() > 0);
1335 if (bCheckForInvalid)
1336 {
1337 // BeginComponentOverlap may have disabled what we thought were valid overlaps at the end (collision response or overlap flags could change).
1338 GetPointersToArrayDataByPredicate(NewOverlappingComponentPtrs, *OverlapsAtEndLocationPtr, FPredicateFilterCanOverlap(*this));
1339 }
1340 else
1341 {
1342 GetPointersToArrayData(NewOverlappingComponentPtrs, *OverlapsAtEndLocationPtr);
1343 }
1344 }
1345 else
1346 {
1347 SCOPE_CYCLE_COUNTER(STAT_PerformOverlapQueryVR);
1348 UE_LOG(LogVRRootComponent, VeryVerbose, TEXT("%s->%s Performing overlaps!"), *GetNameSafe(GetOwner()), *GetName());
1349 UWorld* const MyWorld = GetWorld();
1350 TArray<FOverlapResult> Overlaps;
1351 // note this will optionally include overlaps with components in the same actor (depending on bIgnoreChildren).
1352
1353 FComponentQueryParams Params(SCENE_QUERY_STAT(UpdateOverlaps), bIgnoreChildren ? MyActor : nullptr); //(PrimitiveComponentStatics::UpdateOverlapsName, bIgnoreChildren ? MyActor : nullptr);
1354
1355 Params.bIgnoreBlocks = true; //We don't care about blockers since we only route overlap events to real overlaps
1356 FCollisionResponseParams ResponseParam;
1357 InitSweepCollisionParams(Params, ResponseParam);
1358 ComponentOverlapMulti(Overlaps, MyWorld, OffsetComponentToWorld.GetTranslation(), GetComponentQuat(), GetCollisionObjectType(), Params);
1359
1360 for (int32 ResultIdx = 0; ResultIdx < Overlaps.Num(); ResultIdx++)
1361 {
1362 const FOverlapResult& Result = Overlaps[ResultIdx];
1363
1364 UPrimitiveComponent* const HitComp = Result.Component.Get();
1365 if (HitComp && (HitComp != this) && HitComp->GetGenerateOverlapEvents())
1366 {
1367 const bool bCheckOverlapFlags = false; // Already checked above
1368 if (!ShouldIgnoreOverlapResult(MyWorld, MyActor, *this, Result.GetActor(), *HitComp, bCheckOverlapFlags))
1369 {
1370 OverlapMultiResult.Emplace(HitComp, Result.ItemIndex); // don't need to add unique unless the overlap check can return dupes
1371 }
1372 }
1373 }
1374
1375 // Fill pointers to overlap results. We ensure below that OverlapMultiResult stays in scope so these pointers remain valid.
1376 GetPointersToArrayData(NewOverlappingComponentPtrs, OverlapMultiResult);
1377 }
1378 }
1379
1380 // If we have any overlaps from BeginComponentOverlap() (from now or in the past), see if anything has changed by filtering NewOverlappingComponents
1381 if (OverlappingComponents.Num() > 0)
1382 {
1383 TInlineOverlapPointerArray OldOverlappingComponentPtrs;
1384 if (bIgnoreChildren)
1385 {
1386 GetPointersToArrayDataByPredicate(OldOverlappingComponentPtrs, OverlappingComponents, FPredicateOverlapHasDifferentActor(*MyActor));
1387 }
1388 else
1389 {
1390 GetPointersToArrayData(OldOverlappingComponentPtrs, OverlappingComponents);
1391 }
1392
1393 // Now we want to compare the old and new overlap lists to determine
1394 // what overlaps are in old and not in new (need end overlap notifies), and
1395 // what overlaps are in new and not in old (need begin overlap notifies).
1396 // We do this by removing common entries from both lists, since overlapping status has not changed for them.
1397 // What is left over will be what has changed.
1398 for (int32 CompIdx = 0; CompIdx < OldOverlappingComponentPtrs.Num() && NewOverlappingComponentPtrs.Num() > 0; ++CompIdx)
1399 {
1400 // RemoveAtSwap is ok, since it is not necessary to maintain order
1401 const bool bAllowShrinking = false;
1402
1403 const FOverlapInfo* SearchItem = OldOverlappingComponentPtrs[CompIdx];
1404 const int32 NewElementIdx = IndexOfOverlapFast(NewOverlappingComponentPtrs, SearchItem);
1405 if (NewElementIdx != INDEX_NONE)
1406 {
1407 NewOverlappingComponentPtrs.RemoveAtSwap(NewElementIdx, 1, bAllowShrinking);
1408 OldOverlappingComponentPtrs.RemoveAtSwap(CompIdx, 1, bAllowShrinking);
1409 --CompIdx;
1410 }
1411 }
1412
1413 const int32 NumOldOverlaps = OldOverlappingComponentPtrs.Num();
1414 if (NumOldOverlaps > 0)
1415 {
1416 // Now we have to make a copy of the overlaps because we can't keep pointers to them, that list is about to be manipulated in EndComponentOverlap().
1417 TInlineOverlapInfoArray OldOverlappingComponents;
1418 OldOverlappingComponents.SetNumUninitialized(NumOldOverlaps);
1419 for (int32 i = 0; i < NumOldOverlaps; i++)
1420 {
1421 OldOverlappingComponents[i] = *(OldOverlappingComponentPtrs[i]);
1422 }
1423
1424 // OldOverlappingComponents now contains only previous overlaps that are confirmed to no longer be valid.
1425 for (const FOverlapInfo& OtherOverlap : OldOverlappingComponents)
1426 {
1427 if (OtherOverlap.OverlapInfo.Component.IsValid())
1428 {
1429 EndComponentOverlap(OtherOverlap, bDoNotifies, false);
1430 }
1431 else
1432 {
1433 // Remove stale item. Reclaim memory only if it's getting large, to try to avoid churn but avoid bloating component's memory usage.
1434 const bool bAllowShrinking = (OverlappingComponents.Max() >= 24);
1435 const int32 StaleElementIndex = IndexOfOverlapFast(OverlappingComponents, OtherOverlap);
1436 if (StaleElementIndex != INDEX_NONE)
1437 {
1438 OverlappingComponents.RemoveAtSwap(StaleElementIndex, 1, bAllowShrinking);
1439 }
1440 }
1441 }
1442 }
1443 }
1444
1445 // Ensure these arrays are still in scope, because we kept pointers to them in NewOverlappingComponentPtrs.
1446 static_assert(sizeof(OverlapMultiResult) != 0, "Variable must be in this scope");
1447 static_assert(sizeof(OverlapsAtEndLocationPtr) != 0, "Variable must be in this scope");
1448
1449 // NewOverlappingComponents now contains only new overlaps that didn't exist previously.
1450 for (const FOverlapInfo* NewOverlap : NewOverlappingComponentPtrs)
1451 {
1452 BeginComponentOverlap(*NewOverlap, bDoNotifies);
1453 }
1454 }
1455 }
1456 else
1457 {
1458 // GetGenerateOverlapEvents() is false or collision is disabled
1459 // End all overlaps that exist, in case GetGenerateOverlapEvents() was true last tick (i.e. was just turned off)
1460 if (OverlappingComponents.Num() > 0)
1461 {
1462 const bool bSkipNotifySelf = false;
1463 ClearComponentOverlaps(bDoNotifies, bSkipNotifySelf);
1464 }
1465 }
1466
1467 // now update any children down the chain.
1468 // since on overlap events could manipulate the child array we need to take a copy
1469 // of it to avoid missing any children if one is removed from the middle
1470 TInlineComponentArray<USceneComponent*> AttachedChildren;
1471 AttachedChildren.Append(GetAttachChildren());
1472
1473 for (USceneComponent* const ChildComp : AttachedChildren)
1474 {
1475 if (ChildComp)
1476 {
1477 // Do not pass on OverlapsAtEndLocation, it only applied to this component.
1478 bCanSkipUpdateOverlaps &= ChildComp->UpdateOverlaps(nullptr, bDoNotifies, nullptr);
1479 }
1480 }
1481
1482 // Update physics volume using most current overlaps
1483 if (GetShouldUpdatePhysicsVolume())
1484 {
1485 UpdatePhysicsVolume(bDoNotifies);
1486 bCanSkipUpdateOverlaps = false;
1487 }
1488
1489 return bCanSkipUpdateOverlaps;
1490}
1491
1492
1493template<typename AllocatorType>
1495 TArray<FOverlapInfo, AllocatorType>& OverlapsAtEndLocation, const TOverlapArrayView& SweptOverlaps, int32 SweptOverlapsIndex,
1496 const FVector& EndLocation, const FQuat& EndRotationQuat)
1497{
1498 if (SweptOverlapsIndex == -1)
1499 {
1500 SweptOverlapsIndex = 0;
1501 }
1502 else
1503 {
1504 return false;
1505 }
1506
1507 checkSlow(SweptOverlapsIndex >= 0);
1508
1509 // Override location check with our own
1510 //GenerateOffsetToWorld();
1511 FVector EndLocationVR = OffsetComponentToWorld.GetLocation();
1512
1513
1514 bool bResult = false;
1515 const bool bForceGatherOverlaps = !ShouldCheckOverlapFlagToQueueOverlaps(*this);
1516
1517 static const auto CVarAllowCachedOverlaps = IConsoleManager::Get().FindConsoleVariable(TEXT("p.AllowCachedOverlaps"));
1518 if ((GetGenerateOverlapEvents() || bForceGatherOverlaps) && CVarAllowCachedOverlaps->GetInt())
1519 {
1520 const AActor* Actor = GetOwner();
1521 if (Actor && Actor->GetRootComponent() == this)
1522 {
1523 // We know we are not overlapping any new components at the end location. Children are ignored here (see note below).
1525 {
1526 //SCOPE_CYCLE_COUNTER(STAT_MoveComponent_FastOverlap);
1527
1528 // Check components we hit during the sweep, keep only those still overlapping
1529 const FCollisionQueryParams UnusedQueryParams(NAME_None, FCollisionQueryParams::GetUnknownStatId());
1530 const int32 NumSweptOverlaps = SweptOverlaps.Num();
1531 OverlapsAtEndLocation.Reserve(OverlapsAtEndLocation.Num() + NumSweptOverlaps);
1532 for (int32 Index = SweptOverlapsIndex; Index < NumSweptOverlaps; ++Index)
1533 {
1534 const FOverlapInfo& OtherOverlap = SweptOverlaps[Index];
1535 UPrimitiveComponent* OtherPrimitive = OtherOverlap.OverlapInfo.GetComponent();
1536 if (OtherPrimitive && (OtherPrimitive->GetGenerateOverlapEvents() || bForceGatherOverlaps))
1537 {
1538 if (OtherPrimitive->bMultiBodyOverlap)
1539 {
1540 // Not handled yet. We could do it by checking every body explicitly and track each body index in the overlap test, but this seems like a rare need.
1541 return false;
1542 }
1543 else if (Cast<USkeletalMeshComponent>(OtherPrimitive) || Cast<USkeletalMeshComponent>(this))
1544 {
1545 // SkeletalMeshComponent does not support this operation, and would return false in the test when an actual query could return true.
1546 return false;
1547 }
1548 else if (OtherPrimitive->ComponentOverlapComponent(this, EndLocationVR, EndRotationQuat, UnusedQueryParams))
1549 {
1550 OverlapsAtEndLocation.Add(OtherOverlap);
1551 }
1552 }
1553 }
1554
1555 // Note: we don't worry about adding any child components here, because they are not included in the sweep results.
1556 // Children test for their own overlaps after we update our own, and we ignore children in our own update.
1557 checkfSlow(OverlapsAtEndLocation.FindByPredicate(FPredicateOverlapHasSameActor(*Actor)) == nullptr,
1558 TEXT("Child overlaps should not be included in the SweptOverlaps() array in UPrimitiveComponent::ConvertSweptOverlapsToCurrentOverlaps()."));
1559
1560 bResult = true;
1561 }
1562 else
1563 {
1564 if (SweptOverlaps.Num() == 0 && AreAllCollideableDescendantsRelative())
1565 {
1566 // Add overlaps with components in this actor.
1567 GetOverlapsWithActor_Template(Actor, OverlapsAtEndLocation);
1568 bResult = true;
1569 }
1570 }
1571 }
1572 }
1573
1574 return bResult;
1575}
1576
1577
1578template<typename AllocatorType>
1579bool UVRRootComponent::GetOverlapsWithActor_Template(const AActor* Actor, TArray<FOverlapInfo, AllocatorType>& OutOverlaps) const
1580{
1581 const int32 InitialCount = OutOverlaps.Num();
1582 if (Actor)
1583 {
1584 for (int32 OverlapIdx = 0; OverlapIdx < OverlappingComponents.Num(); ++OverlapIdx)
1585 {
1586 UPrimitiveComponent const* const PrimComp = OverlappingComponents[OverlapIdx].OverlapInfo.Component.Get();
1587 if (PrimComp && (PrimComp->GetOwner() == Actor))
1588 {
1589 OutOverlaps.Add(OverlappingComponents[OverlapIdx]);
1590 }
1591 }
1592 }
1593
1594 return InitialCount != OutOverlaps.Num();
1595}
1596
1597template<typename AllocatorType>
1598bool UVRRootComponent::ConvertRotationOverlapsToCurrentOverlaps(TArray<FOverlapInfo, AllocatorType>& OutOverlapsAtEndLocation, const TOverlapArrayView& CurrentOverlaps)
1599{
1600 bool bResult = false;
1601 const bool bForceGatherOverlaps = !ShouldCheckOverlapFlagToQueueOverlaps(*this);
1602
1603 static const auto CVarAllowCachedOverlaps = IConsoleManager::Get().FindConsoleVariable(TEXT("p.AllowCachedOverlaps"));
1604
1605 if ((GetGenerateOverlapEvents() || bForceGatherOverlaps) && /*bAllowCachedOverlapsCVar*/ CVarAllowCachedOverlaps->GetInt())
1606 {
1607 const AActor* Actor = GetOwner();
1608 if (Actor && Actor->GetRootComponent() == this)
1609 {
1611 {
1612 // Add all current overlaps that are not children. Children test for their own overlaps after we update our own, and we ignore children in our own update.
1613 OutOverlapsAtEndLocation.Reserve(OutOverlapsAtEndLocation.Num() + CurrentOverlaps.Num());
1614 Algo::CopyIf(CurrentOverlaps, OutOverlapsAtEndLocation, FPredicateOverlapHasDifferentActor(*Actor));
1615 bResult = true;
1616 }
1617 }
1618 }
1619
1620 return bResult;
1621}
1622
1624{
1625 // I like epics implementation better than my own
1626 const AActor* MyOwner = GetOwner();
1627 return MyOwner->HasLocalNetOwner();
1628 //const APawn* MyPawn = Cast<APawn>(MyOwner);
1629 //return MyPawn ? MyPawn->IsLocallyControlled() : (MyOwner->Role == ENetRole::ROLE_Authority);
1630}
1631
1632void UVRRootComponent::UpdatePhysicsVolume(bool bTriggerNotifiers)
1633{
1634 if (GetShouldUpdatePhysicsVolume() && !IsPendingKill())
1635 {
1636 // SCOPE_CYCLE_COUNTER(STAT_UpdatePhysicsVolume);
1637 if (UWorld * MyWorld = GetWorld())
1638 {
1639 if (MyWorld->GetNonDefaultPhysicsVolumeCount() == 0)
1640 {
1641 SetPhysicsVolume(MyWorld->GetDefaultPhysicsVolume(), bTriggerNotifiers);
1642 }
1643 else if (GetGenerateOverlapEvents() && IsQueryCollisionEnabled())
1644 {
1645 APhysicsVolume* BestVolume = MyWorld->GetDefaultPhysicsVolume();
1646 int32 BestPriority = BestVolume->Priority;
1647
1648 for (auto CompIt = OverlappingComponents.CreateIterator(); CompIt; ++CompIt)
1649 {
1650 const FOverlapInfo& Overlap = *CompIt;
1651 UPrimitiveComponent* OtherComponent = Overlap.OverlapInfo.Component.Get();
1652 if (OtherComponent && OtherComponent->GetGenerateOverlapEvents())
1653 {
1654 APhysicsVolume* V = Cast<APhysicsVolume>(OtherComponent->GetOwner());
1655 if (V && V->Priority > BestPriority)
1656 {
1657 //if (V->IsOverlapInVolume(*this))
1659 {
1660 BestPriority = V->Priority;
1661 BestVolume = V;
1662 }
1663 }
1664 }
1665 }
1666
1667 SetPhysicsVolume(BestVolume, bTriggerNotifiers);
1668 }
1669 else
1670 {
1671 Super::UpdatePhysicsVolume(bTriggerNotifiers);
1672 }
1673 }
1674 }
1675}
1676
1677#undef LOCTEXT_NAMESPACE
static FORCEINLINE_DEBUGGABLE bool ShouldIgnoreOverlapResult(const UWorld *World, const AActor *ThisActor, const UPrimitiveComponent &ThisComponent, const AActor *OtherActor, const UPrimitiveComponent &OtherComponent, bool bCheckOverlapFlags)
DEFINE_LOG_CATEGORY(LogVRRootComponent)
static FORCEINLINE_DEBUGGABLE bool CanComponentsGenerateOverlap(const UPrimitiveComponent *MyComponent, UPrimitiveComponent *OtherComp)
static bool ShouldIgnoreHitResult(const UWorld *InWorld, bool bAllowSimulatingCollision, FHitResult const &TestHit, FVector const &MovementDirDenormalized, const AActor *MovingActor, EMoveComponentFlags MoveFlags)
static FORCEINLINE_DEBUGGABLE void GetPointersToArrayDataByPredicate(TArray< const ElementType *, AllocatorType1 > &Pointers, const TArray< ElementType, AllocatorType2 > &DataArray, PredicateT Predicate)
FORCEINLINE_DEBUGGABLE int32 IndexOfOverlapFast(const TArray< FOverlapInfo, AllocatorType > &OverlapArray, const FOverlapInfo &SearchItem)
static FORCEINLINE_DEBUGGABLE void GetPointersToArrayData(TArray< const ElementType *, AllocatorType1 > &Pointers, const TArray< ElementType, AllocatorType2 > &DataArray)
FORCEINLINE_DEBUGGABLE void AddUniqueOverlapFast(TArray< FOverlapInfo, AllocatorType > &OverlapArray, FOverlapInfo &NewOverlap)
static void PullBackHit(FHitResult &Hit, const FVector &Start, const FVector &End, const float Dist)
TArray< const FOverlapInfo *, TInlineAllocator< 8 > > TInlineOverlapPointerArray
static int32 bEnableFastOverlapCheck
DECLARE_CYCLE_STAT(TEXT("VRRootMovement"), STAT_VRRootMovement, STATGROUP_VRRootComponent)
static bool ShouldCheckOverlapFlagToQueueOverlaps(const UPrimitiveComponent &ThisComponent)
UReplicatedVRCameraComponent * VRReplicatedCamera
UPROPERTY(Category = VRBaseCharacter, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess ...
UCLASS()
Definition VRCharacter.h:23
SIZE_T GetTypeHash() const override
virtual uint32 GetMemoryFootprint(void) const override
uint32 GetAllocatedSize(void) const
FDrawVRCylinderSceneProxy(const UVRRootComponent *InComponent)
virtual void GetDynamicMeshElements(const TArray< const FSceneView * > &Views, const FSceneViewFamily &ViewFamily, uint32 VisibilityMap, FMeshElementCollector &Collector) const override
void UpdateTransform_RenderThread(const FTransform &NewTransform, float NewHalfHeight, bool bIsSimulating)
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView *View) const override
static FTransform Default_GetWaistOrientationAndPosition(FBPVRWaistTracking_Info &WaistTrackingInfo)
void ApplyTrackingParameters(FVector &OriginalPosition)
bool bIgnoreSimulatingComponentsInFloorCheck
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRMovement")
static FRotator GetHMDPureYaw_I(FRotator HMDRotation)
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = VRExpansionLibrary)
UVRRootComponent(const FObjectInitializer &ObjectInitializer)
FBPVRWaistTracking_Info OptionalWaistTrackingParent
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRTrackedParentInterface")
FRotator StoredCameraRotOffset
FORCEINLINE void GenerateOffsetToWorld(bool bUpdateBounds=true, bool bGetPureYaw=true)
FVector DifferenceFromLastFrame
void SetTrackingPaused(bool bPaused)
UFUNCTION(BlueprintCallable, Category = "VRExpansionLibrary")
void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override
FPrimitiveSceneProxy * CreateSceneProxy() override
virtual bool MoveComponentImpl(const FVector &Delta, const FQuat &NewRotation, bool bSweep, FHitResult *OutHit=NULL, EMoveComponentFlags MoveFlags=MOVECOMP_NoFlags, ETeleportType Teleport=ETeleportType::None) override
bool AreWeOverlappingVolume(APhysicsVolume *V)
FTransform OffsetComponentToWorld
FVector VRCapsuleOffset
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
bool bAllowSimulatingCollision
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
USceneComponent * TargetPrimitiveComponent
UPROPERTY(BlueprintReadWrite, Transient, Category = "VRExpansionLibrary")
bool GetOverlapsWithActor_Template(const AActor *Actor, TArray< FOverlapInfo, AllocatorType > &OutOverlaps) const
bool bUseWalkingCollisionOverride
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
bool IsLocallyControlled() const
virtual void GetNavigationData(FNavigationRelevantData &Data) const override
void SendPhysicsTransform(ETeleportType Teleport)
bool bCenterCapsuleOnHMD
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
bool ConvertSweptOverlapsToCurrentOverlaps(TArray< FOverlapInfo, AllocatorType > &OutOverlapsAtEndLocation, const TOverlapArrayView &SweptOverlaps, int32 SweptOverlapsIndex, const FVector &EndLocation, const FQuat &EndRotationQuat)
virtual void SetSimulatePhysics(bool bSimulate) override
virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport=ETeleportType::None) override
AVRBaseCharacter * owningVRChar
TEnumAsByte< ECollisionChannel > WalkingCollisionOverride
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
virtual void InitializeComponent() override
bool bPauseTracking
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
bool bHadRelativeMovement
UPROPERTY(BlueprintReadOnly, Category = "VRExpansionLibrary")
void BeginPlay() override
virtual bool UpdateOverlapsImpl(const TOverlapArrayView *NewPendingOverlaps=nullptr, bool bDoNotifies=true, const TOverlapArrayView *OverlapsAtEndLocation=nullptr) override
bool ConvertRotationOverlapsToCurrentOverlaps(TArray< FOverlapInfo, AllocatorType > &OutOverlapsAtEndLocation, const TOverlapArrayView &CurrentOverlaps)
virtual FBoxSphereBounds CalcBounds(const FTransform &LocalToWorld) const override
virtual void UpdatePhysicsVolume(bool bTriggerNotifiers) override
static const FName MoveComponentName(TEXT("MoveComponent"))
static const FName UpdateOverlapsName(TEXT("UpdateOverlaps"))
bool operator()(const FOverlapInfo &Info)
FFastOverlapInfoCompare(const FOverlapInfo &BaseInfo)
const FOverlapInfo & MyBaseInfo
const UPrimitiveComponent & MyComponent
FPredicateFilterCanOverlap(const UPrimitiveComponent &OwningComponent)
bool operator()(const FOverlapInfo &Info) const
const UPrimitiveComponent & MyComponent
FPredicateFilterCannotOverlap(const UPrimitiveComponent &OwningComponent)
bool operator()(const FOverlapInfo &Info) const
bool operator()(const FOverlapInfo &Info)
const TWeakObjectPtr< const AActor > MyOwnerPtr
FPredicateOverlapHasDifferentActor(const AActor &Owner)
bool operator()(const FOverlapInfo &Info)
FPredicateOverlapHasSameActor(const AActor &Owner)
const TWeakObjectPtr< const AActor > MyOwnerPtr