Skip to content

Ciberusps/unreal-helper-library

Repository files navigation

Unreal Helper Library [UHL]

UHL - unreal helper library, toolset to help developers working with AI, GAS, customizing editor and so on. Goal is to became a tool that insta-installed on new project creation. All tools are mostly tested on melee combat so if you have other background and think that something should work another way or have an idea on how to improve developer experience feel free to discuss.

GAS things not required to be used at all, you can use library only for AI things. GAS features provides much smoother GAS experience mostly based on Lyra features. All GAS features designed in mind that they or their part can be added or dropped by you in development in any time and replaced by something custom that fits your project needs

Support: tested UE5.4 - UE5.5-preview

Install

From source (recommended):

  • git submodule add https://github.com/Ciberusps/unreal-helper-library.git ./Plugins/UnrealHelperLibrary - add git submodule to your plugins folder
  • to use C++ things add code to file <ProjectName>.Build.cs
    // <ProjectName>.Build.cs
    public GameName(ReadOnlyTargetRules Target) : base(Target)
    {
        PublicDependencyModuleNames.AddRange(new string[] {
            // add "UnrealHelperLibrary" to use it in C++
            "UnrealHelperLibrary",
        });

        // OPTIONALLY add "UnrealHelperEditor" module to use custom unreal engine editor features
        if (Target.bBuildEditor)
        {
            PrivateDependencyModuleNames.AddRange(new string[] { "UnrealHelperEditor" });
        }
    }

Note

Don't forget to update your README.md with instructions on how to setup - git submodule update --init --recursive and how to update submodules/plugin(s) - git submodule update --remote

Note

Add Editor Preferences -> Force Compilation on Startup in Config/EditorPerProjectUserSettings.ini your team don't want to recompile plugin manually 😉

From marketplace:

later this year on FAB

Update

From source:

  • git submodule update --remote to update plugin from source

Modules

UHL consists of 3 modules:

  • UnrealHelperLibrary - main module with GAS helper classes, AI behavior tree nodes, Blueprint Function Libraries. Most functionality can be tested in Gyms(maps for testing atomic/single gameplay mechanic), all Gyms located in /Plugins/UnrealHelperLibrary/Content/Gyms
  • UnrealHelperEditor - optional module with editor customization, e.g. custom thumnails, custom class icons
  • UHL Utils (EditorUtilityWidget) - widget with tools helping you make trivial things, like ConvertToORM quite often task when you want to combine 3 textures Occlusion, Roughness, Metalic in one ORM texture

Documentation

UnrealHelperLibrary - main module

UnrealHelperEditor

UHL Utils (Editor Utility Widget)


GAS

Many GAS-related things based on "Lyra" sample project.

AbilitySystemComponent

UHLAbilitySystemComponent

UHLAbilitySystemComponent - for quick start with GAS. You can nest from it on start and than turn off its functions when you ready to replace them with your custom solution.

Features:

  • set InitialAttributes
  • give Abilities on start
  • activate InitialActiveAbilities
  • apply InitialGameplayTags
  • "Lyra"-like "InputConfig", GAS abilities input binding

Setup:

Option 1 - zero setup

Easy way with zero setup, just nest your character from AUHLBaseCharacterWithASC, fits new projects there you don't want to waste time at all.

Option 2 - BP way

Easy way - just add UHLAbilitySystemComponent to your character and call InitAbilitySystem on BeginPlay/Possessed

image

Option 3 - C++

A bit harder and requires small C++ work, fits for projects with GAS already integrated. Follow instructions below or just check AUHLBaseCharacterWithASC example

AUHLBaseCharacterWithASC::AUHLBaseCharacterWithASC(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    // create AbilitySystemComponent if you don't have it
    AbilitySystemComponent = CreateDefaultSubobject<UUHLAbilitySystemComponent>(TEXT("UHLAbilitySystem"));
}

void AUHLBaseCharacterWithASC::PossessedBy(AController* NewController)
{
    Super::PossessedBy(NewController);

    // init AbilitySystem
    AbilitySystemComponent->InitAbilitySystem(NewController, this);
}

If you want custom attributes init you can do it

  • by overriding InitAttributes_Implementation - recommended
  • or just don't activate abilities AbilitySystemComponent->InitAbilitySystem(NewController, this, false) and make your own attributes init, and then call AbilitySystemComponent->ActivateInitialAbilities()

You have 3 levels of advancement using GAS with UHL

  1. entry - just using abilities/attributes in your character on start of a project
  2. when you understand that you want to share some abilities to other characters - use AbilitySets
  3. when your team grows and you understand that locking whole character just to add ability is or change some ability system settings is too much - use AbilitySystem Config and optionally defaults in UHLSettings

image

InputConfig (GAS abilities input binding)

Binding InputActions to GameplayAbilities using tags, based on Lyra but enhanced and adopted for 3D action game.

image

Setup
  • turn on bUseInputConfig on UHLAbilitySystemComponent
  • create InputConfig - DataAsset nested from UHLInputConfig
  • add InputConfig to your character UHLAbilitySystemComponent
  • in Project Settings -> Input -> Default Input Component Class -> set UHLInputComponent
  • in your PlayerCharacter class add lines in SetupPlayerInputComponent for binding actions from InputConfig

For now only C++ setup tested (blueprint option will be later)

// Your PlayerCharacter class
void AUHLPlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    UUHLInputComponent* UHLInputComponent = CastChecked<UUHLInputComponent>(PlayerInputComponent);
    UUHLInputConfig* UHLInputConfig = AbilitySystemComponent->InputConfig;
    TArray<uint32> BindHandles;
    UHLInputComponent->BindAbilityActions(UHLInputConfig, AbilitySystemComponent, &UUHLAbilitySystemComponent::AbilityInputTagPressed, &UUHLAbilitySystemComponent::AbilityInputTagReleased, BindHandles);

    // optional
    // if (UHLInputComponent)
    // {
    //     UHLInputComponent->BindAction(UHLInputConfig->NativeInputAction_Move.InputAction, ETriggerEvent::Triggered, this, &AUHLPlayerCharacter::InputMove);
    //     UHLInputComponent->BindAction(UHLInputConfig->NativeInputAction_Move.InputAction, ETriggerEvent::Completed, this, &AUHLPlayerCharacter::InputStopMove);

    //     UHLInputComponent->BindAction(UHLInputConfig->NativeInputAction_LookMouse.InputAction, ETriggerEvent::Triggered, this, &AUHLPlayerCharacter::InputLook);
    //     UHLInputComponent->BindAction(UHLInputConfig->NativeInputAction_LookStick.InputAction, ETriggerEvent::Triggered, this, &AUHLPlayerCharacter::InputLook);
    // }
}
  • in your PlayerController class add
// Your PlayerController.cpp
void AUHLPlayerController::OnPossess(APawn* InPawn)
{
    Super::OnPossess(InPawn);

    CachedPlayerCharacter = Cast<AUHLPlayerCharacter>(InPawn);
}

void AUHLPlayerController::PostProcessInput(const float DeltaTime, const bool bGamePaused)
{
    Super::PostProcessInput(DeltaTime, bGamePaused);

    if (!CachedPlayerCharacter.IsValid()) return;

    if (UUHLAbilitySystemComponent* ASC = CachedPlayerCharacter.Get()->GetUHLAbilitySystemComponent())
    {
        ASC->ProcessAbilityInput(DeltaTime, bGamePaused);
    }
}


