Files
integration/Source/Integration/UtilityLibrary.cpp

232 lines
7.5 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "UtilityLibrary.h"
#include "GameFramework/PlayerController.h"
#include "EnhancedInputSubsystems.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "Blueprint/UserWidget.h"
#include "Components/GridPanel.h"
#include "InputMappingContext.h"
#define LOCTEXT_NAMESPACE "Luprex Utility"
void UlxUtilityLibrary::CallFunctionByName(UObject *object, const FString &namepart1, const FString &namepart2, const FString &fallback, bool bFailIfNotFound) {
FString fullname = namepart1 + namepart2;
if (!IsValid(object)) {
UE_LOG(LogBlueprint, Error, TEXT("In CallFunctionByName, object passed in is not valid."));
return;
}
UFunction* function = object->FindFunction(FName(*fullname));
if (function == nullptr) {
function = object->FindFunction(FName(*fallback));
if (function == nullptr) {
if (!bFailIfNotFound) {
return;
}
UE_LOG(LogBlueprint, Error, TEXT("In CallFunctionByName, cannot find the named function or the fallback function"));
return;
}
}
if (function->ParmsSize != 0) {
UE_LOG(LogBlueprint, Error, TEXT("CallFunctionByName can only call functions that have no parameters and no return values"));
return;
}
object->ProcessEvent(function, nullptr);
}
FBox UlxUtilityLibrary::GetActorBounds(const AActor *target, bool bOnlyCollidingComponents, bool bIncludeFromChildActors)
{
FVector ActorOrigin;
FVector BoxExtent;
// First argument is bOnlyCollidingComponents - if you want to get the bounds for components that don't have collision enabled then set to false
// Last argument is bIncludeFromChildActors. Usually this won't do anything but if we've child-ed an actor - like a gun child-ed to a character
// then we wouldn't want the gun to be part of the bounds so set to false
target->GetActorBounds(bOnlyCollidingComponents, ActorOrigin, BoxExtent, bIncludeFromChildActors);
return FBox::BuildAABB(ActorOrigin, BoxExtent);
}
void UlxUtilityLibrary::AddMovementInputRightward(APawn *target, double ScaleValue, bool Force) {
FRotator rotator = target->GetControlRotation();
rotator.Pitch = 0.0;
rotator.Roll = 0.0;
rotator.Yaw += 90.0;
FVector vector = rotator.Vector();
target->AddMovementInput(vector, ScaleValue, Force);
}
void UlxUtilityLibrary::AddMovementInputForward(APawn *target, double ScaleValue, bool Force) {
FRotator rotator = target->GetControlRotation();
rotator.Roll = 0.0;
rotator.Pitch = 0.0;
FVector vector = rotator.Vector();
target->AddMovementInput(vector, ScaleValue, Force);
}
UEnhancedInputLocalPlayerSubsystem *UlxUtilityLibrary::GetEnhancedInputLocalPlayerSubsystem(AController *Controller) {
APlayerController *pc = Cast<APlayerController>(Controller);
if (pc != nullptr) {
UEnhancedInputLocalPlayerSubsystem* subsys =
ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(pc->GetLocalPlayer());
if (subsys != nullptr) {
return subsys;
}
}
return nullptr;
}
FVector2D UlxUtilityLibrary::PixelToViewportPosition(FVector2D Pixel)
{
FVector2D ViewportSize;
GEngine->GameViewport->GetViewportSize(ViewportSize);
return Pixel / ViewportSize;
}
FVector2D UlxUtilityLibrary::ViewportPositionToPixel(FVector2D Fraction, bool Snap)
{
FVector2D ViewportSize;
GEngine->GameViewport->GetViewportSize(ViewportSize);
FVector2D Pixel = Fraction * ViewportSize;
if (Snap)
{
Pixel.X = FMath::FloorToDouble(Pixel.X) + 0.5;
Pixel.Y = FMath::FloorToDouble(Pixel.Y) + 0.5;
Pixel.X = FMath::Min(ViewportSize.X - 0.5, FMath::Max(0.5, Pixel.X));
Pixel.Y = FMath::Min(ViewportSize.Y - 0.5, FMath::Max(0.5, Pixel.Y));
}
else
{
Pixel.X = FMath::Min(ViewportSize.X, FMath::Max(0.0, Pixel.X));
Pixel.Y = FMath::Min(ViewportSize.Y, FMath::Max(0.0, Pixel.Y));
}
return Pixel;
}
bool UlxUtilityLibrary::LineTraceThroughPixel(const APlayerController* PlayerController,
FVector2D PixelXY, double MaxDistanceFromCamera,
ETraceTypeQuery TraceChannel, bool bTraceComplex, EDrawDebugTrace::Type DrawDebugType, bool bIgnorePlayerPawn,
const TArray<AActor*>& ActorsToIgnore, FHitResult& HitResult)
{
const FLinearColor TraceColor = FLinearColor::Red;
const FLinearColor TraceHitColor = FLinearColor::Green;
const double DrawTime = 1.0;
// Zero out the return values.
HitResult.Init();
// Sanity check the distance.
if (MaxDistanceFromCamera <= 0.0)
{
return false;
}
// Make sure there's a player pawn.
AActor *PlayerPawn = PlayerController->GetPawn();
if (!PlayerPawn) return false;
// Calculate the trace start and trace end positions in world space.
FVector WorldStart, WorldDirection, WorldEnd;
if (!UGameplayStatics::DeprojectScreenToWorld(PlayerController, PixelXY, WorldStart, WorldDirection))
{
return false;
}
WorldEnd = WorldStart + (WorldDirection * MaxDistanceFromCamera);
// Find the hit.
if (UKismetSystemLibrary::LineTraceSingle(PlayerPawn, WorldStart, WorldEnd, TraceChannel, bTraceComplex,
ActorsToIgnore, DrawDebugType, HitResult, bIgnorePlayerPawn, TraceColor, TraceHitColor, DrawTime))
{
return true;
}
// Fail.
HitResult.Init();
return false;
}
void UlxUtilityLibrary::SetPositionOfGridPanelMiddleCell(UGridPanel *GridPanel, FVector2D UpperLeftXY, FVector2D LowerRightXY)
{
if ((GridPanel == nullptr) || (GridPanel->ColumnFill.Num() != 3) || (GridPanel->RowFill.Num() != 3))
{
UE_LOG(LogBlueprint, Error, TEXT("SetPositionOfGridPanelMiddleCell only works on 3x3 GridPanels."));
return;
}
if ((LowerRightXY.X < UpperLeftXY.X) || (LowerRightXY.Y < UpperLeftXY.Y))
{
UE_LOG(LogBlueprint, Error, TEXT("LowerRightXY must be greater than or equal to UpperLeftXY"));
return;
}
UpperLeftXY.X = FMath::Clamp(UpperLeftXY.X, 0.0f, 1.0f);
UpperLeftXY.Y = FMath::Clamp(UpperLeftXY.Y, 0.0f, 1.0f);
LowerRightXY.X = FMath::Clamp(LowerRightXY.X, 0.0f, 1.0f);
LowerRightXY.Y = FMath::Clamp(LowerRightXY.Y, 0.0f, 1.0f);
GridPanel->SetRowFill(0, UpperLeftXY.Y);
GridPanel->SetRowFill(1, LowerRightXY.Y - UpperLeftXY.Y);
GridPanel->SetRowFill(2, 1.0 - LowerRightXY.Y);
GridPanel->SetColumnFill(0, UpperLeftXY.X);
GridPanel->SetColumnFill(1, LowerRightXY.X - UpperLeftXY.X);
GridPanel->SetColumnFill(2, 1.0 - LowerRightXY.X);
}
void UlxUtilityLibrary::GetPositionOfGridPanelMiddleCell(UGridPanel *GridPanel, FVector2D &UpperLeftXY, FVector2D &LowerRightXY)
{
TArray<float> &Col = GridPanel->ColumnFill;
TArray<float> &Row = GridPanel->RowFill;
// Set default return value for error situations.
UpperLeftXY.X = 0.0;
LowerRightXY.X = 1.0;
UpperLeftXY.Y = 0.0;
LowerRightXY.Y = 1.0;
if ((GridPanel == nullptr) || (Row.Num() != 3) || (Col.Num() != 3))
{
UE_LOG(LogBlueprint, Error, TEXT("SetPositionOfGridPanelMiddleCell only works on 3x3 GridPanels."));
return;
}
double TotalX = Col[0] + Col[1] + Col[2];
double TotalY = Row[0] + Row[1] + Row[2];
if (TotalX > 0)
{
UpperLeftXY.X = Col[0] / TotalX;
LowerRightXY.X = (Col[0] + Col[1]) / TotalX;
}
if (TotalY > 0)
{
UpperLeftXY.Y = Row[0] / TotalY;
LowerRightXY.Y = (Row[0] + Row[1]) / TotalY;
}
}
void UlxUtilityLibrary::MapAllKeyboardKeysToOneInputAction(UInputMappingContext *IMC, UInputAction *Action)
{
TArray<FKey> AllKeys;
EKeys::GetAllKeys(AllKeys);
// Map every keyboard key to the provided LuaAction
for (const FKey& Key : AllKeys)
{
if ((Key.IsValid()) &&
(Key.IsBindableInBlueprints()) &&
(Key.GetMenuCategory() == EKeys::NAME_KeyboardCategory) &&
(!Key.IsModifierKey()))
{
IMC->MapKey(Action, Key);
}
}
}