From 0ccb5e0c97459de1ec2736ef3c5fe31a1daad311 Mon Sep 17 00:00:00 2001 From: Ciberus Date: Mon, 14 Oct 2024 17:59:52 +0300 Subject: [PATCH 01/23] [InputSystem] try to fix "WhileInputActive"(not possible), "OnInputTriggered" fix activation while ability already active --- .../UHLAbilitySystemComponent.cpp | 66 +++++++++++-------- .../Abilities/UHLGameplayAbility.h | 29 ++++++-- .../AbilitySystem/UHLAbilitySystemComponent.h | 2 + 3 files changed, 64 insertions(+), 33 deletions(-) diff --git a/Source/UnrealHelperLibrary/Private/AbilitySystem/UHLAbilitySystemComponent.cpp b/Source/UnrealHelperLibrary/Private/AbilitySystem/UHLAbilitySystemComponent.cpp index 645e5b7..d752032 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,24 @@ 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() + // 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 +492,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 +516,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/Public/AbilitySystem/Abilities/UHLGameplayAbility.h b/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h index 3e4c9c0..06f1211 100644 --- a/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h +++ b/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h @@ -18,17 +18,29 @@ enum class EUHLAbilityActivationPolicy : uint8 { // Try to activate the ability when the input is triggered. OnInputTriggered, - - // Don't work, known issue, fix will come soon, - // for now just use "WaitInputRelease" in GameplayAbility to check when input released and "EndAbility" - // - // Continually try to activate the ability while the input is active. To cancel ability use WaitInputRelease + + // Continually try to activate the ability while the input is active. + // Subscribe on "WaitInputRelease" and "EndAbility" in blueprint, + // it's not possible to EndAbility from C++ WhileInputActive, // Try to activate the ability when an avatar is assigned. OnSpawn }; +// USTRUCT(BlueprintType) +// struct FUHLWhileInputActiveSettings +// { +// GENERATED_BODY() +// +// UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) +// bool bCancelAbilityAutomatically = true; +// UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) +// bool bReplicateEndAbility = true; +// // UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) +// // bool bMarkAsCanceledOnEnd = false; +// }; + /** * */ @@ -38,8 +50,12 @@ class UNREALHELPERLIBRARY_API UUHLGameplayAbility : public UGameplayAbility GENERATED_BODY() public: + UFUNCTION(BlueprintCallable) EUHLAbilityActivationPolicy GetActivationPolicy() const { return ActivationPolicy; } + // UFUNCTION(BlueprintCallable) + // FUHLWhileInputActiveSettings GetWhileInputActiveSettings() const { return WhileInputActiveSettings; } + // should cache input if ability can't be activated for now // Requirements: // - ASC should enable "bUseAbilityInputCache" @@ -63,6 +79,9 @@ class UNREALHELPERLIBRARY_API UUHLGameplayAbility : public UGameplayAbility // Defines how this ability is meant to activate. UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) EUHLAbilityActivationPolicy ActivationPolicy = EUHLAbilityActivationPolicy::OnInputTriggered; + + // UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(EditCondition="ActivationPolicy == EUHLAbilityActivationPolicy::WhileInputActive", EditConditionHides)) + // FUHLWhileInputActiveSettings WhileInputActiveSettings; virtual void OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) override; virtual void OnRemoveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) override; diff --git a/Source/UnrealHelperLibrary/Public/AbilitySystem/UHLAbilitySystemComponent.h b/Source/UnrealHelperLibrary/Public/AbilitySystem/UHLAbilitySystemComponent.h index 4368f81..310394d 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); From dec5186b40671114159e4c796fc40b9a2b1ff01f Mon Sep 17 00:00:00 2001 From: Ciberus Date: Tue, 15 Oct 2024 18:35:23 +0300 Subject: [PATCH 02/23] [Docs] BlueprintNodes --- Content/BP_UHL_BlueprintNode.uasset | Bin 0 -> 154342 bytes Content/BP_UHL_BlueprintNodes.uasset | Bin 43227 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Content/BP_UHL_BlueprintNode.uasset delete mode 100644 Content/BP_UHL_BlueprintNodes.uasset diff --git a/Content/BP_UHL_BlueprintNode.uasset b/Content/BP_UHL_BlueprintNode.uasset new file mode 100644 index 0000000000000000000000000000000000000000..e1bb2e108ac3ab684c9890c01c671130aa51198c GIT binary patch literal 154342 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 a{)tI=1$~Lk#B+ngU#QsEo4mWw{r>^TfIx-- literal 0 HcmV?d00001 diff --git a/Content/BP_UHL_BlueprintNodes.uasset b/Content/BP_UHL_BlueprintNodes.uasset deleted file mode 100644 index 04db4e678217964c462d77850c978b5bd0ade1b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43227 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 Date: Wed, 16 Oct 2024 09:30:07 +0300 Subject: [PATCH 03/23] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 052e90f..839fecb 100644 --- a/README.md +++ b/README.md @@ -81,8 +81,8 @@ UHL consists of 3 modules: > - AnimNotifyState (ANS) > - [ANS_UHL_Base](#ans_uhl_base) > - [ANS_ActivateAbility](#ans_activateability) - - +> +> > - [AI](#ai) > - Components > - [AIPerceptionComponent](#uhlaiperceptioncomponent) @@ -141,7 +141,7 @@ UHL consists of 3 modules: > - [TraceUtilsBPL](#traceutilsbpl) > - SweepCapsuleSingleByChannel > - [Settings](#settings) -> - [UHL Settings](#) +> - [UHL Settings](#uhl-settings) **UnrealHelperEditor** From 693c6eb0d35f38670276cae45c6993c28cfa412f Mon Sep 17 00:00:00 2001 From: Ciberus Date: Wed, 16 Oct 2024 10:24:10 +0300 Subject: [PATCH 04/23] Update UHLAbilitySystemComponent.cpp --- .../Private/AbilitySystem/UHLAbilitySystemComponent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/UnrealHelperLibrary/Private/AbilitySystem/UHLAbilitySystemComponent.cpp b/Source/UnrealHelperLibrary/Private/AbilitySystem/UHLAbilitySystemComponent.cpp index d752032..7ff0416 100644 --- a/Source/UnrealHelperLibrary/Private/AbilitySystem/UHLAbilitySystemComponent.cpp +++ b/Source/UnrealHelperLibrary/Private/AbilitySystem/UHLAbilitySystemComponent.cpp @@ -408,6 +408,7 @@ void UUHLAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGame 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 From 34fc2a51c14911165bebd9e6a46f419d95aee753 Mon Sep 17 00:00:00 2001 From: Ciberus Date: Thu, 17 Oct 2024 10:40:28 +0300 Subject: [PATCH 05/23] [DebugSubsystem] check Blocks not empty --- .../Private/Subsystems/DebugSubsystem/UHLDebugSubsystem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/UnrealHelperLibrary/Private/Subsystems/DebugSubsystem/UHLDebugSubsystem.cpp b/Source/UnrealHelperLibrary/Private/Subsystems/DebugSubsystem/UHLDebugSubsystem.cpp index ef29303..3e96f0f 100644 --- a/Source/UnrealHelperLibrary/Private/Subsystems/DebugSubsystem/UHLDebugSubsystem.cpp +++ b/Source/UnrealHelperLibrary/Private/Subsystems/DebugSubsystem/UHLDebugSubsystem.cpp @@ -127,6 +127,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); From 97ad95398740683ba1a9b3a9d98db3f6a6142124 Mon Sep 17 00:00:00 2001 From: Ciberus Date: Fri, 25 Oct 2024 17:08:25 +0300 Subject: [PATCH 06/23] [Anim] ANS_UHL_Base add ShouldUseExperimentalUHLFeatures, NotifyEndOrBlendOut --- .../ANS_EnableRootMotionZAxisMovement.cpp | 25 ++++++------------- .../Animation/Notifies/ANS_UHL_Base.cpp | 22 ++++++++++++++++ .../ANS_EnableRootMotionZAxisMovement.h | 12 ++++----- .../Public/Animation/Notifies/ANS_UHL_Base.h | 10 ++++++++ 4 files changed, 45 insertions(+), 24 deletions(-) diff --git a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp index f927568..29d0d2f 100644 --- a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp +++ b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp @@ -20,26 +20,15 @@ void UANS_EnableRootMotionZAxisMovement::NotifyBegin(USkeletalMeshComponent* Mes 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); - - if (!BaseCharacter.IsValid()) return; - - BaseCharacter->GetMesh()->GetAnimInstance()->OnMontageBlendingOut.RemoveDynamic(this, &UANS_EnableRootMotionZAxisMovement::OnMontageBlendingOut); -} + Super::NotifyEndOrBlendOut(MeshComp); -void UANS_EnableRootMotionZAxisMovement::OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupted) -{ - if (!BaseCharacter.IsValid()) return; - - UCharacterMovementComponent* MovementComponent = BaseCharacter->GetCharacterMovement(); - if (MovementComponent->MovementMode == MOVE_Flying) - { - MovementComponent->SetMovementMode(MOVE_Falling); - } + UCharacterMovementComponent* MovementComponent = BaseCharacter->GetCharacterMovement(); + if (MovementComponent->MovementMode == MOVE_Flying) + { + MovementComponent->SetMovementMode(MOVE_Falling); + } } diff --git a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp index 3a510ef..cbb767b 100644 --- a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp +++ b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp @@ -13,6 +13,11 @@ void UANS_UHL_Base::NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceB { Super::NotifyBegin(MeshComp, Animation, TotalDuration, EventReference); + if (ShouldUseExperimentalUHLFeatures()) + { + MeshCompRef = MeshComp; + } + CurrentAnimMontage = EventReference.GetNotify()->GetLinkedMontage(); if (CurrentAnimMontage.IsValid()) @@ -28,12 +33,24 @@ void UANS_UHL_Base::NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBas { Super::NotifyEnd(MeshComp, Animation, EventReference); + if (ShouldUseExperimentalUHLFeatures()) + { + NotifyEndOrBlendOut(MeshCompRef.Get()); + } + 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() @@ -41,4 +58,9 @@ void UANS_UHL_Base::OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupte { return; } + + if (ShouldUseExperimentalUHLFeatures()) + { + NotifyEndOrBlendOut(MeshCompRef.Get()); + } } diff --git a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.h b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.h index d0576f2..7620979 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" @@ -13,7 +14,7 @@ class ACharacter; * */ UCLASS() -class UNREALHELPERLIBRARY_API UANS_EnableRootMotionZAxisMovement : public UAnimNotifyState +class UNREALHELPERLIBRARY_API UANS_EnableRootMotionZAxisMovement : public UANS_UHL_Base { GENERATED_BODY() @@ -28,12 +29,11 @@ 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; + TWeakObjectPtr BaseCharacter = nullptr; 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..e80b539 100644 --- a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_UHL_Base.h +++ b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_UHL_Base.h @@ -7,6 +7,7 @@ #include "ANS_UHL_Base.generated.h" class UAnimMontage; +class USkeletalMeshComponent; /** * with events like OnMontageBlendOut, OnMontageInterrupted... @@ -21,11 +22,20 @@ 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 **/ + TWeakObjectPtr MeshCompRef; + // 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 ... From be5fa31c6562cf017c6878b0aa1e1b43ea84bbec Mon Sep 17 00:00:00 2001 From: Ciberus Date: Mon, 28 Oct 2024 11:01:15 +0300 Subject: [PATCH 07/23] ANS_EnableRootMotionZAxisMovement land check --- .../ANS_EnableRootMotionZAxisMovement.cpp | 70 ++++++++++++++++++- .../ANS_EnableRootMotionZAxisMovement.h | 19 ++++- 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp index 29d0d2f..98ade6f 100644 --- a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp +++ b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp @@ -6,7 +6,9 @@ #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 UE_INLINE_GENERATED_CPP_BY_NAME(ANS_EnableRootMotionZAxisMovement) @@ -20,15 +22,81 @@ void UANS_EnableRootMotionZAxisMovement::NotifyBegin(USkeletalMeshComponent* Mes UCharacterMovementComponent* MovementComponent = BaseCharacter->GetCharacterMovement(); InitialMovementMode = MovementComponent->MovementMode; MovementComponent->SetMovementMode(MOVE_Flying); + + BaseCharacter->LandedDelegate.AddUniqueDynamic(this, &UANS_EnableRootMotionZAxisMovement::OnLanded); } void UANS_EnableRootMotionZAxisMovement::NotifyEndOrBlendOut(USkeletalMeshComponent* MeshComp) { Super::NotifyEndOrBlendOut(MeshComp); - + UCharacterMovementComponent* MovementComponent = BaseCharacter->GetCharacterMovement(); if (MovementComponent->MovementMode == MOVE_Flying) { MovementComponent->SetMovementMode(MOVE_Falling); } + + // 1) land до окончания, когда например запрыгиваем куда-то - + // а OnLanded в этом случае вообще будет работать, кмк - нет. + // Значит нужно чекать самостоятельно "land" и на MOVE_Falling переключать? + // UPD вообще не нужно ничо чекать, ANS должен закончится до/вовремя Land'а + // а значит никаких проблем с этим нет + // 2) ANS кончился а мы при этом не приземлились на землю и до земли далеко + // нужно Stop'ить montage, а для этого сделать sweep test капсулы вниз + if (bMakeLandCheckOnEnd) + { + FVector CurrentLocation = BaseCharacter->GetActorLocation(); + FVector EndLocation = CurrentLocation + FVector(0, 0, LandCheckDistance); + + FCollisionQueryParams CollisionParams; + CollisionParams.AddIgnoredActor(BaseCharacter.Get()); + // 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(); + FMontageBlendSettings BlendSettings; + BlendSettings.Blend = 0.25f; + BlendSettings.BlendMode = EMontageBlendMode::Inertialization; + BaseCharacter.Get()->GetRootMotionAnimMontageInstance()->PushDisableRootMotion(); + BaseCharacter.Get()->GetRootMotionAnimMontageInstance()->Stop(BlendSettings, true); + } + else + { + DrawDebugString( + BaseCharacter->GetWorld(), HitResult.Location, FString::Printf(TEXT("Land check: %s"), + *HitResult.GetActor()->GetName()), nullptr, + FColor::Green, 5.0f, true, 2.0f + ); + } + } +} + +void UANS_EnableRootMotionZAxisMovement::OnLanded(const FHitResult& HitResult) +{ + int32 test = 0; } diff --git a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.h b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.h index 7620979..ccb6586 100644 --- a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.h +++ b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.h @@ -11,7 +11,10 @@ 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 */ UCLASS() class UNREALHELPERLIBRARY_API UANS_EnableRootMotionZAxisMovement : public UANS_UHL_Base @@ -19,7 +22,18 @@ class UNREALHELPERLIBRARY_API UANS_EnableRootMotionZAxisMovement : public UANS_U GENERATED_BODY() public: - + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="EnableRootMotionZAxisMovement") + bool bMakeLandCheckOnEnd = true; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="EnableRootMotionZAxisMovement") + float LandCheckDistance = 50.0f; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="EnableRootMotionZAxisMovement") + bool bStopMontageIfLandCheckFails = true; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="EnableRootMotionZAxisMovement") + TEnumAsByte CollisionChannel = ECC_Pawn; + + 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; } @@ -36,4 +50,7 @@ class UNREALHELPERLIBRARY_API UANS_EnableRootMotionZAxisMovement : public UANS_U private: TWeakObjectPtr BaseCharacter = nullptr; EMovementMode InitialMovementMode = EMovementMode::MOVE_None; + + UFUNCTION() + void OnLanded(const FHitResult& HitResult); }; From 690e8e518deee746f897555a375e61ab5b6c1910 Mon Sep 17 00:00:00 2001 From: Ciberus Date: Tue, 29 Oct 2024 15:47:57 +0300 Subject: [PATCH 08/23] ANS_EnableRootMotionZAxisMovement ground check --- .../Notifies/ANS_ActivateAbility.cpp | 4 +- .../ANS_EnableRootMotionZAxisMovement.cpp | 62 ++++++++++++------- .../Animation/Notifies/ANS_UHL_Base.cpp | 21 +++---- .../Animation/Notifies/ANS_ActivateAbility.h | 1 + .../ANS_EnableRootMotionZAxisMovement.h | 18 +++--- .../Public/Animation/Notifies/ANS_UHL_Base.h | 6 +- 6 files changed, 62 insertions(+), 50 deletions(-) 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 98ade6f..60bb4dc 100644 --- a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp +++ b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.cpp @@ -9,26 +9,38 @@ #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->LandedDelegate.AddUniqueDynamic(this, &UANS_EnableRootMotionZAxisMovement::OnLanded); } void UANS_EnableRootMotionZAxisMovement::NotifyEndOrBlendOut(USkeletalMeshComponent* MeshComp) { Super::NotifyEndOrBlendOut(MeshComp); + + if (!MeshComp) return; + + ACharacter* BaseCharacter = Cast(MeshComp->GetOwner()); + if (!BaseCharacter) return; UCharacterMovementComponent* MovementComponent = BaseCharacter->GetCharacterMovement(); if (MovementComponent->MovementMode == MOVE_Flying) @@ -43,13 +55,13 @@ void UANS_EnableRootMotionZAxisMovement::NotifyEndOrBlendOut(USkeletalMeshCompon // а значит никаких проблем с этим нет // 2) ANS кончился а мы при этом не приземлились на землю и до земли далеко // нужно Stop'ить montage, а для этого сделать sweep test капсулы вниз - if (bMakeLandCheckOnEnd) + if (bStopMontageIfLandCheckFails) { FVector CurrentLocation = BaseCharacter->GetActorLocation(); - FVector EndLocation = CurrentLocation + FVector(0, 0, LandCheckDistance); + FVector EndLocation = CurrentLocation + FVector(0.0f, 0.0f, -LandCheckDistance); FCollisionQueryParams CollisionParams; - CollisionParams.AddIgnoredActor(BaseCharacter.Get()); + CollisionParams.AddIgnoredActor(BaseCharacter); // ignore all attached actors TArray CharacterAttachedActors; BaseCharacter->GetAttachedActors(CharacterAttachedActors, false, true); @@ -79,24 +91,30 @@ void UANS_EnableRootMotionZAxisMovement::NotifyEndOrBlendOut(USkeletalMeshCompon // TODO try stop specific montage // const UAnimMontage* AnimMontage = CurrentAnimMontage.Get(); // BaseCharacter->StopAnimMontage(); - FMontageBlendSettings BlendSettings; - BlendSettings.Blend = 0.25f; - BlendSettings.BlendMode = EMontageBlendMode::Inertialization; - BaseCharacter.Get()->GetRootMotionAnimMontageInstance()->PushDisableRootMotion(); - BaseCharacter.Get()->GetRootMotionAnimMontageInstance()->Stop(BlendSettings, true); + 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 { - DrawDebugString( - BaseCharacter->GetWorld(), HitResult.Location, FString::Printf(TEXT("Land check: %s"), - *HitResult.GetActor()->GetName()), nullptr, - FColor::Green, 5.0f, true, 2.0f - ); + 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 + ); + } } } } - -void UANS_EnableRootMotionZAxisMovement::OnLanded(const FHitResult& HitResult) -{ - int32 test = 0; -} diff --git a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp index cbb767b..0360604 100644 --- a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp +++ b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp @@ -13,14 +13,9 @@ void UANS_UHL_Base::NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceB { Super::NotifyBegin(MeshComp, Animation, TotalDuration, EventReference); - if (ShouldUseExperimentalUHLFeatures()) - { - MeshCompRef = MeshComp; - } + const UAnimMontage* CurrentAnimMontage = EventReference.GetNotify()->GetLinkedMontage(); - CurrentAnimMontage = EventReference.GetNotify()->GetLinkedMontage(); - - if (CurrentAnimMontage.IsValid()) + if (CurrentAnimMontage) { if (bUseOnMontageBlendingOut) { @@ -35,7 +30,7 @@ void UANS_UHL_Base::NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBas if (ShouldUseExperimentalUHLFeatures()) { - NotifyEndOrBlendOut(MeshCompRef.Get()); + NotifyEndOrBlendOut(MeshComp); } if (bUseOnMontageBlendingOut) @@ -53,14 +48,18 @@ void UANS_UHL_Base::NotifyEndOrBlendOut(USkeletalMeshComponent* MeshComp) void UANS_UHL_Base::OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupted) { - if (!CurrentAnimMontage.IsValid() - || Montage != CurrentAnimMontage) + if (!Montage) { return; } if (ShouldUseExperimentalUHLFeatures()) { - NotifyEndOrBlendOut(MeshCompRef.Get()); + UObject* Outer = Montage->GetController()._getUObject(); + USkeletalMeshComponent* SkeletalMeshComponent = Cast(Outer); + if (SkeletalMeshComponent) + { + NotifyEndOrBlendOut(SkeletalMeshComponent); + } } } 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 ccb6586..c3a2626 100644 --- a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.h +++ b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_EnableRootMotionZAxisMovement.h @@ -15,6 +15,8 @@ class ACharacter; * * 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 UANS_UHL_Base @@ -22,14 +24,16 @@ class UNREALHELPERLIBRARY_API UANS_EnableRootMotionZAxisMovement : public UANS_U GENERATED_BODY() public: + UANS_EnableRootMotionZAxisMovement(const FObjectInitializer& ObjectInitializer); + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="EnableRootMotionZAxisMovement") - bool bMakeLandCheckOnEnd = true; - 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") - bool bStopMontageIfLandCheckFails = true; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="EnableRootMotionZAxisMovement") + 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; @@ -48,9 +52,5 @@ class UNREALHELPERLIBRARY_API UANS_EnableRootMotionZAxisMovement : public UANS_U virtual void NotifyEndOrBlendOut(USkeletalMeshComponent* MeshComp) override; private: - TWeakObjectPtr BaseCharacter = nullptr; EMovementMode InitialMovementMode = EMovementMode::MOVE_None; - - UFUNCTION() - void OnLanded(const FHitResult& HitResult); }; diff --git a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_UHL_Base.h b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_UHL_Base.h index e80b539..6f0cf82 100644 --- a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_UHL_Base.h +++ b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_UHL_Base.h @@ -22,14 +22,10 @@ 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 **/ - TWeakObjectPtr MeshCompRef; +/** Experimental **/ // Should use experimental features like "NotifyEndOrBlendOut" virtual bool ShouldUseExperimentalUHLFeatures() const { return false; }; // experimental works only with "ShouldUseExperimentalUHLFeatures" enabled From 6fec47f70bad6cda6f1b83f77dfe53c1b391815f Mon Sep 17 00:00:00 2001 From: Ciberus Date: Thu, 14 Nov 2024 21:16:43 +0300 Subject: [PATCH 09/23] Update README.md --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b7bcf49..77670ff 100644 --- a/README.md +++ b/README.md @@ -685,6 +685,7 @@ 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()` ```C++ +// UInventoryItem.h #if WITH_EDITOR #include "UHECustomThumbnail.h" #endif @@ -702,10 +703,18 @@ class GAMECODE_API UInventoryItem : public UObject, /** IUHECustomThumbnail **/ #if WITH_EDITOR UFUNCTION(BlueprintCallable, BlueprintNativeEvent) - UTexture2D* GetCustomThumbnailIcon() { return Description.Icon; }; + UTexture2D* GetCustomThumbnailIcon(); #endif /** ~IUHECustomThumbnail **/ + +// UInventoryItem.cpp +#if WITH_EDITOR +UTexture2D* UInventoryItem::GetCustomThumbnailIcon_Implementation() +{ + return Description.Icon; +} +#endif // ... ``` From 560cd4964fc7687386f8fbdecbbde1d254ac2643 Mon Sep 17 00:00:00 2001 From: Ciberus Date: Thu, 14 Nov 2024 21:18:04 +0300 Subject: [PATCH 10/23] Update README.md --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 77670ff..01f4750 100644 --- a/README.md +++ b/README.md @@ -698,15 +698,15 @@ class IUHECustomThumbnail {}; class GAMECODE_API UInventoryItem : public UObject, public IUHECustomThumbnail { -// ... - - /** IUHECustomThumbnail **/ +/** IUHECustomThumbnail **/ #if WITH_EDITOR UFUNCTION(BlueprintCallable, BlueprintNativeEvent) UTexture2D* GetCustomThumbnailIcon(); #endif /** ~IUHECustomThumbnail **/ +} +------------------------------------------------------------------ // UInventoryItem.cpp #if WITH_EDITOR @@ -715,7 +715,6 @@ UTexture2D* UInventoryItem::GetCustomThumbnailIcon_Implementation() return Description.Icon; } #endif -// ... ``` ⚠️ for now works only with C++, TODO add support for blueprints From c7dc544b49b7174312df1bf081452d838672ff6a Mon Sep 17 00:00:00 2001 From: Ciberus Date: Thu, 14 Nov 2024 21:30:18 +0300 Subject: [PATCH 11/23] [Editor] CustomThumbnails refactoring --- README.md | 8 ++++---- Source/UnrealHelperEditor/Private/UHECustomThumbnail.cpp | 7 ++++++- Source/UnrealHelperEditor/Public/UHECustomThumbnail.h | 3 ++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 01f4750..585c1b0 100644 --- a/README.md +++ b/README.md @@ -684,6 +684,9 @@ 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 @@ -700,8 +703,7 @@ class GAMECODE_API UInventoryItem : public UObject, { /** IUHECustomThumbnail **/ #if WITH_EDITOR - UFUNCTION(BlueprintCallable, BlueprintNativeEvent) - UTexture2D* GetCustomThumbnailIcon(); + virtual UTexture2D* GetCustomThumbnailIcon_Implementation() const override; #endif /** ~IUHECustomThumbnail **/ } @@ -717,8 +719,6 @@ UTexture2D* UInventoryItem::GetCustomThumbnailIcon_Implementation() #endif ``` -⚠️ for now works only with C++, TODO add support for blueprints - 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) #### `Custom class icon` 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/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 **/ }; From 2cc1f3cf4c57aa84deebdd227f90d1e0f1132247 Mon Sep 17 00:00:00 2001 From: Ciberus Date: Fri, 15 Nov 2024 21:18:13 +0300 Subject: [PATCH 12/23] [Debug] experimental debug lines through "AHUD::DrawHUD" --- .../UnrealHelperLibrary/Private/UI/UHLHUD.cpp | 49 ++++++++++ .../Private/Utils/UnrealHelperLibraryBPL.cpp | 90 +++++++++++++++++++ Source/UnrealHelperLibrary/Public/UI/UHLHUD.h | 51 +++++++++++ .../Public/Utils/UnrealHelperLibraryBPL.h | 24 +++++ 4 files changed, 214 insertions(+) create mode 100644 Source/UnrealHelperLibrary/Private/UI/UHLHUD.cpp create mode 100644 Source/UnrealHelperLibrary/Public/UI/UHLHUD.h 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/UnrealHelperLibraryBPL.cpp b/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp index c4137fd..b7926fe 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,93 @@ 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; + } + + 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; +} + +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/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/UnrealHelperLibraryBPL.h b/Source/UnrealHelperLibrary/Public/Utils/UnrealHelperLibraryBPL.h index 7ebd06e..c17e961 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,29 @@ 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 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 **/ From 923b2d78d5b0ef45bec9d0ae1a47cf917105feb9 Mon Sep 17 00:00:00 2001 From: Ciberus Date: Fri, 15 Nov 2024 22:11:30 +0300 Subject: [PATCH 13/23] [Debug] experimental debug lines through "AHUD::DrawHUD" 2 --- .../Private/Utils/UnrealHelperLibraryBPL.cpp | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp b/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp index b7926fe..92c46a1 100644 --- a/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp +++ b/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp @@ -350,18 +350,21 @@ AActor* UUnrealHelperLibraryBPL::GetActorClosestToCenterOfScreen(UObject* WorldC Result = Actor; } - 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); + 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; From 066ef6f71eecf1e2a104bd3c9aff92a0288bef3d Mon Sep 17 00:00:00 2001 From: Ciberus Date: Sat, 16 Nov 2024 18:58:21 +0300 Subject: [PATCH 14/23] ANS_UHL_Base fix critical build err --- .../Private/Animation/Notifies/ANS_UHL_Base.cpp | 6 +++--- .../Public/Animation/Notifies/ANS_UHL_Base.h | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp b/Source/UnrealHelperLibrary/Private/Animation/Notifies/ANS_UHL_Base.cpp index 0360604..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" @@ -55,7 +55,7 @@ void UANS_UHL_Base::OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupte if (ShouldUseExperimentalUHLFeatures()) { - UObject* Outer = Montage->GetController()._getUObject(); + UObject* Outer = Montage->GetOuter(); USkeletalMeshComponent* SkeletalMeshComponent = Cast(Outer); if (SkeletalMeshComponent) { diff --git a/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_UHL_Base.h b/Source/UnrealHelperLibrary/Public/Animation/Notifies/ANS_UHL_Base.h index 6f0cf82..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,6 @@ #include "Animation/AnimNotifies/AnimNotifyState.h" #include "ANS_UHL_Base.generated.h" -class UAnimMontage; class USkeletalMeshComponent; /** From 24c81d5b0a667f69ff945288905f5002ed64ea94 Mon Sep 17 00:00:00 2001 From: Ciberus Date: Sun, 17 Nov 2024 13:55:45 +0300 Subject: [PATCH 15/23] UUHLTraceUtilsBPL::SweepCapsuleMultiByChannel --- .../Private/Utils/UHLTraceUtilsBPL.cpp | 33 +++++++++++++++++++ .../Public/Utils/UHLTraceUtilsBPL.h | 7 ++++ 2 files changed, 40 insertions(+) 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/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, From 7e17ac2b574b7d09fed9e23e4177a7921128a27b Mon Sep 17 00:00:00 2001 From: Ciberus Date: Tue, 19 Nov 2024 18:36:59 +0300 Subject: [PATCH 16/23] Update README.md --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 585c1b0..f6ed75d 100644 --- a/README.md +++ b/README.md @@ -647,6 +647,18 @@ 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(); +); +``` + ### LoadingUtilLibrary **UHLLoadingUtilLibrary** - loading utils from Lyra From af29abdca1b6565e9c2cd11cbad07e9140f6775f Mon Sep 17 00:00:00 2001 From: Ciberus Date: Fri, 22 Nov 2024 08:58:15 +0300 Subject: [PATCH 17/23] [BPL] GetMostDistantActor --- .../Private/Utils/UnrealHelperLibraryBPL.cpp | 31 +++++++++++++++++++ .../Public/Utils/UnrealHelperLibraryBPL.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp b/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp index 92c46a1..2dae609 100644 --- a/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp +++ b/Source/UnrealHelperLibrary/Private/Utils/UnrealHelperLibraryBPL.cpp @@ -371,6 +371,37 @@ AActor* UUnrealHelperLibraryBPL::GetActorClosestToCenterOfScreen(UObject* WorldC 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); diff --git a/Source/UnrealHelperLibrary/Public/Utils/UnrealHelperLibraryBPL.h b/Source/UnrealHelperLibrary/Public/Utils/UnrealHelperLibraryBPL.h index c17e961..1299af5 100644 --- a/Source/UnrealHelperLibrary/Public/Utils/UnrealHelperLibraryBPL.h +++ b/Source/UnrealHelperLibrary/Public/Utils/UnrealHelperLibraryBPL.h @@ -58,6 +58,8 @@ class UNREALHELPERLIBRARY_API UUnrealHelperLibraryBPL : public UBlueprintFunctio // 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( From 21abdaac5673c718d4ba0a5e06e9b5db707eb64b Mon Sep 17 00:00:00 2001 From: Ciberus Date: Fri, 20 Dec 2024 22:04:35 +0300 Subject: [PATCH 18/23] [Editor] CustomIcons add classes array support --- .../Private/UnrealHelperEditorStyle.cpp | 19 ++++++++++++++----- .../Public/Development/UHESettings.h | 5 ++++- 2 files changed, 18 insertions(+), 6 deletions(-) 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; }; /** From 77d960c57288bb8655c883d21a654cca9d2aefaa Mon Sep 17 00:00:00 2001 From: Ciberus Date: Sat, 21 Dec 2024 13:17:52 +0300 Subject: [PATCH 19/23] [DebugSubsystem] fix RandomColors for DebugCategories --- .../Public/Subsystems/DebugSubsystem/UHLDebugCategory.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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; From 5bf688b4a0e7e47166da808793af37cd360f698e Mon Sep 17 00:00:00 2001 From: Ciberus Date: Sun, 5 Jan 2025 12:38:33 +0300 Subject: [PATCH 20/23] by default InstancingPolicy = InstancedPerActor --- .../AbilitySystem/Abilities/UHLGameplayAbility.cpp | 9 +++++++++ .../Public/AbilitySystem/Abilities/UHLGameplayAbility.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/Source/UnrealHelperLibrary/Private/AbilitySystem/Abilities/UHLGameplayAbility.cpp b/Source/UnrealHelperLibrary/Private/AbilitySystem/Abilities/UHLGameplayAbility.cpp index 96b6f29..b9bcc85 100644 --- a/Source/UnrealHelperLibrary/Private/AbilitySystem/Abilities/UHLGameplayAbility.cpp +++ b/Source/UnrealHelperLibrary/Private/AbilitySystem/Abilities/UHLGameplayAbility.cpp @@ -8,6 +8,15 @@ #include UE_INLINE_GENERATED_CPP_BY_NAME(UHLGameplayAbility) +UUHLGameplayAbility::UUHLGameplayAbility(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + ReplicationPolicy = EGameplayAbilityReplicationPolicy::ReplicateNo; + InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor; + NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::LocalPredicted; + NetSecurityPolicy = EGameplayAbilityNetSecurityPolicy::ClientOrServer; +} + UUHLAbilitySystemComponent* UUHLGameplayAbility::GetUHLAbilitySystemComponentFromActorInfo() const { if (!ensure(CurrentActorInfo)) diff --git a/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h b/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h index a277eb0..cd8158c 100644 --- a/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h +++ b/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h @@ -50,6 +50,8 @@ class UNREALHELPERLIBRARY_API UUHLGameplayAbility : public UGameplayAbility GENERATED_BODY() public: + UUHLGameplayAbility(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + UFUNCTION(BlueprintCallable, Category = "UHL GameplayAbility") EUHLAbilityActivationPolicy GetActivationPolicy() const { return ActivationPolicy; } From b8f7067f6c46e5b78473a325b4d5769226183d65 Mon Sep 17 00:00:00 2001 From: Ciberus Date: Sun, 5 Jan 2025 12:39:27 +0300 Subject: [PATCH 21/23] Revert "by default InstancingPolicy = InstancedPerActor" This reverts commit 5bf688b4a0e7e47166da808793af37cd360f698e. --- .../AbilitySystem/Abilities/UHLGameplayAbility.cpp | 9 --------- .../Public/AbilitySystem/Abilities/UHLGameplayAbility.h | 2 -- 2 files changed, 11 deletions(-) diff --git a/Source/UnrealHelperLibrary/Private/AbilitySystem/Abilities/UHLGameplayAbility.cpp b/Source/UnrealHelperLibrary/Private/AbilitySystem/Abilities/UHLGameplayAbility.cpp index b9bcc85..96b6f29 100644 --- a/Source/UnrealHelperLibrary/Private/AbilitySystem/Abilities/UHLGameplayAbility.cpp +++ b/Source/UnrealHelperLibrary/Private/AbilitySystem/Abilities/UHLGameplayAbility.cpp @@ -8,15 +8,6 @@ #include UE_INLINE_GENERATED_CPP_BY_NAME(UHLGameplayAbility) -UUHLGameplayAbility::UUHLGameplayAbility(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) -{ - ReplicationPolicy = EGameplayAbilityReplicationPolicy::ReplicateNo; - InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor; - NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::LocalPredicted; - NetSecurityPolicy = EGameplayAbilityNetSecurityPolicy::ClientOrServer; -} - UUHLAbilitySystemComponent* UUHLGameplayAbility::GetUHLAbilitySystemComponentFromActorInfo() const { if (!ensure(CurrentActorInfo)) diff --git a/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h b/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h index cd8158c..a277eb0 100644 --- a/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h +++ b/Source/UnrealHelperLibrary/Public/AbilitySystem/Abilities/UHLGameplayAbility.h @@ -50,8 +50,6 @@ class UNREALHELPERLIBRARY_API UUHLGameplayAbility : public UGameplayAbility GENERATED_BODY() public: - UUHLGameplayAbility(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); - UFUNCTION(BlueprintCallable, Category = "UHL GameplayAbility") EUHLAbilityActivationPolicy GetActivationPolicy() const { return ActivationPolicy; } From 31243b1feea407ee748f48c42e93099188561fec Mon Sep 17 00:00:00 2001 From: Ciberus Date: Sun, 5 Jan 2025 13:46:06 +0300 Subject: [PATCH 22/23] update readme.md --- README.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f6ed75d..2168ae8 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,7 @@ UHL consists of 3 modules: > - [TurnTo](#turnto) > - [Subsystems](#subsystems) > - [DebugSubsystem](#debugsubsystem) +> - [UHLHUD](#uhlhud) > - [UnrealHelperLibraryBPL](#unrealhelperlibrarybpl) > - GAS > - TryActivateAbilityWithTag @@ -648,17 +649,21 @@ 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(); -); + 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 From 3b1fc36f759d4a40b887b3937d18de0da42dcfc1 Mon Sep 17 00:00:00 2001 From: Ciberus Date: Sun, 5 Jan 2025 13:50:23 +0300 Subject: [PATCH 23/23] update readme.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 2168ae8..b885c71 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,9 @@ UHL consists of 3 modules: > - [DebugSubsystem](#debugsubsystem) > - [UHLHUD](#uhlhud) > - [UnrealHelperLibraryBPL](#unrealhelperlibrarybpl) +> - Gameplay +> - GetActorClosestToCenterOfScreen +> - GetMostDistantActor > - GAS > - TryActivateAbilityWithTag > - TryCancelAbilityWithTag @@ -123,6 +126,8 @@ UHL consists of 3 modules: > - [GetPointAtAngleRelativeToOtherActor](#getpointatanglerelativetootheractor) > - [GetPointAtDirectionRelativeToOtherActor](#getpointatdirectionrelativetootheractor) > - [DirectionToAngle](#directiontoangle) +> - UI/Screen +> - GetViewportSizeUnscaled > - Misc > - [GetProjectVersion](#getprojectversion) > - [GetNamesOfComponentsOnObject](#getnamesofcomponentsonobject) @@ -130,6 +135,8 @@ UHL consists of 3 modules: > - GetBuildType > > +> - Debug +> - DrawDebugLineOnCanvas > - Other > - [GetHighestPoint](#gethighestpoint) > - [LoadingUtilLibrary](#loadingutillibrary)