A modded EditSaber for making beat saber maps.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

5540 lines
145 KiB

/*
By Rama
*/
#include "VictoryBPLibraryPrivatePCH.h"
#include "VictoryBPFunctionLibrary.h"
//Foreground Window check, clipboard copy/paste
#include "Runtime/ApplicationCore/Public/HAL/PlatformApplicationMisc.h"
//FGPUDriverInfo GPU
#include "Runtime/Core/Public/GenericPlatform/GenericPlatformDriver.h"
//MD5 Hash
#include "Runtime/Core/Public/Misc/SecureHash.h"
#include "StaticMeshResources.h"
#include "HeadMountedDisplay.h"
#include "GenericTeamAgentInterface.h"
//For PIE error messages
#include "MessageLog.h"
#define LOCTEXT_NAMESPACE "Fun BP Lib"
//Use MessasgeLog like this: (see GameplayStatics.cpp
/*
#if WITH_EDITOR
FMessageLog("PIE").Error(FText::Format(LOCTEXT("SpawnObjectWrongClass", "SpawnObject wrong class: {0}'"), FText::FromString(GetNameSafe(*ObjectClass))));
#endif // WITH_EDITOR
*/
// To be able to perform regex operatins on level stream info package name
#if WITH_EDITOR
#include "Runtime/Core/Public/Internationalization/Regex.h"
#endif
//~~~ Image Wrapper ~~~
#include "ImageUtils.h"
#include "IImageWrapper.h"
#include "IImageWrapperModule.h"
//~~~ Image Wrapper ~~~
//Body Setup
#include "PhysicsEngine/BodySetup.h"
#include "DestructibleComponent.h"
//Apex issues, can add iOS here <3 Rama
#if PLATFORM_ANDROID || PLATFORM_HTML5 || PLATFORM_IOS
#ifdef WITH_APEX
#undef WITH_APEX
#endif
#define WITH_APEX 0
#endif //APEX EXCLUSIONS
//~~~ PhysX ~~~
#include "PhysXIncludes.h"
#include "PhysXPublic.h" //For the ptou conversions
//For Scene Locking using Epic's awesome helper macros like SCOPED_SCENE_READ_LOCK
#include "Runtime/Engine/Private/PhysicsEngine/PhysXSupport.h"
//~~~~~~~~~~~
#include "IXRTrackingSystem.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Saxon Rah Random Nodes
// Chrono and Random
//Order Matters,
// has to be after PhysX includes to avoid isfinite name definition issues
#include <chrono>
#include <random>
#include <string>
/*
~~~ Rama File Operations CopyRight ~~~
If you use any of my file operation code below,
please credit me somewhere appropriate as "Rama"
*/
template <class FunctorType>
class PlatformFileFunctor : public IPlatformFile::FDirectoryVisitor //GenericPlatformFile.h
{
public:
virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override
{
return Functor(FilenameOrDirectory, bIsDirectory);
}
PlatformFileFunctor(FunctorType&& FunctorInstance)
: Functor(MoveTemp(FunctorInstance))
{
}
private:
FunctorType Functor;
};
template <class Functor>
PlatformFileFunctor<Functor> MakeDirectoryVisitor(Functor&& FunctorInstance)
{
return PlatformFileFunctor<Functor>(MoveTemp(FunctorInstance));
}
static FDateTime GetFileTimeStamp(const FString& File)
{
return FPlatformFileManager::Get().GetPlatformFile().GetTimeStamp(*File);
}
static void SetTimeStamp(const FString& File, const FDateTime& TimeStamp)
{
FPlatformFileManager::Get().GetPlatformFile().SetTimeStamp(*File,TimeStamp);
}
//Radial Result Struct
struct FFileStampSort
{
FString* FileName;
FDateTime FileStamp;
FFileStampSort(FString* IN_Name, FDateTime Stamp)
: FileName(IN_Name)
, FileStamp(Stamp)
{}
};
//For Array::Sort()
FORCEINLINE bool operator< (const FFileStampSort& Left, const FFileStampSort& Right)
{
return Left.FileStamp < Right.FileStamp;
}
//Written by Rama, please credit me if you use this code elsewhere
static bool GetFiles(const FString& FullPathOfBaseDir, TArray<FString>& FilenamesOut, bool Recursive=false, const FString& FilterByExtension = "")
{
//Format File Extension, remove the "." if present
const FString FileExt = FilterByExtension.Replace(TEXT("."),TEXT("")).ToLower();
FString Str;
auto FilenamesVisitor = MakeDirectoryVisitor(
[&](const TCHAR* FilenameOrDirectory, bool bIsDirectory)
{
//Files
if ( ! bIsDirectory)
{
//Filter by Extension
if(FileExt != "")
{
Str = FPaths::GetCleanFilename(FilenameOrDirectory);
//Filter by Extension
if(FPaths::GetExtension(Str).ToLower() == FileExt)
{
if(Recursive)
{
FilenamesOut.Push(FilenameOrDirectory); //need whole path for recursive
}
else
{
FilenamesOut.Push(Str);
}
}
}
//Include All Filenames!
else
{
//Just the Directory
Str = FPaths::GetCleanFilename(FilenameOrDirectory);
if(Recursive)
{
FilenamesOut.Push(FilenameOrDirectory); //need whole path for recursive
}
else
{
FilenamesOut.Push(Str);
}
}
}
return true;
}
);
if(Recursive)
{
return FPlatformFileManager::Get().GetPlatformFile().IterateDirectoryRecursively(*FullPathOfBaseDir, FilenamesVisitor);
}
else
{
return FPlatformFileManager::Get().GetPlatformFile().IterateDirectory(*FullPathOfBaseDir, FilenamesVisitor);
}
}
static bool FileExists(const FString& File)
{
return FPlatformFileManager::Get().GetPlatformFile().FileExists(*File);
}
static bool FolderExists(const FString& Dir)
{
return FPlatformFileManager::Get().GetPlatformFile().DirectoryExists(*Dir);
}
static bool RenameFile(const FString& Dest, const FString& Source)
{
//Make sure file modification time gets updated!
SetTimeStamp(Source,FDateTime::Now());
return FPlatformFileManager::Get().GetPlatformFile().MoveFile(*Dest,*Source);
}
//Create Directory, Creating Entire Structure as Necessary
// so if JoyLevels and Folder1 do not exist in JoyLevels/Folder1/Folder2
// they will be created so that Folder2 can be created!
//This is my solution for fact that trying to create a directory fails
// if its super directories do not exist
static bool VCreateDirectory(FString FolderToMake) //not const so split can be used, and does not damage input
{
if(FolderExists(FolderToMake))
{
return true;
}
// Normalize all / and \ to TEXT("/") and remove any trailing TEXT("/") if the character before that is not a TEXT("/") or a colon
FPaths::NormalizeDirectoryName(FolderToMake);
//Normalize removes the last "/", but is needed by algorithm
// Guarantees While loop will end in a timely fashion.
FolderToMake += "/";
FString Base;
FString Left;
FString Remaining;
//Split off the Root
FolderToMake.Split(TEXT("/"),&Base,&Remaining);
Base += "/"; //add root text and Split Text to Base
while(Remaining != "")
{
Remaining.Split(TEXT("/"),&Left,&Remaining);
//Add to the Base
Base += Left + FString("/"); //add left and split text to Base
//Create Incremental Directory Structure!
if ( ! FPlatformFileManager::Get().GetPlatformFile().CreateDirectory(*Base) &&
! FPlatformFileManager::Get().GetPlatformFile().DirectoryExists(*Base) )
{
return false;
//~~~~~
}
}
return true;
}
/*
~~~ Rama File Operations CopyRight ~~~
If you use any of my file operation code above,
please credit me somewhere appropriate as "Rama"
*/
//////////////////////////////////////////////////////////////////////////
// UVictoryBPFunctionLibrary
UVictoryBPFunctionLibrary::UVictoryBPFunctionLibrary(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
//~~~~~~~~~~~~~~~~~~
// Level Generation
//~~~~~~~~~~~~~~~~~~
/*
CHANGE RETURN TYPE TO KISMET (or remove the kismet part)
AND THEN GIVE OPTION TO ADD OR SET ROTATION OF A KISMET
LoadedLevel->LevelTransform.SetRotation(FRotator(0, 120, 0).Quaternion());
//Trigger update!
GetWorld()->UpdateLevelStreaming();
*/
ULevelStreaming* UVictoryBPFunctionLibrary::VictoryLoadLevelInstance(
UObject* WorldContextObject,
FString MapFolderOffOfContent,
FString LevelName,
int32 InstanceNumber,
FVector Location, FRotator Rotation,bool& Success
){
Success = false;
if(!WorldContextObject) return nullptr;
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return nullptr;
//~~~~~~~~~~~
//Full Name
FString FullName = "/Game/" + MapFolderOffOfContent + "/" + LevelName;
FName LevelFName = FName(*FullName);
FString PackageFileName = FullName;
ULevelStreamingKismet* StreamingLevel = NewObject<ULevelStreamingKismet>(World, ULevelStreamingKismet::StaticClass(), NAME_None, RF_Transient, NULL);
if(!StreamingLevel)
{
return nullptr;
}
//Long Package Name
FString LongLevelPackageName = FPackageName::FilenameToLongPackageName(PackageFileName);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Here is where a unique name is chosen for the new level asset
// Ensure unique names to gain ability to have multiple instances of same level!
// <3 Rama
//Create Unique Name based on BP-supplied instance value
FString UniqueLevelPackageName = LongLevelPackageName;
UniqueLevelPackageName += "_VictoryInstance_" + FString::FromInt(InstanceNumber);
//Set!
StreamingLevel->SetWorldAssetByPackageName(FName(*UniqueLevelPackageName));
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (World->IsPlayInEditor())
{
FWorldContext WorldContext = GEngine->GetWorldContextFromWorldChecked(World);
StreamingLevel->RenameForPIE(WorldContext.PIEInstance);
}
StreamingLevel->LevelColor = FColor::MakeRandomColor();
StreamingLevel->bShouldBeLoaded = true;
StreamingLevel->bShouldBeVisible = true;
StreamingLevel->bShouldBlockOnLoad = false;
StreamingLevel->bInitiallyLoaded = true;
StreamingLevel->bInitiallyVisible = true;
//Transform
StreamingLevel->LevelTransform = FTransform(Rotation,Location);
StreamingLevel->PackageNameToLoad = LevelFName;
if (!FPackageName::DoesPackageExist(StreamingLevel->PackageNameToLoad.ToString(), NULL, &PackageFileName))
{
return nullptr;
}
//~~~
//Actual map package to load
StreamingLevel->PackageNameToLoad = FName(*LongLevelPackageName);
//~~~
// Add the new level to world.
World->StreamingLevels.Add(StreamingLevel);
Success = true;
return StreamingLevel;
}
//~~~~~~~
// AI
//~~~~~~~
EPathFollowingRequestResult::Type UVictoryBPFunctionLibrary::Victory_AI_MoveToWithFilter(
APawn* Pawn,
const FVector& Dest,
TSubclassOf<UNavigationQueryFilter> FilterClass ,
float AcceptanceRadius ,
bool bProjectDestinationToNavigation ,
bool bStopOnOverlap ,
bool bCanStrafe
){
if(!Pawn)
{
return EPathFollowingRequestResult::Failed;
}
AAIController* AIControl = Cast<AAIController>(Pawn->GetController());
if(!AIControl)
{
return EPathFollowingRequestResult::Failed;
}
return AIControl->MoveToLocation(
Dest,
AcceptanceRadius,
bStopOnOverlap, //bStopOnOverlap
true, //bUsePathfinding
bProjectDestinationToNavigation,
bCanStrafe, //bCanStrafe
FilterClass //<~~~
);
}
//~~~~~~
//GPU
//~~~~~~
void UVictoryBPFunctionLibrary::Victory_GetGPUInfo(FString& DeviceDescription, FString& Provider, FString& DriverVersion, FString& DriverDate )
{
FGPUDriverInfo GPUDriverInfo = FPlatformMisc::GetGPUDriverInfo(GRHIAdapterName);
DeviceDescription = GPUDriverInfo.DeviceDescription;
Provider = GPUDriverInfo.ProviderName;
DriverVersion = GPUDriverInfo.UserDriverVersion;
DriverDate = GPUDriverInfo.DriverDate;
}
//~~~~~~
//Core
//~~~~~~
//~~~~~~
//Physics
//~~~~~~
float UVictoryBPFunctionLibrary::GetDistanceToCollision(UPrimitiveComponent* CollisionComponent, const FVector& Point, FVector& ClosestPointOnCollision)
{
if(!CollisionComponent) return -1;
return CollisionComponent->GetDistanceToCollision(Point,ClosestPointOnCollision);
}
float UVictoryBPFunctionLibrary::GetDistanceBetweenComponentSurfaces(UPrimitiveComponent* CollisionComponent1, UPrimitiveComponent* CollisionComponent2, FVector& PointOnSurface1, FVector& PointOnSurface2)
{
if(!CollisionComponent1 || !CollisionComponent2) return -1;
//Closest Point on 2 to 1
CollisionComponent2->GetDistanceToCollision(CollisionComponent1->GetComponentLocation(), PointOnSurface2);
//Closest Point on 1 to closest point on surface of 2
return CollisionComponent1->GetDistanceToCollision(PointOnSurface2, PointOnSurface1);
}
void UVictoryBPFunctionLibrary::VictoryCreateProc(int32& ProcessId, FString FullPathOfProgramToRun,TArray<FString> CommandlineArgs,bool Detach,bool Hidden, int32 Priority, FString OptionalWorkingDirectory)
{
//Please note ProcessId should really be uint32 but that is not supported by BP yet
FString Args = "";
if(CommandlineArgs.Num() > 1)
{
Args = CommandlineArgs[0];
for(int32 v = 1; v < CommandlineArgs.Num(); v++)
{
Args += " " + CommandlineArgs[v];
}
}
else if(CommandlineArgs.Num() > 0)
{
Args = CommandlineArgs[0];
}
uint32 NeedBPUINT32 = 0;
FProcHandle ProcHandle = FPlatformProcess::CreateProc(
*FullPathOfProgramToRun,
*Args,
Detach,//* @param bLaunchDetached if true, the new process will have its own window
false,//* @param bLaunchHidded if true, the new process will be minimized in the task bar
Hidden,//* @param bLaunchReallyHidden if true, the new process will not have a window or be in the task bar
&NeedBPUINT32,
Priority,
(OptionalWorkingDirectory != "") ? *OptionalWorkingDirectory : nullptr,//const TCHAR* OptionalWorkingDirectory,
nullptr
);
//Not sure what to do to expose UINT32 to BP
ProcessId = NeedBPUINT32;
}
bool UVictoryBPFunctionLibrary::CompareMD5Hash(FString MD5HashFile1, FString MD5HashFile2 )
{
//Load Hash Files
TArray<uint8> TheBinaryArray;
if (!FFileHelper::LoadFileToArray(TheBinaryArray, *MD5HashFile1))
{
UE_LOG(LogTemp,Error,TEXT("First hash file invalid %s"), *MD5HashFile1);
return false;
//~~
}
FMemoryReader FromBinary = FMemoryReader(TheBinaryArray, true); //true, free data after done
FMD5Hash FirstHash;
FromBinary << FirstHash;
TheBinaryArray.Empty();
if (!FFileHelper::LoadFileToArray(TheBinaryArray, *MD5HashFile2))
{
UE_LOG(LogTemp,Error,TEXT("second hash file invalid %s"), *MD5HashFile2);
return false;
//~~
}
FMemoryReader FromBinarySecond = FMemoryReader(TheBinaryArray, true); //true, free data after done
FMD5Hash SecondHash;
FromBinarySecond << SecondHash;
return FirstHash == SecondHash;
}
bool UVictoryBPFunctionLibrary::CreateMD5Hash(FString FileToHash, FString FileToStoreHashTo )
{
if(!FPlatformFileManager::Get().GetPlatformFile().FileExists(*FileToHash))
{
UE_LOG(LogTemp,Error,TEXT("File to hash not found %d"), *FileToHash);
return false;
}
int64 SizeOfFileToHash = FPlatformFileManager::Get().GetPlatformFile().FileSize(*FileToHash);
if(SizeOfFileToHash > 2 * 1000000000)
{
UE_LOG(LogTemp,Warning,TEXT("File is >2gb, hashing will be very slow %d"), SizeOfFileToHash);
}
FMD5Hash FileHash = FMD5Hash::HashFile(*FileToHash);
//write to file
FBufferArchive ToBinary;
ToBinary << FileHash;
if (FFileHelper::SaveArrayToFile(ToBinary, * FileToStoreHashTo))
{
// Free Binary Array
ToBinary.FlushCache();
ToBinary.Empty();
}
else
{
UE_LOG(LogTemp,Warning,TEXT("File hashed successfully but could not be saved to disk, file IO error %s"), *FileToHash);
return false;
}
return true;
}
bool UVictoryBPFunctionLibrary::VictoryPhysics_UpdateAngularDamping(UPrimitiveComponent* CompToUpdate, float NewAngularDamping)
{
if(!CompToUpdate) return false;
FBodyInstance* Body = CompToUpdate->GetBodyInstance();
if(!Body) return false;
//Deep safety check
if(!Body->IsValidBodyInstance()) return false;
//Set!
Body->AngularDamping = NewAngularDamping;
//~~~~~~~~~~~~~~~~~
Body->UpdateDampingProperties();
//~~~~~~~~~~~~~~~~~
return true;
}
bool UVictoryBPFunctionLibrary::VictoryDestructible_DestroyChunk(UDestructibleComponent* DestructibleComp, int32 HitItem)
{
#if WITH_APEX
if(!DestructibleComp)
{
return false;
}
//Visibility
DestructibleComp->SetChunkVisible( HitItem, false );
//Collision
physx::PxShape** PShapes;
const physx::PxU32 PShapeCount = DestructibleComp->ApexDestructibleActor->getChunkPhysXShapes(PShapes, HitItem);
if (PShapeCount > 0)
{
PxFilterData PQueryFilterData,PSimFilterData; //null data
for(uint32 ShapeIndex = 0; ShapeIndex < PShapeCount; ++ShapeIndex)
{
PxShape* Shape = PShapes[ShapeIndex];
if(!Shape) continue;
{
SCOPED_SCENE_WRITE_LOCK(Shape->getActor()->getScene());
Shape->setQueryFilterData(PQueryFilterData); //null data
Shape->setSimulationFilterData(PSimFilterData); //null data
Shape->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, false);
Shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
Shape->setFlag(PxShapeFlag::eVISUALIZATION, false);
}
}
}
return true;
#endif //WITH_APEX
UE_LOG(LogTemp,Error,TEXT("UVictoryBPFunctionLibrary::VictoryDestructible_DestroyChunk ~ Current Platform does not support APEX"));
return false;
}
static int32 GetChildBones(const FReferenceSkeleton& ReferenceSkeleton, int32 ParentBoneIndex, TArray<int32> & Children)
{
Children.Empty();
const int32 NumBones = ReferenceSkeleton.GetNum();
for(int32 ChildIndex=ParentBoneIndex+1; ChildIndex<NumBones; ChildIndex++)
{
if ( ParentBoneIndex == ReferenceSkeleton.GetParentIndex(ChildIndex) )
{
Children.Add(ChildIndex);
}
}
return Children.Num();
}
static void GetChildBoneNames_Recursive(USkeletalMeshComponent* SkeletalMeshComp, int32 ParentBoneIndex, TArray<FName>& ChildBoneNames)
{
TArray<int32> BoneIndicies;
GetChildBones(SkeletalMeshComp->SkeletalMesh->RefSkeleton, ParentBoneIndex, BoneIndicies);
if(BoneIndicies.Num() < 1)
{
//Stops the recursive skeleton search
return;
}
for(const int32& BoneIndex : BoneIndicies)
{
FName ChildBoneName = SkeletalMeshComp->GetBoneName(BoneIndex);
ChildBoneNames.Add(ChildBoneName);
//Recursion
GetChildBoneNames_Recursive(SkeletalMeshComp, BoneIndex,ChildBoneNames);
}
}
int32 UVictoryBPFunctionLibrary::GetAllBoneNamesBelowBone( USkeletalMeshComponent* SkeletalMeshComp, FName StartingBoneName, TArray<FName>& BoneNames )
{
BoneNames.Empty();
if(!SkeletalMeshComp || !SkeletalMeshComp->SkeletalMesh)
{
return -1;
//~~~~
}
int32 StartingBoneIndex = SkeletalMeshComp->GetBoneIndex(StartingBoneName);
//Recursive
GetChildBoneNames_Recursive(SkeletalMeshComp, StartingBoneIndex, BoneNames);
return BoneNames.Num();
}
//~~~~~~
// File IO
//~~~~~~
bool UVictoryBPFunctionLibrary::JoyFileIO_GetFiles(TArray<FString>& Files, FString RootFolderFullPath, FString Ext)
{
if(RootFolderFullPath.Len() < 1) return false;
FPaths::NormalizeDirectoryName(RootFolderFullPath);
IFileManager& FileManager = IFileManager::Get();
if(!Ext.Contains(TEXT("*")))
{
if(Ext == "")
{
Ext = "*.*";
}
else
{
Ext = (Ext.Left(1) == ".") ? "*" + Ext : "*." + Ext;
}
}
FString FinalPath = RootFolderFullPath + "/" + Ext;
FileManager.FindFiles(Files, *FinalPath, true, false);
return true;
}
bool UVictoryBPFunctionLibrary::JoyFileIO_GetFilesInRootAndAllSubFolders(TArray<FString>& Files, FString RootFolderFullPath, FString Ext)
{
if(RootFolderFullPath.Len() < 1) return false;
FPaths::NormalizeDirectoryName(RootFolderFullPath);
IFileManager& FileManager = IFileManager::Get();
if(!Ext.Contains(TEXT("*")))
{
if(Ext == "")
{
Ext = "*.*";
}
else
{
Ext = (Ext.Left(1) == ".") ? "*" + Ext : "*." + Ext;
}
}
FileManager.FindFilesRecursive(Files, *RootFolderFullPath, *Ext, true, false);
return true;
}
bool UVictoryBPFunctionLibrary::ScreenShots_Rename_Move_Most_Recent(
FString& OriginalFileName,
FString NewName,
FString NewAbsoluteFolderPath,
bool HighResolution
){
OriginalFileName = "None";
//File Name given?
if(NewName.Len() <= 0) return false;
//Normalize
FPaths::NormalizeDirectoryName(NewAbsoluteFolderPath);
//Ensure target directory exists,
// _or can be created!_ <3 Rama
if(!VCreateDirectory(NewAbsoluteFolderPath)) return false;
FString ScreenShotsDir = VictoryPaths__ScreenShotsDir();
//Find all screenshots
TArray<FString> Files; //false = not recursive, not expecting subdirectories
bool Success = GetFiles(ScreenShotsDir, Files, false);
if(!Success)
{
return false;
}
//Filter
TArray<FString> ToRemove; //16 bytes each, more stable than ptrs though since RemoveSwap is involved
for(FString& Each : Files)
{
if(HighResolution)
{
//remove those that dont have it
if(Each.Left(4) != "High")
{
ToRemove.Add(Each);
}
}
else
{
//Remove those that have it!
if(Each.Left(4) == "High")
{
ToRemove.Add(Each);
}
}
}
//Remove!
for(FString& Each : ToRemove)
{
Files.RemoveSwap(Each); //Fast remove! Does not preserve order
}
//No files?
if(Files.Num() < 1)
{
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Rama's Sort Files by Time Stamp Feature
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Sort the file names by time stamp
// This is my custom c++ struct to do this,
// combined with my operator< and UE4's
// TArray::Sort() function!
TArray<FFileStampSort> FileSort;
for(FString& Each : Files)
{
FileSort.Add(FFileStampSort(&Each,GetFileTimeStamp(Each)));
}
//Sort all the file names by their Time Stamp!
FileSort.Sort();
//Biggest value = last entry
OriginalFileName = *FileSort.Last().FileName;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Generate new Full File Path!
FString NewFullFilePath = NewAbsoluteFolderPath + "/" + NewName + ".png";
//Move File!
return RenameFile(NewFullFilePath, ScreenShotsDir + "/" + OriginalFileName);
}
void UVictoryBPFunctionLibrary::VictoryISM_GetAllVictoryISMActors(UObject* WorldContextObject, TArray<AVictoryISM*>& Out)
{
if(!WorldContextObject) return;
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return;
//~~~~~~~~~~~
Out.Empty();
for(TActorIterator<AVictoryISM> Itr(World); Itr; ++Itr)
{
Out.Add(*Itr);
}
}
void UVictoryBPFunctionLibrary::VictoryISM_ConvertToVictoryISMActors(
UObject* WorldContextObject,
TSubclassOf<AActor> ActorClass,
TArray<AVictoryISM*>& CreatedISMActors,
bool DestroyOriginalActors,
int32 MinCountToCreateISM
){
//User Input Safety
if(MinCountToCreateISM < 1) MinCountToCreateISM = 1; //require for array access safety
CreatedISMActors.Empty();
if(!WorldContextObject) return;
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return;
//~~~~~~~~~~~
//I want one array of actors for each unique static mesh asset! -Rama
TMap< UStaticMesh*,TArray<AActor*> > VictoryISMMap;
//Note the ActorClass filter on the Actor Iterator! -Rama
for (TActorIterator<AActor> Itr(World, ActorClass); Itr; ++Itr)
{
//Get Static Mesh Component!
UStaticMeshComponent* Comp = Itr->FindComponentByClass<UStaticMeshComponent>();
if(!Comp) continue;
if(!Comp->IsValidLowLevel()) continue;
//~~~~~~~~~
//Add Key if not present!
if(!VictoryISMMap.Contains(Comp->GetStaticMesh()))
{
VictoryISMMap.Add(Comp->GetStaticMesh());
VictoryISMMap[Comp->GetStaticMesh()].Empty(); //ensure array is properly initialized
}
//Add the actor!
VictoryISMMap[Comp->GetStaticMesh()].Add(*Itr);
}
//For each Static Mesh Asset in the Victory ISM Map
for (TMap< UStaticMesh*,TArray<AActor*> >::TIterator It(VictoryISMMap); It; ++It)
{
//Get the Actor Array for this particular Static Mesh Asset!
TArray<AActor*>& ActorArray = It.Value();
//No entries?
if(ActorArray.Num() < MinCountToCreateISM) continue;
//~~~~~~~~~~~~~~~~~~
//Get the Root
UStaticMeshComponent* RootSMC = ActorArray[0]->FindComponentByClass<UStaticMeshComponent>();
if(!RootSMC) continue;
//~~~~~~~~~~
//Gather transforms!
TArray<FTransform> WorldTransforms;
for(AActor* Each : ActorArray)
{
WorldTransforms.Add(Each->GetTransform());
//Destroy original?
if(DestroyOriginalActors)
{
Each->Destroy();
}
}
//Create Victory ISM
FActorSpawnParameters SpawnInfo;
//SpawnInfo.bNoCollisionFail = true; //always create!
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
SpawnInfo.bDeferConstruction = false;
AVictoryISM* NewISM = World->SpawnActor<AVictoryISM>(
AVictoryISM::StaticClass(),
RootSMC->GetComponentLocation() ,
RootSMC->GetComponentRotation(),
SpawnInfo
);
if(!NewISM) continue;
//~~~~~~~~~~
//Mesh
NewISM->Mesh->SetStaticMesh(RootSMC->GetStaticMesh());
//Materials
const int32 MatTotal = RootSMC->GetNumMaterials();
for(int32 v = 0; v < MatTotal; v++)
{
NewISM->Mesh->SetMaterial(v,RootSMC->GetMaterial(v));
}
//Set Transforms!
for(const FTransform& Each : WorldTransforms)
{
NewISM->Mesh->AddInstanceWorldSpace(Each);
}
//Add new ISM!
CreatedISMActors.Add(NewISM);
}
//Clear memory
VictoryISMMap.Empty();
}
void UVictoryBPFunctionLibrary::SaveGameObject_GetAllSaveSlotFileNames(TArray<FString>& FileNames)
{
FileNames.Empty();
FString Path = VictoryPaths__SavedDir() + "SaveGames";
GetFiles(Path,FileNames); //see top of this file, my own file IO code - Rama
}
//~~~ Victory Paths ~~~
FString UVictoryBPFunctionLibrary::VictoryPaths__Win64Dir_BinaryLocation()
{
return FString(FPlatformProcess::BaseDir());
}
FString UVictoryBPFunctionLibrary::VictoryPaths__WindowsNoEditorDir()
{
return FPaths::ConvertRelativePathToFull(FPaths::RootDir());
}
FString UVictoryBPFunctionLibrary::VictoryPaths__GameRootDirectory()
{
return FPaths::ConvertRelativePathToFull(FPaths::ProjectDir());
}
FString UVictoryBPFunctionLibrary::VictoryPaths__SavedDir()
{
return FPaths::ConvertRelativePathToFull(FPaths::ProjectSavedDir());
}
FString UVictoryBPFunctionLibrary::VictoryPaths__ConfigDir()
{
return FPaths::ConvertRelativePathToFull(FPaths::ProjectConfigDir());
}
FString UVictoryBPFunctionLibrary::VictoryPaths__ScreenShotsDir()
{
return FPaths::ConvertRelativePathToFull(FPaths::ScreenShotDir());
}
FString UVictoryBPFunctionLibrary::VictoryPaths__LogsDir()
{
return FPaths::ConvertRelativePathToFull(FPaths::ProjectLogDir());
}
//~~~~~~~~~~~~~~~~~
FVector2D UVictoryBPFunctionLibrary::Vector2DInterpTo(FVector2D Current, FVector2D Target, float DeltaTime, float InterpSpeed)
{
return FMath::Vector2DInterpTo( Current, Target, DeltaTime, InterpSpeed );
}
FVector2D UVictoryBPFunctionLibrary::Vector2DInterpTo_Constant(FVector2D Current, FVector2D Target, float DeltaTime, float InterpSpeed)
{
return FMath::Vector2DInterpConstantTo( Current, Target, DeltaTime, InterpSpeed );
}
float UVictoryBPFunctionLibrary::MapRangeClamped(float Value, float InRangeA, float InRangeB, float OutRangeA, float OutRangeB)
{
return FMath::GetMappedRangeValueClamped(FVector2D(InRangeA,InRangeB),FVector2D(OutRangeA,OutRangeB),Value);
}
FVictoryInput UVictoryBPFunctionLibrary::VictoryGetVictoryInput(const FKeyEvent& KeyEvent)
{
FVictoryInput VInput;
VInput.Key = KeyEvent.GetKey();
VInput.KeyAsString = VInput.Key.GetDisplayName().ToString();
VInput.bAlt = KeyEvent.IsAltDown();
VInput.bCtrl = KeyEvent.IsControlDown();
VInput.bShift = KeyEvent.IsShiftDown();
VInput.bCmd = KeyEvent.IsCommandDown();
return VInput;
}
FVictoryInputAxis UVictoryBPFunctionLibrary::VictoryGetVictoryInputAxis(const FKeyEvent& KeyEvent)
{
FVictoryInputAxis VInput;
VInput.Key = KeyEvent.GetKey();
VInput.KeyAsString = VInput.Key.GetDisplayName().ToString();
VInput.Scale = 1;
return VInput;
}
void UVictoryBPFunctionLibrary::VictoryGetAllAxisKeyBindings(TArray<FVictoryInputAxis>& Bindings)
{
Bindings.Empty();
const UInputSettings* Settings = GetDefault<UInputSettings>();
if(!Settings) return;
const TArray<FInputAxisKeyMapping>& Axi = Settings->AxisMappings;
for(const FInputAxisKeyMapping& Each : Axi)
{
Bindings.Add(FVictoryInputAxis(Each));
}
}
void UVictoryBPFunctionLibrary::VictoryRemoveAxisKeyBind(FVictoryInputAxis ToRemove)
{
//GetMutableDefault
UInputSettings* Settings = GetMutableDefault<UInputSettings>();
if(!Settings) return;
TArray<FInputAxisKeyMapping>& Axi = Settings->AxisMappings;
bool Found = false;
for(int32 v = 0; v < Axi.Num(); v++)
{
if(Axi[v].Key == ToRemove.Key)
{
Found = true;
Axi.RemoveAt(v);
v = 0;
continue;
}
}
if(Found)
{
//SAVES TO DISK
Settings->SaveKeyMappings();
//REBUILDS INPUT, creates modified config in Saved/Config/Windows/Input.ini
for (TObjectIterator<UPlayerInput> It; It; ++It)
{
It->ForceRebuildingKeyMaps(true);
}
}
}
void UVictoryBPFunctionLibrary::VictoryGetAllActionKeyBindings(TArray<FVictoryInput>& Bindings)
{
Bindings.Empty();
const UInputSettings* Settings = GetDefault<UInputSettings>();
if(!Settings) return;
const TArray<FInputActionKeyMapping>& Actions = Settings->ActionMappings;
for(const FInputActionKeyMapping& Each : Actions)
{
Bindings.Add(FVictoryInput(Each));
}
}
void UVictoryBPFunctionLibrary::VictoryRemoveActionKeyBind(FVictoryInput ToRemove)
{
//GetMutableDefault
UInputSettings* Settings = GetMutableDefault<UInputSettings>();
if(!Settings) return;
TArray<FInputActionKeyMapping>& Actions = Settings->ActionMappings;
bool Found = false;
for(int32 v = 0; v < Actions.Num(); v++)
{
if(Actions[v].Key == ToRemove.Key)
{
Found = true;
Actions.RemoveAt(v);
v = 0;
continue;
}
}
if(Found)
{
//SAVES TO DISK
Settings->SaveKeyMappings();
//REBUILDS INPUT, creates modified config in Saved/Config/Windows/Input.ini
for (TObjectIterator<UPlayerInput> It; It; ++It)
{
It->ForceRebuildingKeyMaps(true);
}
}
}
void UVictoryBPFunctionLibrary::VictoryGetAllAxisAndActionMappingsForKey(FKey Key, TArray<FVictoryInput>& ActionBindings, TArray<FVictoryInputAxis>& AxisBindings)
{
ActionBindings.Empty();
AxisBindings.Empty();
const UInputSettings* Settings = GetDefault<UInputSettings>();
if(!Settings) return;
const TArray<FInputActionKeyMapping>& Actions = Settings->ActionMappings;
for(const FInputActionKeyMapping& Each : Actions)
{
if(Each.Key == Key)
{
ActionBindings.Add(FVictoryInput(Each));
}
}
const TArray<FInputAxisKeyMapping>& Axi = Settings->AxisMappings;
for(const FInputAxisKeyMapping& Each : Axi)
{
if(Each.Key == Key)
{
AxisBindings.Add(FVictoryInputAxis(Each));
}
}
}
bool UVictoryBPFunctionLibrary::VictoryReBindAxisKey(FVictoryInputAxis Original, FVictoryInputAxis NewBinding)
{
UInputSettings* Settings = const_cast<UInputSettings*>(GetDefault<UInputSettings>());
if(!Settings) return false;
TArray<FInputAxisKeyMapping>& Axi = Settings->AxisMappings;
//~~~
bool Found = false;
for(FInputAxisKeyMapping& Each : Axi)
{
//Search by original
if(Each.AxisName.ToString() == Original.AxisName &&
Each.Key == Original.Key
){
//Update to new!
UVictoryBPFunctionLibrary::UpdateAxisMapping(Each,NewBinding);
Found = true;
break;
}
}
if(Found)
{
//SAVES TO DISK
const_cast<UInputSettings*>(Settings)->SaveKeyMappings();
//REBUILDS INPUT, creates modified config in Saved/Config/Windows/Input.ini
for (TObjectIterator<UPlayerInput> It; It; ++It)
{
It->ForceRebuildingKeyMaps(true);
}
}
return Found;
}
bool UVictoryBPFunctionLibrary::VictoryReBindActionKey(FVictoryInput Original, FVictoryInput NewBinding)
{
UInputSettings* Settings = const_cast<UInputSettings*>(GetDefault<UInputSettings>());
if(!Settings) return false;
TArray<FInputActionKeyMapping>& Actions = Settings->ActionMappings;
//~~~
bool Found = false;
for(FInputActionKeyMapping& Each : Actions)
{
//Search by original
if(Each.ActionName.ToString() == Original.ActionName &&
Each.Key == Original.Key
){
//Update to new!
UVictoryBPFunctionLibrary::UpdateActionMapping(Each,NewBinding);
Found = true;
break;
}
}
if(Found)
{
//SAVES TO DISK
const_cast<UInputSettings*>(Settings)->SaveKeyMappings();
//REBUILDS INPUT, creates modified config in Saved/Config/Windows/Input.ini
for (TObjectIterator<UPlayerInput> It; It; ++It)
{
It->ForceRebuildingKeyMaps(true);
}
}
return Found;
}
void UVictoryBPFunctionLibrary::GetAllWidgetsOfClass(UObject* WorldContextObject, TSubclassOf<UUserWidget> WidgetClass, TArray<UUserWidget*>& FoundWidgets,bool TopLevelOnly)
{
//Prevent possibility of an ever-growing array if user uses this in a loop
FoundWidgets.Empty();
//~~~~~~~~~~~~
if(!WidgetClass) return;
if(!WorldContextObject) return;
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return;
//~~~~~~~~~~~
for(TObjectIterator<UUserWidget> Itr; Itr; ++Itr)
{
if(Itr->GetWorld() != World) continue;
//~~~~~~~~~~~~~~~~~~~~~
if( ! Itr->IsA(WidgetClass)) continue;
//~~~~~~~~~~~~~~~~~~~
//Top Level?
if(TopLevelOnly)
{
//only add top level widgets
if(Itr->IsInViewport())
{
FoundWidgets.Add(*Itr);
}
}
else
{
//add all internal widgets
FoundWidgets.Add(*Itr);
}
}
}
void UVictoryBPFunctionLibrary::RemoveAllWidgetsOfClass(UObject* WorldContextObject, TSubclassOf<UUserWidget> WidgetClass)
{
if(!WidgetClass) return;
if(!WorldContextObject) return;
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return;
//~~~~~~~~~~~
for(TObjectIterator<UUserWidget> Itr; Itr; ++Itr)
{
if(Itr->GetWorld() != World) continue;
//~~~~~~~~~~~~~~~~~~~~~
if( ! Itr->IsA(WidgetClass)) continue;
//~~~~~~~~~~~~~~~~~~~
//only add top level widgets
if(Itr->IsInViewport()) //IsInViewport in 4.6
{
Itr->RemoveFromViewport();
}
}
}
bool UVictoryBPFunctionLibrary::IsWidgetOfClassInViewport(UObject* WorldContextObject, TSubclassOf<UUserWidget> WidgetClass)
{
if(!WidgetClass) return false;
if(!WorldContextObject) return false;
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return false;
//~~~~~~~~~~~
for(TObjectIterator<UUserWidget> Itr; Itr; ++Itr)
{
if(Itr->GetWorld() != World) continue;
//~~~~~~~~~~~~~~~~~~~~~
if( ! Itr->IsA(WidgetClass)) continue;
//~~~~~~~~~~~~~~~~~~~
if(Itr->GetIsVisible()) //IsInViewport in 4.6
{
return true;
}
}
return false;
}
void UVictoryBPFunctionLibrary::ServerTravel(UObject* WorldContextObject, FString MapName,bool bNotifyPlayers)
{
if(!WorldContextObject) return;
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return;
//~~~~~~~~~~~
World->ServerTravel(MapName,false,bNotifyPlayers); //abs //notify players
}
APlayerStart* UVictoryBPFunctionLibrary::GetPlayerStart(UObject* WorldContextObject,FString PlayerStartName)
{
if(!WorldContextObject) return nullptr;
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return nullptr;
//~~~~~~~~~~~
for(TActorIterator<APlayerStart> Itr(World); Itr; ++Itr)
{
if(Itr->GetName() == PlayerStartName)
{
return *Itr;
}
}
return nullptr;
}
bool UVictoryBPFunctionLibrary::VictorySoundVolumeChange(USoundClass* SoundClassObject, float NewVolume)
{
if(!SoundClassObject)
{
return false;
}
SoundClassObject->Properties.Volume = NewVolume;
return true;
/*
FAudioDevice* Device = GEngine->GetAudioDevice();
if (!Device || !SoundClassObject)
{
return false;
}
bool bFound = Device->SoundClasses.Contains(SoundClassObject);
if(bFound)
{
Device->SetClassVolume(SoundClassObject, NewVolume);
return true;
}
return false;
*/
/*
bool SetBaseSoundMix( class USoundMix* SoundMix );
*/
}
float UVictoryBPFunctionLibrary::VictoryGetSoundVolume(USoundClass* SoundClassObject)
{
if (!SoundClassObject)
{
return -1;
}
return SoundClassObject->Properties.Volume;
/*
FAudioDevice* Device = GEngine->GetMainAudioDevice();
if (!Device || !SoundClassObject)
{
return -1;
}
FSoundClassProperties* Props = Device->GetSoundClassCurrentProperties(SoundClassObject);
if(!Props) return -1;
return Props->Volume;
*/
}
void UVictoryBPFunctionLibrary::VictoryIntPlusEquals(UPARAM(ref) int32& Int, int32 Add, int32& IntOut)
{
Int += Add;
IntOut = Int;
}
void UVictoryBPFunctionLibrary::VictoryIntMinusEquals(UPARAM(ref) int32& Int, int32 Sub, int32& IntOut)
{
Int -= Sub;
IntOut = Int;
}
void UVictoryBPFunctionLibrary::VictoryFloatPlusEquals(UPARAM(ref) float& Float, float Add, float& FloatOut)
{
Float += Add;
FloatOut = Float;
}
void UVictoryBPFunctionLibrary::VictoryFloatMinusEquals(UPARAM(ref) float& Float, float Sub, float& FloatOut)
{
Float -= Sub;
FloatOut = Float;
}
void UVictoryBPFunctionLibrary::VictorySortIntArray(UPARAM(ref) TArray<int32>& IntArray, TArray<int32>& IntArrayRef)
{
IntArray.Sort();
IntArrayRef = IntArray;
}
void UVictoryBPFunctionLibrary::VictorySortFloatArray(UPARAM(ref) TArray<float>& FloatArray, TArray<float>& FloatArrayRef)
{
FloatArray.Sort();
FloatArrayRef = FloatArray;
}
//String Back To Type
void UVictoryBPFunctionLibrary::Conversions__StringToVector(const FString& String, FVector& ConvertedVector, bool& IsValid)
{
IsValid = ConvertedVector.InitFromString( String );
}
void UVictoryBPFunctionLibrary::Conversions__StringToRotator(const FString& String, FRotator& ConvertedRotator, bool& IsValid)
{
IsValid = ConvertedRotator.InitFromString( String );
}
void UVictoryBPFunctionLibrary::Conversions__StringToColor(const FString& String, FLinearColor& ConvertedColor, bool& IsValid)
{
IsValid = ConvertedColor.InitFromString( String );
}
void UVictoryBPFunctionLibrary::Conversions__ColorToString(const FLinearColor& Color, FString& ColorAsString)
{
ColorAsString = Color.ToString();
}
//String Back To Type
//! not working yet, always getting 255
/*
uint8 UVictoryBPFunctionLibrary::Victory_ConvertStringToByte(UEnum* Enum, FString String)
{
if( !Enum ) return 255;
return Enum->GetIndexByName(*String);
}
*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool UVictoryBPFunctionLibrary::VictoryGetCustomConfigVar_Bool(FString SectionName,FString VariableName, bool& IsValid)
{
if(!GConfig) return false;
//~~~~~~~~~~~
bool Value;
IsValid = GConfig->GetBool(
*SectionName,
*VariableName,
Value,
GGameIni
);
return Value;
}
int32 UVictoryBPFunctionLibrary::VictoryGetCustomConfigVar_Int(FString SectionName,FString VariableName, bool& IsValid)
{
if(!GConfig) return 0;
//~~~~~~~~~~~
int32 Value;
IsValid = GConfig->GetInt(
*SectionName,
*VariableName,
Value,
GGameIni
);
return Value;
}
float UVictoryBPFunctionLibrary::VictoryGetCustomConfigVar_Float(FString SectionName,FString VariableName, bool& IsValid)
{
if(!GConfig) return 0;
//~~~~~~~~~~~
float Value;
IsValid = GConfig->GetFloat(
*SectionName,
*VariableName,
Value,
GGameIni
);
return Value;
}
FVector UVictoryBPFunctionLibrary::VictoryGetCustomConfigVar_Vector(FString SectionName,FString VariableName, bool& IsValid)
{
if(!GConfig) return FVector::ZeroVector;
//~~~~~~~~~~~
FVector Value;
IsValid = GConfig->GetVector(
*SectionName,
*VariableName,
Value,
GGameIni
);
return Value;
}
FRotator UVictoryBPFunctionLibrary::VictoryGetCustomConfigVar_Rotator(FString SectionName,FString VariableName, bool& IsValid)
{
if(!GConfig) return FRotator::ZeroRotator;
//~~~~~~~~~~~
FRotator Value;
IsValid = GConfig->GetRotator(
*SectionName,
*VariableName,
Value,
GGameIni
);
return Value;
}
FLinearColor UVictoryBPFunctionLibrary::VictoryGetCustomConfigVar_Color(FString SectionName,FString VariableName, bool& IsValid)
{
if(!GConfig) return FColor::Black;
//~~~~~~~~~~~
FColor Value;
IsValid = GConfig->GetColor(
*SectionName,
*VariableName,
Value,
GGameIni
);
return FLinearColor(Value);
}
FString UVictoryBPFunctionLibrary::VictoryGetCustomConfigVar_String(FString SectionName,FString VariableName, bool& IsValid)
{
if(!GConfig) return "";
//~~~~~~~~~~~
FString Value;
IsValid = GConfig->GetString(
*SectionName,
*VariableName,
Value,
GGameIni
);
return Value;
}
FVector2D UVictoryBPFunctionLibrary::VictoryGetCustomConfigVar_Vector2D(FString SectionName, FString VariableName, bool& IsValid)
{
if(!GConfig) return FVector2D::ZeroVector;
//~~~~~~~~~~~
FVector Value;
IsValid = GConfig->GetVector(
*SectionName,
*VariableName,
Value,
GGameIni
);
return FVector2D(Value.X,Value.Y);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void UVictoryBPFunctionLibrary::VictorySetCustomConfigVar_Vector2D(FString SectionName, FString VariableName, FVector2D Value)
{
if(!GConfig) return;
//~~~~~~~~~~~
GConfig->SetVector(
*SectionName,
*VariableName,
FVector(Value.X,Value.Y,0),
GGameIni
);
}
void UVictoryBPFunctionLibrary::VictorySetCustomConfigVar_Bool(FString SectionName,FString VariableName, bool Value)
{
if(!GConfig) return;
//~~~~~~~~~~~
GConfig->SetBool(
*SectionName,
*VariableName,
Value,
GGameIni
);
}
void UVictoryBPFunctionLibrary::VictorySetCustomConfigVar_Int(FString SectionName,FString VariableName, int32 Value)
{
if(!GConfig) return;
//~~~~~~~~~~~
GConfig->SetInt(
*SectionName,
*VariableName,
Value,
GGameIni
);
}
void UVictoryBPFunctionLibrary::VictorySetCustomConfigVar_Float(FString SectionName,FString VariableName, float Value)
{
if(!GConfig) return;
//~~~~~~~~~~~
GConfig->SetFloat(
*SectionName,
*VariableName,
Value,
GGameIni
);
}
void UVictoryBPFunctionLibrary::VictorySetCustomConfigVar_Vector(FString SectionName,FString VariableName, FVector Value)
{
if(!GConfig) return;
//~~~~~~~~~~~
GConfig->SetVector(
*SectionName,
*VariableName,
Value,
GGameIni
);
}
void UVictoryBPFunctionLibrary::VictorySetCustomConfigVar_Rotator(FString SectionName,FString VariableName, FRotator Value)
{
if(!GConfig) return;
//~~~~~~~~~~~
GConfig->SetRotator(
*SectionName,
*VariableName,
Value,
GGameIni
);
}
void UVictoryBPFunctionLibrary::VictorySetCustomConfigVar_Color(FString SectionName,FString VariableName, FLinearColor Value)
{
if(!GConfig) return;
//~~~~~~~~~~~
GConfig->SetColor(
*SectionName,
*VariableName,
Value.ToFColor(true),
GGameIni
);
}
void UVictoryBPFunctionLibrary::VictorySetCustomConfigVar_String(FString SectionName,FString VariableName, FString Value)
{
if(!GConfig) return;
//~~~~~~~~~~~
GConfig->SetString(
*SectionName,
*VariableName,
*Value,
GGameIni
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FName UVictoryBPFunctionLibrary::GetHeadMountedDisplayDeviceType()
{
/*
4.19
The IHeadMountedDisplay::GetHMDDeviceType() method has been removed as it was not extensible
enough. Code that needs know which XR plugin is currently active should use
IXRTrackingSystem::GetSystemName() instead.
*/
if(!GEngine) return "None";
if (GEngine->XRSystem.IsValid() && GEngine->XRSystem->GetHMDDevice())
{
//Actively connected?
if(!GEngine->XRSystem->GetHMDDevice()->IsHMDConnected())
{
return "None";
}
//!See IIdentifiableXRDevice.h
return GEngine->XRSystem->GetSystemName();
}
return "None";
}
UObject* UVictoryBPFunctionLibrary::LoadObjectFromAssetPath(TSubclassOf<UObject> ObjectClass,FName Path,bool& IsValid)
{
IsValid = false;
if(Path == NAME_None) return NULL;
//~~~~~~~~~~~~~~~~~~~~~
UObject* LoadedObj = StaticLoadObject( ObjectClass, NULL,*Path.ToString());
IsValid = LoadedObj != nullptr;
return LoadedObj;
}
FName UVictoryBPFunctionLibrary::GetObjectPath(UObject* Obj)
{
if(!Obj) return NAME_None;
if(!Obj->IsValidLowLevel()) return NAME_None;
//~~~~~~~~~~~~~~~~~~~~~~~~~
FStringAssetReference ThePath = FStringAssetReference(Obj);
if(!ThePath.IsValid()) return "";
//The Class FString Name For This Object
FString str=Obj->GetClass()->GetDescription();
//Remove spaces in Material Instance Constant class description!
str = str.Replace(TEXT(" "),TEXT(""));
str += "'";
str += ThePath.ToString();
str += "'";
return FName(*str);
}
int32 UVictoryBPFunctionLibrary::GetPlayerUniqueNetID()
{
TObjectIterator<APlayerController> ThePC;
if(!ThePC) return -1;
if(!ThePC->PlayerState) return -1;
//~~~~~~~~~~~~~~~~~~~
return ThePC->PlayerState->PlayerId;
}
UObject* UVictoryBPFunctionLibrary::CreateObject(UObject* WorldContextObject,UClass* TheObjectClass)
{
//See deprecation warning
// Deprecation warning makes it no longer appear in context menu as a new node to add
return nullptr;
/*
if(!TheObjectClass) return NULL;
//~~~~~~~~~~~~~~~~~
//using a context object to get the world!
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return NULL;
//~~~~~~~~~~~
//Need to submit pull request for custom name and custom class both
return NewObject<UObject>(World,TheObjectClass);
*/
}
UPrimitiveComponent* UVictoryBPFunctionLibrary::CreatePrimitiveComponent(
UObject* WorldContextObject,
TSubclassOf<UPrimitiveComponent> CompClass,
FName Name,
FVector Location,
FRotator Rotation
){
if(!CompClass) return NULL;
//~~~~~~~~~~~~~~~~~
//using a context object to get the world!
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return NULL;
//~~~~~~~~~~~
UPrimitiveComponent* NewComp = NewObject<UPrimitiveComponent>(World, Name);
if(!NewComp) return NULL;
//~~~~~~~~~~~~~
NewComp->SetWorldLocation(Location);
NewComp->SetWorldRotation(Rotation);
NewComp->RegisterComponentWithWorld(World);
return NewComp;
}
AActor* UVictoryBPFunctionLibrary::SpawnActorIntoLevel(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass, FName Level, FVector Location, FRotator Rotation,bool SpawnEvenIfColliding)
{
if(!ActorClass) return NULL;
//~~~~~~~~~~~~~~~~~
//using a context object to get the world!
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return NULL;
//~~~~~~~~~~~
FActorSpawnParameters SpawnParameters;
if (SpawnEvenIfColliding)
{
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
}
SpawnParameters.bDeferConstruction = false;
//Get Level from Name!
ULevel* FoundLevel = NULL;
for(const ULevelStreaming* EachLevel : World->StreamingLevels)
{
if( ! EachLevel) continue;
//~~~~~~~~~~~~~~~~
ULevel* LevelPtr = EachLevel->GetLoadedLevel();
//Valid?
if(!LevelPtr) continue;
if(EachLevel->GetWorldAssetPackageFName() == Level)
{
FoundLevel = LevelPtr;
break;
}
}
//~~~~~~~~~~~~~~~~~~~~~
if(FoundLevel)
{
SpawnParameters.OverrideLevel = FoundLevel;
}
//~~~~~~~~~~~~~~~~~~~~~
return World->SpawnActor( ActorClass, &Location, &Rotation, SpawnParameters);
}
void UVictoryBPFunctionLibrary::GetNamesOfLoadedLevels(UObject* WorldContextObject, TArray<FString>& NamesOfLoadedLevels)
{
//using a context object to get the world!
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return;
//~~~~~~~~~~~
NamesOfLoadedLevels.Empty();
//Get Level from Name!
ULevel* FoundLevel = NULL;
for(const ULevelStreaming* EachLevel : World->StreamingLevels)
{
if( ! EachLevel) continue;
//~~~~~~~~~~~~~~~~
ULevel* LevelPtr = EachLevel->GetLoadedLevel();
//Valid?
if(!LevelPtr) continue;
//Is This Level Visible?
if(!LevelPtr->bIsVisible) continue;
//~~~~~~~~~~~~~~~~~~~
NamesOfLoadedLevels.Add(EachLevel->GetWorldAssetPackageFName().ToString());
}
}
void UVictoryBPFunctionLibrary::Loops_ResetBPRunawayCounter()
{
//Reset Runaway loop counter (use carefully)
GInitRunaway();
}
void UVictoryBPFunctionLibrary::GraphicsSettings__SetFrameRateToBeUnbound()
{
if(!GEngine) return;
//~~~~~~~~~
GEngine->bSmoothFrameRate = 0;
}
void UVictoryBPFunctionLibrary::GraphicsSettings__SetFrameRateCap(float NewValue)
{
if(!GEngine) return;
//~~~~~~~~~
GEngine->bSmoothFrameRate = 1;
GEngine->SmoothedFrameRateRange = FFloatRange(10,NewValue);
}
FVector2D UVictoryBPFunctionLibrary::ProjectWorldToScreenPosition(const FVector& WorldLocation)
{
TObjectIterator<APlayerController> ThePC;
if(!ThePC) return FVector2D::ZeroVector;
ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(ThePC->Player);
if (LocalPlayer != NULL && LocalPlayer->ViewportClient != NULL && LocalPlayer->ViewportClient->Viewport != NULL)
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a view family for the game viewport
FSceneViewFamilyContext ViewFamily( FSceneViewFamily::ConstructionValues(
LocalPlayer->ViewportClient->Viewport,
ThePC->GetWorld()->Scene,
LocalPlayer->ViewportClient->EngineShowFlags )
.SetRealtimeUpdate(true) );
// Calculate a view where the player is to update the streaming from the players start location
FVector ViewLocation;
FRotator ViewRotation;
FSceneView* SceneView = LocalPlayer->CalcSceneView( &ViewFamily, /*out*/ ViewLocation, /*out*/ ViewRotation, LocalPlayer->ViewportClient->Viewport );
//Valid Scene View?
if (SceneView)
{
//Return
FVector2D ScreenLocation;
SceneView->WorldToPixel(WorldLocation,ScreenLocation );
return ScreenLocation;
}
}
return FVector2D::ZeroVector;
}
bool UVictoryBPFunctionLibrary::GetStaticMeshVertexLocations(UStaticMeshComponent* Comp, TArray<FVector>& VertexPositions)
{
VertexPositions.Empty();
if(!Comp)
{
return false;
}
if(!Comp->IsValidLowLevel())
{
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~
//Component Transform
FTransform RV_Transform = Comp->GetComponentTransform();
//Body Setup valid?
UBodySetup* BodySetup = Comp->GetBodySetup();
if(!BodySetup || !BodySetup->IsValidLowLevel())
{
return false;
}
for(PxTriangleMesh* EachTriMesh : BodySetup->TriMeshes)
{
if (!EachTriMesh)
{
return false;
}
//~~~~~~~~~~~~~~~~
//Number of vertices
PxU32 VertexCount = EachTriMesh->getNbVertices();
//Vertex array
const PxVec3* Vertices = EachTriMesh->getVertices();
//For each vertex, transform the position to match the component Transform
for (PxU32 v = 0; v < VertexCount; v++)
{
VertexPositions.Add(RV_Transform.TransformPosition(P2UVector(Vertices[v])));
}
}
return true;
/*
//See this wiki for more info on getting triangles
// https://wiki.unrealengine.com/Accessing_mesh_triangles_and_vertex_positions_in_build
*/
}
void UVictoryBPFunctionLibrary::AddToActorRotation(AActor* TheActor, FRotator AddRot)
{
if (!TheActor) return;
//~~~~~~~~~~~
FTransform TheTransform = TheActor->GetTransform();
TheTransform.ConcatenateRotation(AddRot.Quaternion());
TheTransform.NormalizeRotation();
TheActor->SetActorTransform(TheTransform);
}
void UVictoryBPFunctionLibrary::DrawCircle(
UObject* WorldContextObject,
FVector Center,
float Radius,
int32 NumPoints,
float Thickness,
FLinearColor LineColor,
FVector YAxis,
FVector ZAxis,
float Duration,
bool PersistentLines
){
if(!WorldContextObject) return ;
//using a context object to get the world!
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return;
//~~~~~~~~~~~
/* //FOR PULL REQUEST TO EPIC
FMatrix TM;
TM.SetOrigin(Center);
TM.SetAxis(0, FVector(1,0,0));
TM.SetAxis(1, YAxis);
TM.SetAxis(2, ZAxis);
DrawDebugCircle(
World,
TM,
Radius, NumPoints,
FColor::Red,
false,
-1.f,
0
);
*/
// Need at least 4 segments
NumPoints = FMath::Max(NumPoints, 4);
const float AngleStep = 2.f * PI / float(NumPoints);
float Angle = 0.f;
for(int32 v = 0; v < NumPoints; v++)
{
const FVector Vertex1 = Center + Radius * (YAxis * FMath::Cos(Angle) + ZAxis * FMath::Sin(Angle));
Angle += AngleStep;
const FVector Vertex2 = Center + Radius * (YAxis * FMath::Cos(Angle) + ZAxis * FMath::Sin(Angle));
DrawDebugLine(
World,
Vertex1,
Vertex2,
LineColor.ToFColor(true),
PersistentLines,
Duration,
0, //depth
Thickness
);
}
}
bool UVictoryBPFunctionLibrary::LoadStringArrayFromFile(TArray<FString>& StringArray, int32& ArraySize, FString FullFilePath, bool ExcludeEmptyLines)
{
ArraySize = 0;
if(FullFilePath == "" || FullFilePath == " ") return false;
//Empty any previous contents!
StringArray.Empty();
TArray<FString> FileArray;
if( ! FFileHelper::LoadANSITextFileToStrings(*FullFilePath, NULL, FileArray))
{
return false;
}
if(ExcludeEmptyLines)
{
for(const FString& Each : FileArray )
{
if(Each == "") continue;
//~~~~~~~~~~~~~
//check for any non whitespace
bool FoundNonWhiteSpace = false;
for(int32 v = 0; v < Each.Len(); v++)
{
if(Each[v] != ' ' && Each[v] != '\n')
{
FoundNonWhiteSpace = true;
break;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
if(FoundNonWhiteSpace)
{
StringArray.Add(Each);
}
}
}
else
{
StringArray.Append(FileArray);
}
ArraySize = StringArray.Num();
return true;
}
AActor* UVictoryBPFunctionLibrary::GetClosestActorOfClassInRadiusOfLocation(
UObject* WorldContextObject,
TSubclassOf<AActor> ActorClass,
FVector Center,
float Radius,
bool& IsValid
){
IsValid = false;
//using a context object to get the world!
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return NULL;
//~~~~~~~~~~~
AActor* ClosestActor = NULL;
float MinDistanceSq = Radius*Radius; //Max Radius
for (TActorIterator<AActor> Itr(World, ActorClass); Itr; ++Itr)
{
const float DistanceSquared = FVector::DistSquared(Center, Itr->GetActorLocation());
//Is this the closest possible actor within the max radius?
if (DistanceSquared < MinDistanceSq)
{
ClosestActor = *Itr; //New Output!
MinDistanceSq = DistanceSquared; //New Min!
}
}
if (ClosestActor)
{
IsValid = true;
}
return ClosestActor;
}
AActor* UVictoryBPFunctionLibrary::GetClosestActorOfClassInRadiusOfActor(
UObject* WorldContextObject,
TSubclassOf<AActor> ActorClass,
AActor* ActorCenter,
float Radius,
bool& IsValid
){
IsValid = false;
if(!ActorCenter)
{
return nullptr;
}
const FVector Center = ActorCenter->GetActorLocation();
//using a context object to get the world!
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return NULL;
//~~~~~~~~~~~
AActor* ClosestActor = NULL;
float MinDistanceSq = Radius*Radius; //Max Radius
for (TActorIterator<AActor> Itr(World, ActorClass); Itr; ++Itr)
{
//Skip ActorCenter!
if(*Itr == ActorCenter) continue;
//~~~~~~~~~~~~~~~~~
const float DistanceSquared = FVector::DistSquared(Center, Itr->GetActorLocation());
//Is this the closest possible actor within the max radius?
if (DistanceSquared < MinDistanceSq)
{
ClosestActor = *Itr; //New Output!
MinDistanceSq = DistanceSquared; //New Min!
}
}
if (ClosestActor)
{
IsValid = true;
}
return ClosestActor;
}
void UVictoryBPFunctionLibrary::Selection_SelectionBox(UObject* WorldContextObject,TArray<AActor*>& SelectedActors, FVector2D AnchorPoint,FVector2D DraggedPoint,TSubclassOf<AActor> ClassFilter)
{
if(!WorldContextObject) return ;
//using a context object to get the world!
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return;
//~~~~~~~~~~~
SelectedActors.Empty();
FBox2D Box;
Box+=DraggedPoint;
Box+=AnchorPoint;
for(TActorIterator<AActor> Itr(World); Itr; ++Itr)
{
if(!Itr->IsA(ClassFilter)) continue;
//~~~~~~~~~~~~~~~~~~
if(Box.IsInside(UVictoryBPFunctionLibrary::ProjectWorldToScreenPosition(Itr->GetActorLocation())))
{
SelectedActors.Add(*Itr);
}
}
}
bool UVictoryBPFunctionLibrary::PlayerController_GetControllerID(APlayerController* ThePC, int32& ControllerID)
{
if(!ThePC) return false;
ULocalPlayer * LP = Cast<ULocalPlayer>(ThePC->Player);
if(!LP) return false;
ControllerID = LP->GetControllerId();
return true;
}
bool UVictoryBPFunctionLibrary::PlayerState_GetPlayerID(APlayerController* ThePC, int32& PlayerID)
{
if(!ThePC) return false;
if(!ThePC->PlayerState) return false;
PlayerID = ThePC->PlayerState->PlayerId;
return true;
}
void UVictoryBPFunctionLibrary::Open_URL_In_Web_Browser(FString TheURL)
{
FPlatformProcess::LaunchURL( *TheURL, nullptr, nullptr );
}
void UVictoryBPFunctionLibrary::OperatingSystem__GetCurrentPlatform(
bool& Windows_, //some weird bug of making it all caps engine-side
bool& Mac,
bool& Linux,
bool& iOS,
bool& Android,
bool& Android_ARM,
bool& Android_Vulkan,
bool& PS4,
bool& XBoxOne,
bool& HTML5,
bool& Apple
){
//#define's in UE4 source code
Windows_ = PLATFORM_WINDOWS;
Mac = PLATFORM_MAC;
Linux = PLATFORM_LINUX;
PS4 = PLATFORM_PS4;
XBoxOne = PLATFORM_XBOXONE;
iOS = PLATFORM_IOS;
Android = PLATFORM_ANDROID;
Android_ARM = PLATFORM_ANDROID_ARM;
Android_Vulkan = PLATFORM_ANDROID_VULKAN;
HTML5 = PLATFORM_HTML5;
Apple = PLATFORM_APPLE;
}
FString UVictoryBPFunctionLibrary::RealWorldTime__GetCurrentOSTime(
int32& MilliSeconds,
int32& Seconds,
int32& Minutes,
int32& Hours12,
int32& Hours24,
int32& Day,
int32& Month,
int32& Year
){
const FDateTime Now = FDateTime::Now();
MilliSeconds = Now.GetMillisecond( );
Seconds = Now.GetSecond( );
Minutes = Now.GetMinute( );
Hours12 = Now.GetHour12( );
Hours24 = Now.GetHour( ); //24
Day = Now.GetDay( );
Month = Now.GetMonth( );
Year = Now.GetYear( );
//MS are not included in FDateTime::ToString(), so adding it
//The Parse function accepts if MS are present.
FString NowWithMS = Now.ToString();
NowWithMS += "." + FString::FromInt(MilliSeconds);
return NowWithMS;
}
void UVictoryBPFunctionLibrary::RealWorldTime__GetTimePassedSincePreviousTime(
const FString& PreviousTime,
float& Milliseconds,
float& Seconds,
float& Minutes,
float& Hours
){
FDateTime ParsedDateTime;
FDateTime::Parse(PreviousTime,ParsedDateTime);
const FTimespan TimeDiff = FDateTime::Now() - ParsedDateTime;
Milliseconds = TimeDiff.GetTotalMilliseconds( );
Seconds = TimeDiff.GetTotalSeconds( );
Minutes = TimeDiff.GetTotalMinutes( );
Hours = TimeDiff.GetTotalHours( );
}
void UVictoryBPFunctionLibrary::RealWorldTime__GetDifferenceBetweenTimes(
const FString& PreviousTime1,
const FString& PreviousTime2,
float& Milliseconds,
float& Seconds,
float& Minutes,
float& Hours
){
FDateTime ParsedDateTime1;
FDateTime::Parse(PreviousTime1,ParsedDateTime1);
FDateTime ParsedDateTime2;
FDateTime::Parse(PreviousTime2,ParsedDateTime2);
FTimespan TimeDiff;
if(PreviousTime1 < PreviousTime2)
{
TimeDiff = ParsedDateTime2 - ParsedDateTime1;
}
else
{
TimeDiff = ParsedDateTime1 - ParsedDateTime2;
}
Milliseconds = TimeDiff.GetTotalMilliseconds( );
Seconds = TimeDiff.GetTotalSeconds( );
Minutes = TimeDiff.GetTotalMinutes( );
Hours = TimeDiff.GetTotalHours( );
}
void UVictoryBPFunctionLibrary::MaxOfFloatArray(const TArray<float>& FloatArray, int32& IndexOfMaxValue, float& MaxValue)
{
MaxValue = UVictoryBPFunctionLibrary::Max(FloatArray,&IndexOfMaxValue);
}
void UVictoryBPFunctionLibrary::MaxOfIntArray(const TArray<int32>& IntArray, int32& IndexOfMaxValue, int32& MaxValue)
{
MaxValue = UVictoryBPFunctionLibrary::Max(IntArray,&IndexOfMaxValue);
}
void UVictoryBPFunctionLibrary::MinOfFloatArray(const TArray<float>& FloatArray, int32& IndexOfMinValue, float& MinValue)
{
MinValue = UVictoryBPFunctionLibrary::Min(FloatArray,&IndexOfMinValue);
}
void UVictoryBPFunctionLibrary::MinOfIntArray(const TArray<int32>& IntArray, int32& IndexOfMinValue, int32& MinValue)
{
MinValue = UVictoryBPFunctionLibrary::Min(IntArray,&IndexOfMinValue);
}
bool UVictoryBPFunctionLibrary::CharacterMovement__SetMaxMoveSpeed(ACharacter* TheCharacter, float NewMaxMoveSpeed)
{
if(!TheCharacter)
{
return false;
}
if(!TheCharacter->GetCharacterMovement())
{
return false;
}
TheCharacter->GetCharacterMovement()->MaxWalkSpeed = NewMaxMoveSpeed;
return true;
}
int32 UVictoryBPFunctionLibrary::Conversion__FloatToRoundedInteger(float IN_Float)
{
return FGenericPlatformMath::RoundToInt(IN_Float);
}
FString UVictoryBPFunctionLibrary::Victory_SecondsToHoursMinutesSeconds(float Seconds, bool TrimZeroes)
{
FString Str = FTimespan(0, 0, Seconds).ToString();
if(TrimZeroes)
{
FString Left,Right;
Str.Split(TEXT("."),&Left,&Right);
Str = Left;
Str.ReplaceInline(TEXT("00:00"), TEXT("00"));
//Str Count!
int32 Count = CountOccurrancesOfSubString(Str,":");
//Remove Empty Hours
if(Count >= 2)
{
Str.ReplaceInline(TEXT("00:"), TEXT(""));
}
}
return Str;
}
bool UVictoryBPFunctionLibrary::IsAlphaNumeric(const FString& String)
{
std::string str = (TCHAR_TO_UTF8(*String));
for ( std::string::iterator it=str.begin(); it!=str.end(); ++it)
{
if(!isalnum(*it))
{
return false;
}
}
return true;
}
void UVictoryBPFunctionLibrary::Victory_GetStringFromOSClipboard(FString& FromClipboard)
{
FPlatformApplicationMisc::ClipboardPaste(FromClipboard);
}
void UVictoryBPFunctionLibrary::Victory_SaveStringToOSClipboard(const FString& ToClipboard)
{
FPlatformApplicationMisc::ClipboardCopy(*ToClipboard);
}
bool UVictoryBPFunctionLibrary::HasSubstring(const FString& SearchIn, const FString& Substring, ESearchCase::Type SearchCase, ESearchDir::Type SearchDir)
{
return SearchIn.Contains(Substring, SearchCase, SearchDir);
}
FString UVictoryBPFunctionLibrary::String__CombineStrings(FString StringFirst, FString StringSecond, FString Separator, FString StringFirstLabel, FString StringSecondLabel)
{
return StringFirstLabel + StringFirst + Separator + StringSecondLabel + StringSecond;
}
FString UVictoryBPFunctionLibrary::String__CombineStrings_Multi(FString A, FString B)
{
return A + " " + B;
}
bool UVictoryBPFunctionLibrary::OptionsMenu__GetDisplayAdapterScreenResolutions(TArray<int32>& Widths, TArray<int32>& Heights, TArray<int32>& RefreshRates,bool IncludeRefreshRates)
{
//Clear any Previous
Widths.Empty();
Heights.Empty();
RefreshRates.Empty();
TArray<FString> Unique;
FScreenResolutionArray Resolutions;
if(RHIGetAvailableResolutions(Resolutions, false))
{
for (const FScreenResolutionRHI& EachResolution : Resolutions)
{
FString Str = "";
Str += FString::FromInt(EachResolution.Width);
Str += FString::FromInt(EachResolution.Height);
//Include Refresh Rates?
if(IncludeRefreshRates)
{
Str += FString::FromInt(EachResolution.RefreshRate);
}
if(Unique.Contains(Str))
{
//Skip! This is duplicate!
continue;
}
else
{
//Add to Unique List!
Unique.AddUnique(Str);
}
//Add to Actual Data Output!
Widths.Add( EachResolution.Width);
Heights.Add( EachResolution.Height);
RefreshRates.Add( EachResolution.RefreshRate);
}
return true;
}
return false;
}
void UVictoryBPFunctionLibrary::GetUserDisplayAdapterBrand(bool& IsAMD, bool& IsNvidia, bool& IsIntel, bool& IsUnknown, int32& UnknownId)
{
IsAMD = IsRHIDeviceAMD();
IsNvidia = IsRHIDeviceNVIDIA();
IsIntel = IsRHIDeviceIntel();
IsUnknown = !IsAMD && !IsNvidia && !IsIntel;
if(IsUnknown)
{
UnknownId = GRHIVendorId;
}
}
//Make .h's for these two!
FRotator UVictoryBPFunctionLibrary::TransformVectorToActorSpaceAngle(AActor* Actor, const FVector& InVector)
{
if(!Actor) return FRotator::ZeroRotator;
return Actor->ActorToWorld().InverseTransformVector(InVector).Rotation();
}
FVector UVictoryBPFunctionLibrary::TransformVectorToActorSpace(AActor* Actor, const FVector& InVector)
{
if(!Actor) return FVector::ZeroVector;
return Actor->ActorToWorld().InverseTransformVector(InVector);
}
AStaticMeshActor* UVictoryBPFunctionLibrary::Clone__StaticMeshActor(UObject* WorldContextObject, bool&IsValid, AStaticMeshActor* ToClone, FVector LocationOffset,FRotator RotationOffset)
{
IsValid = false;
if(!ToClone) return NULL;
if(!ToClone->IsValidLowLevel()) return NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~
if(!WorldContextObject) return NULL;
//using a context object to get the world!
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return NULL;
//~~~~~~~~~~~
//For BPS
UClass* SpawnClass = ToClone->GetClass();
FActorSpawnParameters SpawnInfo;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
SpawnInfo.Owner = ToClone;
SpawnInfo.Instigator = NULL;
SpawnInfo.bDeferConstruction = false;
AStaticMeshActor* NewSMA = World->SpawnActor<AStaticMeshActor>(SpawnClass, ToClone->GetActorLocation() + FVector(0,0,512) ,ToClone->GetActorRotation(), SpawnInfo );
if(!NewSMA) return NULL;
//Copy Transform
NewSMA->SetActorTransform(ToClone->GetTransform());
//Mobility
NewSMA->GetStaticMeshComponent()->SetMobility(EComponentMobility::Movable );
//copy static mesh
NewSMA->GetStaticMeshComponent()->SetStaticMesh(ToClone->GetStaticMeshComponent()->GetStaticMesh());
//~~~
//copy materials
TArray<UMaterialInterface*> Mats;
ToClone->GetStaticMeshComponent()->GetUsedMaterials(Mats);
const int32 Total = Mats.Num();
for(int32 v = 0; v < Total; v++ )
{
NewSMA->GetStaticMeshComponent()->SetMaterial(v,Mats[v]);
}
//~~~
//copy physics state
if(ToClone->GetStaticMeshComponent()->IsSimulatingPhysics())
{
NewSMA->GetStaticMeshComponent()->SetSimulatePhysics(true);
}
//~~~
//Add Location Offset
const FVector SpawnLoc = ToClone->GetActorLocation() + LocationOffset;
NewSMA->SetActorLocation(SpawnLoc);
//Add Rotation offset
FTransform TheTransform = NewSMA->GetTransform();
TheTransform.ConcatenateRotation(RotationOffset.Quaternion());
TheTransform.NormalizeRotation();
//Set Transform
NewSMA->SetActorTransform(TheTransform);
IsValid = true;
return NewSMA;
}
bool UVictoryBPFunctionLibrary::Actor__TeleportToActor(AActor* ActorToTeleport, AActor* DestinationActor)
{
if(!ActorToTeleport) return false;
if(!ActorToTeleport->IsValidLowLevel()) return false;
if(!DestinationActor) return false;
if(!DestinationActor->IsValidLowLevel()) return false;
//Set Loc
ActorToTeleport->SetActorLocation(DestinationActor->GetActorLocation());
//Set Rot
ActorToTeleport->SetActorRotation(DestinationActor->GetActorRotation());
return true;
}
bool UVictoryBPFunctionLibrary::WorldType__InEditorWorld(UObject* WorldContextObject)
{
if(!WorldContextObject) return false;
//using a context object to get the world!
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return false;
//~~~~~~~~~~~
return (World->WorldType == EWorldType::Editor );
}
bool UVictoryBPFunctionLibrary::WorldType__InPIEWorld(UObject* WorldContextObject)
{
if(!WorldContextObject) return false;
//using a context object to get the world!
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return false;
//~~~~~~~~~~~
return (World->WorldType == EWorldType::PIE );
}
bool UVictoryBPFunctionLibrary::WorldType__InGameInstanceWorld(UObject* WorldContextObject)
{
if(!WorldContextObject) return false;
//using a context object to get the world!
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return false;
//~~~~~~~~~~~
return (World->WorldType == EWorldType::Game );
}
bool UVictoryBPFunctionLibrary::DoesMaterialHaveParameter(UMaterialInterface* Mat, FName Parameter)
{
if(!Mat || Parameter == NAME_None)
{
return false;
}
//Lesson, always use the parent of a Material Instance Dynamic,
// for some reason the dynamic version finds parameters that aren't actually valid.
// -Rama
UMaterialInterface* Parent = Mat;
UMaterialInstance* MatInst = Cast<UMaterialInstance>(Mat);
if(MatInst)
{
Parent = MatInst->Parent;
}
if(!Parent)
{
return false;
}
float ScalarValue;
if(Parent->GetScalarParameterValue(Parameter,ScalarValue))
{
return true;
}
FLinearColor VectValue;
if(Parent->GetVectorParameterValue(Parameter,VectValue))
{
return true;
}
UTexture* T2DValue;
return Parent->GetTextureParameterValue(Parameter,T2DValue);
}
FString UVictoryBPFunctionLibrary::Accessor__GetNameAsString(const UObject* TheObject)
{
if (!TheObject) return "";
return TheObject->GetName();
}
FRotator UVictoryBPFunctionLibrary::Conversions__VectorToRotator(const FVector& TheVector)
{
return TheVector.Rotation();
}
FVector UVictoryBPFunctionLibrary::Conversions__RotatorToVector(const FRotator& TheRotator)
{
return TheRotator.Vector();
}
FRotator UVictoryBPFunctionLibrary::Character__GetControllerRotation(AActor * TheCharacter)
{
ACharacter * AsCharacter = Cast<ACharacter>(TheCharacter);
if (!AsCharacter) return FRotator::ZeroRotator;
return AsCharacter->GetControlRotation();
}
//Draw From Socket on Character's Mesh
void UVictoryBPFunctionLibrary::Draw__Thick3DLineFromCharacterSocket(AActor* TheCharacter, const FVector& EndPoint, FName Socket, FLinearColor LineColor, float Thickness, float Duration)
{
ACharacter * AsCharacter = Cast<ACharacter>(TheCharacter);
if (!AsCharacter) return;
if (!AsCharacter->GetMesh()) return;
//~~~~~~~~~~~~~~~~~~~~
//Get World
UWorld* TheWorld = AsCharacter->GetWorld();
if (!TheWorld) return;
//~~~~~~~~~~~~~~~~~
const FVector SocketLocation = AsCharacter->GetMesh()->GetSocketLocation(Socket);
DrawDebugLine(
TheWorld,
SocketLocation,
EndPoint,
LineColor.ToFColor(true),
false,
Duration,
0,
Thickness
);
}
/** Draw 3D Line of Chosen Thickness From Mesh Socket to Destination */
void UVictoryBPFunctionLibrary::Draw__Thick3DLineFromSocket(USkeletalMeshComponent* Mesh, const FVector& EndPoint, FName Socket, FLinearColor LineColor, float Thickness, float Duration)
{
if (!Mesh) return;
//~~~~~~~~~~~~~~
//Get an actor to GetWorld() from
TObjectIterator<APlayerController> Itr;
if (!Itr) return;
//~~~~~~~~~~~~
//Get World
UWorld* TheWorld = Itr->GetWorld();
if (!TheWorld) return;
//~~~~~~~~~~~~~~~~~
const FVector SocketLocation = Mesh->GetSocketLocation(Socket);
DrawDebugLine(
TheWorld,
SocketLocation,
EndPoint,
LineColor.ToFColor(true),
false,
Duration,
0,
Thickness
);
}
/** Draw 3D Line of Chosen Thickness Between Two Actors */
void UVictoryBPFunctionLibrary::Draw__Thick3DLineBetweenActors(AActor * StartActor, AActor * EndActor, FLinearColor LineColor, float Thickness, float Duration)
{
if (!StartActor) return;
if (!EndActor) return;
//~~~~~~~~~~~~~~~~
DrawDebugLine(
StartActor->GetWorld(),
StartActor->GetActorLocation(),
EndActor->GetActorLocation(),
LineColor.ToFColor(true),
false,
Duration,
0,
Thickness
);
}
bool UVictoryBPFunctionLibrary::Animation__GetAimOffsets(AActor* AnimBPOwner, float& Pitch, float& Yaw)
{
//Get Owning Character
ACharacter * TheCharacter = Cast<ACharacter>(AnimBPOwner);
if (!TheCharacter) return false;
//~~~~~~~~~~~~~~~
//Get Owning Controller Rotation
const FRotator TheCtrlRotation = TheCharacter->GetControlRotation();
const FVector RotationDir = TheCtrlRotation.Vector();
//Inverse of ActorToWorld matrix is Actor to Local Space
//so this takes the direction vector, the PC or AI rotation
//and outputs what this dir is
//in local actor space &
//local actor space is what we want for aiming offsets
const FVector LocalDir = TheCharacter->ActorToWorld().InverseTransformVectorNoScale(RotationDir);
const FRotator LocalRotation = LocalDir.Rotation();
//Pass out Yaw and Pitch
Yaw = LocalRotation.Yaw;
Pitch = LocalRotation.Pitch;
return true;
}
bool UVictoryBPFunctionLibrary::Animation__GetAimOffsetsFromRotation(AActor * AnimBPOwner, const FRotator & TheRotation, float & Pitch, float & Yaw)
{
//Get Owning Character
ACharacter * TheCharacter = Cast<ACharacter>(AnimBPOwner);
if (!TheCharacter) return false;
//~~~~~~~~~~~~~~~
//using supplied rotation
const FVector RotationDir = TheRotation.Vector();
//Inverse of ActorToWorld matrix is Actor to Local Space
//so this takes the direction vector, the PC or AI rotation
//and outputs what this dir is
//in local actor space &
//local actor space is what we want for aiming offsets
const FVector LocalDir = TheCharacter->ActorToWorld().InverseTransformVectorNoScale(RotationDir);
const FRotator LocalRotation = LocalDir.Rotation();
//Pass out Yaw and Pitch
Yaw = LocalRotation.Yaw;
Pitch = LocalRotation.Pitch;
return true;
}
void UVictoryBPFunctionLibrary::Visibility__GetRenderedActors(UObject* WorldContextObject, TArray<AActor*>& CurrentlyRenderedActors, float MinRecentTime)
{
if(!WorldContextObject) return;
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return;
//~~~~~~~~~~~
//Empty any previous entries
CurrentlyRenderedActors.Empty();
//Iterate Over Actors
for ( TActorIterator<AActor> Itr(World); Itr; ++Itr )
{
if (World->GetTimeSeconds() - Itr->GetLastRenderTime() <= MinRecentTime)
{
CurrentlyRenderedActors.Add( * Itr);
}
}
}
void UVictoryBPFunctionLibrary::Visibility__GetNotRenderedActors(UObject* WorldContextObject, TArray<AActor*>& CurrentlyNotRenderedActors, float MinRecentTime)
{
if(!WorldContextObject) return;
UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!World) return;
//~~~~~~~~~~~
//Empty any previous entries
CurrentlyNotRenderedActors.Empty();
//Iterate Over Actors
for ( TActorIterator<AActor> Itr(World); Itr; ++Itr )
{
if (World->GetTimeSeconds() - Itr->GetLastRenderTime() > MinRecentTime)
{
CurrentlyNotRenderedActors.Add( * Itr);
}
}
}
void UVictoryBPFunctionLibrary::Rendering__FreezeGameRendering()
{
FViewport::SetGameRenderingEnabled(false);
}
void UVictoryBPFunctionLibrary::Rendering__UnFreezeGameRendering()
{
FViewport::SetGameRenderingEnabled(true);
}
bool UVictoryBPFunctionLibrary::ClientWindow__GameWindowIsForeGroundInOS()
{
return FPlatformApplicationMisc::IsThisApplicationForeground();
/*
//Iterate Over Actors
UWorld* TheWorld = NULL;
for ( TObjectIterator<AActor> Itr; Itr; ++Itr )
{
TheWorld = Itr->GetWorld();
if (TheWorld) break;
//~~~~~~~~~~~~~~~~~~~~~~~
}
//Get Player
ULocalPlayer* VictoryPlayer =
TheWorld->GetFirstLocalPlayerFromController();
if (!VictoryPlayer) return false;
//~~~~~~~~~~~~~~~~~~~~
//get view port ptr
UGameViewportClient * VictoryViewportClient =
Cast < UGameViewportClient > (VictoryPlayer->ViewportClient);
if (!VictoryViewportClient) return false;
//~~~~~~~~~~~~~~~~~~~~
FViewport * VictoryViewport = VictoryViewportClient->Viewport;
if (!VictoryViewport) return false;
//~~~~~~~~~~~~~~~~~~~~
return VictoryViewport->IsForegroundWindow();
*/
}
bool UVictoryBPFunctionLibrary::FileIO__SaveStringTextToFile(
FString SaveDirectory,
FString JoyfulFileName,
FString SaveText,
bool AllowOverWriting
){
if(!FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*SaveDirectory))
{
//Could not make the specified directory
return false;
//~~~~~~~~~~~~~~~~~~~~~~
}
//get complete file path
SaveDirectory += "\\";
SaveDirectory += JoyfulFileName;
//No over-writing?
if (!AllowOverWriting)
{
//Check if file exists already
if (FPlatformFileManager::Get().GetPlatformFile().FileExists( * SaveDirectory))
{
//no overwriting
return false;
}
}
return FFileHelper::SaveStringToFile(SaveText, * SaveDirectory);
}
bool UVictoryBPFunctionLibrary::FileIO__SaveStringArrayToFile(FString SaveDirectory, FString JoyfulFileName, TArray<FString> SaveText, bool AllowOverWriting)
{
//Dir Exists?
if ( !VCreateDirectory(SaveDirectory))
{
//Could not make the specified directory
return false;
//~~~~~~~~~~~~~~~~~~~~~~
}
//get complete file path
SaveDirectory += "\\";
SaveDirectory += JoyfulFileName;
//No over-writing?
if (!AllowOverWriting)
{
//Check if file exists already
if (FPlatformFileManager::Get().GetPlatformFile().FileExists( * SaveDirectory))
{
//no overwriting
return false;
}
}
FString FinalStr = "";
for(FString& Each : SaveText)
{
FinalStr += Each;
FinalStr += LINE_TERMINATOR;
}
return FFileHelper::SaveStringToFile(FinalStr, * SaveDirectory);
}
float UVictoryBPFunctionLibrary::Calcs__ClosestPointToSourcePoint(const FVector & Source, const TArray<FVector>& OtherPoints, FVector& ClosestPoint)
{
float CurDist = 0;
float ClosestDistance = -1;
int32 ClosestVibe = 0;
ClosestPoint = FVector::ZeroVector;
if (OtherPoints.Num() <= 0) return ClosestDistance;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (int32 Itr = 0; Itr < OtherPoints.Num(); Itr++)
{
if (Source == OtherPoints[Itr]) continue;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Dist
CurDist = FVector::Dist(Source, OtherPoints[Itr]);
//Min
if (ClosestDistance < 0 || ClosestDistance >= CurDist)
{
ClosestVibe = Itr;
ClosestDistance = CurDist;
}
}
//Out
ClosestPoint = OtherPoints[ClosestVibe];
return ClosestDistance;
}
bool UVictoryBPFunctionLibrary::Data__GetCharacterBoneLocations(AActor * TheCharacter, TArray<FVector>& BoneLocations)
{
ACharacter * Source = Cast<ACharacter>(TheCharacter);
if (!Source) return false;
if (!Source->GetMesh()) return false;
//~~~~~~~~~~~~~~~~~~~~~~~~~
TArray<FName> BoneNames;
BoneLocations.Empty();
//Get Bone Names
Source->GetMesh()->GetBoneNames(BoneNames);
//Get Bone Locations
for (int32 Itr = 0; Itr < BoneNames.Num(); Itr++ )
{
BoneLocations.Add(Source->GetMesh()->GetBoneLocation(BoneNames[Itr]));
}
return true;
}
USkeletalMeshComponent* UVictoryBPFunctionLibrary::Accessor__GetCharacterSkeletalMesh(AActor * TheCharacter, bool& IsValid)
{
IsValid = false;
ACharacter * AsCharacter = Cast<ACharacter>(TheCharacter);
if (!AsCharacter) return NULL;
//~~~~~~~~~~~~~~~~~
//Is Valid?
if (AsCharacter->GetMesh())
if (AsCharacter->GetMesh()->IsValidLowLevel() )
IsValid = true;
return AsCharacter->GetMesh();
}
bool UVictoryBPFunctionLibrary::TraceData__GetTraceDataFromCharacterSocket(
FVector & TraceStart, //out
FVector & TraceEnd, //out
AActor * TheCharacter,
const FRotator& TraceRotation,
float TraceLength,
FName Socket,
bool DrawTraceData,
FLinearColor TraceDataColor,
float TraceDataThickness
) {
ACharacter * AsCharacter = Cast<ACharacter>(TheCharacter);
if (!AsCharacter) return false;
//Mesh Exists?
if (!AsCharacter->GetMesh()) return false;
//Socket Exists?
if (!AsCharacter->GetMesh()->DoesSocketExist(Socket)) return false;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TraceStart = AsCharacter->GetMesh()->GetSocketLocation(Socket);
TraceEnd = TraceStart + TraceRotation.Vector() * TraceLength;
if (DrawTraceData)
{
//Get World
UWorld* TheWorld = AsCharacter->GetWorld();
if (!TheWorld) return false;
//~~~~~~~~~~~~~~~~~
DrawDebugLine(
TheWorld,
TraceStart,
TraceEnd,
TraceDataColor.ToFColor(true),
false,
0.0333,
0,
TraceDataThickness
);
}
return true;
}
bool UVictoryBPFunctionLibrary::TraceData__GetTraceDataFromSkeletalMeshSocket(
FVector & TraceStart, //out
FVector & TraceEnd, //out
USkeletalMeshComponent * Mesh,
const FRotator & TraceRotation,
float TraceLength,
FName Socket,
bool DrawTraceData,
FLinearColor TraceDataColor,
float TraceDataThickness
) {
//Mesh Exists?
if (!Mesh) return false;
//Socket Exists?
if (!Mesh->DoesSocketExist(Socket)) return false;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TraceStart = Mesh->GetSocketLocation(Socket);
TraceEnd = TraceStart + TraceRotation.Vector() * TraceLength;
if (DrawTraceData)
{
//Get a PC to GetWorld() from
TObjectIterator<APlayerController> Itr;
if (!Itr) return false;
//~~~~~~~~~~~~
//Get World
UWorld* TheWorld = Itr->GetWorld();
if (!TheWorld) return false;
//~~~~~~~~~~~~~~~~~
DrawDebugLine(
TheWorld,
TraceStart,
TraceEnd,
TraceDataColor.ToFColor(true),
false,
0.0333,
0,
TraceDataThickness
);
}
return true;
}
AActor* UVictoryBPFunctionLibrary::Traces__CharacterMeshTrace___ClosestBone(
AActor* TraceOwner,
const FVector & TraceStart,
const FVector & TraceEnd,
FVector & OutImpactPoint,
FVector & OutImpactNormal,
FName & ClosestBoneName,
FVector & ClosestBoneLocation,
bool& IsValid
)
{
IsValid = false;
AActor * HitActor = NULL;
//~~~~~~~~~~~~~~~~~~~~~~
//Get a PC to GetWorld() from
TObjectIterator<APlayerController> Itr;
if (!Itr) return NULL;
//~~~~~~~~~~~~
//Get World
UWorld* TheWorld = Itr->GetWorld();
if (TheWorld == nullptr) return NULL;
//~~~~~~~~~~~~~~~~~
//Simple Trace First
FCollisionQueryParams TraceParams(FName(TEXT("VictoryBPTrace::CharacterMeshTrace")), true, HitActor);
TraceParams.bTraceComplex = true;
TraceParams.bTraceAsyncScene = true;
TraceParams.bReturnPhysicalMaterial = false;
TraceParams.AddIgnoredActor(TraceOwner);
//initialize hit info
FHitResult RV_Hit(ForceInit);
TheWorld->LineTraceSingleByChannel(
RV_Hit, //result
TraceStart,
TraceEnd,
ECC_Pawn, //collision channel
TraceParams
);
//Hit Something!
if (!RV_Hit.bBlockingHit) return HitActor;
//Character?
HitActor = RV_Hit.GetActor();
ACharacter * AsCharacter = Cast<ACharacter>(HitActor);
if (!AsCharacter) return HitActor;
//Mesh
if (!AsCharacter->GetMesh()) return HitActor;
//Component Trace
FHitResult Hit;
IsValid = AsCharacter->GetMesh()->K2_LineTraceComponent(
TraceStart,
TraceEnd,
true,
false,
OutImpactPoint,
OutImpactNormal,
ClosestBoneName,
Hit
);
//Location
ClosestBoneLocation = AsCharacter->GetMesh()->GetBoneLocation(ClosestBoneName);
return HitActor;
}
AActor* UVictoryBPFunctionLibrary::Traces__CharacterMeshTrace___ClosestSocket(
UObject* WorldContextObject,
const AActor * TraceOwner,
const FVector & TraceStart,
const FVector & TraceEnd,
FVector & OutImpactPoint,
FVector & OutImpactNormal,
FName & ClosestSocketName,
FVector & SocketLocation,
bool & IsValid
)
{
IsValid = false;
AActor * HitActor = NULL;
//~~~~~~~~~~~~~~~~~~~~~~
if(!WorldContextObject) return nullptr;
UWorld* const TheWorld = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if(!TheWorld) return nullptr;
//~~~~~~~~~~~
//Simple Trace First
FCollisionQueryParams TraceParams(FName(TEXT("VictoryBPTrace::CharacterMeshSocketTrace")), true, HitActor);
TraceParams.bTraceComplex = true;
TraceParams.bTraceAsyncScene = true;
TraceParams.bReturnPhysicalMaterial = false;
TraceParams.AddIgnoredActor(TraceOwner);
//initialize hit info
FHitResult RV_Hit(ForceInit);
TheWorld->LineTraceSingleByChannel(
RV_Hit, //result
TraceStart,
TraceEnd,
ECC_Pawn, //collision channel
TraceParams
);
//Hit Something!
if (!RV_Hit.bBlockingHit) return HitActor;
//Character?
HitActor = RV_Hit.GetActor();
ACharacter * AsCharacter = Cast<ACharacter>(HitActor);
if (!AsCharacter) return HitActor;
//Mesh
if (!AsCharacter->GetMesh()) return HitActor;
//Component Trace
FHitResult Hit;
FName BoneName;
if (! AsCharacter->GetMesh()->K2_LineTraceComponent(
TraceStart,
TraceEnd,
true,
false,
OutImpactPoint,
OutImpactNormal,
BoneName,
Hit
)) return HitActor;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Socket Names
TArray<FComponentSocketDescription> SocketNames;
//Get Bone Names
AsCharacter->GetMesh()->QuerySupportedSockets(SocketNames);
// Min
FVector CurLoc;
float CurDist = 0;
float ClosestDistance = -1;
int32 ClosestVibe = 0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Check All Bones Locations
for (int32 Itr = 0; Itr < SocketNames.Num(); Itr++ )
{
//Is this a Bone not a socket?
if(SocketNames[Itr].Type == EComponentSocketType::Bone) continue;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CurLoc = AsCharacter->GetMesh()->GetSocketLocation(SocketNames[Itr].Name);
//Dist
CurDist = FVector::Dist(OutImpactPoint, CurLoc);
//Min
if (ClosestDistance < 0 || ClosestDistance >= CurDist)
{
ClosestVibe = Itr;
ClosestDistance = CurDist;
}
}
//Name
ClosestSocketName = SocketNames[ClosestVibe].Name;
//Location
SocketLocation = AsCharacter->GetMesh()->GetSocketLocation(ClosestSocketName);
//Valid
IsValid = true;
//Actor
return HitActor;
}
void UVictoryBPFunctionLibrary::VictorySimulateMouseWheel(const float& Delta)
{
FSlateApplication::Get().OnMouseWheel(int32(Delta));
}
void UVictoryBPFunctionLibrary::VictorySimulateKeyPress(APlayerController* ThePC, FKey Key, EInputEvent EventType)
{
if (!ThePC) return;
ThePC->InputKey(Key, EventType, 1, false); //amount depressed, bGamepad
//! This will fire twice if the event is not handled, for umg widgets place an invisible button in background.
if (Key == EKeys::LeftMouseButton || Key == EKeys::MiddleMouseButton || Key == EKeys::RightMouseButton || Key == EKeys::ThumbMouseButton || Key == EKeys::ThumbMouseButton2)
{
EMouseButtons::Type Button = EMouseButtons::Invalid;
if (Key == EKeys::LeftMouseButton)
{
Button = EMouseButtons::Left;
}
else if (Key == EKeys::MiddleMouseButton)
{
Button = EMouseButtons::Middle;
}
else if (Key == EKeys::RightMouseButton)
{
Button = EMouseButtons::Right;
}
else if (Key == EKeys::ThumbMouseButton)
{
Button = EMouseButtons::Thumb01;
}
else if (Key == EKeys::ThumbMouseButton2)
{
Button = EMouseButtons::Thumb02;
}
if (EventType == IE_Pressed)
{
FSlateApplication::Get().OnMouseDown(nullptr, Button);
}
else if (EventType == IE_Released)
{
FSlateApplication::Get().OnMouseUp(Button);
}
else if (EventType == IE_DoubleClick)
{
FSlateApplication::Get().OnMouseDoubleClick(nullptr, Button);
}
}
else
{
const uint32 *KeyCode = 0;
const uint32 *CharacterCode = 0;
FInputKeyManager::Get().GetCodesFromKey(Key, KeyCode, CharacterCode);
uint32 KeyCodeVal = (KeyCode != NULL) ? *KeyCode : -1;
uint32 CharacterCodeVal = (CharacterCode != NULL) ? *CharacterCode : -1;
if (EventType == IE_Pressed)
{
FSlateApplication::Get().OnKeyDown(KeyCodeVal, CharacterCodeVal, false);
}
else if (EventType == IE_Released)
{
FSlateApplication::Get().OnKeyUp(KeyCodeVal, CharacterCodeVal, false);
}
}
}
bool UVictoryBPFunctionLibrary::Viewport__EnableWorldRendering(const APlayerController* ThePC, bool RenderTheWorld)
{
if (!ThePC) return false;
//~~~~~~~~~~~~~
//Get Player
ULocalPlayer * VictoryPlayer = Cast<ULocalPlayer>(ThePC->Player);
//PlayerController::Player is UPlayer
if (!VictoryPlayer) return false;
//~~~~~~~~~~~~~~~~~~~~
//get view port ptr
UGameViewportClient * VictoryViewportClient =
Cast < UGameViewportClient > (VictoryPlayer->ViewportClient);
if (!VictoryViewportClient) return false;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
VictoryViewportClient->bDisableWorldRendering = !RenderTheWorld;
return true;
}
//Most HUD stuff is in floats so I do the conversion internally
bool UVictoryBPFunctionLibrary::Viewport__SetMousePosition(const APlayerController* ThePC, const float& PosX, const float& PosY)
{
if (!ThePC) return false;
//~~~~~~~~~~~~~
//Get Player
const ULocalPlayer * VictoryPlayer = Cast<ULocalPlayer>(ThePC->Player);
//PlayerController::Player is UPlayer
if (!VictoryPlayer) return false;
//~~~~~~~~~~~~~~~~~~~~
//get view port ptr
const UGameViewportClient * VictoryViewportClient =
Cast < UGameViewportClient > (VictoryPlayer->ViewportClient);
if (!VictoryViewportClient) return false;
//~~~~~~~~~~~~~~~~~~~~
FViewport * VictoryViewport = VictoryViewportClient->Viewport;
if (!VictoryViewport) return false;
//~~~~~~~~~~~~~~~~~~~~
//Set Mouse
VictoryViewport->SetMouse(int32(PosX), int32(PosY));
return true;
}
APlayerController * UVictoryBPFunctionLibrary::Accessor__GetPlayerController(
AActor * TheCharacter,
bool & IsValid
)
{
IsValid = false;
//Cast to Character
ACharacter * AsCharacter = Cast<ACharacter>(TheCharacter);
if (!AsCharacter) return NULL;
//cast to PC
APlayerController * ThePC = Cast < APlayerController > (AsCharacter->GetController());
if (!ThePC ) return NULL;
IsValid = true;
return ThePC;
}
bool UVictoryBPFunctionLibrary::Viewport__GetCenterOfViewport(const APlayerController * ThePC, float & PosX, float & PosY)
{
if (!ThePC) return false;
//~~~~~~~~~~~~~
//Get Player
const ULocalPlayer * VictoryPlayer = Cast<ULocalPlayer>(ThePC->Player);
//PlayerController::Player is UPlayer
if (!VictoryPlayer) return false;
//~~~~~~~~~~~~~~~~~~~~
//get view port ptr
const UGameViewportClient * VictoryViewportClient =
Cast < UGameViewportClient > (VictoryPlayer->ViewportClient);
if (!VictoryViewportClient) return false;
//~~~~~~~~~~~~~~~~~~~~
FViewport * VictoryViewport = VictoryViewportClient->Viewport;
if (!VictoryViewport) return false;
//~~~~~~~~~~~~~~~~~~~~
//Get Size
FIntPoint Size = VictoryViewport->GetSizeXY();
//Center
PosX = Size.X / 2;
PosY = Size.Y / 2;
return true;
}
bool UVictoryBPFunctionLibrary::Viewport__GetMousePosition(const APlayerController * ThePC, float & PosX, float & PosY)
{
if (!ThePC) return false;
//~~~~~~~~~~~~~
//Get Player
const ULocalPlayer * VictoryPlayer = Cast<ULocalPlayer>(ThePC->Player);
//PlayerController::Player is UPlayer
if (!VictoryPlayer) return false;
//~~~~~~~~~~~~~~~~~~~~
//get view port ptr
const UGameViewportClient * VictoryViewportClient =
Cast < UGameViewportClient > (VictoryPlayer->ViewportClient);
if (!VictoryViewportClient) return false;
//~~~~~~~~~~~~~~~~~~~~
FViewport * VictoryViewport = VictoryViewportClient->Viewport;
if (!VictoryViewport) return false;
//~~~~~~~~~~~~~~~~~~~~
PosX = float(VictoryViewport->GetMouseX());
PosY = float(VictoryViewport->GetMouseY());
return true;
}
bool UVictoryBPFunctionLibrary::Physics__EnterRagDoll(AActor * TheCharacter)
{
ACharacter * AsCharacter = Cast<ACharacter>(TheCharacter);
if (!AsCharacter) return false;
//Mesh?
if (!AsCharacter->GetMesh()) return false;
//Physics Asset?
if(!AsCharacter->GetMesh()->GetPhysicsAsset()) return false;
//Victory Ragdoll
AsCharacter->GetMesh()->SetSimulatePhysics(true);
return true;
}
bool UVictoryBPFunctionLibrary::Physics__LeaveRagDoll(
AActor* TheCharacter,
bool SetToFallingMovementMode,
float HeightAboveRBMesh,
const FVector& InitLocation,
const FRotator& InitRotation
){
ACharacter * AsCharacter = Cast<ACharacter>(TheCharacter);
if (!AsCharacter) return false;
//Mesh?
if (!AsCharacter->GetMesh()) return false;
//Set Actor Location to Be Near Ragdolled Mesh
//Calc Ref Bone Relative Pos for use with IsRagdoll
TArray<FName> BoneNames;
AsCharacter->GetMesh()->GetBoneNames(BoneNames);
if(BoneNames.Num() > 0)
{
AsCharacter->SetActorLocation(FVector(0,0,HeightAboveRBMesh) + AsCharacter->GetMesh()->GetBoneLocation(BoneNames[0]));
}
//Exit Ragdoll
AsCharacter->GetMesh()->SetSimulatePhysics(false);
AsCharacter->GetMesh()->AttachToComponent(AsCharacter->GetCapsuleComponent(), FAttachmentTransformRules::KeepRelativeTransform);
//Restore Defaults
AsCharacter->GetMesh()->SetRelativeRotation(InitRotation);
AsCharacter->GetMesh()->SetRelativeLocation(InitLocation);
//Set Falling After Final Capsule Relocation
if(SetToFallingMovementMode)
{
if(AsCharacter->GetCharacterMovement()) AsCharacter->GetCharacterMovement()->SetMovementMode(MOVE_Falling);
}
return true;
}
bool UVictoryBPFunctionLibrary::Physics__IsRagDoll(AActor* TheCharacter)
{
ACharacter * AsCharacter = Cast<ACharacter>(TheCharacter);
if (!AsCharacter) return false;
//Mesh?
if (!AsCharacter->GetMesh()) return false;
return AsCharacter->GetMesh()->IsAnySimulatingPhysics();
}
bool UVictoryBPFunctionLibrary::Physics__GetLocationofRagDoll(AActor* TheCharacter, FVector& RagdollLocation)
{
ACharacter * AsCharacter = Cast<ACharacter>(TheCharacter);
if (!AsCharacter) return false;
//Mesh?
if (!AsCharacter->GetMesh()) return false;
TArray<FName> BoneNames;
AsCharacter->GetMesh()->GetBoneNames(BoneNames);
if(BoneNames.Num() > 0)
{
RagdollLocation = AsCharacter->GetMesh()->GetBoneLocation(BoneNames[0]);
}
else return false;
return true;
}
bool UVictoryBPFunctionLibrary::Physics__InitializeVictoryRagDoll(
AActor* TheCharacter,
FVector& InitLocation,
FRotator& InitRotation
){
ACharacter * AsCharacter = Cast<ACharacter>(TheCharacter);
if (!AsCharacter) return false;
//Mesh?
if (!AsCharacter->GetMesh()) return false;
InitLocation = AsCharacter->GetMesh()->GetRelativeTransform().GetLocation();
InitRotation = AsCharacter->GetMesh()->GetRelativeTransform().Rotator();
return true;
}
bool UVictoryBPFunctionLibrary::Physics__UpdateCharacterCameraToRagdollLocation(
AActor* TheCharacter,
float HeightOffset,
float InterpSpeed
){
ACharacter * AsCharacter = Cast<ACharacter>(TheCharacter);
if (!AsCharacter) return false;
//Mesh?
if (!AsCharacter->GetMesh()) return false;
//Ragdoll?
if(!AsCharacter->GetMesh()->IsAnySimulatingPhysics()) return false;
FVector RagdollLocation = FVector(0,0,0);
TArray<FName> BoneNames;
AsCharacter->GetMesh()->GetBoneNames(BoneNames);
if(BoneNames.Num() > 0)
{
RagdollLocation = AsCharacter->GetMesh()->GetBoneLocation(BoneNames[0]);
}
//Interp
RagdollLocation = FMath::VInterpTo(AsCharacter->GetActorLocation(), RagdollLocation + FVector(0,0,HeightOffset), AsCharacter->GetWorld()->DeltaTimeSeconds, InterpSpeed);
//Set Loc
AsCharacter->SetActorLocation(RagdollLocation);
return true;
}
/*
bool UVictoryBPFunctionLibrary::Accessor__GetSocketLocalTransform(const USkeletalMeshComponent* Mesh, FTransform& LocalTransform, FName SocketName)
{
if(!Mesh) return false;
LocalTransform = Mesh->GetSocketLocalTransform(SocketName);
return true;
}
*/
void UVictoryBPFunctionLibrary::StringConversion__GetFloatAsStringWithPrecision(float TheFloat, FString & FloatString, int32 Precision, bool IncludeLeadingZero)
{
FNumberFormattingOptions NumberFormat; //Text.h
NumberFormat.MinimumIntegralDigits = (IncludeLeadingZero) ? 1 : 0;
NumberFormat.MaximumIntegralDigits = 10000;
NumberFormat.MinimumFractionalDigits = Precision;
NumberFormat.MaximumFractionalDigits = Precision;
FloatString = FText::AsNumber(TheFloat, &NumberFormat).ToString();
}
bool UVictoryBPFunctionLibrary::LensFlare__GetLensFlareOffsets(
APlayerController* PlayerController,
AActor* LightSource,
float& PitchOffset,
float& YawOffset,
float& RollOffset
){
if(!PlayerController) return false;
if(!LightSource) return false;
//~~~~~~~~~~~~~~~~~~~
//angle from player to light source
const FRotator AngleToLightSource = (LightSource->GetActorLocation() - PlayerController->GetFocalLocation()).Rotation();
const FRotator Offsets = AngleToLightSource - PlayerController->GetControlRotation();
PitchOffset = Offsets.Pitch;
YawOffset = Offsets.Yaw;
RollOffset = Offsets.Roll;
return true;
}
//SMA Version
float UVictoryBPFunctionLibrary::DistanceToSurface__DistaceOfPointToMeshSurface(AStaticMeshActor* TheSMA, const FVector& TestPoint, FVector& ClosestSurfacePoint)
{
if(!TheSMA) return -1;
if(!TheSMA->GetStaticMeshComponent()) return -1;
//~~~~~~~~~~
//Dist of pt to Surface, retrieve closest Surface Point to Actor
return TheSMA->GetStaticMeshComponent()->GetDistanceToCollision(TestPoint, ClosestSurfacePoint);
}
bool UVictoryBPFunctionLibrary::Mobility__SetSceneCompMobility(
USceneComponent* SceneComp,
EComponentMobility::Type NewMobility
)
{
if(!SceneComp) return false;
//~~~~~~~~~~~
SceneComp->SetMobility(NewMobility);
return true;
}
//~~~~~~~~~~~~~~~~~~
// FullScreen
//~~~~~~~~~~~~~~~~~~
TEnumAsByte<EJoyGraphicsFullScreen::Type> UVictoryBPFunctionLibrary::JoyGraphicsSettings__FullScreen_Get()
{
return TEnumAsByte<EJoyGraphicsFullScreen::Type>(JoyGraphics_FullScreen_GetFullScreenType());
}
void UVictoryBPFunctionLibrary::JoyGraphicsSettings__FullScreen_Set(TEnumAsByte<EJoyGraphicsFullScreen::Type> NewSetting)
{
JoyGraphics_FullScreen_SetFullScreenType(NewSetting.GetValue());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Contributed by Others
/**
* Contributed by: SaxonRah
* Better random numbers. Seeded with a random device. if the random device's entropy is 0; defaults to current time for seed.
* can override with seed functions;
*/
//----------------------------------------------------------------------------------------------BeginRANDOM
std::random_device rd;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::mt19937 rand_MT;
std::default_random_engine rand_DRE;
/** Construct a random device and set seed for engines dependent on entropy */
void UVictoryBPFunctionLibrary::constructRand()
{
seed = std::chrono::system_clock::now().time_since_epoch().count();
if (rd.entropy() == 0)
{
seedRand(seed);
}else{
seedRand(rd());
}
}
/** Set seed for Rand */
void UVictoryBPFunctionLibrary::seedRand(int32 _seed)
{
seed = _seed;
}
/** Set seed with time for Rand */
void UVictoryBPFunctionLibrary::seedRandWithTime()
{
seed = std::chrono::system_clock::now().time_since_epoch().count();
}
/** Set seed with entropy for Rand */
void UVictoryBPFunctionLibrary::seedRandWithEntropy()
{
seedRand(rd());
}
/** Random Bool - Bernoulli distribution */
bool UVictoryBPFunctionLibrary::RandBool_Bernoulli(float fBias)
{
std::bernoulli_distribution dis(fBias);
return dis(rand_DRE);
}
/** Random Integer - Uniform distribution */
int32 UVictoryBPFunctionLibrary::RandInt_uniDis()
{
std::uniform_int_distribution<int32> dis(0, 1);
return dis(rand_DRE);
}
/** Random Integer - Uniform distribution */
int32 UVictoryBPFunctionLibrary::RandInt_MINMAX_uniDis(int32 iMin, int32 iMax)
{
std::uniform_int_distribution<int32> dis(iMin, iMax);
return dis(rand_DRE);
}
/** Random Float - Zero to One Uniform distribution */
float UVictoryBPFunctionLibrary::RandFloat_uniDis()
{
std::uniform_real_distribution<float> dis(0, 1);
return dis(rand_DRE);
}
/** Random Float - MIN to MAX Uniform distribution */
float UVictoryBPFunctionLibrary::RandFloat_MINMAX_uniDis(float iMin, float iMax)
{
std::uniform_real_distribution<float> dis(iMin, iMax);
return dis(rand_DRE);
}
/** Random Bool - Bernoulli distribution - Mersenne Twister */
bool UVictoryBPFunctionLibrary::RandBool_Bernoulli_MT(float fBias)
{
std::bernoulli_distribution dis(fBias);
return dis(rand_MT);
}
/** Random Integer - Uniform distribution - Mersenne Twister */
int32 UVictoryBPFunctionLibrary::RandInt_uniDis_MT()
{
std::uniform_int_distribution<int32> dis(0, 1);
return dis(rand_MT);
}
/** Random Integer - Uniform distribution - Mersenne Twister */
int32 UVictoryBPFunctionLibrary::RandInt_MINMAX_uniDis_MT(int32 iMin, int32 iMax)
{
std::uniform_int_distribution<int32> dis(iMin, iMax);
return dis(rand_MT);
}
/** Random Float - Zero to One Uniform distribution - Mersenne Twister */
float UVictoryBPFunctionLibrary::RandFloat_uniDis_MT()
{
std::uniform_real_distribution<float> dis(0, 1);
return dis(rand_MT);
}
/** Random Float - MIN to MAX Uniform distribution - Mersenne Twister */
float UVictoryBPFunctionLibrary::RandFloat_MINMAX_uniDis_MT(float iMin, float iMax)
{
std::uniform_real_distribution<float> dis(iMin, iMax);
return dis(rand_MT);
}
//----------------------------------------------------------------------------------------------ENDRANDOM
void UVictoryBPFunctionLibrary::String__ExplodeString(TArray<FString>& OutputStrings, FString InputString, FString Separator, int32 limit, bool bTrimElements)
{
OutputStrings.Empty();
//~~~~~~~~~~~
if (InputString.Len() > 0 && Separator.Len() > 0) {
int32 StringIndex = 0;
int32 SeparatorIndex = 0;
FString Section = "";
FString Extra = "";
int32 PartialMatchStart = -1;
while (StringIndex < InputString.Len()) {
if (InputString[StringIndex] == Separator[SeparatorIndex]) {
if (SeparatorIndex == 0) {
//A new partial match has started.
PartialMatchStart = StringIndex;
}
Extra.AppendChar(InputString[StringIndex]);
if (SeparatorIndex == (Separator.Len() - 1)) {
//We have matched the entire separator.
SeparatorIndex = 0;
PartialMatchStart = -1;
if (bTrimElements == true) {
OutputStrings.Add(FString(Section).TrimStart().TrimEnd());
}
else {
OutputStrings.Add(FString(Section));
}
//if we have reached the limit, stop.
if (limit > 0 && OutputStrings.Num() >= limit)
{
return;
//~~~~
}
Extra.Empty();
Section.Empty();
}
else {
++SeparatorIndex;
}
}
else {
//Not matched.
//We should revert back to PartialMatchStart+1 (if there was a partial match) and clear away extra.
if (PartialMatchStart >= 0) {
StringIndex = PartialMatchStart;
PartialMatchStart = -1;
Extra.Empty();
SeparatorIndex = 0;
}
Section.AppendChar(InputString[StringIndex]);
}
++StringIndex;
}
//If there is anything left in Section or Extra. They should be added as a new entry.
if (bTrimElements == true) {
OutputStrings.Add(FString(Section + Extra).TrimStart().TrimEnd());
}
else {
OutputStrings.Add(FString(Section + Extra));
}
Section.Empty();
Extra.Empty();
}
}
UTexture2D* UVictoryBPFunctionLibrary::LoadTexture2D_FromDDSFile(const FString& FullFilePath)
{
UTexture2D* Texture = NULL;
FString TexturePath = FullFilePath;//FPaths::GameContentDir( ) + TEXT( "../Data/" ) + TextureFilename;
TArray<uint8> FileData;
/* Load DDS texture */
if( FFileHelper::LoadFileToArray( FileData, *TexturePath, 0 ) )
{
FDDSLoadHelper DDSLoadHelper( &FileData[ 0 ], FileData.Num( ) );
if( DDSLoadHelper.IsValid2DTexture( ) )
{
int32 NumMips = DDSLoadHelper.ComputeMipMapCount( );
EPixelFormat Format = DDSLoadHelper.ComputePixelFormat( );
int32 BlockSize = 16;
if( NumMips == 0 )
{
NumMips = 1;
}
if( Format == PF_DXT1 )
{
BlockSize = 8;
}
/* Create transient texture */
Texture = UTexture2D::CreateTransient( DDSLoadHelper.DDSHeader->dwWidth, DDSLoadHelper.DDSHeader->dwHeight, Format );
if(!Texture) return NULL;
Texture->PlatformData->NumSlices = 1;
Texture->NeverStream = true;
/* Get pointer to actual data */
uint8* DataPtr = (uint8*) DDSLoadHelper.GetDDSDataPointer( );
uint32 CurrentWidth = DDSLoadHelper.DDSHeader->dwWidth;
uint32 CurrentHeight = DDSLoadHelper.DDSHeader->dwHeight;
/* Iterate through mips */
for( int32 i = 0; i < NumMips; i++ )
{
/* Lock to 1x1 as smallest size */
CurrentWidth = ( CurrentWidth < 1 ) ? 1 : CurrentWidth;
CurrentHeight = ( CurrentHeight < 1 ) ? 1 : CurrentHeight;
/* Get number of bytes to read */
int32 NumBytes = CurrentWidth * CurrentHeight * 4;
if( Format == PF_DXT1 || Format == PF_DXT3 || Format == PF_DXT5 )
{
/* Compressed formats */
NumBytes = ( ( CurrentWidth + 3 ) / 4 ) * ( ( CurrentHeight + 3 ) / 4 ) * BlockSize;
}
/* Write to existing mip */
if( i < Texture->PlatformData->Mips.Num( ) )
{
FTexture2DMipMap& Mip = Texture->PlatformData->Mips[ i ];
void* Data = Mip.BulkData.Lock( LOCK_READ_WRITE );
FMemory::Memcpy( Data, DataPtr, NumBytes );
Mip.BulkData.Unlock( );
}
/* Add new mip */
else
{
FTexture2DMipMap* Mip = new( Texture->PlatformData->Mips ) FTexture2DMipMap( );
Mip->SizeX = CurrentWidth;
Mip->SizeY = CurrentHeight;
Mip->BulkData.Lock( LOCK_READ_WRITE );
Mip->BulkData.Realloc( NumBytes );
Mip->BulkData.Unlock( );
void* Data = Mip->BulkData.Lock( LOCK_READ_WRITE );
FMemory::Memcpy( Data, DataPtr, NumBytes );
Mip->BulkData.Unlock( );
}
/* Set next mip level */
CurrentWidth /= 2;
CurrentHeight /= 2;
DataPtr += NumBytes;
}
Texture->UpdateResource( );
}
}
return Texture;
}
//this is how you can make cpp only internal functions!
static EImageFormat GetJoyImageFormat(EJoyImageFormats JoyFormat)
{
/*
ImageWrapper.h
namespace EImageFormat
{
Enumerates the types of image formats this class can handle
enum Type
{
//Portable Network Graphics
PNG,
//Joint Photographic Experts Group
JPEG,
//Single channel jpeg
GrayscaleJPEG,
//Windows Bitmap
BMP,
//Windows Icon resource
ICO,
//OpenEXR (HDR) image file format
EXR,
//Mac icon
ICNS
};
};
*/
switch(JoyFormat)
{
case EJoyImageFormats::JPG : return EImageFormat::JPEG;
case EJoyImageFormats::PNG : return EImageFormat::PNG;
case EJoyImageFormats::BMP : return EImageFormat::BMP;
case EJoyImageFormats::ICO : return EImageFormat::ICO;
case EJoyImageFormats::EXR : return EImageFormat::EXR;
case EJoyImageFormats::ICNS : return EImageFormat::ICNS;
}
return EImageFormat::JPEG;
}
static FString GetJoyImageExtension(EJoyImageFormats JoyFormat)
{
switch(JoyFormat)
{
case EJoyImageFormats::JPG : return ".jpg";
case EJoyImageFormats::PNG : return ".png";
case EJoyImageFormats::BMP : return ".bmp";
case EJoyImageFormats::ICO : return ".ico";
case EJoyImageFormats::EXR : return ".exr";
case EJoyImageFormats::ICNS : return ".icns";
}
return ".png";
}
UTexture2D* UVictoryBPFunctionLibrary::Victory_LoadTexture2D_FromFile(const FString& FullFilePath,EJoyImageFormats ImageFormat, bool& IsValid,int32& Width, int32& Height)
{
IsValid = false;
UTexture2D* LoadedT2D = NULL;
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(GetJoyImageFormat(ImageFormat));
//Load From File
TArray<uint8> RawFileData;
if (!FFileHelper::LoadFileToArray(RawFileData, *FullFilePath)) return NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Create T2D!
if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(RawFileData.GetData(), RawFileData.Num()))
{
const TArray<uint8>* UncompressedBGRA = NULL;
if (ImageWrapper->GetRaw(ERGBFormat::BGRA, 8, UncompressedBGRA))
{
LoadedT2D = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_B8G8R8A8);
//Valid?
if(!LoadedT2D) return NULL;
//~~~~~~~~~~~~~~
//Out!
Width = ImageWrapper->GetWidth();
Height = ImageWrapper->GetHeight();
//Copy!
void* TextureData = LoadedT2D->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(TextureData, UncompressedBGRA->GetData(), UncompressedBGRA->Num());
LoadedT2D->PlatformData->Mips[0].BulkData.Unlock();
//Update!
LoadedT2D->UpdateResource();
}
}
// Success!
IsValid = true;
return LoadedT2D;
}
UTexture2D* UVictoryBPFunctionLibrary::Victory_LoadTexture2D_FromFile_Pixels(const FString& FullFilePath,EJoyImageFormats ImageFormat,bool& IsValid, int32& Width, int32& Height, TArray<FLinearColor>& OutPixels)
{
//Clear any previous data
OutPixels.Empty();
IsValid = false;
UTexture2D* LoadedT2D = NULL;
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(GetJoyImageFormat(ImageFormat));
//Load From File
TArray<uint8> RawFileData;
if (!FFileHelper::LoadFileToArray(RawFileData, *FullFilePath)) return NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Create T2D!
if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(RawFileData.GetData(), RawFileData.Num()))
{
const TArray<uint8>* UncompressedRGBA = NULL;
if (ImageWrapper->GetRaw(ERGBFormat::RGBA, 8, UncompressedRGBA))
{
LoadedT2D = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_R8G8B8A8);
//Valid?
if(!LoadedT2D) return NULL;
//~~~~~~~~~~~~~~
//Out!
Width = ImageWrapper->GetWidth();
Height = ImageWrapper->GetHeight();
const TArray<uint8>& ByteArray = *UncompressedRGBA;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for(int32 v = 0; v < ByteArray.Num(); v+=4)
{
if(!ByteArray.IsValidIndex(v+3))
{
break;
}
OutPixels.Add(
FLinearColor(
ByteArray[v], //R
ByteArray[v+1], //G
ByteArray[v+2], //B
ByteArray[v+3] //A
)
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Copy!
void* TextureData = LoadedT2D->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(TextureData, UncompressedRGBA->GetData(), UncompressedRGBA->Num());
LoadedT2D->PlatformData->Mips[0].BulkData.Unlock();
//Update!
LoadedT2D->UpdateResource();
}
}
// Success!
IsValid = true;
return LoadedT2D;
}
bool UVictoryBPFunctionLibrary::Victory_Get_Pixel(const TArray<FLinearColor>& Pixels,int32 ImageHeight, int32 x, int32 y, FLinearColor& FoundColor)
{
int32 Index = y * ImageHeight + x;
if(!Pixels.IsValidIndex(Index))
{
return false;
}
FoundColor = Pixels[Index];
return true;
}
bool UVictoryBPFunctionLibrary::Victory_SavePixels(
const FString& FullFilePath
, int32 Width, int32 Height
, const TArray<FLinearColor>& ImagePixels
, bool SaveAsBMP
, bool sRGB
, FString& ErrorString
){
if(FullFilePath.Len() < 1)
{
ErrorString = "No file path";
return false;
}
//~~~~~~~~~~~~~~~~~
//Ensure target directory exists,
// _or can be created!_ <3 Rama
FString NewAbsoluteFolderPath = FPaths::GetPath(FullFilePath);
FPaths::NormalizeDirectoryName(NewAbsoluteFolderPath);
if(!VCreateDirectory(NewAbsoluteFolderPath))
{
ErrorString = "Folder could not be created, check read/write permissions~ " + NewAbsoluteFolderPath;
return false;
}
//Create FColor version
TArray<FColor> ColorArray;
for(const FLinearColor& Each : ImagePixels)
{
ColorArray.Add(Each.ToFColor(sRGB));
}
if(ColorArray.Num() != Width * Height)
{
ErrorString = "Error ~ height x width is not equal to the total pixel array length!";
return false;
}
//Remove any supplied file extension and/or add accurate one
FString FinalFilename = FPaths::GetBaseFilename(FullFilePath, false); //false = dont remove path
FinalFilename += (SaveAsBMP) ? ".bmp" : ".png";
//~~~
if(SaveAsBMP)
{
ErrorString = "Success! or if returning false, the saving of file to disk did not succeed for File IO reasons";
return FFileHelper::CreateBitmap(
*FinalFilename,
Width,
Height,
ColorArray.GetData(), //const struct FColor* Data,
nullptr,//struct FIntRect* SubRectangle = NULL,
&IFileManager::Get(),
nullptr, //out filename info only
true //bool bInWriteAlpha
);
}
else
{
TArray<uint8> CompressedPNG;
FImageUtils::CompressImageArray(
Width,
Height,
ColorArray,
CompressedPNG
);
ErrorString = "Success! or if returning false, the saving of file to disk did not succeed for File IO reasons";
return FFileHelper::SaveArrayToFile(CompressedPNG, *FinalFilename);
}
/*
//Crashed for JPG, worked great for PNG
//Maybe also works for BMP so could offer those two as save options?
const int32 x = Width;
const int32 y = Height;
if(ColorArray.Num() != x * y)
{
ErrorString = "Error ~ height x width is not equal to the total pixel array length!";
return false;
}
//Image Wrapper Module
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
//Create Compressor
IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper(GetJoyImageFormat(ImageFormat));
if(!ImageWrapper.IsValid())
{
ErrorString = "Error ~ Image wrapper could not be created!";
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~
if ( ! ImageWrapper->SetRaw(
(void*)&ColorArray[0], //mem address of array start
sizeof(FColor) * x * y, //total size
x, y, //dimensions
ERGBFormat::BGRA, //LinearColor == RGBA
(sizeof(FColor) / 4) * 8 //Bits per pixel
)) {
ErrorString = "ImageWrapper::SetRaw() did not succeed";
return false;
}
ErrorString = "Success! or if returning false, the saving of file to disk did not succeed for File IO reasons";
return FFileHelper::SaveArrayToFile(ImageWrapper->GetCompressed(), *FinalFilename);
*/
}
bool UVictoryBPFunctionLibrary::Victory_GetPixelFromT2D(UTexture2D* T2D, int32 X, int32 Y, FLinearColor& PixelColor)
{
if(!T2D)
{
return false;
}
if(X <= -1 || Y <= -1)
{
return false;
}
T2D->SRGB = false;
T2D->CompressionSettings = TC_VectorDisplacementmap;
//Update settings
T2D->UpdateResource();
FTexture2DMipMap& MipsMap = T2D->PlatformData->Mips[0];
int32 TextureWidth = MipsMap.SizeX;
int32 TextureHeight = MipsMap.SizeY;
FByteBulkData* RawImageData = &MipsMap.BulkData;
if(!RawImageData)
{
return false;
}
FColor* RawColorArray = static_cast<FColor*>(RawImageData->Lock(LOCK_READ_ONLY));
//Safety check!
if (X >= TextureWidth || Y >= TextureHeight)
{
return false;
}
//Get!, converting FColor to FLinearColor
PixelColor = RawColorArray[Y * TextureWidth + X];
RawImageData->Unlock();
return true;
}
bool UVictoryBPFunctionLibrary::Victory_GetPixelsArrayFromT2DDynamic(UTexture2DDynamic* T2D, int32& TextureWidth, int32& TextureHeight,TArray<FLinearColor>& PixelArray)
{
if(!T2D)
{
return false;
}
//To prevent overflow in BP if used in a loop
PixelArray.Empty();
//~~~~~~~~~~~~~~~~~~~~~~
// Modifying original here
T2D->SRGB = false;
T2D->CompressionSettings = TC_VectorDisplacementmap;
//Update settings
T2D->UpdateResource();
//~~~~~~~~~~~~~~~~~~~~~~
//Confused, DDC / platform data is invalid for dynamic, how to get its byte data?
//FTextureResource from UTexture base class?
return false;
/*
FTexturePlatformData** PtrPtr = T2D->GetRunningPlatformData();
if(!PtrPtr) return false;
FTexturePlatformData* Ptr = *PtrPtr;
if(!Ptr) return false;
FTexture2DMipMap& MyMipMap = Ptr->Mips[0];
TextureWidth = MyMipMap.SizeX;
TextureHeight = MyMipMap.SizeY;
FByteBulkData* RawImageData = &MyMipMap.BulkData;
if(!RawImageData)
{
return false;
}
FColor* RawColorArray = static_cast<FColor*>(RawImageData->Lock(LOCK_READ_ONLY));
UE_LOG(LogTemp,Warning,TEXT("Victory Plugin, Get Pixels, tex width for mip %d"), TextureWidth);
UE_LOG(LogTemp,Warning,TEXT("Victory Plugin, Get Pixels, tex width from T2D ptr %d"), T2D->GetSurfaceWidth());
for(int32 x = 0; x < TextureWidth; x++)
{
for(int32 y = 0; y < TextureHeight; y++)
{
PixelArray.Add(RawColorArray[x * TextureWidth + y]);
}
}
RawImageData->Unlock();
*/
return true;
}
bool UVictoryBPFunctionLibrary::Victory_GetPixelsArrayFromT2D(UTexture2D* T2D, int32& TextureWidth, int32& TextureHeight,TArray<FLinearColor>& PixelArray)
{
if(!T2D)
{
return false;
}
//To prevent overflow in BP if used in a loop
PixelArray.Empty();
T2D->SRGB = false;
T2D->CompressionSettings = TC_VectorDisplacementmap;
//Update settings
T2D->UpdateResource();
FTexture2DMipMap& MyMipMap = T2D->PlatformData->Mips[0];
TextureWidth = MyMipMap.SizeX;
TextureHeight = MyMipMap.SizeY;
FByteBulkData* RawImageData = &MyMipMap.BulkData;
if(!RawImageData)
{
return false;
}
FColor* RawColorArray = static_cast<FColor*>(RawImageData->Lock(LOCK_READ_ONLY));
for(int32 x = 0; x < TextureWidth; x++)
{
for(int32 y = 0; y < TextureHeight; y++)
{
PixelArray.Add(RawColorArray[x * TextureWidth + y]);
}
}
RawImageData->Unlock();
return true;
}
class UAudioComponent* UVictoryBPFunctionLibrary::PlaySoundAttachedFromFile(const FString& FilePath, class USceneComponent* AttachToComponent, FName AttachPointName, FVector Location, EAttachLocation::Type LocationType, bool bStopWhenAttachedToDestroyed, float VolumeMultiplier, float PitchMultiplier, float StartTime, class USoundAttenuation* AttenuationSettings)
{
USoundWave* sw = GetSoundWaveFromFile(FilePath);
if (!sw)
return NULL;
return UGameplayStatics::SpawnSoundAttached(sw, AttachToComponent, AttachPointName, Location, LocationType, bStopWhenAttachedToDestroyed, VolumeMultiplier, PitchMultiplier, StartTime, AttenuationSettings);
}
void UVictoryBPFunctionLibrary::PlaySoundAtLocationFromFile(UObject* WorldContextObject, const FString& FilePath, FVector Location, float VolumeMultiplier, float PitchMultiplier, float StartTime, class USoundAttenuation* AttenuationSettings)
{
USoundWave* sw = GetSoundWaveFromFile(FilePath);
if (!sw)
return;
UGameplayStatics::PlaySoundAtLocation(WorldContextObject, sw, Location, VolumeMultiplier, PitchMultiplier, StartTime, AttenuationSettings);
}
class USoundWave* UVictoryBPFunctionLibrary::GetSoundWaveFromFile(const FString& FilePath)
{
#if PLATFORM_PS4
UE_LOG(LogTemp, Error, TEXT("UVictoryBPFunctionLibrary::GetSoundWaveFromFile ~ vorbis-method not supported on PS4. See UVictoryBPFunctionLibrary::fillSoundWaveInfo"));
return nullptr;
#else
USoundWave* sw = NewObject<USoundWave>(USoundWave::StaticClass());
if (!sw)
return NULL;
//* If true the song was successfully loaded
bool loaded = false;
//* loaded song file (binary, encoded)
TArray < uint8 > rawFile;
loaded = FFileHelper::LoadFileToArray(rawFile, FilePath.GetCharArray().GetData());
if (loaded)
{
FByteBulkData* bulkData = &sw->CompressedFormatData.GetFormat(TEXT("OGG"));
bulkData->Lock(LOCK_READ_WRITE);
FMemory::Memcpy(bulkData->Realloc(rawFile.Num()), rawFile.GetData(), rawFile.Num());
bulkData->Unlock();
loaded = fillSoundWaveInfo(sw, &rawFile) == 0 ? true : false;
}
if (!loaded)
return NULL;
return sw;
#endif
}
#if !PLATFORM_PS4
int32 UVictoryBPFunctionLibrary::fillSoundWaveInfo(class USoundWave* sw, TArray<uint8>* rawFile)
{
FSoundQualityInfo info;
FVorbisAudioInfo vorbis_obj;
if (!vorbis_obj.ReadCompressedInfo(rawFile->GetData(), rawFile->Num(), &info))
{
//Debug("Can't load header");
return 1;
}
if(!sw) return 1;
sw->SoundGroup = ESoundGroup::SOUNDGROUP_Default;
sw->NumChannels = info.NumChannels;
sw->Duration = info.Duration;
sw->RawPCMDataSize = info.SampleDataSize;
sw->SampleRate = info.SampleRate;
return 0;
}
int32 UVictoryBPFunctionLibrary::findSource(class USoundWave* sw, class FSoundSource* out_audioSource)
{
FAudioDevice* device = GEngine ? GEngine->GetMainAudioDevice() : NULL; //gently ask for the audio device
FActiveSound* activeSound;
FSoundSource* audioSource;
FWaveInstance* sw_instance;
if (!device)
{
activeSound = NULL;
audioSource = NULL;
out_audioSource = audioSource;
return -1;
}
TArray<FActiveSound*> tmpActualSounds = device->GetActiveSounds();
if (tmpActualSounds.Num())
{
for (auto activeSoundIt(tmpActualSounds.CreateIterator()); activeSoundIt; ++activeSoundIt)
{
activeSound = *activeSoundIt;
for (auto WaveInstanceIt(activeSound->WaveInstances.CreateIterator()); WaveInstanceIt; ++WaveInstanceIt)
{
sw_instance = WaveInstanceIt.Value();
if (sw_instance->WaveData->CompressedDataGuid == sw->CompressedDataGuid)
{
audioSource = device->GetSoundSource(sw_instance); //4.13 onwards, <3 Rama
out_audioSource = audioSource;
return 0;
}
}
}
}
audioSource = NULL;
activeSound = NULL;
out_audioSource = audioSource;
return -2;
}
#endif //PLATFORM_PS4
//~~~ Kris ~~~
bool UVictoryBPFunctionLibrary::Array_IsValidIndex(const TArray<int32>& TargetArray, int32 Index)
{
// We should never hit these! They're stubs to avoid NoExport on the class. Call the Generic* equivalent instead
check(0);
return false;
}
bool UVictoryBPFunctionLibrary::GenericArray_IsValidIndex(void* TargetArray, const UArrayProperty* ArrayProp, int32 Index)
{
bool bResult = false;
if (TargetArray)
{
FScriptArrayHelper ArrayHelper(ArrayProp, TargetArray);
bResult = ArrayHelper.IsValidIndex(Index);
}
return bResult;
}
float UVictoryBPFunctionLibrary::GetCreationTime(const AActor* Target)
{
return (Target) ? Target->CreationTime : 0.0f;
}
float UVictoryBPFunctionLibrary::GetTimeAlive(const AActor* Target)
{
return (Target) ? (Target->GetWorld()->GetTimeSeconds() - Target->CreationTime) : 0.0f;
}
bool UVictoryBPFunctionLibrary::CaptureComponent2D_Project(class USceneCaptureComponent2D* Target, FVector Location, FVector2D& OutPixelLocation)
{
if ((Target == nullptr) || (Target->TextureTarget == nullptr))
{
return false;
}
const FTransform& Transform = Target->GetComponentToWorld();
FMatrix ViewMatrix = Transform.ToInverseMatrixWithScale();
FVector ViewLocation = Transform.GetTranslation();
// swap axis st. x=z,y=x,z=y (unreal coord space) so that z is up
ViewMatrix = ViewMatrix * FMatrix(
FPlane(0, 0, 1, 0),
FPlane(1, 0, 0, 0),
FPlane(0, 1, 0, 0),
FPlane(0, 0, 0, 1));
const float FOV = Target->FOVAngle * (float)PI / 360.0f;
FIntPoint CaptureSize(Target->TextureTarget->GetSurfaceWidth(), Target->TextureTarget->GetSurfaceHeight());
float XAxisMultiplier;
float YAxisMultiplier;
if (CaptureSize.X > CaptureSize.Y)
{
// if the viewport is wider than it is tall
XAxisMultiplier = 1.0f;
YAxisMultiplier = CaptureSize.X / (float)CaptureSize.Y;
}
else
{
// if the viewport is taller than it is wide
XAxisMultiplier = CaptureSize.Y / (float)CaptureSize.X;
YAxisMultiplier = 1.0f;
}
FMatrix ProjectionMatrix = FReversedZPerspectiveMatrix (
FOV,
FOV,
XAxisMultiplier,
YAxisMultiplier,
GNearClippingPlane,
GNearClippingPlane
);
FMatrix ViewProjectionMatrix = ViewMatrix * ProjectionMatrix;
FVector4 ScreenPoint = ViewProjectionMatrix.TransformFVector4(FVector4(Location,1));
if (ScreenPoint.W > 0.0f)
{
float InvW = 1.0f / ScreenPoint.W;
float Y = (GProjectionSignY > 0.0f) ? ScreenPoint.Y : 1.0f - ScreenPoint.Y;
FIntRect ViewRect = FIntRect(0, 0, CaptureSize.X, CaptureSize.Y);
OutPixelLocation = FVector2D(
ViewRect.Min.X + (0.5f + ScreenPoint.X * 0.5f * InvW) * ViewRect.Width(),
ViewRect.Min.Y + (0.5f - Y * 0.5f * InvW) * ViewRect.Height()
);
return true;
}
return false;
}
bool UVictoryBPFunctionLibrary::Capture2D_Project(class ASceneCapture2D* Target, FVector Location, FVector2D& OutPixelLocation)
{
return (Target) ? CaptureComponent2D_Project(Target->GetCaptureComponent2D(), Location, OutPixelLocation) : false;
}
static TSharedPtr<IImageWrapper> GetImageWrapperByExtention(const FString InImagePath)
{
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
if (InImagePath.EndsWith(".png"))
{
return ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
}
else if (InImagePath.EndsWith(".jpg") || InImagePath.EndsWith(".jpeg"))
{
return ImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG);
}
else if (InImagePath.EndsWith(".bmp"))
{
return ImageWrapperModule.CreateImageWrapper(EImageFormat::BMP);
}
else if (InImagePath.EndsWith(".ico"))
{
return ImageWrapperModule.CreateImageWrapper(EImageFormat::ICO);
}
else if (InImagePath.EndsWith(".exr"))
{
return ImageWrapperModule.CreateImageWrapper(EImageFormat::EXR);
}
else if (InImagePath.EndsWith(".icns"))
{
return ImageWrapperModule.CreateImageWrapper(EImageFormat::ICNS);
}
return nullptr;
}
bool UVictoryBPFunctionLibrary::CaptureComponent2D_SaveImage(class USceneCaptureComponent2D* Target, const FString ImagePath, const FLinearColor ClearColour)
{
// Bad scene capture component! No render target! Stay! Stay! Ok, feed!... wait, where was I?
if ((Target == nullptr) || (Target->TextureTarget == nullptr))
{
return false;
}
FRenderTarget* RenderTarget = Target->TextureTarget->GameThread_GetRenderTargetResource();
if (RenderTarget == nullptr)
{
return false;
}
TArray<FColor> RawPixels;
// Format not supported - use PF_B8G8R8A8.
if (Target->TextureTarget->GetFormat() != PF_B8G8R8A8)
{
// TRACEWARN("Format not supported - use PF_B8G8R8A8.");
return false;
}
if (!RenderTarget->ReadPixels(RawPixels))
{
return false;
}
// Convert to FColor.
FColor ClearFColour = ClearColour.ToFColor(false); // FIXME - want sRGB or not?
for (auto& Pixel : RawPixels)
{
// Switch Red/Blue changes.
const uint8 PR = Pixel.R;
const uint8 PB = Pixel.B;
Pixel.R = PB;
Pixel.B = PR;
// Set alpha based on RGB values of ClearColour.
Pixel.A = ((Pixel.R == ClearFColour.R) && (Pixel.G == ClearFColour.G) && (Pixel.B == ClearFColour.B)) ? 0 : 255;
}
TSharedPtr<IImageWrapper> ImageWrapper = GetImageWrapperByExtention(ImagePath);
const int32 Width = Target->TextureTarget->SizeX;
const int32 Height = Target->TextureTarget->SizeY;
if (ImageWrapper.IsValid() && ImageWrapper->SetRaw(&RawPixels[0], RawPixels.Num() * sizeof(FColor), Width, Height, ERGBFormat::RGBA, 8))
{
FFileHelper::SaveArrayToFile(ImageWrapper->GetCompressed(), *ImagePath);
return true;
}
return false;
}
bool UVictoryBPFunctionLibrary::Capture2D_SaveImage(class ASceneCapture2D* Target, const FString ImagePath, const FLinearColor ClearColour)
{
return (Target) ? CaptureComponent2D_SaveImage(Target->GetCaptureComponent2D(), ImagePath, ClearColour) : false;
}
UTexture2D* UVictoryBPFunctionLibrary::LoadTexture2D_FromFileByExtension(const FString& ImagePath, bool& IsValid, int32& OutWidth, int32& OutHeight)
{
UTexture2D* Texture = nullptr;
IsValid = false;
// To avoid log spam, make sure it exists before doing anything else.
if (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*ImagePath))
{
return nullptr;
}
TArray<uint8> CompressedData;
if (!FFileHelper::LoadFileToArray(CompressedData, *ImagePath))
{
return nullptr;
}
TSharedPtr<IImageWrapper> ImageWrapper = GetImageWrapperByExtention(ImagePath);
if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(CompressedData.GetData(), CompressedData.Num()))
{
const TArray<uint8>* UncompressedRGBA = nullptr;
if (ImageWrapper->GetRaw(ERGBFormat::RGBA, 8, UncompressedRGBA))
{
Texture = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_R8G8B8A8);
if (Texture != nullptr)
{
IsValid = true;
OutWidth = ImageWrapper->GetWidth();
OutHeight = ImageWrapper->GetHeight();
void* TextureData = Texture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(TextureData, UncompressedRGBA->GetData(), UncompressedRGBA->Num());
Texture->PlatformData->Mips[0].BulkData.Unlock();
Texture->UpdateResource();
}
}
}
return Texture;
}
UUserWidget* UVictoryBPFunctionLibrary::GetFirstWidgetOfClass(UObject* WorldContextObject, TSubclassOf<UUserWidget> WidgetClass, bool TopLevelOnly)
{
if (!WidgetClass || !WorldContextObject)
{
return nullptr;
}
const UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if (!World)
{
return nullptr;
}
UUserWidget* ResultWidget = nullptr;
for (TObjectIterator<UUserWidget> Itr; Itr; ++Itr)
{
UUserWidget* LiveWidget = *Itr;
// Skip any widget that's not in the current world context.
if (LiveWidget->GetWorld() != World)
{
continue;
}
// Skip any widget that is not a child of the class specified.
if (!LiveWidget->GetClass()->IsChildOf(WidgetClass))
{
continue;
}
if (!TopLevelOnly || LiveWidget->IsInViewport())
{
ResultWidget = LiveWidget;
break;
}
}
return ResultWidget;
}
bool UVictoryBPFunctionLibrary::WidgetIsChildOf(UWidget* ChildWidget, UWidget* PossibleParent)
{
return (ChildWidget && PossibleParent) ? ChildWidget->IsChildOf(PossibleParent) : false;
}
UUserWidget* UVictoryBPFunctionLibrary::WidgetGetParentOfClass(UWidget* ChildWidget, TSubclassOf<UUserWidget> WidgetClass)
{
UUserWidget* ResultParent = nullptr;
if (ChildWidget && WidgetClass)
{
UWidget* PossibleParent = ChildWidget->GetParent();
UWidget* NextPossibleParent = nullptr;
int32 count = 0;
while (PossibleParent != nullptr)
{
// Return once we find a parent of the desired class.
if (PossibleParent->GetClass()->IsChildOf(WidgetClass))
{
ResultParent = Cast<UUserWidget>(PossibleParent);
break;
}
NextPossibleParent = PossibleParent->GetParent();
// If we don't have a parent, follow the outer chain until we find another widget, if at all.
if (NextPossibleParent == nullptr)
{
UWidgetTree* WidgetTree = Cast<UWidgetTree>(PossibleParent->GetOuter());
if (WidgetTree)
{
NextPossibleParent = Cast<UWidget>(WidgetTree->GetOuter());
}
}
PossibleParent = NextPossibleParent;
}
}
return ResultParent;
}
void UVictoryBPFunctionLibrary::WidgetGetChildrenOfClass(UWidget* ParentWidget, TArray<UUserWidget*>& ChildWidgets, TSubclassOf<UUserWidget> WidgetClass, bool bImmediateOnly)
{
ChildWidgets.Empty();
if (ParentWidget && WidgetClass)
{
// Current set of widgets to check
TInlineComponentArray<UWidget*> WidgetsToCheck;
// Set of all widgets we have checked
TInlineComponentArray<UWidget*> CheckedWidgets;
WidgetsToCheck.Push(ParentWidget);
// While still work left to do
while (WidgetsToCheck.Num() > 0)
{
// Get the next widgets off the queue
const bool bAllowShrinking = false;
UWidget* PossibleParent = WidgetsToCheck.Pop(bAllowShrinking);
// Add it to the 'checked' set, should not already be there!
if (!CheckedWidgets.Contains(PossibleParent))
{
CheckedWidgets.Add(PossibleParent);
TArray<UWidget*> Widgets;
UWidgetTree::GetChildWidgets(PossibleParent, Widgets);
for (UWidget* Widget : Widgets)
{
if (!CheckedWidgets.Contains(Widget))
{
// Add any widget that is a child of the class specified.
if (Widget->GetClass()->IsChildOf(WidgetClass))
{
ChildWidgets.Add(Cast<UUserWidget>(Widget));
}
// If we're not just looking for our immediate children,
// add this widget to list of widgets to check next.
if (!bImmediateOnly)
{
WidgetsToCheck.Push(Widget);
}
}
}
if (bImmediateOnly)
{
break;
}
}
}
}
}
UWidget* UVictoryBPFunctionLibrary::GetWidgetFromName(UUserWidget* ParentUserWidget, const FName& Name)
{
UWidget* ResultWidget = nullptr;
if (ParentUserWidget && (Name != NAME_None))
{
ResultWidget = ParentUserWidget->GetWidgetFromName(Name);
}
return ResultWidget;
}
uint8 UVictoryBPFunctionLibrary::GetGenericTeamId(AActor* Target)
{
IGenericTeamAgentInterface* TeamAgentInterface = nullptr;
if (Target)
{
TeamAgentInterface = Cast<IGenericTeamAgentInterface>(Target);
}
return (TeamAgentInterface != nullptr) ? TeamAgentInterface->GetGenericTeamId() : FGenericTeamId::NoTeam;
}
void UVictoryBPFunctionLibrary::SetGenericTeamId(AActor* Target, uint8 NewTeamId)
{
if (Target)
{
IGenericTeamAgentInterface* TeamAgentInterface = Cast<IGenericTeamAgentInterface>(Target);
if (TeamAgentInterface != nullptr)
{
TeamAgentInterface->SetGenericTeamId(NewTeamId);
}
}
}
FLevelStreamInstanceInfo::FLevelStreamInstanceInfo(ULevelStreamingKismet* LevelInstance)
{
PackageName = LevelInstance->GetWorldAssetPackageFName();
PackageNameToLoad = LevelInstance->PackageNameToLoad;
Location = LevelInstance->LevelTransform.GetLocation();
Rotation = LevelInstance->LevelTransform.GetRotation().Rotator();
bShouldBeLoaded = LevelInstance->bShouldBeLoaded;
bShouldBeVisible = LevelInstance->bShouldBeVisible;
bShouldBlockOnLoad = LevelInstance->bShouldBlockOnLoad;
LODIndex = LevelInstance->LevelLODIndex;
};
FLevelStreamInstanceInfo UVictoryBPFunctionLibrary::GetLevelInstanceInfo(ULevelStreamingKismet* LevelInstance)
{
return FLevelStreamInstanceInfo(LevelInstance);
}
void UVictoryBPFunctionLibrary::AddToStreamingLevels(UObject* WorldContextObject, const FLevelStreamInstanceInfo& LevelInstanceInfo)
{
bool bResult = true;
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
if (World != nullptr)
{
bool bAlreadyExists = false;
for (auto StreamingLevel : World->StreamingLevels)
{
if (StreamingLevel->GetWorldAssetPackageFName() == LevelInstanceInfo.PackageName)
{
bAlreadyExists = true;
// KRIS : Would normally log a warning here! Is there a LogVictory?
break;
}
}
if (!bAlreadyExists)
{
FName PackageName = LevelInstanceInfo.PackageName;
// For PIE Networking: remap the packagename to our local PIE packagename
FString PackageNameStr = PackageName.ToString();
if (GEngine->NetworkRemapPath(World->GetNetDriver(), PackageNameStr, true))
{
PackageName = FName(*PackageNameStr);
}
GEngine->DelayGarbageCollection();
// Setup streaming level object that will load specified map
ULevelStreamingKismet* StreamingLevel = NewObject<ULevelStreamingKismet>(World, ULevelStreamingKismet::StaticClass(), NAME_None, RF_Transient, nullptr);
StreamingLevel->SetWorldAssetByPackageName(PackageName);
StreamingLevel->LevelColor = FColor::MakeRandomColor();
StreamingLevel->bShouldBeLoaded = LevelInstanceInfo.bShouldBeLoaded;
StreamingLevel->bShouldBeVisible = LevelInstanceInfo.bShouldBeVisible;
StreamingLevel->bShouldBlockOnLoad = LevelInstanceInfo.bShouldBlockOnLoad;
StreamingLevel->bInitiallyLoaded = true;
StreamingLevel->bInitiallyVisible = true;
// Transform
StreamingLevel->LevelTransform = FTransform(LevelInstanceInfo.Rotation, LevelInstanceInfo.Location);
// Map to Load
StreamingLevel->PackageNameToLoad = LevelInstanceInfo.PackageNameToLoad;
// Add the new level to world.
World->StreamingLevels.Add(StreamingLevel);
World->FlushLevelStreaming(EFlushLevelStreamingType::Full);
}
}
}
void UVictoryBPFunctionLibrary::RemoveFromStreamingLevels(UObject* WorldContextObject, const FLevelStreamInstanceInfo& LevelInstanceInfo)
{
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
// Check if the world exists and we have a level to unload
if (World != nullptr && !LevelInstanceInfo.PackageName.IsNone())
{
#if WITH_EDITOR
// If we are using the editor we will use this lambda to remove the play in editor string
auto GetCorrectPackageName = [&]( FName PackageName) {
FString PackageNameStr = PackageName.ToString();
if (GEngine->NetworkRemapPath(World->GetNetDriver(), PackageNameStr, true))
{
PackageName = FName(*PackageNameStr);
}
return PackageName;
};
#endif
// Get the package name that we want to check
FName PackageNameToCheck = LevelInstanceInfo.PackageName;
#if WITH_EDITOR
// Remove the play in editor string and client id to be able to use it with replication
PackageNameToCheck = GetCorrectPackageName(PackageNameToCheck);
#endif
// Find the level to unload
for (auto StreamingLevel : World->StreamingLevels)
{
FName LoadedPackageName = StreamingLevel->GetWorldAssetPackageFName();
#if WITH_EDITOR
// Remove the play in editor string and client id to be able to use it with replication
LoadedPackageName = GetCorrectPackageName(LoadedPackageName);
#endif
// If we find the level unload it and break
if(PackageNameToCheck == LoadedPackageName)
{
// This unload the level
StreamingLevel->bShouldBeLoaded = false;
StreamingLevel->bShouldBeVisible = false;
// This removes the level from the streaming level list
StreamingLevel->bIsRequestingUnloadAndRemoval = true;
// Force a refresh of the world
World->FlushLevelStreaming(EFlushLevelStreamingType::Full);
break;
}
}
}
}
bool UVictoryBPFunctionLibrary::GenericArray_SortCompare(const UProperty* LeftProperty, void* LeftValuePtr, const UProperty* RightProperty, void* RightValuePtr)
{
bool bResult = false;
if (const UNumericProperty *LeftNumericProperty = Cast<const UNumericProperty>(LeftProperty))
{
if (LeftNumericProperty->IsFloatingPoint())
{
bResult = (LeftNumericProperty->GetFloatingPointPropertyValue(LeftValuePtr) < Cast<const UNumericProperty>(RightProperty)->GetFloatingPointPropertyValue(RightValuePtr));
}
else if (LeftNumericProperty->IsInteger())
{
bResult = (LeftNumericProperty->GetSignedIntPropertyValue(LeftValuePtr) < Cast<const UNumericProperty>(RightProperty)->GetSignedIntPropertyValue(RightValuePtr));
}
}
else if (const UBoolProperty* LeftBoolProperty = Cast<const UBoolProperty>(LeftProperty))
{
bResult = (!LeftBoolProperty->GetPropertyValue(LeftValuePtr) && Cast<const UBoolProperty>(RightProperty)->GetPropertyValue(RightValuePtr));
}
else if (const UNameProperty* LeftNameProperty = Cast<const UNameProperty>(LeftProperty))
{
bResult = (LeftNameProperty->GetPropertyValue(LeftValuePtr).ToString() < Cast<const UNameProperty>(RightProperty)->GetPropertyValue(RightValuePtr).ToString());
}
else if (const UStrProperty* LeftStringProperty = Cast<const UStrProperty>(LeftProperty))
{
bResult = (LeftStringProperty->GetPropertyValue(LeftValuePtr) < Cast<const UStrProperty>(RightProperty)->GetPropertyValue(RightValuePtr));
}
else if (const UTextProperty* LeftTextProperty = Cast<const UTextProperty>(LeftProperty))
{
bResult = (LeftTextProperty->GetPropertyValue(LeftValuePtr).ToString() < Cast<const UTextProperty>(RightProperty)->GetPropertyValue(RightValuePtr).ToString());
}
return bResult;
}
void UVictoryBPFunctionLibrary::GenericArray_Sort(void* TargetArray, const UArrayProperty* ArrayProp, bool bAscendingOrder /* = true */, FName VariableName /* = NAME_None */)
{
if (TargetArray)
{
FScriptArrayHelper ArrayHelper(ArrayProp, TargetArray);
const int32 LastIndex = ArrayHelper.Num();
if (const UObjectProperty* ObjectProperty = Cast<const UObjectProperty>(ArrayProp->Inner))
{
for (int32 i = 0; i < LastIndex; ++i)
{
for (int32 j = 0; j < LastIndex - 1 - i; ++j)
{
UObject* LeftObject = ObjectProperty->GetObjectPropertyValue(ArrayHelper.GetRawPtr(j));
UObject* RightObject = ObjectProperty->GetObjectPropertyValue(ArrayHelper.GetRawPtr(j + 1));
UProperty* LeftProperty = FindField<UProperty>(LeftObject->GetClass(), VariableName);
UProperty* RightProperty = FindField<UProperty>(RightObject->GetClass(), VariableName);
if (LeftProperty && RightProperty)
{
void* LeftValuePtr = LeftProperty->ContainerPtrToValuePtr<void>(LeftObject);
void* RightValuePtr = RightProperty->ContainerPtrToValuePtr<void>(RightObject);
if (GenericArray_SortCompare(LeftProperty, LeftValuePtr, RightProperty, RightValuePtr) != bAscendingOrder)
{
ArrayHelper.SwapValues(j, j + 1);
}
}
}
}
}
else
{
UProperty* Property = nullptr;
if (const UStructProperty* StructProperty = Cast<const UStructProperty>(ArrayProp->Inner))
{
Property = FindField<UProperty>(StructProperty->Struct, VariableName);
}
else
{
Property = ArrayProp->Inner;
}
if (Property)
{
for (int32 i = 0; i < LastIndex; ++i)
{
for (int32 j = 0; j < LastIndex - 1 - i; ++j)
{
void* LeftValuePtr = Property->ContainerPtrToValuePtr<void>(ArrayHelper.GetRawPtr(j));
void* RightValuePtr = Property->ContainerPtrToValuePtr<void>(ArrayHelper.GetRawPtr(j + 1));
if (GenericArray_SortCompare(Property, LeftValuePtr, Property, RightValuePtr) != bAscendingOrder)
{
ArrayHelper.SwapValues(j, j + 1);
}
}
}
}
}
}
}
void UVictoryBPFunctionLibrary::Array_Sort(const TArray<int32>& TargetArray, bool bAscendingOrder /* = true */, FName VariableName /* = NAME_None */)
{
// We should never hit these! They're stubs to avoid NoExport on the class. Call the Generic* equivalent instead
check(0);
}
void UVictoryBPFunctionLibrary::Actor_PrestreamTextures(AActor* Target, float Seconds, bool bEnableStreaming /*= true*/, int32 CinematicTextureGroups /*= 0*/)
{
if (Target != nullptr)
{
Target->PrestreamTextures(Seconds, bEnableStreaming, CinematicTextureGroups);
}
}
void UVictoryBPFunctionLibrary::Component_PrestreamTextures(UMeshComponent* Target, float Seconds, bool bEnableStreaming /*= true*/, int32 CinematicTextureGroups /*= 0*/)
{
if ((Target != nullptr) && (Target->IsRegistered()))
{
float Duration = Seconds;
if (bEnableStreaming)
{
// A Seconds==0.0f, it means infinite (e.g. 30 days)
Duration = FMath::IsNearlyZero(Seconds) ? (60.0f*60.0f*24.0f*30.0f) : Seconds;
}
Target->PrestreamTextures(Duration, false, CinematicTextureGroups);
}
}
bool UVictoryBPFunctionLibrary::GetViewportPosition(UObject* WorldContextObject, const FVector2D& ScreenPosition, FVector2D& OutViewportPosition)
{
OutViewportPosition = FVector2D::ZeroVector;
if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull))
{
FVector2D ViewportSize;
World->GetGameViewport()->GetViewportSize(ViewportSize);
OutViewportPosition = World->GetGameViewport()->Viewport->VirtualDesktopPixelToViewport(FIntPoint(ScreenPosition.X, ScreenPosition.Y)) * ViewportSize;
}
return !OutViewportPosition.IsZero();
}
bool UVictoryBPFunctionLibrary::GetViewportPositionHitResultByChannel(UObject* WorldContextObject, const FVector2D& ViewportPosition, ECollisionChannel TraceChannel, bool bTraceComplex, FHitResult& OutHitResult)
{
bool bResult = false;
if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull))
{
bResult = World->GetFirstPlayerController()->GetHitResultAtScreenPosition(ViewportPosition, TraceChannel, bTraceComplex, OutHitResult);
}
if (!bResult) // For Blueprint users
{
OutHitResult = FHitResult();
}
return bResult;
}
bool UVictoryBPFunctionLibrary::ViewportPositionDeproject(UObject* WorldContextObject, const FVector2D& ViewportPosition, FVector& OutWorldOrigin, FVector& OutWorldDirection)
{
bool bResult = false;
if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull))
{
bResult = UGameplayStatics::DeprojectScreenToWorld(World->GetFirstPlayerController(), ViewportPosition, OutWorldOrigin, OutWorldDirection);
}
return bResult;
}
UPanelSlot* UVictoryBPFunctionLibrary::InsertChildAt(UWidget* Parent, int32 Index, UWidget* Content)
{
UPanelSlot* ResultSlot = nullptr;
if (Parent && Content)
{
if (UPanelWidget* PanelWidget = Cast<UPanelWidget>(Parent))
{
Index = FMath::Clamp(Index, 0, FMath::Max(0, PanelWidget->GetChildrenCount() - 1));
if (PanelWidget->GetChildIndex(Content) != Index)
{
ResultSlot = PanelWidget->AddChild(Content);
UWidget* SlotContent = nullptr;
for (int32 i = Index; i < PanelWidget->GetChildrenCount(); ++i)
{
SlotContent = PanelWidget->GetChildAt(Index);
if (SlotContent == Content)
{
break;
}
PanelWidget->RemoveChild(SlotContent);
PanelWidget->AddChild(SlotContent);
}
}
}
}
return ResultSlot;
}
void UVictoryBPFunctionLibrary::FlushPressedKeys(class APlayerController* PlayerController)
{
if (PlayerController)
{
PlayerController->FlushPressedKeys();
}
}
FVector UVictoryBPFunctionLibrary::GetVectorRelativeLocation(FVector ParentLocation, FRotator ParentRotation, FVector ChildLocation)
{
return ParentRotation.UnrotateVector(ChildLocation - ParentLocation);
}
FVector UVictoryBPFunctionLibrary::GetComponentRelativeLocation(class USceneComponent* ParentComponent, class USceneComponent* ChildComponent)
{
return (ParentComponent && ChildComponent) ? GetVectorRelativeLocation(ParentComponent->GetComponentLocation(), ParentComponent->GetComponentRotation(), ChildComponent->GetComponentLocation()) : FVector::ZeroVector;
}
FVector UVictoryBPFunctionLibrary::GetActorRelativeLocation(class AActor* ParentActor, class AActor* ChildActor)
{
return (ParentActor && ChildActor) ? GetVectorRelativeLocation(ParentActor->GetActorLocation(), ParentActor->GetActorRotation(), ChildActor->GetActorLocation()) : FVector::ZeroVector;
}
FRotator UVictoryBPFunctionLibrary::GetRotatorRelativeRotation(FRotator ParentRotation, FRotator ChildRotation)
{
const FRotator RelativeRotation = (FQuatRotationMatrix(ChildRotation.Quaternion()) * FQuatRotationMatrix(ParentRotation.Quaternion()).GetTransposed()).Rotator();
return RelativeRotation;
}
FRotator UVictoryBPFunctionLibrary::GetComponentRelativeRotation(class USceneComponent* ParentComponent, class USceneComponent* ChildComponent)
{
return (ParentComponent && ChildComponent) ? GetRotatorRelativeRotation(ParentComponent->GetComponentRotation(), ChildComponent->GetComponentRotation()) : FRotator::ZeroRotator;
}
FRotator UVictoryBPFunctionLibrary::GetActorRelativeRotation(class AActor* ParentActor, class AActor* ChildActor)
{
return (ParentActor && ChildActor) ? GetRotatorRelativeRotation(ParentActor->GetActorRotation(), ChildActor->GetActorRotation()) : FRotator::ZeroRotator;
}
float UVictoryBPFunctionLibrary::HorizontalFOV(float VerticalFOV, float AspectRatio)
{
VerticalFOV = FMath::DegreesToRadians(VerticalFOV);
return FMath::RadiansToDegrees(2 * FMath::Atan2(FMath::Tan(VerticalFOV * 0.5f) * AspectRatio, 1));
}
float UVictoryBPFunctionLibrary::VerticalFOV(float HorizontalFOV, float AspectRatio)
{
HorizontalFOV = FMath::DegreesToRadians(HorizontalFOV);
return FMath::RadiansToDegrees(2 * FMath::Atan2(FMath::Tan(HorizontalFOV * 0.5f) * (1 / AspectRatio), 1));
}
bool UVictoryBPFunctionLibrary::StringIsEmpty(const FString& Target)
{
return Target.IsEmpty();
}
//~~~~~~~~~ END OF CONTRIBUTED BY KRIS ~~~~~~~~~~~
//~~~ Inspired by Sahkan ~~~
void UVictoryBPFunctionLibrary::Actor__GetAttachedActors(AActor* ParentActor,TArray<AActor*>& ActorsArray)
{
if(!ParentActor) return;
//~~~~~~~~~~~~
ActorsArray.Empty();
ParentActor->GetAttachedActors(ActorsArray);
}
void UVictoryBPFunctionLibrary::SetBloomIntensity(APostProcessVolume* PostProcessVolume,float Intensity)
{
if(!PostProcessVolume) return;
//~~~~~~~~~~~~~~~~
PostProcessVolume->Settings.bOverride_BloomIntensity = true;
PostProcessVolume->Settings.BloomIntensity = Intensity;
}
//~~~ Key To Truth ~~~
//.cpp
//Append different text strings with optional pins.
FString UVictoryBPFunctionLibrary::AppendMultiple(FString A, FString B)
{
FString Result = "";
Result += A;
Result += B;
return Result;
}
//~~~ Mhousse ~~~
//TESTING
static void TESTINGInternalDrawDebugCircle(const UWorld* InWorld, const FMatrix& TransformMatrix, float Radius, int32 Segments, const FColor& Color, bool bPersistentLines, float LifeTime, uint8 DepthPriority, float Thickness=0)
{
//this is how you can make cpp only internal functions!
}
#undef LOCTEXT_NAMESPACE