// Your PlayerController.h
UCLASS()
class UHL_API AUHLPlayerController : public APlayerController
{
  GENERATED_BODY()

protected:
    virtual void OnPossess(APawn* InPawn) override;
    virtual void PostProcessInput(const float DeltaTime, const bool bGamePaused) override;

private:
    TWeakObjectPtr<AUHLPlayerCharacter> CachedPlayerCharacter;
};
  • now create InputAction(IA) and map it in your InputMappingContext(IMC)
  • add InputAction to created InputConfig and map it to AbilityTags
  • now Abilities associated with AbilityTags will activates when InputAction triggered
  • WARN! abilities should nest from UHLGameplayAbility for ActivationPolicy work correctly
  • to controll ability activation, every UHLGameplayAbility have ActivationPolicy
    • OnInputTriggered - will activate when InputAction triggered
    • WhileInputActive - activates ability when input pressed and deactivates when input released
    • OnSpawn - activates ability when it gived(granted) to character

AbilityInputCache

AbilityInputCache (beta) - caches abilities activation. If you want to have input quality like in AAA games when you need cache some inputs and fire whem when its available. Abilities/Inputs to cache may vary depending on project e.g. for 3D actions(souls-likes, slashers) its critical, for shooters less important

[!WARN] dont work without UHLAbilitySystemComponent and InputConfig enabled

image

Setup:

Instructions here provided with souls-like developing background. Remember you can control AbilityInputCache wherever ASC(AbilitySystemComponent) is available just take AbilityInputCache from ASC and call AddTagToCache, CheckCache, ClearCache.... If you need "input window" just add UHL.AbilityInputCache.Catching on your character by hand and remove when window not required

  • activate bUseAbilityInputCache in UHLAbilitySystemComponent
  • [optionaly] strongly recommended to activate bUseInputCacheWindows also. If bUseInputCacheWindows not activated any GameplayAbility marked with bInputCache that you try to activate in any time on fail will be added to AbilityInputCache thats not what you want in 3D action game
  • in GameplayAbility that you want to cache activate bInputCache and fill if required
    • AddingToCacheInputRequiredTags - tags that required to be on your character for this ability to be added to AbilityInputCache
    • AddingToCacheInputBlockedTags - tags that blocks adding this ability to AbilityInputCache
  • prepare you attack animation - add anim notifies
    • ANS_CatchToAbilityInputCache - to mark when its possible to cache ability. Best practice - leave some frames on start(5-10frames at least) and finish when your "BlockAction" end
    • ANS_CheckAbilityInputCache - when you want to check cache and activate ability. Best practice - on end of "BlockAction" with 5-10frames duration
Debug:
  • activate AbilityInputCache debug category in DebugSubsystem from
    • ProjectSettings -> UHL DebugSubsystem Settings
    • or in runtime via UHLDebugCategoriesListWidget
  • write in console ToggleAbilityInputDebug, don't forget to add ProcessConsoleExec to your GameInstance or it won't work

AttributeSet

Just class with default things that every AttributeSet wants like ATTRIBUTE_ACCESSORS. Nest your AttributeSets from it to not duplicate same things other and other again.

AbilitySet

"Lyra"-like set of Abilities, AttributeSets, GameplayEffects, that can be added to character and removed later by tag

image

AbilitySet - is second level of advancement of using GAS in UHL, when you understand that you want to share some abilities to other characters - use AbilitySets

Use cases:

  • gived by external source using or AbilitySet->GiveToAbilitySystem and removed by external source via AbilitySetGrantedHandles.TakeFromAbilitySystem
  • gived by external source using ASC->GiveAbilitySet(UUHLAbilitySet* AbilitySet) and removed by tag calling ASC->RemoveAbilitySetByTag(), of course if tag associated with set by defining AbilitySetTags in AbilitySet

AbilitySystem Config

DataAsset - option for teams to edit AbilitySystem config externally to not locking character for just changing abilities/initial attributes

image

Defaults can be changed in ProjectSettings -> UHL Settings

GameplayAbility

Additional events - OnSpawn

Activation policy - InputTriggered, WhileInputActive, OnSpawn

InputCache - to use it required to nest from GameplayAbility

InterpolateToPosition

AT_InterpolateToPosition - interpolate actor to specified position/rotation at a predetermined amount of time

image

BaseCharacter

UHLBaseCharacter - simplest BaseCharacter with only UHL interfaces implemented, so you don't need to do it by yourself

