Skip to content
Snippets Groups Projects
Commit eb5eaab0 authored by David Gilbert's avatar David Gilbert :bug:
Browse files

refactor(interaction, replication): Initial refactoring of the interaction...

refactor(interaction, replication): Initial refactoring of the interaction system to better lay the groundwork for interaction replication.
Very rough untested draft as of now, changes include:
- Action/Hover now inherit from a BaseBehaviour which can save shared information, and adds some basic replication properties.
- Adds a BaseInteractionComponent which similarly to the BaseBehaviour contains replication and some general properties shared by both direct and ray interactors.
- Start/End functions have been condensed into one, and an Enum now separates the two. This reduces code duplication especially for replication by a lot.
- Adjusts other components such as intenselect to the new refactoring
parent d0c248c5
Branches
Tags
2 merge requests!107UE5.4-2024.1-rc1,!91Interaction refactoring and replication
Pipeline #426475 failed
This commit is part of merge request !91. Comments created here will be created in the context of that merge request.
Showing
with 472 additions and 197 deletions
...@@ -19,3 +19,9 @@ ...@@ -19,3 +19,9 @@
+FunctionRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.OnEndGrab",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.OnEndInteraction") +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.PreviousGrabBehavioursInRange",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.PreviousInteractableComponentsInRange")
+PropertyRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.CurrentGrabBehavioursInRange",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.CurrentInteractableComponentsInRange") +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
...@@ -6,12 +6,7 @@ ...@@ -6,12 +6,7 @@
// We disable ticking here, as we are mainly interested in the events // We disable ticking here, as we are mainly interested in the events
UActionBehaviour::UActionBehaviour() { PrimaryComponentTick.bCanEverTick = false; } 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) const FInputActionValue& Value)
{ {
} }
...@@ -20,13 +15,5 @@ void UActionBehaviour::BeginPlay() ...@@ -20,13 +15,5 @@ void UActionBehaviour::BeginPlay()
{ {
Super::BeginPlay(); Super::BeginPlay();
OnActionBeginEvent.AddDynamic(this, &UActionBehaviour::OnActionStart); OnActionEventEvent.AddDynamic(this, &UActionBehaviour::OnActionEvent);
OnActionEndEvent.AddDynamic(this, &UActionBehaviour::OnActionEnd);
}
// Called every frame
void UActionBehaviour::TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
} }
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/Interactables/BaseBehaviour.h"
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "Interaction/Interactables/GrabBehavior.h" #include "Interaction/Interactables/GrabBehavior.h"
#include "Interaction/Interactables/InteractableComponent.h" #include "Interaction/Interactables/InteractableComponent.h"
#include "Interaction/Interactables/InteractionEventType.h"
#include "Logging/StructuredLog.h" #include "Logging/StructuredLog.h"
#include "Serialization/JsonTypes.h" #include "Serialization/JsonTypes.h"
#include "Utility/RWTHVRUtilities.h" #include "Utility/RWTHVRUtilities.h"
...@@ -34,15 +35,46 @@ UPrimitiveComponent* UGrabBehavior::GetHighestParentSimulatingPhysics(UPrimitive ...@@ -34,15 +35,46 @@ UPrimitiveComponent* UGrabBehavior::GetHighestParentSimulatingPhysics(UPrimitive
return Comp; return Comp;
} }
void UGrabBehavior::OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction, void UGrabBehavior::OnActionEvent(USceneComponent* TriggerComponent, const EInteractionEventType EventType,
const FInputActionValue& Value) 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) if (bObjectGrabbed)
{ {
return; return;
} }
USceneComponent* CurrentAttachParent = Cast<USceneComponent>(TriggeredComponent->GetAttachParent()); USceneComponent* CurrentAttachParent = Cast<USceneComponent>(TriggerComponent->GetAttachParent());
const FAttachmentTransformRules Rules = FAttachmentTransformRules(EAttachmentRule::KeepWorld, false); const FAttachmentTransformRules Rules = FAttachmentTransformRules(EAttachmentRule::KeepWorld, false);
if (MyPhysicsComponent = GetFirstComponentSimulatingPhysics(GetOwner()); MyPhysicsComponent != nullptr) if (MyPhysicsComponent = GetFirstComponentSimulatingPhysics(GetOwner()); MyPhysicsComponent != nullptr)
...@@ -72,18 +104,16 @@ void UGrabBehavior::OnActionStart(USceneComponent* TriggeredComponent, const UIn ...@@ -72,18 +104,16 @@ void UGrabBehavior::OnActionStart(USceneComponent* TriggeredComponent, const UIn
GetOwner()->GetComponents<UInteractableComponent>(Interactables, false); GetOwner()->GetComponents<UInteractableComponent>(Interactables, false);
for (UInteractableComponent* Interactable : Interactables) for (UInteractableComponent* Interactable : Interactables)
{ {
Interactable->RestrictInteractionToComponent(TriggeredComponent); Interactable->RestrictInteractionToComponent(TriggerComponent);
} }
} }
OnGrabStartEvent.Broadcast(CurrentAttachParent, MyPhysicsComponent); OnGrabStartEvent.Broadcast(CurrentAttachParent, MyPhysicsComponent);
} }
void UGrabBehavior::OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction, void UGrabBehavior::EndGrab(USceneComponent* TriggerComponent)
const FInputActionValue& Value)
{ {
USceneComponent* CurrentAttachParent = Cast<USceneComponent>(TriggerComponent->GetAttachParent());
USceneComponent* CurrentAttachParent = Cast<USceneComponent>(TriggeredComponent->GetAttachParent());
// We try to release the attached component. If it is not succesful we log and return. Otherwise, we continue. // We try to release the attached component. If it is not succesful we log and return. Otherwise, we continue.
if (!TryRelease()) if (!TryRelease())
...@@ -107,23 +137,3 @@ void UGrabBehavior::OnActionEnd(USceneComponent* TriggeredComponent, const UInpu ...@@ -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;
}
...@@ -3,14 +3,13 @@ ...@@ -3,14 +3,13 @@
#include "Interaction/Interactables/HoverBehaviour.h" #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() void UHoverBehaviour::BeginPlay()
{ {
Super::BeginPlay(); Super::BeginPlay();
OnHoverEventEvent.AddDynamic(this, &UHoverBehaviour::OnHoverEvent);
OnHoverStartEvent.AddDynamic(this, &UHoverBehaviour::OnHoverStart);
OnHoverEndEvent.AddDynamic(this, &UHoverBehaviour::OnHoverEnd);
} }
...@@ -62,7 +62,8 @@ void UIntenSelectable::HandleOnSelectStartEvents(const UIntenSelectComponent* In ...@@ -62,7 +62,8 @@ void UIntenSelectable::HandleOnSelectStartEvents(const UIntenSelectComponent* In
{ {
for (const UHoverBehaviour* CurrentHoverBehaviour : OnHoverBehaviours) 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 ...@@ -70,7 +71,9 @@ void UIntenSelectable::HandleOnSelectEndEvents(const UIntenSelectComponent* Inte
{ {
for (const UHoverBehaviour* CurrentHoverBehaviour : OnHoverBehaviours) 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 ...@@ -79,8 +82,8 @@ void UIntenSelectable::HandleOnClickStartEvents(UIntenSelectComponent* IntenSele
for (const UActionBehaviour* CurrentActionBehaviour : OnActionBehaviours) for (const UActionBehaviour* CurrentActionBehaviour : OnActionBehaviours)
{ {
FInputActionValue EmptyInputActionValue{}; FInputActionValue EmptyInputActionValue{};
const UInputAction* EmptyInputAction{}; CurrentActionBehaviour->OnActionEventEvent.Broadcast(IntenSelect, EInteractionEventType::InteractionStart,
CurrentActionBehaviour->OnActionBeginEvent.Broadcast(IntenSelect, EmptyInputAction, EmptyInputActionValue); EmptyInputActionValue);
} }
} }
...@@ -88,8 +91,8 @@ void UIntenSelectable::HandleOnClickEndEvents(UIntenSelectComponent* IntenSelect ...@@ -88,8 +91,8 @@ void UIntenSelectable::HandleOnClickEndEvents(UIntenSelectComponent* IntenSelect
{ {
for (const UActionBehaviour* CurrentActionBehaviour : OnActionBehaviours) for (const UActionBehaviour* CurrentActionBehaviour : OnActionBehaviours)
{ {
const UInputAction* EmptyInputActionValue{}; CurrentActionBehaviour->OnActionEventEvent.Broadcast(IntenSelect, EInteractionEventType::InteractionEnd,
CurrentActionBehaviour->OnActionEndEvent.Broadcast(IntenSelect, EmptyInputActionValue, InputValue); InputValue);
} }
} }
......
...@@ -4,6 +4,11 @@ ...@@ -4,6 +4,11 @@
#include "Interaction/Interactables/InteractableComponent.h" #include "Interaction/Interactables/InteractableComponent.h"
#include "Interaction/Interactables/ActionBehaviour.h" #include "Interaction/Interactables/ActionBehaviour.h"
#include "Interaction/Interactables/HoverBehaviour.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) void UInteractableComponent::RestrictInteractionToComponents(const TArray<USceneComponent*>& Components)
{ {
...@@ -39,9 +44,8 @@ void UInteractableComponent::BeginPlay() ...@@ -39,9 +44,8 @@ void UInteractableComponent::BeginPlay()
InitDefaultBehaviourReferences(); InitDefaultBehaviourReferences();
} }
// This functions dispatches the HoverStart Event to the attached Hover Behaviour Components void UInteractableComponent::HandleOnHoverEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor,
void UInteractableComponent::HandleOnHoverStartEvents(USceneComponent* TriggerComponent, const EInteractionEventType EventType)
const EInteractorType Interactor)
{ {
// We early return if there the InteractorFilter is set and the Interactor is allowed. // We early return if there the InteractorFilter is set and the Interactor is allowed.
if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor)) if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor))
...@@ -52,34 +56,44 @@ void UInteractableComponent::HandleOnHoverStartEvents(USceneComponent* TriggerCo ...@@ -52,34 +56,44 @@ void UInteractableComponent::HandleOnHoverStartEvents(USceneComponent* TriggerCo
return; return;
// Broadcast event to all HoverBehaviours // Broadcast event to all HoverBehaviours
for (const UHoverBehaviour* b : OnHoverBehaviours) for (UHoverBehaviour* HoverBehaviour : OnHoverBehaviours)
{ {
b->OnHoverStartEvent.Broadcast(TriggerComponent, HitResult); // Check if we need to replicate the action to the server
} if (HoverBehaviour->bExecuteOnServer)
}
// 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. // Request the server to execute our behaviour.
if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor)) // As we can only execute RPCs from an owned object, and we don't necessarily own this actor, pipe it
return; // through the interactor. Because behaviours can also be triggered from non-interactors, only do this on a
// successful cast
// We early return if the source Interactor is not part of the allowed components auto* InteractorComponent = Cast<UUBaseInteractionComponent>(TriggerComponent);
if (!IsComponentAllowed(TriggerComponent)) if (!InteractorComponent)
{
UE_LOGFMT(Toolkit, Warning,
"Interaction: TriggerComponent {TriggerComponent} is not a UUBaseInteractionComponent. Only "
"UUBaseInteractionComponent TriggerComponents can be replicated.",
TriggerComponent->GetName());
return; return;
}
// Broadcast event to all HoverBehaviours InteractorComponent->RequestHoverBehaviourReplicationStart(HoverBehaviour, EventType, HitResult);
for (const UHoverBehaviour* b : OnHoverBehaviours) }
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)
{ {
b->OnHoverEndEvent.Broadcast(TriggerComponent); HoverBehaviour->OnHoverEventEvent.Broadcast(TriggerComponent, EventType, HitResult);
}
} }
} }
// This functions dispatches the ActionStart Event to the attached Action Behaviour Components // This functions dispatches the ActionStart Event to the attached Action Behaviour Components
void UInteractableComponent::HandleOnActionStartEvents(USceneComponent* TriggerComponent, void UInteractableComponent::HandleOnActionEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor,
const UInputAction* InputAction, const FInputActionValue& Value, const EInteractionEventType EventType, const FInputActionValue& Value)
const EInteractorType Interactor)
{ {
// We early return if there the InteractorFilter is set and the Interactor is allowed. // We early return if there the InteractorFilter is set and the Interactor is allowed.
if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor)) if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor))
...@@ -90,28 +104,38 @@ void UInteractableComponent::HandleOnActionStartEvents(USceneComponent* TriggerC ...@@ -90,28 +104,38 @@ void UInteractableComponent::HandleOnActionStartEvents(USceneComponent* TriggerC
return; return;
// Broadcast event to all ActionBehaviours // Broadcast event to all ActionBehaviours
for (const UActionBehaviour* b : OnActionBehaviours) for (UActionBehaviour* ActionBehaviour : OnActionBehaviours)
{ {
b->OnActionBeginEvent.Broadcast(TriggerComponent, InputAction, Value); // Check if we need to replicate the action to the server
} if (ActionBehaviour->bExecuteOnServer)
}
// 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. // Request the server to execute our behaviour.
if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor)) // As we can only execute RPCs from an owned object, and we don't necessarily own this actor, pipe it
return; // through the interactor. Because behaviours can also be triggered from non-interactors, only do this on a
// successful cast
// We early return if the source Interactor is not part of the allowed components auto* InteractorComponent = Cast<UUBaseInteractionComponent>(TriggerComponent);
if (!IsComponentAllowed(TriggerComponent)) if (!InteractorComponent)
{
UE_LOGFMT(Toolkit, Warning,
"Interaction: TriggerComponent {TriggerComponent} is not a UUBaseInteractionComponent. Only "
"UUBaseInteractionComponent TriggerComponents can be replicated.",
TriggerComponent->GetName());
return; return;
}
// Broadcast event to all ActionBehaviours InteractorComponent->RequestActionBehaviourReplicationStart(ActionBehaviour, EventType, Value);
for (const UActionBehaviour* b : OnActionBehaviours) }
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)
{ {
b->OnActionEndEvent.Broadcast(TriggerComponent, InputAction, Value); ActionBehaviour->OnActionEventEvent.Broadcast(TriggerComponent, EventType, Value);
}
} }
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"
#include "Interaction/Interactables/InteractableComponent.h" #include "Interaction/Interactables/InteractableComponent.h"
#include "Interaction/Interactables/InteractionBitSet.h" #include "Interaction/Interactables/InteractionBitSet.h"
#include "Interaction/Interactables/InteractionEventType.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "Logging/StructuredLog.h" #include "Logging/StructuredLog.h"
...@@ -30,7 +31,7 @@ void UDirectInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tick ...@@ -30,7 +31,7 @@ void UDirectInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tick
TArray<FHitResult> OutHits; TArray<FHitResult> OutHits;
const ETraceTypeQuery TraceType = UEngineTypes::ConvertToTraceType(ECollisionChannel::ECC_PhysicsBody); 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(), UKismetSystemLibrary::SphereTraceMulti(GetWorld(), GetAttachParent()->GetComponentLocation(),
GetAttachParent()->GetComponentLocation(), InteractionSphereRadius, GetAttachParent()->GetComponentLocation(), InteractionSphereRadius,
...@@ -59,7 +60,8 @@ void UDirectInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tick ...@@ -59,7 +60,8 @@ void UDirectInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tick
if (!PreviousInteractableComponentsInRange.Contains(CurrentInteractableComp)) if (!PreviousInteractableComponentsInRange.Contains(CurrentInteractableComp))
{ {
PreviousInteractableComponentsInRange.AddUnique(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 ...@@ -71,7 +73,8 @@ void UDirectInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tick
if (!CurrentInteractableCompsInRange.Contains(PrevInteractableComp)) if (!CurrentInteractableCompsInRange.Contains(PrevInteractableComp))
{ {
ComponentsToRemove.AddUnique(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 ...@@ -97,12 +100,12 @@ void UDirectInteractionComponent::SetupPlayerInput(UInputComponent* PlayerInputC
return; return;
EI->BindAction(InteractionInputAction, ETriggerEvent::Started, this, EI->BindAction(InteractionInputAction, ETriggerEvent::Started, this,
&UDirectInteractionComponent::OnBeginInteraction); &UDirectInteractionComponent::OnBeginInteractionInputAction);
EI->BindAction(InteractionInputAction, ETriggerEvent::Completed, this, 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(); const FVector InteractionLocation = GetAttachParent()->GetComponentLocation();
...@@ -115,7 +118,7 @@ void UDirectInteractionComponent::OnBeginInteraction(const FInputActionValue& Va ...@@ -115,7 +118,7 @@ void UDirectInteractionComponent::OnBeginInteraction(const FInputActionValue& Va
CurrentInteractableComponentsInRange, CurrentInteractableComponentsInRange,
[&](auto Element) [&](auto Element)
{ return FVector(Element->GetOwner()->GetActorLocation() - InteractionLocation).Size(); }); { return FVector(Element->GetOwner()->GetActorLocation() - InteractionLocation).Size(); });
MinElement->HandleOnActionStartEvents(this, InteractionInputAction, Value, EInteractorType::Direct); MinElement->HandleOnActionEvents(this, EInteractorType::Direct, EInteractionEventType::InteractionStart, Value);
CurrentlyInteractedComponents = {MinElement}; CurrentlyInteractedComponents = {MinElement};
} }
else else
...@@ -124,19 +127,21 @@ void UDirectInteractionComponent::OnBeginInteraction(const FInputActionValue& Va ...@@ -124,19 +127,21 @@ void UDirectInteractionComponent::OnBeginInteraction(const FInputActionValue& Va
CurrentInteractableComponentsInRange.Num()); CurrentInteractableComponentsInRange.Num());
for (UInteractableComponent* InteractableComp : CurrentInteractableComponentsInRange) for (UInteractableComponent* InteractableComp : CurrentInteractableComponentsInRange)
{ {
InteractableComp->HandleOnActionStartEvents(this, InteractionInputAction, Value, EInteractorType::Direct); InteractableComp->HandleOnActionEvents(this, EInteractorType::Direct,
EInteractionEventType::InteractionStart, Value);
CurrentlyInteractedComponents.Add(InteractableComp); CurrentlyInteractedComponents.Add(InteractableComp);
} }
} }
} }
void UDirectInteractionComponent::OnEndInteraction(const FInputActionValue& Value) void UDirectInteractionComponent::OnEndInteractionInputAction(const FInputActionValue& Value)
{ {
for (auto& Component : CurrentlyInteractedComponents) for (auto& Component : CurrentlyInteractedComponents)
{ {
if (Component.IsValid()) if (Component.IsValid())
{ {
Component->HandleOnActionEndEvents(this, InteractionInputAction, Value, EInteractorType::Direct); Component->HandleOnActionEvents(this, EInteractorType::Direct, EInteractionEventType::InteractionStart,
Value);
} }
} }
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"
#include "Interaction/Interactables/InteractableComponent.h" #include "Interaction/Interactables/InteractableComponent.h"
#include "Interaction/Interactables/InteractionEventType.h"
#include "Kismet/KismetSystemLibrary.h" #include "Kismet/KismetSystemLibrary.h"
// Sets default values for this component's properties // Sets default values for this component's properties
...@@ -25,14 +26,13 @@ void URaycastInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tic ...@@ -25,14 +26,13 @@ void URaycastInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tic
UInteractableComponent* NewInteractableComponent = nullptr; UInteractableComponent* NewInteractableComponent = nullptr;
TArray<AActor*> ActorsToIgnore;
FHitResult Hit; FHitResult Hit;
const ETraceTypeQuery TraceType = UEngineTypes::ConvertToTraceType(ECollisionChannel::ECC_PhysicsBody); const ETraceTypeQuery TraceType = UEngineTypes::ConvertToTraceType(ECollisionChannel::ECC_PhysicsBody);
FVector TraceStart = GetAttachParent()->GetComponentLocation(); const FVector TraceStart = GetAttachParent()->GetComponentLocation();
FVector TraceEnd = GetAttachParent()->GetComponentLocation() + TraceLength * GetAttachParent()->GetForwardVector(); 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, UKismetSystemLibrary::LineTraceSingle(GetWorld(), TraceStart, TraceEnd, TraceType, true, ActorsToIgnore, DebugTrace,
Hit, true, FColor::Green); Hit, true, FColor::Green);
...@@ -53,24 +53,28 @@ void URaycastInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tic ...@@ -53,24 +53,28 @@ void URaycastInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tic
if (CurrentInteractable != PreviousInteractable) if (CurrentInteractable != PreviousInteractable)
{ {
if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast))
CurrentInteractable->HandleOnHoverStartEvents(this, EInteractorType::Raycast); CurrentInteractable->HandleOnHoverEvents(this, EInteractorType::Raycast,
EInteractionEventType::InteractionStart);
if (PreviousInteractable && PreviousInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) if (PreviousInteractable && PreviousInteractable->HasInteractionTypeFlag(EInteractorType::Raycast))
PreviousInteractable->HandleOnHoverEndEvents(this, EInteractorType::Raycast); PreviousInteractable->HandleOnHoverEvents(this, EInteractorType::Raycast,
EInteractionEventType::InteractionEnd);
} }
PreviousInteractable = CurrentInteractable; PreviousInteractable = CurrentInteractable;
} }
void URaycastInteractionComponent::OnBeginInteraction(const FInputActionValue& Value) void URaycastInteractionComponent::OnBeginInteractionInputAction(const FInputActionValue& Value)
{ {
if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) 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)) 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) void URaycastInteractionComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent)
...@@ -86,7 +90,7 @@ void URaycastInteractionComponent::SetupPlayerInput(UInputComponent* PlayerInput ...@@ -86,7 +90,7 @@ void URaycastInteractionComponent::SetupPlayerInput(UInputComponent* PlayerInput
return; return;
EI->BindAction(InteractionInputAction, ETriggerEvent::Started, this, EI->BindAction(InteractionInputAction, ETriggerEvent::Started, this,
&URaycastInteractionComponent::OnBeginInteraction); &URaycastInteractionComponent::OnBeginInteractionInputAction);
EI->BindAction(InteractionInputAction, ETriggerEvent::Completed, this, EI->BindAction(InteractionInputAction, ETriggerEvent::Completed, this,
&URaycastInteractionComponent::OnEndInteraction); &URaycastInteractionComponent::OnEndInteractionInputAction);
} }
// 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);
}
...@@ -3,21 +3,18 @@ ...@@ -3,21 +3,18 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "InputAction.h" #include "BaseBehaviour.h"
#include "Components/SceneComponent.h" #include "Components/SceneComponent.h"
#include "InputActionValue.h" #include "InputActionValue.h"
#include "InteractionBitSet.h"
#include "ActionBehaviour.generated.h" #include "ActionBehaviour.generated.h"
enum EInteractionEventType : uint8;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnActionBegin, USceneComponent*, TriggeredComponent, DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnActionBegin, USceneComponent*, TriggerComponent,
const UInputAction*, InputAction, const FInputActionValue&, Value); const EInteractionEventType, EventType, const FInputActionValue&, Value);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnActionEnd, USceneComponent*, TriggeredComponent, const UInputAction*,
InputAction, const FInputActionValue&, Value);
UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class RWTHVRTOOLKIT_API UActionBehaviour : public USceneComponent class RWTHVRTOOLKIT_API UActionBehaviour : public UBaseBehaviour
{ {
GENERATED_BODY() GENERATED_BODY()
...@@ -26,22 +23,12 @@ public: ...@@ -26,22 +23,12 @@ public:
UActionBehaviour(); UActionBehaviour();
UPROPERTY(BlueprintAssignable) UPROPERTY(BlueprintAssignable)
FOnActionBegin OnActionBeginEvent; FOnActionBegin OnActionEventEvent;
UPROPERTY(BlueprintAssignable)
FOnActionEnd OnActionEndEvent;
protected: protected:
UFUNCTION() 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); const FInputActionValue& Value);
virtual void BeginPlay() override; virtual void BeginPlay() override;
virtual void TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction) override;
}; };
// 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;
};
...@@ -23,11 +23,8 @@ public: ...@@ -23,11 +23,8 @@ public:
UPROPERTY(EditAnywhere, Category = "Grabbing") UPROPERTY(EditAnywhere, Category = "Grabbing")
bool bBlockOtherInteractionsWhileGrabbed = true; bool bBlockOtherInteractionsWhileGrabbed = true;
virtual void OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction, virtual void OnActionEvent(USceneComponent* TriggerComponent, const EInteractionEventType EventType,
const FInputActionValue& Value) override; 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 * Called after the object was successfully attached to the hand
...@@ -61,6 +58,10 @@ private: ...@@ -61,6 +58,10 @@ private:
*/ */
bool TryRelease(); bool TryRelease();
void StartGrab(USceneComponent* TriggerComponent);
void EndGrab(USceneComponent* TriggerComponent);
bool bObjectGrabbed = false; bool bObjectGrabbed = false;
bool bWasSimulatingPhysics; bool bWasSimulatingPhysics;
......
...@@ -3,16 +3,16 @@ ...@@ -3,16 +3,16 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "BaseBehaviour.h"
#include "InteractionEventType.h"
#include "Components/SceneComponent.h" #include "Components/SceneComponent.h"
#include "HoverBehaviour.generated.h" #include "HoverBehaviour.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnHoverEvent, const USceneComponent*, TriggeredComponent,
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnHoverStart, const USceneComponent*, TriggeredComponent, FHitResult, const EInteractionEventType, EventType, const FHitResult&, Hit);
Hit);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHoverEnd, const USceneComponent*, TriggeredComponent);
UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class RWTHVRTOOLKIT_API UHoverBehaviour : public USceneComponent class RWTHVRTOOLKIT_API UHoverBehaviour : public UBaseBehaviour
{ {
GENERATED_BODY() GENERATED_BODY()
...@@ -22,16 +22,12 @@ public: ...@@ -22,16 +22,12 @@ public:
* VRPawn) Hit: Hit Result of the trace to get access to e.g. contact point/normals etc. * VRPawn) Hit: Hit Result of the trace to get access to e.g. contact point/normals etc.
*/ */
UPROPERTY(BlueprintAssignable) UPROPERTY(BlueprintAssignable)
FOnHoverStart OnHoverStartEvent; FOnHoverEvent OnHoverEventEvent;
UPROPERTY(BlueprintAssignable)
FOnHoverEnd OnHoverEndEvent;
protected: protected:
UFUNCTION() UFUNCTION()
virtual void OnHoverStart(const USceneComponent* TriggeredComponent, FHitResult Hit); virtual void OnHoverEvent(const USceneComponent* TriggerComponent, EInteractionEventType EventType,
UFUNCTION() const FHitResult& Hit);
virtual void OnHoverEnd(const USceneComponent* TriggeredComponent);
virtual void BeginPlay() override; virtual void BeginPlay() override;
}; };
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include "InteractableComponent.generated.h" #include "InteractableComponent.generated.h"
enum EInteractionEventType : uint8;
class UBaseBehaviour;
struct FInputActionValue; struct FInputActionValue;
class UActionBehaviour; class UActionBehaviour;
class UHoverBehaviour; class UHoverBehaviour;
...@@ -53,7 +55,7 @@ public: ...@@ -53,7 +55,7 @@ public:
bool bAllowInteractionFromChildGeometry = true; bool bAllowInteractionFromChildGeometry = true;
UFUNCTION(BlueprintCallable) 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 * @brief Restrict interactability to given components (e.g. if an object is grabbed, block interactions from other
...@@ -74,12 +76,10 @@ protected: ...@@ -74,12 +76,10 @@ protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
public: public:
void HandleOnHoverStartEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor); void HandleOnHoverEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor,
void HandleOnHoverEndEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor); const EInteractionEventType EventType);
void HandleOnActionStartEvents(USceneComponent* TriggerComponent, const UInputAction* InputAction, void HandleOnActionEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor,
const FInputActionValue& Value, const EInteractorType Interactor); const EInteractionEventType EventType, const FInputActionValue& Value);
void HandleOnActionEndEvents(USceneComponent* TriggerComponent, const UInputAction* InputAction,
const FInputActionValue& Value, const EInteractorType Interactor);
/** /**
* @brief If hover and action behaviors are not explicitly specified, load all existing ones * @brief If hover and action behaviors are not explicitly specified, load all existing ones
......
#pragma once
UENUM(BlueprintType)
enum EInteractionEventType : uint8
{
InteractionStart = 0,
InteractionEnd = 1,
};
...@@ -3,13 +3,13 @@ ...@@ -3,13 +3,13 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "UBaseInteractionComponent.h"
#include "Components/SceneComponent.h" #include "Components/SceneComponent.h"
#include "Interaction/Interactables/InteractableComponent.h" #include "Interaction/Interactables/InteractableComponent.h"
#include "Pawn/InputExtensionInterface.h"
#include "DirectInteractionComponent.generated.h" #include "DirectInteractionComponent.generated.h"
UCLASS(Abstract, Blueprintable) UCLASS(Abstract, Blueprintable)
class RWTHVRTOOLKIT_API UDirectInteractionComponent : public USceneComponent, public IInputExtensionInterface class RWTHVRTOOLKIT_API UDirectInteractionComponent : public UUBaseInteractionComponent
{ {
GENERATED_BODY() GENERATED_BODY()
...@@ -20,29 +20,18 @@ public: ...@@ -20,29 +20,18 @@ public:
virtual void TickComponent(float DeltaTime, ELevelTick TickType, virtual void TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction) override; FActorComponentTickFunction* ThisTickFunction) override;
UPROPERTY(EditAnywhere, Category = "Input")
class UInputAction* InteractionInputAction;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction") UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction")
float InteractionSphereRadius = 15.0; float InteractionSphereRadius = 15.0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction")
bool bShowDebugTrace = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction") UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction")
bool bOnlyInteractWithClosestActor = false; bool bOnlyInteractWithClosestActor = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction")
TArray<AActor*> ActorsToIgnore;
virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override; virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override;
private: private:
UFUNCTION() virtual void OnBeginInteractionInputAction(const FInputActionValue& Value) override;
void OnBeginInteraction(const FInputActionValue& Value);
UFUNCTION() virtual void OnEndInteractionInputAction(const FInputActionValue& Value) override;
void OnEndInteraction(const FInputActionValue& Value);
UPROPERTY() UPROPERTY()
TArray<UInteractableComponent*> PreviousInteractableComponentsInRange; TArray<UInteractableComponent*> PreviousInteractableComponentsInRange;
......
...@@ -2,16 +2,15 @@ ...@@ -2,16 +2,15 @@
#pragma once #pragma once
#include <Pawn/InputExtensionInterface.h>
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "UBaseInteractionComponent.h"
#include "Components/SceneComponent.h" #include "Components/SceneComponent.h"
#include "Interaction/Interactables/InteractableComponent.h" #include "Interaction/Interactables/InteractableComponent.h"
#include "RaycastInteractionComponent.generated.h" #include "RaycastInteractionComponent.generated.h"
UCLASS(Abstract, Blueprintable) UCLASS(Abstract, Blueprintable)
class RWTHVRTOOLKIT_API URaycastInteractionComponent : public USceneComponent, public IInputExtensionInterface class RWTHVRTOOLKIT_API URaycastInteractionComponent : public UUBaseInteractionComponent
{ {
GENERATED_BODY() GENERATED_BODY()
...@@ -23,20 +22,13 @@ public: ...@@ -23,20 +22,13 @@ public:
virtual void TickComponent(float DeltaTime, ELevelTick TickType, virtual void TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction) override; FActorComponentTickFunction* ThisTickFunction) override;
UPROPERTY(EditAnywhere, Category = "Input")
class UInputAction* InteractionInputAction;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Raycast") UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Raycast")
float TraceLength = 3000.0; float TraceLength = 3000.0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Raycast")
bool bShowDebugTrace = false;
private: private:
UFUNCTION() virtual void OnBeginInteractionInputAction(const FInputActionValue& Value) override;
void OnBeginInteraction(const FInputActionValue& Value);
UFUNCTION() virtual void OnEndInteractionInputAction(const FInputActionValue& Value) override;
void OnEndInteraction(const FInputActionValue& Value);
public: public:
virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override; virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override;
......
// 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);
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment