From 808b378db1ba0202ca4c5e8fb0e3b6317cfd4f62 Mon Sep 17 00:00:00 2001 From: Simeon Wallrath Date: Mon, 26 Aug 2024 16:01:27 +0200 Subject: [PATCH] Update VRE --- VIRTUOS_ExpansionPluginTests/Plugins/SPUD | 2 +- .../OpenXRExpansionPlugin.uplugin | 6 +- .../OpenXRExpansionPlugin.Build.cs | 4 +- .../Private/AnimNode_ApplyOpenXRHandPose.cpp | 35 +- .../Private/OpenXRHandPoseComponent.cpp | 15 +- .../Public/AnimNode_ApplyOpenXRHandPose.h | 3 +- .../Public/OpenXRExpansionTypes.h | 2 +- .../Plugins/VRExpansionPlugin/README.md | 2 +- .../Private/HandSocketVisualizer.cpp | 27 +- .../Private/VRGlobalSettingsDetails.cpp | 54 + .../Public/VRGlobalSettingsDetails.h | 2 + .../Private/CharacterMovementCompTypes.cpp | 2 +- .../Private/GripMotionControllerComponent.cpp | 397 ++++-- .../Private/GripScripts/GS_Melee.cpp | 58 +- .../Private/Grippables/GrippableActor.cpp | 125 +- .../Grippables/GrippableBoxComponent.cpp | 93 +- .../Grippables/GrippableCapsuleComponent.cpp | 93 +- .../GrippablePhysicsReplication.cpp | 1061 +++++++++++++---- .../Grippables/GrippableSkeletalMeshActor.cpp | 136 ++- .../GrippableSkeletalMeshComponent.cpp | 92 +- .../Grippables/GrippableSphereComponent.cpp | 95 +- .../Grippables/GrippableStaticMeshActor.cpp | 129 +- .../GrippableStaticMeshComponent.cpp | 92 +- .../Grippables/HandSocketComponent.cpp | 67 +- .../Interactibles/VRButtonComponent.cpp | 43 +- .../Private/Interactibles/VRDialComponent.cpp | 106 +- .../Interactibles/VRLeverComponent.cpp | 54 +- .../Interactibles/VRMountComponent.cpp | 51 +- .../Interactibles/VRSliderComponent.cpp | 67 +- .../Private/Misc/CollisionIgnoreSubsystem.cpp | 11 + .../Misc/OptionalRepSkeletalMeshActor.cpp | 34 +- .../Private/Misc/VRAIPerceptionOverrides.cpp | 55 +- .../Misc/VREPhysicalAnimationComponent.cpp | 35 +- .../Private/Misc/VRFullScreenUserWidget.cpp | 2 +- .../Private/Misc/VRLogComponent.cpp | 3 + .../Private/Misc/VRPlayerStart.cpp | 2 + .../Private/Misc/VRRenderTargetManager.cpp | 21 +- .../Private/Mover/VRMoverComponent.cpp | 207 ++++ .../ParentRelativeAttachmentComponent.cpp | 1 + .../Private/ReplicatedVRCameraComponent.cpp | 62 +- .../Private/VRAIController.cpp | 2 + .../Private/VRBPDatatypes.cpp | 83 +- .../Private/VRBaseCharacter.cpp | 49 +- .../VRBaseCharacterMovementComponent.cpp | 48 +- .../VRExpansionPlugin/Private/VRCharacter.cpp | 40 + .../Private/VRCharacterMovementComponent.cpp | 94 +- .../Private/VRGestureComponent.cpp | 16 +- .../Private/VRPathFollowingComponent.cpp | 33 +- .../Private/VRPlayerController.cpp | 18 - .../Private/VRRootComponent.cpp | 53 +- .../Private/VRStereoWidgetComponent.cpp | 23 +- .../Public/GripMotionControllerComponent.h | 61 +- .../Public/GripScripts/GS_Melee.h | 7 +- .../Public/Grippables/GrippableActor.h | 55 +- .../Public/Grippables/GrippableBoxComponent.h | 23 + .../Grippables/GrippableCapsuleComponent.h | 25 + .../Grippables/GrippablePhysicsReplication.h | 33 +- .../Grippables/GrippableSkeletalMeshActor.h | 55 +- .../GrippableSkeletalMeshComponent.h | 23 + .../Grippables/GrippableSphereComponent.h | 22 + .../Grippables/GrippableStaticMeshActor.h | 49 +- .../Grippables/GrippableStaticMeshComponent.h | 25 + .../Public/Grippables/HandSocketComponent.h | 19 +- .../Public/Interactibles/VRButtonComponent.h | 14 + .../Public/Interactibles/VRDialComponent.h | 18 +- .../Public/Interactibles/VRLeverComponent.h | 16 +- .../Public/Interactibles/VRMountComponent.h | 18 +- .../Public/Interactibles/VRSliderComponent.h | 21 +- .../Public/Misc/CollisionIgnoreSubsystem.h | 10 +- .../Misc/OptionalRepSkeletalMeshActor.h | 11 +- .../Public/Misc/VRAIPerceptionOverrides.h | 2 + .../Misc/VREPhysicalAnimationComponent.h | 12 +- .../Public/Misc/VRLogComponent.h | 1 + .../Public/Misc/VRRenderTargetManager.h | 16 +- .../Public/Mover/VRMoverComponent.h | 154 +++ .../Public/ReplicatedVRCameraComponent.h | 24 +- .../VRExpansionPlugin/Public/VRBPDatatypes.h | 124 +- .../Public/VRBaseCharacter.h | 8 +- .../VRExpansionPlugin/Public/VRCharacter.h | 4 + .../Public/VRGestureComponent.h | 26 +- .../Public/VRRootComponent.h | 3 + .../Public/VRStereoWidgetComponent.h | 11 +- .../VRExpansionPlugin.Build.cs | 26 +- .../VRExpansionPlugin.uplugin | 12 +- 84 files changed, 3837 insertions(+), 896 deletions(-) create mode 100644 VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Mover/VRMoverComponent.cpp create mode 100644 VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Mover/VRMoverComponent.h diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/SPUD b/VIRTUOS_ExpansionPluginTests/Plugins/SPUD index 53b07d7..2c50d98 160000 --- a/VIRTUOS_ExpansionPluginTests/Plugins/SPUD +++ b/VIRTUOS_ExpansionPluginTests/Plugins/SPUD @@ -1 +1 @@ -Subproject commit 53b07d78ecc5f40016a287d1c7c79a80ea0ad5b5 +Subproject commit 2c50d98d0de49b79602a30397dbda089b672c3b6 diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/OpenXRExpansionPlugin.uplugin b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/OpenXRExpansionPlugin.uplugin index 02a46d5..6422043 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/OpenXRExpansionPlugin.uplugin +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/OpenXRExpansionPlugin.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, - "Version": 5.3, - "VersionName": "5.3", + "Version": 5.4, + "VersionName": "5.4", "FriendlyName": "OpenXRExpansionPlugin", "Description": "An set of utility functions for OpenXR", "Category": "Virtual Reality", @@ -31,7 +31,7 @@ { "Name": "OpenXRExpansionEditor", "Type": "UnCookedOnly", - "LoadingPhase": "PostEngineInit" + "LoadingPhase": "PreDefault" } ], "Plugins": [ diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/OpenXRExpansionPlugin.Build.cs b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/OpenXRExpansionPlugin.Build.cs index 5e4b5d1..6670404 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/OpenXRExpansionPlugin.Build.cs +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/OpenXRExpansionPlugin.Build.cs @@ -10,7 +10,9 @@ namespace UnrealBuildTool.Rules public OpenXRExpansionPlugin(ReadOnlyTargetRules Target) : base(Target) { - PublicDependencyModuleNames.AddRange( + SetupIrisSupport(Target); + + PublicDependencyModuleNames.AddRange( new string[] { //"InputDevice", diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Private/AnimNode_ApplyOpenXRHandPose.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Private/AnimNode_ApplyOpenXRHandPose.cpp index 6a14619..c086912 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Private/AnimNode_ApplyOpenXRHandPose.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Private/AnimNode_ApplyOpenXRHandPose.cpp @@ -29,9 +29,28 @@ void FAnimNode_ApplyOpenXRHandPose::OnInitializeAnimInstance(const FAnimInstance { Super::OnInitializeAnimInstance(InProxy, InAnimInstance); - if (const UOpenXRAnimInstance * animInst = Cast(InAnimInstance)) + if (const UOpenXRAnimInstance * OpenXRAnimInstance = Cast(InAnimInstance)) { bIsOpenInputAnimationInstance = true; + + if (OpenXRAnimInstance->AnimInstanceProxy.HandSkeletalActionData.Num()) + { + for (int i = 0; i < OpenXRAnimInstance->AnimInstanceProxy.HandSkeletalActionData.Num(); ++i) + { + EVRSkeletalHandIndex TargetHand = OpenXRAnimInstance->AnimInstanceProxy.HandSkeletalActionData[i].TargetHand; + + if (OpenXRAnimInstance->AnimInstanceProxy.HandSkeletalActionData[i].bMirrorLeftRight) + { + TargetHand = (TargetHand == EVRSkeletalHandIndex::EActionHandIndex_Left) ? EVRSkeletalHandIndex::EActionHandIndex_Right : EVRSkeletalHandIndex::EActionHandIndex_Left; + } + + if (TargetHand == MappedBonePairs.TargetHand) + { + bIsMirroringHand = OpenXRAnimInstance->AnimInstanceProxy.HandSkeletalActionData[i].bMirrorLeftRight; + break; + } + } + } } } @@ -168,7 +187,16 @@ void FAnimNode_ApplyOpenXRHandPose::CalculateOpenXRAdjustment() // Side direction // Do I need to flip this for left hand? - static FVector OpenXRSideDirection = FVector(0.f, 1.f, 0.f); + + bool bUseLeftHandOffsets = false; + if ((!bIsMirroringHand && MappedBonePairs.TargetHand == EVRSkeletalHandIndex::EActionHandIndex_Left) || + (bIsMirroringHand && MappedBonePairs.TargetHand == EVRSkeletalHandIndex::EActionHandIndex_Right)) + { + bUseLeftHandOffsets = true; + } + + //static FVector OpenXRSideDirection = FVector(0.f, 1.f, 0.f); + FVector OpenXRSideDirection = bUseLeftHandOffsets ? FVector(0.f, -1.f, 0.f) : FVector(0.f, 1.f, 0.f); // Align forward vectors, openXR once in engine is X+ forward FQuat AlignmentRot = FQuat::FindBetweenNormals(WristForwardLS_UE, OpenXRForwardDirection); @@ -380,9 +408,6 @@ void FAnimNode_ApplyOpenXRHandPose::EvaluateSkeletalControl_AnyThread(FComponent return; } - - - FTransform trans = FTransform::Identity; OutBoneTransforms.Reserve(MappedBonePairs.BonePairs.Num()); TArray TransBones; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Private/OpenXRHandPoseComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Private/OpenXRHandPoseComponent.cpp index 0912c8d..cd6b6f9 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Private/OpenXRHandPoseComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Private/OpenXRHandPoseComponent.cpp @@ -6,6 +6,7 @@ #include "MotionControllerComponent.h" #include "OpenXRExpansionFunctionLibrary.h" #include "Engine/NetSerialization.h" +#include "Net/Core/PushModel/PushModel.h" #include "XRMotionControllerBase.h" // for GetHandEnumForSourceName() //#include "EngineMinimal.h" @@ -29,9 +30,13 @@ void UOpenXRHandPoseComponent::GetLifetimeReplicatedProps(TArray< class FLifetim { Super::GetLifetimeReplicatedProps(OutLifetimeProps); + FDoRepLifetimeParams SkipOwnerParams; + SkipOwnerParams.Condition = COND_SkipOwner; + SkipOwnerParams.bIsPushBased = true; + // Skipping the owner with this as the owner will use the controllers location directly - DOREPLIFETIME_CONDITION(UOpenXRHandPoseComponent, LeftHandRep, COND_SkipOwner); - DOREPLIFETIME_CONDITION(UOpenXRHandPoseComponent, RightHandRep, COND_SkipOwner); + DOREPLIFETIME_WITH_PARAMS_FAST(UOpenXRHandPoseComponent, LeftHandRep, SkipOwnerParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UOpenXRHandPoseComponent, RightHandRep, SkipOwnerParams); } void UOpenXRHandPoseComponent::Server_SendSkeletalTransforms_Implementation(const FBPXRSkeletalRepContainer& SkeletalInfo) @@ -49,6 +54,9 @@ void UOpenXRHandPoseComponent::Server_SendSkeletalTransforms_Implementation(cons FBPXRSkeletalRepContainer::CopyReplicatedTo(SkeletalInfo, HandSkeletalActions[i]); LeftHandRep = SkeletalInfo; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UOpenXRHandPoseComponent, LeftHandRep, this); +#endif if (bSmoothReplicatedSkeletalData) { @@ -64,6 +72,9 @@ void UOpenXRHandPoseComponent::Server_SendSkeletalTransforms_Implementation(cons FBPXRSkeletalRepContainer::CopyReplicatedTo(SkeletalInfo, HandSkeletalActions[i]); RightHandRep = SkeletalInfo; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UOpenXRHandPoseComponent, RightHandRep, this); +#endif if (bSmoothReplicatedSkeletalData) { diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Public/AnimNode_ApplyOpenXRHandPose.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Public/AnimNode_ApplyOpenXRHandPose.h index f3868d6..7f35919 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Public/AnimNode_ApplyOpenXRHandPose.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Public/AnimNode_ApplyOpenXRHandPose.h @@ -42,7 +42,8 @@ public: UPROPERTY(EditAnywhere, Category = Skeletal, meta = (PinHiddenByDefault)) FBPOpenXRSkeletalMappingData MappedBonePairs; - bool bIsOpenInputAnimationInstance; + bool bIsOpenInputAnimationInstance = false; + bool bIsMirroringHand = false; void ConvertHandTransformsSpace(TArray& OutTransforms, const TArray& WorldTransforms, FTransform AddTrans, bool bMirrorLeftRight, bool bMergeMissingUE4Bones); diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Public/OpenXRExpansionTypes.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Public/OpenXRExpansionTypes.h index c2b7af6..6da369d 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Public/OpenXRExpansionTypes.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/OpenXRExpansionPlugin/Source/OpenXRExpansionPlugin/Public/OpenXRExpansionTypes.h @@ -103,7 +103,7 @@ public: UPROPERTY(EditAnywhere, NotReplicated, BlueprintReadWrite, Category = Default) bool bAllowDeformingMesh; - // If true then the bones will be mirrored from left/right, to allow you to swap a hand mesh or apply to a full body mesh + // If true then the bones will be mirrored from left/right, to allow you to swap a hand mesh to the other hand UPROPERTY(EditAnywhere, NotReplicated, BlueprintReadWrite, Category = Default) bool bMirrorLeftRight; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/README.md b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/README.md index 875fec0..fa9c46f 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/README.md +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/README.md @@ -1,4 +1,4 @@ -UE4 Forums Thread +UE Forums Thread https://forums.unrealengine.com/development-discussion/vr-ar-development/89050-vr-openvr-expansion-plugin Example Template Project diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionEditor/Private/HandSocketVisualizer.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionEditor/Private/HandSocketVisualizer.cpp index e7da798..89b851d 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionEditor/Private/HandSocketVisualizer.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionEditor/Private/HandSocketVisualizer.cpp @@ -97,8 +97,19 @@ bool FHandSocketVisualizer::GetCustomInputCoordinateSystem(const FEditorViewport { if (UHandSocketComponent* CurrentlyEditingComponent = GetCurrentlyEditingComponent()) { - FTransform newTrans = CurrentlyEditingComponent->HandVisualizerComponent->GetBoneTransform(CurrentlySelectedBoneIdx); - OutMatrix = FRotationMatrix::Make(newTrans.GetRotation()); + if (IsValid(CurrentlyEditingComponent->HandVisualizerComponent)) + { + FTransform newTrans = CurrentlyEditingComponent->HandVisualizerComponent->GetBoneTransform(CurrentlySelectedBoneIdx); + FQuat Rot = newTrans.GetRotation(); + if (!newTrans.GetRotation().ContainsNaN()) + { + Rot.Normalize(); + OutMatrix = FRotationMatrix::Make(Rot); + return true; + } + } + + return false; } } @@ -126,7 +137,7 @@ void FHandSocketVisualizer::DrawVisualizationHUD(const UActorComponent* Componen { if (UHandSocketComponent* CurrentlyEditingComponent = GetCurrentlyEditingComponent()) { - if (!CurrentlyEditingComponent->HandVisualizerComponent) + if (!IsValid(CurrentlyEditingComponent->HandVisualizerComponent)) { return; } @@ -142,6 +153,7 @@ void FHandSocketVisualizer::DrawVisualizationHUD(const UActorComponent* Componen const float DrawPositionX = FMath::FloorToFloat(CanvasRect.Min.X + (CanvasRect.Width() - XL) * 0.5f); const float DrawPositionY = CanvasRect.Min.Y + 50.0f; Canvas->DrawShadowedString(DrawPositionX, DrawPositionY, *CurrentlySelectedBone.ToString(), GEngine->GetLargeFont(), FLinearColor::Yellow); + } } } @@ -310,7 +322,14 @@ bool FHandSocketVisualizer::GetWidgetLocation(const FEditorViewportClient* Viewp { if (UHandSocketComponent* CurrentlyEditingComponent = GetCurrentlyEditingComponent()) { - OutLocation = CurrentlyEditingComponent->HandVisualizerComponent->GetBoneTransform(CurrentlySelectedBoneIdx).GetLocation(); + if (IsValid(CurrentlyEditingComponent->HandVisualizerComponent)) + { + OutLocation = CurrentlyEditingComponent->HandVisualizerComponent->GetBoneTransform(CurrentlySelectedBoneIdx).GetLocation(); + } + else + { + return false; + } } } diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionEditor/Private/VRGlobalSettingsDetails.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionEditor/Private/VRGlobalSettingsDetails.cpp index 0c6ad90..b774672 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionEditor/Private/VRGlobalSettingsDetails.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionEditor/Private/VRGlobalSettingsDetails.cpp @@ -31,6 +31,8 @@ #include "AssetRegistry/AssetRegistryModule.h" #include "AssetRegistry/ARFilter.h" +#include "FileHelpers.h" +#include "Engine/Engine.h" #include "Editor/UnrealEdEngine.h" #include "UnrealEdGlobals.h" @@ -76,8 +78,60 @@ void FVRGlobalSettingsDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuil .Text(LOCTEXT("FixInvalidAnimationAssetsButton", "Fix Animation Assets")) ] ]; + + /*DetailBuilder.EditCategory("Utilities") + .AddCustomRow(LOCTEXT("Fix 5.4.0 Shadow Shader", "Fix Broken 5.4.0 Shadow Shader")) + .NameContent() + [ + SNew(STextBlock) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .Text(LOCTEXT("Fix54ShadowShader", "Fix Broken 5.4.0 Shadow Shader")) + ] + .ValueContent() + .MaxDesiredWidth(125.f) + .MinDesiredWidth(125.f) + [ + SNew(SButton) + .ContentPadding(2) + .VAlign(VAlign_Center) + .HAlign(HAlign_Center) + .OnClicked(this, &FVRGlobalSettingsDetails::OnFixShadowShader) + [ + SNew(STextBlock) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .Text(LOCTEXT("Fix54ShadowShaderButton", "Fix Broken 5.4.0 Shadow Shader")) + ] + ];*/ } +/*FReply FVRGlobalSettingsDetails::OnFixShadowShader() +{ +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION == 4 + FString EnginePath = FPaths::EngineDir(); + EnginePath += "/Shaders/Private/ShadowProjectionPixelShader.usf"; + + if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*EnginePath)) + { + FString FileStr = ""; + if (FFileHelper::LoadFileToString(FileStr, *EnginePath)) + { + // Don't need to do anything complicated, the shader only contains one line with this define in it + FileStr = FileStr.Replace(TEXT("#if MOBILE_MULTI_VIEW || INSTANCED_STEREO"),TEXT("#if ((MOBILE_MULTI_VIEW || INSTANCED_STEREO) && SHADING_PATH_MOBILE)")); + + FFileHelper::SaveStringToFile(FileStr, *EnginePath); + + GEngine->Exec(GEngine->GetWorld(), TEXT("recompileshaders changed")); + UE_LOG(LogPath, Log, TEXT("ShadowProjectionPixelShader.usf resaved and recompiled!")); + return FReply::Handled(); + } + } + +#endif + + UE_LOG(LogPath, Error, TEXT("ShadowProjectionPixelShader.usf could not be found, edited, or the engine version is incorrect!")); + return FReply::Handled(); +}*/ + FReply FVRGlobalSettingsDetails::OnCorrectInvalidAnimationAssets() { diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionEditor/Public/VRGlobalSettingsDetails.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionEditor/Public/VRGlobalSettingsDetails.h index 6e5ee1e..3266b3a 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionEditor/Public/VRGlobalSettingsDetails.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionEditor/Public/VRGlobalSettingsDetails.h @@ -20,6 +20,8 @@ public: virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override; FReply OnCorrectInvalidAnimationAssets(); + + FReply OnFixShadowShader(); void OnLockedStateUpdated(IDetailLayoutBuilder* LayoutBuilder); diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/CharacterMovementCompTypes.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/CharacterMovementCompTypes.cpp index 3ae2705..300790d 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/CharacterMovementCompTypes.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/CharacterMovementCompTypes.cpp @@ -118,7 +118,7 @@ void FSavedMove_VRBaseCharacter::SetInitialPosition(ACharacter* C) // Instead, re-purpose it to be the capsule half height if (AVRBaseCharacter* BaseChar = Cast(C)) { - if (BaseChar->VRReplicateCapsuleHeight) + if (BaseChar->GetVRReplicateCapsuleHeight()) CapsuleHeight = BaseChar->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight(); else CapsuleHeight = 0.0f; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/GripMotionControllerComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/GripMotionControllerComponent.cpp index 2009dcc..5bcf7aa 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/GripMotionControllerComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/GripMotionControllerComponent.cpp @@ -57,6 +57,10 @@ #include "Features/IModularFeatures.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif + DEFINE_LOG_CATEGORY(LogVRMotionController); //For UE4 Profiler ~ Stat DECLARE_CYCLE_STAT(TEXT("TickGrip ~ TickingGrip"), STAT_TickGrip, STATGROUP_TickGrip); @@ -666,17 +670,25 @@ void UGripMotionControllerComponent::GetLifetimeReplicatedProps(TArray< class FL DISABLE_REPLICATED_PRIVATE_PROPERTY(USceneComponent, RelativeRotation); DISABLE_REPLICATED_PRIVATE_PROPERTY(USceneComponent, RelativeScale3D); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; - // Skipping the owner with this as the owner will use the controllers location directly - DOREPLIFETIME_CONDITION(UGripMotionControllerComponent, ReplicatedControllerTransform, COND_SkipOwner); - DOREPLIFETIME(UGripMotionControllerComponent, GrippedObjects); - DOREPLIFETIME(UGripMotionControllerComponent, ControllerNetUpdateRate); - DOREPLIFETIME(UGripMotionControllerComponent, bSmoothReplicatedMotion); - DOREPLIFETIME(UGripMotionControllerComponent, bReplicateWithoutTracking); + DOREPLIFETIME_WITH_PARAMS_FAST(UGripMotionControllerComponent, GrippedObjects, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGripMotionControllerComponent, ControllerNetUpdateRate, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGripMotionControllerComponent, bSmoothReplicatedMotion, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGripMotionControllerComponent, bReplicateWithoutTracking, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_SkipOwner, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + // Skipping the owner with this as the owner will use the controllers location directly + DOREPLIFETIME_WITH_PARAMS_FAST(UGripMotionControllerComponent, ReplicatedControllerTransform, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(UGripMotionControllerComponent, LocallyGrippedObjects, PushModelParamsWithCondition); - DOREPLIFETIME_CONDITION(UGripMotionControllerComponent, LocallyGrippedObjects, COND_SkipOwner); - DOREPLIFETIME_CONDITION(UGripMotionControllerComponent, LocalTransactionBuffer, COND_OwnerOnly); + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithConditionOwnerOnly{ COND_OwnerOnly, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UGripMotionControllerComponent, LocalTransactionBuffer, PushModelParamsWithConditionOwnerOnly); // DOREPLIFETIME(UGripMotionControllerComponent, bReplicateControllerTransform); } @@ -694,6 +706,9 @@ void UGripMotionControllerComponent::Server_SendControllerTransform_Implementati { // Store new transform and trigger OnRep_Function ReplicatedControllerTransform = NewTransform; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGripMotionControllerComponent, ReplicatedControllerTransform, this); +#endif // Server should no longer call this RPC itself, but if is using non tracked then it will so keeping auth check if(!bHasAuthority) @@ -732,6 +747,14 @@ void UGripMotionControllerComponent::GetPhysicsVelocities(const FBPActorGripInfo return; } + // TMP #TODO: Fix when 5.4 bug is fixed + if (!primComp->IsSimulatingPhysics()) + { + CurLinearVelocity = Grip.LinVel; + CurAngularVelocity = Grip.RotVel; + return; + } + CurAngularVelocity = primComp->GetPhysicsAngularVelocityInDegrees(); CurLinearVelocity = primComp->GetPhysicsLinearVelocity(); } @@ -1031,6 +1054,7 @@ void UGripMotionControllerComponent::SetGripCollisionType(const FBPActorGripInfo { GrippedObjects[fIndex].GripCollisionType = NewGripCollisionType; ReCreateGrip(GrippedObjects[fIndex]); + DIRTY_GRIPPED_OBJECTS(); Result = EBPVRResultSwitch::OnSucceeded; return; } @@ -1049,6 +1073,7 @@ void UGripMotionControllerComponent::SetGripCollisionType(const FBPActorGripInfo } ReCreateGrip(LocallyGrippedObjects[fIndex]); + DIRTY_LOCALLY_GRIPPED_OBJECTS(); Result = EBPVRResultSwitch::OnSucceeded; return; @@ -1065,6 +1090,7 @@ void UGripMotionControllerComponent::SetGripLateUpdateSetting(const FBPActorGrip if (fIndex != INDEX_NONE) { GrippedObjects[fIndex].GripLateUpdateSetting = NewGripLateUpdateSetting; + DIRTY_GRIPPED_OBJECTS(); Result = EBPVRResultSwitch::OnSucceeded; return; } @@ -1082,6 +1108,7 @@ void UGripMotionControllerComponent::SetGripLateUpdateSetting(const FBPActorGrip Server_NotifyLocalGripAddedOrChanged(GripInfo); } + DIRTY_LOCALLY_GRIPPED_OBJECTS(); Result = EBPVRResultSwitch::OnSucceeded; return; } @@ -1107,6 +1134,8 @@ void UGripMotionControllerComponent::SetGripRelativeTransform( NotifyGripTransformChanged(Grip); } + DIRTY_GRIPPED_OBJECTS(); + Result = EBPVRResultSwitch::OnSucceeded; return; } @@ -1129,6 +1158,8 @@ void UGripMotionControllerComponent::SetGripRelativeTransform( Server_NotifyLocalGripAddedOrChanged(GripInfo); } + DIRTY_LOCALLY_GRIPPED_OBJECTS(); + Result = EBPVRResultSwitch::OnSucceeded; return; } @@ -1148,6 +1179,7 @@ void UGripMotionControllerComponent::SetGripAdditionTransform( if (fIndex != INDEX_NONE) { GrippedObjects[fIndex].AdditionTransform = CreateGripRelativeAdditionTransform(Grip, NewAdditionTransform, bMakeGripRelative); + DIRTY_GRIPPED_OBJECTS(); Result = EBPVRResultSwitch::OnSucceeded; return; @@ -1159,6 +1191,7 @@ void UGripMotionControllerComponent::SetGripAdditionTransform( if (fIndex != INDEX_NONE) { LocallyGrippedObjects[fIndex].AdditionTransform = CreateGripRelativeAdditionTransform(Grip, NewAdditionTransform, bMakeGripRelative); + DIRTY_LOCALLY_GRIPPED_OBJECTS(); Result = EBPVRResultSwitch::OnSucceeded; return; @@ -1187,6 +1220,8 @@ void UGripMotionControllerComponent::SetGripStiffnessAndDamping( GrippedObjects[fIndex].AdvancedGripSettings.PhysicsSettings.AngularDamping = OptionalAngularDamping; } + DIRTY_GRIPPED_OBJECTS(); + Result = EBPVRResultSwitch::OnSucceeded; SetGripConstraintStiffnessAndDamping(&GrippedObjects[fIndex]); //return; @@ -1212,6 +1247,8 @@ void UGripMotionControllerComponent::SetGripStiffnessAndDamping( Server_NotifyLocalGripAddedOrChanged(GripInfo); } + DIRTY_LOCALLY_GRIPPED_OBJECTS(); + Result = EBPVRResultSwitch::OnSucceeded; SetGripConstraintStiffnessAndDamping(&LocallyGrippedObjects[fIndex]); // return; @@ -1710,6 +1747,8 @@ bool UGripMotionControllerComponent::GripActor( if (!bIsLocalGrip) { int32 Index = GrippedObjects.Add(newActorGrip); + DIRTY_GRIPPED_OBJECTS(); + if (Index != INDEX_NONE) NotifyGrip(GrippedObjects[Index]); //NotifyGrip(newActorGrip); @@ -1719,9 +1758,13 @@ bool UGripMotionControllerComponent::GripActor( if (!IsLocallyControlled()) { LocalTransactionBuffer.Add(newActorGrip); +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGripMotionControllerComponent, LocalTransactionBuffer, this); +#endif } int32 Index = LocallyGrippedObjects.Add(newActorGrip); + DIRTY_LOCALLY_GRIPPED_OBJECTS(); if (Index != INDEX_NONE) { @@ -1966,6 +2009,8 @@ bool UGripMotionControllerComponent::GripComponent( if (!bIsLocalGrip) { int32 Index = GrippedObjects.Add(newComponentGrip); + DIRTY_GRIPPED_OBJECTS(); + if (Index != INDEX_NONE) NotifyGrip(GrippedObjects[Index]); @@ -1976,9 +2021,13 @@ bool UGripMotionControllerComponent::GripComponent( if (!IsLocallyControlled()) { LocalTransactionBuffer.Add(newComponentGrip); +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGripMotionControllerComponent, LocalTransactionBuffer, this); +#endif } int32 Index = LocallyGrippedObjects.Add(newComponentGrip); + DIRTY_LOCALLY_GRIPPED_OBJECTS(); if (Index != INDEX_NONE) { @@ -2083,6 +2132,9 @@ bool UGripMotionControllerComponent::DropGrip_Implementation(const FBPActorGripI if (LocalTransactionBuffer[i].GripID == Grip.GripID) LocalTransactionBuffer.RemoveAt(i); } +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGripMotionControllerComponent, LocalTransactionBuffer, this); +#endif } UPrimitiveComponent * PrimComp = nullptr; @@ -2699,6 +2751,8 @@ void UGripMotionControllerComponent::DropAndSocket_Implementation(const FBPActor int fIndex = 0; if (LocallyGrippedObjects.Find(NewDrop, fIndex)) { + DIRTY_LOCALLY_GRIPPED_OBJECTS(); + if (HasGripAuthority(NewDrop) || IsServer()) { LocallyGrippedObjects.RemoveAt(fIndex); @@ -2714,6 +2768,7 @@ void UGripMotionControllerComponent::DropAndSocket_Implementation(const FBPActor fIndex = 0; if (GrippedObjects.Find(NewDrop, fIndex)) { + DIRTY_GRIPPED_OBJECTS(); if (HasGripAuthority(NewDrop) || IsServer()) { GrippedObjects.RemoveAt(fIndex); @@ -3069,7 +3124,7 @@ bool UGripMotionControllerComponent::NotifyGrip(FBPActorGripInformation &NewGrip case EGripCollisionType::AttachmentGrip: { - if (root) + if (IsValid(root)) root->SetSimulatePhysics(false); // Move it to the correct location automatically @@ -3096,7 +3151,7 @@ bool UGripMotionControllerComponent::NotifyGrip(FBPActorGripInformation &NewGrip default: { - if (root) + if (IsValid(root)) { if (root->IsSimulatingPhysics()) { @@ -3129,6 +3184,13 @@ bool UGripMotionControllerComponent::NotifyGrip(FBPActorGripInformation &NewGrip if (!bIsReInit) { + // TMP #TODO: Remove when 5.4 velocity bug is fixed + if (IsValid(root)) + { + // Set initial world transform for velocity + NewGrip.LastVelWorldTrans = root->GetComponentTransform(); + } + // Broadcast a new grip OnGrippedObject.Broadcast(NewGrip); if (!LocallyGrippedObjects.Contains(NewGrip.GripID) && !GrippedObjects.Contains(NewGrip.GripID)) @@ -3724,15 +3786,14 @@ void UGripMotionControllerComponent::Drop_Implementation(const FBPActorGripInfor }; - - - // Copy over the information instead of working with a reference for the OnDroppedBroadcast FBPActorGripInformation DropBroadcastData = NewDrop; int fIndex = 0; if (LocallyGrippedObjects.Find(NewDrop, fIndex)) { + DIRTY_LOCALLY_GRIPPED_OBJECTS(); + if (HasGripAuthority(NewDrop) || IsServer()) { LocallyGrippedObjects.RemoveAt(fIndex); @@ -3748,6 +3809,7 @@ void UGripMotionControllerComponent::Drop_Implementation(const FBPActorGripInfor fIndex = 0; if (GrippedObjects.Find(NewDrop, fIndex)) { + DIRTY_GRIPPED_OBJECTS(); if (HasGripAuthority(NewDrop) || IsServer()) { GrippedObjects.RemoveAt(fIndex); @@ -4024,6 +4086,15 @@ bool UGripMotionControllerComponent::AddSecondaryAttachmentToGrip(const FBPActor Server_NotifySecondaryAttachmentChanged(GripToUse->GripID, GripToUse->SecondaryGripInfo); } + if (bWasLocal) + { + DIRTY_LOCALLY_GRIPPED_OBJECTS(); + } + else + { + DIRTY_GRIPPED_OBJECTS(); + } + OnSecondaryGripAdded.Broadcast(*GripToUse); GripToUse = nullptr; @@ -4214,6 +4285,15 @@ bool UGripMotionControllerComponent::RemoveSecondaryAttachmentFromGrip(const FBP } + if (bWasLocal) + { + DIRTY_LOCALLY_GRIPPED_OBJECTS(); + } + else + { + DIRTY_GRIPPED_OBJECTS(); + } + SecondaryGripIDs.Remove(GripToUse->GripID); OnSecondaryGripRemoved.Broadcast(*GripToUse); GripToUse = nullptr; @@ -4532,6 +4612,10 @@ bool UGripMotionControllerComponent::TeleportMoveGrip_Impl(FBPActorGripInformati } } + // TMP #TODO: Remove with 5.4 bug with velocity is fixed + // Reset our last world transform velocity as typically we don't want to accumulate teleport speeds into it. + Grip.LastVelWorldTrans = PrimComp->GetComponentTransform(); + return true; } @@ -4727,6 +4811,10 @@ void UGripMotionControllerComponent::UpdateTracking(float DeltaTime) ReplicatedControllerTransform.Position = RelLoc; ReplicatedControllerTransform.Rotation = RelRot; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGripMotionControllerComponent, ReplicatedControllerTransform, this); +#endif + // I would keep the torn off check here, except this can be checked on tick if they // Set 100 htz updates, and in the TornOff case, it actually can't hurt any besides some small // Perf difference. @@ -5003,6 +5091,22 @@ FVector UGripMotionControllerComponent::GetComponentVelocity() const return Super::GetComponentVelocity(); } +// TEMP: #TODO: Remove +void UGripMotionControllerComponent::CalculateGripVelocity(FBPActorGripInformation& GripToFill, UPrimitiveComponent* ComponentToSample, float DeltaTime) +{ + if (!bHasAuthority && !IsServer()) + { + return; + } + + FTransform CurTrans = ComponentToSample->GetComponentTransform(); + + GripToFill.LinVel = (CurTrans.GetLocation() - GripToFill.LastVelWorldTrans.GetLocation()) / DeltaTime; + GripToFill.RotVel = FVector::RadiansToDegrees(((CurTrans.GetRotation().ToRotationVector() - GripToFill.LastVelWorldTrans.GetRotation().ToRotationVector()))) / DeltaTime; + + GripToFill.LastVelWorldTrans = CurTrans; +} + void UGripMotionControllerComponent::HandleGripArray(TArray &GrippedObjectsArray, const FTransform & ParentTransform, float DeltaTime, bool bReplicatedArray) { if (GrippedObjectsArray.Num()) @@ -5090,6 +5194,8 @@ void UGripMotionControllerComponent::HandleGripArray(TArray ActorHandles; - HandleInfo->KinActorData2->GetGameThreadAPI().SetGeometry(TUniquePtr(new TSphere(TVector(0.f), 1000.f))); + HandleInfo->KinActorData2->GetGameThreadAPI().SetGeometry(MakeImplicitObjectPtr>(TVector(0.f), 1000.f)); HandleInfo->KinActorData2->GetGameThreadAPI().SetObjectState(EObjectStateType::Kinematic); FPhysicsInterface::AddActorToSolver(HandleInfo->KinActorData2, ActorParams.Scene->GetSolver()); //ActorHandles.Add(HandleInfo->KinActorData2); @@ -6536,7 +6645,7 @@ bool UGripMotionControllerComponent::SetUpPhysicsHandle(const FBPActorGripInform NewLinDrive.Stiffness = Stiffness; NewLinDrive.MaxForce = MaxForce; - HandleInfo->LinConstraint.bEnablePositionDrive = true; + //HandleInfo->LinConstraint.bEnablePositionDrive = true; HandleInfo->LinConstraint.XDrive = NewLinDrive; HandleInfo->LinConstraint.YDrive = NewLinDrive; HandleInfo->LinConstraint.ZDrive = NewLinDrive; @@ -6608,7 +6717,11 @@ bool UGripMotionControllerComponent::SetUpPhysicsHandle(const FBPActorGripInform NewAngDrive.MaxForce = AngularMaxForce; //NewAngDrive.MaxForce = MAX_FLT; - HandleInfo->LinConstraint.bEnablePositionDrive = true; + //HandleInfo->LinConstraint.bEnablePositionDrive = true; + HandleInfo->LinConstraint.XDrive.bEnablePositionDrive = true; + HandleInfo->LinConstraint.YDrive.bEnablePositionDrive = true; + HandleInfo->LinConstraint.ZDrive.bEnablePositionDrive = true; + HandleInfo->LinConstraint.XDrive = NewLinDrive; HandleInfo->LinConstraint.YDrive = NewLinDrive; HandleInfo->LinConstraint.ZDrive = NewLinDrive; @@ -7202,78 +7315,9 @@ bool UGripMotionControllerComponent::GripPollControllerState_GameThread(FVector& bPolledHMD_GameThread = false; } - //GripUEMotionController::FScopeLockOptional LockOptional; - TArray MotionControllers; - MotionControllers = IModularFeatures::Get().GetModularFeatureImplementations(IMotionController::GetModularFeatureName()); - for (auto MotionController : MotionControllers) - { - if (MotionController == nullptr) - { - continue; - } - - if (bIsInGameThread) - { - CurrentTrackingStatus = MotionController->GetControllerTrackingStatus(PlayerIndex, MotionSource); - if (!bIgnoreTrackingStatus && CurrentTrackingStatus == ETrackingStatus::NotTracked) - continue; - } - - if (MotionController->GetControllerOrientationAndPosition(PlayerIndex, MotionSource, Orientation, Position, OutbProvidedLinearVelocity, OutLinearVelocity, OutbProvidedAngularVelocity, OutAngularVelocityAsAxisAndLength, OutbProvidedLinearAcceleration, OutLinearAcceleration, WorldToMetersScale)) - { - /*#if PLATFORM_PS4 - // Moving this in here to work around a PSVR module bug - if (bIsInGameThread) - { - CurrentTrackingStatus = MotionController->GetControllerTrackingStatus(PlayerIndex, MotionSource); - if (CurrentTrackingStatus == ETrackingStatus::NotTracked) - continue; - } - #endif*/ - - if (HasTrackingParameters()) - { - ApplyTrackingParameters(Position, bIsInGameThread); - } - - if (bOffsetByControllerProfile) - { - FTransform FinalControllerTransform(Orientation,Position); - if (bIsInGameThread) - { - FinalControllerTransform = CurrentControllerProfileTransform * FinalControllerTransform; - } - else - { - FinalControllerTransform = LateUpdateParams.GripRenderThreadProfileTransform * FinalControllerTransform; - } - - Orientation = FinalControllerTransform.Rotator(); - Position = FinalControllerTransform.GetTranslation(); - } - - InUseMotionController = MotionController; - OnMotionControllerUpdated(); - InUseMotionController = nullptr; - - { - FScopeLock Lock(&PolledMotionControllerMutex); - PolledMotionController_GameThread = MotionController; // We only want a render thread update from the motion controller we polled on the game thread. - } - return true; - } - - /*#if PLATFORM_PS4 - else if (bIsInGameThread) - { - CurrentTrackingStatus = MotionController->GetControllerTrackingStatus(PlayerIndex, MotionSource); - } - #endif*/ - } - // #NOTE: This was adding in 4.20, I presume to allow for HMDs as tracking sources for mixed reality. // Skipping all of my special logic here for now - if (MotionSource == IMotionController::HMDSourceId) + if (MotionSource == IMotionController::HMDSourceId || MotionSource == IMotionController::HeadSourceId) { IXRTrackingSystem* TrackingSys = GEngine->XRSystem.Get(); if (TrackingSys) @@ -7290,6 +7334,81 @@ bool UGripMotionControllerComponent::GripPollControllerState_GameThread(FVector& } } } + else + { + //GripUEMotionController::FScopeLockOptional LockOptional; + TArray MotionControllers; + MotionControllers = IModularFeatures::Get().GetModularFeatureImplementations(IMotionController::GetModularFeatureName()); + for (auto MotionController : MotionControllers) + { + if (MotionController == nullptr) + { + continue; + } + + if (bIsInGameThread) + { + EControllerHand HandType; + GetHandType(HandType); + FName GripSource = (HandType == EControllerHand::Left) ? FName("LeftGrip") : FName("RightGrip"); + + CurrentTrackingStatus = MotionController->GetControllerTrackingStatus(PlayerIndex, MotionSource); + if (!bIgnoreTrackingStatus && CurrentTrackingStatus == ETrackingStatus::NotTracked) + continue; + } + + if (MotionController->GetControllerOrientationAndPosition(PlayerIndex, MotionSource, Orientation, Position, OutbProvidedLinearVelocity, OutLinearVelocity, OutbProvidedAngularVelocity, OutAngularVelocityAsAxisAndLength, OutbProvidedLinearAcceleration, OutLinearAcceleration, WorldToMetersScale)) + { + /*#if PLATFORM_PS4 + // Moving this in here to work around a PSVR module bug + if (bIsInGameThread) + { + CurrentTrackingStatus = MotionController->GetControllerTrackingStatus(PlayerIndex, MotionSource); + if (CurrentTrackingStatus == ETrackingStatus::NotTracked) + continue; + } + #endif*/ + + if (HasTrackingParameters()) + { + ApplyTrackingParameters(Position, bIsInGameThread); + } + + if (bOffsetByControllerProfile) + { + FTransform FinalControllerTransform(Orientation, Position); + if (bIsInGameThread) + { + FinalControllerTransform = CurrentControllerProfileTransform * FinalControllerTransform; + } + else + { + FinalControllerTransform = LateUpdateParams.GripRenderThreadProfileTransform * FinalControllerTransform; + } + + Orientation = FinalControllerTransform.Rotator(); + Position = FinalControllerTransform.GetTranslation(); + } + + InUseMotionController = MotionController; + OnMotionControllerUpdated(); + InUseMotionController = nullptr; + + { + FScopeLock Lock(&PolledMotionControllerMutex); + PolledMotionController_GameThread = MotionController; // We only want a render thread update from the motion controller we polled on the game thread. + } + return true; + } + + /*#if PLATFORM_PS4 + else if (bIsInGameThread) + { + CurrentTrackingStatus = MotionController->GetControllerTrackingStatus(PlayerIndex, MotionSource); + } + #endif*/ + } + } } return false; } @@ -7301,7 +7420,11 @@ bool UGripMotionControllerComponent::GripPollControllerState_RenderThread(FVecto if (PolledMotionController_RenderThread) { - CurrentTrackingStatus = PolledMotionController_RenderThread->GetControllerTrackingStatus(PlayerIndex, MotionSource); + EControllerHand HandType; + GetHandType(HandType); + FName GripSource = (HandType == EControllerHand::Left) ? FName("LeftGrip") : FName("RightGrip"); + + CurrentTrackingStatus = PolledMotionController_RenderThread->GetControllerTrackingStatus(PlayerIndex, GripSource); if (PolledMotionController_RenderThread->GetControllerOrientationAndPosition(PlayerIndex, MotionSource, Orientation, Position, WorldToMetersScale)) { if (HasTrackingParameters()) @@ -7636,6 +7759,10 @@ void UGripMotionControllerComponent::Server_NotifyHandledTransaction_Implementat if(LocalTransactionBuffer[i].GripID == GripID) LocalTransactionBuffer.RemoveAt(i); } + +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGripMotionControllerComponent, LocalTransactionBuffer, this); +#endif } bool UGripMotionControllerComponent::Server_NotifyLocalGripAddedOrChanged_Validate(const FBPActorGripInformation & newGrip) @@ -7645,6 +7772,8 @@ bool UGripMotionControllerComponent::Server_NotifyLocalGripAddedOrChanged_Valida void UGripMotionControllerComponent::Server_NotifyLocalGripAddedOrChanged_Implementation(const FBPActorGripInformation & newGrip) { + DIRTY_LOCALLY_GRIPPED_OBJECTS(); + if (!newGrip.GrippedObject || newGrip.GripMovementReplicationSetting != EGripMovementReplicationSettings::ClientSide_Authoritive) { Client_NotifyInvalidLocalGrip(newGrip.GrippedObject, newGrip.GripID); @@ -7765,6 +7894,7 @@ void UGripMotionControllerComponent::Server_NotifyLocalGripAddedOrChanged_Implem } int32 NewIndex = LocallyGrippedObjects.Add(newGrip); + DIRTY_LOCALLY_GRIPPED_OBJECTS(); if (NewIndex != INDEX_NONE && LocallyGrippedObjects.Num() > 0) { @@ -7808,6 +7938,8 @@ bool UGripMotionControllerComponent::Server_NotifyLocalGripRemoved_Validate(uint void UGripMotionControllerComponent::Server_NotifyLocalGripRemoved_Implementation(uint8 GripID, const FTransform_NetQuantize &TransformAtDrop, FVector_NetQuantize100 OptAngularVelocity, FVector_NetQuantize100 OptLinearVelocity) { + DIRTY_LOCALLY_GRIPPED_OBJECTS(); + FBPActorGripInformation FoundGrip; EBPVRResultSwitch Result; GetGripByID(FoundGrip, GripID, Result); @@ -7861,6 +7993,7 @@ void UGripMotionControllerComponent::Server_NotifySecondaryAttachmentChanged_Imp uint8 GripID, const FBPSecondaryGripInfo& SecondaryGripInfo) { + DIRTY_LOCALLY_GRIPPED_OBJECTS(); FBPActorGripInformation * GripInfo = LocallyGrippedObjects.FindByKey(GripID); if (GripInfo != nullptr) @@ -7887,6 +8020,7 @@ void UGripMotionControllerComponent::Server_NotifySecondaryAttachmentChanged_Ret uint8 GripID, const FBPSecondaryGripInfo& SecondaryGripInfo, const FTransform_NetQuantize & NewRelativeTransform) { + DIRTY_LOCALLY_GRIPPED_OBJECTS(); FBPActorGripInformation * GripInfo = LocallyGrippedObjects.FindByKey(GripID); if (GripInfo != nullptr) @@ -7987,8 +8121,9 @@ void FExpandedLateUpdateManager::Setup(const FTransform& ParentToWorld, UGripMot //void FExpandedLateUpdateManager::Apply_RenderThread(FSceneInterface* Scene, const int32 FrameNumber, const FTransform& OldRelativeTransform, const FTransform& NewRelativeTransform) void FExpandedLateUpdateManager::Apply_RenderThread(FSceneInterface* Scene, const FTransform& OldRelativeTransform, const FTransform& NewRelativeTransform) { - check(IsInRenderingThread()); + FRHICommandListBase& RHICmdList = FRHICommandListImmediate::Get(); + check(IsInRenderingThread()); if (!UpdateStates[LateUpdateRenderReadIndex].Primitives.Num() || UpdateStates[LateUpdateRenderReadIndex].bSkip) { @@ -8025,7 +8160,7 @@ void FExpandedLateUpdateManager::Apply_RenderThread(FSceneInterface* Scene, cons } else if (CachedSceneInfo->Proxy) { - CachedSceneInfo->Proxy->ApplyLateUpdateTransform(LateUpdateTransform); + CachedSceneInfo->Proxy->ApplyLateUpdateTransform(RHICmdList, LateUpdateTransform); PrimitivePair.Value = -1; // Set the cached index to -1 to indicate that this primitive was already processed /*if (FrameNumber >= 0) { @@ -8045,7 +8180,7 @@ void FExpandedLateUpdateManager::Apply_RenderThread(FSceneInterface* Scene, cons if (RetrievedSceneInfo->Proxy && PrimitiveIndex != nullptr && *PrimitiveIndex >= 0)*/ if (RetrievedSceneInfo->Proxy && UpdateStates[LateUpdateRenderReadIndex].Primitives.Contains(RetrievedSceneInfo) && UpdateStates[LateUpdateRenderReadIndex].Primitives[RetrievedSceneInfo] >= 0) { - RetrievedSceneInfo->Proxy->ApplyLateUpdateTransform(LateUpdateTransform); + RetrievedSceneInfo->Proxy->ApplyLateUpdateTransform(RHICmdList, LateUpdateTransform); /*if (FrameNumber >= 0) { RetrievedSceneInfo->Proxy->SetPatchingFrameNumber(FrameNumber); @@ -8264,7 +8399,7 @@ bool UGripMotionControllerComponent::GetIsComponentHeld(const UPrimitiveComponen return (GrippedObjects.FindByKey(ComponentToCheck) || LocallyGrippedObjects.FindByKey(ComponentToCheck)); - return false; + //return false; } bool UGripMotionControllerComponent::GetIsSecondaryAttachment(const USceneComponent * ComponentToCheck, FBPActorGripInformation & Grip) @@ -8378,3 +8513,81 @@ bool UGripMotionControllerComponent::HasAuthority() const return bHasAuthority; } +void UGripMotionControllerComponent::CheckTransactionBuffer() +{ + if (LocalTransactionBuffer.Num()) + { + for (int i = LocalTransactionBuffer.Num() - 1; i >= 0; --i) + { + if (LocalTransactionBuffer[i].ValueCache.bWasInitiallyRepped && LocalTransactionBuffer[i].GripID != LocalTransactionBuffer[i].ValueCache.CachedGripID) + { + // There appears to be a bug with TArray replication where if you replace an index with another value of that + // Index, it doesn't fully re-init the object, this is a workaround to re-zero non replicated variables + // when that happens. + LocalTransactionBuffer[i].ClearNonReppingItems(); + } + + if (!LocalTransactionBuffer[i].ValueCache.bWasInitiallyRepped && LocalTransactionBuffer[i].GrippedObject->IsValidLowLevelFast()) + { + LocalTransactionBuffer[i].ValueCache.bWasInitiallyRepped = true; + LocalTransactionBuffer[i].ValueCache.CachedGripID = LocalTransactionBuffer[i].GripID; + + int32 Index = LocallyGrippedObjects.Add(LocalTransactionBuffer[i]); + DIRTY_LOCALLY_GRIPPED_OBJECTS(); + + if (Index != INDEX_NONE) + { + NotifyGrip(LocallyGrippedObjects[Index]); + } + + Server_NotifyHandledTransaction(LocalTransactionBuffer[i].GripID); + } + } + } +} + +///////////////////////////////////////////////// +//- Push networking getter / setter functions +///////////////////////////////////////////////// + +void UGripMotionControllerComponent::SetSmoothReplicatedMotion(bool bNewSmoothReplicatedMotion) +{ + bSmoothReplicatedMotion = bNewSmoothReplicatedMotion; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGripMotionControllerComponent, bSmoothReplicatedMotion, this); +#endif +} + +void UGripMotionControllerComponent::SetReplicateWithoutTracking(bool bNewReplicateWithoutTracking) +{ + bReplicateWithoutTracking = bNewReplicateWithoutTracking; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGripMotionControllerComponent, bReplicateWithoutTracking, this); +#endif +} + +void UGripMotionControllerComponent::SetControllerNetUpdateRate(float NewControllerNetUpdateRate) +{ + ControllerNetUpdateRate = NewControllerNetUpdateRate; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGripMotionControllerComponent, ControllerNetUpdateRate, this); +#endif +} + +void UGripMotionControllerComponent::DIRTY_GRIPPED_OBJECTS() +{ +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGripMotionControllerComponent, GrippedObjects, this); +#endif +} + +void UGripMotionControllerComponent::DIRTY_LOCALLY_GRIPPED_OBJECTS() +{ +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGripMotionControllerComponent, LocallyGrippedObjects, this); +#endif +} + +///////////////////////////////////////////////// +//- End Push networking getter / setter functions +///////////////////////////////////////////////// \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/GripScripts/GS_Melee.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/GripScripts/GS_Melee.cpp index bb7d926..312f6f4 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/GripScripts/GS_Melee.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/GripScripts/GS_Melee.cpp @@ -46,6 +46,12 @@ UGS_Melee::UGS_Melee(const FObjectInitializer& ObjectInitializer) : bOnlyPenetrateWithTwoHands = false; } +void UGS_Melee::SetIsLodged(bool IsLodged, UPrimitiveComponent* LodgeComponent) +{ + bIsLodged = IsLodged; + LodgedComponent = LodgeComponent; +} + void UGS_Melee::UpdateDualHandInfo() { TArray HoldingControllers; @@ -448,12 +454,6 @@ void UGS_Melee::OnGripRelease_Implementation(UGripMotionControllerComponent* Rel TArray HoldingControllers; IVRGripInterface::Execute_IsHeld(GetParent(), HoldingControllers, bIsHeld); - //if(!bAlwaysTickPenetration) - //SetTickEnabled(false); - - //if (!bAlwaysTickPenetration) - // bCheckLodge = false; - if (SecondaryHand.IsValid() && SecondaryHand.HoldingController == ReleasingController && SecondaryHand.GripID == GripInformation.GripID) { SecondaryHand = FBPGripPair(); @@ -471,6 +471,37 @@ void UGS_Melee::OnGripRelease_Implementation(UGripMotionControllerComponent* Rel } } + if (COMType != EVRMeleeComType::VRPMELEECOM_Normal) + { + if (UPrimitiveComponent* PrimComp = Cast(GetParentSceneComp())) + { + if (FBodyInstance* rBodyInstance = PrimComp->GetBodyInstance()) + { + if (rBodyInstance->IsValidBodyInstance() && rBodyInstance->BodySetup.IsValid()) + { + + // If bound we need to cancel out + bool bWasBound = false; + if (PrimaryHand.IsValid()) + { + if (rBodyInstance->OnRecalculatedMassProperties().IsBoundToObject(PrimaryHand.HoldingController)) + { + rBodyInstance->OnRecalculatedMassProperties().RemoveAll(this); + bWasBound = true; + } + } + + rBodyInstance->UpdateMassProperties(); + + // Restore binding + if (bWasBound) + { + rBodyInstance->OnRecalculatedMassProperties().AddUObject(PrimaryHand.HoldingController, &UGripMotionControllerComponent::OnGripMassUpdated); + } + } + } + } + } if (PrimaryHand.IsValid()) { @@ -480,6 +511,13 @@ void UGS_Melee::OnGripRelease_Implementation(UGripMotionControllerComponent* Rel { FBPActorGripInformation * GripInfo = PrimaryHand.HoldingController->GetGripPtrByID(PrimaryHand.GripID); + // Reset custom COM changes + if (!SecondaryHand.IsValid()) + { + HandleInfo->bSkipResettingCom = false; + UpdateDualHandInfo(); + } + if (GripInfo) { //Reset defaults here still!!! @@ -760,8 +798,8 @@ void UGS_Melee::HandlePostPhysicsHandle(UGripMotionControllerComponent* Gripping PrimaryHandPhysicsSettings.FillTo(HandleInfo); } - //HandleInfo->bSetCOM = false; // Should i remove this? - HandleInfo->bSkipResettingCom = false; + if (COMType != EVRMeleeComType::VRPMELEECOM_Normal) + SetComBetweenHands(GrippingController, HandleInfo); } } @@ -793,6 +831,10 @@ void UGS_Melee::SetComBetweenHands(UGripMotionControllerComponent* GrippingContr HandleInfo->bSetCOM = true; // Should i remove this? HandleInfo->bSkipResettingCom = true; } + else + { + HandleInfo->bSkipResettingCom = false; + } } /*void UGS_Melee::Tick(float DeltaTime) diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableActor.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableActor.cpp index 0e30a65..57d69df 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableActor.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableActor.cpp @@ -19,7 +19,6 @@ #include "Net/Core/PushModel/PushModel.h" #endif - //============================================================================= AGrippableActor::AGrippableActor(const FObjectInitializer& ObjectInitializer) : Super() @@ -62,13 +61,20 @@ void AGrippableActor::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME_CONDITION(AGrippableActor, GripLogicScripts, COND_Custom); - DOREPLIFETIME(AGrippableActor, bReplicateGripScripts); - DOREPLIFETIME(AGrippableActor, bRepGripSettingsAndGameplayTags); - DOREPLIFETIME(AGrippableActor, bAllowIgnoringAttachOnOwner); - DOREPLIFETIME(AGrippableActor, ClientAuthReplicationData); - DOREPLIFETIME_CONDITION(AGrippableActor, VRGripInterfaceSettings, COND_Custom); - DOREPLIFETIME_CONDITION(AGrippableActor, GameplayTags, COND_Custom); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableActor, bReplicateGripScripts, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableActor, bRepGripSettingsAndGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableActor, bAllowIgnoringAttachOnOwner, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableActor, ClientAuthReplicationData, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableActor, GripLogicScripts, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableActor, VRGripInterfaceSettings, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableActor, GameplayTags, PushModelParamsWithCondition); DISABLE_REPLICATED_PRIVATE_PROPERTY(AActor, AttachmentReplication); @@ -78,7 +84,6 @@ void AGrippableActor::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty void AGrippableActor::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) { - // Don't replicate if set to not do it DOREPLIFETIME_ACTIVE_OVERRIDE_FAST(AGrippableActor, VRGripInterfaceSettings, bRepGripSettingsAndGameplayTags); DOREPLIFETIME_ACTIVE_OVERRIDE_FAST(AGrippableActor, GameplayTags, bRepGripSettingsAndGameplayTags); @@ -254,6 +259,30 @@ void AGrippableActor::GatherCurrentMovement() } } +bool AGrippableActor::ShouldWeSkipAttachmentReplication(bool bConsiderHeld) const +{ + if ((bConsiderHeld && !VRGripInterfaceSettings.bWasHeld) || GetNetMode() < ENetMode::NM_Client) + return false; + + if (VRGripInterfaceSettings.MovementReplicationType == EGripMovementReplicationSettings::ClientSide_Authoritive || + VRGripInterfaceSettings.MovementReplicationType == EGripMovementReplicationSettings::ClientSide_Authoritive_NoRep) + { + // First return if we are locally held (owner may not have replicated yet) + for (const FBPGripPair& Grip : VRGripInterfaceSettings.HoldingControllers) + { + if (IsValid(Grip.HoldingController) && Grip.HoldingController->IsLocallyControlled()) + { + return true; + } + } + + // then return if we have a local net owner + return HasLocalNetOwner(); + } + else + return false; +} + void AGrippableActor::OnRep_AttachmentReplication() { if (bAllowIgnoringAttachOnOwner && (ClientAuthReplicationData.bIsCurrentlyClientAuth || ShouldWeSkipAttachmentReplication())) @@ -822,4 +851,80 @@ void AGrippableActor::GetSubobjectsWithStableNamesForNetworking(TArray } } } -} \ No newline at end of file +} + +///////////////////////////////////////////////// +//- Push networking getter / setter functions +///////////////////////////////////////////////// + +void AGrippableActor::SetReplicateGripScripts(bool bNewReplicateGripScripts) +{ + bReplicateGripScripts = bNewReplicateGripScripts; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableActor, bReplicateGripScripts, this); +#endif +} + +TArray>& AGrippableActor::GetGripLogicScripts() +{ +#if WITH_PUSH_MODEL + if (bReplicateGripScripts) + { + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableActor, GripLogicScripts, this); + } +#endif + + return GripLogicScripts; +} + +void AGrippableActor::SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags) +{ + bRepGripSettingsAndGameplayTags = bNewRepGripSettingsAndGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableActor, bRepGripSettingsAndGameplayTags, this); +#endif +} + +void AGrippableActor::SetAllowIgnoringAttachOnOwner(bool bNewAllowIgnoringAttachOnOwner) +{ + bAllowIgnoringAttachOnOwner = bNewAllowIgnoringAttachOnOwner; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableActor, bAllowIgnoringAttachOnOwner, this); +#endif +} + +FVRClientAuthReplicationData& AGrippableActor::GetClientAuthReplicationData(FVRClientAuthReplicationData& ClientAuthData) +{ +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableActor, ClientAuthReplicationData, this); +#endif + return ClientAuthReplicationData; +} + +FBPInterfaceProperties& AGrippableActor::GetVRGripInterfaceSettings(bool bMarkDirty) +{ +#if WITH_PUSH_MODEL + if (bMarkDirty && bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableActor, VRGripInterfaceSettings, this); + } +#endif + + return VRGripInterfaceSettings; +} + +FGameplayTagContainer& AGrippableActor::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableActor, GameplayTags, this); + } +#endif + + return GameplayTags; +} + +///////////////////////////////////////////////// +//- End Push networking getter / setter functions +///////////////////////////////////////////////// \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableBoxComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableBoxComponent.cpp index 235959a..ec8f05d 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableBoxComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableBoxComponent.cpp @@ -8,6 +8,10 @@ #include "GripScripts/VRGripScriptBase.h" #include "Net/UnrealNetwork.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif + //============================================================================= UGrippableBoxComponent::~UGrippableBoxComponent() { @@ -47,12 +51,19 @@ void UGrippableBoxComponent::GetLifetimeReplicatedProps(TArray< class FLifetimeP { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME_CONDITION(UGrippableBoxComponent, GripLogicScripts, COND_Custom); - DOREPLIFETIME(UGrippableBoxComponent, bReplicateGripScripts); - DOREPLIFETIME(UGrippableBoxComponent, bRepGripSettingsAndGameplayTags); - DOREPLIFETIME(UGrippableBoxComponent, bReplicateMovement); - DOREPLIFETIME_CONDITION(UGrippableBoxComponent, VRGripInterfaceSettings, COND_Custom); - DOREPLIFETIME_CONDITION(UGrippableBoxComponent, GameplayTags, COND_Custom); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableBoxComponent, bReplicateGripScripts, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableBoxComponent, bRepGripSettingsAndGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableBoxComponent, bReplicateMovement, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableBoxComponent, GripLogicScripts, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableBoxComponent, VRGripInterfaceSettings, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableBoxComponent, GameplayTags, PushModelParamsWithCondition); } void UGrippableBoxComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) @@ -320,4 +331,72 @@ void UGrippableBoxComponent::OnComponentDestroyed(bool bDestroyingHierarchy) } GripLogicScripts.Empty(); -} \ No newline at end of file +} + +///////////////////////////////////////////////// +//- Push networking getter / setter functions +///////////////////////////////////////////////// + +void UGrippableBoxComponent::SetReplicateGripScripts(bool bNewReplicateGripScripts) +{ + bReplicateGripScripts = bNewReplicateGripScripts; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableBoxComponent, bReplicateGripScripts, this); +#endif +} + +TArray>& UGrippableBoxComponent::GetGripLogicScripts() +{ +#if WITH_PUSH_MODEL + if (bReplicateGripScripts) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableBoxComponent, GripLogicScripts, this); + } +#endif + + return GripLogicScripts; +} + +void UGrippableBoxComponent::SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags) +{ + bRepGripSettingsAndGameplayTags = bNewRepGripSettingsAndGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableBoxComponent, bRepGripSettingsAndGameplayTags, this); +#endif +} + +void UGrippableBoxComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableBoxComponent, bReplicateMovement, this); +#endif +} + +FBPInterfaceProperties& UGrippableBoxComponent::GetVRGripInterfaceSettings(bool bMarkDirty) +{ +#if WITH_PUSH_MODEL + if (bMarkDirty && bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableBoxComponent, VRGripInterfaceSettings, this); + } +#endif + + return VRGripInterfaceSettings; +} + +FGameplayTagContainer& UGrippableBoxComponent::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableBoxComponent, GameplayTags, this); + } +#endif + + return GameplayTags; +} + +///////////////////////////////////////////////// +//- End Push networking getter / setter functions +///////////////////////////////////////////////// \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableCapsuleComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableCapsuleComponent.cpp index bbb8853..9178cb5 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableCapsuleComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableCapsuleComponent.cpp @@ -8,6 +8,10 @@ #include "GripScripts/VRGripScriptBase.h" #include "Net/UnrealNetwork.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif + //============================================================================= UGrippableCapsuleComponent::UGrippableCapsuleComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -43,12 +47,19 @@ void UGrippableCapsuleComponent::GetLifetimeReplicatedProps(TArray< class FLifet { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME_CONDITION(UGrippableCapsuleComponent, GripLogicScripts, COND_Custom); - DOREPLIFETIME(UGrippableCapsuleComponent, bReplicateGripScripts); - DOREPLIFETIME(UGrippableCapsuleComponent, bRepGripSettingsAndGameplayTags); - DOREPLIFETIME(UGrippableCapsuleComponent, bReplicateMovement); - DOREPLIFETIME_CONDITION(UGrippableCapsuleComponent, VRGripInterfaceSettings, COND_Custom); - DOREPLIFETIME_CONDITION(UGrippableCapsuleComponent, GameplayTags, COND_Custom); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableCapsuleComponent, bReplicateGripScripts, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableCapsuleComponent, bRepGripSettingsAndGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableCapsuleComponent, bReplicateMovement, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableCapsuleComponent, GripLogicScripts, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableCapsuleComponent, VRGripInterfaceSettings, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableCapsuleComponent, GameplayTags, PushModelParamsWithCondition); } void UGrippableCapsuleComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) @@ -320,4 +331,72 @@ void UGrippableCapsuleComponent::OnComponentDestroyed(bool bDestroyingHierarchy) } GripLogicScripts.Empty(); -} \ No newline at end of file +} + +///////////////////////////////////////////////// +//- Push networking getter / setter functions +///////////////////////////////////////////////// + +void UGrippableCapsuleComponent::SetReplicateGripScripts(bool bNewReplicateGripScripts) +{ + bReplicateGripScripts = bNewReplicateGripScripts; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableCapsuleComponent, bReplicateGripScripts, this); +#endif +} + +TArray>& UGrippableCapsuleComponent::GetGripLogicScripts() +{ +#if WITH_PUSH_MODEL + if (bReplicateGripScripts) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableCapsuleComponent, GripLogicScripts, this); + } +#endif + + return GripLogicScripts; +} + +void UGrippableCapsuleComponent::SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags) +{ + bRepGripSettingsAndGameplayTags = bNewRepGripSettingsAndGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableCapsuleComponent, bRepGripSettingsAndGameplayTags, this); +#endif +} + +void UGrippableCapsuleComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableCapsuleComponent, bReplicateMovement, this); +#endif +} + +FBPInterfaceProperties& UGrippableCapsuleComponent::GetVRGripInterfaceSettings(bool bMarkDirty) +{ +#if WITH_PUSH_MODEL + if (bMarkDirty && bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableCapsuleComponent, VRGripInterfaceSettings, this); + } +#endif + + return VRGripInterfaceSettings; +} + +FGameplayTagContainer& UGrippableCapsuleComponent::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableCapsuleComponent, GameplayTags, this); + } +#endif + + return GameplayTags; +} + +///////////////////////////////////////////////// +//- End Push networking getter / setter functions +///////////////////////////////////////////////// \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippablePhysicsReplication.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippablePhysicsReplication.cpp index 284a52a..d727289 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippablePhysicsReplication.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippablePhysicsReplication.cpp @@ -1,21 +1,31 @@ -// Fill out your copyright notice in the Description page of Project Settings. + +/*============================================================================= + PhysicsReplication.cpp: Code for keeping replicated physics objects in sync with the server based on replicated server state data. + Copy / override of this class for VR client authority +=============================================================================*/ + #include "Grippables/GrippablePhysicsReplication.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(GrippablePhysicsReplication) +#include "CoreMinimal.h" +#include "PhysicsEngine\BodyInstance.h" +#include "Components/PrimitiveComponent.h" +#include "Components/SkeletalMeshComponent.h" #include "UObject/ObjectMacros.h" #include "UObject/Interface.h" #include "DrawDebugHelpers.h" #include "Chaos/ChaosMarshallingManager.h" #include "PhysicsProxy/SingleParticlePhysicsProxy.h" #include "Chaos/PhysicsObjectInternalInterface.h" -#include "Chaos/PhysicsObject.h" + #include "PBDRigidsSolver.h" #include "Chaos/PBDRigidsEvolutionGBF.h" #include "VRGlobalSettings.h" #include "PhysicsEngine/PhysicsSettings.h" #include "Physics/Experimental/PhysScene_Chaos.h" #include "Chaos/DebugDrawQueue.h" +#include "Chaos/Particles.h" //#include "Components/SkeletalMeshComponent.h" #include "Misc/ScopeRWLock.h" @@ -31,6 +41,71 @@ namespace VRPhysicsReplicationStatics static bool bHasVRPhysicsReplication = false; } +// Hacky work around for them not exporting these.... +#if WITH_EDITOR +namespace PhysicsReplicationCVars +{ + int32 SkipSkeletalRepOptimization = 1; +#if !UE_BUILD_SHIPPING + //int32 LogPhysicsReplicationHardSnaps = 0; +#endif + + int32 EnableDefaultReplication = 0; + + namespace ResimulationCVars + { + bool bRuntimeCorrectionEnabled = true; + bool bRuntimeVelocityCorrection = false; + bool bRuntimeCorrectConnectedBodies = true; + float PosStabilityMultiplier = 0.5f; + float RotStabilityMultiplier = 1.0f; + float VelStabilityMultiplier = 0.5f; + float AngVelStabilityMultiplier = 0.5f; + bool bDrawDebug = false; + } + + namespace PredictiveInterpolationCVars + { + float PosCorrectionTimeBase = 0.0f; + float PosCorrectionTimeMin = 0.1f; + float PosCorrectionTimeMultiplier = 1.0f; + float RotCorrectionTimeBase = 0.0f; + float RotCorrectionTimeMin = 0.1f; + float RotCorrectionTimeMultiplier = 1.0f; + float PosInterpolationTimeMultiplier = 1.1f; + float RotInterpolationTimeMultiplier = 1.25f; + float AverageReceiveIntervalSmoothing = 3.0f; + float ExtrapolationTimeMultiplier = 3.0f; + float ExtrapolationMinTime = 0.75f; + float MinExpectedDistanceCovered = 0.5f; + float ErrorAccumulationDecreaseMultiplier = 0.5f; + float ErrorAccumulationSeconds = 3.0f; + bool bDisableErrorVelocityLimits = false; + float ErrorAccLinVelMaxLimit = 50.0f; + float ErrorAccAngVelMaxLimit = 1.5f; + float SoftSnapPosStrength = 0.5f; + float SoftSnapRotStrength = 0.5f; + bool bSoftSnapToSource = false; + float EarlyOutDistanceSqr = 1.0f; + float EarlyOutAngle = 1.5f; + bool bEarlyOutWithVelocity = true; + bool bSkipVelocityRepOnPosEarlyOut = true; + bool bPostResimWaitForUpdate = false; + bool bVelocityBased = true; + bool bPosCorrectionAsVelocity = false; + bool bDisableSoftSnap = false; + bool bAlwaysHardSnap = false; + bool bSkipReplication = false; + bool bDontClearTarget = false; + bool bDrawDebugTargets = false; + bool bDrawDebugVectors = false; + float SleepSecondsClearTarget = 15.0f; + int32 TargetTickAlignmentClampMultiplier = 1; + } + +} +#endif + /*struct FAsyncPhysicsRepCallbackDataVR : public Chaos::FSimCallbackInput { TArray Buffer; @@ -206,7 +281,7 @@ bool FPhysicsReplicationVR::ApplyRigidBodyState(float DeltaSeconds, FBodyInstanc return ApplyRigidBodyState(DeltaSeconds, BI, PhysicsTarget, ErrorCorrection, InPingSecondsOneWay); } -void FPhysicsReplicationVR::SetReplicatedTarget(UPrimitiveComponent* Component, FName BoneName, const FRigidBodyState& ReplicatedTarget, int32 ServerFrame) +/*void FPhysicsReplicationVR::SetReplicatedTarget(UPrimitiveComponent* Component, FName BoneName, const FRigidBodyState& ReplicatedTarget, int32 ServerFrame) { // Skip all of the custom logic if we aren't the server @@ -222,25 +297,30 @@ void FPhysicsReplicationVR::SetReplicatedTarget(UPrimitiveComponent* Component, // If networked physics prediction is enabled, enforce the new physics replication flow via SetReplicatedTarget() using PhysicsObject instead of BodyInstance from BoneName. AActor* Owner = Component->GetOwner(); - if (UPhysicsSettings::Get()->PhysicsPrediction.bEnablePhysicsPrediction && Owner && - (CVarEnableDefaultReplication->GetInt() || Owner->GetPhysicsReplicationMode() != EPhysicsReplicationMode::Default)) // For now, only opt in to the PhysicsObject flow if not using Default replication or if default is allowed via CVar. + + if (Owner && (CVarEnableDefaultReplication->GetBool() || Owner->GetPhysicsReplicationMode() != EPhysicsReplicationMode::Default)) // For now, only opt in to the PhysicsObject flow if not using Default replication or if default is allowed via CVar. { const ENetRole OwnerRole = Owner->GetLocalRole(); const bool bIsSimulated = OwnerRole == ROLE_SimulatedProxy; const bool bIsReplicatedAutonomous = OwnerRole == ROLE_AutonomousProxy && Component->bReplicatePhysicsToAutonomousProxy; if (bIsSimulated || bIsReplicatedAutonomous) { - Chaos::FPhysicsObjectHandle PhysicsObject = Component->GetPhysicsObjectByName(BoneName); + Chaos::FConstPhysicsObjectHandle PhysicsObject = Component->GetPhysicsObjectByName(BoneName); SetReplicatedTargetVR(PhysicsObject, ReplicatedTarget, ServerFrame, Owner->GetPhysicsReplicationMode()); return; } } return FPhysicsReplication::SetReplicatedTarget(Component, BoneName, ReplicatedTarget, ServerFrame); -} +}*/ -void FPhysicsReplicationVR::SetReplicatedTargetVR(Chaos::FPhysicsObject* PhysicsObject, const FRigidBodyState& ReplicatedTarget, int32 ServerFrame, EPhysicsReplicationMode ReplicationMode) +void FPhysicsReplicationVR::SetReplicatedTargetVR(Chaos::FConstPhysicsObjectHandle PhysicsObject, const FRigidBodyState& ReplicatedTarget, int32 ServerFrame, EPhysicsReplicationMode ReplicationMode) { + if (!PhysicsObject) + { + return; + } + UWorld* OwningWorld = GetOwningWorld(); if (OwningWorld == nullptr) { @@ -249,8 +329,8 @@ void FPhysicsReplicationVR::SetReplicatedTargetVR(Chaos::FPhysicsObject* Physics // TODO, Check if owning actor is ROLE_SimulatedProxy or ROLE_AutonomousProxy ? - FReplicatedPhysicsTarget Target; - Target.PhysicsObject = PhysicsObject; + FReplicatedPhysicsTarget Target(PhysicsObject); + Target.ReplicationMode = ReplicationMode; Target.ServerFrame = ServerFrame; Target.TargetState = ReplicatedTarget; @@ -261,6 +341,35 @@ void FPhysicsReplicationVR::SetReplicatedTargetVR(Chaos::FPhysicsObject* Physics ReplicatedTargetsQueueVR.Add(Target); } +void FPhysicsReplicationVR::RemoveReplicatedTarget(UPrimitiveComponent* Component) +{ + + // Skip all of the custom logic if we aren't the server + if (const UWorld* World = GetOwningWorld()) + { + if (World->GetNetMode() == ENetMode::NM_Client) + { + return FPhysicsReplication::RemoveReplicatedTarget(Component); + } + } + + if (Component == nullptr) + { + return; + } + + // Call super version to ensure its removed from the inaccessible deprecated targets list + FPhysicsReplication::RemoveReplicatedTarget(Component); + + // Remove from legacy flow + //ComponentToTargets_DEPRECATED.Remove(Component); + + // Remove from FPhysicsObject flow + Chaos::FConstPhysicsObjectHandle PhysicsObject = Component->GetPhysicsObjectByName(NAME_None); + FReplicatedPhysicsTarget Target(PhysicsObject); // This creates a new but empty target and when it tries to update the current target in the async flow it will remove it from replication since it's empty. + ReplicatedTargetsQueueVR.Add(Target); +} + bool FPhysicsReplicationVR::ApplyRigidBodyState(float DeltaSeconds, FBodyInstance* BI, FReplicatedPhysicsTarget& PhysicsTarget, const FRigidBodyErrorCorrection& ErrorCorrection, const float PingSecondsOneWay, bool* bDidHardSnap) { // Skip all of the custom logic if we aren't the server @@ -521,12 +630,11 @@ bool FPhysicsReplicationVR::ApplyRigidBodyState(float DeltaSeconds, FBodyInstanc else { //If async is used, enqueue for callback - FPhysicsRepAsyncInputData AsyncInputData; + FPhysicsRepAsyncInputData AsyncInputData(nullptr); AsyncInputData.TargetState = NewState; AsyncInputData.TargetState.Position = IdealWorldTM.GetLocation(); AsyncInputData.TargetState.Quaternion = IdealWorldTM.GetRotation(); AsyncInputData.Proxy = static_cast(BI->GetPhysicsActorHandle()); - AsyncInputData.PhysicsObject = nullptr; AsyncInputData.ErrorCorrection = { ErrorCorrection.LinearVelocityCoefficient, ErrorCorrection.AngularVelocityCoefficient, ErrorCorrection.PositionLerp, ErrorCorrection.AngleLerp }; AsyncInputData.LatencyOneWay = PingSeconds; @@ -614,7 +722,7 @@ void FPhysicsReplicationVR::OnTick(float DeltaSeconds, TMapGetFirstPlayerController()) { - LocalFrameOffset = PlayerController->GetServerToLocalAsyncPhysicsTickOffset(); + LocalFrameOffset = PlayerController->GetNetworkPhysicsTickOffset(); } } } @@ -631,33 +739,29 @@ void FPhysicsReplicationVR::OnTick(float DeltaSeconds, TMapGetBodyInstance(Itr.Value().BoneName)) + { + if (PrimComp->GetAttachParent() == nullptr) { - FReplicatedPhysicsTarget& PhysicsTarget = Itr.Value(); - FRigidBodyState& UpdatedState = PhysicsTarget.TargetState; - bool bUpdated = false; - if (AActor* OwningActor = PrimComp->GetOwner()) + if (FBodyInstance* BI = PrimComp->GetBodyInstance(Itr.Value().BoneName)) { - // Remove if there is no owner - if (!OwningActor->GetNetOwningPlayer()) - { - bRemoveItr = true; - } - else + FReplicatedPhysicsTarget& PhysicsTarget = Itr.Value(); + FRigidBodyState& UpdatedState = PhysicsTarget.TargetState; + bool bUpdated = false; + if (AActor* OwningActor = PrimComp->GetOwner()) { // Removed as this is server sided - /*const ENetRole OwnerRole = OwningActor->GetLocalRole(); + /* + const ENetRole OwnerRole = OwningActor->GetLocalRole(); const bool bIsSimulated = OwnerRole == ROLE_SimulatedProxy; const bool bIsReplicatedAutonomous = OwnerRole == ROLE_AutonomousProxy && PrimComp->bReplicatePhysicsToAutonomousProxy; if (bIsSimulated || bIsReplicatedAutonomous)*/ - // Deleted everything here, we will always be the server, I already filtered out clients to default logic { + // Get the ping of this thing's owner. If nobody owns it, + // then it's server authoritative. /*const*/ float OwnerPing = 0.0f;// GetOwnerPing(OwningActor, PhysicsTarget); /*if (UPlayer* OwningPlayer = OwningActor->GetNetOwningPlayer()) @@ -676,12 +780,10 @@ void FPhysicsReplicationVR::OnTick(float DeltaSeconds, TMapSyncComponentToRBPhysics(); } - - // Added a sleeping check from the input state as well, we always want to cease activity on sleep - if (bRestoredState /* || ((UpdatedState.Flags & ERigidBodyFlags::Sleeping) != 0)*/) + if (bRestoredState) { bRemoveItr = true; } @@ -700,34 +800,31 @@ void FPhysicsReplicationVR::OnTick(float DeltaSeconds, TMapInputData.Add(AsyncInputData); - } + AsyncInputData.RepMode = PhysicsTarget.ReplicationMode; + AsyncInputData.ServerFrame = PhysicsTarget.ServerFrame; + AsyncInputData.FrameOffset = LocalFrameOffset; + AsyncInputData.LatencyOneWay = PingSecondsOneWay; + + AsyncInputVR->InputData.Add(AsyncInputData); } ReplicatedTargetsQueueVR.Reset(); @@ -817,8 +914,48 @@ bool FRepMovementVR::GatherActorsMovement(AActor* OwningActor) return true; } + +#pragma region FPhysicsReplicationAsync + +void FPhysicsReplicationAsyncVR::OnPhysicsObjectUnregistered_Internal(Chaos::FConstPhysicsObjectHandle PhysicsObject) +{ + ObjectToTarget.Remove(PhysicsObject); + ObjectToSettings.Remove(PhysicsObject); +} + +void FPhysicsReplicationAsyncVR::RegisterSettings(Chaos::FConstPhysicsObjectHandle PhysicsObject, FNetworkPhysicsSettingsAsync InSettings) +{ + if (PhysicsObject != nullptr) + { + FNetworkPhysicsSettingsAsync& Settings = ObjectToSettings.FindOrAdd(PhysicsObject); + Settings = InSettings; + } +} + +void FPhysicsReplicationAsyncVR::FetchObjectSettings(Chaos::FConstPhysicsObjectHandle PhysicsObject) +{ + FNetworkPhysicsSettingsAsync* CustomSettings = ObjectToSettings.Find(PhysicsObject); + SettingsCurrent = (CustomSettings != nullptr) ? *CustomSettings : SettingsDefault; +} + +void FPhysicsReplicationAsyncVR::OnPostInitialize_Internal() +{ + Chaos::FPBDRigidsSolver* RigidsSolver = static_cast(GetSolver()); + + if (ensure(RigidsSolver)) + { + // This doesn't even do anything currently, nothing gets it #TODO: CHECK BACK ON THIS + //RigidsSolver->SetPhysicsReplication(this); + } +} + void FPhysicsReplicationAsyncVR::OnPreSimulate_Internal() { + if (FPhysicsReplication::ShouldSkipPhysicsReplication()) + { + return; + } + if (const FPhysicsReplicationAsyncInput* AsyncInput = GetConsumerInput_Internal()) { Chaos::FPBDRigidsSolver* RigidsSolver = static_cast(GetSolver()); @@ -826,11 +963,12 @@ void FPhysicsReplicationAsyncVR::OnPreSimulate_Internal() // Early out if this is a resim frame Chaos::FRewindData* RewindData = RigidsSolver->GetRewindData(); - if (RewindData && RewindData->IsResim()) + const bool bRewindDataExist = RewindData != nullptr; + if (bRewindDataExist && RewindData->IsResim()) { - // TODO, Handle the transition from post-resim to interpolation better. + // TODO, Handle the transition from post-resim to interpolation better (disabled by default, resim vs replication interaction is handled via FPhysicsReplicationAsync::CacheResimInteractions) static const auto CVarPostResimWaitForUpdate = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.PostResimWaitForUpdate")); - if (CVarPostResimWaitForUpdate->GetBool() && RewindData->IsFinalResim()) + if (CVarPostResimWaitForUpdate->GetBool() && RewindData->IsFinalResim()) { for (auto Itr = ObjectToTarget.CreateIterator(); Itr; ++Itr) { @@ -839,8 +977,7 @@ void FPhysicsReplicationAsyncVR::OnPreSimulate_Internal() // If final resim frame, mark interpolated targets as waiting for up to date data from the server. if (Target.RepMode == EPhysicsReplicationMode::PredictiveInterpolation) { - Target.bWaiting = true; - Target.ServerFrame = RigidsSolver->GetCurrentFrame() + Target.FrameOffset; + Target.SetWaiting(RigidsSolver->GetCurrentFrame() + Target.FrameOffset, Target.RepModeOverride); } } } @@ -851,8 +988,30 @@ void FPhysicsReplicationAsyncVR::OnPreSimulate_Internal() // Update async targets with target input for (const FPhysicsRepAsyncInputData& Input : AsyncInput->InputData) { + if (Input.TargetState.Flags == ERigidBodyFlags::None) + { + // Remove replication target + ObjectToTarget.Remove(Input.PhysicsObject); + continue; + } + + if (!bRewindDataExist && Input.RepMode == EPhysicsReplicationMode::Resimulation) + { + // We don't have rewind data but an actor is set to replicate using resimulation; we need to enable rewind capture. + if (ensure(Chaos::FPBDRigidsSolver::IsNetworkPhysicsPredictionEnabled())) + { + const int32 NumFrames = FMath::Max(1, Chaos::FPBDRigidsSolver::GetPhysicsHistoryCount()); + RigidsSolver->EnableRewindCapture(NumFrames, true); + } + } + UpdateRewindDataTarget(Input); - UpdateAsyncTarget(Input); + UpdateAsyncTarget(Input, RigidsSolver); + } + + if (Chaos::FPBDRigidsSolver::IsNetworkPhysicsPredictionEnabled()) + { + CacheResimInteractions(); } ApplyTargetStatesAsync(GetDeltaTime_Internal(), AsyncInput->ErrorCorrection, AsyncInput->InputData); @@ -879,9 +1038,7 @@ void FPhysicsReplicationAsyncVR::UpdateRewindDataTarget(const FPhysicsRepAsyncIn } Chaos::FReadPhysicsObjectInterface_Internal Interface = Chaos::FPhysicsObjectInternalInterface::GetRead(); - Chaos::FPBDRigidParticleHandle* Handle = Interface.GetRigidParticle(Input.PhysicsObject); - - if (Handle != nullptr) + if (Chaos::FGeometryParticleHandle* Handle = Interface.GetParticle(Input.PhysicsObject)) { // Cache all target states inside RewindData const int32 LocalFrame = Input.ServerFrame - Input.FrameOffset; @@ -891,7 +1048,7 @@ void FPhysicsReplicationAsyncVR::UpdateRewindDataTarget(const FPhysicsRepAsyncIn } } -void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputData& Input) +void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputData& Input, Chaos::FPBDRigidsSolver* RigidsSolver) { if (Input.PhysicsObject == nullptr) { @@ -899,34 +1056,142 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa } FReplicatedPhysicsTargetAsync* Target = ObjectToTarget.Find(Input.PhysicsObject); - if (Target == nullptr) + bool bFirstTarget = Target == nullptr; + if (bFirstTarget) { - // First time we add a target, set it's previous and correction - // positions to the target position to avoid math with uninitialized - // memory. - Target = &ObjectToTarget.Add(Input.PhysicsObject); + // First time we add a target, set previous state to current input + Target = &ObjectToTarget.Add(Input.PhysicsObject, FReplicatedPhysicsTargetAsync()); Target->PrevPos = Input.TargetState.Position; Target->PrevPosTarget = Input.TargetState.Position; Target->PrevRotTarget = Input.TargetState.Quaternion; Target->PrevLinVel = Input.TargetState.LinVel; + Target->RepModeOverride = Input.RepMode; } - if (Input.ServerFrame > Target->ServerFrame) + /** Target Update Description + * @param Input = incoming state target for replication. + * + * Input comes mainly from the server but can be a faked state produced by the client for example if the client object wakes up from sleeping. + * Fake inputs should have a ServerFrame of -1 (bool bIsFake = Input.ServerFrame == -1) + * Server inputs can have ServerFrame values of either 0 or an incrementing integer value. + * If the ServerFrame is 0 it should always be 0. If it's incrementing it will always increment. + * + * @local Target = The current state target used for replication, to be updated with data from Input. + * Read about the different target properties in FReplicatedPhysicsTargetAsync + * + * IMPORTANT: + * Target.ServerFrame can be -1 if the target is newly created or if it has data from a fake input. + * + * SendInterval is calculated by taking Input.ServerFrame - Target.ServerFrame + * Note, can only be calculated if the server is sending incrementing SendIntervals and if we have received a valid input previously so we have the previous ServerFrame cached in Target. + * + * ReceiveInterval is calculated by taking RigidsSolver->GetCurrentFrame() - Target.ReceiveFrame + * Note that ReceiveInterval is only used if SendInterval is 0 + * + * Target.TickCount starts at 0 and is incremented each tick that the target is used for, TickCount is reset back to 0 each time Target is updated with new Input. + * + * NOTE: With perfect network conditions SendInterval, ReceiveInterval and Target.TickCount will be the same value. + */ + + if ((bFirstTarget || Input.ServerFrame == 0 || Input.ServerFrame > Target->ServerFrame)) { - Target->PhysicsObject = Input.PhysicsObject; - Target->PrevServerFrame = Target->ServerFrame; - Target->ServerFrame = Input.ServerFrame; + // Get the current physics frame + const int32 CurrentFrame = RigidsSolver->GetCurrentFrame(); + + // Cache TickCount before updating it, force to 0 if ServerFrame is -1 + const int32 PrevTickCount = (Target->ServerFrame < 0) ? 0 : Target->TickCount; + + // Cache SendInterval, only calculate if we have a valid Target->ServerFrame, else leave at 0. + const int32 SendInterval = (Target->ServerFrame <= 0) ? 0 : Input.ServerFrame - Target->ServerFrame; + + // Cache if this target was previously allowed to be altered, before this update + const bool bPrevAllowTargetAltering = Target->bAllowTargetAltering; + + // Set if the target is allowed to be altered after this update + Target->bAllowTargetAltering = !(Target->TargetState.Flags & ERigidBodyFlags::Sleeping) && !(Input.TargetState.Flags & ERigidBodyFlags::Sleeping); + + // Set Target->ReceiveInterval from either SendInterval or the number of physics ticks between receiving input states + if (SendInterval > 0) + { + Target->ReceiveInterval = SendInterval; + } + else + { + const int32 PrevReceiveFrame = Target->ReceiveFrame < 0 ? (CurrentFrame - 1) : Target->ReceiveFrame; + Target->ReceiveInterval = (CurrentFrame - PrevReceiveFrame); + } + + // Update target from input and reset properties + PRAGMA_DISABLE_DEPRECATION_WARNINGS + Target->PrevServerFrame = Target->bWaiting ? Input.ServerFrame : Target->ServerFrame; // DEPRECATED UE5.4 + Target->PrevReceiveFrame = (Target->ReceiveFrame == INDEX_NONE) ? (RigidsSolver->GetCurrentFrame() - 1) : Target->ReceiveFrame; // DEPRECATED UE5.4 + PRAGMA_ENABLE_DEPRECATION_WARNINGS + Target->ServerFrame = Input.ServerFrame; + Target->ReceiveFrame = CurrentFrame; Target->TargetState = Input.TargetState; Target->RepMode = Input.RepMode; Target->FrameOffset = Input.FrameOffset; Target->TickCount = 0; - Target->bWaiting = false; + Target->AccumulatedSleepSeconds = 0.0f; + + // Update waiting state + Target->UpdateWaiting(Input.ServerFrame); if (Input.RepMode == EPhysicsReplicationMode::PredictiveInterpolation) { + +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) + static const auto CVarDrawDebugTargets = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DrawDebugTargets")); + if (CVarDrawDebugTargets->GetBool()) + { + const FVector Offset = FVector(0.0f, 0.0f, 50.0f); + + static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime")); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(Input.TargetState.Position + Offset, FVector(15.0f, 15.0f, 15.0f), Input.TargetState.Quaternion, FColor::MakeRandomSeededColor(Input.ServerFrame), false, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f); + } +#endif + // Cache the position we received this target at, Predictive Interpolation will alter the target state but use this as the source position for reconciliation. Target->PrevPosTarget = Input.TargetState.Position; Target->PrevRotTarget = Input.TargetState.Quaternion; + + { + /** Target Alignment Feature + * With variable network conditions state inputs from the server can arrive both later or earlier than expected. + * Target Alignment can adjust for this to make replication act on a target in the timeline that the client is currently replicating in. + * + * If SendInterval is 4 we expect TickCount to be 4. TickCount - SendInterval = 0, meaning the client and server has ticked physics the same amount between the target states. + * + * If SendInterval is 4 and TickCount is 2 we have only simulated physics for 2 ticks with the previous target while the server had simulated physics 4 ticks between previous target and new target + * TickCount - SendInterval = -2 + * To align this we need to adjust the new target by predicting backwards by 2 ticks, else the replication will start replicating towards a state that is 2 ticks further ahead than expected, making replication speed up. + * + * Same goes for vice-versa: + * If SendInterval is 4 and TickCount is 6 we have simulated physics for 6 ticks with the previous target while the server had simulated physics 4 ticks between previous target and new target + * TickCount - SendInterval = 2 + * To align this we need to adjust the new target by predicting forwards by 2 ticks, else the replication will start replicating towards a state that is 2 ticks behind than expected, making replication slow down. + * + * Note that state inputs from the server can arrive fluctuating between above examples, but over time the alignment is evened out to 0. + * If the clients latency is raised or lowered since replication started there might be a consistent offset in the TickCount which is handled by TimeDilation of client physics through APlayerController::UpdateServerAsyncPhysicsTickOffset() + */ + + // Run target alignment if we have been allowed to alter the target during the last two target updates + if (!bFirstTarget && bPrevAllowTargetAltering && Target->bAllowTargetAltering) + { + static const auto CVarTargetTickAlignmentClampMultiplier = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.TargetTickAlignmentClampMultiplier")); + const int32 AdjustedAverageReceiveInterval = FMath::CeilToInt(Target->AverageReceiveInterval) * CVarTargetTickAlignmentClampMultiplier->GetInt(); + + // Set the TickCount to the physics tick offset value from where we expected this target to arrive. + // If the client has ticked 2 times ahead from the last target and this target is 3 ticks in front of the previous target then the TickOffset should be -1 + Target->TickCount = FMath::Clamp(PrevTickCount - Target->ReceiveInterval, -AdjustedAverageReceiveInterval, AdjustedAverageReceiveInterval); + + // Apply target alignment if we aren't waiting for a newer state from the server + if (!Target->IsWaiting()) + { + FPhysicsReplicationAsyncVR::ExtrapolateTarget(*Target, Target->TickCount, GetDeltaTime_Internal()); + } + } + } } } @@ -934,11 +1199,47 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa LatencyOneWay = Input.LatencyOneWay; } + +void FPhysicsReplicationAsyncVR::CacheResimInteractions() +{ + static const auto CVarResimDisableReplicationOnInteraction = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.Resim.DisableReplicationOnInteraction")); + if (!CVarResimDisableReplicationOnInteraction->GetBool()) + { + return; + } + + Chaos::FPBDRigidsSolver* RigidsSolver = static_cast(GetSolver()); + if (RigidsSolver == nullptr) + { + return; + } + + ParticlesInResimIslands.Empty(FMath::CeilToInt(static_cast(ParticlesInResimIslands.Num()) * 0.9f)); + Chaos::Private::FPBDIslandManager& IslandManager = RigidsSolver->GetEvolution()->GetIslandManager(); + Chaos::FWritePhysicsObjectInterface_Internal Interface = Chaos::FPhysicsObjectInternalInterface::GetWrite(); + for (auto Itr = ObjectToTarget.CreateIterator(); Itr; ++Itr) + { + FReplicatedPhysicsTargetAsync& Target = Itr.Value(); + if (Target.RepMode == EPhysicsReplicationMode::Resimulation) + { + Chaos::FConstPhysicsObjectHandle& POHandle = Itr.Key(); + if (Chaos::FGeometryParticleHandle* Handle = Interface.GetParticle(POHandle)) + { + // Get a list of particles from the same island as a resim particle is in, i.e. particles interacting with a resim particle + for (const Chaos::FGeometryParticleHandle* InteractParticle : IslandManager.FindParticlesInIslands(IslandManager.FindParticleIslands(Handle))) + { + ParticlesInResimIslands.Add(InteractParticle->GetHandleIdx()); + } + } + } + } +} + void FPhysicsReplicationAsyncVR::ApplyTargetStatesAsync(const float DeltaSeconds, const FPhysicsRepErrorCorrectionData& ErrorCorrection, const TArray& InputData) { using namespace Chaos; - // Deprecated, BodyInstance flow + // Deprecated, legacy BodyInstance flow for (const FPhysicsRepAsyncInputData& Input : InputData) { if (Input.Proxy != nullptr) @@ -952,40 +1253,38 @@ void FPhysicsReplicationAsyncVR::ApplyTargetStatesAsync(const float DeltaSeconds } // PhysicsObject flow + Chaos::FWritePhysicsObjectInterface_Internal Interface = Chaos::FPhysicsObjectInternalInterface::GetWrite(); for (auto Itr = ObjectToTarget.CreateIterator(); Itr; ++Itr) { bool bRemoveItr = true; // Remove current cached replication target unless replication logic tells us to store it for next tick - FReplicatedPhysicsTargetAsync& Target = Itr.Value(); - - if (Target.PhysicsObject != nullptr) + Chaos::FConstPhysicsObjectHandle& POHandle = Itr.Key(); + if (FGeometryParticleHandle* Handle = Interface.GetParticle(POHandle)) { - Chaos::FWritePhysicsObjectInterface_Internal Interface = Chaos::FPhysicsObjectInternalInterface::GetWrite(); - FPBDRigidParticleHandle* Handle = Interface.GetRigidParticle(Target.PhysicsObject); + FReplicatedPhysicsTargetAsync& Target = Itr.Value(); - if (Handle != nullptr) + + if (FPBDRigidParticleHandle* RigidHandle = Handle->CastToRigidParticle()) { - // TODO, Remove the resim option from project settings, we only need the physics prediction one now - EPhysicsReplicationMode RepMode = Target.RepMode; - if (!Chaos::FPBDRigidsSolver::IsPhysicsResimulationEnabled() && RepMode == EPhysicsReplicationMode::Resimulation) - { - RepMode = EPhysicsReplicationMode::Default; - } + // Cache custom settings for this object if there are any + FetchObjectSettings(POHandle); + const EPhysicsReplicationMode RepMode = Target.IsWaiting() ? Target.RepModeOverride : Target.RepMode; switch (RepMode) { case EPhysicsReplicationMode::Default: - bRemoveItr = DefaultReplication(Handle, Target, DeltaSeconds); + bRemoveItr = DefaultReplication(RigidHandle, Target, DeltaSeconds); break; case EPhysicsReplicationMode::PredictiveInterpolation: - bRemoveItr = PredictiveInterpolation(Handle, Target, DeltaSeconds); + bRemoveItr = PredictiveInterpolation(RigidHandle, Target, DeltaSeconds); break; case EPhysicsReplicationMode::Resimulation: - bRemoveItr = ResimulationReplication(Handle, Target, DeltaSeconds); + bRemoveItr = ResimulationReplication(RigidHandle, Target, DeltaSeconds); break; } + Target.TickCount++; } } @@ -1059,6 +1358,12 @@ bool FPhysicsReplicationAsyncVR::DefaultReplication(Chaos::FPBDRigidParticleHand return true; } + static const auto CVarResimDisableReplicationOnInteraction = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.Resim.DisableReplicationOnInteraction")); + if (CVarResimDisableReplicationOnInteraction->GetBool() && ParticlesInResimIslands.Contains(Handle->GetHandleIdx())) + { + return false; + } + // // NOTES: // @@ -1097,7 +1402,7 @@ bool FPhysicsReplicationAsyncVR::DefaultReplication(Chaos::FPBDRigidParticleHand const FString ObjectName #if CHAOS_DEBUG_NAME - = Handle->DebugName() ? *Handle->DebugName() : FString(TEXT("")); + = Handle && Handle->DebugName() ? *Handle->DebugName() : FString(TEXT("")); #else = FString(TEXT("")); #endif @@ -1162,10 +1467,10 @@ bool FPhysicsReplicationAsyncVR::DefaultReplication(Chaos::FPBDRigidParticleHand // Get Current state FRigidBodyState CurrentState; - CurrentState.Position = Handle->X(); - CurrentState.Quaternion = Handle->R(); - CurrentState.AngVel = Handle->W(); - CurrentState.LinVel = Handle->V(); + CurrentState.Position = Handle->GetX(); + CurrentState.Quaternion = Handle->GetR(); + CurrentState.AngVel = Handle->GetW(); + CurrentState.LinVel = Handle->GetV(); // Starting from the last known authoritative position, and @@ -1317,7 +1622,13 @@ bool FPhysicsReplicationAsyncVR::DefaultReplication(Chaos::FPBDRigidParticleHand */ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticleHandle* Handle, FReplicatedPhysicsTargetAsync& Target, const float DeltaSeconds) { - if (Target.bWaiting) + static const auto CVarSkipReplication = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.SkipReplication")); + if (CVarSkipReplication->GetBool()) + { + return true; + } + + if (Target.IsWaiting()) { return false; } @@ -1328,171 +1639,341 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl return true; } - static const auto CVarErrorAccumulationSeconds = IConsoleManager::Get().FindConsoleVariable(TEXT("p.ErrorAccumulationSeconds")); - const float ErrorAccumulationSeconds = CVarErrorAccumulationSeconds->GetFloat() >= 0.0f ? CVarErrorAccumulationSeconds->GetFloat() : ErrorCorrectionDefault.ErrorAccumulationSeconds; - - static const auto CVarMaxRestoredStateError = IConsoleManager::Get().FindConsoleVariable(TEXT("p.MaxRestoredStateError")); - const float MaxRestoredStateErrorSqr = CVarMaxRestoredStateError->GetFloat() >= 0.0f ? - (CVarMaxRestoredStateError->GetFloat() * CVarMaxRestoredStateError->GetFloat()) : - (ErrorCorrectionDefault.MaxRestoredStateError * ErrorCorrectionDefault.MaxRestoredStateError); + static const auto CVarResimDisableReplicationOnInteraction = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.Resim.DisableReplicationOnInteraction")); + if (CVarResimDisableReplicationOnInteraction->GetBool() && ParticlesInResimIslands.Contains(Handle->GetHandleIdx())) + { + // If particle is in an island with a resim object, don't run replication and wait for an up to date target (after leaving the island) + Target.SetWaiting(RigidsSolver->GetCurrentFrame() + Target.FrameOffset, EPhysicsReplicationMode::Resimulation); + return false; + } - const bool bShouldSleep = (Target.TargetState.Flags & ERigidBodyFlags::Sleeping) != 0; - const int32 LocalFrame = Target.ServerFrame - Target.FrameOffset; - const int32 NumPredictedFrames = RigidsSolver->GetCurrentFrame() - LocalFrame - Target.TickCount; - const float PredictedTime = DeltaSeconds * NumPredictedFrames; - const float SendRate = (Target.ServerFrame - Target.PrevServerFrame) * DeltaSeconds; +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) + static const auto CVarDrawDebugTargets = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DrawDebugTargets")); + if (CVarDrawDebugTargets->GetBool()) + { + const FVector Offset = FVector(0.0f, 0.0f, 50.0f); + const FVector StartPos = Target.TargetState.Position + Offset; + const int32 SizeMultiplier = FMath::Clamp(Target.TickCount, -4, 30); + static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime")); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(StartPos, FVector(5.0f + SizeMultiplier * 0.75f, 5.0f + SizeMultiplier * 0.75f, 5.0f + SizeMultiplier * 0.75f), Target.TargetState.Quaternion, FColor::MakeRandomSeededColor(Target.ServerFrame), false, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f); + } +#endif - static const auto CVarPosCorrectionTimeMultiplier = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.PosCorrectionTimeMultiplier")); - const float PosCorrectionTime = PredictedTime * CVarPosCorrectionTimeMultiplier->GetFloat(); + const bool bIsSleeping = Handle->IsSleeping(); + const bool bCanSimulate = Handle->IsDynamic() || bIsSleeping; - static const auto CVarInterpolationTimeMultiplier = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.InterpolationTimeMultiplier")); - const float InterpolationTime = SendRate * CVarInterpolationTimeMultiplier->GetFloat(); + // Accumulate sleep time or reset back to 0s if not sleeping + Target.AccumulatedSleepSeconds = bIsSleeping ? (Target.AccumulatedSleepSeconds + DeltaSeconds) : 0.0f; + + // Helper for sleep and target clearing at replication end + auto EndReplicationHelper = [RigidsSolver, Handle, bCanSimulate, bIsSleeping, DeltaSeconds](FReplicatedPhysicsTargetAsync& Target, bool bOkToClear) -> bool + { + const bool bShouldSleep = (Target.TargetState.Flags & ERigidBodyFlags::Sleeping) != 0; + const bool bReplicatingPhysics = (Target.TargetState.Flags & ERigidBodyFlags::RepPhysics) != 0; + + // --- Set Sleep State --- + if (bOkToClear && bShouldSleep && bCanSimulate) + { + RigidsSolver->GetEvolution()->SetParticleObjectState(Handle, Chaos::EObjectStateType::Sleeping); + } + + static const auto CVarSleepSecondsClearTarget = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.SleepSecondsClearTarget")); + static const auto CVarDontClearTarget = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DontClearTarget")); + // --- Should replication stop? --- + const bool bClearTarget = + (!bCanSimulate + || (bOkToClear && bShouldSleep && Target.AccumulatedSleepSeconds >= CVarSleepSecondsClearTarget->GetFloat()) // Don't clear the target due to sleeping until the object both should sleep and is sleeping for n seconds + || (bOkToClear && !bReplicatingPhysics)) + && !CVarDontClearTarget->GetBool(); + + // --- Target Prediction --- + if (!bClearTarget && Target.bAllowTargetAltering) + { + static const auto CVarExtrapolationTimeMultiplier = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.ExtrapolationTimeMultiplier")); + static const auto CVarExtrapolationMinTime = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.ExtrapolationMinTime")); + const int32 ExtrapolationTickLimit = FMath::Max( + FMath::CeilToInt(Target.AverageReceiveInterval * CVarExtrapolationTimeMultiplier->GetFloat()), // Extrapolate time based on receive interval * multiplier + FMath::CeilToInt(CVarExtrapolationMinTime->GetFloat() / DeltaSeconds)); // At least extrapolate for N seconds + if (Target.TickCount <= ExtrapolationTickLimit) + { + FPhysicsReplicationAsyncVR::ExtrapolateTarget(Target, 1, DeltaSeconds); + } + } + + return bClearTarget; + }; + + + static const auto CVarEarlyOutWithVelocity = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.EarlyOutWithVelocity")); + static const auto CVarEarlyOutDistanceSqr = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.EarlyOutDistanceSqr")); + // If target velocity is low enough, check the distance from the current position to the source position of our target to see if it's low enough to early out of replication + const bool bXCanEarlyOut = (CVarEarlyOutWithVelocity->GetBool() || Target.TargetState.LinVel.SizeSquared() < UE_KINDA_SMALL_NUMBER) && + (Target.PrevPosTarget - Handle->GetX()).SizeSquared() < CVarEarlyOutDistanceSqr->GetFloat(); + + // Early out if we are within range of target, also apply target sleep state + if (bXCanEarlyOut) + { + // Get the rotational offset between the blended rotation target and the current rotation + const FQuat TargetRotDelta = Target.TargetState.Quaternion * Handle->GetR().Inverse(); + + // Convert to angle axis + float Angle; + FVector Axis; + TargetRotDelta.ToAxisAndAngle(Axis, Angle); + Angle = FMath::Abs(FMath::UnwindRadians(Angle)); + + static const auto CVarEarlyOutAngle = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.EarlyOutAngle")); + if (Angle < FMath::DegreesToRadians(CVarEarlyOutAngle->GetFloat())) + { + // Early Out + return EndReplicationHelper(Target, true); + } + } + + // Wake up if sleeping + if (bIsSleeping) + { + RigidsSolver->GetEvolution()->SetParticleObjectState(Handle, Chaos::EObjectStateType::Dynamic); + } + + static const auto CVarAverageReceiveIntervalSmoothing = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.AverageReceiveIntervalSmoothing")); + // Update the AverageReceiveInterval if Target.ReceiveInterval has a valid value to update from + Target.AverageReceiveInterval = Target.ReceiveInterval == 0 ? Target.AverageReceiveInterval : FMath::Lerp(Target.AverageReceiveInterval, Target.ReceiveInterval, FMath::Clamp((1.0f / (Target.ReceiveInterval * CVarAverageReceiveIntervalSmoothing->GetFloat())), 0.0f, 1.0f)); // CurrentState FRigidBodyState CurrentState; - CurrentState.Position = Handle->X(); - CurrentState.Quaternion = Handle->R(); - CurrentState.LinVel = Handle->V(); - CurrentState.AngVel = Handle->W(); + CurrentState.Position = Handle->GetX(); + CurrentState.Quaternion = Handle->GetR(); + CurrentState.LinVel = Handle->GetV(); + CurrentState.AngVel = Handle->GetW(); // Note: Current angular velocity is in Radians // NewState - const FVector TargetPos = Target.TargetState.Position; + const FVector TargetPos = FVector(Target.TargetState.Position); const FQuat TargetRot = Target.TargetState.Quaternion; - const FVector TargetLinVel = Target.TargetState.LinVel; - const FVector TargetAngVel = Target.TargetState.AngVel; - + const FVector TargetLinVel = FVector(Target.TargetState.LinVel); + const FVector TargetAngVel = FVector(Target.TargetState.AngVel); // Note: Target angular velocity is in Degrees /** --- Reconciliation --- - * Get the traveled direction and distance from previous frame and compare with replicated linear velocity. - * If the object isn't moving enough along the replicated velocity it's considered stuck and needs a hard reconciliation. - */ - const FVector PrevDiff = CurrentState.Position - Target.PrevPos; - const float ExpectedDistance = (Target.PrevLinVel * DeltaSeconds).Size(); - const float CoveredDistance = FVector::DotProduct(PrevDiff, Target.PrevLinVel.GetSafeNormal()); + * If target velocities are low enough, check the traveled direction and distance from previous frame and compare with replicated linear velocity. + * If the object isn't moving enough along the replicated velocity it's considered stuck and needs reconciliation. + * SoftSnap is performed each tick while there is a registered error, if enough time pass HardSnap forces the object into the correct state. */ + static const auto CVarVelocityBased = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.VelocityBased")); + bool bSoftSnap = !CVarVelocityBased->GetBool(); - // If the object is moving less than X% of the expected distance, accumulate error seconds - static const auto CVarMinExpectedDistanceCovered = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.MinExpectedDistanceCovered")); - if (CoveredDistance / ExpectedDistance < CVarMinExpectedDistanceCovered->GetFloat()) + static const auto CVarDisableErrorVelocityLimits = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DisableErrorVelocityLimits")); + static const auto CVarErrorAccLinVelMaxLimit = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.ErrorAccLinVelMaxLimit")); + static const auto CVarErrorAccAngVelMaxLimit = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.ErrorAccAngVelMaxLimit")); + if (CVarDisableErrorVelocityLimits->GetBool() || + (TargetLinVel.Size() < CVarErrorAccLinVelMaxLimit->GetFloat() && TargetAngVel.Size() < CVarErrorAccAngVelMaxLimit->GetFloat())) { - Target.AccumulatedErrorSeconds += DeltaSeconds; + const FVector PrevDiff = CurrentState.Position - Target.PrevPos; + const float ExpectedDistance = (Target.PrevLinVel * DeltaSeconds).Size(); + const float CoveredDistance = FVector::DotProduct(PrevDiff, Target.PrevLinVel.GetSafeNormal()); + const float CoveredAplha = FMath::Clamp(CoveredDistance / ExpectedDistance, 0.0f, 1.0f); + + // If the object is moving less than X% of the expected distance, accumulate error seconds + static const auto CVarMinExpectedDistanceCovered = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.MinExpectedDistanceCovered")); + if (CoveredAplha < CVarMinExpectedDistanceCovered->GetFloat()) + { + Target.AccumulatedErrorSeconds += DeltaSeconds; + bSoftSnap = true; + } + else if (Target.AccumulatedErrorSeconds > 0.f) + { + static const auto CVarErrorAccumulationDecreaseMultiplier = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.ErrorAccumulationDecreaseMultiplier")); + const float DecreaseTime = DeltaSeconds * CVarErrorAccumulationDecreaseMultiplier->GetFloat(); + Target.AccumulatedErrorSeconds = FMath::Max(Target.AccumulatedErrorSeconds - DecreaseTime, 0.0f); + bSoftSnap = true; + } } else { - Target.AccumulatedErrorSeconds = FMath::Max(Target.AccumulatedErrorSeconds - DeltaSeconds, 0.0f); + Target.AccumulatedErrorSeconds = 0; } - static const auto CVarbPredictiveInterpolationAlwaysHardSnap = IConsoleManager::Get().FindConsoleVariable(TEXT("p.PredictiveInterpolation.AlwaysHardSnap")); - const bool bHardSnap = Target.AccumulatedErrorSeconds > ErrorAccumulationSeconds || CVarbPredictiveInterpolationAlwaysHardSnap->GetBool(); - bool bClearTarget = bHardSnap; + static const auto CVarVelocityBasedSetting = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.VelocityBased")); + if (SettingsCurrent.PredictiveInterpolationSettings.GetDisableSoftSnap() && CVarVelocityBasedSetting->GetBool()) + { + bSoftSnap = false; + } + + static const auto CVarErrorAccumulationSeconds = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.ErrorAccumulationSeconds")); + static const auto CVarAlwaysHardSnap = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.AlwaysHardSnap")); + const bool bHardSnap = !bCanSimulate || + Target.AccumulatedErrorSeconds > CVarErrorAccumulationSeconds->GetFloat() || + CVarAlwaysHardSnap->GetBool(); + if (bHardSnap) { - // Too much error so just snap state here and be done with it Target.AccumulatedErrorSeconds = 0.0f; - Handle->SetX(Target.PrevPosTarget); - Handle->SetP(Target.PrevPosTarget); - Handle->SetR(Target.PrevRotTarget); - Handle->SetQ(Target.PrevRotTarget); - Handle->SetV(Target.TargetState.LinVel); - Handle->SetW(Target.TargetState.AngVel); + + if (Handle->IsKinematic()) + { + // Set a FKinematicTarget to hard snap kinematic object + const Chaos::FKinematicTarget KinTarget = Chaos::FKinematicTarget::MakePositionTarget(Target.PrevPosTarget, Target.PrevRotTarget); // Uses EKinematicTargetMode::Position + RigidsSolver->GetEvolution()->SetParticleKinematicTarget(Handle, KinTarget); + } + else + { + // Set XPRQVW to hard snap dynamic object + Handle->SetX(Target.PrevPosTarget); + Handle->SetP(Target.PrevPosTarget); + Handle->SetR(Target.PrevRotTarget); + Handle->SetQ(Target.PrevRotTarget); + Handle->SetV(Target.TargetState.LinVel); + Handle->SetW(FMath::DegreesToRadians(Target.TargetState.AngVel)); + } + + // Cache data for next replication + Target.PrevLinVel = FVector(Target.TargetState.LinVel); + + // End replication and go to sleep if that's requested + return EndReplicationHelper(Target, true); } else // Velocity-based Replication { - const Chaos::EObjectStateType ObjectState = Handle->ObjectState(); - if (ObjectState != Chaos::EObjectStateType::Dynamic) - { - RigidsSolver->GetEvolution()->SetParticleObjectState(Handle, Chaos::EObjectStateType::Dynamic); + // Calculate interpolation time based on current average receive rate + const float AverageReceiveIntervalSeconds = Target.AverageReceiveInterval * DeltaSeconds; + const float InterpolationTime = AverageReceiveIntervalSeconds * SettingsCurrent.PredictiveInterpolationSettings.GetPosInterpolationTimeMultiplier(); + + // Calculate position correction time based on current Round Trip Time + const float RTT = LatencyOneWay * 2.f; + const float PosCorrectionTime = FMath::Max(SettingsCurrent.PredictiveInterpolationSettings.GetPosCorrectionTimeBase() + AverageReceiveIntervalSeconds + RTT * SettingsCurrent.PredictiveInterpolationSettings.GetPosCorrectionTimeMultiplier(), + DeltaSeconds + SettingsCurrent.PredictiveInterpolationSettings.GetPosCorrectionTimeMin()); + const float RotCorrectionTime = FMath::Max(SettingsCurrent.PredictiveInterpolationSettings.GetRotCorrectionTimeBase() + AverageReceiveIntervalSeconds + RTT * SettingsCurrent.PredictiveInterpolationSettings.GetRotCorrectionTimeMultiplier(), + DeltaSeconds + SettingsCurrent.PredictiveInterpolationSettings.GetRotCorrectionTimeMin()); + + if ((bXCanEarlyOut && SettingsCurrent.PredictiveInterpolationSettings.GetSkipVelocityRepOnPosEarlyOut()) == false) + { // --- Velocity Replication --- + + // Get PosDiff + const FVector PosDiff = TargetPos - CurrentState.Position; + + // Get LinVelDiff by adding inverted CurrentState.LinVel to TargetLinVel + const FVector LinVelDiff = -CurrentState.LinVel + TargetLinVel; + + // Calculate velocity blend amount for this tick as an alpha value + const float Alpha = FMath::Clamp(DeltaSeconds / InterpolationTime, 0.0f, 1.0f); + + FVector RepLinVel; + static const auto CVarPosCorrectionAsVelocity = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.PosCorrectionAsVelocity")); + if (CVarPosCorrectionAsVelocity->GetBool()) + { + // Convert PosDiff to a velocity + const FVector PosDiffVelocity = PosDiff / PosCorrectionTime; + + // Add PosDiffVelocity to LinVelDiff to get BlendedTargetVelocity + const FVector BlendedTargetVelocity = LinVelDiff + PosDiffVelocity; + + // Add BlendedTargetVelocity onto current velocity + + RepLinVel = CurrentState.LinVel + (BlendedTargetVelocity * Alpha); + } + else // Positional correction as position shift + { + // Calculate the PosDiff amount to correct this tick + const FVector PosDiffVelocityDelta = PosDiff * (DeltaSeconds / PosCorrectionTime); // Same as (PosDiff / PosCorrectionTime) * DeltaSeconds + + // Add velocity diff onto current velocity + RepLinVel = CurrentState.LinVel + (LinVelDiff * Alpha); + + + // Apply positional correction + Handle->SetX(Handle->GetX() + PosDiffVelocityDelta); + } + + // Apply velocity replication + + Handle->SetV(RepLinVel); + +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) + static const auto CVarDrawDebugVectors = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DrawDebugVectors")); + if (CVarDrawDebugVectors->GetBool()) + { + const FVector Offset = FVector(0.0f, 0.0f, 50.0f); + const FVector OffsetAdd = FVector(0.0f, 0.0f, 10.0f); + const FVector StartPos = TargetPos + Offset; + FVector Direction = TargetLinVel; + Direction.Normalize(); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow((StartPos + OffsetAdd * 0), (StartPos + OffsetAdd * 0) + TargetLinVel * 0.5f, 5.0f, FColor::Green, false, -1.0f, 0, 2.0f); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow((StartPos + OffsetAdd * 1), (StartPos + OffsetAdd * 1) + CurrentState.LinVel * 0.5f, 5.0f, FColor::Blue, false, -1.0f, 0, 2.0f); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow((StartPos + OffsetAdd * 2), (StartPos + OffsetAdd * 2) + (Target.PrevLinVel - CurrentState.LinVel) * 0.5f, 5.0f, FColor::Red, false, -1.0f, 0, 2.0f); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow((StartPos + OffsetAdd * 3), (StartPos + OffsetAdd * 3) + RepLinVel * 0.5f, 5.0f, FColor::Magenta, false, -1.0f, 0, 2.0f); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow((StartPos + OffsetAdd * 4), (StartPos + OffsetAdd * 4) + (Target.PrevLinVel - RepLinVel) * 0.5f, 5.0f, FColor::Orange, false, -1.0f, 0, 2.0f); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow((StartPos + OffsetAdd * 5), (StartPos + OffsetAdd * 5) + Direction * RTT, 5.0f, FColor::White, false, -1.0f, 0, 2.0f); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow((StartPos + OffsetAdd * 6), (StartPos + OffsetAdd * 6) + Direction * InterpolationTime, 5.0f, FColor::Yellow, false, -1.0f, 0, 2.0f); + } +#endif + // Cache data for next replication + Target.PrevLinVel = FVector(RepLinVel); } + { // --- Angular Velocity Replication --- + /* Todo, Implement InterpolationTime */ - // --- Velocity Replication --- - // Get PosDiff - const FVector PosDiff = TargetPos - CurrentState.Position; + // Extrapolate current rotation along current angular velocity to see where we would end up + float CurAngVelSize; + FVector CurAngVelAxis; + CurrentState.AngVel.FVector::ToDirectionAndLength(CurAngVelAxis, CurAngVelSize); + const FQuat CurRotExtrapDelta = FQuat(CurAngVelAxis, CurAngVelSize * DeltaSeconds); + const FQuat CurRotExtrap = CurRotExtrapDelta * CurrentState.Quaternion; - // Convert PosDiff to a velocity - const FVector PosDiffVelocity = PosDiff / PosCorrectionTime; + // Slerp from the extrapolated current rotation towards the target rotation + // This takes current angular velocity into account + const float RotCorrectionAmount = FMath::Clamp(DeltaSeconds / RotCorrectionTime, 0.0f, 1.0f); + const FQuat TargetRotBlended = FQuat::Slerp(CurRotExtrap, TargetRot, RotCorrectionAmount); - // Get LinVelDiff by adding inverted CurrentState.LinVel to TargetLinVel - const FVector LinVelDiff = -CurrentState.LinVel + TargetLinVel; + // Get the rotational offset between the blended rotation target and the current rotation + const FQuat TargetRotDelta = TargetRotBlended * CurrentState.Quaternion.Inverse(); - // Add PosDiffVelocity to LinVelDiff to get BlendedTargetVelocity - const FVector BlendedTargetVelocity = LinVelDiff + PosDiffVelocity; + // Convert the rotational delta to angular velocity + float WAngle; + FVector WAxis; + TargetRotDelta.ToAxisAndAngle(WAxis, WAngle); + const FVector TargetRotDeltaBlend = FVector(WAxis * (WAngle / (DeltaSeconds * SettingsCurrent.PredictiveInterpolationSettings.GetRotInterpolationTimeMultiplier()))); + const FVector RepAngVel = FMath::DegreesToRadians(TargetAngVel) + TargetRotDeltaBlend; - // Multiply BlendedTargetVelocity with(deltaTime / interpolationTime), clamp to 1 and add to CurrentState.LinVel to get BlendedTargetVelocityInterpolated - const float BlendStepAmount = FMath::Clamp(DeltaSeconds / InterpolationTime, 0.f, 1.f); - const FVector RepLinVel = CurrentState.LinVel + (BlendedTargetVelocity * BlendStepAmount); + Handle->SetW(RepAngVel); + } - - // --- Angular Velocity Replication --- - // Extrapolate current rotation along current angular velocity to see where we would end up - float CurAngVelSize; - FVector CurAngVelAxis; - CurrentState.AngVel.FVector::ToDirectionAndLength(CurAngVelAxis, CurAngVelSize); - CurAngVelSize = FMath::DegreesToRadians(CurAngVelSize); - const FQuat CurRotExtrapDelta = FQuat(CurAngVelAxis, CurAngVelSize * DeltaSeconds); - const FQuat CurRotExtrap = CurRotExtrapDelta * CurrentState.Quaternion; - - // Slerp from the extrapolated current rotation towards the target rotation - // This takes current angular velocity into account - const FQuat TargetRotBlended = FQuat::Slerp(CurRotExtrap, TargetRot, BlendStepAmount); - - // Get the rotational offset between the blended rotation target and the current rotation - const FQuat TargetRotDelta = TargetRotBlended * CurrentState.Quaternion.Inverse(); - - // Convert the rotational delta to angular velocity with a magnitude that will make it arrive at the rotation after DeltaTime has passed - float WAngle; - FVector WAxis; - TargetRotDelta.ToAxisAndAngle(WAxis, WAngle); - - const FVector RepAngVel = WAxis * (WAngle / DeltaSeconds); - - - // Apply velocity - Handle->SetV(RepLinVel); - Handle->SetW(RepAngVel); - - - // Cache data for reconciliation + // Cache data for next replication Target.PrevPos = FVector(CurrentState.Position); - Target.PrevLinVel = FVector(RepLinVel); - } - - if (bShouldSleep) - { - // --- Sleep --- - // Get the distance from the current position to the source position of our target state - const float SourceDistanceSqr = (Target.PrevPosTarget - CurrentState.Position).SizeSquared(); - - // Don't allow kinematic to sleeping transition - static const auto CVarMaxDistanceToSleepSqr = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.MaxDistanceToSleepSqr")); - if (SourceDistanceSqr < CVarMaxDistanceToSleepSqr->GetFloat() && !Handle->IsKinematic()) + if (bSoftSnap) { - RigidsSolver->GetEvolution()->SetParticleObjectState(Handle, Chaos::EObjectStateType::Sleeping); - bClearTarget = true; - } - } - else - { - // --- Target Extrapolation --- - static const auto CVarExtrapolationTimeMultiplier = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.ExtrapolationTimeMultiplier")); - if ((Target.TickCount * DeltaSeconds) < SendRate * CVarExtrapolationTimeMultiplier->GetFloat()) - { - // Extrapolate target position - Target.TargetState.Position = Target.TargetState.Position + Target.TargetState.LinVel * DeltaSeconds; + const FVector SoftSnapPos = FMath::Lerp(FVector(CurrentState.Position), + SettingsCurrent.PredictiveInterpolationSettings.GetSoftSnapToSource() ? Target.PrevPosTarget : Target.TargetState.Position, + FMath::Clamp(SettingsCurrent.PredictiveInterpolationSettings.GetSoftSnapPosStrength(), 0.0f, 1.0f)); - // Extrapolate target rotation - float TargetAngVelSize; - FVector TargetAngVelAxis; - Target.TargetState.AngVel.FVector::ToDirectionAndLength(TargetAngVelAxis, TargetAngVelSize); - TargetAngVelSize = FMath::DegreesToRadians(TargetAngVelSize); - const FQuat TargetRotExtrapDelta = FQuat(TargetAngVelAxis, TargetAngVelSize * DeltaSeconds); - Target.TargetState.Quaternion = TargetRotExtrapDelta * Target.TargetState.Quaternion; + const FQuat SoftSnapRot = FQuat::Slerp(CurrentState.Quaternion, + SettingsCurrent.PredictiveInterpolationSettings.GetSoftSnapToSource() ? Target.PrevRotTarget : Target.TargetState.Quaternion, + FMath::Clamp(SettingsCurrent.PredictiveInterpolationSettings.GetSoftSnapRotStrength(), 0.0f, 1.0f)); + + Handle->SetX(SoftSnapPos); + Handle->SetP(SoftSnapPos); + Handle->SetR(SoftSnapRot); + Handle->SetQ(SoftSnapRot); } } - Target.TickCount++; + return EndReplicationHelper(Target, false); +} - return bClearTarget;; +/** Static function to extrapolate a target for N ticks using X DeltaSeconds */ +void FPhysicsReplicationAsyncVR::ExtrapolateTarget(FReplicatedPhysicsTargetAsync& Target, const int32 ExtrapolateFrames, const float DeltaSeconds) +{ + const float ExtrapolationTime = DeltaSeconds * static_cast(ExtrapolateFrames); + + // Extrapolate target position + Target.TargetState.Position = Target.TargetState.Position + Target.TargetState.LinVel * ExtrapolationTime; + + // Extrapolate target rotation + float TargetAngVelSize; + FVector TargetAngVelAxis; + Target.TargetState.AngVel.FVector::ToDirectionAndLength(TargetAngVelAxis, TargetAngVelSize); + TargetAngVelSize = FMath::DegreesToRadians(TargetAngVelSize); + const FQuat TargetRotExtrapDelta = FQuat(TargetAngVelAxis, TargetAngVelSize * ExtrapolationTime); + Target.TargetState.Quaternion = TargetRotExtrapDelta * Target.TargetState.Quaternion; } /** Compare states and trigger resimulation if needed */ @@ -1512,67 +1993,131 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl const int32 LocalFrame = Target.ServerFrame - Target.FrameOffset; - if (LocalFrame <= RewindData->CurrentFrame() && LocalFrame >= RewindData->GetEarliestFrame_Internal()) + if (LocalFrame >= RewindData->CurrentFrame() || LocalFrame < RewindData->GetEarliestFrame_Internal()) { - static constexpr Chaos::FFrameAndPhase::EParticleHistoryPhase RewindPhase = Chaos::FFrameAndPhase::EParticleHistoryPhase::PostPushData; + if (LocalFrame > 0 && (RewindData->CurrentFrame() - RewindData->GetEarliestFrame_Internal()) == RewindData->Capacity()) + { + UE_LOG(LogPhysics, Warning, TEXT("FPhysicsReplication::ResimulationReplication target frame (%d) out of rewind data bounds (%d,%d)"), + LocalFrame, RewindData->GetEarliestFrame_Internal(), RewindData->CurrentFrame()); + } + return true; + } - FAsyncPhysicsTimestamp TimeStamp; - TimeStamp.LocalFrame = RewindData->CurrentFrame(); + bool bClearTarget = true; - const float ResimErrorThreshold = Chaos::FPhysicsSolverBase::ResimulationErrorThreshold(); - auto PastState = RewindData->GetPastStateAtFrame(*Handle, LocalFrame, RewindPhase); + static constexpr Chaos::FFrameAndPhase::EParticleHistoryPhase RewindPhase = Chaos::FFrameAndPhase::EParticleHistoryPhase::PostPushData; + + const float ResimErrorThreshold = SettingsCurrent.ResimulationSettings.GetResimulationErrorThreshold(Chaos::FPhysicsSolverBase::ResimulationErrorThreshold()); + const Chaos::FGeometryParticleState PastState = RewindData->GetPastStateAtFrame(*Handle, LocalFrame, RewindPhase); + + const FVector ErrorOffset = (Target.TargetState.Position - PastState.GetX()); + const float ErrorDistance = ErrorOffset.Size(); + const bool ShouldTriggerResim = ErrorDistance >= ResimErrorThreshold; - const FVector ErrorOffset = (PastState.X() - Target.TargetState.Position); - const float ErrorDistance = ErrorOffset.Size(); - const bool ShouldTriggerResim = ErrorDistance >= ResimErrorThreshold; - float ColorLerp = ShouldTriggerResim ? 1.0f : 0.0f; #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - if (Chaos::FPhysicsSolverBase::CanDebugNetworkPhysicsPrediction()) - { - UE_LOG(LogTemp, Log, TEXT("Apply Rigid body state at local frame %d with offset = %d"), LocalFrame, Target.FrameOffset); - UE_LOG(LogTemp, Log, TEXT("Particle Position Error = %f | Should Trigger Resim = %s | Server Frame = %d | Client Frame = %d"), ErrorDistance, (ShouldTriggerResim ? TEXT("True") : TEXT("False")), Target.ServerFrame, LocalFrame); - UE_LOG(LogTemp, Log, TEXT("Particle Target Position = %s | Current Position = %s"), *Target.TargetState.Position.ToString(), *PastState.X().ToString()); - UE_LOG(LogTemp, Log, TEXT("Particle Target Velocity = %s | Current Velocity = %s"), *Target.TargetState.LinVel.ToString(), *PastState.V().ToString()); - UE_LOG(LogTemp, Log, TEXT("Particle Target Quaternion = %s | Current Quaternion = %s"), *Target.TargetState.Quaternion.ToString(), *PastState.R().ToString()); - UE_LOG(LogTemp, Log, TEXT("Particle Target Omega = %s | Current Omega= %s"), *Target.TargetState.AngVel.ToString(), *PastState.W().ToString()); + if (Chaos::FPhysicsSolverBase::CanDebugNetworkPhysicsPrediction()) + { + UE_LOG(LogTemp, Log, TEXT("Apply Rigid body state at local frame %d with offset = %d"), LocalFrame, Target.FrameOffset); + UE_LOG(LogTemp, Log, TEXT("Particle Position Error = %f | Should Trigger Resim = %s | Server Frame = %d | Client Frame = %d"), ErrorDistance, (ShouldTriggerResim ? TEXT("True") : TEXT("False")), Target.ServerFrame, LocalFrame); + UE_LOG(LogTemp, Log, TEXT("Particle Target Position = %s | Current Position = %s"), *Target.TargetState.Position.ToString(), *PastState.GetX().ToString()); + UE_LOG(LogTemp, Log, TEXT("Particle Target Velocity = %s | Current Velocity = %s"), *Target.TargetState.LinVel.ToString(), *PastState.GetV().ToString()); + UE_LOG(LogTemp, Log, TEXT("Particle Target Quaternion = %s | Current Quaternion = %s"), *Target.TargetState.Quaternion.ToString(), *PastState.GetR().ToString()); + UE_LOG(LogTemp, Log, TEXT("Particle Target Omega = %s | Current Omega= %s"), *Target.TargetState.AngVel.ToString(), *PastState.GetW().ToString()); + } - { // DrawDebug - static constexpr float BoxSize = 5.0f; - const FColor DebugColor = FLinearColor::LerpUsingHSV(FLinearColor::Green, FLinearColor::Red, ColorLerp).ToFColor(false); + static const auto CVarResimDrawDebug = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.Resim.DrawDebug")); + if (CVarResimDrawDebug->GetBool()) + { + static constexpr float BoxSize = 5.0f; + const float ColorLerp = ShouldTriggerResim ? 1.0f : 0.0f; + const FColor DebugColor = FLinearColor::LerpUsingHSV(FLinearColor::Green, FLinearColor::Red, ColorLerp).ToFColor(false); - static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime")); - - Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(Target.TargetState.Position, FVector(BoxSize, BoxSize, BoxSize), Target.TargetState.Quaternion, FColor::Orange, true, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f); - Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(PastState.X(), FVector(6, 6, 6), PastState.R(), DebugColor, true, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f); - - Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow(PastState.X(), Target.TargetState.Position, 5.0f, FColor::Green, true, CVarNetCorrectionLifetime->GetFloat(), 0, 0.5f); - } - } + static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime")); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(Target.TargetState.Position, FVector(BoxSize, BoxSize, BoxSize), Target.TargetState.Quaternion, FColor::Orange, true, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(PastState.GetX(), FVector(6, 6, 6), PastState.GetR(), DebugColor, true, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow(PastState.GetX(), Target.TargetState.Position, 5.0f, FColor::MakeRandomSeededColor(LocalFrame), true, CVarNetCorrectionLifetime->GetFloat(), 0, 0.5f); + } #endif - if (ShouldTriggerResim) + if (LocalFrame > RewindData->GetBlockedResimFrame()) + { + if (ShouldTriggerResim && Target.TickCount == 0) { + // Trigger resimulation RigidsSolver->GetEvolution()->GetIslandManager().SetParticleResimFrame(Handle, LocalFrame); int32 ResimFrame = RewindData->GetResimFrame(); ResimFrame = (ResimFrame == INDEX_NONE) ? LocalFrame : FMath::Min(ResimFrame, LocalFrame); RewindData->SetResimFrame(ResimFrame); } - } - else if (LocalFrame > 0) - { - UE_LOG(LogPhysics, Warning, TEXT("FPhysicsReplication::ApplyRigidBodyState target frame (%d) out of rewind data bounds (%d,%d)"), LocalFrame, - RewindData->GetEarliestFrame_Internal(), RewindData->CurrentFrame()); - } + else if (SettingsCurrent.ResimulationSettings.GetRuntimeCorrectionEnabled()) - return true; + { + const int32 NumPredictedFrames = RigidsSolver->GetCurrentFrame() - LocalFrame - Target.TickCount; + + + + if (Target.TickCount <= NumPredictedFrames && NumPredictedFrames > 0) + { + // Positional Correction + const float CorrectionAmountX = SettingsCurrent.ResimulationSettings.GetPosStabilityMultiplier() / NumPredictedFrames; + const FVector PosDiffCorrection = ErrorOffset * CorrectionAmountX; // Same result as (ErrorOffset / NumPredictedFrames) * PosStabilityMultiplier + const FVector CorrectedX = Handle->GetX() + PosDiffCorrection; + + + // Rotational Correction + const float CorrectionAmountR = SettingsCurrent.ResimulationSettings.GetRotStabilityMultiplier() / NumPredictedFrames; + + const FQuat DeltaQuat = PastState.GetR().Inverse() * Target.TargetState.Quaternion; + const FQuat TargetCorrectionR = Handle->GetR() * DeltaQuat; + const FQuat CorrectedR = FQuat::Slerp(Handle->GetR(), TargetCorrectionR, CorrectionAmountR); + + if (SettingsCurrent.ResimulationSettings.GetRuntimeVelocityCorrectionEnabled()) + { + // Linear Velocity Correction + const FVector LinVelDiff = Target.TargetState.LinVel - PastState.GetV(); // Velocity vector that the server covers but the client doesn't + const float CorrectionAmountV = SettingsCurrent.ResimulationSettings.GetVelStabilityMultiplier() / NumPredictedFrames; + const FVector VelCorrection = LinVelDiff * CorrectionAmountV; // Same result as (LinVelDiff / NumPredictedFrames) * VelStabilityMultiplier + const FVector CorrectedV = Handle->GetV() + VelCorrection; + + // Angular Velocity Correction + const FVector AngVelDiff = Target.TargetState.AngVel - PastState.GetW(); // Angular velocity vector that the server covers but the client doesn't + const float CorrectionAmountW = SettingsCurrent.ResimulationSettings.GetAngVelStabilityMultiplier() / NumPredictedFrames; + const FVector AngVelCorrection = AngVelDiff * CorrectionAmountW; // Same result as (AngVelDiff / NumPredictedFrames) * VelStabilityMultiplier + const FVector CorrectedW = Handle->GetW() + AngVelCorrection; + + // Apply correction to velocities + Handle->SetV(CorrectedV); + Handle->SetW(CorrectedW); + } + + +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) + if (CVarResimDrawDebug->GetBool()) + { + static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime")); + Chaos::FDebugDrawQueue::GetInstance().DrawDebugDirectionalArrow(Handle->GetX(), CorrectedX, 5.0f, FColor::MakeRandomSeededColor(LocalFrame), true, CVarNetCorrectionLifetime->GetFloat(), 0, 0.5f); + } +#endif + // Apply correction to position and rotation + static const auto CVarResimRuntimeCorrectConnectedBodies = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.Resim.RuntimeCorrectConnectedBodies")); + RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, CorrectedX, CorrectedR, CVarResimRuntimeCorrectConnectedBodies->GetBool()); + } + + // Keep target for NumPredictedFrames time to perform runtime corrections with until a new target is received + bClearTarget = Target.TickCount >= NumPredictedFrames; + } + } + return bClearTarget; } FName FPhysicsReplicationAsyncVR::GetFNameForStatId() const { const static FLazyName StaticName("FPhysicsReplicationAsyncCallback"); return StaticName; -} \ No newline at end of file +} + +#pragma endregion // FPhysicsReplicationAsync \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableSkeletalMeshActor.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableSkeletalMeshActor.cpp index 330ee78..b1a36b3 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableSkeletalMeshActor.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableSkeletalMeshActor.cpp @@ -37,7 +37,18 @@ void UOptionalRepSkeletalMeshComponent::GetLifetimeReplicatedProps(TArray< class { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME(UOptionalRepSkeletalMeshComponent, bReplicateMovement); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UOptionalRepSkeletalMeshComponent, bReplicateMovement, PushModelParams); +} + +void UOptionalRepSkeletalMeshComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UOptionalRepSkeletalMeshComponent, bReplicateMovement, this); +#endif } void UOptionalRepSkeletalMeshComponent::GetWeldedBodies(TArray& OutWeldedBodies, TArray& OutLabels, bool bIncludingAutoWeld) @@ -152,13 +163,20 @@ void AGrippableSkeletalMeshActor::GetLifetimeReplicatedProps(TArray< class FLife { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME_CONDITION(AGrippableSkeletalMeshActor, GripLogicScripts, COND_Custom); - DOREPLIFETIME(AGrippableSkeletalMeshActor, bReplicateGripScripts); - DOREPLIFETIME(AGrippableSkeletalMeshActor, bRepGripSettingsAndGameplayTags); - DOREPLIFETIME(AGrippableSkeletalMeshActor, bAllowIgnoringAttachOnOwner); - DOREPLIFETIME(AGrippableSkeletalMeshActor, ClientAuthReplicationData); - DOREPLIFETIME_CONDITION(AGrippableSkeletalMeshActor, VRGripInterfaceSettings, COND_Custom); - DOREPLIFETIME_CONDITION(AGrippableSkeletalMeshActor, GameplayTags, COND_Custom); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableSkeletalMeshActor, bReplicateGripScripts, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableSkeletalMeshActor, bRepGripSettingsAndGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableSkeletalMeshActor, bAllowIgnoringAttachOnOwner, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableSkeletalMeshActor, ClientAuthReplicationData, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableSkeletalMeshActor, GripLogicScripts, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableSkeletalMeshActor, VRGripInterfaceSettings, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableSkeletalMeshActor, GameplayTags, PushModelParamsWithCondition); DISABLE_REPLICATED_PRIVATE_PROPERTY(AActor, AttachmentReplication); @@ -732,6 +750,30 @@ void AGrippableSkeletalMeshActor::Server_GetClientAuthReplication_Implementation } } +bool AGrippableSkeletalMeshActor::ShouldWeSkipAttachmentReplication(bool bConsiderHeld) const +{ + if ((bConsiderHeld && !VRGripInterfaceSettings.bWasHeld) || GetNetMode() < ENetMode::NM_Client) + return false; + + if (VRGripInterfaceSettings.MovementReplicationType == EGripMovementReplicationSettings::ClientSide_Authoritive || + VRGripInterfaceSettings.MovementReplicationType == EGripMovementReplicationSettings::ClientSide_Authoritive_NoRep) + { + // First return if we are locally held (owner may not have replicated yet) + for (const FBPGripPair& Grip : VRGripInterfaceSettings.HoldingControllers) + { + if (IsValid(Grip.HoldingController) && Grip.HoldingController->IsLocallyControlled()) + { + return true; + } + } + + // then return if we have a local net owner + return HasLocalNetOwner(); + } + else + return false; +} + void AGrippableSkeletalMeshActor::OnRep_AttachmentReplication() { if (bAllowIgnoringAttachOnOwner && (ClientAuthReplicationData.bIsCurrentlyClientAuth || ShouldWeSkipAttachmentReplication())) @@ -907,4 +949,80 @@ void AGrippableSkeletalMeshActor::GetSubobjectsWithStableNamesForNetworking(TArr } } } -} \ No newline at end of file +} + +///////////////////////////////////////////////// +//- Push networking getter / setter functions +///////////////////////////////////////////////// + +void AGrippableSkeletalMeshActor::SetReplicateGripScripts(bool bNewReplicateGripScripts) +{ + bReplicateGripScripts = bNewReplicateGripScripts; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableSkeletalMeshActor, bReplicateGripScripts, this); +#endif +} + +TArray>& AGrippableSkeletalMeshActor::GetGripLogicScripts() +{ +#if WITH_PUSH_MODEL + if (bReplicateGripScripts) + { + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableSkeletalMeshActor, GripLogicScripts, this); + } +#endif + + return GripLogicScripts; +} + +void AGrippableSkeletalMeshActor::SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags) +{ + bRepGripSettingsAndGameplayTags = bNewRepGripSettingsAndGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableSkeletalMeshActor, bRepGripSettingsAndGameplayTags, this); +#endif +} + +void AGrippableSkeletalMeshActor::SetAllowIgnoringAttachOnOwner(bool bNewAllowIgnoringAttachOnOwner) +{ + bAllowIgnoringAttachOnOwner = bNewAllowIgnoringAttachOnOwner; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableSkeletalMeshActor, bAllowIgnoringAttachOnOwner, this); +#endif +} + +FVRClientAuthReplicationData& AGrippableSkeletalMeshActor::GetClientAuthReplicationData(FVRClientAuthReplicationData& ClientAuthData) +{ +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableSkeletalMeshActor, ClientAuthReplicationData, this); +#endif + return ClientAuthReplicationData; +} + +FBPInterfaceProperties& AGrippableSkeletalMeshActor::GetVRGripInterfaceSettings(bool bMarkDirty) +{ +#if WITH_PUSH_MODEL + if (bMarkDirty && bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableSkeletalMeshActor, VRGripInterfaceSettings, this); + } +#endif + + return VRGripInterfaceSettings; +} + +FGameplayTagContainer& AGrippableSkeletalMeshActor::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableSkeletalMeshActor, GameplayTags, this); + } +#endif + + return GameplayTags; +} + +///////////////////////////////////////////////// +//- End Push networking getter / setter functions +///////////////////////////////////////////////// \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableSkeletalMeshComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableSkeletalMeshComponent.cpp index c9781fa..4059705 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableSkeletalMeshComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableSkeletalMeshComponent.cpp @@ -8,6 +8,9 @@ #include "GripScripts/VRGripScriptBase.h" #include "PhysicsEngine/PhysicsAsset.h" // Tmp until epic bug fixes skeletal welding #include "Net/UnrealNetwork.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif //============================================================================= UGrippableSkeletalMeshComponent::UGrippableSkeletalMeshComponent(const FObjectInitializer& ObjectInitializer) @@ -44,12 +47,19 @@ void UGrippableSkeletalMeshComponent::GetLifetimeReplicatedProps(TArray< class F { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME_CONDITION(UGrippableSkeletalMeshComponent, GripLogicScripts, COND_Custom); - DOREPLIFETIME(UGrippableSkeletalMeshComponent, bReplicateGripScripts); - DOREPLIFETIME(UGrippableSkeletalMeshComponent, bRepGripSettingsAndGameplayTags); - DOREPLIFETIME(UGrippableSkeletalMeshComponent, bReplicateMovement); - DOREPLIFETIME_CONDITION(UGrippableSkeletalMeshComponent, VRGripInterfaceSettings, COND_Custom); - DOREPLIFETIME_CONDITION(UGrippableSkeletalMeshComponent, GameplayTags, COND_Custom); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableSkeletalMeshComponent, bReplicateGripScripts, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableSkeletalMeshComponent, bRepGripSettingsAndGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableSkeletalMeshComponent, bReplicateMovement, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableSkeletalMeshComponent, GripLogicScripts, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableSkeletalMeshComponent, VRGripInterfaceSettings, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableSkeletalMeshComponent, GameplayTags, PushModelParamsWithCondition); } void UGrippableSkeletalMeshComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) @@ -389,4 +399,72 @@ FBodyInstance* UGrippableSkeletalMeshComponent::GetBodyInstance(FName BoneName, } return BodyInst; -} \ No newline at end of file +} + +///////////////////////////////////////////////// +//- Push networking getter / setter functions +///////////////////////////////////////////////// + +void UGrippableSkeletalMeshComponent::SetReplicateGripScripts(bool bNewReplicateGripScripts) +{ + bReplicateGripScripts = bNewReplicateGripScripts; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableSkeletalMeshComponent, bReplicateGripScripts, this); +#endif +} + +TArray>& UGrippableSkeletalMeshComponent::GetGripLogicScripts() +{ +#if WITH_PUSH_MODEL + if (bReplicateGripScripts) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableSkeletalMeshComponent, GripLogicScripts, this); + } +#endif + + return GripLogicScripts; +} + +void UGrippableSkeletalMeshComponent::SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags) +{ + bRepGripSettingsAndGameplayTags = bNewRepGripSettingsAndGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableSkeletalMeshComponent, bRepGripSettingsAndGameplayTags, this); +#endif +} + +void UGrippableSkeletalMeshComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableSkeletalMeshComponent, bReplicateMovement, this); +#endif +} + +FBPInterfaceProperties& UGrippableSkeletalMeshComponent::GetVRGripInterfaceSettings(bool bMarkDirty) +{ +#if WITH_PUSH_MODEL + if (bMarkDirty && bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableSkeletalMeshComponent, VRGripInterfaceSettings, this); + } +#endif + + return VRGripInterfaceSettings; +} + +FGameplayTagContainer& UGrippableSkeletalMeshComponent::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableSkeletalMeshComponent, GameplayTags, this); + } +#endif + + return GameplayTags; +} + +///////////////////////////////////////////////// +//- End Push networking getter / setter functions +///////////////////////////////////////////////// \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableSphereComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableSphereComponent.cpp index 3e22391..6fca280 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableSphereComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableSphereComponent.cpp @@ -8,6 +8,11 @@ #include "GripScripts/VRGripScriptBase.h" #include "Net/UnrealNetwork.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif + + //============================================================================= UGrippableSphereComponent::UGrippableSphereComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -42,12 +47,19 @@ void UGrippableSphereComponent::GetLifetimeReplicatedProps(TArray< class FLifeti { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME_CONDITION(UGrippableSphereComponent, GripLogicScripts, COND_Custom); - DOREPLIFETIME(UGrippableSphereComponent, bReplicateGripScripts) - DOREPLIFETIME(UGrippableSphereComponent, bRepGripSettingsAndGameplayTags); - DOREPLIFETIME(UGrippableSphereComponent, bReplicateMovement); - DOREPLIFETIME_CONDITION(UGrippableSphereComponent, VRGripInterfaceSettings, COND_Custom); - DOREPLIFETIME_CONDITION(UGrippableSphereComponent, GameplayTags, COND_Custom); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableSphereComponent, bReplicateGripScripts, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableSphereComponent, bRepGripSettingsAndGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableSphereComponent, bReplicateMovement, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableSphereComponent, GripLogicScripts, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableSphereComponent, VRGripInterfaceSettings, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableSphereComponent, GameplayTags, PushModelParamsWithCondition); } void UGrippableSphereComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) @@ -319,4 +331,73 @@ void UGrippableSphereComponent::OnComponentDestroyed(bool bDestroyingHierarchy) } GripLogicScripts.Empty(); -} \ No newline at end of file +} + + +///////////////////////////////////////////////// +//- Push networking getter / setter functions +///////////////////////////////////////////////// + +void UGrippableSphereComponent::SetReplicateGripScripts(bool bNewReplicateGripScripts) +{ + bReplicateGripScripts = bNewReplicateGripScripts; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableSphereComponent, bReplicateGripScripts, this); +#endif +} + +TArray>& UGrippableSphereComponent::GetGripLogicScripts() +{ +#if WITH_PUSH_MODEL + if (bReplicateGripScripts) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableSphereComponent, GripLogicScripts, this); + } +#endif + + return GripLogicScripts; +} + +void UGrippableSphereComponent::SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags) +{ + bRepGripSettingsAndGameplayTags = bNewRepGripSettingsAndGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableSphereComponent, bRepGripSettingsAndGameplayTags, this); +#endif +} + +void UGrippableSphereComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableSphereComponent, bReplicateMovement, this); +#endif +} + +FBPInterfaceProperties& UGrippableSphereComponent::GetVRGripInterfaceSettings(bool bMarkDirty) +{ +#if WITH_PUSH_MODEL + if (bMarkDirty && bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableSphereComponent, VRGripInterfaceSettings, this); + } +#endif + + return VRGripInterfaceSettings; +} + +FGameplayTagContainer& UGrippableSphereComponent::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableSphereComponent, GameplayTags, this); + } +#endif + + return GameplayTags; +} + +///////////////////////////////////////////////// +//- End Push networking getter / setter functions +///////////////////////////////////////////////// \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableStaticMeshActor.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableStaticMeshActor.cpp index 3ca4bde..74dec5c 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableStaticMeshActor.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableStaticMeshActor.cpp @@ -110,13 +110,20 @@ void AGrippableStaticMeshActor::GetLifetimeReplicatedProps(TArray< class FLifeti { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME_CONDITION(AGrippableStaticMeshActor, GripLogicScripts, COND_Custom); - DOREPLIFETIME(AGrippableStaticMeshActor, bReplicateGripScripts); - DOREPLIFETIME(AGrippableStaticMeshActor, bRepGripSettingsAndGameplayTags); - DOREPLIFETIME(AGrippableStaticMeshActor, bAllowIgnoringAttachOnOwner); - DOREPLIFETIME(AGrippableStaticMeshActor, ClientAuthReplicationData); - DOREPLIFETIME_CONDITION(AGrippableStaticMeshActor, VRGripInterfaceSettings, COND_Custom); - DOREPLIFETIME_CONDITION(AGrippableStaticMeshActor, GameplayTags, COND_Custom); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableStaticMeshActor, bReplicateGripScripts, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableStaticMeshActor, bRepGripSettingsAndGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableStaticMeshActor, bAllowIgnoringAttachOnOwner, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableStaticMeshActor, ClientAuthReplicationData, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableStaticMeshActor, GripLogicScripts, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableStaticMeshActor, VRGripInterfaceSettings, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(AGrippableStaticMeshActor, GameplayTags, PushModelParamsWithCondition); DISABLE_REPLICATED_PRIVATE_PROPERTY(AActor, AttachmentReplication); @@ -682,6 +689,30 @@ void AGrippableStaticMeshActor::Server_GetClientAuthReplication_Implementation(c } } +bool AGrippableStaticMeshActor::ShouldWeSkipAttachmentReplication(bool bConsiderHeld) const +{ + if ((bConsiderHeld && !VRGripInterfaceSettings.bWasHeld) || GetNetMode() < ENetMode::NM_Client) + return false; + + if (VRGripInterfaceSettings.MovementReplicationType == EGripMovementReplicationSettings::ClientSide_Authoritive || + VRGripInterfaceSettings.MovementReplicationType == EGripMovementReplicationSettings::ClientSide_Authoritive_NoRep) + { + // First return if we are locally held (owner may not have replicated yet) + for (const FBPGripPair& Grip : VRGripInterfaceSettings.HoldingControllers) + { + if (IsValid(Grip.HoldingController) && Grip.HoldingController->IsLocallyControlled()) + { + return true; + } + } + + // then return if we have a local net owner + return HasLocalNetOwner(); + } + else + return false; +} + void AGrippableStaticMeshActor::OnRep_AttachmentReplication() { if (bAllowIgnoringAttachOnOwner && (ClientAuthReplicationData.bIsCurrentlyClientAuth || ShouldWeSkipAttachmentReplication())) @@ -774,6 +805,12 @@ void AGrippableStaticMeshActor::OnRep_ReplicatedMovement() return; } + if (VRGripInterfaceSettings.HoldingControllers.Num() > 0) + { + ShouldWeSkipAttachmentReplication(); + int gg = 0; + } + Super::OnRep_ReplicatedMovement(); } @@ -858,4 +895,80 @@ void AGrippableStaticMeshActor::GetSubobjectsWithStableNamesForNetworking(TArray } } } -} \ No newline at end of file +} + +///////////////////////////////////////////////// +//- Push networking getter / setter functions +///////////////////////////////////////////////// + +void AGrippableStaticMeshActor::SetReplicateGripScripts(bool bNewReplicateGripScripts) +{ + bReplicateGripScripts = bNewReplicateGripScripts; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableStaticMeshActor, bReplicateGripScripts, this); +#endif +} + +TArray>& AGrippableStaticMeshActor::GetGripLogicScripts() +{ +#if WITH_PUSH_MODEL + if (bReplicateGripScripts) + { + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableStaticMeshActor, GripLogicScripts, this); + } +#endif + + return GripLogicScripts; +} + +void AGrippableStaticMeshActor::SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags) +{ + bRepGripSettingsAndGameplayTags = bNewRepGripSettingsAndGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableStaticMeshActor, bRepGripSettingsAndGameplayTags, this); +#endif +} + +void AGrippableStaticMeshActor::SetAllowIgnoringAttachOnOwner(bool bNewAllowIgnoringAttachOnOwner) +{ + bAllowIgnoringAttachOnOwner = bNewAllowIgnoringAttachOnOwner; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableStaticMeshActor, bAllowIgnoringAttachOnOwner, this); +#endif +} + +FVRClientAuthReplicationData& AGrippableStaticMeshActor::GetClientAuthReplicationData(FVRClientAuthReplicationData& ClientAuthData) +{ +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableStaticMeshActor, ClientAuthReplicationData, this); +#endif + return ClientAuthReplicationData; +} + +FBPInterfaceProperties& AGrippableStaticMeshActor::GetVRGripInterfaceSettings(bool bMarkDirty) +{ +#if WITH_PUSH_MODEL + if (bMarkDirty && bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableStaticMeshActor, VRGripInterfaceSettings, this); + } +#endif + + return VRGripInterfaceSettings; +} + +FGameplayTagContainer& AGrippableStaticMeshActor::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(AGrippableStaticMeshActor, GameplayTags, this); + } +#endif + + return GameplayTags; +} + +///////////////////////////////////////////////// +//- End Push networking getter / setter functions +///////////////////////////////////////////////// \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableStaticMeshComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableStaticMeshComponent.cpp index 77ca8fe..1f6b0bc 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableStaticMeshComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/GrippableStaticMeshComponent.cpp @@ -7,6 +7,9 @@ #include "VRExpansionFunctionLibrary.h" #include "GripScripts/VRGripScriptBase.h" #include "Net/UnrealNetwork.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif //============================================================================= UGrippableStaticMeshComponent::UGrippableStaticMeshComponent(const FObjectInitializer& ObjectInitializer) @@ -43,12 +46,19 @@ void UGrippableStaticMeshComponent::GetLifetimeReplicatedProps(TArray< class FLi { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME_CONDITION(UGrippableStaticMeshComponent, GripLogicScripts, COND_Custom); - DOREPLIFETIME(UGrippableStaticMeshComponent, bReplicateGripScripts); - DOREPLIFETIME(UGrippableStaticMeshComponent, bRepGripSettingsAndGameplayTags); - DOREPLIFETIME(UGrippableStaticMeshComponent, bReplicateMovement); - DOREPLIFETIME_CONDITION(UGrippableStaticMeshComponent, VRGripInterfaceSettings, COND_Custom); - DOREPLIFETIME_CONDITION(UGrippableStaticMeshComponent, GameplayTags, COND_Custom); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableStaticMeshComponent, bReplicateGripScripts, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableStaticMeshComponent, bRepGripSettingsAndGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableStaticMeshComponent, bReplicateMovement, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableStaticMeshComponent, GripLogicScripts, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableStaticMeshComponent, VRGripInterfaceSettings, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(UGrippableStaticMeshComponent, GameplayTags, PushModelParamsWithCondition); } void UGrippableStaticMeshComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) @@ -314,4 +324,72 @@ void UGrippableStaticMeshComponent::OnComponentDestroyed(bool bDestroyingHierarc } GripLogicScripts.Empty(); -} \ No newline at end of file +} + +///////////////////////////////////////////////// +//- Push networking getter / setter functions +///////////////////////////////////////////////// + +void UGrippableStaticMeshComponent::SetReplicateGripScripts(bool bNewReplicateGripScripts) +{ + bReplicateGripScripts = bNewReplicateGripScripts; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableStaticMeshComponent, bReplicateGripScripts, this); +#endif +} + +TArray>& UGrippableStaticMeshComponent::GetGripLogicScripts() +{ +#if WITH_PUSH_MODEL + if (bReplicateGripScripts) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableStaticMeshComponent, GripLogicScripts, this); + } +#endif + + return GripLogicScripts; +} + +void UGrippableStaticMeshComponent::SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags) +{ + bRepGripSettingsAndGameplayTags = bNewRepGripSettingsAndGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableStaticMeshComponent, bRepGripSettingsAndGameplayTags, this); +#endif +} + +void UGrippableStaticMeshComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableStaticMeshComponent, bReplicateMovement, this); +#endif +} + +FBPInterfaceProperties& UGrippableStaticMeshComponent::GetVRGripInterfaceSettings(bool bMarkDirty) +{ +#if WITH_PUSH_MODEL + if (bMarkDirty && bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableStaticMeshComponent, VRGripInterfaceSettings, this); + } +#endif + + return VRGripInterfaceSettings; +} + +FGameplayTagContainer& UGrippableStaticMeshComponent::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGripSettingsAndGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UGrippableStaticMeshComponent, GameplayTags, this); + } +#endif + + return GameplayTags; +} + +///////////////////////////////////////////////// +//- End Push networking getter / setter functions +///////////////////////////////////////////////// \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/HandSocketComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/HandSocketComponent.cpp index dfbdd58..97d6e18 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/HandSocketComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/HandSocketComponent.cpp @@ -3,11 +3,16 @@ #include "Grippables/HandSocketComponent.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(HandSocketComponent) +#include "CoreMinimal.h" +#include "UObject/UObjectIterator.h" #include "Engine/CollisionProfile.h" +#include "BoneContainer.h" #include "Animation/AnimSequence.h" #include "Animation/AnimInstanceProxy.h" #include "Animation/PoseSnapshot.h" #include "Animation/AnimData/AnimDataModel.h" +#include "Engine/SkinnedAssetCommon.h" +#include "Engine/SkinnedAsset.h" //#include "VRExpansionFunctionLibrary.h" #include "Components/SkeletalMeshComponent.h" #include "Components/PoseableMeshComponent.h" @@ -17,6 +22,10 @@ #include "Net/UnrealNetwork.h" #include "Serialization/CustomVersion.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif + DEFINE_LOG_CATEGORY(LogVRHandSocketComponent); const FGuid FVRHandSocketCustomVersion::GUID(0x5A018B7F, 0x48A7AFDE, 0xAFBEB580, 0xAD575412); @@ -876,10 +885,17 @@ void UHandSocketComponent::OnComponentDestroyed(bool bDestroyingHierarchy) void UHandSocketComponent::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - - DOREPLIFETIME(UHandSocketComponent, bRepGameplayTags); - DOREPLIFETIME(UHandSocketComponent, bReplicateMovement); - DOREPLIFETIME_CONDITION(UHandSocketComponent, GameplayTags, COND_Custom); + + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UHandSocketComponent, bRepGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UHandSocketComponent, bReplicateMovement, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UHandSocketComponent, GameplayTags, PushModelParamsWithCondition); } void UHandSocketComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) @@ -963,4 +979,47 @@ UHandSocketComponent* UHandSocketComponent::GetHandSocketComponentFromObject(UOb } return nullptr; +} + +///////////////////////////////////////////////// +//- Push networking getter / setter functions +///////////////////////////////////////////////// + +void UHandSocketComponent::SetRepGameplayTags(bool bNewRepGameplayTags) +{ + bRepGameplayTags = bNewRepGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UHandSocketComponent, bRepGameplayTags, this); +#endif +} + +void UHandSocketComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UHandSocketComponent, bReplicateMovement, this); +#endif +} + +FGameplayTagContainer& UHandSocketComponent::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UHandSocketComponent, GameplayTags, this); + } +#endif + + return GameplayTags; +} + +///////////////////////////////////////////////// +//- End Push networking getter / setter functions +///////////////////////////////////////////////// + +void UHandSocketAnimInstance::NativeInitializeAnimation() +{ + Super::NativeInitializeAnimation(); + + OwningSocket = Cast(GetOwningComponent()->GetAttachParent()); } \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRButtonComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRButtonComponent.cpp index 8219fb2..e9da277 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRButtonComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRButtonComponent.cpp @@ -9,6 +9,10 @@ #include "GameFramework/Character.h" #include "GameFramework/PlayerController.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif + //============================================================================= UVRButtonComponent::UVRButtonComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -48,10 +52,17 @@ void UVRButtonComponent::GetLifetimeReplicatedProps(TArray< class FLifetimePrope { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME(UVRButtonComponent, InitialRelativeTransform); - DOREPLIFETIME(UVRButtonComponent, bReplicateMovement); - DOREPLIFETIME(UVRButtonComponent, StateChangeAuthorityType); - DOREPLIFETIME_CONDITION(UVRButtonComponent, bButtonState, COND_InitialOnly); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UVRButtonComponent, InitialRelativeTransform, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UVRButtonComponent, bReplicateMovement, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UVRButtonComponent, StateChangeAuthorityType, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_InitialOnly, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UVRButtonComponent, bButtonState, PushModelParamsWithCondition); } void UVRButtonComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) @@ -422,4 +433,28 @@ FVector UVRButtonComponent::SetAxisValue(float SetValue) } return vec; +} + +void UVRButtonComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRButtonComponent, bReplicateMovement, this); +#endif +} + +void UVRButtonComponent::SetStateChangeAuthorityType(EVRStateChangeAuthorityType NewStateChangeAuthorityType) +{ + StateChangeAuthorityType = NewStateChangeAuthorityType; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRButtonComponent, StateChangeAuthorityType, this); +#endif +} + +void UVRButtonComponent::SetButtonState(bool bNewButtonState) +{ + bButtonState = bNewButtonState; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRButtonComponent, bButtonState, this); +#endif } \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRDialComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRDialComponent.cpp index 766f5e7..7930efc 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRDialComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRDialComponent.cpp @@ -7,6 +7,10 @@ #include "GripMotionControllerComponent.h" #include "Net/UnrealNetwork.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif + //============================================================================= UVRDialComponent::UVRDialComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -63,12 +67,19 @@ void UVRDialComponent::GetLifetimeReplicatedProps(TArray< class FLifetimePropert { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME(UVRDialComponent, InitialRelativeTransform); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UVRDialComponent, InitialRelativeTransform, PushModelParams); //DOREPLIFETIME_CONDITION(UVRDialComponent, bIsLerping, COND_InitialOnly); - DOREPLIFETIME(UVRDialComponent, bRepGameplayTags); - DOREPLIFETIME(UVRDialComponent, bReplicateMovement); - DOREPLIFETIME_CONDITION(UVRDialComponent, GameplayTags, COND_Custom); + DOREPLIFETIME_WITH_PARAMS_FAST(UVRDialComponent, bRepGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UVRDialComponent, bReplicateMovement, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UVRDialComponent, GameplayTags, PushModelParamsWithCondition); } void UVRDialComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) @@ -255,10 +266,20 @@ void UVRDialComponent::OnGripRelease_Implementation(UGripMotionControllerCompone } } } - else if (bDialUsesAngleSnap && SnapAngleIncrement > 0.f && FMath::Abs(FMath::Fmod(CurRotBackEnd, SnapAngleIncrement)) <= FMath::Min(SnapAngleIncrement, SnapAngleThreshold)) + else if (bDialUsesAngleSnap && SnapAngleIncrement > 0.f)// && FMath::Abs(FMath::Fmod(CurRotBackEnd, SnapAngleIncrement)) <= FMath::Min(SnapAngleIncrement, SnapAngleThreshold)) { - this->SetRelativeRotation((FTransform(UVRInteractibleFunctionLibrary::SetAxisValueRot(DialRotationAxis, FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement), FRotator::ZeroRotator)) * InitialRelativeTransform).Rotator()); - CurRotBackEnd = FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement); + + float AngleOffsetCheck = FMath::Abs(FRotator::ClampAxis(CurRotBackEnd) - FRotator::ClampAxis(LastSnapAngle)); + float TargetSnap = FMath::RoundToFloat(FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement)); + + if (FMath::Abs(FRotator::ClampAxis(CurRotBackEnd) - TargetSnap) <= FMath::Min(SnapAngleIncrement, SnapAngleThreshold)) + { + if (AngleOffsetCheck >= SnapAngleThreshold)//FMath::Min(SnapAngleIncrement, SnapAngleThreshold)) + { + this->SetRelativeRotation((FTransform(UVRInteractibleFunctionLibrary::SetAxisValueRot(DialRotationAxis, FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement), FRotator::ZeroRotator)) * InitialRelativeTransform).Rotator()); + CurRotBackEnd = FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement); + } + } if (bUseRollover) { @@ -494,7 +515,7 @@ void UVRDialComponent::AddDialAngle(float DialAngleDelta, bool bCallEvents, bool CurRotBackEnd = FMath::Clamp(CurRotBackEnd + DeltaRot, MaxCheckValue, 360.0f); } } - else if(!bUseRollover && tempCheck > ClockwiseMaximumDialAngle && tempCheck < MaxCheckValue) + else if (!bUseRollover && tempCheck > ClockwiseMaximumDialAngle && tempCheck < MaxCheckValue) { if (CurRotBackEnd < MaxCheckValue) { @@ -529,7 +550,7 @@ void UVRDialComponent::AddDialAngle(float DialAngleDelta, bool bCallEvents, bool { float closestAngle = 0.f; // Always default 0.0f to the list - float closestVal = FMath::Abs(closestAngle - CurRotBackEnd); + float closestVal = FMath::Abs(closestAngle - CurRotBackEnd); float closestValt = 0.f; for (float val : DialSnapAngleList) { @@ -556,19 +577,34 @@ void UVRDialComponent::AddDialAngle(float DialAngleDelta, bool bCallEvents, bool LastSnapAngle = CurrentDialAngle; } } - else if (bDialUsesAngleSnap && SnapAngleIncrement > 0.f && FMath::Abs(FMath::Fmod(CurRotBackEnd, SnapAngleIncrement)) <= FMath::Min(SnapAngleIncrement, SnapAngleThreshold)) + else if (bDialUsesAngleSnap && SnapAngleIncrement > 0.f)// && FMath::Abs(FMath::Fmod(CurRotBackEnd, SnapAngleIncrement)) <= FMath::Min(SnapAngleIncrement, SnapAngleThreshold)) { - if (!bSkipSettingRot) - this->SetRelativeRotation((FTransform(UVRInteractibleFunctionLibrary::SetAxisValueRot(DialRotationAxis, FMath::UnwindDegrees(FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement)), FRotator::ZeroRotator)) * InitialRelativeTransform).Rotator()); - CurrentDialAngle = FMath::RoundToFloat(FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement)); + float AngleOffsetCheck = FMath::Abs(FRotator::ClampAxis(CurRotBackEnd) - FRotator::ClampAxis(LastSnapAngle)); + float TargetSnap = FMath::RoundToFloat(FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement)); - if (bCallEvents && !FMath::IsNearlyEqual(LastSnapAngle, CurrentDialAngle)) + if (FMath::Abs(FRotator::ClampAxis(CurRotBackEnd) - TargetSnap) <= FMath::Min(SnapAngleIncrement, SnapAngleThreshold)) { - ReceiveDialHitSnapAngle(CurrentDialAngle); - OnDialHitSnapAngle.Broadcast(CurrentDialAngle); - } + if (AngleOffsetCheck >= SnapAngleThreshold)//FMath::Min(SnapAngleIncrement, SnapAngleThreshold)) + { + if (!bSkipSettingRot) + this->SetRelativeRotation((FTransform(UVRInteractibleFunctionLibrary::SetAxisValueRot(DialRotationAxis, FMath::UnwindDegrees(FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement)), FRotator::ZeroRotator)) * InitialRelativeTransform).Rotator()); + CurrentDialAngle = FMath::RoundToFloat(FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement)); - LastSnapAngle = CurrentDialAngle; + if (bCallEvents && !FMath::IsNearlyEqual(LastSnapAngle, CurrentDialAngle)) + { + ReceiveDialHitSnapAngle(CurrentDialAngle); + OnDialHitSnapAngle.Broadcast(CurrentDialAngle); + } + + LastSnapAngle = CurrentDialAngle; + } + } + else + { + if (!bSkipSettingRot) + this->SetRelativeRotation((FTransform(UVRInteractibleFunctionLibrary::SetAxisValueRot(DialRotationAxis, FMath::UnwindDegrees(CurRotBackEnd), FRotator::ZeroRotator)) * InitialRelativeTransform).Rotator()); + CurrentDialAngle = FMath::RoundToFloat(CurRotBackEnd); + } } else { @@ -583,6 +619,11 @@ void UVRDialComponent::ResetInitialDialLocation() { // Get our initial relative transform to our parent (or not if un-parented). InitialRelativeTransform = this->GetRelativeTransform(); + +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRDialComponent, InitialRelativeTransform, this); +#endif + CurRotBackEnd = 0.0f; CalculateDialProgress(); } @@ -593,4 +634,33 @@ void UVRDialComponent::CalculateDialProgress() LastGripRot = UVRInteractibleFunctionLibrary::GetDeltaAngleFromTransforms(DialRotationAxis, InitialRelativeTransform, CurRelativeTransform); CurRotBackEnd = LastGripRot; AddDialAngle(0.0f, false, true); +} + + +void UVRDialComponent::SetRepGameplayTags(bool bNewRepGameplayTags) +{ + bRepGameplayTags = bNewRepGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRDialComponent, bRepGameplayTags, this); +#endif +} + +void UVRDialComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRDialComponent, bReplicateMovement, this); +#endif +} + +FGameplayTagContainer& UVRDialComponent::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UVRDialComponent, GameplayTags, this); + } +#endif + + return GameplayTags; } \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRLeverComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRLeverComponent.cpp index f6a63a0..44ca29f 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRLeverComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRLeverComponent.cpp @@ -7,6 +7,10 @@ #include "VRExpansionFunctionLibrary.h" #include "Net/UnrealNetwork.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif + //============================================================================= UVRLeverComponent::UVRLeverComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -85,12 +89,19 @@ void UVRLeverComponent::GetLifetimeReplicatedProps(TArray< class FLifetimeProper { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME(UVRLeverComponent, InitialRelativeTransform); - //DOREPLIFETIME_CONDITION(UVRLeverComponent, bIsLerping, COND_InitialOnly); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; - DOREPLIFETIME(UVRLeverComponent, bRepGameplayTags); - DOREPLIFETIME(UVRLeverComponent, bReplicateMovement); - DOREPLIFETIME_CONDITION(UVRLeverComponent, GameplayTags, COND_Custom); + DOREPLIFETIME_WITH_PARAMS_FAST(UVRLeverComponent, InitialRelativeTransform, PushModelParams); + //DOREPLIFETIME_CONDITION(UVRDialComponent, bIsLerping, COND_InitialOnly); + + DOREPLIFETIME_WITH_PARAMS_FAST(UVRLeverComponent, bRepGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UVRLeverComponent, bReplicateMovement, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UVRLeverComponent, GameplayTags, PushModelParamsWithCondition); } void UVRLeverComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) @@ -655,6 +666,11 @@ void UVRLeverComponent::ResetInitialLeverLocation(bool bAllowThrowingEvents) { // Get our initial relative transform to our parent (or not if un-parented). InitialRelativeTransform = this->GetRelativeTransform(); + +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRLeverComponent, InitialRelativeTransform, this); +#endif + CalculateCurrentAngle(InitialRelativeTransform); ProccessCurrentState(bIsLerping, bAllowThrowingEvents, bAllowThrowingEvents); } @@ -816,4 +832,32 @@ float UVRLeverComponent::CalcAngle(EVRInteractibleLeverAxis AxisToCalc, FVector bIsInFirstTick = false; return ReturnAxis; +} + +void UVRLeverComponent::SetRepGameplayTags(bool bNewRepGameplayTags) +{ + bRepGameplayTags = bNewRepGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRLeverComponent, bRepGameplayTags, this); +#endif +} + +void UVRLeverComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRLeverComponent, bReplicateMovement, this); +#endif +} + +FGameplayTagContainer& UVRLeverComponent::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UVRLeverComponent, GameplayTags, this); + } +#endif + + return GameplayTags; } \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRMountComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRMountComponent.cpp index 63ad99b..115e95a 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRMountComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRMountComponent.cpp @@ -9,6 +9,10 @@ //#include "PhysicsEngine/ConstraintInstance.h" #include "Net/UnrealNetwork.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif + //============================================================================= UVRMountComponent::UVRMountComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -58,9 +62,16 @@ void UVRMountComponent::GetLifetimeReplicatedProps(TArray< class FLifetimeProper { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME(UVRMountComponent, bRepGameplayTags); - DOREPLIFETIME(UVRMountComponent, bReplicateMovement); - DOREPLIFETIME_CONDITION(UVRMountComponent, GameplayTags, COND_Custom); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UVRMountComponent, bRepGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UVRMountComponent, bReplicateMovement, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UVRMountComponent, GameplayTags, PushModelParamsWithCondition); } void UVRMountComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) @@ -577,8 +588,42 @@ void UVRMountComponent::SetHeld_Implementation(UGripMotionControllerComponent * return FBPInteractionSettings(); }*/ +void UVRMountComponent::ResetInitialMountLocation() +{ + // Get our initial relative transform to our parent (or not if un-parented). + InitialRelativeTransform = this->GetRelativeTransform(); +} + bool UVRMountComponent::GetGripScripts_Implementation(TArray & ArrayReference) { return false; +} + +void UVRMountComponent::SetRepGameplayTags(bool bNewRepGameplayTags) +{ + bRepGameplayTags = bNewRepGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRMountComponent, bRepGameplayTags, this); +#endif +} + +void UVRMountComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRMountComponent, bReplicateMovement, this); +#endif +} + +FGameplayTagContainer& UVRMountComponent::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UVRMountComponent, GameplayTags, this); + } +#endif + + return GameplayTags; } \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRSliderComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRSliderComponent.cpp index 64ef4b8..9113d33 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRSliderComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Interactibles/VRSliderComponent.cpp @@ -8,6 +8,10 @@ #include "GripMotionControllerComponent.h" #include "Net/UnrealNetwork.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif + //============================================================================= UVRSliderComponent::UVRSliderComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -84,13 +88,20 @@ void UVRSliderComponent::GetLifetimeReplicatedProps(TArray< class FLifetimePrope { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME(UVRSliderComponent, InitialRelativeTransform); - DOREPLIFETIME(UVRSliderComponent, SplineComponentToFollow); - //DOREPLIFETIME_CONDITION(UVRSliderComponent, bIsLerping, COND_InitialOnly); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; - DOREPLIFETIME(UVRSliderComponent, bRepGameplayTags); - DOREPLIFETIME(UVRSliderComponent, bReplicateMovement); - DOREPLIFETIME_CONDITION(UVRSliderComponent, GameplayTags, COND_Custom); + DOREPLIFETIME_WITH_PARAMS_FAST(UVRSliderComponent, InitialRelativeTransform, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UVRSliderComponent, SplineComponentToFollow, PushModelParams); + //DOREPLIFETIME_CONDITION(UVRDialComponent, bIsLerping, COND_InitialOnly); + + DOREPLIFETIME_WITH_PARAMS_FAST(UVRSliderComponent, bRepGameplayTags, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(UVRSliderComponent, bReplicateMovement, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_Custom, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UVRSliderComponent, GameplayTags, PushModelParamsWithCondition); } void UVRSliderComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) @@ -734,7 +745,12 @@ FVector UVRSliderComponent::ClampSlideVector(FVector ValueToClamp) FVector MinScale = (bUseLegacyLogic ? MinSlideDistance : MinSlideDistance.GetAbs()) * fScaleFactor; FVector Dist = (bUseLegacyLogic ? (MinSlideDistance + MaxSlideDistance) : (MinSlideDistance.GetAbs() + MaxSlideDistance.GetAbs())) * fScaleFactor; - FVector Progress = (ValueToClamp - (-MinScale)) / Dist; + FVector Progress{ + Dist.X > 0.0f ? (ValueToClamp.X - (-MinScale.X)) / Dist.X : 0.f, + Dist.Y > 0.0f ? (ValueToClamp.Y - (-MinScale.Y)) / Dist.Y : 0.f, + Dist.Z > 0.0f ? (ValueToClamp.Z - (-MinScale.Z)) / Dist.Z : 0.f, + }; + if (bSliderUsesSnapPoints) { @@ -892,6 +908,10 @@ void UVRSliderComponent::SetSplineComponentToFollow(USplineComponent * SplineToF { SplineComponentToFollow = SplineToFollow; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRSliderComponent, SplineComponentToFollow, this); +#endif + if (SplineToFollow != nullptr) ResetToParentSplineLocation(); else @@ -902,6 +922,11 @@ void UVRSliderComponent::ResetInitialSliderLocation() { // Get our initial relative transform to our parent (or not if un-parented). InitialRelativeTransform = this->GetRelativeTransform(); + +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRSliderComponent, InitialRelativeTransform, this); +#endif + ResetToParentSplineLocation(); if (SplineComponentToFollow == nullptr) @@ -985,4 +1010,32 @@ float UVRSliderComponent::CalculateSliderProgress() } return CurrentSliderProgress; +} + +void UVRSliderComponent::SetRepGameplayTags(bool bNewRepGameplayTags) +{ + bRepGameplayTags = bNewRepGameplayTags; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRSliderComponent, bRepGameplayTags, this); +#endif +} + +void UVRSliderComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UVRSliderComponent, bReplicateMovement, this); +#endif +} + +FGameplayTagContainer& UVRSliderComponent::GetGameplayTags() +{ +#if WITH_PUSH_MODEL + if (bRepGameplayTags) + { + MARK_PROPERTY_DIRTY_FROM_NAME(UVRSliderComponent, GameplayTags, this); + } +#endif + + return GameplayTags; } \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/CollisionIgnoreSubsystem.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/CollisionIgnoreSubsystem.cpp index c41b3d5..0308f80 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/CollisionIgnoreSubsystem.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/CollisionIgnoreSubsystem.cpp @@ -4,6 +4,7 @@ #include UE_INLINE_GENERATED_CPP_BY_NAME(CollisionIgnoreSubsystem) #include "Components/SkeletalMeshComponent.h" +#include "Engine/World.h" #include "Runtime/Engine/Classes/Kismet/GameplayStatics.h" #include "VRGlobalSettings.h" @@ -92,6 +93,16 @@ void UCollisionIgnoreSubsystem::ConstructInput() } } +void UCollisionIgnoreSubsystem::Deinitialize() +{ + Super::Deinitialize(); + + if (UpdateHandle.IsValid()) + { + GetWorld()->GetTimerManager().ClearTimer(UpdateHandle); + } +} + void UCollisionIgnoreSubsystem::UpdateTimer(bool bChangesWereMade) { diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/OptionalRepSkeletalMeshActor.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/OptionalRepSkeletalMeshActor.cpp index 2fb79cf..480b36f 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/OptionalRepSkeletalMeshActor.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/OptionalRepSkeletalMeshActor.cpp @@ -30,7 +30,10 @@ void UNoRepSphereComponent::GetLifetimeReplicatedProps(TArray< class FLifetimePr { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME(UNoRepSphereComponent, bReplicateMovement); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UNoRepSphereComponent, bReplicateMovement, PushModelParams); RESET_REPLIFETIME_CONDITION_PRIVATE_PROPERTY(USceneComponent, AttachParent, COND_InitialOnly); RESET_REPLIFETIME_CONDITION_PRIVATE_PROPERTY(USceneComponent, AttachSocketName, COND_InitialOnly); @@ -41,6 +44,14 @@ void UNoRepSphereComponent::GetLifetimeReplicatedProps(TArray< class FLifetimePr //DISABLE_REPLICATED_PRIVATE_PROPERTY(AActor, AttachmentReplication); } +void UNoRepSphereComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UNoRepSphereComponent, bReplicateMovement, this); +#endif +} + void UNoRepSphereComponent::PreReplication(IRepChangedPropertyTracker& ChangedPropertyTracker) { Super::PreReplication(ChangedPropertyTracker); @@ -95,6 +106,15 @@ void UInversePhysicsSkeletalMeshComponent::PreReplication(IRepChangedPropertyTra DOREPLIFETIME_ACTIVE_OVERRIDE_FAST(USceneComponent, RelativeScale3D, bReplicateMovement); } + +void UInversePhysicsSkeletalMeshComponent::SetReplicateMovement(bool bNewReplicateMovement) +{ + bReplicateMovement = bNewReplicateMovement; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UInversePhysicsSkeletalMeshComponent, bReplicateMovement, this); +#endif +} + void UInversePhysicsSkeletalMeshComponent::EndPhysicsTickComponentVR(FSkeletalMeshComponentEndPhysicsTickFunctionVR& ThisTickFunction) { //IMPORTANT! @@ -632,7 +652,10 @@ void UInversePhysicsSkeletalMeshComponent::GetLifetimeReplicatedProps(TArray< cl { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME(UInversePhysicsSkeletalMeshComponent, bReplicateMovement); + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UInversePhysicsSkeletalMeshComponent, bReplicateMovement, PushModelParams); } AOptionalRepGrippableSkeletalMeshActor::AOptionalRepGrippableSkeletalMeshActor(const FObjectInitializer& ObjectInitializer) : @@ -646,8 +669,11 @@ void AOptionalRepGrippableSkeletalMeshActor::GetLifetimeReplicatedProps(TArray< { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME(AOptionalRepGrippableSkeletalMeshActor, bIgnoreAttachmentReplication); - DOREPLIFETIME(AOptionalRepGrippableSkeletalMeshActor, bIgnorePhysicsReplication); + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_InitialOnly, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(AOptionalRepGrippableSkeletalMeshActor, bIgnoreAttachmentReplication, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(AOptionalRepGrippableSkeletalMeshActor, bIgnorePhysicsReplication, PushModelParamsWithCondition); if (bIgnoreAttachmentReplication) { diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/VRAIPerceptionOverrides.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/VRAIPerceptionOverrides.cpp index a874925..8dcd672 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/VRAIPerceptionOverrides.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/VRAIPerceptionOverrides.cpp @@ -3,8 +3,11 @@ #include "Misc/VRAIPerceptionOverrides.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(VRAIPerceptionOverrides) -#include "EngineDefines.h" -#include "EngineGlobals.h" +#include "CoreMinimal.h" +#include "Engine/Engine.h" +#include "Engine/World.h" +//#include "EngineDefines.h" +//#include "EngineGlobals.h" #include "CollisionQueryParams.h" //#include "Engine/Engine.h" #include "AISystem.h" @@ -45,12 +48,12 @@ DECLARE_CYCLE_STAT(TEXT("Perception Sense: Sight, Process pending result"), STAT -static const int32 DefaultMaxTracesPerTick = 6; -static const int32 DefaultMaxAsyncTracesPerTick = 10; -static const int32 DefaultMinQueriesPerTimeSliceCheck = 40; -static const float DefaultPendingQueriesBudgetReductionRatio = 0.5f; -static const bool bDefaultUseAsynchronousTraceForDefaultSightQueries = false; -static const float DefaultStimulusStrength = 1.f; +constexpr int32 DefaultMaxTracesPerTick = 6; +constexpr int32 DefaultMaxAsyncTracesPerTick = 10; +constexpr int32 DefaultMinQueriesPerTimeSliceCheck = 40; +constexpr float DefaultPendingQueriesBudgetReductionRatio = 0.5f; +constexpr bool bDefaultUseAsynchronousTraceForDefaultSightQueries = false; +constexpr float DefaultStimulusStrength = 1.f; enum class EForEachResult : uint8 { @@ -111,7 +114,7 @@ FORCEINLINE_DEBUGGABLE bool CheckIsTargetInSightPie(const FPerceptionListener& L const FAISightTargetVR::FTargetId FAISightTargetVR::InvalidTargetId = FAISystem::InvalidUnsignedID; FAISightTargetVR::FAISightTargetVR(AActor* InTarget, FGenericTeamId InTeamId) - : Target(InTarget), SightTargetInterface(NULL), TeamId(InTeamId) + : Target(InTarget), SightTargetInterface(nullptr), TeamId(InTeamId) { if (InTarget) { @@ -139,8 +142,10 @@ UAISense_Sight_VR::FDigestedSightProperties::FDigestedSightProperties(const UAIS } UAISense_Sight_VR::FDigestedSightProperties::FDigestedSightProperties() - : PeripheralVisionAngleCos(0.f), SightRadiusSq(-1.f), AutoSuccessRangeSqFromLastSeenLocation(FAISystem::InvalidRange), LoseSightRadiusSq(-1.f), PointOfViewBackwardOffset(0.0f), NearClippingRadiusSq(0.0f), AffiliationFlags(-1) -{} + : PeripheralVisionAngleCos(0.f), SightRadiusSq(-1.f), AutoSuccessRangeSqFromLastSeenLocation(FAISystem::InvalidRange), LoseSightRadiusSq(-1.f), PointOfViewBackwardOffset(0.0f), NearClippingRadiusSq(0.0f) +{ + AffiliationFlags = FAISenseAffiliationFilter::DetectAllFlags(); +} //----------------------------------------------------------------------// @@ -338,7 +343,7 @@ float UAISense_Sight_VR::Update() #if AISENSE_SIGHT_TIMESLICING_DEBUG UE::AISense_SightVR::FTimingSlicingInfo SlicingInfo; #endif // AISENSE_SIGHT_TIMESLICING_DEBUG - static const int32 InitialInvalidItemsSize = 16; + constexpr int32 InitialInvalidItemsSize = 16; enum class EOperationType : uint8 { Remove, @@ -488,7 +493,7 @@ float UAISense_Sight_VR::Update() }); // Do all the removes first and save the out of range swaps because we will insert them at the right location to prevent sorting TArray SightQueriesOutOfRangeToInsert; - for (FQueryOperation& Operation : QueryOperations) + for (const FQueryOperation& Operation : QueryOperations) { switch (Operation.OpType) { @@ -520,12 +525,12 @@ float UAISense_Sight_VR::Update() if (Operation.bInRange) { // In range queries are always sorted at the beginning of the update - SightQueriesInRange.RemoveAtSwap(Operation.Index, 1, /*bAllowShrinking*/false); + SightQueriesInRange.RemoveAtSwap(Operation.Index, 1, EAllowShrinking::No); } else { // Preserve the list ordered - SightQueriesOutOfRange.RemoveAt(Operation.Index, 1, /*bAllowShrinking*/false); + SightQueriesOutOfRange.RemoveAt(Operation.Index, 1, EAllowShrinking::No); if (Operation.Index < NextOutOfRangeIndex) { NextOutOfRangeIndex--; @@ -547,7 +552,7 @@ float UAISense_Sight_VR::Update() for (const auto& TargetId : InvalidTargets) { // remove affected queries - RemoveAllQueriesToTarget(TargetId); + RemoveAllQueriesToTarget_Internal(TargetId); // remove target itself ObservedTargets.Remove(TargetId); } @@ -751,7 +756,7 @@ void UAISense_Sight_VR::OnPendingTraceQueryProcessed(const FTraceHandle& TraceHa void UAISense_Sight_VR::OnPendingQueryProcessed(const int32 SightQueryIndex, const bool bIsVisible, const float StimulusStrength, const FVector& SeenLocation, const TOptional& UserData, const TOptional InTargetActor) { FAISightQueryVR SightQuery = SightQueriesPending[SightQueryIndex]; - SightQueriesPending.RemoveAtSwap(SightQueryIndex, 1, false); + SightQueriesPending.RemoveAtSwap(SightQueryIndex, 1, EAllowShrinking::No); AIPerception::FListenerMap& ListenersMap = *GetListeners(); FPerceptionListener* Listener = ListenersMap.Find(SightQuery.ObserverId); @@ -855,7 +860,7 @@ void UAISense_Sight_VR::UnregisterSource(AActor& SourceActor) Listener.RegisterStimulus(TargetActor, FAIStimulus(*this, 0.f, SightQuery->LastSeenLocation, Listener.CachedLocation, FAIStimulus::SensingFailed)); } - SightQueries.RemoveAtSwap(QueryIndex, 1, /*bAllowShrinking=*/false); + SightQueries.RemoveAtSwap(QueryIndex, 1, EAllowShrinking::No); return EReverseForEachResult::Modified; } @@ -1015,7 +1020,7 @@ void UAISense_Sight_VR::OnListenerUpdateImpl(const FPerceptionListener& UpdatedL // see if this listener is a Target as well const FAISightTargetVR::FTargetId AsTargetId = UpdatedListener.GetBodyActorUniqueID(); FAISightTargetVR* AsTarget = ObservedTargets.Find(AsTargetId); - if (AsTarget != NULL) + if (AsTarget != nullptr) { if (AsTarget->Target.IsValid()) { @@ -1126,13 +1131,11 @@ void UAISense_Sight_VR::RemoveAllQueriesByListener(const FPerceptionListener& Li { OnRemoveFunc(SightQuery); } - SightQueries.RemoveAtSwap(QueryIndex, 1, /*bAllowShrinking=*/false); + SightQueries.RemoveAtSwap(QueryIndex, 1, EAllowShrinking::No); return EReverseForEachResult::Modified; } - - return EReverseForEachResult::UnTouched; }; ReverseForEach(SightQueriesInRange, RemoveQuery); @@ -1148,6 +1151,12 @@ void UAISense_Sight_VR::RemoveAllQueriesToTarget(const FAISightTargetVR::FTarget { SCOPE_CYCLE_COUNTER(STAT_AI_Sense_Sight_RemoveToTarget); UE_MT_SCOPED_WRITE_ACCESS(QueriesListAccessDetector); + RemoveAllQueriesToTarget_Internal(TargetId, OnRemoveFunc); +} + +void UAISense_Sight_VR::RemoveAllQueriesToTarget_Internal(const FAISightTargetVR::FTargetId& TargetId, const TFunction& OnRemoveFunc/*= nullptr */) +{ + SCOPE_CYCLE_COUNTER(STAT_AI_Sense_Sight_RemoveToTarget); auto RemoveQuery = [&TargetId, &OnRemoveFunc](TArray& SightQueries, const int32 QueryIndex)->EReverseForEachResult { @@ -1159,7 +1168,7 @@ void UAISense_Sight_VR::RemoveAllQueriesToTarget(const FAISightTargetVR::FTarget { OnRemoveFunc(SightQuery); } - SightQueries.RemoveAtSwap(QueryIndex, 1, /*bAllowShrinking=*/false); + SightQueries.RemoveAtSwap(QueryIndex, 1, EAllowShrinking::No); return EReverseForEachResult::Modified; } diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/VREPhysicalAnimationComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/VREPhysicalAnimationComponent.cpp index 24b97a8..f109a22 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/VREPhysicalAnimationComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Misc/VREPhysicalAnimationComponent.cpp @@ -8,9 +8,11 @@ #include "ReferenceSkeleton.h" #include "DrawDebugHelpers.h" -#if ENABLE_DRAW_DEBUG +#if UE_ENABLE_DEBUG_DRAWING #include "Chaos/ImplicitObject.h" #include "Chaos/TriangleMeshImplicitObject.h" +#include "Chaos/ShapeInstance.h" +#include "Chaos/DebugDrawQueue.h" #endif #include "Physics/PhysicsInterfaceCore.h" @@ -231,8 +233,8 @@ void UVREPhysicalAnimationComponent::UpdateWeldedBoneDriver(float DeltaTime) if (FPhysicsInterface::IsValid(ActorHandle) /*&& FPhysicsInterface::IsRigidBody(ActorHandle)*/) { -#if ENABLE_DRAW_DEBUG - if (bDebugDrawCollision) +#if UE_ENABLE_DEBUG_DRAWING + if (false)//bDebugDrawCollision) { Chaos::FDebugDrawQueue::GetInstance().SetConsumerActive(this, true); // Need to deactivate this later as well Chaos::FDebugDrawQueue::GetInstance().SetMaxCost(20000); @@ -251,8 +253,8 @@ void UVREPhysicalAnimationComponent::UpdateWeldedBoneDriver(float DeltaTime) FTransform GlobalPoseInv = GlobalPose.Inverse(); -#if ENABLE_DRAW_DEBUG - if (bDebugDrawCollision) +#if UE_ENABLE_DEBUG_DRAWING + if (false)//bDebugDrawCollision) { Chaos::FDebugDrawQueue::GetInstance().SetRegionOfInterest(GlobalPose.GetLocation(), 100.0f); } @@ -305,33 +307,33 @@ void UVREPhysicalAnimationComponent::UpdateWeldedBoneDriver(float DeltaTime) } } -#if ENABLE_DRAW_DEBUG - if (bDebugDrawCollision) +#if UE_ENABLE_DEBUG_DRAWING + if (false)//bDebugDrawCollision) { - const Chaos::FImplicitObject* ShapeImplicit = Shape.Shape->GetGeometry().Get(); - Chaos::EImplicitObjectType Type = ShapeImplicit->GetType(); + /*const Chaos::FImplicitObject& ShapeImplicit = Shape.GetGeometry(); + Chaos::EImplicitObjectType Type = ShapeImplicit.GetType(); FTransform shapeTransform = FPhysicsInterface::GetLocalTransform(Shape); FTransform FinalTransform = shapeTransform * GlobalPose; Chaos::FRigidTransform3 RigTransform(FinalTransform); - Chaos::DebugDraw::DrawShape(RigTransform, ShapeImplicit, Chaos::FShapeOrShapesArray(), FColor::White); + Chaos::DebugDraw::DrawShape(RigTransform, &ShapeImplicit, Shape.Shape, FColor::White);*/ } #endif } }); -#if ENABLE_DRAW_DEBUG - if (bDebugDrawCollision) +#if UE_ENABLE_DEBUG_DRAWING + if (false)//bDebugDrawCollision) { // Get the latest commands - TArray DrawCommands; + /*TArray DrawCommands; Chaos::FDebugDrawQueue::GetInstance().ExtractAllElements(DrawCommands); if (DrawCommands.Num()) { DebugDrawMesh(DrawCommands); } Chaos::FDebugDrawQueue::GetInstance().SetConsumerActive(this, false); // Need to deactivate this later as well - Chaos::FDebugDrawQueue::GetInstance().SetEnabled(false); + Chaos::FDebugDrawQueue::GetInstance().SetEnabled(false);*/ } #endif } @@ -341,7 +343,8 @@ void UVREPhysicalAnimationComponent::UpdateWeldedBoneDriver(float DeltaTime) } } -#if ENABLE_DRAW_DEBUG +#if UE_ENABLE_DEBUG_DRAWING +/* void UVREPhysicalAnimationComponent::DebugDrawMesh(const TArray& DrawCommands) { UWorld* World = this->GetWorld(); @@ -382,5 +385,5 @@ void UVREPhysicalAnimationComponent::DebugDrawMesh(const TArraybBegunPlay) + if (!World || !World->GetBegunPlay()) return; // Reference to the Render Target resource @@ -485,14 +490,24 @@ void ARenderTargetReplicationProxy::SendNextDataBlob() } } +void ARenderTargetReplicationProxy::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + if (SendTimer_Handle.IsValid()) + GetWorld()->GetTimerManager().ClearTimer(SendTimer_Handle); + + Super::EndPlay(EndPlayReason); +} + //============================================================================= void ARenderTargetReplicationProxy::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty >& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_InitialOnly, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; - DOREPLIFETIME(ARenderTargetReplicationProxy, OwningManager); - DOREPLIFETIME(ARenderTargetReplicationProxy, OwnersID); + DOREPLIFETIME_WITH_PARAMS_FAST(ARenderTargetReplicationProxy, OwningManager, PushModelParamsWithCondition); + DOREPLIFETIME_WITH_PARAMS_FAST(ARenderTargetReplicationProxy, OwnersID, PushModelParamsWithCondition); } void ARenderTargetReplicationProxy::ReceiveTextureBlob_Implementation(const TArray& TextureBlob, int32 LocationInData, int32 BlobNumber) diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Mover/VRMoverComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Mover/VRMoverComponent.cpp new file mode 100644 index 0000000..e6bb8ba --- /dev/null +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Mover/VRMoverComponent.cpp @@ -0,0 +1,207 @@ + +#include "Mover/VRMoverComponent.h" +#include UE_INLINE_GENERATED_CPP_BY_NAME(VRMoverComponent) + +#include "VRBPDatatypes.h" +#include "DefaultMovementSet\LayeredMoves\BasicLayeredMoves.h" +#include "Engine/BlueprintGeneratedClass.h" +#include "Curves\CurveFloat.h" // Delete after tests, only needed for cloning +#include "ReplicatedVRCameraComponent.h" + +DEFINE_LOG_CATEGORY(LogVRMoverComponent); + + +static const FName Name_CharacterMotionComponent(TEXT("MoverComponent")); + +/* + + Layered move to inject VR movement into the mover component + +*/ + + +FLayeredMove_VRMovement::FLayeredMove_VRMovement() + : Velocity(FVector::ZeroVector) + , MagnitudeOverTime(nullptr) + , SettingsFlags(0) +{ + // This should never end + DurationMs = -1.0f; +} + +bool FLayeredMove_VRMovement::IsFinished(float CurrentSimTimeMs) const +{ + // We never end the VR velocity injection + return false; +} + +bool FLayeredMove_VRMovement::GenerateMove(const FMoverTickStartData& SimState, const FMoverTimeStep& TimeStep, const UMoverComponent* MoverComp, UMoverBlackboard* SimBlackboard, FProposedMove& OutProposedMove) +{ + const FMoverDefaultSyncState* SyncState = SimState.SyncState.SyncStateCollection.FindDataByType(); + check(SyncState); + + const float DeltaSeconds = TimeStep.StepMs * 0.001f; + + // Convert starting velocity based on starting orientation, if settings call for it + if (SettingsFlags & (uint8)ELayeredMove_ConstantVelocitySettingsFlags::VelocityStartRelative && + StartSimTimeMs == TimeStep.BaseSimTimeMs) + { + SettingsFlags &= ~(uint8)ELayeredMove_ConstantVelocitySettingsFlags::VelocityStartRelative; + Velocity = SyncState->GetOrientation_WorldSpace().RotateVector(Velocity); + } + + FVector VelocityThisFrame = Velocity; + + // Put velocity into worldspace + if (SettingsFlags & (uint8)ELayeredMove_ConstantVelocitySettingsFlags::VelocityAlwaysRelative) + { + VelocityThisFrame = SyncState->GetOrientation_WorldSpace().RotateVector(Velocity); + } + + if (MagnitudeOverTime && DurationMs > 0) + { + const float TimeValue = DurationMs > 0.f ? FMath::Clamp((TimeStep.BaseSimTimeMs - StartSimTimeMs) / DurationMs, 0.f, 1.f) : TimeStep.BaseSimTimeMs; + const float TimeFactor = MagnitudeOverTime->GetFloatValue(TimeValue); + VelocityThisFrame *= TimeFactor; + } + + OutProposedMove.LinearVelocity = VelocityThisFrame; + + return true; +} + +FLayeredMoveBase* FLayeredMove_VRMovement::Clone() const +{ + FLayeredMove_VRMovement* CopyPtr = new FLayeredMove_VRMovement(*this); + return CopyPtr; +} + +void FLayeredMove_VRMovement::NetSerialize(FArchive& Ar) +{ + Super::NetSerialize(Ar); + + SerializePackedVector<10, 16>(Velocity, Ar); + Ar << SettingsFlags; + Ar << MagnitudeOverTime; +} + +UScriptStruct* FLayeredMove_VRMovement::GetScriptStruct() const +{ + return FLayeredMove_VRMovement::StaticStruct(); +} + +FString FLayeredMove_VRMovement::ToSimpleString() const +{ + return FString::Printf(TEXT("LinearVelocity")); +} + +void FLayeredMove_VRMovement::AddReferencedObjects(class FReferenceCollector& Collector) +{ + Super::AddReferencedObjects(Collector); +} + + +/* + + VR HMD Sync State to store the HMD velocities + Which should be pulled from input somehow +*/ + +FMoverDataStructBase* FVRMoverHMDSyncState::Clone() const +{ + // TODO: ensure that this memory allocation jives with deletion method + FVRMoverHMDSyncState* CopyPtr = new FVRMoverHMDSyncState(*this); + return CopyPtr; +} + +bool FVRMoverHMDSyncState::NetSerialize(FArchive& Ar, UPackageMap* Map, bool& bOutSuccess) +{ + Super::NetSerialize(Ar, Map, bOutSuccess); + + SerializeFixedVector<2, 8>(MoveDirectionIntent, Ar); + bOutSuccess = true; + return true; +} + + + +AVRMoverBasePawn::AVRMoverBasePawn(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + + CharacterMotionComponent = CreateDefaultSubobject(Name_CharacterMotionComponent); + ensure(CharacterMotionComponent); + + // Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it. + PrimaryActorTick.bCanEverTick = true; + + SetReplicatingMovement(false); // disable Actor-level movement replication, since our Mover component will handle it + + // Let the code know if blueprints have implemented input + auto IsImplementedInBlueprint = [](const UFunction* Func) -> bool + { + return Func && ensure(Func->GetOuter()) + && Func->GetOuter()->IsA(UBlueprintGeneratedClass::StaticClass()); + }; + + static FName ProduceInputBPFuncName = FName(TEXT("OnProduceInputInBlueprint")); + UFunction* ProduceInputFunction = GetClass()->FindFunctionByName(ProduceInputBPFuncName); + bHasProduceInputinBpFunc = IsImplementedInBlueprint(ProduceInputFunction); +} + +void AVRMoverBasePawn::BeginPlay() +{ + Super::BeginPlay(); + + // In constructor for the data instead of begin play? Might even be able to queue the layered move there too + if (IsValid(CharacterMotionComponent)) + { + // Add the sync data for our layered HMD movement injection + CharacterMotionComponent->PersistentSyncStateDataTypes.Add(FMoverDataPersistence(FVRMoverHMDSyncState::StaticStruct(), true)); + + // Needs to be handled off of possession instead? + if (HasLocalNetOwner()) + { + // Add the persistant HMDlayered move addition + TSharedPtr VRMoveLayer = MakeShared(); + CharacterMotionComponent->QueueLayeredMove(VRMoveLayer); + } + } +} + + +UPrimitiveComponent* AVRMoverBasePawn::GetMovementBase() const +{ + return CharacterMotionComponent ? CharacterMotionComponent->GetMovementBase() : nullptr; +} + + +void AVRMoverBasePawn::ProduceInput_Implementation(int32 SimTimeMs, FMoverInputCmdContext& InputCmdResult) +{ + OnProduceInput((float)SimTimeMs, InputCmdResult); + + if (bHasProduceInputinBpFunc) + { + InputCmdResult = OnProduceInputInBlueprint((float)SimTimeMs, InputCmdResult); + } +} + + +void AVRMoverBasePawn::OnProduceInput(float DeltaMs, FMoverInputCmdContext& OutInputCmd) +{ + + // Generate user commands. Called right before the Character movement simulation will tick (for a locally controlled pawn) + // This isn't meant to be the best way of doing a camera system. It is just meant to show a couple of ways it may be done + // and to make sure we can keep distinct the movement, rotation, and view angles. + // Styles 1-3 are really meant to be used with a gamepad. + // + // Its worth calling out: the code that happens here is happening *outside* of the Character movement simulation. All we are doing + // is generating the input being fed into that simulation. That said, this means that A) the code below does not run on the server + // (and non controlling clients) and B) the code is not rerun during reconcile/resimulates. Use this information guide any + // decisions about where something should go (such as aim assist, lock on targeting systems, etc): it is hard to give absolute + // answers and will depend on the game and its specific needs. In general, at this time, I'd recommend aim assist and lock on + // targeting systems to happen /outside/ of the system, i.e, here. But I can think of scenarios where that may not be ideal too. + + //FCharacterDefaultInputs& CharacterInputs = OutInputCmd.InputCollection.FindOrAddMutableDataByType(); + +} diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/ParentRelativeAttachmentComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/ParentRelativeAttachmentComponent.cpp index 6dc37e9..741ed2f 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/ParentRelativeAttachmentComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/ParentRelativeAttachmentComponent.cpp @@ -3,6 +3,7 @@ #include "ParentRelativeAttachmentComponent.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(ParentRelativeAttachmentComponent) +#include "Engine/Engine.h" #include "VRBaseCharacter.h" #include "VRCharacter.h" #include "IXRTrackingSystem.h" diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/ReplicatedVRCameraComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/ReplicatedVRCameraComponent.cpp index 6e45633..c592ee2 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/ReplicatedVRCameraComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/ReplicatedVRCameraComponent.cpp @@ -3,6 +3,9 @@ #include "ReplicatedVRCameraComponent.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(ReplicatedVRCameraComponent) +#include "CoreMinimal.h" +#include "Engine/Engine.h" +#include "Engine/World.h" #include "Net/UnrealNetwork.h" #include "VRBaseCharacter.h" #include "VRCharacter.h" @@ -11,6 +14,9 @@ #include "IXRCamera.h" #include "Rendering/MotionVectorSimulation.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif UReplicatedVRCameraComponent::UReplicatedVRCameraComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -41,7 +47,6 @@ UReplicatedVRCameraComponent::UReplicatedVRCameraComponent(const FObjectInitiali MaximumTrackedBounds = 1028; bSetPositionDuringTick = false; - bSmoothReplicatedMotion = false; bLerpingPosition = false; bReppedOnce = false; @@ -70,28 +75,27 @@ void UReplicatedVRCameraComponent::GetLifetimeReplicatedProps(TArray< class FLif DISABLE_REPLICATED_PRIVATE_PROPERTY(USceneComponent, RelativeRotation); DISABLE_REPLICATED_PRIVATE_PROPERTY(USceneComponent, RelativeScale3D); + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_SkipOwner, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + // Skipping the owner with this as the owner will use the location directly - DOREPLIFETIME_CONDITION(UReplicatedVRCameraComponent, ReplicatedCameraTransform, COND_SkipOwner); - DOREPLIFETIME(UReplicatedVRCameraComponent, NetUpdateRate); - DOREPLIFETIME(UReplicatedVRCameraComponent, bSmoothReplicatedMotion); + DOREPLIFETIME_WITH_PARAMS_FAST(UReplicatedVRCameraComponent, ReplicatedCameraTransform, PushModelParamsWithCondition); + + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(UReplicatedVRCameraComponent, NetUpdateRate, PushModelParams); + //DOREPLIFETIME(UReplicatedVRCameraComponent, bSmoothReplicatedMotion); // This doesn't need to be replicated //DOREPLIFETIME(UReplicatedVRCameraComponent, bReplicateTransform); } -// Just skipping this, it generates warnings for attached meshes when using this method of denying transform replication -/*void UReplicatedVRCameraComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) -{ - Super::PreReplication(ChangedPropertyTracker); - - // Don't ever replicate these, they are getting replaced by my custom send anyway - DOREPLIFETIME_ACTIVE_OVERRIDE(USceneComponent, RelativeLocation, false); - DOREPLIFETIME_ACTIVE_OVERRIDE(USceneComponent, RelativeRotation, false); - DOREPLIFETIME_ACTIVE_OVERRIDE(USceneComponent, RelativeScale3D, false); -}*/ - void UReplicatedVRCameraComponent::Server_SendCameraTransform_Implementation(FBPVRComponentPosRep NewTransform) { // Store new transform and trigger OnRep_Function ReplicatedCameraTransform = NewTransform; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UReplicatedVRCameraComponent, ReplicatedCameraTransform, this); +#endif // Don't call on rep on the server if the server controls this controller if (!bHasAuthority) @@ -191,7 +195,7 @@ void UReplicatedVRCameraComponent::UpdateTracking(float DeltaTime) { if (HasTrackingParameters()) { - ApplyTrackingParameters(Position); + ApplyTrackingParameters(Position, true); } ReplicatedCameraTransform.Position = Position; @@ -403,6 +407,10 @@ void UReplicatedVRCameraComponent::TickComponent(float DeltaTime, enum ELevelTic ReplicatedCameraTransform.Rotation = RelativeRot; } +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UReplicatedVRCameraComponent, ReplicatedCameraTransform, this); +#endif + if (GetNetMode() == NM_Client) { AVRBaseCharacter* OwningChar = Cast(GetOwner()); @@ -458,7 +466,7 @@ void UReplicatedVRCameraComponent::HandleXRCamera() { if (HasTrackingParameters()) { - ApplyTrackingParameters(Position); + ApplyTrackingParameters(Position, true); } ReplicatedCameraTransform.Position = Position; @@ -506,6 +514,11 @@ void UReplicatedVRCameraComponent::HandleXRCamera() } } +FTransform UReplicatedVRCameraComponent::GetHMDTrackingTransform() +{ + return FTransform(ReplicatedCameraTransform.Rotation, ReplicatedCameraTransform.Position); +} + void UReplicatedVRCameraComponent::OnRep_ReplicatedCameraTransform() { if (GetNetMode() < ENetMode::NM_Client && HasTrackingParameters()) @@ -570,4 +583,19 @@ void UReplicatedVRCameraComponent::OnRep_ReplicatedCameraTransform() } else SetRelativeLocationAndRotation(CameraPosition, ReplicatedCameraTransform.Rotation); +} + +void UReplicatedVRCameraComponent::SetNetUpdateRate(float NewNetUpdateRate) +{ + NetUpdateRate = NewNetUpdateRate; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(UReplicatedVRCameraComponent, NetUpdateRate, this); +#endif +} + +bool UReplicatedVRCameraComponent::IsLocallyControlled() const +{ + // I like epics new authority check more than my own + const AActor* MyOwner = GetOwner(); + return MyOwner->HasLocalNetOwner(); } \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRAIController.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRAIController.cpp index 0d770db..dc6fc4c 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRAIController.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRAIController.cpp @@ -4,6 +4,8 @@ #include UE_INLINE_GENERATED_CPP_BY_NAME(VRAIController) //#include "VRBPDatatypes.h" +#include "CoreMinimal.h" +#include "Engine/World.h" #include "VRBaseCharacter.h" #include "Components/CapsuleComponent.h" #include "NetworkingDistanceConstants.h" // Needed for the LinOfSightTo function override to work diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRBPDatatypes.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRBPDatatypes.cpp index 0e390cc..30b9c3d 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRBPDatatypes.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRBPDatatypes.cpp @@ -3,6 +3,9 @@ #include "VRBPDatatypes.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(VRBPDatatypes) +#include "CoreMinimal.h" +#include "VRGlobalSettings.h" +#include "Components\PrimitiveComponent.h" #include "HAL/IConsoleManager.h" #include "Chaos/ChaosEngineInterface.h" @@ -104,7 +107,7 @@ void FBPEuroLowPassFilter::ResetSmoothingFilter() DeltaFilter.bFirstTime = true; } -FVector FBPEuroLowPassFilter::RunFilterSmoothing(const FVector &InRawValue, const float &InDeltaTime) +FVector FBPEuroLowPassFilter::RunFilterSmoothing(const FVector& InRawValue, const float& InDeltaTime) { if (InDeltaTime <= 0.0f) { @@ -113,7 +116,7 @@ FVector FBPEuroLowPassFilter::RunFilterSmoothing(const FVector &InRawValue, cons } // Calculate the delta, if this is the first time then there is no delta - const FVector Delta = RawFilter.bFirstTime == true ? FVector::ZeroVector : (InRawValue - RawFilter.PreviousRaw) * 1.0f / InDeltaTime; + const FVector Delta = RawFilter.bFirstTime == true ? FVector::ZeroVector : (InRawValue - RawFilter.PreviousRaw) * 1.0 / InDeltaTime; // Filter the delta to get the estimated const FVector Estimated = DeltaFilter.Filter(Delta, FVector(DeltaFilter.CalculateAlphaTau(DeltaCutoff, InDeltaTime))); @@ -154,11 +157,11 @@ FQuat FBPEuroLowPassFilterQuat::RunFilterSmoothing(const FQuat& InRawValue, cons if (!RawFilter.bFirstTime) { - Delta = (NewInVal - RawFilter.PreviousRaw) * (1.0f / InDeltaTime); + Delta = (NewInVal - RawFilter.PreviousRaw) * (1.0 / InDeltaTime); } - float AlphaTau = DeltaFilter.CalculateAlphaTau(DeltaCutoff, InDeltaTime); + double AlphaTau = DeltaFilter.CalculateAlphaTau(DeltaCutoff, InDeltaTime); FQuat AlphaTauQ(AlphaTau, AlphaTau, AlphaTau, AlphaTau); const FQuat Estimated = DeltaFilter.Filter(Delta, AlphaTauQ); @@ -198,7 +201,7 @@ FTransform FBPEuroLowPassFilterTrans::RunFilterSmoothing(const FTransform& InRaw // Calculate the delta, if this is the first time then there is no delta FTransform Delta = FTransform::Identity; - float Frequency = 1.0f / InDeltaTime; + double Frequency = 1.0 / InDeltaTime; if (!RawFilter.bFirstTime) { Delta.SetLocation((NewInVal.GetLocation() - RawFilter.PreviousRaw.GetLocation()) * Frequency); @@ -207,7 +210,7 @@ FTransform FBPEuroLowPassFilterTrans::RunFilterSmoothing(const FTransform& InRaw } - float AlphaTau = DeltaFilter.CalculateAlphaTau(DeltaCutoff, InDeltaTime); + double AlphaTau = DeltaFilter.CalculateAlphaTau(DeltaCutoff, InDeltaTime); FTransform AlphaTauQ(FQuat(AlphaTau, AlphaTau, AlphaTau, AlphaTau), FVector(AlphaTau), FVector(AlphaTau)); const FTransform Estimated = DeltaFilter.Filter(Delta, AlphaTauQ); @@ -219,3 +222,71 @@ FTransform FBPEuroLowPassFilterTrans::RunFilterSmoothing(const FTransform& InRaw // Filter passed value return NewTrans; } + +bool FBPAdvancedPhysicsHandleSettings::FillTo(FBPActorPhysicsHandleInformation* HandleInfo, bool bModifyWithScalers) const +{ + if (!HandleInfo) + return false; + + float DampingMod = 0.0f; + float StiffnessMod = 0.0f; + float ADampingMod = 0.0f; + float AStiffnessMod = 0.0f; + const UVRGlobalSettings& VRSettings = *GetDefault(); + + if (VRSettings.bUseChaosTranslationScalers) + { + StiffnessMod = VRSettings.LinearDriveStiffnessScale; + DampingMod = VRSettings.LinearDriveDampingScale; + AStiffnessMod = VRSettings.AngularDriveStiffnessScale; + ADampingMod = VRSettings.AngularDriveDampingScale; + } + else + { + auto CVarLinearDriveStiffnessScale = IConsoleManager::Get().FindConsoleVariable(TEXT("p.Chaos.JointConstraint.LinearDriveStiffnessScale")); + auto CVarLinearDriveDampingScale = IConsoleManager::Get().FindConsoleVariable(TEXT("p.Chaos.JointConstraint.LinaearDriveDampingScale")); + auto CVarAngularDriveStiffnessScale = IConsoleManager::Get().FindConsoleVariable(TEXT("p.Chaos.JointConstraint.AngularDriveStiffnessScale")); + auto CVarAngularDriveDampingScale = IConsoleManager::Get().FindConsoleVariable(TEXT("p.Chaos.JointConstraint.AngularDriveDampingScale")); + + StiffnessMod = CVarLinearDriveStiffnessScale->GetFloat(); + DampingMod = CVarLinearDriveDampingScale->GetFloat(); + AStiffnessMod = CVarAngularDriveStiffnessScale->GetFloat(); + ADampingMod = CVarAngularDriveDampingScale->GetFloat(); + } + + XAxisSettings.FillTo(HandleInfo->LinConstraint.XDrive, DampingMod, StiffnessMod); + YAxisSettings.FillTo(HandleInfo->LinConstraint.YDrive, DampingMod, StiffnessMod); + ZAxisSettings.FillTo(HandleInfo->LinConstraint.ZDrive, DampingMod, StiffnessMod); + + if ((SlerpSettings.bEnablePositionDrive || SlerpSettings.bEnableVelocityDrive)) + { + HandleInfo->AngConstraint.AngularDriveMode = EAngularDriveMode::SLERP; + SlerpSettings.FillTo(HandleInfo->AngConstraint.SlerpDrive, ADampingMod, AStiffnessMod); + } + else + { + HandleInfo->AngConstraint.AngularDriveMode = EAngularDriveMode::TwistAndSwing; + TwistSettings.FillTo(HandleInfo->AngConstraint.TwistDrive, ADampingMod, AStiffnessMod); + SwingSettings.FillTo(HandleInfo->AngConstraint.SwingDrive, ADampingMod, AStiffnessMod); + } + + return true; +} + +AActor* FBPActorGripInformation::GetGrippedActor() const +{ + return Cast(GrippedObject); +} + +UPrimitiveComponent* FBPActorGripInformation::GetGrippedComponent() const +{ + return Cast(GrippedObject); +} + +bool FBPActorGripInformation::operator==(const UPrimitiveComponent* Other) const +{ + if (Other && GrippedObject && GrippedObject == (const UObject*)Other) + return true; + + return false; +} \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRBaseCharacter.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRBaseCharacter.cpp index bbf298b..43efdf8 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRBaseCharacter.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRBaseCharacter.cpp @@ -14,8 +14,13 @@ #include "VRPathFollowingComponent.h" #include "Net/UnrealNetwork.h" #include "XRMotionControllerBase.h" +#include "NavFilters/NavigationQueryFilter.h" //#include "Runtime/Engine/Private/EnginePrivate.h" +#if WITH_PUSH_MODEL +#include "Net/Core/PushModel/PushModel.h" +#endif + DEFINE_LOG_CATEGORY(LogBaseVRCharacter); FName AVRBaseCharacter::LeftMotionControllerComponentName(TEXT("Left Grip Motion Controller")); @@ -235,13 +240,24 @@ void AVRBaseCharacter::PostInitializeComponents() void AVRBaseCharacter::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - DOREPLIFETIME_CONDITION(AVRBaseCharacter, SeatInformation, COND_None); - DOREPLIFETIME_CONDITION(AVRBaseCharacter, VRReplicateCapsuleHeight, COND_None); - DOREPLIFETIME_CONDITION(AVRBaseCharacter, ReplicatedCapsuleHeight, COND_SimulatedOnly); + + // For std properties + FDoRepLifetimeParams PushModelParams{ COND_None, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(AVRBaseCharacter, SeatInformation, PushModelParams); + DOREPLIFETIME_WITH_PARAMS_FAST(AVRBaseCharacter, VRReplicateCapsuleHeight, PushModelParams); + + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsWithCondition{ COND_SimulatedOnly, REPNOTIFY_OnChanged, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(AVRBaseCharacter, ReplicatedCapsuleHeight, PushModelParamsWithCondition); DISABLE_REPLICATED_PRIVATE_PROPERTY(AActor, ReplicatedMovement); - DOREPLIFETIME_CONDITION_NOTIFY(AVRBaseCharacter, ReplicatedMovementVR, COND_SimulatedOrPhysics, REPNOTIFY_Always); + // For properties with special conditions + FDoRepLifetimeParams PushModelParamsReplicatedMovement{ COND_SimulatedOrPhysics, REPNOTIFY_Always, /*bIsPushBased=*/true }; + + DOREPLIFETIME_WITH_PARAMS_FAST(AVRBaseCharacter, ReplicatedMovementVR, PushModelParamsReplicatedMovement); } void AVRBaseCharacter::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) @@ -283,6 +299,10 @@ void AVRBaseCharacter::Server_ReZeroSeating_Implementation(FTransform_NetQuantiz SeatInformation.StoredTargetTransform.AddToTranslation(FVector(0, 0, -newLocation.Z)); } +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AVRBaseCharacter, SeatInformation, this); +#endif + OnRep_SeatedCharInfo(); } @@ -457,6 +477,10 @@ void AVRBaseCharacter::GatherCurrentMovement() ReplicatedMovementVR.PausedTrackingLoc = PausedTrackingLoc; ReplicatedMovementVR.PausedTrackingRot = PausedTrackingRot; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AVRBaseCharacter, ReplicatedMovementVR, this); +#endif + } @@ -784,7 +808,7 @@ bool AVRBaseCharacter::SetSeatedMode(USceneComponent * SeatParent, bool bSetSeat // I think we can remove the initial value alltogether eventually right? if (!bRetainRoomscale && VRReplicatedCamera) { - InitialRelCameraTransform = FTransform(VRReplicatedCamera->ReplicatedCameraTransform.Rotation, VRReplicatedCamera->ReplicatedCameraTransform.Position, VRReplicatedCamera->GetComponentScale()); + InitialRelCameraTransform = VRReplicatedCamera->GetHMDTrackingTransform(); } SeatInformation.SeatParent = SeatParent; @@ -805,6 +829,10 @@ bool AVRBaseCharacter::SetSeatedMode(USceneComponent * SeatParent, bool bSetSeat SeatInformation.StoredTargetTransform.AddToTranslation(FVector(0, 0, -newLocation.Z)); } +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AVRBaseCharacter, SeatInformation, this); +#endif + //SetReplicateMovement(false);/ / No longer doing this, allowing it to replicate down to simulated clients now instead } else @@ -815,6 +843,9 @@ bool AVRBaseCharacter::SetSeatedMode(USceneComponent * SeatParent, bool bSetSeat //SetReplicateMovement(true); // No longer doing this, allowing it to replicate down to simulated clients now instead SeatInformation.bSitting = false; } +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AVRBaseCharacter, SeatInformation, this); +#endif OnRep_SeatedCharInfo(); // Call this on server side because it won't call itself NotifyOfTeleport(); // Teleport the controllers @@ -1205,3 +1236,11 @@ void AVRBaseCharacter::StopNavigationMovement() pathComp->AbortMove(*this, FPathFollowingResultFlags::MovementStop | FPathFollowingResultFlags::ForcedScript); } } + +void AVRBaseCharacter::SetVRReplicateCapsuleHeight(bool bNewVRReplicateCapsuleHeight) +{ + VRReplicateCapsuleHeight = bNewVRReplicateCapsuleHeight; +#if WITH_PUSH_MODEL + MARK_PROPERTY_DIRTY_FROM_NAME(AVRBaseCharacter, VRReplicateCapsuleHeight, this); +#endif +} \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRBaseCharacterMovementComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRBaseCharacterMovementComponent.cpp index 32854cf..ea4e5d6 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRBaseCharacterMovementComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRBaseCharacterMovementComponent.cpp @@ -19,6 +19,7 @@ #include "Navigation/PathFollowingComponent.h" #include "VRPlayerController.h" #include "GameFramework/PhysicsVolume.h" +#include "Animation\AnimInstance.h" DEFINE_LOG_CATEGORY(LogVRBaseCharacterMovement); @@ -1620,11 +1621,17 @@ void UVRBaseCharacterMovementComponent::OnClientCorrectionReceived(class FNetwor { BaseVRCharacterOwner->OnCharacterNetworkCorrected_Bind.Broadcast(); - if(IsValid(BaseVRCharacterOwner->LeftMotionController)) + if (IsValid(BaseVRCharacterOwner->LeftMotionController)) + { BaseVRCharacterOwner->LeftMotionController->TeleportMoveGrips(false, false); + BaseVRCharacterOwner->LeftMotionController->PostTeleportMoveGrippedObjects(); + } if (IsValid(BaseVRCharacterOwner->RightMotionController)) + { BaseVRCharacterOwner->RightMotionController->TeleportMoveGrips(false, false); + BaseVRCharacterOwner->RightMotionController->PostTeleportMoveGrippedObjects(); + } //BaseVRCharacterOwner->NotifyOfTeleport(false); } } @@ -1887,6 +1894,9 @@ void UVRBaseCharacterMovementComponent::MoveAutonomous( const bool bWasPlayingRootMotion = CharacterOwner->IsPlayingRootMotion(); + // Scope these, they nest with Outer references so it should work fine, this keeps the update rotation and move autonomous from double updating the char + //const FScopedPreventAttachedComponentMove PreventMeshMove(BaseVRCharacterOwner ? BaseVRCharacterOwner->NetSmoother : nullptr); + PerformMovement(DeltaTime); // Check if data is valid as PerformMovement can mark character for pending kill @@ -1904,12 +1914,31 @@ void UVRBaseCharacterMovementComponent::MoveAutonomous( } // TODO: SaveBaseLocation() in case tick moves us? + + USkeletalMeshComponent* OwnerMesh = CharacterOwner->GetMesh(); + check(OwnerMesh != nullptr) + static const auto CVarEnableQueuedAnimEventsOnServer = IConsoleManager::Get().FindConsoleVariable(TEXT("a.EnableQueuedAnimEventsOnServer")); - if (!CVarEnableQueuedAnimEventsOnServer->GetInt() || CharacterOwner->GetMesh()->ShouldOnlyTickMontages(DeltaTime)) + if (CVarEnableQueuedAnimEventsOnServer->GetInt()) { - // If we're not doing a full anim graph update on the server, - // trigger events right away, as we could be receiving multiple ServerMoves per frame. - CharacterOwner->GetMesh()->ConditionallyDispatchQueuedAnimEvents(); + if (const UAnimInstance* AnimInstance = OwnerMesh->GetAnimInstance()) + { + if (OwnerMesh->VisibilityBasedAnimTickOption <= EVisibilityBasedAnimTickOption::AlwaysTickPose && AnimInstance->NeedsUpdate()) + { + // If we are doing a full graph update on the server but its doing a parallel update, + // trigger events right away since these are notifies queued from the montage update and we could be receiving multiple ServerMoves per frame. + OwnerMesh->ConditionallyDispatchQueuedAnimEvents(); + OwnerMesh->AllowQueuedAnimEventsNextDispatch(); + } + } + } + else + { + // Revert back to old behavior if wanted/needed. + if (OwnerMesh->ShouldOnlyTickMontages(DeltaTime)) + { + OwnerMesh->ConditionallyDispatchQueuedAnimEvents(); + } } } @@ -2229,9 +2258,10 @@ void UVRBaseCharacterMovementComponent::UpdateFromCompressedFlags(uint8 Flags) FVector UVRBaseCharacterMovementComponent::RoundDirectMovement(FVector InMovement) const { // Match FVector_NetQuantize100 (2 decimal place of precision). - InMovement.X = FMath::RoundToFloat(InMovement.X * 100.f) / 100.f; - InMovement.Y = FMath::RoundToFloat(InMovement.Y * 100.f) / 100.f; - InMovement.Z = FMath::RoundToFloat(InMovement.Z * 100.f) / 100.f; + UE::Net::QuantizeVector(100, InMovement); + //InMovement.X = FMath::RoundToFloat(InMovement.X * 100.f) / 100.f; + //InMovement.Y = FMath::RoundToFloat(InMovement.Y * 100.f) / 100.f; + //InMovement.Z = FMath::RoundToFloat(InMovement.Z * 100.f) / 100.f; return InMovement; } @@ -2378,5 +2408,5 @@ bool UVRBaseCharacterMovementComponent::SetCharacterToNewGravity(FVector NewGrav return true; } - return false; + //return false; } \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRCharacter.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRCharacter.cpp index a263946..a81130a 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRCharacter.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRCharacter.cpp @@ -14,6 +14,7 @@ #include "GameFramework/Controller.h" #include "Runtime/Launch/Resources/Version.h" #include "VRPathFollowingComponent.h" +#include "NavFilters/NavigationQueryFilter.h" //#include "Runtime/Engine/Private/EnginePrivate.h" DEFINE_LOG_CATEGORY(LogVRCharacter); @@ -197,6 +198,45 @@ FVector AVRCharacter::GetTargetHeightOffset() return bRetainRoomscale ? FVector::ZeroVector : VRRootReference->GetTargetHeightOffset(); } +void AVRCharacter::OnStartCrouch(float HeightAdjust, float ScaledHeightAdjust) +{ + RecalculateBaseEyeHeight(); + + /*const ACharacter* DefaultChar = GetDefault(GetClass()); + if (Mesh && DefaultChar->Mesh) + { + FVector& MeshRelativeLocation = Mesh->GetRelativeLocation_DirectMutable(); + MeshRelativeLocation.Z = DefaultChar->Mesh->GetRelativeLocation().Z + HeightAdjust; + BaseTranslationOffset.Z = MeshRelativeLocation.Z; + } + else + { + BaseTranslationOffset.Z = DefaultChar->BaseTranslationOffset.Z + HeightAdjust; + }*/ + + K2_OnStartCrouch(HeightAdjust, ScaledHeightAdjust); +} + +void AVRCharacter::OnEndCrouch(float HeightAdjust, float ScaledHeightAdjust) +{ + RecalculateBaseEyeHeight(); + + /*const ACharacter* DefaultChar = GetDefault(GetClass()); + if (Mesh && DefaultChar->Mesh) + { + FVector& MeshRelativeLocation = Mesh->GetRelativeLocation_DirectMutable(); + MeshRelativeLocation.Z = DefaultChar->Mesh->GetRelativeLocation().Z; + BaseTranslationOffset.Z = MeshRelativeLocation.Z; + } + else + { + BaseTranslationOffset.Z = DefaultChar->BaseTranslationOffset.Z; + }*/ + + K2_OnEndCrouch(HeightAdjust, ScaledHeightAdjust); +} + + void AVRCharacter::RegenerateOffsetComponentToWorld(bool bUpdateBounds, bool bCalculatePureYaw) { if (VRRootReference) diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRCharacterMovementComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRCharacterMovementComponent.cpp index 490f506..504ad79 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRCharacterMovementComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRCharacterMovementComponent.cpp @@ -457,7 +457,7 @@ void FSavedMove_VRCharacter::PrepMoveFor(ACharacter* Character) if (AVRBaseCharacter * BaseChar = Cast(CharMove->GetCharacterOwner())) { - if (BaseChar->VRReplicateCapsuleHeight && this->CapsuleHeight > 0.0f && !FMath::IsNearlyEqual(this->CapsuleHeight, CharMove->VRRootCapsule->GetUnscaledCapsuleHalfHeight())) + if (BaseChar->GetVRReplicateCapsuleHeight() && this->CapsuleHeight > 0.0f && !FMath::IsNearlyEqual(this->CapsuleHeight, CharMove->VRRootCapsule->GetUnscaledCapsuleHalfHeight())) { BaseChar->SetCharacterHalfHeightVR(CapsuleHeight, false); //CharMove->VRRootCapsule->SetCapsuleHalfHeight(this->LFDiff.Z, false); @@ -566,6 +566,10 @@ void UVRCharacterMovementComponent::ServerMove_PerformMovement(const FCharacterN DeltaTime = ServerData->GetServerMoveDeltaTime(ClientTimeStamp, CharacterOwner->GetActorTimeDilation(*MyWorld)); } + // They added a scope here, im not using it as im doing the full capsule above + // Scope these, they nest with Outer references so it should work fine, this keeps the update rotation and move autonomous from double updating the char + //const FScopedPreventAttachedComponentMove PreventMeshMove(BaseVRCharacterOwner ? BaseVRCharacterOwner->NetSmoother : nullptr); + if (DeltaTime > 0.f) { ServerData->CurrentClientTimeStamp = ClientTimeStamp; @@ -615,7 +619,7 @@ void UVRCharacterMovementComponent::ServerMove_PerformMovement(const FCharacterN if (BaseVRCharacterOwner) { - if (BaseVRCharacterOwner->VRReplicateCapsuleHeight && MoveDataVR->CapsuleHeight > 0.0f && !FMath::IsNearlyEqual(MoveDataVR->CapsuleHeight, VRRootCapsule->GetUnscaledCapsuleHalfHeight())) + if (BaseVRCharacterOwner->GetVRReplicateCapsuleHeight() && MoveDataVR->CapsuleHeight > 0.0f && !FMath::IsNearlyEqual(MoveDataVR->CapsuleHeight, VRRootCapsule->GetUnscaledCapsuleHalfHeight())) { BaseVRCharacterOwner->SetCharacterHalfHeightVR(MoveDataVR->CapsuleHeight, false); // BaseChar->ReplicatedCapsuleHeight.CapsuleHeight = LFDiff.Z; @@ -896,6 +900,9 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration bool bTriedLedgeMove = false; float remainingTime = deltaTime; + const EMovementMode StartingMovementMode = MovementMode; + const uint8 StartingCustomMovementMode = CustomMovementMode; + // Rewind the players position by the new capsule location RewindVRRelativeMovement(); @@ -937,9 +944,9 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration devCodeVR(ensureMsgf(!Velocity.ContainsNaN(), TEXT("PhysWalking: Velocity contains NaN after Root Motion application (%s)\n%s"), *GetPathNameSafe(this), *Velocity.ToString())); - if (IsFalling()) + if (MovementMode != StartingMovementMode || CustomMovementMode != StartingCustomMovementMode) { - // Root motion could have put us into Falling. + // Root motion could have taken us out of our current mode // No movement has taken place this movement tick so we pass on full time/past iteration count StartNewPhysics(remainingTime + timeTick, Iterations - 1); return; @@ -980,9 +987,15 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration // try to move forward MoveAlongFloor(MoveVelocity, timeTick, &StepDownResult); - if (IsFalling()) + if (IsSwimming()) //just entered water { - // pawn decided to jump up + StartSwimming(OldLocation, OldVelocity, timeTick, remainingTime, Iterations); + return; + } + else if (MovementMode != StartingMovementMode || CustomMovementMode != StartingCustomMovementMode) + { + // pawn ended up in a different mode, probably due to the step-up-and-over flow + // let's refund the estimated unused time (if any) and keep moving in the new mode const float DesiredDist = Delta.Size(); if (DesiredDist > UE_KINDA_SMALL_NUMBER) { @@ -993,12 +1006,6 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration StartNewPhysics(remainingTime, Iterations); return; } - else if (IsSwimming()) //just entered water - { - RestorePreAdditiveVRMotionVelocity(); - StartSwimmingVR(OldCapsuleLocation, OldVelocity, timeTick, remainingTime, Iterations); - return; - } } // Update floor. @@ -1296,8 +1303,7 @@ void UVRCharacterMovementComponent::ReplicateMoveToServer(float DeltaTime, const // Remove pending move from move list. It would have to be the last move on the list. if (ClientData->SavedMoves.Num() > 0 && ClientData->SavedMoves.Last() == ClientData->PendingMove) { - const bool bAllowShrinking = false; - ClientData->SavedMoves.Pop(bAllowShrinking); + ClientData->SavedMoves.Pop(EAllowShrinking::No); } ClientData->FreeMove(ClientData->PendingMove); ClientData->PendingMove = nullptr; @@ -2293,6 +2299,17 @@ void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds) } else { + // Set MovementBase's root actor as ignored when moving the character primitive component, + // only perform if bDeferUpdateBasedMovement is true since this means the MovementBase is simulating physics + const bool bIgnoreBaseActor = bDeferUpdateBasedMovement && bBasedMovementIgnorePhysicsBase; + AActor* MovementBaseRootActor = nullptr; + if (bIgnoreBaseActor) + { + MovementBaseRootActor = MovementBase->GetAttachmentRootActor(); + UpdatedPrimitive->IgnoreActorWhenMoving(MovementBaseRootActor, true); + MoveComponentFlags |= MOVECOMP_CheckBlockingRootActorInIgnoreList; // Hit actors during MoveUpdatedComponent will have their root actor compared with the ignored actors array + } + // hack - transforms between local and world space introducing slight error FIXMESTEVE - discuss with engine team: just skip the transforms if no rotation? FVector BaseMoveDelta = NewBaseLocation - OldBaseLocation; if (!bRotationChanged && (BaseMoveDelta.X == 0.f) && (BaseMoveDelta.Y == 0.f)) @@ -2304,10 +2321,18 @@ void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds) FHitResult MoveOnBaseHit(1.f); const FVector OldLocation = UpdatedComponent->GetComponentLocation(); MoveUpdatedComponent(DeltaPosition, FinalQuat, true, &MoveOnBaseHit); + if ((UpdatedComponent->GetComponentLocation() - (OldLocation + DeltaPosition)).IsNearlyZero() == false) { OnUnableToFollowBaseMove(DeltaPosition, OldLocation, MoveOnBaseHit); } + + // Reset base actor ignore state + if (bIgnoreBaseActor) + { + MoveComponentFlags &= ~MOVECOMP_CheckBlockingRootActorInIgnoreList; + UpdatedPrimitive->IgnoreActorWhenMoving(MovementBaseRootActor, false); + } } if (MovementBase->IsSimulatingPhysics() && CharacterOwner->GetMesh()) @@ -2315,6 +2340,27 @@ void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds) CharacterOwner->GetMesh()->ApplyDeltaToAllPhysicsTransforms(DeltaPosition, DeltaQuat); } } + + + // Check if falling above current base + if (IsFalling() && bStayBasedInAir) + { + FVector PawnLocation = UpdatedComponent->GetComponentLocation(); + if (VRRootCapsule) + PawnLocation = VRRootCapsule->OffsetComponentToWorld.GetLocation(); + + FFindFloorResult OutFloorResult; + ComputeFloorDist(PawnLocation, StayBasedInAirHeight, StayBasedInAirHeight, OutFloorResult, CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleRadius(), NULL); + + UPrimitiveComponent* HitComponent = OutFloorResult.HitResult.Component.Get(); + if (!HitComponent || HitComponent->GetAttachmentRoot() != MovementBase->GetAttachmentRoot()) + { + // New or no base under the character + ApplyImpartedMovementBaseVelocity(); + SetBase(NULL); + return; + } + } } FVector UVRCharacterMovementComponent::GetImpartedMovementBaseVelocity() const @@ -3119,6 +3165,9 @@ void UVRCharacterMovementComponent::PhysNavWalking(float deltaTime, int32 Iterat return; } + const EMovementMode StartingMovementMode = MovementMode; + const uint8 StartingCustomMovementMode = CustomMovementMode; + // Rewind the players position by the new capsule location RewindVRRelativeMovement(); @@ -3140,12 +3189,12 @@ void UVRCharacterMovementComponent::PhysNavWalking(float deltaTime, int32 Iterat ApplyRootMotionToVelocity(deltaTime); ApplyVRMotionToVelocity(deltaTime); - /*if (IsFalling()) + if (MovementMode != StartingMovementMode || CustomMovementMode != StartingCustomMovementMode) { - // Root motion could have put us into Falling + // Root motion could have taken us out of our current mode StartNewPhysics(deltaTime, Iterations); return; - }*/ + } Iterations++; @@ -4387,6 +4436,14 @@ void UVRCharacterMovementComponent::ServerMoveHandleClientErrorVR(float ClientTi bCanTrustClientOnLanding = false; } + // They have it private.... + // Check for lift-off, going from walking to falling. + // Note that if bStayBasedInAir is enabled we can't rely on the walking to falling transition, instead run logic on the first tick after clearing the MovementBase + //const bool bCanLiftOffFromBase = bStayBasedInAir + // ? !MovementBase && LastServerMovementBase.Get() // If we keep the base while in air, consider lift-off if base gets set to null and we had a base last tick + // : bLastServerIsWalking; // If walking last tick, we were can consider lift-off logic + //if (bServerIsFalling && bCanLiftOffFromBase && !bTeleportedSinceLastUpdate) + if (bServerIsFalling && bLastServerIsWalking && !bTeleportedSinceLastUpdate) { float ClientForwardFactor = 1.f; @@ -4686,6 +4743,9 @@ bool UVRCharacterMovementComponent::ClientUpdatePositionAfterServerUpdate() CharacterOwner->bClientUpdating = true; bForceNextFloorCheck = true; + // Scope these, they nest with Outer references so it should work fine, this keeps the update rotation and move autonomous from double updating the char + //const FScopedPreventAttachedComponentMove PreventMeshMove(BaseVRCharacterOwner ? BaseVRCharacterOwner->NetSmoother : nullptr); + // Store out our custom properties to restore after replaying const FVRMoveActionArray Orig_MoveActions = MoveActionArray; const FVector Orig_CustomInput = CustomVRInputVector; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRGestureComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRGestureComponent.cpp index ca3e61d..00be260 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRGestureComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRGestureComponent.cpp @@ -2,6 +2,8 @@ #include UE_INLINE_GENERATED_CPP_BY_NAME(VRGestureComponent) #include "VRBaseCharacter.h" +#include "Engine/Engine.h" +#include "Engine/World.h" #include "Components/SplineMeshComponent.h" #include "Components/SplineComponent.h" #include "Components/LineBatchComponent.h" @@ -22,7 +24,6 @@ UVRGestureComponent::UVRGestureComponent(const FObjectInitializer& ObjectInitial maxSlope = 3;// INT_MAX; //globalThreshold = 10.0f; SameSampleTolerance = 0.1f; - bGestureChanged = false; MirroringHand = EVRGestureMirrorMode::GES_NoMirror; bDrawSplinesCurved = true; bGetGestureInWorldSpace = true; @@ -124,14 +125,14 @@ void UGesturesDatabase::FillSplineWithGesture(FVRGesture &Gesture, USplineCompon } -void UVRGestureComponent::BeginRecording(bool bRunDetection, bool bFlattenGesture, bool bDrawGesture, bool bDrawAsSpline, int SamplingHTZ, int SampleBufferSize, float ClampingTolerance) +void UVRGestureComponent::BeginRecording(bool bRunDetection, EVRGestureFlattenAxis FlattenAxis, bool bDrawGesture, bool bDrawAsSpline, int SamplingHTZ, int SampleBufferSize, float ClampingTolerance) { RecordingBufferSize = SampleBufferSize; RecordingDelta = 1.0f / SamplingHTZ; RecordingClampingTolerance = ClampingTolerance; bDrawRecordingGesture = bDrawGesture; bDrawRecordingGestureAsSpline = bDrawAsSpline; - bRecordingFlattenGesture = bFlattenGesture; + RecordingFlattenAxis = FlattenAxis; GestureLog.GestureSize.Init(); // Reset does the reserve already @@ -221,8 +222,13 @@ void UVRGestureComponent::CaptureGestureFrame() if (CurrentState == EVRGestureState::GES_Recording) { - if (bRecordingFlattenGesture) - NewSample.X = 0; + switch (RecordingFlattenAxis) + { + case EVRGestureFlattenAxis::GES_FlattenX: {NewSample.X = 0.0; }break; + case EVRGestureFlattenAxis::GES_FlattenY: {NewSample.Y = 0.0; }break; + case EVRGestureFlattenAxis::GES_FlattenZ: {NewSample.Z = 0.0; }break; + default: {}break; + } if (RecordingClampingTolerance > 0.0f) { diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRPathFollowingComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRPathFollowingComponent.cpp index 25593ae..ffdc6df 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRPathFollowingComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRPathFollowingComponent.cpp @@ -3,6 +3,8 @@ #include "VRPathFollowingComponent.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(VRPathFollowingComponent) +#include "CoreMinimal.h" +#include "Engine/World.h" //#include "Runtime/Engine/Private/EnginePrivate.h" //#if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 13 @@ -254,8 +256,16 @@ void UVRPathFollowingComponent::UpdatePathSegment() { const FVector AgentLocation = DestinationAgent ? DestinationAgent->GetNavAgentLocation() : DestinationActor->GetActorLocation(); // note that the condition below requires GoalLocation to be in world space. - const FVector GoalLocation = FQuatRotationTranslationMatrix(DestinationActor->GetActorQuat(), AgentLocation).TransformPosition(MoveOffset); + FVector GoalLocation = FQuatRotationTranslationMatrix(DestinationActor->GetActorQuat(), AgentLocation).TransformPosition(MoveOffset); + if (bMoveToGoalClampedToNavigation && NavigationFilter) + { + FVector HitLocation; + if (MyNavData->Raycast(CurrentLocation, GoalLocation, HitLocation, NavigationFilter)) + { + GoalLocation = HitLocation; + } + } CurrentDestination.Set(NULL, GoalLocation); //UE_VLOG(this, LogPathFollowing, Log, TEXT("Moving directly to move goal rather than following last path segment")); @@ -361,6 +371,27 @@ bool UVRPathFollowingComponent::HasReachedCurrentTarget(const FVector& CurrentLo return false; } + // If the next segment is a link with a custom reach condition, we need to call the HasReachedLinkStart on the link interface. + if (bMoveSegmentIsUsingCustomLinkReachCondition) + { + if (const INavLinkCustomInterface* MoveSegmentCustomLink = Cast(MoveSegmentCustomLinkOb.Get())) + { + if (ensureMsgf(Path.IsValid(), TEXT("%hs: Path should be valid when we get here. Owner [%s]."), __FUNCTION__, *GetNameSafe(GetOwner()))) + { + const FNavPathPoint& LinkStart = Path->GetPathPoints()[MoveSegmentEndIndex]; + if (Path->GetPathPoints().IsValidIndex(MoveSegmentEndIndex + 1)) + { + const FNavPathPoint& LinkEnd = Path->GetPathPoints()[MoveSegmentEndIndex + 1]; + return MoveSegmentCustomLink->HasReachedLinkStart(this, CurrentLocation, LinkStart, LinkEnd); + } + else + { + UE_LOG(LogPathFollowing, Error, TEXT("%hs: NavLink has a start, but no end. Custom reach condition won't be called. NavLinkID [%llu] - LinkStartPos [%s] - Owner [%s]"), __FUNCTION__, LinkStart.CustomNavLinkId.GetId(), *LinkStart.Location.ToString(), *GetNameSafe(GetOwner())); + } + } + } + } + const FVector CurrentTarget = GetCurrentTargetLocation(); const FVector CurrentDirection = GetCurrentDirection(); diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRPlayerController.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRPlayerController.cpp index 39eebe0..94614cb 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRPlayerController.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRPlayerController.cpp @@ -27,24 +27,6 @@ void AVRPlayerController::SpawnPlayerCameraManager() PlayerCameraManager->bUseClientSideCameraUpdates = false; } -// #TODO 4.20: This was removed -/*void AVRPlayerController::InitNavigationControl(UPathFollowingComponent*& PathFollowingComp) -{ - PathFollowingComp = FindComponentByClass(); - if (PathFollowingComp == NULL) - { - PathFollowingComp = NewObject(this); - PathFollowingComp->RegisterComponentWithWorld(GetWorld()); - PathFollowingComp->Initialize(); - } -}*/ - -/*IPathFollowingAgentInterface* AVRPlayerController::GetPathFollowingAgent() const -{ - // Moved spawning the path following component into the path finding logic instead - return FNavigationSystem::FindPathFollowingAgentForActor(*this); -}*/ - void AVRPlayerController::PlayerTick(float DeltaTime) { diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRRootComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRRootComponent.cpp index f50a237..2da97a2 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRRootComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRRootComponent.cpp @@ -6,6 +6,8 @@ //#include "Runtime/Engine/Private/EnginePrivate.h" //#include "WorldCollision.h" #include "PhysicsPublic.h" +#include "Engine/World.h" +#include "Engine/Engine.h" #include "Engine/ScopedMovementUpdate.h" #include "SceneManagement.h" #include "PrimitiveSceneProxy.h" @@ -13,7 +15,9 @@ #include "IHeadMountedDisplay.h" #include "IXRTrackingSystem.h" #include "VRCharacter.h" +#include "Engine/OverlapResult.h" #include "Algo/Copy.h" +#include "AI/Navigation/NavigationRelevantData.h" #include "Components/PrimitiveComponent.h" @@ -310,6 +314,7 @@ UVRRootComponent::UVRRootComponent(const FObjectInitializer& ObjectInitializer) SetCanEverAffectNavigation(false); bDynamicObstacle = true; + LineThickness = 1.25f; //bOffsetByHMD = false; } @@ -333,6 +338,7 @@ public: , bSimulating(false) //, OffsetComponentToWorld(InComponent->OffsetComponentToWorld) , LocalToWorld(InComponent->OffsetComponentToWorld.ToMatrixWithScale()) + , LineThickness(InComponent->GetLineThickness()) { bWillEverBeLit = false; } @@ -357,14 +363,14 @@ public: // If in editor views, lets offset the capsule upwards so that it views correctly if (bSimulating) { - DrawWireCapsule(PDI, LocalToWorld.GetOrigin() - FVector(0.f, 0.f, CapsuleHalfHeight), LocalToWorld.GetUnitAxis(EAxis::X), LocalToWorld.GetUnitAxis(EAxis::Y), LocalToWorld.GetUnitAxis(EAxis::Z), DrawCapsuleColor, CapsuleRadius, CapsuleHalfHeight, CapsuleSides, SDPG_World); + DrawWireCapsule(PDI, LocalToWorld.GetOrigin() - FVector(0.f, 0.f, CapsuleHalfHeight), LocalToWorld.GetUnitAxis(EAxis::X), LocalToWorld.GetUnitAxis(EAxis::Y), LocalToWorld.GetUnitAxis(EAxis::Z), DrawCapsuleColor, CapsuleRadius, CapsuleHalfHeight, CapsuleSides, SDPG_World, LineThickness); } else if (UseEditorCompositing(View)) { - DrawWireCapsule(PDI, LocalToWorld.GetOrigin() /*+ FVector(0.f, 0.f, CapsuleHalfHeight)*/, LocalToWorld.GetUnitAxis(EAxis::X), LocalToWorld.GetUnitAxis(EAxis::Y), LocalToWorld.GetUnitAxis(EAxis::Z), DrawCapsuleColor, CapsuleRadius, CapsuleHalfHeight, CapsuleSides, SDPG_World, 1.25f); + DrawWireCapsule(PDI, LocalToWorld.GetOrigin() /*+ FVector(0.f, 0.f, CapsuleHalfHeight)*/, LocalToWorld.GetUnitAxis(EAxis::X), LocalToWorld.GetUnitAxis(EAxis::Y), LocalToWorld.GetUnitAxis(EAxis::Z), DrawCapsuleColor, CapsuleRadius, CapsuleHalfHeight, CapsuleSides, SDPG_World, LineThickness); } else - DrawWireCapsule(PDI, LocalToWorld.GetOrigin(), LocalToWorld.GetUnitAxis(EAxis::X), LocalToWorld.GetUnitAxis(EAxis::Y), LocalToWorld.GetUnitAxis(EAxis::Z), DrawCapsuleColor, CapsuleRadius, CapsuleHalfHeight, CapsuleSides, SDPG_World, 1.25f); + DrawWireCapsule(PDI, LocalToWorld.GetOrigin(), LocalToWorld.GetUnitAxis(EAxis::X), LocalToWorld.GetUnitAxis(EAxis::Y), LocalToWorld.GetUnitAxis(EAxis::Z), DrawCapsuleColor, CapsuleRadius, CapsuleHalfHeight, CapsuleSides, SDPG_World, LineThickness); } } } @@ -405,6 +411,7 @@ private: bool bSimulating = false; //FTransform OffsetComponentToWorld; FMatrix LocalToWorld; + const float LineThickness; }; FPrimitiveSceneProxy* UVRRootComponent::CreateSceneProxy() @@ -547,9 +554,10 @@ void UVRRootComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, if (bRetainRoomscale) { // Pre-Process this for network sends - curCameraLoc.X = FMath::RoundToFloat(curCameraLoc.X * 100.f) / 100.f; - curCameraLoc.Y = FMath::RoundToFloat(curCameraLoc.Y * 100.f) / 100.f; - curCameraLoc.Z = FMath::RoundToFloat(curCameraLoc.Z * 100.f) / 100.f; + UE::Net::QuantizeVector(100, curCameraLoc); + //curCameraLoc.X = FMath::RoundToFloat(curCameraLoc.X * 100.f) / 100.f; + //curCameraLoc.Y = FMath::RoundToFloat(curCameraLoc.Y * 100.f) / 100.f; + //curCameraLoc.Z = FMath::RoundToFloat(curCameraLoc.Z * 100.f) / 100.f; } @@ -622,9 +630,10 @@ void UVRRootComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, lastCameraRot = curCameraRot; //DifferenceFromLastFrame = (NextTransform.GetLocation() - LastPosition);// .GetSafeNormal2D(); - DifferenceFromLastFrame.X = FMath::RoundToFloat(DifferenceFromLastFrame.X * 100.f) / 100.f; - DifferenceFromLastFrame.Y = FMath::RoundToFloat(DifferenceFromLastFrame.Y * 100.f) / 100.f; - DifferenceFromLastFrame.Z = FMath::RoundToFloat(DifferenceFromLastFrame.Z * 100.f) / 100.f; + UE::Net::QuantizeVector(100, DifferenceFromLastFrame); + //DifferenceFromLastFrame.X = FMath::RoundToFloat(DifferenceFromLastFrame.X * 100.f) / 100.f; + //DifferenceFromLastFrame.Y = FMath::RoundToFloat(DifferenceFromLastFrame.Y * 100.f) / 100.f; + //DifferenceFromLastFrame.Z = FMath::RoundToFloat(DifferenceFromLastFrame.Z * 100.f) / 100.f; //DifferenceFromLastFrame.Z = 0.0f; // Reset Z to zero, its not used anyway and this lets me reuse the Z component for capsule half height } else @@ -648,9 +657,13 @@ void UVRRootComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, { // I'm limiting it to a -100 - 100 unit range in case people somehow skip tracking so far that this multiplication // Would overflow the max/min values of a float. It shouldn't ever be harmful as that is a loooot of travel in one tick - DifferenceFromLastFrame.X = FMath::RoundToFloat(FMath::Clamp(DifferenceFromLastFrame.X, -100.0f, 100.0f) * 10000.f) / 10000.f; - DifferenceFromLastFrame.Y = FMath::RoundToFloat(FMath::Clamp(DifferenceFromLastFrame.Y, -100.0f, 100.0f) * 10000.f) / 10000.f; - DifferenceFromLastFrame.Z = FMath::RoundToFloat(FMath::Clamp(DifferenceFromLastFrame.Z, -100.0f, 100.0f) * 10000.f) / 10000.f; + DifferenceFromLastFrame.X = FMath::Clamp(DifferenceFromLastFrame.X, -100.0f, 100.0f); + DifferenceFromLastFrame.Y = FMath::Clamp(DifferenceFromLastFrame.Y, -100.0f, 100.0f); + DifferenceFromLastFrame.Z = FMath::Clamp(DifferenceFromLastFrame.Z, -100.0f, 100.0f); + UE::Net::QuantizeVector(10000, DifferenceFromLastFrame); + //DifferenceFromLastFrame.X = FMath::RoundToFloat(FMath::Clamp(DifferenceFromLastFrame.X, -100.0f, 100.0f) * 10000.f) / 10000.f; + //DifferenceFromLastFrame.Y = FMath::RoundToFloat(FMath::Clamp(DifferenceFromLastFrame.Y, -100.0f, 100.0f) * 10000.f) / 10000.f; + //DifferenceFromLastFrame.Z = FMath::RoundToFloat(FMath::Clamp(DifferenceFromLastFrame.Z, -100.0f, 100.0f) * 10000.f) / 10000.f; //DifferenceFromLastFrame.Z = 0.0f; // Reset Z to zero, its not used anyway and this lets me reuse the Z component for capsule half height } } @@ -1060,7 +1073,7 @@ bool UVRRootComponent::MoveComponentImpl(const FVector& Delta, const FQuat& NewR if (TestHit.bBlockingHit) { - if (!ShouldIgnoreHitResult(MyWorld, bAllowSimulatingCollision, TestHit, Delta, Actor, MoveFlags)) + if (!ShouldIgnoreHitResult(MyWorld, bAllowSimulatingCollision, TestHit, Delta, Actor, MoveFlags) && !ShouldComponentIgnoreHitResult(TestHit, MoveFlags)) { if (TestHit.bStartPenetrating) { @@ -1136,8 +1149,7 @@ bool UVRRootComponent::MoveComponentImpl(const FVector& Delta, const FQuat& NewR // Remove any pending overlaps after this point, we are not going as far as we swept. if (FirstNonInitialOverlapIdx != INDEX_NONE) { - const bool bAllowShrinking = false; - PendingOverlaps.SetNum(FirstNonInitialOverlapIdx, bAllowShrinking); + PendingOverlaps.SetNum(FirstNonInitialOverlapIdx, EAllowShrinking::No); } } } @@ -1376,14 +1388,13 @@ bool UVRRootComponent::UpdateOverlapsImpl(const TOverlapArrayView* NewPendingOve for (int32 CompIdx = 0; CompIdx < OldOverlappingComponentPtrs.Num() && NewOverlappingComponentPtrs.Num() > 0; ++CompIdx) { // RemoveAtSwap is ok, since it is not necessary to maintain order - const bool bAllowShrinking = false; const FOverlapInfo* SearchItem = OldOverlappingComponentPtrs[CompIdx]; const int32 NewElementIdx = IndexOfOverlapFast(NewOverlappingComponentPtrs, SearchItem); if (NewElementIdx != INDEX_NONE) { - NewOverlappingComponentPtrs.RemoveAtSwap(NewElementIdx, 1, bAllowShrinking); - OldOverlappingComponentPtrs.RemoveAtSwap(CompIdx, 1, bAllowShrinking); + NewOverlappingComponentPtrs.RemoveAtSwap(NewElementIdx, 1, EAllowShrinking::No); + OldOverlappingComponentPtrs.RemoveAtSwap(CompIdx, 1, EAllowShrinking::No); --CompIdx; } } @@ -1413,7 +1424,7 @@ bool UVRRootComponent::UpdateOverlapsImpl(const TOverlapArrayView* NewPendingOve const int32 StaleElementIndex = IndexOfOverlapFast(OverlappingComponents, OtherOverlap); if (StaleElementIndex != INDEX_NONE) { - OverlappingComponents.RemoveAtSwap(StaleElementIndex, 1, bAllowShrinking); + OverlappingComponents.RemoveAtSwap(StaleElementIndex, 1, bAllowShrinking ? EAllowShrinking::Yes : EAllowShrinking::No); } } } @@ -1515,7 +1526,7 @@ bool UVRRootComponent::IsLocallyControlled() const { if (GetNetMode() < ENetMode::NM_Client) { - if (owningVRChar->VRReplicateCapsuleHeight) + if (owningVRChar->GetVRReplicateCapsuleHeight()) { owningVRChar->ReplicatedCapsuleHeight.CapsuleHeight = CapsuleHalfHeight; } @@ -1649,7 +1660,7 @@ bool UVRRootComponent::ConvertSweptOverlapsToCurrentOverlapsVR( // 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. return false; } - else if (Cast(OtherPrimitive) || Cast(this)) + else if (Cast(OtherPrimitive) /* || Cast(this)*/) { // SkeletalMeshComponent does not support this operation, and would return false in the test when an actual query could return true. return false; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRStereoWidgetComponent.cpp b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRStereoWidgetComponent.cpp index cbe63e9..6f03c91 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRStereoWidgetComponent.cpp +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Private/VRStereoWidgetComponent.cpp @@ -17,6 +17,7 @@ #include "IStereoLayers.h" #include "IHeadMountedDisplay.h" #include "PrimitiveViewRelevance.h" +#include "StereoLayerAdditionalFlagsManager.h" #include "PrimitiveSceneProxy.h" #include "UObject/ConstructorHelpers.h" #include "EngineGlobals.h" @@ -346,7 +347,6 @@ void UVRStereoWidgetRenderComponent::RenderWidget(float DeltaTime) const EPixelFormat requestedFormat = FSlateApplication::Get().GetRenderer()->GetSlateRecommendedColorFormat(); RenderTarget = NewObject(); check(RenderTarget); - RenderTarget->AddToRoot(); RenderTarget->ClearColor = RenderTargetClearColor; RenderTarget->TargetGamma = WidgetRenderGamma; RenderTarget->InitCustomFormat(TextureSize.X, TextureSize.Y, requestedFormat /*PF_B8G8R8A8*/, false); @@ -385,9 +385,9 @@ UVRStereoWidgetComponent::UVRStereoWidgetComponent(const FObjectInitializer& Obj //, StereoLayerType(SLT_TrackerLocked) //, StereoLayerShape(SLSH_QuadLayer) , Priority(0) + , LayerId(IStereoLayers::FLayerDesc::INVALID_LAYER_ID) , bIsDirty(true) , bTextureNeedsUpdate(false) - , LayerId(IStereoLayers::FLayerDesc::INVALID_LAYER_ID) , LastTransform(FTransform::Identity) , bLastVisible(false) { @@ -412,6 +412,16 @@ UVRStereoWidgetComponent::~UVRStereoWidgetComponent() { } + +void UVRStereoWidgetComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + if (EndPlayReason == EEndPlayReason::EndPlayInEditor || EndPlayReason == EEndPlayReason::Quit) + { + //FStereoLayerAdditionalFlagsManager::Destroy(); + } +} + + void UVRStereoWidgetComponent::BeginDestroy() { IStereoLayers* StereoLayers; @@ -716,6 +726,13 @@ void UVRStereoWidgetComponent::TickComponent(float DeltaTime, enum ELevelTick Ti LayerDsec.Flags |= (bSupportsDepth) ? IStereoLayers::LAYER_FLAG_SUPPORT_DEPTH : 0; LayerDsec.Flags |= (!bCurrVisible) ? IStereoLayers::LAYER_FLAG_HIDDEN : 0; + // Would love to implement but they aren't exporting the symbols + /*TSharedPtr FlagsManager = FStereoLayerAdditionalFlagsManager::Get(); + for (FName& Flag : AdditionalFlags) + { + LayerDsec.Flags |= FlagsManager->GetFlagValue(Flag); + }*/ + // Fix this later when WorldLocked is no longer wrong. switch (Space) { @@ -1094,7 +1111,7 @@ public: bShadowMapped = false; } - virtual void OnTransformChanged() override + virtual void OnTransformChanged(FRHICommandListBase& RHICmdList) override { Origin = GetLocalToWorld().GetOrigin(); } diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/GripMotionControllerComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/GripMotionControllerComponent.h index a6fb882..3fec2f2 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/GripMotionControllerComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/GripMotionControllerComponent.h @@ -316,6 +316,10 @@ public: ~UGripMotionControllerComponent(); + // TMP until physics velocity bug is fixed #TODO: Remove + void CalculateGripVelocity(FBPActorGripInformation &GripToFill, UPrimitiveComponent* ComponentToSample, float DeltaTime); + + // Custom version of the component sweep function to remove that aggravating warning epic is throwing about skeletal mesh components. void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override; virtual void InitializeComponent() override; @@ -494,10 +498,17 @@ public: UPROPERTY(BlueprintReadOnly, Replicated, Category = "GripMotionController", ReplicatedUsing = OnRep_GrippedObjects) TArray GrippedObjects; + // If modifying members in gripped objects directly or a specific grip you need to call this function if you are using Push Networking + void DIRTY_GRIPPED_OBJECTS(); + // When possible I suggest that you use GetAllGrips/GetGrippedObjects instead of directly referencing this UPROPERTY(BlueprintReadOnly, Replicated, Category = "GripMotionController", ReplicatedUsing = OnRep_LocallyGrippedObjects) TArray LocallyGrippedObjects; + // If modifying members in locally gripped objects directly or a specific grip you need to call this function if you are using Push Networking + void DIRTY_LOCALLY_GRIPPED_OBJECTS(); + + // Local Grip TransactionalBuffer to store server sided grips that need to be emplaced into the local buffer UPROPERTY(BlueprintReadOnly, Replicated, Category = "GripMotionController", ReplicatedUsing = OnRep_LocalTransaction) TArray LocalTransactionBuffer; @@ -766,37 +777,8 @@ public: return true; } - inline void CheckTransactionBuffer() - { - if (LocalTransactionBuffer.Num()) - { - for (int i = LocalTransactionBuffer.Num() - 1; i >= 0; --i) - { - if (LocalTransactionBuffer[i].ValueCache.bWasInitiallyRepped && LocalTransactionBuffer[i].GripID != LocalTransactionBuffer[i].ValueCache.CachedGripID) - { - // There appears to be a bug with TArray replication where if you replace an index with another value of that - // Index, it doesn't fully re-init the object, this is a workaround to re-zero non replicated variables - // when that happens. - LocalTransactionBuffer[i].ClearNonReppingItems(); - } - - if (!LocalTransactionBuffer[i].ValueCache.bWasInitiallyRepped && LocalTransactionBuffer[i].GrippedObject->IsValidLowLevelFast()) - { - LocalTransactionBuffer[i].ValueCache.bWasInitiallyRepped = true; - LocalTransactionBuffer[i].ValueCache.CachedGripID = LocalTransactionBuffer[i].GripID; - - int32 Index = LocallyGrippedObjects.Add(LocalTransactionBuffer[i]); - - if (Index != INDEX_NONE) - { - NotifyGrip(LocallyGrippedObjects[Index]); - } - - Server_NotifyHandledTransaction(LocalTransactionBuffer[i].GripID); - } - } - } - } + // Check the local transaction buffer + void CheckTransactionBuffer(); UFUNCTION() virtual void OnRep_LocalTransaction(TArray OriginalArrayState) // Original array state is useless without full serialize, it just hold last delta @@ -848,18 +830,29 @@ public: // Run the smoothing step void RunNetworkedSmoothing(float DeltaTime); +protected: + // Rate to update the position to the server, 100htz is default (same as replication rate, should also hit every tick). // On dedicated servers the update rate should be at or lower than the server tick rate for smoothing to work UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "GripMotionController|Networking", meta = (ClampMin = "0", UIMin = "0")) float ControllerNetUpdateRate; + +public: + void SetControllerNetUpdateRate(float NewControllerNetUpdateRate); + inline float GetControllerNetUpdateRate() { return ControllerNetUpdateRate; }; // 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 float ControllerNetUpdateCount; + protected: // Whether to smooth (lerp) between ticks for the replicated motion, DOES NOTHING if update rate is larger than FPS! UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "GripMotionController|Networking") bool bSmoothReplicatedMotion; + public: + void SetSmoothReplicatedMotion(bool NewSmoothReplicatedMotion); + inline bool GetSmoothReplicatedMotion() { return bSmoothReplicatedMotion; }; + // If true then we will use exponential smoothing with buffered correction UPROPERTY(EditAnywhere, Category = "GripMotionController|Networking|Smoothing", meta = (editcondition = "bSmoothReplicatedMotion")) bool bUseExponentialSmoothing = true; @@ -876,10 +869,16 @@ public: UPROPERTY(EditAnywhere, Category = "GripMotionController|Networking|Smoothing", meta = (editcondition = "bUseExponentialSmoothing")) float NetworkNoSmoothUpdateDistance = 100.f; + protected: + // Whether to replicate even if no tracking (FPS or test characters) UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "GripMotionController|Networking") bool bReplicateWithoutTracking; + public: + void SetReplicateWithoutTracking(bool NewReplicateWithoutTracking); + inline bool GetReplicateWithoutTracking() { return bReplicateWithoutTracking; }; + // I'm sending it unreliable because it is being resent pretty often UFUNCTION(Unreliable, Server, WithValidation) void Server_SendControllerTransform(FBPVRComponentPosRep NewTransform); diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/GripScripts/GS_Melee.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/GripScripts/GS_Melee.h index 151e1fe..8691b53 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/GripScripts/GS_Melee.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/GripScripts/GS_Melee.h @@ -181,11 +181,8 @@ public: virtual void OnLodgeHitCallback(AActor* SelfActor, AActor* OtherActor, FVector NormalImpulse, const FHitResult& Hit); UFUNCTION(BlueprintCallable, Category = "Weapon Settings") - void SetIsLodged(bool IsLodged, UPrimitiveComponent * LodgeComponent) - { - bIsLodged = IsLodged; - LodgedComponent = LodgeComponent; - } + void SetIsLodged(bool IsLodged, UPrimitiveComponent* LodgeComponent); + bool bIsLodged; TWeakObjectPtr LodgedComponent; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableActor.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableActor.h index 110e8ee..75df06f 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableActor.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableActor.h @@ -38,14 +38,22 @@ public: virtual void GatherCurrentMovement() override; +protected: UPROPERTY(EditAnywhere, Replicated, BlueprintReadOnly, Instanced, Category = "VRGripInterface") TArray> GripLogicScripts; // If true then the grip script array will be considered for replication, if false then it will not // This is an optimization for when you have a lot of grip scripts in use, you can toggle this off in cases // where the object will never have a replicating script - UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") + UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bReplicateGripScripts; +public: + + void SetReplicateGripScripts(bool NewReplicateGripScripts); + inline bool GetReplicateGripScripts() { return bReplicateGripScripts; }; + + // Get the grip script array, will automatically dirty it if they are replicated as it is assumed if you are directly accessing it you are altering it + TArray>& GetGripLogicScripts(); bool ReplicateSubobjects(UActorChannel* Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags) override; virtual void GetSubobjectsWithStableNamesForNetworking(TArray& ObjList) override; @@ -78,8 +86,16 @@ public: // Client Auth Throwing Data and functions // ------------------------------------------------ +protected: + // Replication settings for client auth throwing + // Must call MarkClientAuthReplicationDirty if setting the properties of it live UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "Replication") FVRClientAuthReplicationData ClientAuthReplicationData; +public: + + // If changing this in c++ it is using a getter to make sure it is dirtied + FVRClientAuthReplicationData& GetClientAuthReplicationData(FVRClientAuthReplicationData& ClientAuthData); + // Add this to client side physics replication (until coming to rest or timeout period is hit) UFUNCTION(BlueprintCallable, Category = "Networking") @@ -122,32 +138,31 @@ public: TagContainer = GameplayTags; } + protected: + /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") - FGameplayTagContainer GameplayTags; + FGameplayTagContainer GameplayTags; + + public: + FGameplayTagContainer& GetGameplayTags(); // End Gameplay Tag Interface virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override; + protected: + // Skips the attachment replication if we are locally owned and our grip settings say that we are a client authed grip. UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "Replication") bool bAllowIgnoringAttachOnOwner; + public: + + void SetAllowIgnoringAttachOnOwner(bool bNewAllowIgnoringAttachOnOwner); + inline bool GetAllowIgnoringAttachOnOwner() { return bAllowIgnoringAttachOnOwner; }; // Should we skip attachment replication (vr settings say we are a client auth grip and our owner is locally controlled) - inline bool ShouldWeSkipAttachmentReplication(bool bConsiderHeld = true) const - { - if ((bConsiderHeld && !VRGripInterfaceSettings.bWasHeld) || GetNetMode() < ENetMode::NM_Client) - return false; - - if (VRGripInterfaceSettings.MovementReplicationType == EGripMovementReplicationSettings::ClientSide_Authoritive || - VRGripInterfaceSettings.MovementReplicationType == EGripMovementReplicationSettings::ClientSide_Authoritive_NoRep) - { - return HasLocalNetOwner(); - } - else - return false; - } + /*inline*/ bool ShouldWeSkipAttachmentReplication(bool bConsiderHeld = true) const; // Handle fixing some bugs and issues with ReplicateMovement being off virtual void OnRep_AttachmentReplication() override; @@ -173,11 +188,21 @@ public: // On Destroy clean up our objects virtual void BeginDestroy() override; + protected: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bRepGripSettingsAndGameplayTags; + public: + void SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags); + inline bool GetRepGripSettingsAndGameplayTags() { return bRepGripSettingsAndGameplayTags; }; + + protected: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") FBPInterfaceProperties VRGripInterfaceSettings; + public: + + // Get VRGripInterfaceSettings, set MarkDirty if you intend to (or may) modify the values inside of it + FBPInterfaceProperties& GetVRGripInterfaceSettings(bool bMarkDirty); // Set up as deny instead of allow so that default allows for gripping // The GripInitiator is not guaranteed to be valid, check it for validity diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableBoxComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableBoxComponent.h index f1a94e5..1b7b3b6 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableBoxComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableBoxComponent.h @@ -31,6 +31,7 @@ public: virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; +protected: UPROPERTY(EditAnywhere, Replicated, BlueprintReadOnly, Instanced, Category = "VRGripInterface") TArray> GripLogicScripts; @@ -39,6 +40,13 @@ public: // where the object will never have a replicating script UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bReplicateGripScripts; +public: + + void SetReplicateGripScripts(bool NewReplicateGripScripts); + inline bool GetReplicateGripScripts() { return bReplicateGripScripts; }; + + // Get the grip script array, will automatically dirty it if they are replicated as it is assumed if you are directly accessing it you are altering it + TArray>& GetGripLogicScripts(); bool ReplicateSubobjects(UActorChannel* Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags) override; @@ -76,10 +84,14 @@ public: TagContainer = GameplayTags; } +protected: /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") FGameplayTagContainer GameplayTags; +public: + FGameplayTagContainer& GetGameplayTags(); + // End Gameplay Tag Interface virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override; @@ -94,6 +106,7 @@ public: // This one is for components to clean up virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override; +protected: // Requires bReplicates to be true for the component UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication") bool bRepGripSettingsAndGameplayTags; @@ -106,6 +119,16 @@ public: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") FBPInterfaceProperties VRGripInterfaceSettings; +public: + + void SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags); + inline bool GetRepGripSettingsAndGameplayTags() { return bRepGripSettingsAndGameplayTags; }; + + // Get VRGripInterfaceSettings, set MarkDirty if you intend to (or may) modify the values inside of it + FBPInterfaceProperties& GetVRGripInterfaceSettings(bool bMarkDirty); + + void SetReplicateMovement(bool bNewReplicateMovement); + inline bool GetReplicateMovement() { return bReplicateMovement; }; // Set up as deny instead of allow so that default allows for gripping // The GripInitiator is not guaranteed to be valid, check it for validity diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableCapsuleComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableCapsuleComponent.h index 573e324..b6b9969 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableCapsuleComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableCapsuleComponent.h @@ -31,6 +31,7 @@ public: virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; +protected: UPROPERTY(EditAnywhere, Replicated, BlueprintReadOnly, Instanced, Category = "VRGripInterface") TArray> GripLogicScripts; @@ -40,6 +41,14 @@ public: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bReplicateGripScripts; +public: + + void SetReplicateGripScripts(bool NewReplicateGripScripts); + inline bool GetReplicateGripScripts() { return bReplicateGripScripts; }; + + // Get the grip script array, will automatically dirty it if they are replicated as it is assumed if you are directly accessing it you are altering it + TArray>& GetGripLogicScripts(); + bool ReplicateSubobjects(UActorChannel* Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags) override; // Sets the Deny Gripping variable on the FBPInterfaceSettings struct @@ -75,9 +84,12 @@ public: TagContainer = GameplayTags; } +protected: /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") FGameplayTagContainer GameplayTags; +public: + FGameplayTagContainer& GetGameplayTags(); // End Gameplay Tag Interface @@ -92,6 +104,8 @@ public: // This one is for components to clean up virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override; +protected: + // Requires bReplicates to be true for the component UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication") bool bRepGripSettingsAndGameplayTags; @@ -105,6 +119,17 @@ public: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") FBPInterfaceProperties VRGripInterfaceSettings; +public: + + void SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags); + inline bool GetRepGripSettingsAndGameplayTags() { return bRepGripSettingsAndGameplayTags; }; + + // Get VRGripInterfaceSettings, set MarkDirty if you intend to (or may) modify the values inside of it + FBPInterfaceProperties& GetVRGripInterfaceSettings(bool bMarkDirty); + + void SetReplicateMovement(bool bNewReplicateMovement); + inline bool GetReplicateMovement() { return bReplicateMovement; }; + // Set up as deny instead of allow so that default allows for gripping // The GripInitiator is not guaranteed to be valid, check it for validity virtual bool DenyGripping_Implementation(UGripMotionControllerComponent * GripInitiator = nullptr) override; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippablePhysicsReplication.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippablePhysicsReplication.h index ba33b19..cfb8db2 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippablePhysicsReplication.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippablePhysicsReplication.h @@ -10,9 +10,9 @@ #include "PhysicsReplicationInterface.h" #include "Physics/PhysicsInterfaceDeclares.h" #include "PhysicsProxy/SingleParticlePhysicsProxyFwd.h" -#include "Chaos/Particles.h" #include "Chaos/PhysicsObject.h" #include "Chaos/SimCallbackObject.h" +#include "Physics/NetworkPhysicsSettingsComponent.h" #include "GrippablePhysicsReplication.generated.h" @@ -33,13 +33,18 @@ //struct FAsyncPhysicsRepCallbackDataVR; //class FPhysicsReplicationAsyncCallbackVR; +#pragma region FPhysicsReplicationAsync + class FPhysicsReplicationAsyncVR : public Chaos::TSimCallbackObject< FPhysicsReplicationAsyncInput, Chaos::FSimCallbackNoOutput, - Chaos::ESimCallbackOptions::Presimulate> + Chaos::ESimCallbackOptions::Presimulate | Chaos::ESimCallbackOptions::PhysicsObjectUnregister> { virtual FName GetFNameForStatId() const override; + virtual void OnPostInitialize_Internal() override; virtual void OnPreSimulate_Internal() override; + virtual void OnPhysicsObjectUnregistered_Internal(Chaos::FConstPhysicsObjectHandle PhysicsObject) override; + virtual void ApplyTargetStatesAsync(const float DeltaSeconds, const FPhysicsRepErrorCorrectionData& ErrorCorrection, const TArray& TargetStates); // Replication functions @@ -48,14 +53,25 @@ class FPhysicsReplicationAsyncVR : public Chaos::TSimCallbackObject< virtual bool PredictiveInterpolation(Chaos::FPBDRigidParticleHandle* Handle, FReplicatedPhysicsTargetAsync& Target, const float DeltaSeconds); virtual bool ResimulationReplication(Chaos::FPBDRigidParticleHandle* Handle, FReplicatedPhysicsTargetAsync& Target, const float DeltaSeconds); +public: + virtual void RegisterSettings(Chaos::FConstPhysicsObjectHandle PhysicsObject, FNetworkPhysicsSettingsAsync InSettings); + private: float LatencyOneWay; FRigidBodyErrorCorrection ErrorCorrectionDefault; - TMap ObjectToTarget; + FNetworkPhysicsSettingsAsync SettingsCurrent; + FNetworkPhysicsSettingsAsync SettingsDefault; + TMap ObjectToTarget; + TMap ObjectToSettings; + TArray ParticlesInResimIslands; private: - void UpdateAsyncTarget(const FPhysicsRepAsyncInputData& Input); + void UpdateAsyncTarget(const FPhysicsRepAsyncInputData& Input, Chaos::FPBDRigidsSolver* RigidsSolver); void UpdateRewindDataTarget(const FPhysicsRepAsyncInputData& Input); + void CacheResimInteractions(); + // Sets SettingsCurrent to either the objects custom settings or to the default settings + void FetchObjectSettings(Chaos::FConstPhysicsObjectHandle PhysicsObject); + static void ExtrapolateTarget(FReplicatedPhysicsTargetAsync& Target, const int32 ExtrapolateFrames, const float DeltaSeconds); public: void Setup(FRigidBodyErrorCorrection ErrorCorrection) @@ -64,7 +80,7 @@ public: } }; - +#pragma endregion // FPhysicsReplicationAsync class FPhysicsReplicationVR : public FPhysicsReplication { @@ -81,9 +97,11 @@ public: virtual bool ApplyRigidBodyState(float DeltaSeconds, FBodyInstance* BI, FReplicatedPhysicsTarget& PhysicsTarget, const FRigidBodyErrorCorrection& ErrorCorrection, const float PingSecondsOneWay, int32 LocalFrame, int32 NumPredictedFrames) override; virtual bool ApplyRigidBodyState(float DeltaSeconds, FBodyInstance* BI, FReplicatedPhysicsTarget& PhysicsTarget, const FRigidBodyErrorCorrection& ErrorCorrection, const float PingSecondsOneWay, bool* bDidHardSnap = nullptr) override; - virtual void SetReplicatedTarget(UPrimitiveComponent* Component, FName BoneName, const FRigidBodyState& ReplicatedTarget, int32 ServerFrame) override; - void SetReplicatedTargetVR(Chaos::FPhysicsObject* PhysicsObject, const FRigidBodyState& ReplicatedTarget, int32 ServerFrame, EPhysicsReplicationMode ReplicationMode); + void SetReplicatedTargetVR(Chaos::FConstPhysicsObjectHandle PhysicsObject, const FRigidBodyState& ReplicatedTarget, int32 ServerFrame, EPhysicsReplicationMode ReplicationMode = EPhysicsReplicationMode::Default); + + virtual void RemoveReplicatedTarget(UPrimitiveComponent* Component) override; + TArray ReplicatedTargetsQueueVR; FPhysicsReplicationAsyncVR* PhysicsReplicationAsyncVR; FPhysicsReplicationAsyncInput* AsyncInputVR; //async data being written into before we push into callback @@ -91,6 +109,7 @@ public: void PrepareAsyncData_ExternalVR(const FRigidBodyErrorCorrection& ErrorCorrection); //prepare async data for writing. Call on external thread (i.e. game thread) }; + class IPhysicsReplicationFactoryVR : public IPhysicsReplicationFactory { public: diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableSkeletalMeshActor.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableSkeletalMeshActor.h index d2fcd0e..85e87a6 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableSkeletalMeshActor.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableSkeletalMeshActor.h @@ -30,11 +30,13 @@ class VREXPANSIONPLUGIN_API UOptionalRepSkeletalMeshComponent : public USkeletal public: UOptionalRepSkeletalMeshComponent(const FObjectInitializer& ObjectInitializer); -public: - +protected: // Overrides the default of : true and allows for controlling it like in an actor, should be default of off normally with grippable components UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "Component Replication") bool bReplicateMovement; +public: + bool GetReplicateMovement() { return bReplicateMovement; } + void SetReplicateMovement(bool bNewReplicateMovement); virtual void PreReplication(IRepChangedPropertyTracker& ChangedPropertyTracker) override; @@ -64,6 +66,7 @@ public: virtual void GatherCurrentMovement() override; +protected: UPROPERTY(EditAnywhere, Replicated, BlueprintReadOnly, Instanced, Category = "VRGripInterface") TArray> GripLogicScripts; @@ -72,6 +75,13 @@ public: // where the object will never have a replicating script UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bReplicateGripScripts; +public: + + void SetReplicateGripScripts(bool NewReplicateGripScripts); + inline bool GetReplicateGripScripts() { return bReplicateGripScripts; }; + + // Get the grip script array, will automatically dirty it if they are replicated as it is assumed if you are directly accessing it you are altering it + TArray>& GetGripLogicScripts(); bool ReplicateSubobjects(UActorChannel* Channel, class FOutBunch* Bunch, FReplicationFlags* RepFlags) override; virtual void GetSubobjectsWithStableNamesForNetworking(TArray& ObjList) override; @@ -104,8 +114,12 @@ public: // Client Auth Throwing Data and functions // ------------------------------------------------ +protected: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "Replication") FVRClientAuthReplicationData ClientAuthReplicationData; +public: + // If changing this in c++ it is using a getter to make sure it is dirtied + FVRClientAuthReplicationData& GetClientAuthReplicationData(FVRClientAuthReplicationData& ClientAuthData); // Add this to client side physics replication (until coming to rest or timeout period is hit) UFUNCTION(BlueprintCallable, Category = "Networking") @@ -148,32 +162,31 @@ public: TagContainer = GameplayTags; } +protected: + /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") - FGameplayTagContainer GameplayTags; + FGameplayTagContainer GameplayTags; + +public: + FGameplayTagContainer& GetGameplayTags(); // End Gameplay Tag Interface virtual void PreReplication(IRepChangedPropertyTracker& ChangedPropertyTracker) override; +protected: // Skips the attachment replication if we are locally owned and our grip settings say that we are a client authed grip. UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "Replication") bool bAllowIgnoringAttachOnOwner; - // Should we skip attachment replication (vr settings say we are a client auth grip and our owner is locally controlled) - inline bool ShouldWeSkipAttachmentReplication(bool bConsiderHeld = true) const - { - if ((bConsiderHeld && !VRGripInterfaceSettings.bWasHeld) || GetNetMode() < ENetMode::NM_Client) - return false; +public: - if (VRGripInterfaceSettings.MovementReplicationType == EGripMovementReplicationSettings::ClientSide_Authoritive || - VRGripInterfaceSettings.MovementReplicationType == EGripMovementReplicationSettings::ClientSide_Authoritive_NoRep) - { - return HasLocalNetOwner(); - } - else - return false; - } + void SetAllowIgnoringAttachOnOwner(bool bNewAllowIgnoringAttachOnOwner); + inline bool GetAllowIgnoringAttachOnOwner() { return bAllowIgnoringAttachOnOwner; }; + + // Should we skip attachment replication (vr settings say we are a client auth grip and our owner is locally controlled) + /*inline*/ bool ShouldWeSkipAttachmentReplication(bool bConsiderHeld = true) const; // Fix bugs with replication and bReplicateMovement virtual void OnRep_AttachmentReplication() override; @@ -199,12 +212,22 @@ public: // On Destroy clean up our objects virtual void BeginDestroy() override; +protected: + UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bRepGripSettingsAndGameplayTags; UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") FBPInterfaceProperties VRGripInterfaceSettings; +public: + + void SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags); + inline bool GetRepGripSettingsAndGameplayTags() { return bRepGripSettingsAndGameplayTags; }; + + // Get VRGripInterfaceSettings, set MarkDirty if you intend to (or may) modify the values inside of it + FBPInterfaceProperties& GetVRGripInterfaceSettings(bool bMarkDirty); + // Set up as deny instead of allow so that default allows for gripping // The GripInitiator is not guaranteed to be valid, check it for validity virtual bool DenyGripping_Implementation(UGripMotionControllerComponent * GripInitiator = nullptr) override; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableSkeletalMeshComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableSkeletalMeshComponent.h index 19e861d..2aec546 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableSkeletalMeshComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableSkeletalMeshComponent.h @@ -35,6 +35,7 @@ public: virtual void GetWeldedBodies(TArray& OutWeldedBodies, TArray& OutLabels, bool bIncludingAutoWeld) override; virtual FBodyInstance* GetBodyInstance(FName BoneName = NAME_None, bool bGetWelded = true, int32 Index = INDEX_NONE) const override; +protected: UPROPERTY(EditAnywhere, Replicated, BlueprintReadOnly, Instanced, Category = "VRGripInterface") TArray> GripLogicScripts; @@ -43,6 +44,12 @@ public: // where the object will never have a replicating script UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bReplicateGripScripts; +public: + void SetReplicateGripScripts(bool NewReplicateGripScripts); + inline bool GetReplicateGripScripts() { return bReplicateGripScripts; }; + + // Get the grip script array, will automatically dirty it if they are replicated as it is assumed if you are directly accessing it you are altering it + TArray>& GetGripLogicScripts(); bool ReplicateSubobjects(UActorChannel* Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags) override; @@ -81,10 +88,15 @@ public: TagContainer = GameplayTags; } +protected: + /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") FGameplayTagContainer GameplayTags; +public: + FGameplayTagContainer& GetGameplayTags(); + // End Gameplay Tag Interface virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override; @@ -98,6 +110,7 @@ public: // This one is for components to clean up virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override; +protected: // Requires bReplicates to be true for the component UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication") bool bRepGripSettingsAndGameplayTags; @@ -110,6 +123,16 @@ public: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") FBPInterfaceProperties VRGripInterfaceSettings; +public: + + void SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags); + inline bool GetRepGripSettingsAndGameplayTags() { return bRepGripSettingsAndGameplayTags; }; + + // Get VRGripInterfaceSettings, set MarkDirty if you intend to (or may) modify the values inside of it + FBPInterfaceProperties& GetVRGripInterfaceSettings(bool bMarkDirty); + + void SetReplicateMovement(bool bNewReplicateMovement); + inline bool GetReplicateMovement() { return bReplicateMovement; }; // Set up as deny instead of allow so that default allows for gripping // The GripInitiator is not guaranteed to be valid, check it for validity diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableSphereComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableSphereComponent.h index 81fd861..ec5058b 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableSphereComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableSphereComponent.h @@ -31,6 +31,7 @@ public: virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; +protected: UPROPERTY(EditAnywhere, Replicated, BlueprintReadOnly, Instanced, Category = "VRGripInterface") TArray> GripLogicScripts; @@ -39,6 +40,13 @@ public: // where the object will never have a replicating script UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bReplicateGripScripts; +public: + + void SetReplicateGripScripts(bool NewReplicateGripScripts); + inline bool GetReplicateGripScripts() { return bReplicateGripScripts; }; + + // Get the grip script array, will automatically dirty it if they are replicated as it is assumed if you are directly accessing it you are altering it + TArray>& GetGripLogicScripts(); bool ReplicateSubobjects(UActorChannel* Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags) override; @@ -77,9 +85,12 @@ public: TagContainer = GameplayTags; } +protected: /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") FGameplayTagContainer GameplayTags; +public: + FGameplayTagContainer& GetGameplayTags(); // End Gameplay Tag Interface @@ -94,6 +105,7 @@ public: // This one is for components to clean up virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override; +protected: // Requires bReplicates to be true for the component UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication") bool bRepGripSettingsAndGameplayTags; @@ -106,6 +118,16 @@ public: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") FBPInterfaceProperties VRGripInterfaceSettings; +public: + + void SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags); + inline bool GetRepGripSettingsAndGameplayTags() { return bRepGripSettingsAndGameplayTags; }; + + // Get VRGripInterfaceSettings, set MarkDirty if you intend to (or may) modify the values inside of it + FBPInterfaceProperties& GetVRGripInterfaceSettings(bool bMarkDirty); + + void SetReplicateMovement(bool bNewReplicateMovement); + inline bool GetReplicateMovement() { return bReplicateMovement; }; // Set up as deny instead of allow so that default allows for gripping // The GripInitiator is not guaranteed to be valid, check it for validity diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableStaticMeshActor.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableStaticMeshActor.h index 36c3a1c..986c521 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableStaticMeshActor.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableStaticMeshActor.h @@ -60,6 +60,8 @@ public: virtual void GatherCurrentMovement() override; +protected: + UPROPERTY(EditAnywhere, Replicated, BlueprintReadOnly, Instanced, Category = "VRGripInterface") TArray> GripLogicScripts; @@ -69,6 +71,14 @@ public: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bReplicateGripScripts; +public: + + void SetReplicateGripScripts(bool NewReplicateGripScripts); + inline bool GetReplicateGripScripts() { return bReplicateGripScripts; }; + + // Get the grip script array, will automatically dirty it if they are replicated as it is assumed if you are directly accessing it you are altering it + TArray>& GetGripLogicScripts(); + bool ReplicateSubobjects(UActorChannel* Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags) override; virtual void GetSubobjectsWithStableNamesForNetworking(TArray& ObjList) override; @@ -101,9 +111,15 @@ public: // Client Auth Throwing Data and functions // ------------------------------------------------ +protected: + UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "Replication") FVRClientAuthReplicationData ClientAuthReplicationData; +public: + // If changing this in c++ it is using a getter to make sure it is dirtied + FVRClientAuthReplicationData& GetClientAuthReplicationData(FVRClientAuthReplicationData& ClientAuthData); + // Add this to client side physics replication (until coming to rest or timeout period is hit) UFUNCTION(BlueprintCallable, Category = "Networking") bool AddToClientReplicationBucket(); @@ -147,32 +163,29 @@ public: TagContainer = GameplayTags; } +protected: + /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") FGameplayTagContainer GameplayTags; +public: + FGameplayTagContainer& GetGameplayTags(); // End Gameplay Tag Interface virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override; +protected: // Skips the attachment replication if we are locally owned and our grip settings say that we are a client authed grip. UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "Replication") bool bAllowIgnoringAttachOnOwner; - // Should we skip attachment replication (vr settings say we are a client auth grip and our owner is locally controlled) - inline bool ShouldWeSkipAttachmentReplication(bool bConsiderHeld = true) const - { - if((bConsiderHeld && !VRGripInterfaceSettings.bWasHeld) || GetNetMode() < ENetMode::NM_Client) - return false; +public: + void SetAllowIgnoringAttachOnOwner(bool bNewAllowIgnoringAttachOnOwner); + inline bool GetAllowIgnoringAttachOnOwner() { return bAllowIgnoringAttachOnOwner; }; - if (VRGripInterfaceSettings.MovementReplicationType == EGripMovementReplicationSettings::ClientSide_Authoritive || - VRGripInterfaceSettings.MovementReplicationType == EGripMovementReplicationSettings::ClientSide_Authoritive_NoRep) - { - return HasLocalNetOwner(); - } - else - return false; - } + // Should we skip attachment replication (vr settings say we are a client auth grip and our owner is locally controlled) + /*inline*/ bool ShouldWeSkipAttachmentReplication(bool bConsiderHeld = true) const; // Fix bugs with replication and bReplicateMovement virtual void OnRep_AttachmentReplication() override; @@ -198,12 +211,22 @@ public: // On Destroy clean up our objects virtual void BeginDestroy() override; +protected: + UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bRepGripSettingsAndGameplayTags; UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") FBPInterfaceProperties VRGripInterfaceSettings; +public: + + void SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags); + inline bool GetRepGripSettingsAndGameplayTags() { return bRepGripSettingsAndGameplayTags; }; + + // Get VRGripInterfaceSettings, set MarkDirty if you intend to (or may) modify the values inside of it + FBPInterfaceProperties& GetVRGripInterfaceSettings(bool bMarkDirty); + // Set up as deny instead of allow so that default allows for gripping // The GripInitiator is not guaranteed to be valid, check it for validity virtual bool DenyGripping_Implementation(UGripMotionControllerComponent * GripInitiator = nullptr) override; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableStaticMeshComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableStaticMeshComponent.h index a16ea6d..900433e 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableStaticMeshComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/GrippableStaticMeshComponent.h @@ -35,6 +35,8 @@ public: // Gameplay tag interface // ------------------------------------------------ +protected: + /** Overridden to return requirements tags */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadOnly, Instanced, Category = "VRGripInterface") TArray> GripLogicScripts; @@ -45,6 +47,13 @@ public: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bReplicateGripScripts; +public: + void SetReplicateGripScripts(bool NewReplicateGripScripts); + inline bool GetReplicateGripScripts() { return bReplicateGripScripts; }; + + // Get the grip script array, will automatically dirty it if they are replicated as it is assumed if you are directly accessing it you are altering it + TArray>& GetGripLogicScripts(); + bool ReplicateSubobjects(UActorChannel* Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags) override; // Sets the Deny Gripping variable on the FBPInterfaceSettings struct @@ -76,10 +85,15 @@ public: TagContainer = GameplayTags; } +protected: + /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") FGameplayTagContainer GameplayTags; +public: + FGameplayTagContainer& GetGameplayTags(); + // End Gameplay Tag Interface virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override; @@ -93,6 +107,7 @@ public: // This one is for components to clean up virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override; +protected: // Requires bReplicates to be true for the component UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication") bool bRepGripSettingsAndGameplayTags; @@ -106,6 +121,16 @@ public: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") FBPInterfaceProperties VRGripInterfaceSettings; +public: + void SetRepGripSettingsAndGameplayTags(bool bNewRepGripSettingsAndGameplayTags); + inline bool GetRepGripSettingsAndGameplayTags() { return bRepGripSettingsAndGameplayTags; }; + + // Get VRGripInterfaceSettings, set MarkDirty if you intend to (or may) modify the values inside of it + FBPInterfaceProperties& GetVRGripInterfaceSettings(bool bMarkDirty); + + void SetReplicateMovement(bool bNewReplicateMovement); + inline bool GetReplicateMovement() { return bReplicateMovement; }; + // Set up as deny instead of allow so that default allows for gripping // The GripInitiator is not guaranteed to be valid, check it for validity virtual bool DenyGripping_Implementation(UGripMotionControllerComponent * GripInitiator = nullptr) override; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/HandSocketComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/HandSocketComponent.h index e539d08..6073e9c 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/HandSocketComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/HandSocketComponent.h @@ -7,7 +7,9 @@ #include "GameplayTagAssetInterface.h" #include "Components/SceneComponent.h" #include "Animation/AnimInstance.h" +#include "Animation/BoneReference.h" #include "Misc/Guid.h" + #include "HandSocketComponent.generated.h" class USkeletalMeshComponent; @@ -409,6 +411,8 @@ public: TagContainer = GameplayTags; } + protected: + /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") FGameplayTagContainer GameplayTags; @@ -423,6 +427,14 @@ public: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication") bool bReplicateMovement; + public: + FGameplayTagContainer& GetGameplayTags(); + + void SetRepGameplayTags(bool NewRepGameplayTags); + inline bool GetRepGameplayTags() { return bRepGameplayTags; }; + void SetReplicateMovement(bool NewReplicateMovement); + inline bool GetReplicateMovement() { return bReplicateMovement; }; + /** mesh component to indicate hand placement */ #if WITH_EDITORONLY_DATA @@ -468,10 +480,5 @@ public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, transient, Category = "Socket Data") TObjectPtr OwningSocket; - virtual void NativeInitializeAnimation() override - { - Super::NativeInitializeAnimation(); - - OwningSocket = Cast(GetOwningComponent()->GetAttachParent()); - } + virtual void NativeInitializeAnimation() override; }; \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRButtonComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRButtonComponent.h index 5b06704..e462761 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRButtonComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRButtonComponent.h @@ -111,6 +111,7 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRButtonComponent") bool bIsEnabled; +protected: // Current state of the button, writable to set initial value UPROPERTY(EditAnywhere,BlueprintReadWrite, Replicated, Category = "VRButtonComponent") bool bButtonState; @@ -118,6 +119,11 @@ public: // Who is allowed to change the button state UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "VRButtonComponent|Replication") EVRStateChangeAuthorityType StateChangeAuthorityType; +public: + bool GetButtonState() { return bButtonState; } + void SetButtonState(bool bNewButtonState); + EVRStateChangeAuthorityType GetStateChangeAuthorityType() { return StateChangeAuthorityType; } + void SetStateChangeAuthorityType(EVRStateChangeAuthorityType NewStateChangeAuthorityType); // Speed that the button de-presses when no longer interacted with UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRButtonComponent") @@ -155,18 +161,26 @@ public: virtual FVector GetTargetRelativeLocation(); + protected: // Overrides the default of : true and allows for controlling it like in an actor, should be default of off normally with grippable components UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication") bool bReplicateMovement; + public: + bool GetReplicateMovement() { return bReplicateMovement; } + void SetReplicateMovement(bool bNewReplicateMovement); virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override; // Resetting the initial transform here so that it comes in prior to BeginPlay and save loading. virtual void OnRegister() override; + protected: // Now replicating this so that it works correctly over the network UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_InitialRelativeTransform, Category = "VRButtonComponent") FTransform_NetQuantize InitialRelativeTransform; + public: + // Gets the initial relative transform, if you want to set it you should be using ResetInitialButtonLocation + FTransform GetInitialRelativeTransform() { return InitialRelativeTransform; } UFUNCTION() virtual void OnRep_InitialRelativeTransform() diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRDialComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRDialComponent.h index 8c510bb..a5e4d7f 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRDialComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRDialComponent.h @@ -120,9 +120,13 @@ public: // Resetting the initial transform here so that it comes in prior to BeginPlay and save loading. virtual void OnRegister() override; +protected: // Now replicating this so that it works correctly over the network UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_InitialRelativeTransform, Category = "VRDialComponent") - FTransform_NetQuantize InitialRelativeTransform; + FTransform_NetQuantize InitialRelativeTransform; +public: + // Gets the initial relative transform, if you want to set it you should be using ResetInitialButtonLocation + FTransform GetInitialRelativeTransform() { return InitialRelativeTransform; } UFUNCTION() virtual void OnRep_InitialRelativeTransform() @@ -161,15 +165,12 @@ public: TagContainer = GameplayTags; } +protected: /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") FGameplayTagContainer GameplayTags; - // End Gameplay Tag Interface - virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override; - - // Requires bReplicates to be true for the component UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bRepGameplayTags; @@ -177,7 +178,14 @@ public: // Overrides the default of : true and allows for controlling it like in an actor, should be default of off normally with grippable components UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication") bool bReplicateMovement; +public: + FGameplayTagContainer& GetGameplayTags(); + bool GetRepGameplayTags() { return bRepGameplayTags; } + void SetRepGameplayTags(bool bNewRepGameplayTags); + bool GetReplicateMovement() { return bReplicateMovement; } + void SetReplicateMovement(bool bNewReplicateMovement); + virtual void PreReplication(IRepChangedPropertyTracker& ChangedPropertyTracker) override; virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override; virtual void BeginPlay() override; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRLeverComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRLeverComponent.h index 54e457b..991dd6e 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRLeverComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRLeverComponent.h @@ -193,9 +193,13 @@ public: // Resetting the initial transform here so that it comes in prior to BeginPlay and save loading. virtual void OnRegister() override; +protected: // Now replicating this so that it works correctly over the network UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_InitialRelativeTransform, Category = "VRLeverComponent") FTransform_NetQuantize InitialRelativeTransform; +public: + // Gets the initial relative transform, if you want to set it you should be using ResetInitialButtonLocation + FTransform GetInitialRelativeTransform() { return InitialRelativeTransform; } UFUNCTION() virtual void OnRep_InitialRelativeTransform() @@ -234,15 +238,12 @@ public: TagContainer = GameplayTags; } +protected: /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") FGameplayTagContainer GameplayTags; - // End Gameplay Tag Interface - virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override; - - // Requires bReplicates to be true for the component UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bRepGameplayTags; @@ -250,7 +251,14 @@ public: // Overrides the default of : true and allows for controlling it like in an actor, should be default of off normally with grippable components UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication") bool bReplicateMovement; +public: + FGameplayTagContainer& GetGameplayTags(); + bool GetRepGameplayTags() { return bRepGameplayTags; } + void SetRepGameplayTags(bool bNewRepGameplayTags); + bool GetReplicateMovement() { return bReplicateMovement; } + void SetReplicateMovement(bool bNewReplicateMovement); + virtual void PreReplication(IRepChangedPropertyTracker& ChangedPropertyTracker) override; virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override; virtual void BeginPlay() override; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRMountComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRMountComponent.h index 5655040..97d2a78 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRMountComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRMountComponent.h @@ -94,15 +94,12 @@ public: TagContainer = GameplayTags; } +protected: /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") FGameplayTagContainer GameplayTags; - // End Gameplay Tag Interface - virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override; - - // Requires bReplicates to be true for the component UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bRepGameplayTags; @@ -110,7 +107,14 @@ public: // Overrides the default of : true and allows for controlling it like in an actor, should be default of off normally with grippable components UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication") bool bReplicateMovement; +public: + FGameplayTagContainer& GetGameplayTags(); + bool GetRepGameplayTags() { return bRepGameplayTags; } + void SetRepGameplayTags(bool bNewRepGameplayTags); + bool GetReplicateMovement() { return bReplicateMovement; } + void SetReplicateMovement(bool bNewReplicateMovement); + virtual void PreReplication(IRepChangedPropertyTracker& ChangedPropertyTracker) override; virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override; virtual void BeginPlay() override; @@ -146,11 +150,7 @@ public: // Should be called after the Mount is moved post begin play UFUNCTION(BlueprintCallable, Category = "VRMountComponent") - void ResetInitialMountLocation() - { - // Get our initial relative transform to our parent (or not if un-parented). - InitialRelativeTransform = this->GetRelativeTransform(); - } + void ResetInitialMountLocation(); virtual void OnUnregister() override;; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRSliderComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRSliderComponent.h index a28bba9..61d5c0b 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRSliderComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Interactibles/VRSliderComponent.h @@ -147,9 +147,13 @@ public: UFUNCTION(BlueprintCallable, Category = "GripSettings") void SetGripPriority(int NewGripPriority); +protected: // Set this to assign a spline component to the slider UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Replicated/*Using = OnRep_SplineComponentToFollow*/, Category = "VRSliderComponent") TObjectPtr SplineComponentToFollow; +public: + // Gets the initial relative transform, if you want to set it you should be using ResetInitialButtonLocation + TObjectPtr GetSplineComponentToFollow() { return SplineComponentToFollow; } /*UFUNCTION() virtual void OnRep_SplineComponentToFollow() @@ -198,9 +202,13 @@ public: // Resetting the initial transform here so that it comes in prior to BeginPlay and save loading. virtual void OnRegister() override; +protected: // Now replicating this so that it works correctly over the network UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_InitialRelativeTransform, Category = "VRSliderComponent") FTransform_NetQuantize InitialRelativeTransform; +public: + // Gets the initial relative transform, if you want to set it you should be using ResetInitialButtonLocation + FTransform GetInitialRelativeTransform() { return InitialRelativeTransform; } UFUNCTION() virtual void OnRep_InitialRelativeTransform() @@ -261,15 +269,13 @@ public: TagContainer = GameplayTags; } +protected: + /** Tags that are set on this object */ UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags") FGameplayTagContainer GameplayTags; - // End Gameplay Tag Interface - virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override; - - // Requires bReplicates to be true for the component UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface") bool bRepGameplayTags; @@ -277,7 +283,14 @@ public: // Overrides the default of : true and allows for controlling it like in an actor, should be default of off normally with grippable components UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication") bool bReplicateMovement; +public: + FGameplayTagContainer& GetGameplayTags(); + bool GetRepGameplayTags() { return bRepGameplayTags; } + void SetRepGameplayTags(bool bNewRepGameplayTags); + bool GetReplicateMovement() { return bReplicateMovement; } + void SetReplicateMovement(bool bNewReplicateMovement); + virtual void PreReplication(IRepChangedPropertyTracker& ChangedPropertyTracker) override; virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override; virtual void BeginPlay() override; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/CollisionIgnoreSubsystem.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/CollisionIgnoreSubsystem.h index 8ffce65..d9d9c60 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/CollisionIgnoreSubsystem.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/CollisionIgnoreSubsystem.h @@ -216,15 +216,7 @@ public: Super::Initialize(Collection); } - virtual void Deinitialize() override - { - Super::Deinitialize(); - - if (UpdateHandle.IsValid()) - { - GetWorld()->GetTimerManager().ClearTimer(UpdateHandle); - } - } + virtual void Deinitialize() override; UPROPERTY() TMap CollisionTrackedPairs; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/OptionalRepSkeletalMeshActor.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/OptionalRepSkeletalMeshActor.h index 0067180..6204dfb 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/OptionalRepSkeletalMeshActor.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/OptionalRepSkeletalMeshActor.h @@ -20,8 +20,12 @@ class VREXPANSIONPLUGIN_API UNoRepSphereComponent : public USphereComponent public: UNoRepSphereComponent(const FObjectInitializer& ObjectInitializer); +protected: UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "Component Replication") bool bReplicateMovement; +public: + bool GetReplicateMovement() { return bReplicateMovement; } + void SetReplicateMovement(bool bNewReplicateMovement); virtual void PreReplication(IRepChangedPropertyTracker& ChangedPropertyTracker) override; }; @@ -63,11 +67,14 @@ class VREXPANSIONPLUGIN_API UInversePhysicsSkeletalMeshComponent : public USkele public: UInversePhysicsSkeletalMeshComponent(const FObjectInitializer& ObjectInitializer); -public: - +protected: // Overrides the default of : true and allows for controlling it like in an actor, should be default of off normally with grippable components UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "Component Replication") bool bReplicateMovement; +public: + bool GetReplicateMovement() { return bReplicateMovement; } + void SetReplicateMovement(bool bNewReplicateMovement); + // This is all overrides to fix the skeletal mesh inverse simulation bug // WILL BE REMOVED LATER when the engine is fixed diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VRAIPerceptionOverrides.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VRAIPerceptionOverrides.h index 7b23c6c..1006aef 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VRAIPerceptionOverrides.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VRAIPerceptionOverrides.h @@ -377,6 +377,8 @@ protected: void RemoveAllQueriesByListener(const FPerceptionListener& Listener, const TFunction& OnRemoveFunc = nullptr); void RemoveAllQueriesToTarget(const FAISightTargetVR::FTargetId& TargetId, const TFunction& OnRemoveFunc = nullptr); + /** RemoveAllQueriesToTarget version that need to already have a write access on QueriesListAccessDetector*/ + void RemoveAllQueriesToTarget_Internal(const FAISightTargetVR::FTargetId& TargetId, const TFunction& OnRemoveFunc = nullptr); /** returns information whether new LoS queries have been added */ bool RegisterTarget(AActor& TargetActor, const TFunction& OnAddedFunc = nullptr); diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VREPhysicalAnimationComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VREPhysicalAnimationComponent.h index 2254c44..0600c4b 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VREPhysicalAnimationComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VREPhysicalAnimationComponent.h @@ -5,8 +5,8 @@ //#include "UObject/ObjectMacros.h" #include "Components/ActorComponent.h" #include "EngineDefines.h" -#if ENABLE_DRAW_DEBUG -#include "Chaos/DebugDrawQueue.h" +#if UE_ENABLE_DEBUG_DRAWING +//#include "Chaos/DebugDrawQueue.h" #endif #include "VREPhysicalAnimationComponent.generated.h" @@ -89,11 +89,11 @@ public: /** If true then we will debug draw the mesh collision post shape alterations */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = WeldedBoneDriver) - bool bDebugDrawCollision = false; + //UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = WeldedBoneDriver) + //bool bDebugDrawCollision = false; -#if ENABLE_DRAW_DEBUG - void DebugDrawMesh(const TArray& DrawCommands); +#if UE_ENABLE_DEBUG_DRAWING + //void DebugDrawMesh(const TArray& DrawCommands); #endif FTransform GetWorldSpaceRefBoneTransform(FReferenceSkeleton& RefSkel, int32 BoneIndex, int32 ParentBoneIndex); diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VRLogComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VRLogComponent.h index b57100a..c3e04c3 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VRLogComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VRLogComponent.h @@ -3,6 +3,7 @@ #pragma once #include "CoreMinimal.h" +#include "Components/ActorComponent.h" #include "Engine/Canvas.h" #include "Engine/TextureRenderTarget2D.h" #include "Engine/Console.h" diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VRRenderTargetManager.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VRRenderTargetManager.h index 27ff397..696817e 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VRRenderTargetManager.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Misc/VRRenderTargetManager.h @@ -1,5 +1,8 @@ #pragma once #include "TimerManager.h" +#include "GameFramework/Actor.h" +#include "Components/ActorComponent.h" +#include "Containers/Queue.h" #include "VRRenderTargetManager.generated.h" class UVRRenderTargetManager; @@ -8,6 +11,8 @@ class UCanvas; class UTexture2D; class UMaterial; class APlayerController; +class FRenderCommandFence; +enum EPixelFormat : uint8; // #TODO: Dirty rects so don't have to send entire texture? @@ -183,7 +188,7 @@ public: UPROPERTY(Replicated) uint32 OwnersID; - + UFUNCTION() void OnRep_Manager(); @@ -214,14 +219,7 @@ public: UPROPERTY() int32 MaxBytesPerSecondRate; - virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override - { - if(SendTimer_Handle.IsValid()) - GetWorld()->GetTimerManager().ClearTimer(SendTimer_Handle); - - Super::EndPlay(EndPlayReason); - } - + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; UFUNCTION(Reliable, Server, WithValidation) void SendLocalDrawOperations(const TArray& LocalRenderOperationStoreList); diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Mover/VRMoverComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Mover/VRMoverComponent.h new file mode 100644 index 0000000..687b613 --- /dev/null +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Mover/VRMoverComponent.h @@ -0,0 +1,154 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once +#include "CoreMinimal.h" +#include "MoverComponent.h" +#include "MoverTypes.h" +#include "GameFramework/Pawn.h" +#include "LayeredMove.h" +#include "VRMoverComponent.generated.h" + +class UCurveVector; +class UCurveFloat; + +DECLARE_LOG_CATEGORY_EXTERN(LogVRMoverComponent, Log, All); + +/** Linear Velocity: A method of inducing a straight-line velocity on an actor over time */ +USTRUCT(BlueprintType) +struct VREXPANSIONPLUGIN_API FLayeredMove_VRMovement : public FLayeredMoveBase +{ + GENERATED_USTRUCT_BODY() + + FLayeredMove_VRMovement(); + + virtual ~FLayeredMove_VRMovement() {} + + // Units per second, could be worldspace vs relative depending on Flags + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Mover) + FVector Velocity; + + // Optional curve float for controlling the magnitude of the velocity applied to the actor over the duration of the move + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Mover) + TObjectPtr MagnitudeOverTime; + + // @see ELayeredMove_ConstantVelocitySettingsFlags + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Mover) + uint8 SettingsFlags; + + // Never finish this movement + virtual bool IsFinished(float CurrentSimTimeMs) const; + + // Generate a movement + virtual bool GenerateMove(const FMoverTickStartData& StartState, const FMoverTimeStep& TimeStep, const UMoverComponent* MoverComp, UMoverBlackboard* SimBlackboard, FProposedMove& OutProposedMove) override; + + virtual FLayeredMoveBase* Clone() const override; + + virtual void NetSerialize(FArchive& Ar) override; + + virtual UScriptStruct* GetScriptStruct() const override; + + virtual FString ToSimpleString() const override; + + virtual void AddReferencedObjects(class FReferenceCollector& Collector) override; +}; + +template<> +struct TStructOpsTypeTraits< FLayeredMove_VRMovement > : public TStructOpsTypeTraitsBase2< FLayeredMove_VRMovement > +{ + enum + { + //WithNetSerializer = true, + WithCopy = true + }; +}; + +// Data block containing basic sync state information +USTRUCT(BlueprintType) +struct VREXPANSIONPLUGIN_API FVRMoverHMDSyncState : public FMoverDataStructBase +{ + GENERATED_USTRUCT_BODY() + +public: + // Movement intent direction relative to MovementBase if set, world space otherwise. Magnitude of range (0-1) + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Mover) + FVector MoveDirectionIntent; + +public: + + FVRMoverHMDSyncState() + { + // In constructor list when the actual var is made + MoveDirectionIntent = FVector::ZeroVector; + } + + virtual ~FVRMoverHMDSyncState() {} + + // @return newly allocated copy of this FMoverDefaultSyncState. Must be overridden by child classes + virtual FMoverDataStructBase* Clone() const override; + + virtual bool NetSerialize(FArchive& Ar, UPackageMap* Map, bool& bOutSuccess) override; + + virtual UScriptStruct* GetScriptStruct() const override { return StaticStruct(); } + + // Need implemented (if needed) + virtual bool ShouldReconcile(const FMoverDataStructBase& AuthorityState) const override + { + return false; + } + + // Needs implemented (should we even do this?) + virtual void Interpolate(const FMoverDataStructBase& From, const FMoverDataStructBase& To, float Pct) override + { + return; + } + + +}; + +template<> +struct TStructOpsTypeTraits< FVRMoverHMDSyncState > : public TStructOpsTypeTraitsBase2< FVRMoverHMDSyncState > +{ + enum + { + WithNetSerializer = true, + WithCopy = true + }; +}; + + + +UCLASS() +class VREXPANSIONPLUGIN_API AVRMoverBasePawn : public APawn, public IMoverInputProducerInterface +{ + GENERATED_BODY() + +public: + // Sets default values for this pawn's properties + AVRMoverBasePawn(const FObjectInitializer& ObjectInitializer); + + /** Accessor for the actor's movement component */ + UFUNCTION(BlueprintPure, Category = Mover) + UMoverComponent* GetMoverComponent() const { return CharacterMotionComponent; } + + virtual void BeginPlay() override; + +protected: + + virtual UPrimitiveComponent* GetMovementBase() const override; + + // Entry point for input production. Do not override. To extend in derived character types, override OnProduceInput for native types or implement "Produce Input" blueprint event + virtual void ProduceInput_Implementation(int32 SimTimeMs, FMoverInputCmdContext& InputCmdResult) override; + + // Override this function in native class to author input for the next simulation frame. Consider also calling Super method. + virtual void OnProduceInput(float DeltaMs, FMoverInputCmdContext& InputCmdResult); + + // Implement this event in Blueprints to author input for the next simulation frame. Consider also calling Parent event. + UFUNCTION(BlueprintImplementableEvent, DisplayName = "On Produce Input", meta = (ScriptName = "OnProduceInput")) + FMoverInputCmdContext OnProduceInputInBlueprint(float DeltaMs, FMoverInputCmdContext InputCmd); + +protected: + UPROPERTY(Category = Movement, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) + TObjectPtr CharacterMotionComponent; + + uint8 bHasProduceInputinBpFunc : 1; +}; \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/ReplicatedVRCameraComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/ReplicatedVRCameraComponent.h index 3b060c8..74e657d 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/ReplicatedVRCameraComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/ReplicatedVRCameraComponent.h @@ -106,6 +106,11 @@ public: UPROPERTY(EditDefaultsOnly, ReplicatedUsing = OnRep_ReplicatedCameraTransform, Category = "ReplicatedCamera|Networking") FBPVRComponentPosRep ReplicatedCameraTransform; + // Returns the actual tracked transform of the HMD, as with RetainRoomscale = False we do not set the camera to it + // Can also just use the HMD function library but this is a fast way if you already have a camera reference + UFUNCTION(BlueprintPure, Category = "ReplicatedCamera|Tracking") + FTransform GetHMDTrackingTransform(); + FVector LastUpdatesRelativePosition = FVector::ZeroVector; FRotator LastUpdatesRelativeRotation = FRotator::ZeroRotator; @@ -115,9 +120,10 @@ public: // Run the smoothing step void RunNetworkedSmoothing(float DeltaTime); + // Whether to smooth (lerp) between ticks for the replicated motion, DOES NOTHING if update rate is larger than FPS! - UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "ReplicatedCamera|Networking") - bool bSmoothReplicatedMotion; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ReplicatedCamera|Networking") + bool bSmoothReplicatedMotion = true; // If true then we will use exponential smoothing with buffered correction UPROPERTY(EditAnywhere, Category = "ReplicatedCamera|Networking|Smoothing", meta = (editcondition = "bSmoothReplicatedMotion")) @@ -138,14 +144,19 @@ public: UFUNCTION() virtual void OnRep_ReplicatedCameraTransform(); +protected: // Rate to update the position to the server, 100htz is default (same as replication rate, should also hit every tick). // On dedicated servers the update rate should be at or lower than the server tick rate for smoothing to work UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "ReplicatedCamera|Networking") float NetUpdateRate; +public: // Used in Tick() to accumulate before sending updates, didn't want to use a timer in this case. float NetUpdateCount; + float GetNetUpdateRate() { return NetUpdateRate; } + void SetNetUpdateRate(float NewNetUpdateRate); + // I'm sending it unreliable because it is being resent pretty often UFUNCTION(Unreliable, Server, WithValidation) void Server_SendCameraTransform(FBPVRComponentPosRep NewTransform); @@ -155,14 +166,7 @@ public: VRBaseCharTransformRPC_Pointer OverrideSendTransform; // Need this as I can't think of another way for an actor component to make sure it isn't on the server - inline bool IsLocallyControlled() const - { - // I like epics new authority check more than my own - const AActor* MyOwner = GetOwner(); - return MyOwner->HasLocalNetOwner(); - //const APawn* MyPawn = Cast(MyOwner); - //return MyPawn ? MyPawn->IsLocallyControlled() : false;// (MyOwner->Role == ENetRole::ROLE_Authority); - } + bool IsLocallyControlled() const; //bool IsServer(); }; \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRBPDatatypes.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRBPDatatypes.h index bebebce..5196519 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRBPDatatypes.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRBPDatatypes.h @@ -14,6 +14,7 @@ class UGripMotionControllerComponent; class UVRGripScriptBase; +class UPrimitiveComponent; // Custom movement modes for the characters UENUM(BlueprintType) @@ -186,9 +187,9 @@ public: if (!bFirstTime) { // This is unsafe in non float / float array data types, but I am not going to be using any like that - for (int i = 0; i < sizeof(filterType)/sizeof(float); i++) + for (int i = 0; i < sizeof(filterType) / sizeof(double); i++) { - ((float*)&Result)[i] = ((float*)&InAlpha)[i] * ((float*)&InValue)[i] + (1.0f - ((float*)&InAlpha)[i]) * ((float*)&Previous)[i]; + ((double*)&Result)[i] = ((double*)&InAlpha)[i] * ((double*)&InValue)[i] + (1.0f - ((double*)&InAlpha)[i]) * ((double*)&Previous)[i]; } } @@ -209,15 +210,15 @@ public: /** If this is the first time doing a filter */ bool bFirstTime; -//private: + //private: - const filterType CalculateCutoff(const filterType& InValue, float& MinCutoff, float& CutoffSlope) + const filterType CalculateCutoff(const filterType& InValue, double& MinCutoff, double& CutoffSlope) { filterType Result; // This is unsafe in non float / float array data types, but I am not going to be using any like that - for (int i = 0; i < sizeof(filterType)/sizeof(float); i++) + for (int i = 0; i < sizeof(filterType) / sizeof(double); i++) { - ((float*)&Result)[i] = MinCutoff + CutoffSlope * FMath::Abs(((float*)&InValue)[i]); + ((double*)&Result)[i] = MinCutoff + CutoffSlope * FMath::Abs(((double*)&InValue)[i]); } return Result; } @@ -226,17 +227,17 @@ public: { filterType Result; // This is unsafe in non float / float array data types, but I am not going to be using any like that - for (int i = 0; i < sizeof(filterType)/sizeof(float); i++) + for (int i = 0; i < sizeof(filterType) / sizeof(double); i++) { - ((float*)&Result)[i] = CalculateAlphaTau(((float*)&InCutoff)[i], InDeltaTime); + ((double*)&Result)[i] = CalculateAlphaTau(((double*)&InCutoff)[i], InDeltaTime); } return Result; } - inline const float CalculateAlphaTau(const float InCutoff, const double InDeltaTime) + inline const double CalculateAlphaTau(const double InCutoff, const double InDeltaTime) { - const float tau = 1.0 / (2.0f * PI * InCutoff); - return 1.0f / (1.0f + tau / InDeltaTime); + const double tau = 1.0 / (2.0 * PI * InCutoff); + return 1.0 / (1.0 + tau / InDeltaTime); } }; @@ -254,14 +255,14 @@ public: /** Default constructor */ FBPEuroLowPassFilter() : - MinCutoff(0.9f), - DeltaCutoff(1.0f), - CutoffSlope(0.007f), + MinCutoff(0.9), + DeltaCutoff(1.0), + CutoffSlope(0.007), RawFilter(FVector::ZeroVector), DeltaFilter(FVector::ZeroVector) {} - FBPEuroLowPassFilter(const float InMinCutoff, const float InCutoffSlope, const float InDeltaCutoff) : + FBPEuroLowPassFilter(const double InMinCutoff, const double InCutoffSlope, const double InDeltaCutoff) : MinCutoff(InMinCutoff), DeltaCutoff(InDeltaCutoff), CutoffSlope(InCutoffSlope), @@ -271,21 +272,21 @@ public: // The smaller the value the less jitter and the more lag with micro movements UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FilterSettings") - float MinCutoff; + double MinCutoff; // If latency is too high with fast movements increase this value UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FilterSettings") - float DeltaCutoff; + double DeltaCutoff; // This is the magnitude of adjustment UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FilterSettings") - float CutoffSlope; + double CutoffSlope; void ResetSmoothingFilter(); /** Smooth vector */ - FVector RunFilterSmoothing(const FVector &InRawValue, const float &InDeltaTime); + FVector RunFilterSmoothing(const FVector& InRawValue, const float& InDeltaTime); private: @@ -308,14 +309,14 @@ public: /** Default constructor */ FBPEuroLowPassFilterQuat() : - MinCutoff(0.9f), - DeltaCutoff(1.0f), - CutoffSlope(0.007f), + MinCutoff(0.9), + DeltaCutoff(1.0), + CutoffSlope(0.007), RawFilter(FQuat::Identity), DeltaFilter(FQuat::Identity) {} - FBPEuroLowPassFilterQuat(const float InMinCutoff, const float InCutoffSlope, const float InDeltaCutoff) : + FBPEuroLowPassFilterQuat(const double InMinCutoff, const double InCutoffSlope, const double InDeltaCutoff) : MinCutoff(InMinCutoff), DeltaCutoff(InDeltaCutoff), CutoffSlope(InCutoffSlope), @@ -325,15 +326,15 @@ public: // The smaller the value the less jitter and the more lag with micro movements UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FilterSettings") - float MinCutoff; + double MinCutoff; // If latency is too high with fast movements increase this value UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FilterSettings") - float DeltaCutoff; + double DeltaCutoff; // This is the magnitude of adjustment UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FilterSettings") - float CutoffSlope; + double CutoffSlope; void ResetSmoothingFilter(); @@ -361,14 +362,14 @@ public: /** Default constructor */ FBPEuroLowPassFilterTrans() : - MinCutoff(0.1f), - DeltaCutoff(10.0f), - CutoffSlope(10.0f), + MinCutoff(0.1), + DeltaCutoff(10.0), + CutoffSlope(10.0), RawFilter(FTransform::Identity), DeltaFilter(FTransform::Identity) {} - FBPEuroLowPassFilterTrans(const float InMinCutoff, const float InCutoffSlope, const float InDeltaCutoff) : + FBPEuroLowPassFilterTrans(const double InMinCutoff, const double InCutoffSlope, const double InDeltaCutoff) : MinCutoff(InMinCutoff), DeltaCutoff(InDeltaCutoff), CutoffSlope(InCutoffSlope), @@ -378,15 +379,15 @@ public: // The smaller the value the less jitter and the more lag with micro movements UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FilterSettings") - float MinCutoff; + double MinCutoff; // If latency is too high with fast movements increase this value UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FilterSettings") - float DeltaCutoff; + double DeltaCutoff; // This is the magnitude of adjustment UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FilterSettings") - float CutoffSlope; + double CutoffSlope; void ResetSmoothingFilter(); @@ -1467,6 +1468,13 @@ public: float LerpSpeed; FTransform OnGripTransform; + ///////////////////// + // TMP: Velocity calculation addition for 5.4 #TODO: Remove this when the bug is fixed + FVector LinVel = FVector::ZeroVector; + FVector RotVel = FVector::ZeroVector; + FTransform LastVelWorldTrans; // Identity by default + /////////////////////// + UPROPERTY(BlueprintReadWrite, NotReplicated, Category = "Settings") bool bIsLerping; @@ -1550,15 +1558,9 @@ public: } - FORCEINLINE AActor * GetGrippedActor() const - { - return Cast(GrippedObject); - } + AActor* GetGrippedActor() const; - FORCEINLINE UPrimitiveComponent * GetGrippedComponent() const - { - return Cast(GrippedObject); - } + UPrimitiveComponent* GetGrippedComponent() const; //Check if a grip is the same as another, the only things I check for are the actor / component //This is here for the Find() function from TArray @@ -1580,13 +1582,7 @@ public: return false; } - FORCEINLINE bool operator==(const UPrimitiveComponent * Other) const - { - if (Other && GrippedObject && GrippedObject == (const UObject*)Other) - return true; - - return false; - } + bool operator==(const UPrimitiveComponent* Other) const; FORCEINLINE bool operator==(const UObject * Other) const { @@ -1868,11 +1864,11 @@ public: bEnableVelocityDrive = ConstraintDrive.bEnableVelocityDrive; } - void FillTo(FConstraintDrive& ConstraintDrive) const + void FillTo(FConstraintDrive& ConstraintDrive, float DampingScaler = 1.0f, float StiffnessScaler = 1.0f) const { - ConstraintDrive.Damping = Damping; - ConstraintDrive.Stiffness = Stiffness; - ConstraintDrive.MaxForce = MaxForceCoefficient * Stiffness; + ConstraintDrive.Damping = Damping * DampingScaler; + ConstraintDrive.Stiffness = Stiffness * StiffnessScaler; + ConstraintDrive.MaxForce = (float)FMath::Clamp((double)ConstraintDrive.Stiffness * (double)MaxForceCoefficient, 0, (double)MAX_FLT); ConstraintDrive.bEnablePositionDrive = bEnablePositionDrive; ConstraintDrive.bEnableVelocityDrive = bEnableVelocityDrive; } @@ -1929,27 +1925,5 @@ public: return true; } - bool FillTo(FBPActorPhysicsHandleInformation* HandleInfo) const - { - if (!HandleInfo) - return false; - - XAxisSettings.FillTo(HandleInfo->LinConstraint.XDrive); - YAxisSettings.FillTo(HandleInfo->LinConstraint.YDrive); - ZAxisSettings.FillTo(HandleInfo->LinConstraint.ZDrive); - - if ((SlerpSettings.bEnablePositionDrive || SlerpSettings.bEnableVelocityDrive)) - { - HandleInfo->AngConstraint.AngularDriveMode = EAngularDriveMode::SLERP; - SlerpSettings.FillTo(HandleInfo->AngConstraint.SlerpDrive); - } - else - { - HandleInfo->AngConstraint.AngularDriveMode = EAngularDriveMode::TwistAndSwing; - TwistSettings.FillTo(HandleInfo->AngConstraint.TwistDrive); - SwingSettings.FillTo(HandleInfo->AngConstraint.SwingDrive); - } - - return true; - } + bool FillTo(FBPActorPhysicsHandleInformation* HandleInfo, bool bModifyWithScalers = true) const; }; \ No newline at end of file diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRBaseCharacter.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRBaseCharacter.h index 51d1850..7764226 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRBaseCharacter.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRBaseCharacter.h @@ -13,6 +13,7 @@ class AVRPlayerController; class UGripMotionControllerComponent; class UParentRelativeAttachmentComponent; class AController; +class UNavigationQueryFilter; DECLARE_LOG_CATEGORY_EXTERN(LogBaseVRCharacter, Log, All); @@ -280,7 +281,7 @@ public: // If true then we will retain roomscale tracking in relative space of the character. // If false than the movement component will offset to the hmd tracking and the tracking will be nulled out UPROPERTY(Category = VRBaseCharacter, EditAnywhere, BlueprintReadOnly) - bool bRetainRoomscale = true; + bool bRetainRoomscale = false; //virtual void CacheInitialMeshOffset(FVector MeshRelativeLocation, FRotator MeshRelativeRotation) override; virtual void PostInitializeComponents() override; @@ -330,9 +331,14 @@ public: virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override; +protected: // If true will replicate the capsule height on to clients, allows for dynamic capsule height changes in multiplayer UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRBaseCharacter") bool VRReplicateCapsuleHeight; +public: + bool GetVRReplicateCapsuleHeight() { return VRReplicateCapsuleHeight; } + void SetVRReplicateCapsuleHeight(bool bNewVRReplicateCapsuleHeight); + // OnlyReplicated to simulated clients UPROPERTY(Replicated, ReplicatedUsing = OnRep_CapsuleHeight) diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRCharacter.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRCharacter.h index fa1e317..80e1217 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRCharacter.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRCharacter.h @@ -25,6 +25,10 @@ public: virtual FVector GetTargetHeightOffset() override; + virtual void OnStartCrouch(float HalfHeightAdjust, float ScaledHalfHeightAdjust) override; + virtual void OnEndCrouch(float HalfHeightAdjust, float ScaledHalfHeightAdjust) override; + + // Regenerates the base offsetcomponenttoworld that VR uses virtual void RegenerateOffsetComponentToWorld(bool bUpdateBounds, bool bCalculatePureYaw) override; virtual void SetCharacterSizeVR(float NewRadius, float NewHalfHeight, bool bUpdateOverlaps = true) override; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRGestureComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRGestureComponent.h index 1618cc8..0634221 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRGestureComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRGestureComponent.h @@ -6,6 +6,7 @@ //#include "Engine/Engine.h" #include "VRBPDatatypes.h" #include "Engine/DataAsset.h" +#include "Components\SceneComponent.h" //#include "Engine/EngineTypes.h" //#include "Engine/EngineBaseTypes.h" @@ -37,6 +38,15 @@ enum class EVRGestureMirrorMode : uint8 GES_MirrorBoth }; +UENUM(Blueprintable) +enum class EVRGestureFlattenAxis : uint8 +{ + GES_FlattenX, + GES_FlattenY, + GES_FlattenZ, + GES_DontFlatten +}; + USTRUCT(BlueprintType, Category = "VRGestures") struct VREXPANSIONPLUGIN_API FVRGestureSettings { @@ -94,7 +104,7 @@ public: uint8 GestureType; // Samples in the recorded gesture - UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "VRGesture") + UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "VRGesture") TArray Samples; UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "VRGesture") @@ -279,11 +289,11 @@ public: // Number of samples to keep in memory during detection int RecordingBufferSize; - float RecordingClampingTolerance; - bool bRecordingFlattenGesture; - bool bDrawRecordingGesture; - bool bDrawRecordingGestureAsSpline; - bool bGestureChanged; + float RecordingClampingTolerance = 0.0f; + EVRGestureFlattenAxis RecordingFlattenAxis = EVRGestureFlattenAxis::GES_DontFlatten; + bool bDrawRecordingGesture = false; + bool bDrawRecordingGestureAsSpline = false; + bool bGestureChanged = false; // Handle to our update timer FTimerHandle TickGestureTimer_Handle; @@ -309,7 +319,7 @@ public: return FVector::DistSquared(Seq1, Seq2); } - void BeginDestroy() override; + virtual void BeginDestroy() override; // Recalculates a gestures size and re-scales it to the given database UFUNCTION(BlueprintCallable, Category = "VRGestures") @@ -335,7 +345,7 @@ public: * ClampingTolerance: If larger than 0.0, we will clamp points to a grid of this size */ UFUNCTION(BlueprintCallable, Category = "VRGestures") - void BeginRecording(bool bRunDetection, bool bFlattenGesture = true, bool bDrawGesture = true, bool bDrawAsSpline = false, int SamplingHTZ = 30, int SampleBufferSize = 60, float ClampingTolerance = 0.01f); + void BeginRecording(bool bRunDetection, EVRGestureFlattenAxis FlattenAxis = EVRGestureFlattenAxis::GES_FlattenX, bool bDrawGesture = true, bool bDrawAsSpline = false, int SamplingHTZ = 30, int SampleBufferSize = 60, float ClampingTolerance = 0.01f); // Ends recording and returns the recorded gesture UFUNCTION(BlueprintCallable, Category = "VRGestures") diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRRootComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRRootComponent.h index fd18e20..08ac90f 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRRootComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRRootComponent.h @@ -230,6 +230,9 @@ public: return bInsideVolume; } + // Expose this + inline float GetLineThickness() const {return LineThickness;} + public: // Begin UObject interface #if WITH_EDITOR diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRStereoWidgetComponent.h b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRStereoWidgetComponent.h index 92f871f..9fddf36 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRStereoWidgetComponent.h +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/Public/VRStereoWidgetComponent.h @@ -117,6 +117,7 @@ public: TObjectPtr Shape; void BeginDestroy() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; void OnUnregister() override; virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override; virtual void DrawWidgetToRenderTarget(float DeltaTime) override; @@ -176,6 +177,10 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "StereoLayer") uint32 bQuadPreserveTextureRatio : 1; + /** Additional flags not included in IStereoLayers::ELayerFlags */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "StereoLayer", Meta = (GetOptions = "EditorFlagCollector.GetFlagNames")) + TArray AdditionalFlags; + protected: /** Texture displayed on the stereo layer (is stereocopic textures are supported on the platfrom and more than one texture is provided, this will be the right eye) **/ //UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "StereoLayer") @@ -220,6 +225,9 @@ public: UPROPERTY(EditAnywhere, BlueprintReadOnly, export, Category = "StereoLayer") int32 Priority; + /** IStereoLayer id, 0 is unassigned **/ + uint32 LayerId; + bool bShouldCreateProxy; private: @@ -230,9 +238,6 @@ private: /** Texture needs to be marked for update **/ bool bTextureNeedsUpdate; - /** IStereoLayer id, 0 is unassigned **/ - uint32 LayerId; - /** Last transform is cached to determine if the new frames transform has changed **/ FTransform LastTransform; diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/VRExpansionPlugin.Build.cs b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/VRExpansionPlugin.Build.cs index c4976b7..f065a80 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/VRExpansionPlugin.Build.cs +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/Source/VRExpansionPlugin/VRExpansionPlugin.Build.cs @@ -59,23 +59,15 @@ public class VRExpansionPlugin : ModuleRules "NetCore", "CoreUObject", "Engine", - // "InputCore", "PhysicsCore", - //"FLEX", remove comment if building in the NVIDIA flex branch - NOTE when put in place FLEX only listed win32 and win64 at compatible platforms "HeadMountedDisplay", - // "RHI", - //"RenderCore", - //"ShaderCore", - //"NetworkReplayStreaming", - //"AIModule", "UMG", "NavigationSystem", "AIModule", "AnimGraphRuntime", "XRBase", - "GameplayTags" - //"Renderer", - //"UtilityShaders" + "GameplayTags", + "Mover" }); //if(Target.bUseChaos) @@ -114,20 +106,6 @@ public class VRExpansionPlugin : ModuleRules } ); - // Don't load APEX on incompatible platforms - /* if ( - Target.Platform != UnrealTargetPlatform.IOS && - Target.Platform != UnrealTargetPlatform.TVOS && - Target.Platform != UnrealTargetPlatform.Android && - Target.Platform != UnrealTargetPlatform.HTML5) - { - PublicDependencyModuleNames.AddRange( - new string[] - { - "APEX" - }); - }*/ - // Allow gameplay debugger on editor builds if (Target.bBuildDeveloperTools || (Target.Configuration != UnrealTargetConfiguration.Shipping && Target.Configuration != UnrealTargetConfiguration.Test)) { diff --git a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/VRExpansionPlugin.uplugin b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/VRExpansionPlugin.uplugin index 2e4de32..cb68065 100644 --- a/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/VRExpansionPlugin.uplugin +++ b/VIRTUOS_ExpansionPluginTests/Plugins/VRExpansionPlugin/VRExpansionPlugin/VRExpansionPlugin.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, - "Version": 5.3, - "VersionName": "5.3", + "Version": 5.4, + "VersionName": "5.4", "FriendlyName": "VRExpansionPlugin", "Description": "Adds several new VR features & components to UE4", "Category": "VRExpansion", @@ -33,7 +33,7 @@ "LoadingPhase": "PostEngineInit" } ], - "Plugins": [ + "Plugins": [ { "Name": "ChaosVehiclesPlugin", "Enabled": true @@ -41,6 +41,10 @@ { "Name": "XRBase", "Enabled": true + }, + { + "Name": "Mover", + "Enabled": true } - ] + ] } \ No newline at end of file