BaseCharacterWithASC

UHLBaseCharacterWithASC - recommended BaseCharacter for start - ASC created on start and inited on PossessedBy. Can be turned off by disabling bInitUHLAbilitySystemOnPosses

ANS_UHL_Base

ANS_UHL_Base - base AnimNotifyState class with commonly used features like

  • subscribing OnMontageBlendingOut by overriding OnMontageBlendingOut can be disabled by bUseOnMontageBlendingOut=false(true by default)
  • more come later

ANS_ActivateAbility

ANS_ActivateAbility - commonly used ANS that just activate ability on start and deactivate on end

image

  • GameplayAbilityTag - tag associated with ability to activate
  • bDeactivateOnMontageBlendingOut - should ability deactivates on montage blends out
  • bAllowRemoteActivation - you can allow remote activation

UHLAIPerceptionComponent

⚒️ InProgress


AI

BTC_RandomSelector

Select random child node using weights

image

With cool validations

Warns if summary of weights > 1

image

Warns if chances array have more items then child nodes

image

Shows error if child nodes count > than chances count

image

CheckGASGameplayTagsOnActor

BTD_CheckGASGameplayTagsOnActor - checks that actor has GAS gameplay tags specified.

Warning

Don't mess with UBTDecorator_CheckGameplayTagsOnActor - its only checks GameplayTags on actor itself not on AbilitySystem.

Requirements:

  • actor should implement IAbilitySystemInterface to get AbilitySystemComponent

image

InAngle

BTD_InAngle - decorator to check is enemy in one of specified angle ranges. Useful in developing big enemies, for example we developing dragon we want to know is player under the right wing or leg, is player in front of dragon or behind and so on.

image

InRange

BTD_InRange - decorator to check distance between actors. Compliant with "MoveTo" node have same settings bIncludeSelfCapsuleRadius and bIncludeTargetCapsuleRadius to check distance excluding capsules radiuses

image InRange

LoopRandomCount

BTD_LoopRandomCount - randomized version of decorator Loop

image

TimeLimitRandom

BTD_TimeLimitRandom - randomized version of decorator TimeLimit

image

RandomChance

BTD_RandomChance - commonly used decorator to randomize actions. Fine for single child node, extra bad for multiple nodes due to chance regression, for randomization between multiple child nodes better to use RandomSelector

image

SetGameplayFocus

BTS_SetGameplayFocus - alternative for "Set default focus". SetGameplayFocus made right way - prevents rotation jittering while enemy rotation. One of most common problems that anybody stucks when starting developing AI - "focus dont work"/"focus works wrong".

image GameplayFocus

Requirements:

  • turn on UseControllerDesiredRotation
  • turn off
    • bOrientRotationToMovement
    • UseControllerRotationYaw
    • UseControllerRotationPitch
    • UseControllerRotationRoll

Troubleshooting:

  • check that nothing "ClearFocus"
  • check that MoveTo uses "AllowStafe"

SetBBValue

BTT_SetBBValue - helps settings values in blackboard, supports all blackboard types and for some values event provides opportunity to make calculations like int

image

DebugPrintBBValue

BTT_DebugPrintBBValue - prints BB value of any type

image

DebugPrintString

BTT_DebugPrintString - simple task for printing debug info on screen

image

InvokeGameplayAbility

BTT_InvokeGameplayAbility - activate/deactivate GAS Gameplay Ability by tag, with optional "wait for finishing"

image

PlayAnimMontage

BTT_PlayAnimMontage - play anim montage with option to customize PlayRate, Starting Position, Start Section Name and stopping montage on task abort

image

TurnTo

BTT_TurnTo - turn to enemy using turn animations Drop in replacement for "RotateToFaceBBEntry" but with option to "RotateTo" with animations To get settings from actor requires IUHLActorSettings to be implemented on character


UnrealHelperLibraryBPL

> RelativeAngles

RelativeAngleToActor

