diff --git a/Content/BP_UHL_BlueprintNode.uasset b/Content/BP_UHL_BlueprintNode.uasset new file mode 100644 index 0000000..e1bb2e1 Binary files /dev/null and b/Content/BP_UHL_BlueprintNode.uasset differ diff --git a/Content/BP_UHL_BlueprintNodes.uasset b/Content/BP_UHL_BlueprintNodes.uasset deleted file mode 100644 index 04db4e6..0000000 Binary files a/Content/BP_UHL_BlueprintNodes.uasset and /dev/null differ diff --git a/README.md b/README.md index 8158719..933ed0f 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,11 @@ UHL consists of 3 modules: > - [TurnTo](#turnto) > - [Subsystems](#subsystems) > - [DebugSubsystem](#debugsubsystem) +> - [UHLHUD](#uhlhud) > - [UnrealHelperLibraryBPL](#unrealhelperlibrarybpl) +> - Gameplay +> - GetActorClosestToCenterOfScreen +> - GetMostDistantActor > - GAS > - TryActivateAbilityWithTag > - TryCancelAbilityWithTag @@ -122,6 +126,8 @@ UHL consists of 3 modules: > - [GetPointAtAngleRelativeToOtherActor](#getpointatanglerelativetootheractor) > - [GetPointAtDirectionRelativeToOtherActor](#getpointatdirectionrelativetootheractor) > - [DirectionToAngle](#directiontoangle) +> - UI/Screen +> - GetViewportSizeUnscaled > - Misc > - [GetProjectVersion](#getprojectversion) > - [GetNamesOfComponentsOnObject](#getnamesofcomponentsonobject) @@ -129,6 +135,8 @@ UHL consists of 3 modules: > - GetBuildType > > +> - Debug +> - DrawDebugLineOnCanvas > - Other > - [GetHighestPoint](#gethighestpoint) > - [LoadingUtilLibrary](#loadingutillibrary) @@ -141,7 +149,7 @@ UHL consists of 3 modules: > - [TraceUtilsBPL](#traceutilsbpl) > - SweepCapsuleSingleByChannel > - [Settings](#settings) -> - [UHL Settings](#) +> - [UHL Settings](#uhl-settings) **UnrealHelperEditor** @@ -647,6 +655,22 @@ void AUHLPlayerController::BeginPlay() How to add DebugCategory: 1) +How to subscribe on debug category change in C++ + +```c++ + UAA_WaitDebugCategoryChange* WaitDebugCategoryChangeTask = UAA_WaitDebugCategoryChange::WaitDebugCategoryChange( + Actor->GetWorld(), + YourGameplayTags::TAG_DebugCategory_Combat // same as FGameplayTag("DebugCategory.Something") + ); + WaitDebugCategoryChangeTask->OnChange.AddUniqueDynamic(this, &UCombatSubsystem::OnDebugCategoryChanged); + // on activation "OnDebugCategoryChanged" will be fired + WaitDebugCategoryChangeTask->Activate(); +``` + +#### UHLHUD + +HUD with debugging abilities, for now used to display debug bars(e.g. HP/hidden attributes) + ### LoadingUtilLibrary **UHLLoadingUtilLibrary** - loading utils from Lyra @@ -684,7 +708,11 @@ if you don't want to copy paste your `AttributeSets` **Custom thumnails** - to override thumbnail by your own, just implement `IUHECustomThumbnail` interface and define your own icon using `GetCustomThumbnailIcon()` +> [!WARNING] +> ⚠️ NOT sure that blueprints supported for now + ```C++ +// UInventoryItem.h #if WITH_EDITOR #include "UHECustomThumbnail.h" #endif @@ -697,19 +725,23 @@ class IUHECustomThumbnail {}; class GAMECODE_API UInventoryItem : public UObject, public IUHECustomThumbnail { -// ... - - /** IUHECustomThumbnail **/ +/** IUHECustomThumbnail **/ #if WITH_EDITOR - UFUNCTION(BlueprintCallable, BlueprintNativeEvent) - UTexture2D* GetCustomThumbnailIcon() { return Description.Icon; }; + virtual UTexture2D* GetCustomThumbnailIcon_Implementation() const override; #endif /** ~IUHECustomThumbnail **/ +} -// ... -``` +------------------------------------------------------------------ -⚠️ for now works only with C++, TODO add support for blueprints +// UInventoryItem.cpp +#if WITH_EDITOR +UTexture2D* UInventoryItem::GetCustomThumbnailIcon_Implementation() +{ + return Description.Icon; +} +#endif +``` Thanks to [this post](https://forums.unrealengine.com/t/custom-thumbnail-not-display-asset-is-never-loaded/143155/2?u=ciberus) and [this](https://forums.unrealengine.com/t/custom-thumbnail-on-blueprint/337532/3?u=ciberus) diff --git a/Source/UnrealHelperEditor/Private/UHECustomThumbnail.cpp b/Source/UnrealHelperEditor/Private/UHECustomThumbnail.cpp index ec3c7c8..6acf479 100644 --- a/Source/UnrealHelperEditor/Private/UHECustomThumbnail.cpp +++ b/Source/UnrealHelperEditor/Private/UHECustomThumbnail.cpp @@ -5,4 +5,9 @@ // Add default functionality here for any IUHECustomThumbnail functions that are not pure virtual. -#include UE_INLINE_GENERATED_CPP_BY_NAME(UHECustomThumbnail) \ No newline at end of file +#include UE_INLINE_GENERATED_CPP_BY_NAME(UHECustomThumbnail) + +UTexture2D* IUHECustomThumbnail::GetCustomThumbnailIcon_Implementation() const +{ + return nullptr; +} \ No newline at end of file diff --git a/Source/UnrealHelperEditor/Private/UnrealHelperEditorStyle.cpp b/Source/UnrealHelperEditor/Private/UnrealHelperEditorStyle.cpp index 44b5de7..fc6cf9a 100644 --- a/Source/UnrealHelperEditor/Private/UnrealHelperEditorStyle.cpp +++ b/Source/UnrealHelperEditor/Private/UnrealHelperEditorStyle.cpp @@ -53,16 +53,25 @@ TSharedRef< FSlateStyleSet > FUnrealHelperEditorStyle::Create() FString Path = CustomClassIcon.Texture2D.GetLongPackageName(); UObject* IconImageObject = LoadObject(nullptr, *Path); - if (IsValid(IconImageObject) && IsValid(CustomClassIcon.Class)) + if (IsValid(IconImageObject)) { UTexture2D* IconImage = Cast(IconImageObject); // FSlateDynamicImageBrush* DynamicImageBrush = new FSlateDynamicImageBrush(IconImage, Icon20x20, FName("CapsuleHitRegistrator")); FSlateImageBrush* ImageBrush = new FSlateImageBrush(IconImage, Icon20x20); - FString ClassName = CustomClassIcon.Class->GetName(); - // Modify the class icons to use our new awesome icons - FString IconStyleName = FString::Printf(TEXT("ClassIcon.%s"), *ClassName); - Style->Set(FName(IconStyleName), ImageBrush); + TArray> AllClasses = CustomClassIcon.Classes; + // support deprecated value + if (IsValid(CustomClassIcon.Class)) + { + AllClasses.Add(CustomClassIcon.Class); + } + for (const TSubclassOf Class : AllClasses) + { + FString ClassName = Class->GetName(); + // Modify the class icons to use our new awesome icons + FString IconStyleName = FString::Printf(TEXT("ClassIcon.%s"), *ClassName); + Style->Set(FName(IconStyleName), ImageBrush); + } } } diff --git a/Source/UnrealHelperEditor/Public/Development/UHESettings.h b/Source/UnrealHelperEditor/Public/Development/UHESettings.h index 6aa20bd..b4aa52d 100644 --- a/Source/UnrealHelperEditor/Public/Development/UHESettings.h +++ b/Source/UnrealHelperEditor/Public/Development/UHESettings.h @@ -13,8 +13,11 @@ struct UNREALHELPEREDITOR_API FUHECustomClassIconDescription UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="CustomClassIconDescription") TSoftObjectPtr Texture2D; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="CustomClassIconDescription") + // deprecated, TODO: remove + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="CustomClassIconDescription", meta=(DeprecatedProperty, DeprecationMessage="Deprecated use Classes")) TSubclassOf Class; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="CustomClassIconDescription") + TArray> Classes; }; /** diff --git a/Source/UnrealHelperEditor/Public/UHECustomThumbnail.h b/Source/UnrealHelperEditor/Public/UHECustomThumbnail.h index 85f5e93..d4ca2d4 100644 --- a/Source/UnrealHelperEditor/Public/UHECustomThumbnail.h +++ b/Source/UnrealHelperEditor/Public/UHECustomThumbnail.h @@ -25,6 +25,7 @@ class UNREALHELPEREDITOR_API IUHECustomThumbnail /** IUHECustomThumbnail **/ UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="Custom Thumbnail") - UTexture2D* GetCustomThumbnailIcon(); + UTexture2D* GetCustomThumbnailIcon() const; + virtual UTexture2D* GetCustomThumbnailIcon_Implementation() const; /** ~IUHECustomThumbnail **/ }; diff --git a/Source/UnrealHelperLibrary/Private/AbilitySystem/UHLAbilitySystemComponent.cpp b/Source/UnrealHelperLibrary/Private/AbilitySystem/UHLAbilitySystemComponent.cpp index 7634378..99defbe 100644 --- a/Source/UnrealHelperLibrary/Private/AbilitySystem/UHLAbilitySystemComponent.cpp +++ b/Source/UnrealHelperLibrary/Private/AbilitySystem/UHLAbilitySystemComponent.cpp @@ -366,12 +366,9 @@ void UUHLAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGame { if (!bUseInputConfig) return; - // TODO: mb check how Lyra use that tag? if (HasMatchingGameplayTag(UHLGameplayTags::TAG_Gameplay_AbilityInputBlocked)) { - InputPressedSpecHandles.Reset(); - InputReleasedSpecHandles.Reset(); - InputHeldSpecHandles.Reset(); + ClearAbilityInput(); return; } @@ -389,8 +386,7 @@ void UUHLAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGame { if (AbilitySpec->Ability && !AbilitySpec->IsActive()) { - const UUHLGameplayAbility* AbilityCDO = CastChecked(AbilitySpec->Ability); - + const UUHLGameplayAbility* AbilityCDO = Cast(AbilitySpec->Ability); if (AbilityCDO->GetActivationPolicy() == EUHLAbilityActivationPolicy::WhileInputActive) { AbilitiesToActivate.AddUnique(AbilitySpec->Handle); @@ -410,30 +406,25 @@ void UUHLAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGame { AbilitySpec->InputPressed = true; - // TODO: если абилка активна, нужно пытаться все равно ее активировать, а не просто данные слать - // If ability active, we should try to activate it again, instead of sending data - - // if (AbilitySpec->IsActive()) - // { - // // Ability is active so pass along the input event. - // AbilitySpecInputPressed(*AbilitySpec); - // } - // else - // { - const UUHLGameplayAbility* AbilityCDO = CastChecked(AbilitySpec->Ability); - - if (AbilityCDO->GetActivationPolicy() == EUHLAbilityActivationPolicy::OnInputTriggered) + const UUHLGameplayAbility* AbilityCDO = Cast(AbilitySpec->Ability); + if (AbilitySpec->IsActive() + // TODO move this logic to "OnInputTriggeredForceReactivate" ?? + // If ability active, we should try to activate it again, instead of sending data + // so that's why if "OnInputTriggered" choosed - skip + && AbilityCDO + && AbilityCDO->GetActivationPolicy() != EUHLAbilityActivationPolicy::OnInputTriggered) { - AbilitiesToActivate.AddUnique(AbilitySpec->Handle); - - // TODO: testing - // if (AbilitySpec->IsActive()) - // { - // Ability is active so pass along the input event. - AbilitySpecInputPressed(*AbilitySpec); - // } + // Ability is active so pass along the input event. + AbilitySpecInputPressed(*AbilitySpec); } - // } + else + { + // const UUHLGameplayAbility* AbilityCDO = Cast(AbilitySpec->Ability); + if (AbilityCDO && AbilityCDO->GetActivationPolicy() == EUHLAbilityActivationPolicy::OnInputTriggered) + { + AbilitiesToActivate.AddUnique(AbilitySpec->Handle); + } + } } } } @@ -502,6 +493,19 @@ void UUHLAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGame { // Ability is active so pass along the input event. AbilitySpecInputReleased(*AbilitySpec); + + // if "WhileInputActive" EndAbility automatically + // const UUHLGameplayAbility* AbilityCDO = Cast(AbilitySpec->Ability); + // if (AbilityCDO && AbilityCDO->GetActivationPolicy() == EUHLAbilityActivationPolicy::WhileInputActive) + // { + // const FUHLWhileInputActiveSettings& WhileInputActiveSettings = AbilityCDO->GetWhileInputActiveSettings(); + // if (WhileInputActiveSettings.bCancelAbilityAutomatically) + // { + // // "EndAbility" not accessible, so try to cancel if "bCancelAbilityAutomatically" + // AbilitySpec->Ability->CancelAbility(AbilitySpec->Handle, AbilityActorInfo.Get(), AbilitySpec->ActivationInfo, WhileInputActiveSettings.bReplicateEndAbility); + // // AbilitySpec->Ability->EndAbility(AbilitySpec->Handle, AbilityActorInfo.Get(), AbilitySpec->ActivationInfo, WhileInputActiveSettings.bReplicateEndAbility, WhileInputActiveSettings.bMarkAsCanceledOnEnd); + // } + // } } } } @@ -513,3 +517,10 @@ void UUHLAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGame InputPressedSpecHandles.Reset(); InputReleasedSpecHandles.Reset(); } + +void UUHLAbilitySystemComponent::ClearAbilityInput() +{ + InputPressedSpecHandles.Reset(); + InputReleasedSpecHandles.Reset(); + InputHeldSpecHandles.Reset(); +} diff --git a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_ActivateAbility.cpp b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_ActivateAbility.cpp index f2b4689..670a74a 100644 --- a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_ActivateAbility.cpp +++ b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_ActivateAbility.cpp @@ -49,9 +49,7 @@ void UANS_ActivateAbility::NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequ void UANS_ActivateAbility::OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupted) { - if (!bDeactivateOnMontageBlendingOut - || !CurrentAnimMontage.IsValid() - || Montage != CurrentAnimMontage) + if (!bDeactivateOnMontageBlendingOut || !Montage) { return; } diff --git a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp index f927568..60bb4dc 100644 --- a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp +++ b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp @@ -6,40 +6,115 @@ #include "GameFramework/Character.h" #include "GameFramework/CharacterMovementComponent.h" #include "Animation/AnimInstance.h" +#include "Components/CapsuleComponent.h" #include "Components/SkeletalMeshComponent.h" +#include "Utils/UHLTraceUtilsBPL.h" +#include "Utils/UnrealHelperLibraryBPL.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(ANS_EnableRootMotionZAxisMovement) +UANS_EnableRootMotionZAxisMovement::UANS_EnableRootMotionZAxisMovement(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + LandCheckBlendOutSettings = FMontageBlendSettings(); + LandCheckBlendOutSettings.Blend = 1.0f; + LandCheckBlendOutSettings.BlendMode = EMontageBlendMode::Inertialization; +} + void UANS_EnableRootMotionZAxisMovement::NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration, const FAnimNotifyEventReference& EventReference) { Super::NotifyBegin(MeshComp, Animation, TotalDuration, EventReference); - BaseCharacter = Cast(MeshComp->GetOwner()); - if (!BaseCharacter.IsValid()) return; + ACharacter* BaseCharacter = Cast(MeshComp->GetOwner()); + if (!BaseCharacter) return; UCharacterMovementComponent* MovementComponent = BaseCharacter->GetCharacterMovement(); InitialMovementMode = MovementComponent->MovementMode; MovementComponent->SetMovementMode(MOVE_Flying); - - BaseCharacter->GetMesh()->GetAnimInstance()->OnMontageBlendingOut.AddUniqueDynamic(this, &UANS_EnableRootMotionZAxisMovement::OnMontageBlendingOut); } -void UANS_EnableRootMotionZAxisMovement::NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference) +void UANS_EnableRootMotionZAxisMovement::NotifyEndOrBlendOut(USkeletalMeshComponent* MeshComp) { - Super::NotifyEnd(MeshComp, Animation, EventReference); + Super::NotifyEndOrBlendOut(MeshComp); - if (!BaseCharacter.IsValid()) return; + if (!MeshComp) return; - BaseCharacter->GetMesh()->GetAnimInstance()->OnMontageBlendingOut.RemoveDynamic(this, &UANS_EnableRootMotionZAxisMovement::OnMontageBlendingOut); -} + ACharacter* BaseCharacter = Cast(MeshComp->GetOwner()); + if (!BaseCharacter) return; + + UCharacterMovementComponent* MovementComponent = BaseCharacter->GetCharacterMovement(); + if (MovementComponent->MovementMode == MOVE_Flying) + { + MovementComponent->SetMovementMode(MOVE_Falling); + } -void UANS_EnableRootMotionZAxisMovement::OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupted) -{ - if (!BaseCharacter.IsValid()) return; + // 1) land до окончания, когда например запрыгиваем куда-то - + // а OnLanded в этом случае вообще будет работать, кмк - нет. + // Значит нужно чекать самостоятельно "land" и на MOVE_Falling переключать? + // UPD вообще не нужно ничо чекать, ANS должен закончится до/вовремя Land'а + // а значит никаких проблем с этим нет + // 2) ANS кончился а мы при этом не приземлились на землю и до земли далеко + // нужно Stop'ить montage, а для этого сделать sweep test капсулы вниз + if (bStopMontageIfLandCheckFails) + { + FVector CurrentLocation = BaseCharacter->GetActorLocation(); + FVector EndLocation = CurrentLocation + FVector(0.0f, 0.0f, -LandCheckDistance); - UCharacterMovementComponent* MovementComponent = BaseCharacter->GetCharacterMovement(); - if (MovementComponent->MovementMode == MOVE_Flying) - { - MovementComponent->SetMovementMode(MOVE_Falling); - } + FCollisionQueryParams CollisionParams; + CollisionParams.AddIgnoredActor(BaseCharacter); + // ignore all attached actors + TArray CharacterAttachedActors; + BaseCharacter->GetAttachedActors(CharacterAttachedActors, false, true); + + FHitResult HitResult; + // TODO use Sphere instead of capsule + bool bHasHit = UUHLTraceUtilsBPL::SweepCapsuleSingleByChannel( + BaseCharacter->GetWorld(), + HitResult, + CurrentLocation, + EndLocation, + BaseCharacter->GetCapsuleComponent()->GetScaledCapsuleRadius(), + BaseCharacter->GetCapsuleComponent()->GetScaledCapsuleHalfHeight(), + BaseCharacter->GetActorRotation().Quaternion(), + CollisionChannel, + CollisionParams, + FCollisionResponseParams::DefaultResponseParam, + bDebug, + 5.0f, + FColor::Red, + FColor::Yellow, + 0.2f + ); + + if (!bHasHit) + { + // TODO try stop specific montage + // const UAnimMontage* AnimMontage = CurrentAnimMontage.Get(); + // BaseCharacter->StopAnimMontage(); + FAnimMontageInstance* AnimMontage = BaseCharacter->GetRootMotionAnimMontageInstance(); + if (AnimMontage && AnimMontage->IsValid()) + { + AnimMontage->PushDisableRootMotion(); + AnimMontage->Stop(LandCheckBlendOutSettings, false); + } + else + { + UUnrealHelperLibraryBPL::DebugPrintString( + BaseCharacter->GetWorld(), + FString::Printf(TEXT("UANS_EnableRootMotionZAxisMovement::NotifyEndOrBlendOut on %s error root motion AnimMontage not found"), *BaseCharacter->GetName()) + ); + } + } + else + { + if (HitResult.IsValidBlockingHit() && bDebug) + { + DrawDebugString( + BaseCharacter->GetWorld(), HitResult.Location, FString::Printf(TEXT("Land check: %s"), + *HitResult.GetActor()->GetName()), nullptr, + FColor::Green, 5.0f, true, 1.0f + ); + } + } + } } diff --git a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp index 3a510ef..ec8ea5d 100644 --- a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp +++ b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp @@ -2,8 +2,8 @@ #include "Animation/Notifies/ANS_UHL_Base.h" -#include "Animation/AnimInstance.h" -#include "Animation/AnimMontage.h" +// #include "Animation/AnimInstance.h" +#include "Runtime/Engine/Classes/Animation/AnimMontage.h" #include "Engine/World.h" #include "Components/SkeletalMeshComponent.h" @@ -13,9 +13,9 @@ void UANS_UHL_Base::NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceB { Super::NotifyBegin(MeshComp, Animation, TotalDuration, EventReference); - CurrentAnimMontage = EventReference.GetNotify()->GetLinkedMontage(); + const UAnimMontage* CurrentAnimMontage = EventReference.GetNotify()->GetLinkedMontage(); - if (CurrentAnimMontage.IsValid()) + if (CurrentAnimMontage) { if (bUseOnMontageBlendingOut) { @@ -28,17 +28,38 @@ void UANS_UHL_Base::NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBas { Super::NotifyEnd(MeshComp, Animation, EventReference); + if (ShouldUseExperimentalUHLFeatures()) + { + NotifyEndOrBlendOut(MeshComp); + } + if (bUseOnMontageBlendingOut) { MeshComp->AnimScriptInstance->OnMontageBlendingOut.RemoveDynamic(this, &UANS_UHL_Base::OnMontageBlendingOut); } } +/** Experimental **/ +void UANS_UHL_Base::NotifyEndOrBlendOut(USkeletalMeshComponent* MeshComp) +{ + if (!ShouldUseExperimentalUHLFeatures()) return; +} +/** ~Experimental **/ + void UANS_UHL_Base::OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupted) { - if (!CurrentAnimMontage.IsValid() - || Montage != CurrentAnimMontage) + if (!Montage) { return; } + + if (ShouldUseExperimentalUHLFeatures()) + { + UObject* Outer = Montage->GetOuter(); + USkeletalMeshComponent* SkeletalMeshComponent = Cast(Outer); + if (SkeletalMeshComponent) + { + NotifyEndOrBlendOut(SkeletalMeshComponent); + } + } } diff --git a/Source/UnrealHelperLibrary/Private/Subsystems/DebugSubsystem/UHLDebugSubsystem.cpp b/Source/UnrealHelperLibrary/Private/Subsystems/DebugSubsystem/UHLDebugSubsystem.cpp index df8864b..8f35061 100644 --- a/Source/UnrealHelperLibrary/Private/Subsystems/DebugSubsystem/UHLDebugSubsystem.cpp +++ b/Source/UnrealHelperLibrary/Private/Subsystems/DebugSubsystem/UHLDebugSubsystem.cpp @@ -128,6 +128,7 @@ void UUHLDebugSubsystem::EnableDebugCategory(const FGameplayTag DebugCategoryTag for (const FUHLDebugCategory& DebugCategory : DebugCategories) { if (DebugCategory != *UHLDebugCategory + && !UHLDebugCategory->Blocks.IsEmpty() && DebugCategory.Tags.HasAny(UHLDebugCategory->Blocks)) { EnableDebugCategory(DebugCategory.Tags.First(), false); diff --git a/Source/UnrealHelperLibrary/Private/UI/UHLHUD.cpp b/Source/UnrealHelperLibrary/Private/UI/UHLHUD.cpp new file mode 100644 index 0000000..54c3dae --- /dev/null +++ b/Source/UnrealHelperLibrary/Private/UI/UHLHUD.cpp @@ -0,0 +1,49 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "UI/UHLHUD.h" + +#include "Blueprint/WidgetLayoutLibrary.h" +#include "Utils/UnrealHelperLibraryBPL.h" + +void AUHLHUD::DrawHUD() +{ + Super::DrawHUD(); + + if (!bEnabledDrawDebug) return; + + FVector2D ViewportSize = UWidgetLayoutLibrary::GetViewportSize(GetWorld()); + FVector2D ViewportSizeOffset = ViewportSize / 2; + + // FVector2f Test; + // UUnrealHelperLibraryBPL::DrawDebugCrossHair(GetWorld(), 100.0f, 3.0f, 0.0f, Test, FLinearColor::Red); + + for (const FLineInfo& LineInfo : LineInfos) + { + FVector2D StartPos = LineInfo.Start; + FVector2D EndPos = LineInfo.End; + if (LineInfo.bRelativeToViewportCenter) + { + StartPos += ViewportSizeOffset; + EndPos += ViewportSizeOffset; + } + DrawLine( + StartPos.X, StartPos.Y, + EndPos.X, EndPos.Y, + LineInfo.Color, + LineInfo.LineThickness + ); + FVector2D TextPos = (EndPos - StartPos) + ViewportSizeOffset; + + DrawText(LineInfo.Text, FColor::Red, TextPos.X, TextPos.Y); + } + LineInfos.RemoveAll([=](const FLineInfo& LineInfo) + { + return !LineInfo.bPersistent; + }); +} + +void AUHLHUD::AddOrUpdateLineInfoToDrawNextTick(FLineInfo LineInfo_In) +{ + LineInfos.Add(LineInfo_In); +} \ No newline at end of file diff --git a/Source/UnrealHelperLibrary/Private/Utils/UHLTraceUtilsBPL.cpp b/Source/UnrealHelperLibrary/Private/Utils/UHLTraceUtilsBPL.cpp index 3950dae..ee81af4 100644 --- a/Source/UnrealHelperLibrary/Private/Utils/UHLTraceUtilsBPL.cpp +++ b/Source/UnrealHelperLibrary/Private/Utils/UHLTraceUtilsBPL.cpp @@ -44,6 +44,39 @@ bool UUHLTraceUtilsBPL::SweepCapsuleSingleByChannel(const UWorld* World, FHitRes return bResult; } +bool UUHLTraceUtilsBPL::SweepCapsuleMultiByChannel(const UWorld* World, TArray& OutHits, const FVector& Start, const FVector& End, float Radius, float HalfHeight, const FQuat& Rot, + ECollisionChannel TraceChannel, const FCollisionQueryParams& Params, const FCollisionResponseParams& ResponseParam, bool bDrawDebug, float DrawTime, FColor TraceColor, FColor HitColor, float FailDrawTime) +{ + bool bResult = false; + + FailDrawTime = FailDrawTime == -1.0f ? DrawTime : FailDrawTime; + + FCollisionShape CollisionShape = FCollisionShape::MakeCapsule(Radius, HalfHeight); + bResult = World->SweepMultiByChannel(OutHits, Start, End, Rot, TraceChannel, CollisionShape, Params, ResponseParam); + +#if ENABLE_DRAW_DEBUG + if (bDrawDebug) + { + DrawDebugCapsule(World, Start, HalfHeight, Radius, Rot, TraceColor, false, bResult ? DrawTime : FailDrawTime); + DrawDebugCapsule(World, End, HalfHeight, Radius, Rot, TraceColor, false, bResult ? DrawTime : FailDrawTime); + DrawDebugLine(World, Start, End, TraceColor, false, bResult ? DrawTime : FailDrawTime); + + if (bResult) + { + float Thickness = FMath::Clamp(HalfHeight / 100, 1.25, 5); + for (const FHitResult& OutHit : OutHits) + { + // UUnrealHelperLibraryBPLibrary::DebugPrintStrings(FString::Printf(TEXT("%f"), Thickness)); + DrawDebugPoint(World, OutHit.ImpactPoint, 10.0f, HitColor, false, DrawTime, 0); + DrawDebugCapsule(World, OutHit.Location, HalfHeight, Radius, Rot, TraceColor, false, DrawTime, 0, Thickness); + } + } + } +#endif + + return bResult; +} + bool UUHLTraceUtilsBPL::SweepCapsuleMultiByProfile(const UWorld* World, TArray& OutHits, const FVector& Start, const FVector& End, float Radius, float HalfHeight, const FQuat& Rot, FName ProfileName, diff --git a/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp b/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp index c4137fd..2dae609 100644 --- a/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp +++ b/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp @@ -26,9 +26,12 @@ #include "Misc/ConfigCacheIni.h" #include "Animation/AnimMontage.h" #include "DrawDebugHelpers.h" +#include "Blueprint/WidgetLayoutLibrary.h" #include "Engine/World.h" #include "Engine/GameInstance.h" +#include "GameFramework/HUD.h" #include "Subsystems/DebugSubsystem/UHLDebugSubsystem.h" +#include "UI/UHLHUD.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(UnrealHelperLibraryBPL) @@ -317,6 +320,127 @@ EUHLDirection UUnrealHelperLibraryBPL::GetHitReactDirection(const FVector& Sourc return EUHLDirection::Left; } +FVector2D UUnrealHelperLibraryBPL::GetViewportSizeUnscaled(UObject* WorldContextObject) +{ + FVector2D ViewportSize = UWidgetLayoutLibrary::GetViewportSize(WorldContextObject); + float ViewportScale = UWidgetLayoutLibrary::GetViewportScale(WorldContextObject); + FVector2D ViewportSizeUnscaled = ViewportSize / ViewportScale; + return ViewportSizeUnscaled; +} + +AActor* UUnrealHelperLibraryBPL::GetActorClosestToCenterOfScreen(UObject* WorldContextObject, const TArray& Actors, APlayerController* PlayerController, FVector WorldLocation, FVector2D& ScreenPosition, bool bPlayerViewportRelative, const bool bDebug, const float DebugLifetime) +{ + bool bRelativeToViewportCenter = false; + AActor* Result = nullptr; + FVector2D ResultScreenPosition = FVector2D(133700.322, 133700.322); + float ResultDistance = FVector2D::Distance(ResultScreenPosition, FVector2D::ZeroVector); + float ViewportScale = UWidgetLayoutLibrary::GetViewportScale(WorldContextObject); + FVector2D ViewportSize = UWidgetLayoutLibrary::GetViewportSize(WorldContextObject); + FVector2D ViewportSizeUnscaled = GetViewportSizeUnscaled(WorldContextObject); + + for (AActor* Actor : Actors) + { + FVector2D CurrentActorScreenPosition; + UWidgetLayoutLibrary::ProjectWorldLocationToWidgetPosition(PlayerController, Actor->GetActorLocation(), CurrentActorScreenPosition, true); + float CurrentDistance = FVector2D::Distance(CurrentActorScreenPosition, ViewportSizeUnscaled / 2); + + if (CurrentDistance < ResultDistance) + { + ResultDistance = CurrentDistance; + Result = Actor; + } + + if (bDebug) + { + FLineInfo LineInfo = { + "TestLine" + Actor->GetName(), + ViewportSize / 2, + CurrentActorScreenPosition * ViewportScale, + FColor::MakeRandomColor(), + 5, + "" + Actor->GetName() + " " + FString::SanitizeFloat(CurrentDistance), + FColor::Blue, + bRelativeToViewportCenter, + true, + }; + DrawDebugLineOnCanvas(Actor->GetWorld(), LineInfo, bRelativeToViewportCenter); + } + } + + ScreenPosition = ResultScreenPosition; + return Result; +} + +AActor* UUnrealHelperLibraryBPL::GetMostDistantActor(const TArray& Actors, float& MaxDistance_Out, FVector Location, const bool bDebug, const float DebugLifetime) +{ + AActor* Result = nullptr; + float GreatestDistance = -9999999; + TMap ActorsAndDistances = {}; + + for (AActor* Actor : Actors) + { + float Distance = FVector::Distance(Actor->GetActorLocation(), Location); + ActorsAndDistances.Add(Actor, Distance); + if (Distance > GreatestDistance) + { + GreatestDistance = Distance; + Result = Actor; + MaxDistance_Out = Distance; + } + } + + if (bDebug) + { + for (const TTuple& ActorWithDist : ActorsAndDistances) + { + bool bMostDistant = Result == ActorWithDist.Key; + DrawDebugLine(ActorWithDist.Key->GetWorld(), ActorWithDist.Key->GetActorLocation(), Location, bMostDistant ? FColor::Green : FColor::Red, false, DebugLifetime, -1, 2.0f); + DrawDebugString(ActorWithDist.Key->GetWorld(), FVector::ZeroVector, FString::Printf(TEXT("Distance: %.2f"), ActorWithDist.Value), ActorWithDist.Key, bMostDistant ? FColor::Green : FColor::Red, 0, true, 1); + } + } + + return Result; +} + +void UUnrealHelperLibraryBPL::DrawDebugLineOnCanvas(UObject* WorldContextObject, const FLineInfo& LineInfo, const bool bRelativeToViewportCenter) +{ + const UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(WorldContextObject); + const APlayerController* PlayerController = GameInstance->GetFirstLocalPlayerController(WorldContextObject->GetWorld()); + AUHLHUD* HUD = PlayerController->GetHUD(); + if (!IsValid(HUD)) return; + + HUD->AddOrUpdateLineInfoToDrawNextTick(LineInfo); +} + +void UUnrealHelperLibraryBPL::DrawDebugCrossHair( + UObject* WorldContextObject, + const float CrossHairLineLength, + const float LineThickness, + const float AngleToRotate, + const FVector2f& CrossHairCenterScreenSpace, + const FLinearColor& LineColor, + const bool bRelativeToViewportCenter + ) +{ + const UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(WorldContextObject); + const APlayerController* PlayerController = GameInstance->GetFirstLocalPlayerController(WorldContextObject->GetWorld()); + AUHLHUD* HUD = PlayerController->GetHUD(); + if (!IsValid(HUD)) return; + + FLineInfo LineInfo = { + "TestLine", + FVector2D(0, 0), + FVector2D(200, 500), + FColor::Red, + 2, + "Test123", + FColor::Blue, + bRelativeToViewportCenter, + true, + }; + DrawDebugLineOnCanvas(WorldContextObject, LineInfo, bRelativeToViewportCenter); +} + UActorComponent* UUnrealHelperLibraryBPL::GetActorComponentByName(AActor* Actor, FString Name) { if (!IsValid(Actor)) diff --git a/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h b/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h index df74c6f..a277eb0 100644 --- a/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h +++ b/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h @@ -50,7 +50,7 @@ class UNREALHELPERLIBRARY_API UUHLGameplayAbility : public UGameplayAbility GENERATED_BODY() public: - UFUNCTION(BlueprintCallable, Category = "UHL GameplayAbility") + UFUNCTION(BlueprintCallable, Category = "UHL GameplayAbility") EUHLAbilityActivationPolicy GetActivationPolicy() const { return ActivationPolicy; } // UFUNCTION(BlueprintCallable) diff --git a/Source/UnrealHelperLibrary/Public/AbilitySystem/UHLAbilitySystemComponent.h b/Source/UnrealHelperLibrary/Public/AbilitySystem/UHLAbilitySystemComponent.h index 4af249d..f6b0d1e 100644 --- a/Source/UnrealHelperLibrary/Public/AbilitySystem/UHLAbilitySystemComponent.h +++ b/Source/UnrealHelperLibrary/Public/AbilitySystem/UHLAbilitySystemComponent.h @@ -105,6 +105,8 @@ class UNREALHELPERLIBRARY_API UUHLAbilitySystemComponent : public UAbilitySystem /** Input Config **/ void ProcessAbilityInput(float DeltaTime, bool bGamePaused); + void ClearAbilityInput(); + virtual void AbilitySpecInputPressed(FGameplayAbilitySpec& Spec) override; virtual void AbilitySpecInputReleased(FGameplayAbilitySpec& Spec) override; virtual void AbilityInputTagPressed(const FGameplayTag InputTag); diff --git a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_ActivateAbility.h b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_ActivateAbility.h index 9d9feb7..ecb24bb 100644 --- a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_ActivateAbility.h +++ b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_ActivateAbility.h @@ -42,6 +42,7 @@ class UNREALHELPERLIBRARY_API UANS_ActivateAbility : public UANS_UHL_Base virtual void OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupted) override; private: + // TODO check ANS's should be stateless!? TWeakInterfacePtr ActorWithASC; UFUNCTION() diff --git a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.h b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.h index d0576f2..c3a2626 100644 --- a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.h +++ b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.h @@ -3,6 +3,7 @@ #pragma once #include "CoreMinimal.h" +#include "ANS_UHL_Base.h" #include "Animation/AnimNotifies/AnimNotifyState.h" #include "Engine/EngineTypes.h" #include "ANS_EnableRootMotionZAxisMovement.generated.h" @@ -10,15 +11,33 @@ class ACharacter; /** + * Usefull for root motion jumps (characters/enemies) * + * Enables MOVE_Flying mode during ANS, + * on end if movement mode is still MOVE_Flying - changes it on MOVE_Falling + * + * if "bStopMontageIfLandCheckFails" - stops montage if land check failed on NotifyEnd */ UCLASS() -class UNREALHELPERLIBRARY_API UANS_EnableRootMotionZAxisMovement : public UAnimNotifyState +class UNREALHELPERLIBRARY_API UANS_EnableRootMotionZAxisMovement : public UANS_UHL_Base { GENERATED_BODY() public: - + UANS_EnableRootMotionZAxisMovement(const FObjectInitializer& ObjectInitializer); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="EnableRootMotionZAxisMovement") + bool bStopMontageIfLandCheckFails = false; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="EnableRootMotionZAxisMovement", meta=(EditCondition = "bStopMontageIfLandCheckFails", EditConditionHides)) + float LandCheckDistance = 50.0f; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="EnableRootMotionZAxisMovement", meta=(EditCondition = "bStopMontageIfLandCheckFails", EditConditionHides)) + TEnumAsByte CollisionChannel = ECC_Pawn; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="EnableRootMotionZAxisMovement", meta=(EditCondition = "bStopMontageIfLandCheckFails", EditConditionHides)) + FMontageBlendSettings LandCheckBlendOutSettings; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, AdvancedDisplay, Category="EnableRootMotionZAxisMovement") + bool bDebug = false; + #if WITH_EDITOR /** Override this to prevent firing this notify state type in animation editors */ virtual bool ShouldFireInEditor() { return false; } @@ -28,12 +47,10 @@ class UNREALHELPERLIBRARY_API UANS_EnableRootMotionZAxisMovement : public UAnimN virtual FString GetNotifyName_Implementation() const override { return FString("EnableRootMotionZAxisMovement"); }; virtual void NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration, const FAnimNotifyEventReference& EventReference) override; - virtual void NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference) override; + virtual bool ShouldUseExperimentalUHLFeatures() const override { return true; }; + virtual void NotifyEndOrBlendOut(USkeletalMeshComponent* MeshComp) override; + private: - TWeakObjectPtr BaseCharacter; EMovementMode InitialMovementMode = EMovementMode::MOVE_None; - - UFUNCTION() - void OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupted); }; diff --git a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_UHL_Base.h b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_UHL_Base.h index 0ef69d3..ad35f17 100644 --- a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_UHL_Base.h +++ b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_UHL_Base.h @@ -6,7 +6,7 @@ #include "Animation/AnimNotifies/AnimNotifyState.h" #include "ANS_UHL_Base.generated.h" -class UAnimMontage; +class USkeletalMeshComponent; /** * with events like OnMontageBlendOut, OnMontageInterrupted... @@ -21,11 +21,16 @@ class UNREALHELPERLIBRARY_API UANS_UHL_Base : public UAnimNotifyState UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="ANS_UHL_Base") bool bUseOnMontageBlendingOut = true; - TWeakObjectPtr CurrentAnimMontage; - virtual void NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration, const FAnimNotifyEventReference& EventReference) override; virtual void NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference) override; +/** Experimental **/ + // Should use experimental features like "NotifyEndOrBlendOut" + virtual bool ShouldUseExperimentalUHLFeatures() const { return false; }; + // experimental works only with "ShouldUseExperimentalUHLFeatures" enabled + virtual void NotifyEndOrBlendOut(USkeletalMeshComponent* MeshComp); +/** ~Experimental **/ + UFUNCTION() virtual void OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupted); // TODO OnMontageBlendOut, OnMontageInterrupted, OnCancelled ... diff --git a/Source/UnrealHelperLibrary/Public/Subsystems/DebugSubsystem/UHLDebugCategory.h b/Source/UnrealHelperLibrary/Public/Subsystems/DebugSubsystem/UHLDebugCategory.h index f0662fe..a805342 100644 --- a/Source/UnrealHelperLibrary/Public/Subsystems/DebugSubsystem/UHLDebugCategory.h +++ b/Source/UnrealHelperLibrary/Public/Subsystems/DebugSubsystem/UHLDebugCategory.h @@ -53,8 +53,8 @@ struct FUHLDebugCategory // ~"FColor::MakeRandomColor()" will lead to non-critical error // ~unreal don't support random colors from native code. // ~They should be deterministic but there is no option - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UHLDebugCategory", AdvancedDisplay) - FLinearColor Color = FLinearColor::Black; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UHLDebugCategory", AdvancedDisplay, meta = (IgnoreForMemberInitializationTest)) + FLinearColor Color = FColor::MakeRandomColor(); UPROPERTY() bool bIsDefaultUHLDebugCategory = false; diff --git a/Source/UnrealHelperLibrary/Public/UI/UHLHUD.h b/Source/UnrealHelperLibrary/Public/UI/UHLHUD.h new file mode 100644 index 0000000..fa0a254 --- /dev/null +++ b/Source/UnrealHelperLibrary/Public/UI/UHLHUD.h @@ -0,0 +1,51 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/HUD.h" +#include "UHLHUD.generated.h" + +USTRUCT(BlueprintType) +struct FLineInfo +{ + GENERATED_BODY() + + FString Id = ""; + FVector2D Start = FVector2D::ZeroVector; + FVector2D End = FVector2D::ZeroVector; + FColor Color = FColor::White; + float LineThickness = 1.0f; + + FString Text = ""; + FColor TextColor = FColor::White; + + bool bRelativeToViewportCenter = false; + bool bPersistent = false; + +// private: +// float TimePassed = 0.0f; +}; + +/** + * + */ +UCLASS() +class UNREALHELPERLIBRARY_API AUHLHUD : public AHUD +{ + GENERATED_BODY() + +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite) + bool bEnabledDrawDebug = true; + + UFUNCTION(BlueprintCallable) + void AddOrUpdateLineInfoToDrawNextTick(FLineInfo LineInfo_In); + +protected: + virtual void DrawHUD() override; + +private: + UPROPERTY() + TArray LineInfos; +}; diff --git a/Source/UnrealHelperLibrary/Public/Utils/UHLTraceUtilsBPL.h b/Source/UnrealHelperLibrary/Public/Utils/UHLTraceUtilsBPL.h index f49f5df..8015bc1 100644 --- a/Source/UnrealHelperLibrary/Public/Utils/UHLTraceUtilsBPL.h +++ b/Source/UnrealHelperLibrary/Public/Utils/UHLTraceUtilsBPL.h @@ -23,6 +23,13 @@ class UNREALHELPERLIBRARY_API UUHLTraceUtilsBPL : public UBlueprintFunctionLibra const FCollisionResponseParams& ResponseParam, bool bDrawDebug = false, float DrawTime = -1.0f, FColor TraceColor = FColor::Black, FColor HitColor = FColor::Red, float FailDrawTime = -1.0f); + static bool SweepCapsuleMultiByChannel(const UWorld* World, TArray& OutHits, const FVector& Start, + const FVector& End, float Radius, float HalfHeight, const FQuat& Rot, + ECollisionChannel TraceChannel, const FCollisionQueryParams& Params, + const FCollisionResponseParams& ResponseParam, bool bDrawDebug = false, + float DrawTime = -1.0f, FColor TraceColor = FColor::Black, + FColor HitColor = FColor::Red, float FailDrawTime = -1.0f); + static bool SweepSphereSingleByChannel(const UWorld* World, struct FHitResult& OutHit, const FVector& Start, const FVector& End, float Radius, ECollisionChannel TraceChannel, const FCollisionQueryParams& Params, diff --git a/Source/UnrealHelperLibrary/Public/Utils/UnrealHelperLibraryBPL.h b/Source/UnrealHelperLibrary/Public/Utils/UnrealHelperLibraryBPL.h index 7ebd06e..1299af5 100644 --- a/Source/UnrealHelperLibrary/Public/Utils/UnrealHelperLibraryBPL.h +++ b/Source/UnrealHelperLibrary/Public/Utils/UnrealHelperLibraryBPL.h @@ -7,6 +7,7 @@ #include "AssetRegistry/AssetData.h" #include "AssetRegistry/AssetRegistryModule.h" #include "Kismet/BlueprintFunctionLibrary.h" +#include "UI/UHLHUD.h" #include "UnrealHelperLibraryBPL.generated.h" struct FBlackboardKeySelector; @@ -50,6 +51,31 @@ class UNREALHELPERLIBRARY_API UUnrealHelperLibraryBPL : public UBlueprintFunctio // - bool bUse8Directions UFUNCTION(BlueprintPure, Category = "UnrealHelperLibrary") static EUHLDirection GetHitReactDirection(const FVector& SourceActorLocation, const AActor* TargetActor); + + UFUNCTION(BlueprintPure, Category = "UnrealHelperLibrary", meta = (WorldContext = "WorldContextObject", Keywords = "UnrealHelperLibrary ui widget editor viewport")) + static FVector2D GetViewportSizeUnscaled(UObject* WorldContextObject); + // UFUNCTION(BlueprintPure, Category = "UnrealHelperLibrary") + // static bool ProjectWorldLocationToWidgetPositionWithScales(APlayerController* PlayerController, FVector WorldLocation, FVector2D& ViewportPosition, bool bPlayerViewportRelative); + UFUNCTION(BlueprintPure, Category = "UnrealHelperLibrary", meta = (WorldContext = "WorldContextObject")) + static AActor* GetActorClosestToCenterOfScreen(UObject* WorldContextObject, const TArray& Actors, APlayerController* PlayerController, FVector WorldLocation, FVector2D& ScreenPosition, bool bPlayerViewportRelative = true, const bool bDebug = false, const float DebugLifetime = -1); + UFUNCTION(BlueprintPure, Category = "UnrealHelperLibrary") + static AActor* GetMostDistantActor(const TArray& Actors, float& MaxDistance_Out, FVector Location, const bool bDebug = false, const float DebugLifetime = -1); + + UFUNCTION(BlueprintPure, Category = "UnrealHelperLibrary") + static void DrawDebugLineOnCanvas( + UObject* WorldContextObject, + const FLineInfo& LineInfo, + const bool bRelativeToViewportCenter = false + ); + UFUNCTION(BlueprintPure, Category = "UnrealHelperLibrary") + static void DrawDebugCrossHair( + UObject* WorldContextObject, + const float CrossHairLineLength, const float LineThickness, + const float AngleToRotate, + const FVector2f& CrossHairCenterScreenSpace, + const FLinearColor& LineColor, + const bool bRelativeToViewportCenter = false + ); /** Gameplay **/ /** Debug **/