// Copyright ExByte Studios. Item Interaction Ecosystem. #pragma once #include "CoreMinimal.h" #include "Components/ActorComponent.h" #include "InteractionTraceComponent.generated.h" class UInteractableComponent; DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInteractionTargetChanged, AActor*, NewTarget, UInteractableComponent*, NewInteractable); /** * Local-only aim trace that finds the best interactable under the crosshair * (section 8.2). Runs only on the owning client; the result drives the prompt UI * and is what the player confirms - never trusted by the server. */ UCLASS(ClassGroup = (Interaction), meta = (BlueprintSpawnableComponent)) class ITEMINTERACTION_API UInteractionTraceComponent : public UActorComponent { GENERATED_BODY() public: UInteractionTraceComponent(); virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; /** Fires the trace once and updates CurrentTarget. */ UFUNCTION(BlueprintCallable, Category = "Interaction") void TickTrace(); UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction") float TraceDistance = 300.f; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction") float TraceRadius = 12.f; /** Trace channel; defaults to Visibility. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction") TEnumAsByte TraceChannel = ECC_Visibility; UPROPERTY(BlueprintReadOnly, Category = "Interaction") TObjectPtr CurrentTarget = nullptr; UPROPERTY(BlueprintReadOnly, Category = "Interaction") TObjectPtr CurrentInteractable = nullptr; UPROPERTY(BlueprintReadOnly, Category = "Interaction") FVector LastHitLocation = FVector::ZeroVector; UPROPERTY(BlueprintReadOnly, Category = "Interaction") FVector LastHitNormal = FVector::ZeroVector; UPROPERTY(BlueprintAssignable, Category = "Interaction") FOnInteractionTargetChanged OnTargetChanged; private: bool GetViewPoint(FVector& OutLocation, FRotator& OutRotation) const; void SetTarget(AActor* NewTarget, UInteractableComponent* NewInteractable); };