// Copyright Epic Games, Inc. All Rights Reserved. #include "LyraWeaponInstance.h" #include "GameFramework/Pawn.h" #include "Engine/World.h" #include "Math/UnrealMathUtility.h" #include "Misc/AssertionMacros.h" #include "GameFramework/InputDeviceSubsystem.h" #include "GameFramework/InputDeviceProperties.h" #include "Character/LyraHealthComponent.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(LyraWeaponInstance) class UAnimInstance; struct FGameplayTagContainer; ULyraWeaponInstance::ULyraWeaponInstance(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { // Listen for death of the owning pawn so that any device properties can be removed if we // die and can't unequip if (APawn* Pawn = GetPawn()) { // We only need to do this for player controlled pawns, since AI and others won't have input devices on the client if (Pawn->IsPlayerControlled()) { if (ULyraHealthComponent* HealthComponent = ULyraHealthComponent::FindHealthComponent(GetPawn())) { HealthComponent->OnDeathStarted.AddDynamic(this, &ThisClass::OnDeathStarted); } } } } void ULyraWeaponInstance::OnEquipped() { Super::OnEquipped(); UWorld* World = GetWorld(); check(World); TimeLastEquipped = World->GetTimeSeconds(); ApplyDeviceProperties(); } void ULyraWeaponInstance::OnUnequipped() { Super::OnUnequipped(); RemoveDeviceProperties(); } void ULyraWeaponInstance::UpdateFiringTime() { UWorld* World = GetWorld(); check(World); TimeLastFired = World->GetTimeSeconds(); } float ULyraWeaponInstance::GetTimeSinceLastInteractedWith() const { UWorld* World = GetWorld(); check(World); const double WorldTime = World->GetTimeSeconds(); double Result = WorldTime - TimeLastEquipped; if (TimeLastFired > 0.0) { const double TimeSinceFired = WorldTime - TimeLastFired; Result = FMath::Min(Result, TimeSinceFired); } return Result; } TSubclassOf ULyraWeaponInstance::PickBestAnimLayer(bool bEquipped, const FGameplayTagContainer& CosmeticTags) const { const FLyraAnimLayerSelectionSet& SetToQuery = (bEquipped ? EquippedAnimSet : UneuippedAnimSet); return SetToQuery.SelectBestLayer(CosmeticTags); } const FPlatformUserId ULyraWeaponInstance::GetOwningUserId() const { if (const APawn* Pawn = GetPawn()) { return Pawn->GetPlatformUserId(); } return PLATFORMUSERID_NONE; } void ULyraWeaponInstance::ApplyDeviceProperties() { const FPlatformUserId UserId = GetOwningUserId(); if (UserId.IsValid()) { if (UInputDeviceSubsystem* InputDeviceSubsystem = UInputDeviceSubsystem::Get()) { for (TObjectPtr& DeviceProp : ApplicableDeviceProperties) { FActivateDevicePropertyParams Params = {}; Params.UserId = UserId; // By default, the device property will be played on the Platform User's Primary Input Device. // If you want to override this and set a specific device, then you can set the DeviceId parameter. //Params.DeviceId = ; // Don't remove this property it was evaluated. We want the properties to be applied as long as we are holding the // weapon, and will remove them manually in OnUnequipped Params.bLooping = true; DevicePropertyHandles.Emplace(InputDeviceSubsystem->ActivateDeviceProperty(DeviceProp, Params)); } } } } void ULyraWeaponInstance::RemoveDeviceProperties() { const FPlatformUserId UserId = GetOwningUserId(); if (UserId.IsValid() && !DevicePropertyHandles.IsEmpty()) { // Remove any device properties that have been applied if (UInputDeviceSubsystem* InputDeviceSubsystem = UInputDeviceSubsystem::Get()) { InputDeviceSubsystem->RemoveDevicePropertyHandles(DevicePropertyHandles); DevicePropertyHandles.Empty(); } } } void ULyraWeaponInstance::OnDeathStarted(AActor* OwningActor) { // Remove any possibly active device properties when we die to make sure that there aren't any lingering around RemoveDeviceProperties(); }