diff --git a/Config/DefaultRWTHVRToolkit.ini b/Config/DefaultRWTHVRToolkit.ini index 13066ebe26e8ab454486f97bbb982275d9b2587c..50643d31a5dd9100fd5e107efa705fae6d70c639 100644 --- a/Config/DefaultRWTHVRToolkit.ini +++ b/Config/DefaultRWTHVRToolkit.ini @@ -18,4 +18,10 @@ +FunctionRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.OnBeginGrab",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.OnBeginInteraction") +FunctionRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.OnEndGrab",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.OnEndInteraction") +PropertyRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.PreviousGrabBehavioursInRange",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.PreviousInteractableComponentsInRange") -+PropertyRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.CurrentGrabBehavioursInRange",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.CurrentInteractableComponentsInRange") \ No newline at end of file ++PropertyRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.CurrentGrabBehavioursInRange",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.CurrentInteractableComponentsInRange") ++FunctionRedirects=(OldName="/Script/RWTHVRToolkit.UBaseInteractionComponent.OnBeginInteraction",NewName="/Script/RWTHVRToolkit.UBaseInteractionComponent.OnBeginInteractionInputAction") ++FunctionRedirects=(OldName="/Script/RWTHVRToolkit.UBaseInteractionComponent.OnEndInteraction",NewName="/Script/RWTHVRToolkit.UBaseInteractionComponent.OnEndInteractionInputAction") ++FunctionRedirects=(OldName="/Script/RWTHVRToolkit.UBaseInteractionComponent.MulticastHoverBehaviourStartRpc",NewName="/Script/RWTHVRToolkit.UBaseInteractionComponent.MulticastHoverBehaviourReplicationStartRpc") ++FunctionRedirects=(OldName="/Script/RWTHVRToolkit.UBaseInteractionComponent.MulticastActionBehaviourStartRpc",NewName="/Script/RWTHVRToolkit.UBaseInteractionComponent.MulticastActionBehaviourReplicationStartRpc") ++FunctionRedirects=(OldName="/Script/RWTHVRToolkit.ActionBehaviour.OnActionStart",NewName="/Script/RWTHVRToolkit.ActionBehaviour.OnActionEvent") ++PropertyRedirects=(OldName="/Script/RWTHVRToolkit.ActionBehaviour.OnActionBeginEvent",NewName="/Script/RWTHVRToolkit.ActionBehaviour.OnActionEventEvent") \ No newline at end of file diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/ActionBehaviour.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/ActionBehaviour.cpp index 4e9c3fd662dd3baa2a30fddd8f516022e4efa9ba..ff1d027208025476ce073a15bd224ca5c9ccb9f0 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactables/ActionBehaviour.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/ActionBehaviour.cpp @@ -6,27 +6,14 @@ // We disable ticking here, as we are mainly interested in the events UActionBehaviour::UActionBehaviour() { PrimaryComponentTick.bCanEverTick = false; } -void UActionBehaviour::OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction, +void UActionBehaviour::OnActionEvent(USceneComponent* TriggerComponent, const EInteractionEventType EventType, const FInputActionValue& Value) { } -void UActionBehaviour::OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction, - const FInputActionValue& Value) -{ -} - void UActionBehaviour::BeginPlay() { Super::BeginPlay(); - OnActionBeginEvent.AddDynamic(this, &UActionBehaviour::OnActionStart); - OnActionEndEvent.AddDynamic(this, &UActionBehaviour::OnActionEnd); -} - -// Called every frame -void UActionBehaviour::TickComponent(float DeltaTime, ELevelTick TickType, - FActorComponentTickFunction* ThisTickFunction) -{ - Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + OnActionEventEvent.AddDynamic(this, &UActionBehaviour::OnActionEvent); } diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/BaseBehaviour.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/BaseBehaviour.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95488260668c095eb5dece6895555ce808e2fd11 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/BaseBehaviour.cpp @@ -0,0 +1,4 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Interaction/Interactables/BaseBehaviour.h" diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/GrabBehavior.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/GrabBehavior.cpp index 1537243da0b6c92a901decadce793bc8bd819bbb..7afd6522eda1b041118e012dd46b9946851a1133 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactables/GrabBehavior.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/GrabBehavior.cpp @@ -3,6 +3,7 @@ #include "Interaction/Interactables/GrabBehavior.h" #include "Interaction/Interactables/InteractableComponent.h" +#include "Interaction/Interactables/InteractionEventType.h" #include "Logging/StructuredLog.h" #include "Serialization/JsonTypes.h" #include "Utility/RWTHVRUtilities.h" @@ -34,15 +35,46 @@ UPrimitiveComponent* UGrabBehavior::GetHighestParentSimulatingPhysics(UPrimitive return Comp; } -void UGrabBehavior::OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction, +void UGrabBehavior::OnActionEvent(USceneComponent* TriggerComponent, const EInteractionEventType EventType, const FInputActionValue& Value) +{ + if (EventType == EInteractionEventType::InteractionStart) + { + StartGrab(TriggerComponent); + } + else + { + EndGrab(TriggerComponent); + } +} + +bool UGrabBehavior::TryRelease() +{ + if (!bObjectGrabbed) + { + return false; + } + + if (MyPhysicsComponent) + { + MyPhysicsComponent->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform); + MyPhysicsComponent->SetSimulatePhysics(bWasSimulatingPhysics); + } + else + { + GetOwner()->GetRootComponent()->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform); + } + bObjectGrabbed = false; + return true; +} +void UGrabBehavior::StartGrab(USceneComponent* TriggerComponent) { if (bObjectGrabbed) { return; } - USceneComponent* CurrentAttachParent = Cast<USceneComponent>(TriggeredComponent->GetAttachParent()); + USceneComponent* CurrentAttachParent = Cast<USceneComponent>(TriggerComponent->GetAttachParent()); const FAttachmentTransformRules Rules = FAttachmentTransformRules(EAttachmentRule::KeepWorld, false); if (MyPhysicsComponent = GetFirstComponentSimulatingPhysics(GetOwner()); MyPhysicsComponent != nullptr) @@ -72,18 +104,16 @@ void UGrabBehavior::OnActionStart(USceneComponent* TriggeredComponent, const UIn GetOwner()->GetComponents<UInteractableComponent>(Interactables, false); for (UInteractableComponent* Interactable : Interactables) { - Interactable->RestrictInteractionToComponent(TriggeredComponent); + Interactable->RestrictInteractionToComponent(TriggerComponent); } } OnGrabStartEvent.Broadcast(CurrentAttachParent, MyPhysicsComponent); } -void UGrabBehavior::OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction, - const FInputActionValue& Value) +void UGrabBehavior::EndGrab(USceneComponent* TriggerComponent) { - - USceneComponent* CurrentAttachParent = Cast<USceneComponent>(TriggeredComponent->GetAttachParent()); + USceneComponent* CurrentAttachParent = Cast<USceneComponent>(TriggerComponent->GetAttachParent()); // We try to release the attached component. If it is not succesful we log and return. Otherwise, we continue. if (!TryRelease()) @@ -107,23 +137,3 @@ void UGrabBehavior::OnActionEnd(USceneComponent* TriggeredComponent, const UInpu } } } - -bool UGrabBehavior::TryRelease() -{ - if (!bObjectGrabbed) - { - return false; - } - - if (MyPhysicsComponent) - { - MyPhysicsComponent->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform); - MyPhysicsComponent->SetSimulatePhysics(bWasSimulatingPhysics); - } - else - { - GetOwner()->GetRootComponent()->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform); - } - bObjectGrabbed = false; - return true; -} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/HoverBehaviour.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/HoverBehaviour.cpp index 96897613cd2f536cb9625a9b395ce49181656e70..f78e75fabfa434b1396d7bffc1354adee7f49441 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactables/HoverBehaviour.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/HoverBehaviour.cpp @@ -3,14 +3,13 @@ #include "Interaction/Interactables/HoverBehaviour.h" -void UHoverBehaviour::OnHoverStart(const USceneComponent* TriggeredComponent, FHitResult Hit) {} - -void UHoverBehaviour::OnHoverEnd(const USceneComponent* TriggeredComponent) {} +void UHoverBehaviour::OnHoverEvent(const USceneComponent* TriggerComponent, EInteractionEventType EventType, + const FHitResult& Hit) +{ +} void UHoverBehaviour::BeginPlay() { Super::BeginPlay(); - - OnHoverStartEvent.AddDynamic(this, &UHoverBehaviour::OnHoverStart); - OnHoverEndEvent.AddDynamic(this, &UHoverBehaviour::OnHoverEnd); + OnHoverEventEvent.AddDynamic(this, &UHoverBehaviour::OnHoverEvent); } diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectable.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectable.cpp index b813e2f9c2906079c2718140c84a78b41d4ebb92..276269b3dc0f389621e6415a71887cf3170a9e79 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectable.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectable.cpp @@ -62,7 +62,8 @@ void UIntenSelectable::HandleOnSelectStartEvents(const UIntenSelectComponent* In { for (const UHoverBehaviour* CurrentHoverBehaviour : OnHoverBehaviours) { - CurrentHoverBehaviour->OnHoverStartEvent.Broadcast(IntenSelect, HitResult); + CurrentHoverBehaviour->OnHoverEventEvent.Broadcast(IntenSelect, EInteractionEventType::InteractionStart, + HitResult); } } @@ -70,7 +71,9 @@ void UIntenSelectable::HandleOnSelectEndEvents(const UIntenSelectComponent* Inte { for (const UHoverBehaviour* CurrentHoverBehaviour : OnHoverBehaviours) { - CurrentHoverBehaviour->OnHoverEndEvent.Broadcast(IntenSelect); + FHitResult EmptyHit; + CurrentHoverBehaviour->OnHoverEventEvent.Broadcast(IntenSelect, EInteractionEventType::InteractionEnd, + EmptyHit); } } @@ -79,8 +82,8 @@ void UIntenSelectable::HandleOnClickStartEvents(UIntenSelectComponent* IntenSele for (const UActionBehaviour* CurrentActionBehaviour : OnActionBehaviours) { FInputActionValue EmptyInputActionValue{}; - const UInputAction* EmptyInputAction{}; - CurrentActionBehaviour->OnActionBeginEvent.Broadcast(IntenSelect, EmptyInputAction, EmptyInputActionValue); + CurrentActionBehaviour->OnActionEventEvent.Broadcast(IntenSelect, EInteractionEventType::InteractionStart, + EmptyInputActionValue); } } @@ -88,8 +91,8 @@ void UIntenSelectable::HandleOnClickEndEvents(UIntenSelectComponent* IntenSelect { for (const UActionBehaviour* CurrentActionBehaviour : OnActionBehaviours) { - const UInputAction* EmptyInputActionValue{}; - CurrentActionBehaviour->OnActionEndEvent.Broadcast(IntenSelect, EmptyInputActionValue, InputValue); + CurrentActionBehaviour->OnActionEventEvent.Broadcast(IntenSelect, EInteractionEventType::InteractionEnd, + InputValue); } } @@ -98,7 +101,7 @@ void UIntenSelectable::InitDefaultBehaviourReferences() // Scoring TSet<UActorComponent*> AllComponents = GetOwner()->GetComponents(); - for (UActorComponent * c : AllComponents) + for (UActorComponent* c : AllComponents) { if (UIntenSelectableScoring* TryToGetScoring = Cast<UIntenSelectableScoring>(c)) { diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/InteractableComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/InteractableComponent.cpp index 29ee75b08e1d37147671228e167c09e4cde462f8..1e954ee1cef0511a89a3dd6d4f846a0a176ee767 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactables/InteractableComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/InteractableComponent.cpp @@ -4,6 +4,11 @@ #include "Interaction/Interactables/InteractableComponent.h" #include "Interaction/Interactables/ActionBehaviour.h" #include "Interaction/Interactables/HoverBehaviour.h" +#include "Interaction/Interactors/UBaseInteractionComponent.h" +#include "Logging/StructuredLog.h" +#include "Utility/RWTHVRUtilities.h" + +bool UInteractableComponent::HasInteractionTypeFlag(EInteractorType type) { return type & InteractorFilter; } void UInteractableComponent::RestrictInteractionToComponents(const TArray<USceneComponent*>& Components) { @@ -39,9 +44,8 @@ void UInteractableComponent::BeginPlay() InitDefaultBehaviourReferences(); } -// This functions dispatches the HoverStart Event to the attached Hover Behaviour Components -void UInteractableComponent::HandleOnHoverStartEvents(USceneComponent* TriggerComponent, - const EInteractorType Interactor) +void UInteractableComponent::HandleOnHoverEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor, + const EInteractionEventType EventType) { // We early return if there the InteractorFilter is set and the Interactor is allowed. if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor)) @@ -52,34 +56,44 @@ void UInteractableComponent::HandleOnHoverStartEvents(USceneComponent* TriggerCo return; // Broadcast event to all HoverBehaviours - for (const UHoverBehaviour* b : OnHoverBehaviours) + for (UHoverBehaviour* HoverBehaviour : OnHoverBehaviours) { - b->OnHoverStartEvent.Broadcast(TriggerComponent, HitResult); - } -} - -// This functions dispatches the HoverEnd Event to the attached Hover Behaviour Components -void UInteractableComponent::HandleOnHoverEndEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor) -{ - // We early return if there the InteractorFilter is set and the Interactor is allowed. - if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor)) - return; - - // We early return if the source Interactor is not part of the allowed components - if (!IsComponentAllowed(TriggerComponent)) - return; - - // Broadcast event to all HoverBehaviours - for (const UHoverBehaviour* b : OnHoverBehaviours) - { - b->OnHoverEndEvent.Broadcast(TriggerComponent); + // Check if we need to replicate the action to the server + if (HoverBehaviour->bExecuteOnServer) + { + // Request the server to execute our behaviour. + // As we can only execute RPCs from an owned object, and we don't necessarily own this actor, pipe it + // through the interactor. Because behaviours can also be triggered from non-interactors, only do this on a + // successful cast + + auto* InteractorComponent = Cast<UUBaseInteractionComponent>(TriggerComponent); + if (!InteractorComponent) + { + UE_LOGFMT(Toolkit, Warning, + "Interaction: TriggerComponent {TriggerComponent} is not a UUBaseInteractionComponent. Only " + "UUBaseInteractionComponent TriggerComponents can be replicated.", + TriggerComponent->GetName()); + return; + } + InteractorComponent->RequestHoverBehaviourReplicationStart(HoverBehaviour, EventType, HitResult); + } + else if (HoverBehaviour->bExecuteOnAllClients) + { + UE_LOGFMT(Toolkit, Warning, + "Interaction: Behaviour {BehaviourName} has bExecuteOnAllClients=true, which requires " + "bExecuteOnServer also set to true, which is not the case.", + HoverBehaviour->GetName()); + } + else // skip replication altogether (default case) + { + HoverBehaviour->OnHoverEventEvent.Broadcast(TriggerComponent, EventType, HitResult); + } } } // This functions dispatches the ActionStart Event to the attached Action Behaviour Components -void UInteractableComponent::HandleOnActionStartEvents(USceneComponent* TriggerComponent, - const UInputAction* InputAction, const FInputActionValue& Value, - const EInteractorType Interactor) +void UInteractableComponent::HandleOnActionEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor, + const EInteractionEventType EventType, const FInputActionValue& Value) { // We early return if there the InteractorFilter is set and the Interactor is allowed. if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor)) @@ -90,28 +104,38 @@ void UInteractableComponent::HandleOnActionStartEvents(USceneComponent* TriggerC return; // Broadcast event to all ActionBehaviours - for (const UActionBehaviour* b : OnActionBehaviours) + for (UActionBehaviour* ActionBehaviour : OnActionBehaviours) { - b->OnActionBeginEvent.Broadcast(TriggerComponent, InputAction, Value); - } -} - -// This functions dispatches the ActionEnd Event to the attached Action Behaviour Components -void UInteractableComponent::HandleOnActionEndEvents(USceneComponent* TriggerComponent, const UInputAction* InputAction, - const FInputActionValue& Value, const EInteractorType Interactor) -{ - // We early return if there the InteractorFilter is set and the Interactor is allowed. - if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor)) - return; - - // We early return if the source Interactor is not part of the allowed components - if (!IsComponentAllowed(TriggerComponent)) - return; - - // Broadcast event to all ActionBehaviours - for (const UActionBehaviour* b : OnActionBehaviours) - { - b->OnActionEndEvent.Broadcast(TriggerComponent, InputAction, Value); + // Check if we need to replicate the action to the server + if (ActionBehaviour->bExecuteOnServer) + { + // Request the server to execute our behaviour. + // As we can only execute RPCs from an owned object, and we don't necessarily own this actor, pipe it + // through the interactor. Because behaviours can also be triggered from non-interactors, only do this on a + // successful cast + + auto* InteractorComponent = Cast<UUBaseInteractionComponent>(TriggerComponent); + if (!InteractorComponent) + { + UE_LOGFMT(Toolkit, Warning, + "Interaction: TriggerComponent {TriggerComponent} is not a UUBaseInteractionComponent. Only " + "UUBaseInteractionComponent TriggerComponents can be replicated.", + TriggerComponent->GetName()); + return; + } + InteractorComponent->RequestActionBehaviourReplicationStart(ActionBehaviour, EventType, Value); + } + else if (ActionBehaviour->bExecuteOnAllClients) + { + UE_LOGFMT(Toolkit, Warning, + "Interaction: Behaviour {BehaviourName} has bExecuteOnAllClients=true, which requires " + "bExecuteOnServer also set to true, which is not the case.", + ActionBehaviour->GetName()); + } + else // skip replication altogether (default case) + { + ActionBehaviour->OnActionEventEvent.Broadcast(TriggerComponent, EventType, Value); + } } } @@ -150,4 +174,4 @@ bool UInteractableComponent::IsComponentAllowed(USceneComponent* Component) cons } } return true; -} +} \ No newline at end of file diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactors/DirectInteractionComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactors/DirectInteractionComponent.cpp index c8cf9ce35e45d0bc107cd73da08333ef5ba5b2d9..4b7af7690e9093ac4f20dda70a3c3951f2f317cf 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactors/DirectInteractionComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactors/DirectInteractionComponent.cpp @@ -6,6 +6,7 @@ #include "EnhancedInputComponent.h" #include "Interaction/Interactables/InteractableComponent.h" #include "Interaction/Interactables/InteractionBitSet.h" +#include "Interaction/Interactables/InteractionEventType.h" #include "Kismet/GameplayStatics.h" #include "Logging/StructuredLog.h" @@ -30,7 +31,7 @@ void UDirectInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tick TArray<FHitResult> OutHits; const ETraceTypeQuery TraceType = UEngineTypes::ConvertToTraceType(ECollisionChannel::ECC_PhysicsBody); - auto DebugTrace = bShowDebugTrace ? EDrawDebugTrace::ForOneFrame : EDrawDebugTrace::None; + const auto DebugTrace = bShowDebugTrace ? EDrawDebugTrace::ForOneFrame : EDrawDebugTrace::None; UKismetSystemLibrary::SphereTraceMulti(GetWorld(), GetAttachParent()->GetComponentLocation(), GetAttachParent()->GetComponentLocation(), InteractionSphereRadius, @@ -59,7 +60,8 @@ void UDirectInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tick if (!PreviousInteractableComponentsInRange.Contains(CurrentInteractableComp)) { PreviousInteractableComponentsInRange.AddUnique(CurrentInteractableComp); - CurrentInteractableComp->HandleOnHoverStartEvents(this, EInteractorType::Direct); + CurrentInteractableComp->HandleOnHoverEvents(this, EInteractorType::Direct, + EInteractionEventType::InteractionStart); } } @@ -71,7 +73,8 @@ void UDirectInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tick if (!CurrentInteractableCompsInRange.Contains(PrevInteractableComp)) { ComponentsToRemove.AddUnique(PrevInteractableComp); - PrevInteractableComp->HandleOnHoverEndEvents(this, EInteractorType::Direct); + PrevInteractableComp->HandleOnHoverEvents(this, EInteractorType::Direct, + EInteractionEventType::InteractionEnd); } } @@ -97,12 +100,12 @@ void UDirectInteractionComponent::SetupPlayerInput(UInputComponent* PlayerInputC return; EI->BindAction(InteractionInputAction, ETriggerEvent::Started, this, - &UDirectInteractionComponent::OnBeginInteraction); + &UDirectInteractionComponent::OnBeginInteractionInputAction); EI->BindAction(InteractionInputAction, ETriggerEvent::Completed, this, - &UDirectInteractionComponent::OnEndInteraction); + &UDirectInteractionComponent::OnEndInteractionInputAction); } -void UDirectInteractionComponent::OnBeginInteraction(const FInputActionValue& Value) +void UDirectInteractionComponent::OnBeginInteractionInputAction(const FInputActionValue& Value) { const FVector InteractionLocation = GetAttachParent()->GetComponentLocation(); @@ -115,7 +118,7 @@ void UDirectInteractionComponent::OnBeginInteraction(const FInputActionValue& Va CurrentInteractableComponentsInRange, [&](auto Element) { return FVector(Element->GetOwner()->GetActorLocation() - InteractionLocation).Size(); }); - MinElement->HandleOnActionStartEvents(this, InteractionInputAction, Value, EInteractorType::Direct); + MinElement->HandleOnActionEvents(this, EInteractorType::Direct, EInteractionEventType::InteractionStart, Value); CurrentlyInteractedComponents = {MinElement}; } else @@ -124,19 +127,21 @@ void UDirectInteractionComponent::OnBeginInteraction(const FInputActionValue& Va CurrentInteractableComponentsInRange.Num()); for (UInteractableComponent* InteractableComp : CurrentInteractableComponentsInRange) { - InteractableComp->HandleOnActionStartEvents(this, InteractionInputAction, Value, EInteractorType::Direct); + InteractableComp->HandleOnActionEvents(this, EInteractorType::Direct, + EInteractionEventType::InteractionStart, Value); CurrentlyInteractedComponents.Add(InteractableComp); } } } -void UDirectInteractionComponent::OnEndInteraction(const FInputActionValue& Value) +void UDirectInteractionComponent::OnEndInteractionInputAction(const FInputActionValue& Value) { for (auto& Component : CurrentlyInteractedComponents) { if (Component.IsValid()) { - Component->HandleOnActionEndEvents(this, InteractionInputAction, Value, EInteractorType::Direct); + Component->HandleOnActionEvents(this, EInteractorType::Direct, EInteractionEventType::InteractionStart, + Value); } } } diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastInteractionComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastInteractionComponent.cpp index 94afba4b4426fe1b861d787826f0e1cc11d6583b..42e1aeea61a94302b199769e8f79d50314c5cc89 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastInteractionComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastInteractionComponent.cpp @@ -5,6 +5,7 @@ #include "EnhancedInputComponent.h" #include "Interaction/Interactables/InteractableComponent.h" +#include "Interaction/Interactables/InteractionEventType.h" #include "Kismet/KismetSystemLibrary.h" // Sets default values for this component's properties @@ -25,14 +26,13 @@ void URaycastInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tic UInteractableComponent* NewInteractableComponent = nullptr; - - TArray<AActor*> ActorsToIgnore; FHitResult Hit; const ETraceTypeQuery TraceType = UEngineTypes::ConvertToTraceType(ECollisionChannel::ECC_PhysicsBody); - FVector TraceStart = GetAttachParent()->GetComponentLocation(); - FVector TraceEnd = GetAttachParent()->GetComponentLocation() + TraceLength * GetAttachParent()->GetForwardVector(); + const FVector TraceStart = GetAttachParent()->GetComponentLocation(); + const FVector TraceEnd = + GetAttachParent()->GetComponentLocation() + TraceLength * GetAttachParent()->GetForwardVector(); - auto DebugTrace = bShowDebugTrace ? EDrawDebugTrace::ForOneFrame : EDrawDebugTrace::None; + const auto DebugTrace = bShowDebugTrace ? EDrawDebugTrace::ForOneFrame : EDrawDebugTrace::None; UKismetSystemLibrary::LineTraceSingle(GetWorld(), TraceStart, TraceEnd, TraceType, true, ActorsToIgnore, DebugTrace, Hit, true, FColor::Green); @@ -53,24 +53,28 @@ void URaycastInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tic if (CurrentInteractable != PreviousInteractable) { if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) - CurrentInteractable->HandleOnHoverStartEvents(this, EInteractorType::Raycast); + CurrentInteractable->HandleOnHoverEvents(this, EInteractorType::Raycast, + EInteractionEventType::InteractionStart); if (PreviousInteractable && PreviousInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) - PreviousInteractable->HandleOnHoverEndEvents(this, EInteractorType::Raycast); + PreviousInteractable->HandleOnHoverEvents(this, EInteractorType::Raycast, + EInteractionEventType::InteractionEnd); } PreviousInteractable = CurrentInteractable; } -void URaycastInteractionComponent::OnBeginInteraction(const FInputActionValue& Value) +void URaycastInteractionComponent::OnBeginInteractionInputAction(const FInputActionValue& Value) { if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) - CurrentInteractable->HandleOnActionStartEvents(this, InteractionInputAction, Value, EInteractorType::Raycast); + CurrentInteractable->HandleOnActionEvents(this, EInteractorType::Raycast, + EInteractionEventType::InteractionStart, Value); } -void URaycastInteractionComponent::OnEndInteraction(const FInputActionValue& Value) +void URaycastInteractionComponent::OnEndInteractionInputAction(const FInputActionValue& Value) { if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) - CurrentInteractable->HandleOnActionEndEvents(this, InteractionInputAction, Value, EInteractorType::Raycast); + CurrentInteractable->HandleOnActionEvents(this, EInteractorType::Raycast, EInteractionEventType::InteractionEnd, + Value); } void URaycastInteractionComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) @@ -86,7 +90,7 @@ void URaycastInteractionComponent::SetupPlayerInput(UInputComponent* PlayerInput return; EI->BindAction(InteractionInputAction, ETriggerEvent::Started, this, - &URaycastInteractionComponent::OnBeginInteraction); + &URaycastInteractionComponent::OnBeginInteractionInputAction); EI->BindAction(InteractionInputAction, ETriggerEvent::Completed, this, - &URaycastInteractionComponent::OnEndInteraction); + &URaycastInteractionComponent::OnEndInteractionInputAction); } diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactors/UBaseInteractionComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactors/UBaseInteractionComponent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..67d718c90cdff0dce7dab7cf7bff226f778877c9 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactors/UBaseInteractionComponent.cpp @@ -0,0 +1,152 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Interaction/Interactors/UBaseInteractionComponent.h" + +#include "Interaction/Interactables/ActionBehaviour.h" +#include "Interaction/Interactables/HoverBehaviour.h" +#include "Logging/StructuredLog.h" +#include "Utility/RWTHVRUtilities.h" + +// Sets default values for this component's properties +UUBaseInteractionComponent::UUBaseInteractionComponent() +{ + // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these + // features off to improve performance if you don't need them. + PrimaryComponentTick.bCanEverTick = true; + SetIsReplicatedByDefault(true); + // ... +} + +void UUBaseInteractionComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) +{ + IInputExtensionInterface::SetupPlayerInput(PlayerInputComponent); +} + +void UUBaseInteractionComponent::OnBeginInteractionInputAction(const FInputActionValue& Value) {} + +void UUBaseInteractionComponent::OnEndInteractionInputAction(const FInputActionValue& Value) {} + +void UUBaseInteractionComponent::RequestHoverBehaviourReplicationStart(UHoverBehaviour* Behaviour, + const EInteractionEventType EventType, + const FHitResult& Hit) +{ + if (GetOwner()->HasLocalNetOwner()) + { + if (GetOwner()->HasAuthority()) + { + HoverBehaviourReplicationStart(Behaviour, EventType, Hit); + } + else + { + // RPC + ServerRequestHoverBehaviourReplicationStartRpc(Behaviour, EventType, Hit); + } + } + else + { + UE_LOGFMT(Toolkit, Error, + "Interaction: Trying to replicate HoverBehaviour {HoverBehaviour} in InteractionComponent " + "{InteractionComponent} which has no local net owner!", + Behaviour->GetName(), this->GetName()); + } +} + +void UUBaseInteractionComponent::HoverBehaviourReplicationStart(UHoverBehaviour* Behaviour, + const EInteractionEventType EventType, + const FHitResult& Hit) +{ + if (!Behaviour->bExecuteOnServer) // this should never happen + { + UE_LOGFMT(Toolkit, Error, + "Interaction: Trying to execute HoverBehaviour {HoverBehaviour} in InteractionComponent " + "{InteractionComponent} on the server, but bExecuteOnServer is false!", + Behaviour->GetName(), this->GetName()); + return; + } + + // If desired, multicast to all clients (including originator) + if (Behaviour->bExecuteOnAllClients) + { + MulticastHoverBehaviourReplicationStartRpc(Behaviour, EventType, Hit); + } + else + { + // Execute the behaviour only on the server + Behaviour->OnHoverEventEvent.Broadcast(this, EventType, Hit); + } +} + +void UUBaseInteractionComponent::ServerRequestHoverBehaviourReplicationStartRpc_Implementation( + UHoverBehaviour* Behaviour, const EInteractionEventType EventType, const FHitResult& Hit) +{ + HoverBehaviourReplicationStart(Behaviour, EventType, Hit); +} + +void UUBaseInteractionComponent::MulticastHoverBehaviourReplicationStartRpc_Implementation( + UHoverBehaviour* Behaviour, const EInteractionEventType EventType, const FHitResult& Hit) +{ + Behaviour->OnHoverEventEvent.Broadcast(this, EventType, Hit); +} + +void UUBaseInteractionComponent::RequestActionBehaviourReplicationStart(UActionBehaviour* Behaviour, + const EInteractionEventType EventType, + const FInputActionValue& Value) +{ + if (GetOwner()->HasLocalNetOwner()) + { + if (GetOwner()->HasAuthority()) + { + ActionBehaviourReplicationStart(Behaviour, EventType, Value); + } + else + { + // RPC + ServerRequestActionBehaviourReplicationStartRpc(Behaviour, EventType, Value); + } + } + else + { + UE_LOGFMT(Toolkit, Error, + "Interaction: Trying to replicate HoverBehaviour {HoverBehaviour} in InteractionComponent " + "{InteractionComponent} which has no local net owner!", + Behaviour->GetName(), this->GetName()); + } +} + +void UUBaseInteractionComponent::ActionBehaviourReplicationStart(UActionBehaviour* Behaviour, + const EInteractionEventType EventType, + const FInputActionValue& Value) +{ + if (!Behaviour->bExecuteOnServer) // this should never happen + { + UE_LOGFMT(Toolkit, Error, + "Interaction: Trying to execute ActionBehaviour {ActionBehaviour} in InteractionComponent " + "{InteractionComponent} on the server, but bExecuteOnServer is false!", + Behaviour->GetName(), this->GetName()); + return; + } + + // If desired, multicast to all clients (including originator) + if (Behaviour->bExecuteOnAllClients) + { + MulticastActionBehaviourReplicationStartRpc(Behaviour, EventType, Value); + } + else + { + // Execute the behaviour only on the server + Behaviour->OnActionEventEvent.Broadcast(this, EventType, Value); + } +} + +void UUBaseInteractionComponent::ServerRequestActionBehaviourReplicationStartRpc_Implementation( + UActionBehaviour* Behaviour, const EInteractionEventType EventType, const FInputActionValue& Value) +{ + ActionBehaviourReplicationStart(Behaviour, EventType, Value); +} + +void UUBaseInteractionComponent::MulticastActionBehaviourReplicationStartRpc_Implementation( + UActionBehaviour* Behaviour, const EInteractionEventType EventType, const FInputActionValue& Value) +{ + Behaviour->OnActionEventEvent.Broadcast(this, EventType, Value); +} diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/ActionBehaviour.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/ActionBehaviour.h index 755d876dc3205b0538f6bc394352def55b2da670..96774874b6e7282348655c04f7f8256b69f7747d 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactables/ActionBehaviour.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/ActionBehaviour.h @@ -3,21 +3,18 @@ #pragma once #include "CoreMinimal.h" -#include "InputAction.h" +#include "BaseBehaviour.h" #include "Components/SceneComponent.h" #include "InputActionValue.h" -#include "InteractionBitSet.h" #include "ActionBehaviour.generated.h" +enum EInteractionEventType : uint8; -DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnActionBegin, USceneComponent*, TriggeredComponent, - const UInputAction*, InputAction, const FInputActionValue&, Value); - -DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnActionEnd, USceneComponent*, TriggeredComponent, const UInputAction*, - InputAction, const FInputActionValue&, Value); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnActionBegin, USceneComponent*, TriggerComponent, + const EInteractionEventType, EventType, const FInputActionValue&, Value); UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) -class RWTHVRTOOLKIT_API UActionBehaviour : public USceneComponent +class RWTHVRTOOLKIT_API UActionBehaviour : public UBaseBehaviour { GENERATED_BODY() @@ -26,22 +23,12 @@ public: UActionBehaviour(); UPROPERTY(BlueprintAssignable) - FOnActionBegin OnActionBeginEvent; - - UPROPERTY(BlueprintAssignable) - FOnActionEnd OnActionEndEvent; + FOnActionBegin OnActionEventEvent; protected: UFUNCTION() - virtual void OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction, + virtual void OnActionEvent(USceneComponent* TriggerComponent, const EInteractionEventType EventType, const FInputActionValue& Value); - UFUNCTION() - virtual void OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction, - const FInputActionValue& Value); - virtual void BeginPlay() override; - - virtual void TickComponent(float DeltaTime, ELevelTick TickType, - FActorComponentTickFunction* ThisTickFunction) override; }; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/BaseBehaviour.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/BaseBehaviour.h new file mode 100644 index 0000000000000000000000000000000000000000..d1f379bb9431749786d2ac871d119e82f5bea46e --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/BaseBehaviour.h @@ -0,0 +1,34 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/SceneComponent.h" +#include "BaseBehaviour.generated.h" + + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UBaseBehaviour : public USceneComponent +{ + GENERATED_BODY() + +public: + /** + * Replication part + */ + + /** + * Defines whether this behaviour will be executed on the server instead of the local client. + * If set to true, an RPC is sent to the server and it will not be run locally. + * */ + UPROPERTY(EditAnywhere, BlueprintReadWrite) + bool bExecuteOnServer = false; + + /** + * Defines whether this behaviour will be executed on all connected clients that are relevant, including the + * local originator client. This only has an effect if bExecuteOnServer is true, as only the server can multicast + * to all other clients. + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (EditCondition = "bExecuteOnServer")) + bool bExecuteOnAllClients = false; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/GrabBehavior.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/GrabBehavior.h index d10affdff4aa25e2e4c22818219375580f342c8f..586477d774f0599d1638df6bb256f50cac4788dd 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactables/GrabBehavior.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/GrabBehavior.h @@ -23,11 +23,8 @@ public: UPROPERTY(EditAnywhere, Category = "Grabbing") bool bBlockOtherInteractionsWhileGrabbed = true; - virtual void OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction, + virtual void OnActionEvent(USceneComponent* TriggerComponent, const EInteractionEventType EventType, const FInputActionValue& Value) override; - virtual void OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction, - const FInputActionValue& Value) override; - /** * Called after the object was successfully attached to the hand @@ -61,6 +58,10 @@ private: */ bool TryRelease(); + void StartGrab(USceneComponent* TriggerComponent); + + void EndGrab(USceneComponent* TriggerComponent); + bool bObjectGrabbed = false; bool bWasSimulatingPhysics; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/HoverBehaviour.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/HoverBehaviour.h index 7557653fbf02dc8d1780bbb32804c583324281ad..3571440f96bf16d20eb976d5fa359bb4d5d43b4a 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactables/HoverBehaviour.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/HoverBehaviour.h @@ -3,16 +3,16 @@ #pragma once #include "CoreMinimal.h" +#include "BaseBehaviour.h" +#include "InteractionEventType.h" #include "Components/SceneComponent.h" #include "HoverBehaviour.generated.h" - -DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnHoverStart, const USceneComponent*, TriggeredComponent, FHitResult, - Hit); -DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHoverEnd, const USceneComponent*, TriggeredComponent); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnHoverEvent, const USceneComponent*, TriggeredComponent, + const EInteractionEventType, EventType, const FHitResult&, Hit); UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) -class RWTHVRTOOLKIT_API UHoverBehaviour : public USceneComponent +class RWTHVRTOOLKIT_API UHoverBehaviour : public UBaseBehaviour { GENERATED_BODY() @@ -22,16 +22,12 @@ public: * VRPawn) Hit: Hit Result of the trace to get access to e.g. contact point/normals etc. */ UPROPERTY(BlueprintAssignable) - FOnHoverStart OnHoverStartEvent; - - UPROPERTY(BlueprintAssignable) - FOnHoverEnd OnHoverEndEvent; + FOnHoverEvent OnHoverEventEvent; protected: UFUNCTION() - virtual void OnHoverStart(const USceneComponent* TriggeredComponent, FHitResult Hit); - UFUNCTION() - virtual void OnHoverEnd(const USceneComponent* TriggeredComponent); + virtual void OnHoverEvent(const USceneComponent* TriggerComponent, EInteractionEventType EventType, + const FHitResult& Hit); virtual void BeginPlay() override; }; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractableComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractableComponent.h index da85ad8b003814098fc21e112de423a097a80535..ee5c925abf5db5f6046f1740274aac26cd9daf84 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractableComponent.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractableComponent.h @@ -9,6 +9,8 @@ #include "InteractableComponent.generated.h" +enum EInteractionEventType : uint8; +class UBaseBehaviour; struct FInputActionValue; class UActionBehaviour; class UHoverBehaviour; @@ -53,7 +55,7 @@ public: bool bAllowInteractionFromChildGeometry = true; UFUNCTION(BlueprintCallable) - FORCEINLINE bool HasInteractionTypeFlag(EInteractorType type) { return type & InteractorFilter; } + FORCEINLINE bool HasInteractionTypeFlag(EInteractorType type); /** * @brief Restrict interactability to given components (e.g. if an object is grabbed, block interactions from other @@ -74,12 +76,10 @@ protected: virtual void BeginPlay() override; public: - void HandleOnHoverStartEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor); - void HandleOnHoverEndEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor); - void HandleOnActionStartEvents(USceneComponent* TriggerComponent, const UInputAction* InputAction, - const FInputActionValue& Value, const EInteractorType Interactor); - void HandleOnActionEndEvents(USceneComponent* TriggerComponent, const UInputAction* InputAction, - const FInputActionValue& Value, const EInteractorType Interactor); + void HandleOnHoverEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor, + const EInteractionEventType EventType); + void HandleOnActionEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor, + const EInteractionEventType EventType, const FInputActionValue& Value); /** * @brief If hover and action behaviors are not explicitly specified, load all existing ones diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractionEventType.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractionEventType.h new file mode 100644 index 0000000000000000000000000000000000000000..9e24c211276613c6ea0e7b11037d59e05caefba0 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractionEventType.h @@ -0,0 +1,8 @@ +#pragma once + +UENUM(BlueprintType) +enum EInteractionEventType : uint8 +{ + InteractionStart = 0, + InteractionEnd = 1, +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactors/DirectInteractionComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactors/DirectInteractionComponent.h index 69ef74ff844a727c11a333047a7f011a12d01241..46d2d160358d991a70e232bce73bc6c9a57c52ef 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactors/DirectInteractionComponent.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactors/DirectInteractionComponent.h @@ -3,13 +3,13 @@ #pragma once #include "CoreMinimal.h" +#include "UBaseInteractionComponent.h" #include "Components/SceneComponent.h" #include "Interaction/Interactables/InteractableComponent.h" -#include "Pawn/InputExtensionInterface.h" #include "DirectInteractionComponent.generated.h" UCLASS(Abstract, Blueprintable) -class RWTHVRTOOLKIT_API UDirectInteractionComponent : public USceneComponent, public IInputExtensionInterface +class RWTHVRTOOLKIT_API UDirectInteractionComponent : public UUBaseInteractionComponent { GENERATED_BODY() @@ -20,29 +20,18 @@ public: virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; - UPROPERTY(EditAnywhere, Category = "Input") - class UInputAction* InteractionInputAction; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction") float InteractionSphereRadius = 15.0; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction") - bool bShowDebugTrace = false; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction") bool bOnlyInteractWithClosestActor = false; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction") - TArray<AActor*> ActorsToIgnore; - virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override; private: - UFUNCTION() - void OnBeginInteraction(const FInputActionValue& Value); + virtual void OnBeginInteractionInputAction(const FInputActionValue& Value) override; - UFUNCTION() - void OnEndInteraction(const FInputActionValue& Value); + virtual void OnEndInteractionInputAction(const FInputActionValue& Value) override; UPROPERTY() TArray<UInteractableComponent*> PreviousInteractableComponentsInRange; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastInteractionComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastInteractionComponent.h index f5c93123e8ba136e747796825f93309b285109b0..31441d516c5a34923c2ca6d26665a50a9f6069ed 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastInteractionComponent.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastInteractionComponent.h @@ -2,16 +2,15 @@ #pragma once -#include <Pawn/InputExtensionInterface.h> - #include "CoreMinimal.h" +#include "UBaseInteractionComponent.h" #include "Components/SceneComponent.h" #include "Interaction/Interactables/InteractableComponent.h" #include "RaycastInteractionComponent.generated.h" UCLASS(Abstract, Blueprintable) -class RWTHVRTOOLKIT_API URaycastInteractionComponent : public USceneComponent, public IInputExtensionInterface +class RWTHVRTOOLKIT_API URaycastInteractionComponent : public UUBaseInteractionComponent { GENERATED_BODY() @@ -23,20 +22,13 @@ public: virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; - UPROPERTY(EditAnywhere, Category = "Input") - class UInputAction* InteractionInputAction; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Raycast") float TraceLength = 3000.0; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Raycast") - bool bShowDebugTrace = false; private: - UFUNCTION() - void OnBeginInteraction(const FInputActionValue& Value); + virtual void OnBeginInteractionInputAction(const FInputActionValue& Value) override; - UFUNCTION() - void OnEndInteraction(const FInputActionValue& Value); + virtual void OnEndInteractionInputAction(const FInputActionValue& Value) override; public: virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactors/UBaseInteractionComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactors/UBaseInteractionComponent.h new file mode 100644 index 0000000000000000000000000000000000000000..327609c8229758f07531f96c59a67e8cb08b56d6 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactors/UBaseInteractionComponent.h @@ -0,0 +1,74 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/SceneComponent.h" +#include "Pawn/InputExtensionInterface.h" +#include "UBaseInteractionComponent.generated.h" + + +struct FInputActionValue; +enum EInteractionEventType : uint8; +class UActionBehaviour; +class UHoverBehaviour; + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UUBaseInteractionComponent : public USceneComponent, public IInputExtensionInterface +{ + GENERATED_BODY() + +public: + // Sets default values for this component's properties + UUBaseInteractionComponent(); + + virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override; + + UPROPERTY(EditAnywhere, Category = "Input") + class UInputAction* InteractionInputAction; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Base Interaction") + TArray<AActor*> ActorsToIgnore; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Base Interaction") + bool bShowDebugTrace = false; + + /* + * Replication part + */ + + void RequestHoverBehaviourReplicationStart(UHoverBehaviour* Behaviour, const EInteractionEventType EventType, + const FHitResult& Hit); + void HoverBehaviourReplicationStart(UHoverBehaviour* Behaviour, const EInteractionEventType EventType, + const FHitResult& Hit); + + void RequestActionBehaviourReplicationStart(UActionBehaviour* Behaviour, const EInteractionEventType EventType, + const FInputActionValue& Value); + void ActionBehaviourReplicationStart(UActionBehaviour* Behaviour, const EInteractionEventType EventType, + const FInputActionValue& Value); + + // RPCs + UFUNCTION(Server, Reliable) + void ServerRequestHoverBehaviourReplicationStartRpc(UHoverBehaviour* Behaviour, + const EInteractionEventType EventType, const FHitResult& Hit); + + UFUNCTION(NetMulticast, Reliable) + void MulticastHoverBehaviourReplicationStartRpc(UHoverBehaviour* Behaviour, const EInteractionEventType EventType, + const FHitResult& Hit); + + UFUNCTION(Server, Reliable) + void ServerRequestActionBehaviourReplicationStartRpc(UActionBehaviour* Behaviour, + const EInteractionEventType EventType, + const FInputActionValue& Value); + + UFUNCTION(NetMulticast, Reliable) + void MulticastActionBehaviourReplicationStartRpc(UActionBehaviour* Behaviour, const EInteractionEventType EventType, + const FInputActionValue& Value); + +private: + UFUNCTION() + virtual void OnBeginInteractionInputAction(const FInputActionValue& Value); + + UFUNCTION() + virtual void OnEndInteractionInputAction(const FInputActionValue& Value); +};