for most cases you want to use "InRange" like IsOtherActorInAngle (or IsOtherCharacterInRange if you want to check distance)

image

GetPointAtRelativeAngle

image image

GetPointAtRelativeDirection

image image

GetPointAtAngleRelativeToOtherActor

GetPointAtDirectionRelativeToOtherActor

DirectionToAngle

> GAS

CreateGenericGASGameplayEffectSpec - TODO: rename, remove "GAS"

> Misc

GetProjectVersion

Get project version from "Project Settings"

image

image

GetNamesOfComponentsOnObject

Get names of actor components on object, usefull for GetOptions UPROPERTY

GetAssetsOfClass

> Other

GetHighestPoint

Subsystems

DebugSubsystem

Any game needs debug system, in mid-size commands you always use limited set of debugging tools more always than others, so DebugSubsystem is as tool for creating your debug system as fast as possible

Use case: I want to have debug for AbilitySystem, it should turn on/off, available in editor between sessions and

Components:

DebugSubsystem
  • you can get IsDebugCategoryEnabled
DebugSubsystemSettings
  • add new categories, turn on/off default state, every debug category is a tag
  • DebugCategoryComponents (DCC)
Check is category enabled/subscribe on debug category state change
  • WaitDebugCategoryChange - blueprint node to easier check isDebugCategoryEnabled or not and wait for its changes
  • IsUHLDebugSubsystemEnabled - blueprint node
  • DebugCategoriesList - UI component for quick integration in your debug menu

Features:

  • you can create DebugCategoryComponents that activate/deactivate console commands, event in blueprints like GAS abilities
  • you can even compose DebugCategoryComponents e.g. you want Collisions + HitBoxes, so you can create combined DebugCategory and add "DCC_Collisions" and "DCC_HitBoxes"
  • you can "Block" other DebugCategories by tag
  • WaitDebugCategoryChange

Setup:

void AUHLPlayerController::BeginPlay()
{
    Super::BeginPlay();
    UUHLDebugSubsystem* UHLDebugSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<UUHLDebugSubsystem>();
    UHLDebugSubsystem->SetUpCategoriesThatRequiresPlayerController();
}

How to add DebugCategory: 1)

LoadingUtilLibrary

UHLLoadingUtilLibrary - loading utils from Lyra

ApplyDefaultPriorityLoading

ApplyStreamingPriorityLoading

ApplyHighestPriorityLoading

ApplyCustomPriorityLoading

ForceGarbageCollection

FlushLevelStreaming

TraceUtilsBPL

UHLTraceUtilsBPL - trace utils

Settings

UHL Settings

UnrealHelperEditor

UnrealHelperEditor - optional module with editor customization, e.g. custom thumnails, custom class icons

Custom thumnails

image

Custom thumnails - to override thumbnail by your own, just implement IUHECustomThumbnail interface and define your own icon using GetCustomThumbnailIcon()

#if WITH_EDITOR
#include "UHECustomThumbnail.h"
#endif

// IUHECustomThumbnail not available in production build
#if !WITH_EDITOR
class IUHECustomThumbnail {};
#endif

class GAMECODE_API UInventoryItem : public UObject,
    public IUHECustomThumbnail
{
//  ...

 /** IUHECustomThumbnail **/
#if WITH_EDITOR
    UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
    UTexture2D* GetCustomThumbnailIcon() { return Description.Icon; };
#endif
/** ~IUHECustomThumbnail **/

// ...

⚠️ for now works only with C++, TODO add support for blueprints

Thanks to this post and this

Custom class icon

Custom class icon - to override classes icons on your own, just implement set settings in Project Settings -> Editor -> UnrealHelperEditor Settings

image

List of default Unreal Engine Editor icons

Thanks to this post and this

UHL Utils (Editor Utility Widget)

⚒️ InProgress

ConvertToORM

Combines separate Occlusion, Roughness, Metalic textures into one ORM

TODO check ref - https://github.com/Atulin/ChannelMerger

Special Thanks

@Ingarnm, @Vamp1rk0 for feedback